From 60a9b49c675c8ab381d1bec8bef4b761df863a0a Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Wed, 18 Nov 1998 00:00:00 +0000 Subject: [PATCH] Plan 9 from Bell Labs 1998-11-18 --- ip/ip.h | 7 +++++ ip/rudp.c | 81 ++++++++++++++++++++++++++++++++++++------------------- ip/tcp.c | 75 ++++++++++++++++++++++++++++++++++++++++----------- 3 files changed, 119 insertions(+), 44 deletions(-) diff --git a/ip/ip.h b/ip/ip.h index 21cdb87e09e1597161adaa123243e303bf563414..1f7eacd25ddd2b6557baa47b7272a96207392e43 100644 --- a/ip/ip.h +++ b/ip/ip.h @@ -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 diff --git a/ip/rudp.c b/ip/rudp.c index e296122c18f41480d2a0da7703ace09906778f99..fcf1a1a4f2505c681513c6908e496fd3d388d120 100644 --- a/ip/rudp.c +++ b/ip/rudp.c @@ -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); } diff --git a/ip/tcp.c b/ip/tcp.c index e1684c13153cb8e1f4570c8d0cc3d47a944d0c9c..09a25012077aeb7e7029cc0c34bba64a1bc2183b 100644 --- a/ip/tcp.c +++ b/ip/tcp.c @@ -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"; }