-- File: PacketExchangeImpl.mesa - last edit:
-- AOF 16-Sep-87 14:44:16
-- SMA 27-May-86 9:26:21
-- Copyright (C) 1984, 1985, 1986, 1987 by Xerox Corporation. All rights reserved.
DIRECTORY
ByteBlt USING [ByteBlt],
CommFlags USING [doStats],
CommHeap USING [zone],
Driver USING [Glitch],
Environment USING [Block],
Inline USING [DBITAND, DBITXOR, LowHalf],
NSBuffer USING [Buffer, Body, GetBuffer, TransferStatus],
NSTypes USING [
bytesPerExchangeHeader, bytesPerIDPHeader, maxDataBytesPerExchange],
PacketExchange USING [
ErrorReason, RequestHandle, RequestObject, ExchangeClientType, ExchangeID,
WaitTime, ExchWords],
PacketExchangeInternal USING [ExchangeHandle, PacketExchangeObject],
Process USING [InitializeCondition, MsecToTicks],
Protocol1 USING [Family, GetFamilyUnit],
RouterInternal USING [FlushCacheEntry, SendErrorPacket],
Socket USING [
AssignNetworkAddress, Create, Delete, GetPacket,
PutPacket, ReturnBuffer, SetWaitTime, TimeOut],
SocketInternal USING [SocketHandle],
Stats USING [StatBump, StatIncr],
System USING [
broadcastHostNumber, GetClockPulses, NetworkAddress, SocketNumber];
PacketExchangeImpl: MONITOR
IMPORTS
ByteBlt, CommHeap, Driver, Inline, NSBuffer, Protocol1,
PacketExchange, Process, RouterInternal, Socket, Stats, System
EXPORTS PacketExchange, PacketExchangeInternal =
BEGIN
nullExchangeHandle: PUBLIC <<PacketExchange>> ExchangeHandle ← NIL;
maxBlockLength: PUBLIC <<PacketExchange>>
CARDINAL ← NSTypes.maxDataBytesPerExchange;
ExchangeHandle: PUBLIC <<PacketExchange>>
TYPE = PacketExchangeInternal.ExchangeHandle;
ChannelHandle: <<LOOPHOLE>> TYPE = SocketInternal.SocketHandle;
sendCompleted: CONDITION;
bufferSent: CARDINAL = 2;
sendAborted: CARDINAL = 3;
sendInProgress: CARDINAL = 1;
bytesPerExchangePacketHeader: CARDINAL =
NSTypes.bytesPerIDPHeader + NSTypes.bytesPerExchangeHeader;
Timeout: PUBLIC <<PacketExchange>> SIGNAL = CODE;
IllegalUseOfRequeueProcedure: <<GLITCH>> ERROR = CODE;
Error: PUBLIC <<PacketExchange>> ERROR [why: PacketExchange.ErrorReason] = CODE;
--we now own rH and we if no errors are encountered free it
Create: PUBLIC <<PacketExchange>> PROC[
localSocket: System.SocketNumber, receiveRequestCount: CARDINAL,
waitTime: PacketExchange.WaitTime]
RETURNS [h: ExchangeHandle] =
BEGIN
sendRequestCount: CARDINAL = 1;
parent: Protocol1.Family = Protocol1.GetFamilyUnit[ns];
maxBlockLength ← parent.maxBufferSize - bytesPerExchangePacketHeader;
h ← CommHeap.zone.NEW[PacketExchangeInternal.PacketExchangeObject ← [
cH: Socket.Create[
socket: localSocket, type: packetExchange,
send: sendRequestCount, receive: receiveRequestCount],
exchangeID: System.GetClockPulses[], retries: 0]];
Socket.SetWaitTime[h.cH, waitTime];
END; --CreateInternal
CreateReplier: PUBLIC <<PacketExchange>> PROC[
local: System.NetworkAddress, requestCount: CARDINAL,
waitTime, retransmissionInterval: PacketExchange.WaitTime]
RETURNS [h: ExchangeHandle] =
BEGIN
h ← Create[local.socket, requestCount, retransmissionInterval];
SetWaitTimes[h, waitTime, retransmissionInterval];
END;
CreateRequestor: PUBLIC <<PacketExchange>> PROC[
waitTime, retransmissionInterval: PacketExchange.WaitTime]
RETURNS [h: ExchangeHandle] =
BEGIN
me: System.NetworkAddress ← Socket.AssignNetworkAddress[];
h ← Create[me.socket, 2, MIN[waitTime, retransmissionInterval]];
SetWaitTimes[h, waitTime, retransmissionInterval];
END;
Delete: PUBLIC <<PacketExchange>> PROC[h: ExchangeHandle] =
BEGIN
Socket.Delete[h.cH];
CommHeap.zone.FREE[@h];
END; --Delete
GetFreeSendPacket: PUBLIC <<PacketExchangeInternal>> PROC[h: ExchangeHandle]
RETURNS [NSBuffer.Buffer] = {RETURN[GetBuffer[h, maxBlockLength]]};
GetBuffer: PROC[h: ExchangeHandle, length: NATURAL]
RETURNS [NSBuffer.Buffer] =
BEGIN
OPEN sH: LOOPHOLE[h.cH, ChannelHandle];
RETURN[NSBuffer.GetBuffer[
sH.pool, send, TRUE, length + bytesPerExchangePacketHeader]];
END;
LostBuffer: PRIVATE PROC[b: NSBuffer.Buffer] =
{Driver.Glitch[IllegalUseOfRequeueProcedure]};
NotifySendCompleted: PRIVATE ENTRY PROC[b: NSBuffer.Buffer] =
BEGIN
b.requeueData ← bufferSent;
b.requeueProcedure ← LostBuffer;
BROADCAST sendCompleted;
END;
--Reject the request without sending a response to the requestor
RejectRequest: PUBLIC <<PacketExchange>> PROC[
h: ExchangeHandle, rH: PacketExchange.RequestHandle] =
{CommHeap.zone.FREE[@rH]};
--Set the wait times (the total and the retransmission interval) for the handle
SetWaitTimes: PUBLIC <<PacketExchange>> PROC[
h: ExchangeHandle, waitTime,
retransmissionInterval: PacketExchange.WaitTime] =
BEGIN
retries: LONG CARDINAL;
max: LONG CARDINAL = LAST[CARDINAL];
Socket.SetWaitTime[h.cH, MIN[waitTime, retransmissionInterval]];
retries ← (waitTime - 1) / retransmissionInterval;
--The following is for the pretty bazarre situation.
h.retries ← Inline.LowHalf[IF retries > max THEN max ELSE retries];
END; --SetWaitTime
SendReply: PUBLIC <<PacketExchange>> PROC[
h: ExchangeHandle, rH: PacketExchange.RequestHandle,
replyBlk: Environment.Block, replyType: PacketExchange.ExchangeClientType] =
BEGIN
nsb: NSBuffer.Body;
replyB: NSBuffer.Buffer;
blkByteLen: CARDINAL = replyBlk.stopIndexPlusOne - replyBlk.startIndex;
IF blkByteLen > maxBlockLength THEN ERROR Error[blockTooBig];
replyB ← GetBuffer[h, blkByteLen]; --get a buffer to send
nsb ← replyB.ns; --make a local copy
--move all info into the replyB
nsb.pktLength ← bytesPerExchangePacketHeader + blkByteLen;
nsb.packetType ← packetExchange;
nsb.destination ← rH.requestorsAddress;
nsb.exchangeType ← replyType;
nsb.exchangeID ← rH.requestorsExchangeID;
[] ← ByteBlt.ByteBlt[[@nsb.exchangeBytes, 0, blkByteLen], replyBlk];
SendReplyPacket[h, replyB ! UNWIND => Socket.ReturnBuffer[replyB]];
CommHeap.zone.FREE[@rH];
END; --SendReply
SendReplyPacket: PUBLIC <<PacketExchangeInternal>> PROC[
h: ExchangeHandle, replyB: NSBuffer.Buffer] =
BEGIN
Socket.PutPacket[h.cH, replyB];
IF CommFlags.doStats THEN
BEGIN
Stats.StatIncr[statDataPacketsSent];
Stats.StatBump[statDataBytesSent,
replyB.ns.pktLength - NSTypes.bytesPerExchangeHeader -
NSTypes.bytesPerIDPHeader];
END;
END; --SendReplyPacket
SendRequest: PUBLIC <<PacketExchange>> PROC[
h: ExchangeHandle, remote: System.NetworkAddress,
requestBlk, replyBlk: Environment.Block,
requestType: PacketExchange.ExchangeClientType]
RETURNS [nBytes: CARDINAL, replyType: PacketExchange.ExchangeClientType] =
BEGIN
blkSizeOK: BOOLEAN;
nsb: NSBuffer.Body;
requestB, replyB: NSBuffer.Buffer;
blkByteLen: CARDINAL ← requestBlk.stopIndexPlusOne - requestBlk.startIndex;
h.exchangeID ← h.exchangeID + 1; --increment by one
IF blkByteLen > maxBlockLength THEN ERROR Error[blockTooBig];
requestB ← GetBuffer[h, blkByteLen];
nsb ← requestB.ns; --make a local copy
--move all info into the requestB
nsb.exchangeID ← LOOPHOLE[PacketExchange.ExchWords[h.exchangeID]];
nsb.pktLength ← bytesPerExchangePacketHeader + blkByteLen;
nsb.packetType ← packetExchange;
nsb.destination ← remote;
nsb.exchangeType ← requestType;
[] ← ByteBlt.ByteBlt[
[@nsb.exchangeBytes, 0, blkByteLen], requestBlk];
--Send the buffer (many times in case of timeouts) and extract
--info from reply buffer.
BEGIN
ENABLE
UNWIND => Socket.ReturnBuffer[requestB];
replyB ← SendRequestPacket[h, requestB, unspecified !
Error => IF why = timeout THEN {SIGNAL Timeout; RETRY}];
nsb ← replyB.ns; --BEWARE!! reusing local variable
END;
Socket.ReturnBuffer[requestB];
replyType ← nsb.exchangeType;
nBytes ← nsb.pktLength - bytesPerExchangePacketHeader;
blkByteLen ← replyBlk.stopIndexPlusOne - replyBlk.startIndex;
IF blkSizeOK ←
((nBytes <= blkByteLen)
AND (replyBlk.startIndex <= replyBlk.stopIndexPlusOne)) THEN
nBytes ← ByteBlt.ByteBlt[replyBlk, [@nsb.exchangeBytes, 0, nBytes]];
Socket.ReturnBuffer[replyB];
IF ~blkSizeOK THEN ERROR Error[blockTooSmall];
END; --SendRequest
<<
Caller has responsibility for returning requestB ,
and replyB if not NIL. The pktLength, destination and exchangeType
must be set by the caller.
>>
SendRequestPacket: PUBLIC <<PacketExchangeInternal>> PROC[
h: ExchangeHandle, requestB: NSBuffer.Buffer,
replyFilter: PacketExchange.ExchangeClientType,
replyMask: LONG CARDINAL ← LAST[LONG CARDINAL]]
RETURNS [replyB: NSBuffer.Buffer] =
BEGIN
WaitSendCompleted: ENTRY PROC[waitBuffer: NSBuffer.Buffer]
RETURNS [NSBuffer.TransferStatus] = INLINE
{WHILE (waitBuffer.requeueData = sendInProgress) DO
WAIT sendCompleted; ENDLOOP; RETURN[waitBuffer.fo.status]};
tries: CARDINAL;
repBB: NSBuffer.Body;
error: PacketExchange.ErrorReason;
reqBB: NSBuffer.Body = requestB.ns;
retryCount: CARDINAL ← h.retries;
exchangeID: PacketExchange.ExchangeID ← reqBB.exchangeID;
reqBB.packetType ← packetExchange;
IF CommFlags.doStats THEN
BEGIN
Stats.StatIncr[statDataPacketsSent];
Stats.StatBump[statDataBytesSent,
reqBB.pktLength - NSTypes.bytesPerExchangeHeader -
NSTypes.bytesPerIDPHeader];
END;
FOR tries IN[0..retryCount] DO --] => execute once if retryCount = 0
IF CommFlags.doStats AND (tries # 0) THEN
Stats.StatIncr[statDataPacketsRetransmitted];
IF (tries MOD 8) = 7 THEN --things are messed up
RouterInternal.FlushCacheEntry[reqBB.destination.net];
--UNTIL EXIT-- DO
replyB ← NIL;
requestB.requeueProcedure ← NotifySendCompleted;
requestB.requeueData ← sendInProgress;
Socket.PutPacket[h.cH, requestB];
SELECT WaitSendCompleted[requestB] FROM
goodCompletion =>
DO --do gets until satisfied or timed out
replyB ← Socket.GetPacket[h.cH ! Socket.TimeOut => EXIT];
repBB ← replyB.ns; --make a local copy
SELECT TRUE FROM
((reqBB.destination.host # System.broadcastHostNumber)
AND (repBB.source.host # reqBB.destination.host)) => NULL;
(repBB.packetType = error) =>
BEGIN
error ← SELECT repBB.errorType FROM
noSocket => noReceiverAtDestination,
congestionWarning, congestionDiscard => timeout,
resourceLimits => insufficientResourcesAtDestination,
listenerReject, invalidPacketType, protocolViolation =>
rejectedByReceiver,
ENDCASE => hardwareProblem;
IF CommFlags.doStats THEN
Stats.StatIncr[statErrorPacketsReceived];
Socket.ReturnBuffer[replyB]; --free buffer
GOTO badTimes; --raise signal
END;
(repBB.packetType # packetExchange) =>
BEGIN
IF CommFlags.doStats THEN
Stats.StatIncr[statPacketsRejectedBadType];
RouterInternal.SendErrorPacket[replyB, invalidPacketType];
replyB ← NIL; LOOP;
END;
(repBB.source.socket # reqBB.destination.socket) =>
IF CommFlags.doStats THEN
Stats.StatIncr[statPacketsRejectedBadSource];
(Inline.DBITAND[Inline.DBITXOR[
LOOPHOLE[repBB.exchangeID, LONG UNSPECIFIED],
LOOPHOLE[exchangeID, LONG UNSPECIFIED]], replyMask]#0) =>
IF CommFlags.doStats THEN
Stats.StatIncr[statPacketsRejectedBadID];
((repBB.exchangeType # replyFilter)
AND (replyFilter # unspecified)) =>
IF CommFlags.doStats THEN
Stats.StatIncr[statPacketsRejectedBadID];
ENDCASE =>
BEGIN
IF CommFlags.doStats THEN
BEGIN
Stats.StatIncr[statDataPacketsReceived];
Stats.StatBump[statDataBytesReceived,
reqBB.pktLength - NSTypes.bytesPerExchangeHeader -
NSTypes.bytesPerIDPHeader];
END;
RETURN; --success
END;
Socket.ReturnBuffer[replyB]; replyB ← NIL;
ENDLOOP; --goodCompletion
aborted => LOOP; --aborted by StuckOutput?
noRouteToNetwork => {error ← noRouteToDestination; GOTO badTimes};
invalidDestAddr => {error ← noReceiverAtDestination; GOTO badTimes};
ENDCASE => {error ← hardwareProblem; GOTO badTimes};
EXIT;
ENDLOOP;
REPEAT badTimes => ERROR Error[error];
ENDLOOP;
Error[timeout];
END; --SendRequestPacket
WaitForRequest: PUBLIC <<PacketExchange>> PROC[
h: ExchangeHandle, requestBlk: Environment.Block,
requiredRequestType: PacketExchange.ExchangeClientType]
RETURNS [PacketExchange.RequestHandle] =
BEGIN
blkSizeOK: BOOLEAN;
reqBB: NSBuffer.Body;
requestB: NSBuffer.Buffer;
nBytes, blkByteLen: CARDINAL;
rH: LONG POINTER TO PacketExchange.RequestObject;
requestB ← WaitForRequestPacket[h, requiredRequestType !
Error => IF why = timeout THEN {SIGNAL Timeout; RETRY}];
reqBB ← requestB.ns; --make a local copy
nBytes ← reqBB.pktLength - bytesPerExchangePacketHeader;
blkByteLen ← requestBlk.stopIndexPlusOne - requestBlk.startIndex;
IF blkSizeOK ←
((nBytes <= blkByteLen)
AND (requestBlk.startIndex <= requestBlk.stopIndexPlusOne)) THEN
BEGIN
rH ← CommHeap.zone.NEW[PacketExchange.RequestObject ← [
nBytes: ByteBlt.ByteBlt[
requestBlk, [@reqBB.exchangeBytes, 0, nBytes]],
requestType: reqBB.exchangeType,
requestorsAddress: reqBB.source,
requestorsExchangeID: reqBB.exchangeID]];
END;
Socket.ReturnBuffer[requestB];
IF ~blkSizeOK THEN ERROR Error[blockTooSmall];
RETURN[LOOPHOLE[rH]];
END; --WaitForRequest
WaitForRequestPacket: PUBLIC <<PacketExchangeInternal>> PROC[
h: ExchangeHandle, request: PacketExchange.ExchangeClientType]
RETURNS [requestB: NSBuffer.Buffer] =
BEGIN
retryCount: CARDINAL ← h.retries;
THROUGH [0..retryCount] DO --execute loop if retryCount = 0
requestB ← NIL;
DO --do gets until satisfied or timed out
reqBB: NSBuffer.Body;
requestB ← Socket.GetPacket[h.cH ! Socket.TimeOut => EXIT];
reqBB ← requestB.ns; --make a local copy
SELECT TRUE FROM
(reqBB.packetType # packetExchange) =>
BEGIN
IF CommFlags.doStats THEN
Stats.StatIncr[statPacketsRejectedBadType];
RouterInternal.SendErrorPacket[requestB, invalidPacketType];
requestB ← NIL; LOOP;
END;
(request # unspecified) AND (reqBB.exchangeType # request) =>
IF CommFlags.doStats THEN
Stats.StatIncr[statPacketsRejectedBadType];
ENDCASE =>
BEGIN
IF CommFlags.doStats THEN
BEGIN
Stats.StatIncr[statDataPacketsReceived];
Stats.StatBump[statDataBytesReceived,
reqBB.pktLength - NSTypes.bytesPerExchangeHeader -
NSTypes.bytesPerIDPHeader];
END;
RETURN;
END;
Socket.ReturnBuffer[requestB];
requestB ← NIL;
ENDLOOP; --get loop
ENDLOOP;
ERROR Error[timeout];
END; --WaitForRequestPacket
--MainLine Code
Process.InitializeCondition[@sendCompleted, Process.MsecToTicks[2000]];
END.
LOG
17-May-84 11:03:36 AOF Post Klamath
25-Apr-85 9:41:49 AOF Remove LOOPHOLEs around .TransferStatus
6-Feb-86 8:47:15 AOF Merge in ExpeditedCourier changes
22-Apr-86 14:46:45 AOF Free replyB in ...$SendReply
22-May-86 18:24:54 SMA No dependencies on Buffer.
27-May-86 9:26:01 SMA Socket.ReturnBuffer => Socket.ReturnBuffer.
18-Aug-86 17:54:19 AOF Local caching of b.ns.
8-Nov-86 20:01:40 AOF Largish buffers.
6-May-87 13:26:54 AOF Flush cache after 8 retries.
16-Sep-87 14:44:11 AOF Reordering of filtering of reply packet (AR#11862).