-- 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 <> ExchangeHandle ¬ NIL; maxBlockLength: PUBLIC <> CARDINAL ¬ NSTypes.maxDataBytesPerExchange; ExchangeHandle: PUBLIC <> TYPE = PacketExchangeInternal.ExchangeHandle; ChannelHandle: <> TYPE = SocketInternal.SocketHandle; sendCompleted: CONDITION; bufferSent: CARDINAL = 2; sendAborted: CARDINAL = 3; sendInProgress: CARDINAL = 1; bytesPerExchangePacketHeader: CARDINAL = NSTypes.bytesPerIDPHeader + NSTypes.bytesPerExchangeHeader; Timeout: PUBLIC <> SIGNAL = CODE; IllegalUseOfRequeueProcedure: <> ERROR = CODE; Error: PUBLIC <> ERROR [why: PacketExchange.ErrorReason] = CODE; --we now own rH and we if no errors are encountered free it Create: PUBLIC <> 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 <> 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 <> 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 <> PROC[h: ExchangeHandle] = BEGIN Socket.Delete[h.cH]; CommHeap.zone.FREE[@h]; END; --Delete GetFreeSendPacket: PUBLIC <> 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 <> 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 <> 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 <> 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 <> 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 <> 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 <> 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 <> 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 <> 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).