ArpaTCPOps.mesa
Copyright (C) 1983, 1985 by Xerox Corporation. All rights reserved. The following program was created in 1983 but has not been published within the meaning of the copyright law, is furnished under license, and may not be used, copied and/or disclosed except in accordance with the terms of said license.
Last Edited by: Nichols, September 1, 1983 4:27 pm
Last Edited by: Taft, January 3, 1984 9:45 am
Last Edited by: HGM, March 23, 1984 10:01:40 am PST
Demers, September 7, 1988 1:54:50 pm PDT
Doug Terry, March 22, 1988 6:37:27 pm PST
Hal Murray July 16, 1985 4:39:19 pm PDT
John Larson, April 14, 1986 11:18:30 pm PST
DIRECTORY
Arpa USING [Address],
ArpaBuf USING [maxBodyBytes],
ArpaIP USING [Buffers, Handle],
ArpaTCP USING [DByte, Port, Reason, TCPInfo],
BasicTime USING [GetClockPulses, Pulses],
PrincOps USING [zEXCH];
ArpaTCPOps: CEDAR DEFINITIONS
IMPORTS BasicTime
~ BEGIN
Constants and types
sendBufferLength: INT ~ 4000; -- max bytes of unacked data to queue for transmission or retransmission to net
recvBufferLength: INT ~ 4000;
tcpHdrWordLength: INT ~ 5;
tcpHdrByteLength: INT ~ tcpHdrWordLength*4;
maxTCPDataLength: INT ~ ArpaBuf.maxBodyBytes - tcpHdrByteLength;
sillyWindowLimit: INT ~ 40; -- try not to send when window is smaller than this
ourLocalAddress: Arpa.Address;
tcpIPHandle: ArpaIP.Handle;
defaultReceiveWindow: INT;
repacketizing: BOOL; -- TRUE if data to be repacketized when retransmitted
Buffer: TYPE = ArpaIP.Buffers;
ConnectionState: TYPE = {closed, listen, synSent, synRcvd, established, finWait1, finWait2, closeWait, closing, lastAck, timeWait};
Pair: TYPE = MACHINE DEPENDENT RECORD [a, b: CARDINAL]; -- used for word swap
The layout of the TCP header in a datagram. One gets a TCPHeaderP by saying LOOPHOLE[@datagram.data].
TCPHeaderP: TYPE = LONG POINTER TO TCPHeader;
TCPHeader: TYPE = MACHINE DEPENDENT RECORD [
sourcePort (0): ArpaTCP.Port, -- source port number
dstnPort (1): ArpaTCP.Port, -- destination port number
seqNumber (2): Pair, -- sequence number
ackNumber (4): Pair, -- acknowledgement number
dataWordOffset (6: 0..3): INT [0..15], -- size of header in 32-bit words
unused (6: 4..9): INT [0..63] ← 0,
urg (6: 10..10): BOOLFALSE, -- control flags, urgent
ack (6: 11..11): BOOLFALSE, -- acknowledgement
psh (6: 12..12): BOOLFALSE, -- push
rst (6: 13..13): BOOLFALSE, -- reset
syn (6: 14..14): BOOLFALSE, -- syn (first packet on connection)
fin (6: 15..15): BOOLFALSE, -- fin (last packet on connection)
window (7): ArpaTCP.DByte, -- window of packets to send
checksum (8): ArpaTCP.DByte, -- for header and pseudo header
urgentPtr (9): ArpaTCP.DByte ← 0, -- ptr to byte following urgent data
options (10): ARRAY INT [1..40] OF BYTE]; -- options
The information about a TCP connection.
TCPHandle: TYPE ~ REF TCPHandleRec;
TCPHandleRec: TYPE ~ MONITORED RECORD [
localPort: ArpaTCP.Port, -- TCP port
foreignAddr: Arpa.Address, -- internet foreign address
foreignPort: ArpaTCP.Port, -- TCP port
matchForeignAddr: BOOL, -- true to use foreign addr
matchForeignPort: BOOL, -- true to use foreign port
state: ConnectionState, -- state of connection
reason: ArpaTCP.Reason, -- why we closed this connection
active: BOOL, -- active or passive open
notListening: CONDITION, -- used to wait for connection when listening
maxSegmentSize: INT, -- max bytes we can send in a datagram
Send state:
sndUna: INT ← 0, -- oldest unacked seq number
sndNxt: INT ← 0, -- next seq number to send
sndWnd: INT ← 0, -- send window
sndWL1: INT ← 0, -- pkt seq used for last window update
sndWL2: INT ← 0, -- pkt ack used for last window update
iss: INT ← 0, -- initial send seq number
sndUrgent: BOOLFALSE, -- true if trying to send urgent data
sndUp: INT ← 0, -- where it is in the stream
fillSlot: INT [0..sendBufferLength) ← 0, -- for repacketizing
sendSlot: INT [0..sendBufferLength) ← 0, -- for repacketizing
sendBuffer: ARRAY INT [0..sendBufferLength) OF BYTE, -- for repacketizing
nBytesToSend: INT [0..sendBufferLength] ← 0, -- number of filled slots in sendBuffer
Receive state:
rcvNxt: INT ← 0, -- next seq number to receive
rcvWnd: INT, -- receive window
rcvUp: INT ← 0, -- receive urgent pointer
zeroRcvWnd: BOOLFALSE, -- last advertised receive window was zero
irs: INT ← 0, -- initial receive sequence number
urgentMode: BOOLFALSE, -- rcvd urgent data and not passed to user
Random:
finSequence: INT ← 0, -- sequence number of fin sent
dataTimeout: INT, -- in msecs, time to wait before signalling client
timeWaitTime: BasicTime.Pulses, -- when to delete a handle in timeWait state
fromNetQueue: LIST OF REF ANY, -- packets received from net (actually TCPRcvBuffers)
readyToReadQueue: LIST OF REF ANY, -- packets processed and ready to hand to client (TCPRcvBuffers)
currentInputBuffer: REF TCPRcvBuffer, -- buffer for doling out input
dataAvailable: CONDITION, -- wait here for incoming data
toNetQueue: LIST OF REF ANY, -- packets to send to net (ArpaIP.Bufferss)
rexmitQueue: LIST OF REF ANY, -- packets to retransmit to net (TCPSendBuffers)
currentOutputDatagram: ArpaIP.Buffers, -- next block of data to send
currentOutputPtr: INT, -- index into currentOutputDatagram for data
currentOutputLimit: INT, -- max size of datagram based on maxSegmentSize
windowAvailable: CONDITION, -- wait here for quota on other end
urgentAvailable: CONDITION, -- wait here for urgent data
Rount Trip Time estimate:
rtt: INT,
Statistics:
rexmits: INT ← 0,
duplicates: INT ← 0
];
Timeouts
defaultProbeTimeout: INT; -- time (ms) to wait on zero window before sending a probe
defaultRTT: INT; -- initial round-trip time
minRTT, maxRTT: INT;
defaultInitialTimeout: INT; -- how long to retransmit SYN before declaring connection dead
tcpSegmentLife: INT; -- value for time to live
beta: INT; -- retransmission timeout = beta * rtt
rexmitLimit: INT; -- max time rexmitting before closing connection, in rtt's
RexmitIntervalFromHandle: PROC [h: TCPHandle] RETURNS [INT]
~ INLINE { RETURN[beta*h.rtt] };
RexmitTimeoutFromHandle: PROC [h: TCPHandle] RETURNS [INT]
~ INLINE { RETURN[rexmitLimit*h.rtt] };
InitialTimeoutFromHandle: PROC [h: TCPHandle] RETURNS [INT]
~ INLINE { RETURN[defaultInitialTimeout] };
ProbeTimeoutFromHandle: PROC [h: TCPHandle] RETURNS [INT]
~ INLINE { RETURN[defaultProbeTimeout] };
TimeWaitTimeoutFromHandle: PROC [h: TCPHandle] RETURNS [INT]
~ INLINE { RETURN[tcpSegmentLife*1000*2] }; -- tcpSegmentLife is in seconds; SetTimeout takes milliseconds; *2 is for round-trip
These describe packets that have been received from the net.
TCPRcvBuffer: TYPE ~ RECORD [
offsetSeqNo: INT, -- for use by TCP
datagramPtr: ArpaIP.Buffers, -- datagram received from net
dataOffset: INT, -- Byte offset of data from dataPtr^
dataByteCount: INT, -- number of data bytes
tcpHdrPtr: TCPHeaderP, -- pointer to TCP header (?)
urg: BOOL, -- value of TCP URG field
endUrgentData: INT]; -- index of byte following urgent data
And these describe packets that have been sent once, but may need to be retransmitted.
TCPSendBuffer: TYPE ~ RECORD [
dataByteCount: INT, -- count of data sent (not control)
xmitTime: BasicTime.Pulses, -- when first sent, or 0 if resent
rexmitTime: BasicTime.Pulses, -- time for next retransmission
timeoutTime: BasicTime.Pulses, -- time to abort connection if segment not acked
datagram: ArpaIP.Buffers]; -- datagram sent to net
TCPControlSet: TYPE ~ RECORD [
urg, ack, psh, rst, syn, fin: BOOLFALSE];
Statistics
pktsSent: INT;
pktsRcvd: INT;
pktsRexmitted: INT;
pktsDuplicate: INT;
pktsWithNoConnection: INT;
pktsFromFuture: INT;
pktsFromPast: INT;
pktsWithBadChecksum: INT;
Routines used by TCPMain
Open: PROC [tcpInfo: ArpaTCP.TCPInfo] RETURNS [handle: TCPHandle];
Attempts to open a new TCP connection. Returns a TCPHandle to use or raises ArpaTCP.Error.
Close: PROC [handle: TCPHandle];
Shut down the connection normally.
Abort: PROC [handle: TCPHandle];
Shut down the connection abnormally.
GetDataTimeout: PROC [handle: TCPHandle] RETURNS [timeout: INT];
Get the timeout associated with handle.
SetDataTimeout: PROC [handle: TCPHandle, timeout: INT];
Reset the timeout associated with handle.
WaitForListenerOpen: PROC [handle: TCPHandle, timeout: INT];
Wait until the listening connection on this socket is open.
SendCurrentDatagram: PROC [handle: TCPHandle, push: BOOL];
The current datagram in the handle is ready to send. Push is true if the TCP push option should be used. Empty datagrams are ignored unless push is true.
GetNextDatagram: PROC [handle: TCPHandle];
We are through with the current input datagram and would like another. Only returns when new datagram has usable data.
SetUrgent: PROC [handle: TCPHandle];
The urgent pointer is set to the current position in the output stream.
WaitForUrgentData: PROC [handle: TCPHandle] RETURNS [urgentIndex: INT];
Wait asynchronously for urgent data indication.
Routines internal to the TCP stuff
The following two procedures swap the halves of a long int for the encapsulation. Stolen from the pup software.
Flip: PROC [Pair] RETURNS [INT] = TRUSTED MACHINE CODE
BEGIN PrincOps.zEXCH; END;
Flop: PROC [INT] RETURNS [Pair] = TRUSTED MACHINE CODE
BEGIN PrincOps.zEXCH; END;
TCPChecksum: PROC [data: ArpaIP.Buffers] RETURNS [checksum: ArpaTCP.DByte];
Find the checksum to be used in the TCP header. Call when data.dataLength is the correct length of the packet.
ChecksumsMatch: PROC [c1, c2: ArpaTCP.DByte] RETURNS [BOOL];
True if c1 and c2 are the same checksum, i.e. they are equal or are both one's complement representations of zero.
SetTimeout: PROC [delta: INT, base: BasicTime.Pulses ← BasicTime.GetClockPulses[]] RETURNS [BasicTime.Pulses];
Returns a timeout time computed by adding delta milliseconds to the specified base time. If delta is negative, meaning "never time out", returns zero, which is specifically defined (in TimedOut) to mean "never time out" and is never otherwise returned.
TimedOut: PROC [timeoutTime: BasicTime.Pulses] RETURNS [BOOL];
Returns true if the specified time has been reached.
END.