Plan 9 from Bell Labs’s /usr/web/sources/extra/9hist/port/tcpoutput.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


## diffname port/tcpoutput.c 1991/0424
## diff -e /dev/null /n/bootesdump/1991/0424/sys/src/9/port/tcpoutput.c
0a
#include	"u.h"
#include	"lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"errno.h"
#include 	"arp.h"
#include 	"ipdat.h"

extern int tcpdbg;
extern ushort tcp_mss;
extern Queue *Tcpoutput;

#define DPRINT if(tcpdbg) print

void
tcp_output(Ipconv *s)
{
	Block *hbp,*dbp, *sndq;
	ushort ssize, dsize, usable, sent, oobsent;
	int qlen;
	char doing_oob;	
	Tcphdr ph;
	Tcp seg;
	Tcpctl *tcb;

	tcb = &s->tcpctl;

	switch(tcb->state) {
	case LISTEN:
	case CLOSED:
		return;
	}
	for(;;){
		if (tcb->sndoobq) {
			/* We have pending out-of-band data - use it */
			qlen = tcb->sndoobcnt;
			oobsent = tcb->snd.ptr - tcb->snd.up;
			if (oobsent >= qlen) {
				oobsent = qlen;
				goto normal;
			}
			sndq = tcb->sndoobq;
			sent = oobsent;
			doing_oob = 1;
			DPRINT("tcp_out: oob: qlen = %lux sent = %lux\n",
						qlen, sent);
		} else {
			oobsent = 0;
			normal:
			qlen = tcb->sndcnt;
			sent = tcb->snd.ptr - tcb->snd.una - oobsent;
			sndq = tcb->sndq;
			doing_oob = 0;
			DPRINT("tcp_out: norm: qlen = %lux sent = %lux\n", qlen, sent);
		}

		/* Don't send anything else until our SYN has been acked */
		if(sent != 0 && !(tcb->flags & SYNACK))
			break;

		if(tcb->snd.wnd == 0){
			/* Allow only one closed-window probe at a time */
			if(sent != 0)
				break;
			/* Force a closed-window probe */
			usable = 1;
		} else {
			/* usable window = offered window - unacked bytes in transit
			 * limited by the congestion window
			 */
			usable = MIN(tcb->snd.wnd,tcb->cwind) - sent;
			if(sent != 0 && qlen - sent < tcb->mss) 
				usable = 0;
		}

		ssize = MIN(qlen - sent, usable);
		ssize = MIN(ssize, tcb->mss);
		dsize = ssize;

		if (!doing_oob)
			seg.up = 0;
		else {
			seg.up = ssize;
			DPRINT("tcp_out: oob seg.up = %d\n", seg.up);
		}

		DPRINT("tcp_out: ssize = %lux\n", ssize);
		if(ssize == 0 && !(tcb->flags & FORCE))
			break;

		/* Stop ack timer if one will be piggy backed on data */
		stop_timer(&tcb->acktimer);

		tcb->flags &= ~FORCE;

		seg.source = s->psrc;
		seg.dest = s->pdst;
		/* Every state except SYN_SENT */
		seg.flags = ACK; 	
		seg.mss = 0;

		switch(tcb->state){
		case SYN_SENT:
			seg.flags = 0;
			/* No break */
		case SYN_RECEIVED:
			if(tcb->snd.ptr == tcb->iss){
				seg.flags |= SYN;
				dsize--;
				/* Also send MSS */
				seg.mss = tcp_mss;
			}
			break;
		}
		seg.seq = tcb->snd.ptr;
		seg.ack = tcb->last_ack = tcb->rcv.nxt;
		seg.wnd = tcb->rcv.wnd;

		if (doing_oob) {
			DPRINT("tcp_out: Setting URG (up = %u)\n", seg.up);
			seg.flags |= URG;
		}

		/* Now try to extract some data from the send queue.
		 * Since SYN and FIN occupy sequence space and are reflected
		 * in sndcnt but don't actually sit in the send queue,
		 * dupb will return one less than dsize if a FIN needs to be sent.
		 */
		if(dsize != 0){
			if(dupb(&dbp, sndq, sent, dsize) != dsize) {
				seg.flags |= FIN;
				dsize--;
			}
			DPRINT("dupb: 1st char = %c\n", dbp->rptr[0]);
		} else
			dbp = 0;

		/* If the entire send queue will now be in the pipe, set the
		 * push flag
		 */
		if((dsize != 0) && 
		   ((sent + ssize) == (tcb->rcvcnt + tcb->rcvoobcnt)))
			seg.flags |= PSH;

		/* If this transmission includes previously transmitted data,
		 * snd.nxt will already be past snd.ptr. In this case,
		 * compute the amount of retransmitted data and keep score
		 */
		if(tcb->snd.ptr < tcb->snd.nxt)
			tcb->resent += MIN((int)tcb->snd.nxt - (int)tcb->snd.ptr,(int)ssize);

		tcb->snd.ptr += ssize;

		/* If this is the first transmission of a range of sequence
		 * numbers, record it so we'll accept acknowledgments
		 * for it later
		 */
		if(seq_gt(tcb->snd.ptr,tcb->snd.nxt))
			tcb->snd.nxt = tcb->snd.ptr;

		/* Fill in fields of pseudo IP header */
		hnputl(ph.tcpdst, s->dst);
		hnputl(ph.tcpsrc, Myip);
		hnputs(ph.tcpsport, s->psrc);
		hnputs(ph.tcpdport, s->pdst);

		/* Build header, link data and compute cksum */
		if((hbp = htontcp(&seg, dbp, &ph)) == 0) {
			freeb(dbp);
			return;
		}

		/* If we're sending some data or flags, start retransmission
		 * and round trip timers if they aren't already running.
		 */
		if(ssize != 0){
			tcb->timer.start = backoff(tcb->backoff) *
			 (2 * tcb->mdev + tcb->srtt + MSPTICK) / MSPTICK;
			if(!run_timer(&tcb->timer))
				start_timer(&tcb->timer);

			/* If round trip timer isn't running, start it */
			if(!run_timer(&tcb->rtt_timer)){
				start_timer(&tcb->rtt_timer);
				tcb->rttseq = tcb->snd.ptr;
			}
		}
		DPRINT("tcp_output: ip_send s%lux a%lux w%lux u%lux\n",
			seg.seq, seg.ack, seg.wnd, seg.up);

		PUTNEXT(Tcpoutput, hbp);
	}
}

int tcptimertype = 0;

void
tcp_timeout(void *arg)
{
	Tcpctl *tcb;
	Ipconv *s;

	s = (Ipconv *)arg;
	tcb = &s->tcpctl;

	DPRINT("Timer %lux state = %d\n", s, tcb->state);

	switch(tcb->state){
	case CLOSED:
		panic("tcptimeout");
	case TIME_WAIT:
		close_self(s, 0);
		break;
	case ESTABLISHED:
		if(tcb->backoff < MAXBACKOFF)
			tcb->backoff++;
		goto retran;
	default:
		tcb->backoff++;
		DPRINT("tcp_timeout: retransmit %d %x\n", tcb->backoff, s);

		if (tcb->backoff >= MAXBACKOFF) {
			DPRINT("tcp_timeout: timeout\n");
			close_self(s, Etimedout);
		}
		else {
	retran:
			qlock(tcb);
			tcb->flags |= RETRAN|FORCE;
			tcb->snd.ptr = tcb->snd.una;

			/* Reduce slowstart threshold to half current window */
			tcb->ssthresh = tcb->cwind / 2;
			tcb->ssthresh = MAX(tcb->ssthresh,tcb->mss);

			/* Shrink congestion window to 1 packet */
			tcb->cwind = tcb->mss;
			tcp_output(s);
			qunlock(tcb);
		}
	}
}

int
backoff(int n)
{
	if(tcptimertype == 1) 
		return n+1;
	else {
		if(n <= 4)
			return 1 << n;
		else
			return n * n;
	}
}

void
tcp_acktimer(Ipconv *s)
{
	Tcpctl *tcb = &s->tcpctl;

	qlock(tcb);
	tcb->flags |= FORCE;
	tcprcvwin(s);
	tcp_output(s);
	qunlock(tcb);
}

void
tcprcvwin(Ipconv *s)
{
	Tcpctl *tcb = &s->tcpctl;

	/* Calculate new window */
	if(s->readq) {
		tcb->rcv.wnd = Streamhi - s->readq->next->len;
		if(tcb->rcv.wnd < 0)
			tcb->rcv.wnd = 0;
	}
	else
		tcb->rcv.wnd = Streamhi;
}
.
## diffname port/tcpoutput.c 1991/0425
## diff -e /n/bootesdump/1991/0424/sys/src/9/port/tcpoutput.c /n/bootesdump/1991/0425/sys/src/9/port/tcpoutput.c
95a
		tcprcvwin(s);
.
## diffname port/tcpoutput.c 1991/0723
## diff -e /n/bootesdump/1991/0425/sys/src/9/port/tcpoutput.c /n/bootesdump/1991/0723/sys/src/9/port/tcpoutput.c
284a

/*
 * Network byte order functions
 */

void
hnputs(uchar *ptr, ushort val)
{
	ptr[0] = val>>8;
	ptr[1] = val;
}

void
hnputl(uchar *ptr, ulong val)
{
	ptr[0] = val>>24;
	ptr[1] = val>>16;
	ptr[2] = val>>8;
	ptr[3] = val;
}

ulong
nhgetl(uchar *ptr)
{
	return ((ptr[0]<<24) | (ptr[1]<<16) | (ptr[2]<<8) | ptr[3]);
}

ushort
nhgets(uchar *ptr)
{
	return ((ptr[0]<<8) | ptr[1]);
}
.
## diffname port/tcpoutput.c 1991/1019
## diff -e /n/bootesdump/1991/0723/sys/src/9/port/tcpoutput.c /n/bootesdump/1991/1019/sys/src/9/port/tcpoutput.c
196,197d
193c
		PUTNEXT(Ipoutput, hbp);
.
13a

.
12c
int tcptimertype = 0;
.
## diffname port/tcpoutput.c 1991/1030
## diff -e /n/bootesdump/1991/1019/sys/src/9/port/tcpoutput.c /n/bootesdump/1991/1030/sys/src/9/port/tcpoutput.c
262c
print("Acktimer!\n");
.
122,126d
113d
90c
		if(ssize == 0 && (tcb->flags & FORCE) == 0)
.
82,88d
80a
		seg.up = 0;
.
36,57c
		qlen = tcb->sndcnt;
		sent = tcb->snd.ptr - tcb->snd.una;
		sndq = tcb->sndq;
.
34a

.
23d
21c
	ushort ssize, dsize, usable, sent;
.
14,16d
10a
#define DPRINT if(tcpdbg) print
.
## diffname port/tcpoutput.c 1991/1101
## diff -e /n/bootesdump/1991/1030/sys/src/9/port/tcpoutput.c /n/bootesdump/1991/1101/sys/src/9/port/tcpoutput.c
229c

.
## diffname port/tcpoutput.c 1991/1126
## diff -e /n/bootesdump/1991/1101/sys/src/9/port/tcpoutput.c /n/bootesdump/1991/1126/sys/src/9/port/tcpoutput.c
111,112c
		if(sent+dsize == qlen)
.
## diffname port/tcpoutput.c 1991/12171
## diff -e /n/bootesdump/1991/1126/sys/src/9/port/tcpoutput.c /n/bootesdump/1991/12171/sys/src/9/port/tcpoutput.c
181c
	case Established:
.
178c
	case Time_wait:
.
176c
	case Closed:
.
82c
		case Syn_received:
.
79c
		case Syn_sent:
.
28,29c
	case Listen:
	case Closed:
.
## diffname port/tcpoutput.c 1992/0111
## diff -e /n/bootesdump/1991/12171/sys/src/9/port/tcpoutput.c /n/bootesdump/1992/0111/sys/src/9/port/tcpoutput.c
6c
#include	"../port/error.h"
.
## diffname port/tcpoutput.c 1992/0213
## diff -e /n/bootesdump/1992/0111/sys/src/9/port/tcpoutput.c /n/bootesdump/1992/0213/sys/src/9/port/tcpoutput.c
132c
		hnputl(ph.tcpsrc, Myip[Myself]);
.
## diffname port/tcpoutput.c 1992/0223
## diff -e /n/bootesdump/1992/0213/sys/src/9/port/tcpoutput.c /n/bootesdump/1992/0223/sys/src/9/port/tcpoutput.c
248a
	qunlock(s);
.
241a
	qlock(s);
.
## diffname port/tcpoutput.c 1992/0313
## diff -e /n/bootesdump/1992/0223/sys/src/9/port/tcpoutput.c /n/bootesdump/1992/0313/sys/src/9/port/tcpoutput.c
180a

.
177a

.
63c
		if(ssize == 0)
		if((tcb->flags & FORCE) == 0)
.
53c
			if(sent != 0)
			if(qlen - sent < tcb->mss) 
.
39c
		if(sent != 0)
		if((tcb->flags & SYNACK) == 0)
.
## diffname port/tcpoutput.c 1992/0319
## diff -e /n/bootesdump/1992/0313/sys/src/9/port/tcpoutput.c /n/bootesdump/1992/0319/sys/src/9/port/tcpoutput.c
242c
tcprcvwin(Ipconv *s)				/* Call with tcb locked */
.
189,212c
		tcprxmit(s);
		break;
.
179,180c
	default:
		tcb->backoff++;
		DPRINT("tcp_timeout: retransmit %d %x\n", tcb->backoff, s);
		if (tcb->backoff >= MAXBACKOFF)
			close_self(s, Etimedout);
		else 
			tcprxmit(s);
		break;
.
176c
	print("Timer %lux state = %d\n", s, tcb->state);
.
167a
tcprxmit(Ipconv *s)
{
	Tcpctl *tcb;

	print("tcp! rexmit\n");
	tcb = &s->tcpctl;
	qlock(tcb);
	tcb->flags |= RETRAN|FORCE;
	tcb->snd.ptr = tcb->snd.una;

	/* Reduce slowstart threshold to half current window */
	tcb->ssthresh = tcb->cwind / 2;
	tcb->ssthresh = MAX(tcb->ssthresh,tcb->mss);

	/* Shrink congestion window to 1 packet */
	tcb->cwind = tcb->mss;
	tcp_output(s);
	qunlock(tcb);
}

void
.
160,162c
		print("snd: %d %x\n", blen(hbp), seg.seq);
.
111,113d
107,109c
			print("dupb: %d\n", dbp->rptr[0]);
		}
.
101a
		dbp = 0;
.
## diffname port/tcpoutput.c 1992/0320
## diff -e /n/bootesdump/1992/0319/sys/src/9/port/tcpoutput.c /n/bootesdump/1992/0320/sys/src/9/port/tcpoutput.c
206,211d
197d
192,193d
167d
157d
108c
			DPRINT("dupb: %d\n", dbp->rptr[0]);
.
66c
		if((tcb->flags&FORCE) == 0)
.
## diffname port/tcpoutput.c 1992/0321
## diff -e /n/bootesdump/1992/0320/sys/src/9/port/tcpoutput.c /n/bootesdump/1992/0321/sys/src/9/port/tcpoutput.c
2c
#include	"../port/lib.h"
.
## diffname port/tcpoutput.c 1992/0724
## diff -e /n/bootesdump/1992/0321/sys/src/9/port/tcpoutput.c /n/bootesdump/1992/0724/sys/src/9/port/tcpoutput.c
240a
		else
			tcb->rcv.wnd = w;
.
238,239c
		/* use w because rcv.wnd is unsigned */
		w = Streamhi - s->readq->next->len;
		if(w < 0)
.
233a
	int w;
.
## diffname port/tcpoutput.c 1992/0822
## diff -e /n/bootesdump/1992/0724/sys/src/9/port/tcpoutput.c /n/bootesdump/1992/0822/sys/src/9/port/tcpoutput.c
142,143c
		/* Start the transmission timers if there is new data and we
		 * expect acknowledges
.
123,126c
		/* Pull up the send pointer so we can accept acks for this window */
.
114,117c
		/*
		 * keep track of balance of resent data */
.
97,101c
		/* Pull out data to send */
.
## diffname port/tcpoutput.c 1992/0826
## diff -e /n/bootesdump/1992/0822/sys/src/9/port/tcpoutput.c /n/bootesdump/1992/0826/sys/src/9/port/tcpoutput.c
191c
		localclose(s, 0);
.
185c
			localclose(s, Etimedout);
.
## diffname port/tcpoutput.c 1992/0903
## diff -e /n/bootesdump/1992/0826/sys/src/9/port/tcpoutput.c /n/bootesdump/1992/0903/sys/src/9/port/tcpoutput.c
217c
	tcpoutput(s);
.
210c
tcpacktimer(Ipconv *s)
.
186,187c
			break;
		}
		tcprxmit(s);
.
184c
		if (tcb->backoff >= MAXBACKOFF) {
.
173c
tcptimeout(void *arg)
.
168c
	tcpoutput(s);
.
144c
				tcpgo(&tcb->rtt_timer);
.
140c
				tcpgo(&tcb->timer);
.
77d
74a
		/* By default we will generate an ack */
.
69,70c
		tcphalt(&tcb->acktimer);
.
64d
49,52c
		}
		else {
.
47d
44d
42a
		/* Compute usable segment based on offered window and limit
		 * window probes to one
		 */
.
33c
	for(;;) {
.
16c
tcpoutput(Ipconv *s)
.
14a
extern	int tcpdbg;
extern	ushort tcp_mss;
	int tcptimertype;

.
12,13d
10d
## diffname port/tcpoutput.c 1992/0906
## diff -e /n/bootesdump/1992/0903/sys/src/9/port/tcpoutput.c /n/bootesdump/1992/0906/sys/src/9/port/tcpoutput.c
229d
226c
	tcb = &s->tcpctl;
.
224a
	Tcpctl *tcb;
.
223d
200,205c

	if(n <= 4)
		return 1 << n;

	return n*n;
.
164d
162c
	tcb->ssthresh = MAX(tcb->ssthresh, tcb->mss);
.
160c
	/* Pull window down to a single packet and halve the slow
	 * start threshold
	 */
.
24a
	Block *hbp,*dbp, *sndq;
	ushort ssize, dsize, usable, sent;
.
23d
19,20c
	Tcp seg;
.
## diffname port/tcpoutput.c 1992/1019
## diff -e /n/bootesdump/1992/0906/sys/src/9/port/tcpoutput.c /n/bootesdump/1992/1019/sys/src/9/port/tcpoutput.c
183c
		if (tcb->backoff >= MAXBACKOFF && tcb->snd.wnd > 0) {
.
179d
48,49c
			if(sent != 0) {
				if (tcb->flags&FORCE)
						tcb->snd.ptr = tcb->snd.una;
				else
					break;
			}
.
## diffname port/tcpoutput.c 1993/0218
## diff -e /n/bootesdump/1992/1019/sys/src/9/port/tcpoutput.c /n/bootesdump/1993/0218/sys/src/9/port/tcpoutput.c
96c
		seg.ack = tcb->rcv.nxt;
.
94a
		tcb->last_ack = tcb->rcv.nxt;
.
52a
				tcb->snd.ptr = tcb->snd.una;
.
49,51c
				if ((tcb->flags&FORCE) == 0)
.
## diffname port/tcpoutput.c 1993/0220
## diff -e /n/bootesdump/1993/0218/sys/src/9/port/tcpoutput.c /n/bootesdump/1993/0220/sys/src/9/port/tcpoutput.c
115c
			tcb->resent += MIN(tcb->snd.nxt - tcb->snd.ptr,(int)ssize);
.
## diffname port/tcpoutput.c 1993/0427
## diff -e /n/bootesdump/1993/0220/sys/src/9/port/tcpoutput.c /n/bootesdump/1993/0427/sys/src/9/port/tcpoutput.c
186a
print("tcp connection timed out\n"); 
.
## diffname port/tcpoutput.c 1993/0501
## diff -e /n/bootesdump/1993/0427/sys/src/9/port/tcpoutput.c /n/fornaxdump/1993/0501/sys/src/brazil/port/tcpoutput.c
187d
115c
			tcb->resent += MIN((int)tcb->snd.nxt - (int)tcb->snd.ptr,(int)ssize);
.
96c
		seg.ack = tcb->last_ack = tcb->rcv.nxt;
.
94d
51d
49c
				if (tcb->flags&FORCE)
						tcb->snd.ptr = tcb->snd.una;
				else
.
## diffname port/tcpoutput.c 1993/0804 # deleted
## diff -e /n/fornaxdump/1993/0501/sys/src/brazil/port/tcpoutput.c /n/fornaxdump/1993/0804/sys/src/brazil/port/tcpoutput.c
1,273d

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.