<> <> <> <> <> <> <> <> <> 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 <> 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 <> 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): BOOL _ FALSE, -- control flags, urgent ack (6: 11..11): BOOL _ FALSE, -- acknowledgement psh (6: 12..12): BOOL _ FALSE, -- push rst (6: 13..13): BOOL _ FALSE, -- reset syn (6: 14..14): BOOL _ FALSE, -- syn (first packet on connection) fin (6: 15..15): BOOL _ FALSE, -- 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 <> 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 <> 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: BOOL _ FALSE, -- 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 <> rcvNxt: INT _ 0, -- next seq number to receive rcvWnd: INT, -- receive window rcvUp: INT _ 0, -- receive urgent pointer zeroRcvWnd: BOOL _ FALSE, -- last advertised receive window was zero irs: INT _ 0, -- initial receive sequence number urgentMode: BOOL _ FALSE, -- rcvd urgent data and not passed to user <> 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 <> rtt: INT, <> rexmits: INT _ 0, duplicates: INT _ 0 ]; <> 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 <> 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 <> 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: BOOL _ FALSE]; <> pktsSent: INT; pktsRcvd: INT; pktsRexmitted: INT; pktsDuplicate: INT; pktsWithNoConnection: INT; pktsFromFuture: INT; pktsFromPast: INT; pktsWithBadChecksum: INT; <> Open: PROC [tcpInfo: ArpaTCP.TCPInfo] RETURNS [handle: TCPHandle]; <> Close: PROC [handle: TCPHandle]; <> Abort: PROC [handle: TCPHandle]; <> GetDataTimeout: PROC [handle: TCPHandle] RETURNS [timeout: INT]; <> SetDataTimeout: PROC [handle: TCPHandle, timeout: INT]; <> WaitForListenerOpen: PROC [handle: TCPHandle, timeout: INT]; <> SendCurrentDatagram: PROC [handle: TCPHandle, push: BOOL]; <> GetNextDatagram: PROC [handle: TCPHandle]; <> SetUrgent: PROC [handle: TCPHandle]; <> WaitForUrgentData: PROC [handle: TCPHandle] RETURNS [urgentIndex: INT]; <> <> <> 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]; <> ChecksumsMatch: PROC [c1, c2: ArpaTCP.DByte] RETURNS [BOOL]; <> SetTimeout: PROC [delta: INT, base: BasicTime.Pulses _ BasicTime.GetClockPulses[]] RETURNS [BasicTime.Pulses]; <> TimedOut: PROC [timeoutTime: BasicTime.Pulses] RETURNS [BOOL]; <> END.