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
Doug Terry, November 20, 1987 11:43:19 am 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
maxSendBufferLength: INT ~ 4000; -- max bytes of unacked data to queue for transmission or retransmission to net
sendBufferLength: INT; -- 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; -- TCP Maximum Segment Size
sillyWindowLimit: INT ~ 40; -- try not to send when window is smaller than this
probeTimeout: INT; -- time (ms) to wait on zero window before sending a probe
defaultProbeTimeout: INT ~ 120000; -- 2 min. suggested by RFC793
ourLocalAddress: Arpa.Address;
tcpIPHandle: ArpaIP.Handle;
defaultReceiveWindow: INT;
repacketizing: BOOL; -- TRUE if data to be repacketized when retransmitted
tcpSegmentLife: INT ~ 60; -- value for time to live
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..maxSendBufferLength) ← 0, -- for repacketizing
sendSlot: INT [0..maxSendBufferLength) ← 0, -- for repacketizing
sendBuffer: ARRAY INT [0..maxSendBufferLength) OF BYTE, -- for repacketizing
nBytesToSend: INT [0..maxSendBufferLength] ← 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
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)
rexmitTime: BasicTime.Pulses, -- time to retransmit segment
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.
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.