PacketExchangeImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
BLyon March 2, 1981 11:43 AM
Levin, August 9, 1983 9:18 am
DIRECTORY
Basics USING [LongNumber],
BufferDefs USING [Buffer, BufferAccessHandle,FreeBufferPool, MakeBufferPool, OisBuffer],
CommunicationInternal USING [],
DriverDefs USING [DriverXmitStatus, Glitch],
PacketExchange USING [ErrorReason, maxBlockLength, RequestHandle, RequestObject],
OISCP USING [GetFreeSendOisBufferFromPool, ReturnFreeOisBuffer, unknownNetID],
OISCPTypes USING [bytesPerExchangeHeader, bytesPerPktHeader, ExchangeID, ExchangeClientType, WaitTime],
PacketExchangeInternal USING [],
PrincOps USING [ByteBltBlock],
PrincOpsUtils USING [ByteBlt],
Process USING [InitializeCondition, MsecToTicks],
ProcessorFace USING [GetClockPulses],
Router USING [FindMyHostID],
NSAddress USING [broadcastHostNumber, NetworkAddress, nullNetworkAddress, SocketNumber],
Socket USING [Abort, AssignNetworkAddress, ChannelAborted, ChannelHandle, Create, Delete, GetPacket, PutPacket, SetWaitTime, TimeOut];
PacketExchangeImpl: MONITOR
IMPORTS DriverDefs, PrincOpsUtils, OISCP, Process, ProcessorFace, Router, Socket
EXPORTS CommunicationInternal, PacketExchange, PacketExchangeInternal
SHARES BufferDefs, PacketExchange = BEGIN
The Packet Exchange Protocol is a request/reply protocol that provides a little more
reliability than raw packets transmitetd from a socket, and less reliabilty than the
Sequenced Packet Protocol. Usually one end will provide some service at a
well known socket or at a network address that is available through a binding
process involving the Clearinghouse. The other end acquires a socket and sends a
request. The request will be retransmitted a number of times with the interval
between retransmissions based on the delay to the remote entity.
NetworkAddress: PUBLIC TYPE = NSAddress.NetworkAddress;
ExchangeHandle: TYPE = REF PacketExchangeObject;
PacketExchangeObject: PUBLIC TYPE = RECORD [
cH: Socket.ChannelHandle,
sendBufferAccessHandle: BufferDefs.BufferAccessHandle];
sendCompleted: CONDITION;
uniqueNetworkAddress: PUBLIC NetworkAddress ← NSAddress.nullNetworkAddress;
sendInProgress: CARDINAL = 1;
bufferSent: CARDINAL = 2;
sendAborted: CARDINAL = 3;
retryCount: CARDINAL = 2;
bytesPerExchangePacketHeader: CARDINAL = OISCPTypes.bytesPerPktHeader + OISCPTypes.bytesPerExchangeHeader;
Timeout: PUBLIC SIGNAL = CODE;
Error: PUBLIC ERROR [why: PacketExchange.ErrorReason] = CODE;
IllegalUseOfRequeueProcedure: PUBLIC ERROR = CODE;
GetFreeSendPacket: PUBLIC PROCEDURE [h: ExchangeHandle] RETURNS [BufferDefs.OisBuffer] =
BEGIN
RETURN[OISCP.GetFreeSendOisBufferFromPool[h.sendBufferAccessHandle]];
END;
NotifySendCompleted: PRIVATE ENTRY PROCEDURE [b: BufferDefs.Buffer] =
BEGIN
b.requeueData ← bufferSent;
b.requeueProcedure ← LostBuffer;
BROADCAST sendCompleted;
END;
LostBuffer: PRIVATE PROCEDURE [b: BufferDefs.Buffer] =
BEGIN
DriverDefs.Glitch[IllegalUseOfRequeueProcedure];
END;
Caller has responsibility for returning requestB ,
and replyB if not NIL. The pktLength, destination and exchangeType must be set
by the caller.
SendRequestPacket: PUBLIC PROCEDURE [h: ExchangeHandle, requestB: BufferDefs.OisBuffer,
replyFilter: OISCPTypes.ExchangeClientType]
RETURNS [replyB: BufferDefs.OisBuffer] =
BEGIN
WaitSendCompleted: ENTRY PROCEDURE [waitBuffer: BufferDefs.OisBuffer] RETURNS [DriverDefs.DriverXmitStatus] =
INLINE BEGIN
WHILE (waitBuffer.requeueData=sendInProgress) DO
WAIT sendCompleted;
ENDLOOP;
RETURN[LOOPHOLE[waitBuffer.status]];
END;
channelAborted: BOOLEANFALSE;
exchangeID: OISCPTypes.ExchangeID;
time: LONG CARDINAL ← ProcessorFace.GetClockPulses[];
exchangeID.a ← LOOPHOLE[time, Basics.LongNumber].highbits;
exchangeID.b ← LOOPHOLE[time, Basics.LongNumber].lowbits;
requestB.ois.transCntlAndPktTp.packetType ← packetExchange;
requestB.ois.exchangeID ← exchangeID;
THROUGH [0..retryCount) DO -- try twice
replyB ← NIL;
requestB.requeueProcedure ← NotifySendCompleted;
requestB.requeueData ← sendInProgress;
Socket.PutPacket[h.cH, requestB ! Socket.ChannelAborted =>
BEGIN
requestB.requeueData ← sendAborted;
channelAborted ← TRUE;
EXIT;
END];
SELECT WaitSendCompleted[requestB] FROM
goodCompletion => DO -- do gets until satisfied or timed out
replyB ← Socket.GetPacket[h.cH !
Socket.TimeOut => EXIT;
Socket.ChannelAborted =>
BEGIN
channelAborted ← TRUE;
EXIT;
END];
IF replyB.ois.transCntlAndPktTp.packetType=packetExchange
AND replyB.ois.exchangeID=exchangeID
AND ((replyB.ois.exchangeType=replyFilter) OR (replyFilter=unspecified))
AND (replyB.ois.source.host = requestB.ois.destination.host OR
requestB.ois.destination.host = NSAddress.broadcastHostNumber)
AND replyB.ois.source.socket=requestB.ois.destination.socket THEN RETURN
ELSE
BEGIN
OISCP.ReturnFreeOisBuffer[replyB];
replyB ← NIL;
END;
ENDLOOP; -- goodCompletion
noRouteToNetwork => RETURN WITH ERROR Error[noRouteToDestination];
ENDCASE => RETURN WITH ERROR Error[hardwareProblem];
ENDLOOP;
RETURN WITH ERROR Error[IF channelAborted THEN aborted ELSE timeout];
END; -- SendRequestPacket
SendRequest: PUBLIC PROCEDURE [h: ExchangeHandle, remote: NetworkAddress,
requestBlk, replyBlk: PrincOps.ByteBltBlock,
requestType: OISCPTypes.ExchangeClientType]
RETURNS [nBytes: CARDINAL, replyType: OISCPTypes.ExchangeClientType] =
BEGIN
blkSizeOK: BOOLEAN;
requestB, replyB: BufferDefs.OisBuffer;
blkByteLen: CARDINAL ← requestBlk.stopIndexPlusOne-requestBlk.startIndex;
IF blkByteLen>PacketExchange.maxBlockLength THEN RETURN WITH ERROR Error[blockTooBig];
requestB ← OISCP.GetFreeSendOisBufferFromPool[h.sendBufferAccessHandle];
move all info into the requestB
requestB.ois.pktLength ← bytesPerExchangePacketHeader + blkByteLen;
requestB.ois.transCntlAndPktTp.packetType ← packetExchange;
requestB.ois.destination ← remote;
requestB.ois.exchangeType ← requestType;
[] ← PrincOpsUtils.ByteBlt[[@requestB.ois.exchangeBody, 0, blkByteLen], requestBlk];
send the buffer (many times in case of timeouts) and extract info from reply buffer.
BEGIN ENABLE UNWIND => OISCP.ReturnFreeOisBuffer[requestB];
replyB ← SendRequestPacket[h, requestB, unspecified
! Error => BEGIN
IF why=timeout THEN
BEGIN
inside catch phrases geneated new signal and catch RESUME
SIGNAL Timeout;
RETRY; -- caller RESUMEs => RETRY; caller does anything else => UNWIND.
END
all other error shot through to the client;
END];
END;
OISCP.ReturnFreeOisBuffer[requestB];
replyType ← replyB.ois.exchangeType;
nBytes ← replyB.ois.pktLength - bytesPerExchangePacketHeader;
blkByteLen ← replyBlk.stopIndexPlusOne - replyBlk.startIndex;
IF blkSizeOK ← ((nBytes<=blkByteLen)
AND (replyBlk.startIndex<=replyBlk.stopIndexPlusOne))
THEN nBytes ← PrincOpsUtils.ByteBlt[replyBlk, [@replyB.ois.exchangeBody, 0, blkByteLen]];
OISCP.ReturnFreeOisBuffer[replyB];
IF NOT blkSizeOK THEN
BEGIN
nBytes ← 0;
RETURN WITH ERROR Error[blockTooSmall];
END;
END; -- SendRequest
WaitForRequestPacket: PUBLIC PROCEDURE [h: ExchangeHandle, request: OISCPTypes.ExchangeClientType] RETURNS [requestB: BufferDefs.OisBuffer] =
BEGIN
channelAborted: BOOLEANFALSE;
THROUGH [0..retryCount) DO -- try twice
requestB ← NIL;
DO -- do gets until satisfied or timed out
requestB ← Socket.GetPacket[h.cH !
Socket.TimeOut => EXIT;
Socket.ChannelAborted =>
BEGIN
channelAborted ← TRUE;
EXIT;
END];
IF requestB.ois.transCntlAndPktTp.packetType=packetExchange
AND ((requestB.ois.exchangeType=request) OR (request=unspecified)) THEN RETURN
ELSE
BEGIN
OISCP.ReturnFreeOisBuffer[requestB];
requestB ← NIL;
END;
ENDLOOP; -- get loop
ENDLOOP;
RETURN WITH ERROR Error[IF channelAborted THEN aborted ELSE timeout];
END; -- WaitForRequestPacket
WaitForRequest: PUBLIC PROCEDURE [h: ExchangeHandle, requestBlk: PrincOps.ByteBltBlock,
requiredRequestType: OISCPTypes.ExchangeClientType]
RETURNS [rH: PacketExchange.RequestHandle ← NIL] =
BEGIN
blkSizeOK: BOOLEAN;
nBytes, blkByteLen: CARDINAL;
requestB: BufferDefs.OisBuffer;
requestB ← WaitForRequestPacket[h, requiredRequestType
! Error => BEGIN
IF why=timeout THEN
BEGIN
the compiler should love this:
SIGNAL Timeout;
RETRY; -- caller RESUMEs => RETRY
END;
all other error shot through to the client;
END];
nBytes ← requestB.ois.pktLength - bytesPerExchangePacketHeader;
blkByteLen ← requestBlk.stopIndexPlusOne - requestBlk.startIndex;
IF blkSizeOK ← ((nBytes<=blkByteLen)
AND (requestBlk.startIndex<=requestBlk.stopIndexPlusOne)) THEN
BEGIN
rH ← NEW[PacketExchange.RequestObject];
rH^ ← [
nBytes: PrincOpsUtils.ByteBlt[requestBlk, [@requestB.ois.exchangeBody, 0, nBytes]],
requestType: requestB.ois.exchangeType,
requestersAddress: requestB.ois.source,
requestersExchangeID: requestB.ois.exchangeID];
END;
OISCP.ReturnFreeOisBuffer[requestB];
IF NOT blkSizeOK THEN RETURN WITH ERROR Error[blockTooSmall];
END; -- WaitForRequest
The length must be set by the caller. We now own buffer replyB.
SendReplyPacket: PUBLIC PROCEDURE [h: ExchangeHandle, replyB: BufferDefs.OisBuffer] =
BEGIN
channelAborted: BOOLEANFALSE;
Socket.PutPacket[h.cH, replyB! Socket.ChannelAborted =>
BEGIN
replyB.requeueProcedure[replyB];
channelAborted ← TRUE;
CONTINUE;
END];
IF channelAborted THEN RETURN WITH ERROR Error[aborted];
END; -- SendReplyPacket
we now own rH and we if no errors are encountered free it
SendReply: PUBLIC PROCEDURE [h: ExchangeHandle, rH: PacketExchange.RequestHandle, replyBlk: PrincOps.ByteBltBlock, replyType: OISCPTypes.ExchangeClientType] =
BEGIN
replyB: BufferDefs.OisBuffer;
blkByteLen: CARDINAL ← replyBlk.stopIndexPlusOne-replyBlk.startIndex;
IF blkByteLen>PacketExchange.maxBlockLength THEN RETURN WITH ERROR Error[blockTooBig];
replyB ← OISCP.GetFreeSendOisBufferFromPool[h.sendBufferAccessHandle];
move all info into the replyB
replyB.ois.pktLength ← bytesPerExchangePacketHeader + blkByteLen;
replyB.ois.transCntlAndPktTp.packetType ← packetExchange;
replyB.ois.destination ← rH.requestersAddress;
replyB.ois.exchangeType ← replyType;
replyB.ois.exchangeID ← rH.requestersExchangeID;
[] ← PrincOpsUtils.ByteBlt[[@replyB.ois.exchangeBody, 0, blkByteLen], replyBlk];
SendReplyPacket[h, replyB
! Error => IF why=aborted THEN OISCP.ReturnFreeOisBuffer[replyB]];
Heap.FreeNode[p: rH];--
END; -- SendReply
Create: PUBLIC PROCEDURE [localSocket: NSAddress.SocketNumber,
receiveRequestCount: CARDINAL, privateBuffers: BOOLEAN,
waitTime: OISCPTypes.WaitTime]
RETURNS [h: ExchangeHandle] =
BEGIN
sendRequestCount: CARDINAL = 1;
me: NetworkAddress = [OISCP.unknownNetID, Router.FindMyHostID[], localSocket];
h ← NEW[PacketExchangeObject];
h.sendBufferAccessHandle ← BufferDefs.MakeBufferPool[sendRequestCount, sendRequestCount, 0, 0, FALSE];
h.cH ← Socket.Create[me, 0, receiveRequestCount, 0, privateBuffers];
Socket.SetWaitTime[h.cH, (waitTime/retryCount)+1];
END; -- CreateInternal
CreateRequestor: PUBLIC PROCEDURE [waitTime: OISCPTypes.WaitTime] RETURNS [h: ExchangeHandle] =
BEGIN
me: NetworkAddress ← Socket.AssignNetworkAddress[];
h ← Create[me.socket, 2, TRUE, waitTime];
END;
CreateReplyer: PUBLIC PROCEDURE [localSocket: NSAddress.SocketNumber, requestCount: CARDINAL,
waitTime: OISCPTypes.WaitTime]
RETURNS [h: ExchangeHandle] =
BEGIN
h ← Create[localSocket, requestCount, TRUE, waitTime];
END;
Delete: PUBLIC PROCEDURE [h: ExchangeHandle] =
BEGIN
Socket.Abort[h.cH];
BufferDefs.FreeBufferPool[h.sendBufferAccessHandle];
Socket.Delete[h.cH];
Heap.FreeNode[p: h];--
END; -- Delete
SetWaitTime: PUBLIC PROCEDURE [h: ExchangeHandle, waitTime: OISCPTypes.WaitTime] =
BEGIN
Socket.SetWaitTime[h.cH, (waitTime/retryCount)+1];
END; -- SetWaitTime
MainLine Code
Process.InitializeCondition[@sendCompleted, Process.MsecToTicks[2000]];
END.\795t10 12t0 61t10 6t0 105b18B225i572I568i1bI7B24b5B57b28B24b17B160b19B162b10B115i156bI17B171b17B585i13I114i1I1031i18I224i21I3b12B868i89I63i1I109i4I2i61I35i67I11i2I2i46I553i16I3b21B193i13I528i12I92i24I3b15B2t10 7t0 378i39I35i28I12i50I682i18I6i68bI15B335i20bI1Bi61bI9B420i35I474i13I6t10b6B33t0 14t10 47t0 14t10 13t0 29t10 13t0 17t10 1t0 13t10 26t0 73t10 11t0 84t10 10t0 16t10 47t0 28t10 29t0 76i5t10 15t0I1t10b15B19t0 32t10 9t0 17t10 1t0 71t10 6t0 40t10b13B1i1I31t0 14t10 36t0 33t10 1t0 2t10 10t0 17t10 1t0 17t10 6t0 1t10 11t0 2t10 14t0 24i1I1t10b6B20t0 17t10 29t0 2t10 16t0 14t10 3t0 22t10 21t0 2t10 3t0 23t10 5t0 1i4t10 6t0I2i1I1t10b11B20t0 48t10 12t0 53t10 5t0 1i4t10 30t0I7t10 1t0 19t10 1t0 41t10 3t0
LOG
Time: November 10, 1980 9:57 AM By: Dalal Action: created file.
Time: January 13, 1981 6:06 PM By: BLyon Action: Moved to Pilot Communication.
\1i