M ip/ip.h => ip/ip.h +7 -0
@@ 12,6 12,7 @@ typedef struct Ipmux Ipmux;
typedef struct IProuter IProuter;
typedef struct Ipifc Ipifc;
typedef struct Log Log;
+typedef struct Ifclog Ifclog;
typedef struct Medium Medium;
typedef struct Proto Proto;
typedef struct Pstate Pstate;
@@ 258,6 259,7 @@ struct Fs
Route *queue; /* used as temp when reinjecting routes */
Log *alog;
+ Ifclog *ilog;
};
int Fsconnected(Conv*, char*);
@@ 302,6 304,11 @@ void netlogclose(Fs*);
char* netlogctl(Fs*, char*, int);
long netlogread(Fs*, void*, ulong, long);
void netlog(Fs*, int, char*, ...);
+void ifcloginit(Fs*);
+long ifclogread(Fs*, Chan *,void*, ulong, long);
+void ifclog(Fs*, uchar *, int);
+void ifclogopen(Fs*, Chan*);
+void ifclogclose(Fs*, Chan*);
/*
* iproute.c
M ip/rudp.c => ip/rudp.c +53 -28
@@ 161,10 161,6 @@ struct Rudppriv
static ulong generation = 0;
static Rendez rend;
-/* Used only for debugging */
-static ushort drop = 0;
-static ushort drop_rate = 10;
-
/*
* protocol specific part of Conv
*/
@@ 173,6 169,7 @@ struct Rudpcb
{
QLock;
uchar headers;
+ uchar randdrop;
Reliable *r;
};
@@ 261,6 258,15 @@ rudpclose(Conv *c)
Rudpcb *ucb;
Reliable *r, *nr;
+ /* force out any delayed acks */
+ ucb = (Rudpcb*)c->ptcl;
+ qlock(ucb);
+ for(r = ucb->r; r; r = r->next){
+ if(r->acksent != r->rcvseq)
+ relsendack(c, r);
+ }
+ qunlock(ucb);
+
qclose(c->rq);
qclose(c->wq);
qclose(c->eq);
@@ 269,10 275,12 @@ rudpclose(Conv *c)
c->lport = 0;
c->rport = 0;
- ucb = (Rudpcb*)c->ptcl;
ucb->headers = 0;
+ ucb->randdrop = 0;
qlock(ucb);
for(r = ucb->r; r; r = nr){
+ if(r->acksent != r->rcvseq)
+ relsendack(c, r);
nr = r->next;
relhangup(c, r);
free(r);
@@ 284,6 292,21 @@ rudpclose(Conv *c)
unlock(c);
}
+/*
+ * randomly don't send packets
+ */
+static void
+doipoput(Conv *c, Fs *f, Block *bp, int x, int ttl)
+{
+ Rudpcb *ucb;
+
+ ucb = (Rudpcb*)c->ptcl;
+ if(ucb->randdrop && nrand(10) == 1)
+ freeblist(bp);
+ else
+ ipoput(f, bp, x, ttl);
+}
+
int
flow(Reliable *r)
{
@@ 411,7 434,7 @@ rudpkick(Conv *c, int)
DPRINT("sent: %lud/%lud, %lud/%lud\n",
r->sndseq, r->sndgen, r->rcvseq, r->rcvgen);
- ipoput(f, bp, 0, c->ttl);
+ doipoput(c, f, bp, 0, c->ttl);
/* flow control of sorts */
qlock(&r->lock);
@@ 593,6 616,9 @@ rudpctl(Conv *c, char **f, int n)
} else if(strcmp(f[0], "headers") == 0){
ucb->headers = 6;
return nil;
+ } else if(strcmp(f[0], "randdrop") == 0){
+ ucb->randdrop = 1;
+ return nil;
}
}
return "unknown control request";
@@ 802,6 828,19 @@ reliput(Conv *c, Block *bp, uchar *addr, ushort port)
DPRINT("rcvd %lud/%lud, %lud/%lud, r->sndgen = %lud\n",
seq, sgen, ack, agen, r->sndgen);
+ /* make sure we're not talking to a new remote side */
+ if(r->rcvgen != sgen){
+ if(seq != 1)
+ return -1;
+
+ /* new connection */
+ if(r->rcvgen != 0){
+ DPRINT("new con r->rcvgen = %lud, sgen = %lud\n", r->rcvgen, sgen);
+ relhangup(c, r);
+ }
+ r->rcvgen = sgen;
+ }
+
/* dequeue acked packets */
if(ack && agen == r->sndgen){
ackreal = 0;
@@ 833,29 872,10 @@ reliput(Conv *c, Block *bp, uchar *addr, ushort port)
}
- /* make sure we're not talking to a new remote side */
- if(r->rcvgen != sgen){
- if(seq != 1)
- return -1;
-
- /* new connection */
- if(r->rcvgen != 0){
- DPRINT("new con r->rcvgen = %lud, sgen = %lud\n", r->rcvgen, sgen);
- relhangup(c, r);
- }
- r->rcvgen = sgen;
- }
-
/* no message or input queue full */
if(seq == 0 || qfull(c->rq))
return -1;
- if(DEBUG && ++drop == drop_rate){
- DPRINT("drop pkt on purpose\n");
- drop = 0;
- return -1;
- }
-
/* refuse out of order delivery */
if(seq != NEXTSEQ(r->rcvseq)){
relsendack(c, r); /* tell him we got it already */
@@ 913,16 933,21 @@ relsendack(Conv *c, Reliable *r)
hnputs(uh->udpcksum, ptclcsum(bp, UDP_IPHDR, UDP_RHDRSIZE));
DPRINT("sendack: %lud/%lud, %lud/%lud\n", 0L, r->sndgen, r->rcvseq, r->rcvgen);
- ipoput(f, bp, 0, c->ttl);
+ doipoput(c, f, bp, 0, c->ttl);
}
/*
* called with ucb locked (and c locked if user initiated close)
*/
void
-relhangup(Conv *, Reliable *r)
+relhangup(Conv *c, Reliable *r)
{
+ int n;
Block *bp;
+ char hup[ERRLEN];
+
+ n = snprint(hup, sizeof(hup), "hangup %I!%d", r->addr, r->port);
+ qproduce(c->eq, hup, n);
/*
* dump any unacked outgoing messages
@@ 965,5 990,5 @@ relrexmit(Conv *c, Reliable *r)
upriv->rxmits++;
np = copyblock(r->unacked, blocklen(r->unacked));
DPRINT("rxmit r->ackrvcd+1 = %lud\n", r->ackrcvd+1);
- ipoput(f, np, 0, c->ttl);
+ doipoput(c, f, np, 0, c->ttl);
}
M ip/tcp.c => ip/tcp.c +59 -16
@@ 38,6 38,7 @@ enum
MSPTICK = 50, /* Milliseconds per timer tick */
DEF_MSS = 1024, /* Default mean segment */
DEF_RTT = 150, /* Default round trip */
+ DEF_KAT = 10000, /* Default keep alive trip in ms */
TCP_LISTEN = 0, /* Listen connection */
TCP_CONNECT = 1, /* Outgoing connection */
@@ 171,11 172,11 @@ struct Tcpctl
Timer timer; /* Activity timer */
Timer acktimer; /* Acknowledge timer */
Timer rtt_timer; /* Round trip timer */
+ Timer katimer; /* keep alive timer */
ulong rttseq; /* Round trip sequence */
int srtt; /* Shortened round trip */
int mdev; /* Mean deviation of round trip */
int kacounter; /* count down for keep alive */
- int f2counter; /* count down for finwait2 state */
uint sndsyntime; /* time syn sent */
Tcphdr protohdr; /* prototype header */
@@ 237,6 238,7 @@ void tcptimeout(void*);
void tcpsndsyn(Tcpctl*);
void tcprcvwin(Conv*);
void tcpacktimer(Conv*);
+void tcpkeepalive(Conv*);
void
tcpsetstate(Conv *s, uchar newstate)
@@ 554,6 556,7 @@ localclose(Conv *s, char *reason) /* called with tcb locked */
tcphalt(tpriv, &tcb->timer);
tcphalt(tpriv, &tcb->rtt_timer);
tcphalt(tpriv, &tcb->acktimer);
+ tcphalt(tpriv, &tcb->katimer);
/* Flush reassembly queue; nothing more can arrive */
for(rp = tcb->reseq; rp != nil; rp = rp1) {
@@ 594,6 597,10 @@ inittcpctl(Conv *s)
tcb->acktimer.start = TCP_ACK / MSPTICK;
tcb->acktimer.func = tcpacktimer;
tcb->acktimer.arg = s;
+ tcb->kacounter = 0;
+ tcb->katimer.start = DEF_KAT / MSPTICK;
+ tcb->katimer.func = tcpkeepalive;
+ tcb->katimer.arg = s;
/* create a prototype(pseudo) header */
if(ipcmp(s->laddr, IPnoaddr) == 0)
@@ 1007,8 1014,6 @@ update(Conv *s, Tcp *seg)
tpriv = s->p->priv;
tcb = (Tcpctl*)s->ptcl;
- tcb->kacounter = MAXBACKOFF; /* keep alive count down */
-
if(seq_gt(seg->ack, tcb->snd.nxt)) {
tcb->flags |= FORCE;
return;
@@ 1224,6 1229,9 @@ tcpiput(Proto *tcp, uchar*, Block *bp)
tcb = (Tcpctl*)s->ptcl;
qlock(tcb);
+ if(tcb->kacounter > 0)
+ tcb->kacounter = MAXBACKOFF;
+
switch(tcb->state) {
case Closed:
sndrst(tcp, source, dest, length, &seg);
@@ 1343,9 1351,9 @@ tcpiput(Proto *tcp, uchar*, Block *bp)
case Finwait1:
update(s, &seg);
if(tcb->sndcnt == 0){
- tcb->f2counter = MAXBACKOFF;
+ tcb->kacounter = MAXBACKOFF;
tcpsetstate(s, Finwait2);
- tcb->timer.start = MSL2 * (1000 / MSPTICK);
+ tcb->katimer.start = MSL2 * (1000 / MSPTICK);
tcpgo(tpriv, &tcb->timer);
}
break;
@@ 1686,6 1694,8 @@ tcpoutput(Conv *s)
}
tpriv->tstats.tcpOutSegs++;
+ if(tcb->kacounter > 0)
+ tcpgo(tpriv, &tcb->katimer);
ipoput(f, hbp, 0, s->ttl);
}
}
@@ 1694,7 1704,7 @@ tcpoutput(Conv *s)
* the BSD convention (hack?) for keep alives. resend last uchar acked.
*/
void
-tcpkeepalive(Conv *s)
+tcpsendka(Conv *s)
{
Tcp seg;
Tcpctl *tcb;
@@ 1730,6 1740,47 @@ tcpkeepalive(Conv *s)
ipoput(s->p->f, hbp, 0, s->ttl);
}
+/*
+ * if we've timed out, close the connection
+ * otherwise, send a keepalive and restart the timer
+ */
+void
+tcpkeepalive(Conv *s)
+{
+ Tcpctl *tcb;
+
+ tcb = (Tcpctl*)s->ptcl;
+ if(--(tcb->kacounter) <= 0)
+ localclose(s, Etimedout);
+ else {
+ qlock(tcb);
+ tcpsendka(s);
+ qunlock(tcb);
+ tcpgo(s->p->priv, &tcb->katimer);
+ }
+}
+
+/*
+ * start keepalive timer
+ */
+char*
+tcpstartka(Conv *s, char **f, int n)
+{
+ Tcpctl *tcb;
+ int x;
+
+ tcb = (Tcpctl*)s->ptcl;
+ if(n > 1){
+ x = atoi(f[1]);
+ if(x >= MSPTICK)
+ tcb->katimer.start = x/MSPTICK;
+ }
+ tcb->kacounter = MAXBACKOFF;
+ tcpgo(s->p->priv, &tcb->katimer);
+
+ return nil;
+}
+
void
tcprxmit(Conv *s)
{
@@ 1782,16 1833,6 @@ tcptimeout(void *arg)
}
tcprxmit(s);
break;
- case Finwait2:
- if(--(tcb->f2counter) <= 0)
- localclose(s, Etimedout);
- else {
- qlock(tcb);
- tcpkeepalive(s);
- qunlock(tcb);
- tcpgo(s->p->priv, &tcb->timer);
- }
- break;
case Time_wait:
localclose(s, nil);
break;
@@ 2001,6 2042,8 @@ tcpctl(Conv* c, char** f, int n)
{
if(n == 1 && strcmp(f[0], "hangup") == 0)
return tcphangup(c);
+ if(n >= 1 && strcmp(f[0], "keepalive") == 0)
+ return tcpstartka(c, f, n);
return "unknown control request";
}