-- 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.