DIRECTORY BasicTime USING [Now], IPDefs USING [Datagram, DatagramRec, DByte, Address, nullAddress], List USING [Append, Nconc1, Remove], Process USING [DisableTimeout, MsecToTicks, SetTimeout], TCP USING [Error, maxTimeout, Reason, TCPInfo], TCPLogging USING [PrintStateChange], TCPOps USING [defaultReceiveWindow, maxTCPDataLength, TCPHandle, TCPHandleRec, tcpHdrByteLength, TCPHeaderP], TCPStates, TCPTransmit USING [SendFIN, SendReset, SendSYN]; TCPStatesImpl: CEDAR MONITOR -- monitors the handleList IMPORTS BasicTime, List, Process, TCP, TCPLogging, TCPOps, TCPTransmit EXPORTS TCPStates ~ BEGIN OPEN TCPOps, TCPStates; handleList: LIST OF REF ANY; -- list of all open TCP connections nextLocalPort: CARDINAL _ 256; -- avoid well-known sockets lastSequenceNumber: INT _ LOOPHOLE[BasicTime.Now[]]; -- used to general initial sequence numbers Close: PUBLIC PROC [handle: TCPHandle] ~ { ValidHandle[handle]; SELECT handle.state FROM listen, synSent => CloseConnection[handle, localClose]; synRcvd, established => {-- send fin after all preceeding sends TCPTransmit.SendFIN[handle]; -- send fin and ack TCPLogging.PrintStateChange[handle, finWait1]; handle.state _ finWait1; handle.reason _ localClose; }; closeWait => {-- send fin after all preceeding sends TCPTransmit.SendFIN[handle]; TCPLogging.PrintStateChange[handle, lastAck]; handle.state _ lastAck; }; closing, lastAck, timeWait => -- connection is closing NULL; -- so what? ENDCASE; }; -- Close Abort: PUBLIC PROC [handle: TCPHandle] ~ { ValidHandle[handle ! TCP.Error => GO TO GiveUp]; SELECT handle.state FROM listen, synSent => CloseConnection[handle, localAbort]; synRcvd, established, finWait1, finWait2, closeWait => { TCPTransmit.SendReset[handle, handle.localPort, handle.foreignPort, handle.foreignAddr, handle.sndNxt, handle.rcvNxt]; CloseConnection[handle, localAbort]; }; closing, lastAck, timeWait => CloseConnection[handle, localAbort]; ENDCASE; EXITS GiveUp => NULL; }; -- Abort GetInitialSequenceNumber: PUBLIC PROC RETURNS [INT] = { lastSequenceNumber _ lastSequenceNumber*1037 + 12345; RETURN [ABS[lastSequenceNumber]]; }; Open: PUBLIC ENTRY PROC [tcpInfo: TCP.TCPInfo] RETURNS [handle: TCPHandle] ~ { ENABLE UNWIND => NULL; IF FindConflictingConn[tcpInfo] # NIL THEN RETURN WITH ERROR TCP.Error[localConflict]; IF tcpInfo.active THEN IF NOT (tcpInfo.matchForeignPort AND tcpInfo.matchForeignAddr) THEN RETURN WITH ERROR TCP.Error[unspecifiedRemoteEnd] ELSE { handle _ CreateHandle[tcpInfo]; handle.iss _ GetInitialSequenceNumber[]; handle.sndUna _ handle.iss; TCPLogging.PrintStateChange[handle, synSent]; handle.state _ synSent; TCPTransmit.SendSYN[handle]; -- send SYN } ELSE { handle _ CreateHandle[tcpInfo]; TCPLogging.PrintStateChange[handle, listen]; handle.state _ listen; }; handleList _ List.Nconc1[handleList, handle]; }; CloseConnection: PUBLIC ENTRY PROC [handle: TCPHandle, reason: TCP.Reason] = { ENABLE UNWIND => NULL; Kill[handle.toNetQueue]; handle.toNetQueue _ NIL; Kill[handle.rexmitQueue]; handle.rexmitQueue _ NIL; TCPLogging.PrintStateChange[handle, closed]; handle.state _ closed; handle.reason _ reason; handleList _ List.Remove[handle, handleList]; BROADCAST handle.windowAvailable; -- make sure everyone finds out. BROADCAST handle.urgentAvailable; BROADCAST handle.dataAvailable; BROADCAST handle.notListening; }; -- CloseConnection Kill: PROC [list: LIST OF REF ANY] = { DO temp: LIST OF REF ANY _ list; IF temp = NIL THEN RETURN; list _ list.rest; temp.first _ NIL; temp.rest _ NIL; ENDLOOP; }; ValidHandle: PUBLIC ENTRY PROC [handle: TCPHandle] ~ { ENABLE UNWIND => NULL; FOR l: LIST OF REF ANY _ handleList, l.rest WHILE l # NIL DO IF l.first = handle THEN RETURN; ENDLOOP; RETURN WITH ERROR TCP.Error[IF handle = NIL THEN neverOpen ELSE handle.reason]; }; FindHandle: PUBLIC ENTRY PROC [rcvdDatagram: IPDefs.Datagram] RETURNS [handle: TCPHandle] ~ TRUSTED { ENABLE UNWIND => NULL; tcpHdrPtr: TCPHeaderP _ LOOPHOLE[@rcvdDatagram.data]; sourceAddr: IPDefs.Address; sourcePort: IPDefs.DByte; dstnPort: IPDefs.DByte; goodHandle: TCPHandle; sourceAddr _ rcvdDatagram.inHdr.source; sourcePort _ tcpHdrPtr^.sourcePort; dstnPort _ tcpHdrPtr^.dstnPort; goodHandle _ NIL; FOR l: LIST OF REF ANY _ handleList, l.rest WHILE l # NIL DO h: TCPOps.TCPHandle _ NARROW[l.first]; IF h.localPort = dstnPort AND (h.foreignAddr = sourceAddr OR NOT h.matchForeignAddr) AND (h.foreignPort = sourcePort OR NOT h.matchForeignPort) THEN IF h.matchForeignAddr AND h.matchForeignPort THEN RETURN [h] -- found exact match, return TCB ELSE -- match TCB with foreign address or port not specified IF h.matchForeignAddr THEN -- address match is best goodHandle _ h ELSE IF h.matchForeignPort AND goodHandle = NIL THEN goodHandle _ h ELSE IF goodHandle = NIL THEN goodHandle _ h; ENDLOOP; RETURN [goodHandle] -- best match found }; -- FindTCB CopyHandleList: PUBLIC ENTRY PROC RETURNS [handleListCopy: LIST OF REF ANY] ~ { ENABLE UNWIND => NULL; RETURN [List.Append[handleList, NIL]]; }; FindConflictingConn: INTERNAL PROC [info: TCP.TCPInfo] RETURNS [conflictingHandle: TCPHandle] = { FOR q: LIST OF REF ANY _ handleList, q.rest WHILE q # NIL DO thisHandle: TCPHandle _ NARROW[q.first]; IF thisHandle.localPort = info.localPort AND info.matchLocalPort AND thisHandle.foreignAddr = info.foreignAddress AND info.matchForeignAddr AND thisHandle.foreignPort = info.foreignPort AND info.matchForeignPort THEN RETURN [thisHandle]; ENDLOOP; RETURN [NIL]; -- no conflict }; -- FindConflictingConn CreateHandle: PROC [info: TCP.TCPInfo] RETURNS [handle: TCPHandle] = { handle _ NEW[TCPHandleRec]; IF info.matchLocalPort THEN handle.localPort _ info.localPort ELSE DO -- assign local port automatically and ensure it doesn't match any existing one handle.localPort _ nextLocalPort; nextLocalPort _ MAX[nextLocalPort+1, 256]; -- avoid well-known sockets FOR q: LIST OF REF ANY _ handleList, q.rest WHILE q#NIL DO IF NARROW[q.first, TCPHandle].localPort=handle.localPort THEN EXIT; -- try again REPEAT FINISHED => GOTO ok; ENDLOOP; REPEAT ok => NULL; ENDLOOP; IF info.matchForeignAddr THEN handle.foreignAddr _ info.foreignAddress ELSE handle.foreignAddr _ IPDefs.nullAddress; IF info.matchForeignPort THEN handle.foreignPort _ info.foreignPort ELSE handle.foreignPort _ 0; handle.matchForeignAddr _ info.matchForeignAddr; handle.matchForeignPort _ info.matchForeignPort; handle.state _ closed; handle.reason _ neverOpen; handle.active _ info.active; handle.maxSegmentSize _ maxTCPDataLength; handle.rcvWnd _ defaultReceiveWindow; handle.fromNetQueue _ NIL; handle.readyToReadQueue _ NIL; handle.currentInputBuffer _ NIL; handle.toNetQueue _ NIL; handle.rexmitQueue _ NIL; handle.currentOutputDatagram _ NEW[IPDefs.DatagramRec]; handle.currentOutputPtr _ tcpHdrByteLength; handle.currentOutputLimit _ handle.currentOutputPtr+handle.maxSegmentSize; handle.dataTimeout _ MIN[info.timeout, TCP.maxTimeout]; TRUSTED { IF handle.dataTimeout>=0 THEN { Process.SetTimeout[@handle.dataAvailable, Process.MsecToTicks[MIN[handle.dataTimeout, 10000]]]; Process.SetTimeout[@handle.windowAvailable, Process.MsecToTicks[MIN[handle.dataTimeout, 10000]]]} ELSE Process.DisableTimeout[@handle.dataAvailable]; }; }; -- CreateHandle END. ΌCopyright (C) 1984 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. TCPStatesImpl.mesa Last Edited by: Nichols, September 1, 1983 4:23 pm Last Edited by: Taft, January 4, 1984 10:11 am Last Edited by: HGM, March 27, 1984 3:23:42 am PST Hal Murray May 16, 1985 3:15:32 am PDT John Larson, April 14, 1986 11:26:36 pm PST Close the TCP connection; returns an error if the connection does not exist or is already closing. Sends a FIN to the remote TCP. Note that the user may receive more data from the remote TCP after calling Close; when the connection is closed, the user will receive a message in which the data is a pointer to a ControlInfo record which contains a pointer to the TCB and the reason for closing. This is the last message that the user receives on the connection; on receipt, the user can delete all connection specific information. Abort the connection. This routine sends a TCP Reset if necessary; it calls CloseConnection to dispose of all the connection specific storage and to send a message to the user. The data in this message is a pointer to a ControlInfo record containing a pointer to the TCB and the reason the connection was closed (UserAbort). On receipt of this message, the user can dispose of all connection specific information. Generate an initial send sequence number for a connection. Attempts to open a new TCP connection. Returns a TCPHandle to use or raises TCP.OpenFailed if the Open request conflicts with an existing request or is a duplicate Open request on the same connection. The connection is open either in the LISTEN or SYNSENT state. In the LISTEN state, wait for a SYN from the remote TCP; in the SYNSENT state, send a SYN to initiate the connection. If an Open call is done to open a connection in the LISTEN state, then another Open call can be done to send the SYN and put the connection in the SYNSENT state. open listening connection Clear off the transmit and retransmit queues and remove this handle form the list. Check if handle given as argument by user is valid. Called by Abort, Close, and Send. Raises TCP.StreamClosing if bad handle, else it just returns. Find matching handle for segment received from the net. Make a copy of the handle list for the retransmit procedure to look at. Checks for conflicting handles; i.e. handles which have the same local and foreign ports; if such a handle exists, then return a pointer to it; used in user open call to determine if user connection request conflicts with existing connection. Κ “– "cedar" style˜Icode2šœ©™©head™J™2J™.J™2Icode™&M™+J™šΟk ˜ Kšœ œ˜Kšœœ6˜BKšœœ˜$Kšœœ+˜8Kšœœ&˜/Kšœ œ˜$Kšœœa˜mK˜ Kšœ œ˜0——šΟn œœœΟc˜8Kšœœ!˜FKšœ ˜Kšœœœ˜Kš œ œœœœŸ#˜AKšœœŸ˜:KšœœœŸ+˜`šžœœœ˜*Kšœ•™•Kšœ˜šœœ˜Kšœ7˜7šœŸ'˜@KšœŸ˜1Kšœ.˜.Kšœ˜K˜Kšœ˜—šœŸ'˜5Kšœ˜Kšœ-˜-Kšœ˜Kšœ˜—šœŸ˜6KšœŸ ˜—Kšœ˜ —KšœŸ ˜ —šžœœœ˜*Kšœ‘™‘Kšœœ œœ ˜0šœœ˜šœ˜Kšœ$˜$—šœ8˜8Kšœw˜wKšœ$˜$Kšœ˜—šœ˜Kšœ$˜$—Kšœ˜—š˜Kšœ œ˜—KšœŸ ˜ —š žœœœœœ˜7Kšœ;™;Kšœ5˜5Kšœœ˜!Kšœ˜—š žœœœœ œ œ˜NKšœ£™£Kšœœœ˜šœ œ˜*Kšœœœœ˜+—šœœ˜šœœœ˜CKšœœœœ˜2—šœ˜Kšœ ˜ Kšœ)˜)Kšœ˜Kšœ.˜.Kšœ˜KšœŸ ˜*K˜——šœ˜Kšœ™Kšœ˜Kšœ,˜,Kšœ˜K˜—K˜-K˜—š žœœœœœ ˜NK™RKšœœœ˜Kšœ-œ˜1Kšœ/œ˜3K˜,K˜K˜K˜-Kš œŸ ˜CKš œ˜!Kš œ˜Kš œ˜KšœŸ˜—š žœœœœœœ˜&š˜Kš œœœœœ˜Kšœœœœ˜Kšœ˜Kšœ œ˜Kšœ œ˜Kšœ˜ ——šž œœœœ˜7Kšœ•™•Kšœœœ˜šœœœœœœœ˜<šœ˜Kšœ˜—Kšœ˜—Kšœœœœœ œœ œ˜OK˜—š ž œœœœ!œœ˜eKšœ7™7Kšœœœ˜Kšœœ˜5Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ(˜(Kšœ$˜$Kšœ ˜ Kšœ œ˜šœœœœœœœ˜œ˜_Kšœ@œ˜a—Kšœ/˜3K˜—KšœŸ˜—Kšœ˜——…—V0₯