-- NetworkStreamMgr.mesa (last edited by: Garlick on: January 26, 1981 11:02 AM) -- Function: The implementation module for the manager of Pilot Network Streams. DIRECTORY BufferDefs USING [OisBuffer], CommunicationInternal USING [], NetworkStream USING [ ConnectionID, ConnectionFailed, ConnectionSuspended, unknownConnID, WaitTime, ClassOfService, CloseStatus, closeSST, closeReplySST, defaultWaitTime, ListenTimeout, infiniteWaitTime], NetworkStreamInstance USING [], NetworkStreamInternal USING [CloseState, ControlHandle], OISCP USING [ReturnFreeOisBuffer], OISCPTypes USING [ConnectionID], PacketStream USING [ ConnectionAlreadyThere, FindAddresses, Handle, Make, SetWaitTime], Router USING [XmitStatus], Socket USING [ Abort, AssignNetworkAddress, ChannelAborted, ChannelError, ChannelHandle, Create, Delete, GetPacket, SetWaitTime, TimeOut], SocketInternal USING [ SocketHandle, SocketHandleToChannelHandle, ChannelHandleToSocketHandle], SpecialSystem USING [NetworkAddress, nullNetworkAddress], Stream USING [ Byte, Handle, PutByte, GetByte, SendNow, SetSST, SSTChange, TimeOut], System USING []; NetworkStreamMgr: PROGRAM IMPORTS NetworkStream, netStrmInst: NetworkStreamInstance, OISCP, PacketStream, Socket, SocketInternal, Stream EXPORTS CommunicationInternal, NetworkStream, System SHARES BufferDefs, NetworkStreamInstance = BEGIN OPEN NetworkStream; -- EXPORTED TYPE(S) and READONLY Variables ListenerHandle: PUBLIC TYPE = SocketInternal.SocketHandle; NetworkAddress: PUBLIC TYPE = SpecialSystem.NetworkAddress; uniqueNetworkAddr: PUBLIC NetworkAddress ← SpecialSystem.nullNetworkAddress; IllegalAddress: PUBLIC ERROR = CODE; ListenTimeout: PUBLIC SIGNAL = CODE; -- Cool Procedures -- This procedure creates a network stream to the specified remote address. Create: PUBLIC PROCEDURE [ remote: NetworkAddress, timeout: WaitTime ← defaultWaitTime, classOfService: ClassOfService ← bulk] RETURNS [Stream.Handle] = BEGIN RETURN[ CreateTransducer[ uniqueNetworkAddr, remote, NetworkStream.unknownConnID, NetworkStream.unknownConnID, TRUE, timeout, classOfService]]; END; -- Create AssignNetworkAddress: PUBLIC PROCEDURE RETURNS [NetworkAddress] = BEGIN RETURN[Socket.AssignNetworkAddress[]]; END; -- AssignNetworkAddress -- This procedure returns the local and remote addresses of the Network Stream. FindAddresses: PUBLIC PROCEDURE [sH: Stream.Handle] RETURNS [local, remote: NetworkAddress] = BEGIN [local, remote] ← PacketStream.FindAddresses[ LOOPHOLE[sH, NetworkStreamInternal.ControlHandle].psH]; END; -- FindAddresses -- This procedure sets the wait time for the Network Stream. SetWaitTime: PUBLIC PROCEDURE [sH: Stream.Handle, time: WaitTime] = BEGIN PacketStream.SetWaitTime[ LOOPHOLE[sH, NetworkStreamInternal.ControlHandle].psH, time]; END; -- SetWaitTime -- This procedure creates a listener at the specified local Network Address. -- The generation of IllegalAddress will become more sophisticated. -- We enqueue all the buffers onto the socket channel. CreateListener: PUBLIC PROCEDURE [addr: NetworkAddress] RETURNS [lH: ListenerHandle] = BEGIN listenerSendBuffers: CARDINAL = 0; listenerReceiveBuffers: CARDINAL = 2; lH ← SocketInternal.ChannelHandleToSocketHandle[ Socket.Create[ addr, listenerSendBuffers, listenerReceiveBuffers, 0, FALSE ! Socket.ChannelError => GOTO bad]]; EXITS bad => RETURN WITH ERROR IllegalAddress; END; -- CreateListener -- This procedure deletes a listener. DeleteListener: PUBLIC PROCEDURE [listenerH: ListenerHandle] = BEGIN -- We assume that there are no processes doing a Listen. -- The Listen code is such that it always does a Socket.Get leaving the buffer with -- the socket channel. Socket.Abort[SocketInternal.SocketHandleToChannelHandle[listenerH]]; Socket.Delete[SocketInternal.SocketHandleToChannelHandle[listenerH]]; END; -- DeleteListener -- This procedure creates a sequenced packet transducer with all its parameters. CreateTransducer: PUBLIC PROCEDURE [ local, remote: NetworkAddress, localConnID, remoteConnID: NetworkStream.ConnectionID, activelyEstablish: BOOLEAN, timeout: NetworkStream.WaitTime ← defaultWaitTime, classOfService: ClassOfService ← bulk] RETURNS [sH: Stream.Handle] = BEGIN psH: PacketStream.Handle; newNetStrmInst: POINTER TO FRAME[NetworkStreamInstance]; psH ← PacketStream.Make[ local, remote, LOOPHOLE[localConnID, OISCPTypes.ConnectionID], LOOPHOLE[remoteConnID, OISCPTypes.ConnectionID], activelyEstablish, timeout, classOfService]; newNetStrmInst ← NEW netStrmInst; sH ← START newNetStrmInst[psH]; END; -- CreateTransducer -- These procedures define an optional close protocol using the exchange of reserved -- subsequence types on the client's behalf. -- This procedure closes communication over a network stream at the client's -- level of protocol. The semantics are I want to close the stream, therefore I do -- not want to transmit any more data and only want to know that the remote -- end is aware of my actions. Any input data arriving on the stream may be discarded. -- The status is good, noReply if the other end just did not respond, and incomplete if it -- was a simultaneous close and the third data packet did not make it and the other -- end is gone. Close: PUBLIC PROCEDURE [sH: Stream.Handle] RETURNS [status: NetworkStream.CloseStatus] = BEGIN state: NetworkStreamInternal.CloseState ← sendClose; dataByte: Stream.Byte ← 0; status ← good; Stream.SetSST[sH, NetworkStream.closeSST]; Stream.PutByte[sH, dataByte]; Stream.SendNow[sH]; state ← waitCloseReply; UNTIL state = closed OR state = sendCloseReply DO dataByte ← Stream.GetByte[ sH ! Stream.SSTChange => BEGIN IF sst = NetworkStream.closeReplySST THEN BEGIN -- tricky we are diddling the stream from within a catch phrase Stream.SetSST[sH, NetworkStream.closeReplySST]; Stream.PutByte[sH, dataByte]; Stream.SendNow[sH]; state ← closed; END ELSE IF sst = NetworkStream.closeSST THEN state ← sendCloseReply; -- simultaneous close RESUME ; END; Stream.TimeOut => BEGIN status ← noReply; state ← closed; EXIT; END; NetworkStream.ConnectionSuspended => BEGIN status ← noReply; state ← closed; EXIT; END]; ENDLOOP; IF state = sendCloseReply THEN status ← CloseReply[sH]; END; -- Close -- This procedure conforms to the close protocol and is invoked by the client of -- a network stream when it receives a subsequence change to closeSST. The -- semantics of this call are that the client knows that the other end wants to -- close the communication and it will not transmit any more data and will reply -- with a closeReplySST. The status can be good, or incomplete; the latter implying -- that an answer to the closeReplySST did not make it back and the other end is -- gone, or that the closeReply was never acked. CloseReply: PUBLIC PROCEDURE [sH: Stream.Handle] RETURNS [status: NetworkStream.CloseStatus] = BEGIN state: NetworkStreamInternal.CloseState ← sendCloseReply; dataByte: Stream.Byte ← 0; status ← good; Stream.SetSST[sH, NetworkStream.closeReplySST]; Stream.PutByte[sH, dataByte]; Stream.SendNow[sH]; state ← waitCloseReplyReply; UNTIL state = closed DO dataByte ← Stream.GetByte[ sH ! Stream.SSTChange => BEGIN IF sst = NetworkStream.closeReplySST THEN state ← closed; RESUME ; END; Stream.TimeOut => BEGIN status ← incomplete; state ← closed; EXIT; END; NetworkStream.ConnectionSuspended => BEGIN status ← noReply; state ← closed; EXIT; END]; ENDLOOP; END; -- CloseReply -- Hot Procedures -- This procedure listens on the specified socket channel for a sequenced packet, and -- creates a network stream from another unique local socket to the remote end. -- This procedure checks to make sure that the arriving packet is not a duplicate. Listen: PUBLIC PROCEDURE [ listenerH: ListenerHandle, listenTimeout: NetworkStream.WaitTime ← infiniteWaitTime, streamTimeout: NetworkStream.WaitTime ← infiniteWaitTime, classOfService: ClassOfService ← bulk] RETURNS [Stream.Handle] = BEGIN OPEN SocketInternal; b: BufferDefs.OisBuffer; sH: Stream.Handle; Socket.SetWaitTime[SocketHandleToChannelHandle[listenerH], listenTimeout]; DO -- until the packet is a sequenced packet and is not a duplicate, or timeout, or aborted socket sH ← NIL; b ← LOOPHOLE[Socket.GetPacket[ SocketInternal.SocketHandleToChannelHandle[listenerH] ! Socket.TimeOut => {SIGNAL NetworkStream.ListenTimeout; RETRY}; Socket.ChannelAborted => EXIT], BufferDefs.OisBuffer]; -- b is NIL if client aborted this process -- b.status can be one of the errors or goodCompletion IF b # NIL AND LOOPHOLE[b.status, Router.XmitStatus] = goodCompletion THEN BEGIN IF b.ois.transCntlAndPktTp.packetType = sequencedPacket THEN BEGIN -- examine this packet IF b.ois.destinationConnectionID = unknownConnID AND b.ois.sourceConnectionID # unknownConnID AND b.ois.sequenceNumber = 0 AND b.ois.systemPacket THEN BEGIN -- good packet, but must see if this is an old duplicate IF NOT PacketStream.ConnectionAlreadyThere[ b.ois.source, b.ois.sourceConnectionID] THEN BEGIN source: SpecialSystem.NetworkAddress ← b.ois.source; remoteConnID: NetworkStream.ConnectionID ← LOOPHOLE[b.ois.sourceConnectionID]; OISCP.ReturnFreeOisBuffer[b]; sH ← CreateTransducer[ uniqueNetworkAddr, source, NetworkStream.unknownConnID, remoteConnID, TRUE, streamTimeout, classOfService ! ConnectionFailed => BEGIN sH ← NIL; CONTINUE; END]; EXIT; END; END; END; END; OISCP.ReturnFreeOisBuffer[b]; ENDLOOP; -- NIL sH means client aborted via DeleteListener or Process.Abort RETURN[sH]; END; -- Listen -- initialization (Cold) END. -- NetworkStreamMgr module LOG Time: May 9, 1978 1:12 PM By: Dalal Action: created file. Time: August 31, 1979 1:14 PM By: Dalal Action: modified Listener routines. Time: January 26, 1980 2:51 PM By: Dalal Action: moved stuff to PacketStreamMgr. Time: April 15, 1980 10:22 AM By: BLyon Action: uses new Level1 routines. Time: July 15, 1980 11:11 AM By: BLyon Action: Use exported types. Time: September 29, 1980 3:51 PM By: BLyon Action: Listener catches Socket.ChannelAborted. Time: January 26, 1981 11:02 AM By: Garlick Action: 1) Listener generates resumeable signal on timeout and also allows client to use Process.Abort. 2) added class of service to Create, CreateTransducer, Listen.