// PupEFTPReceive.bcpl -- by J. Shoch // Copyright Xerox Corporation 1979, 1980 // Last modified September 30, 1980 1:45 PM, by Swinehart get "PupEFTP.decl" external [ // outgoing procedures ReceiveEFTPBlock; ReceiveEFTPPacket // incoming procedures SendEFTPAbort GetPBI; ReleasePBI; CompletePup SetTimer; TimerHasExpired; Block; Dequeue; MultEq MoveBlock ] //---------------------------------------------------------------------------- let ReceiveEFTPBlock(soc, addr, timeout) = valof //---------------------------------------------------------------------------- // Returns a byte count (>=0) or an error code (<0) [ let inPbi = 0 let receiveResult = ReceiveEFTPPacket(soc, timeout, lv inPbi) if receiveResult ge 0 then // succeeded [ MoveBlock(addr, lv inPbi>>PBI.pup.words↑1, (receiveResult+1) rshift 1) if inPbi then // ignore zero-length packets [ ReleasePBI(inPbi); if receiveResult eq 0 loop ] resultis receiveResult // count of dataBytes ] unless receiveResult eq EFTPNotFirstSynch resultis receiveResult ] repeat //---------------------------------------------------------------------------- and ReceiveEFTPPacket(soc, timeout, lvPbi) = valof //---------------------------------------------------------------------------- // Returns a byte count (>=0) or an error code (<0) // If a byte count, @lvPbi contains the pbi with the data // Note that when we start, we may not yet know the socket // number of the foreign socket..... [ let syncMsg = "Your sender is out of sync." let busyMsg = "Receiver busy, please try again later." let longTimer = nil; SetTimer(lv longTimer, timeout) [ // repeat // wait for an incoming packet Block() if timeout ne -1 & TimerHasExpired(lv longTimer) resultis EFTPTimeout let inPbi = Dequeue(lv soc>>EFTPSoc.iQ) if inPbi eq 0 loop let firstPacket = inPbi>>PBI.pup.id↑2 eq 0 let dataPup= inPbi>>PBI.pup.type eq typeEFTPData // See if we are already committed to a file transfer if soc>>EFTPSoc.TransferNotStarted then [ // No established file transfer is in progress. // To start a file transfer, (1) his must be a valid packet 0, // and either (2) its source must match our socket's foreign port // or (3) we must be promiscuous. if dataPup & firstPacket & (soc>>EFTPSoc.frnPort.host eq 0 % // (2) (soc>>EFTPSoc.frnPort.host eq inPbi>>PBI.pup.sPort.host & // (3) soc>>EFTPSoc.frnPort.net eq inPbi>>PBI.pup.sPort.net)) then // (3) [ // establish a "connection" soc>>EFTPSoc.TransferNotStarted = false soc>>EFTPSoc.SeqNum = 0 MoveBlock(lv soc>>EFTPSoc.frnPort, lv inPbi>>PBI.pup.sPort, lenPort) ] ] // Do source filtering unless MultEq(lv soc>>EFTPSoc.frnPort, lv inPbi>>PBI.pup.sPort, lenPort) do [ // Did not pass source filter, generate Abort if dataPup then [ test firstPacket ifso [ // Attempted first packet of transfer. // Either we are busy or we are listening and not promiscuous. SendEFTPAbort(soc, ReceiverBusyAbort, busyMsg, inPbi) soc>>EFTPSoc.SomeoneElseWaiting = true ] ifnot [ // Not legal first packet of transfer. SendEFTPAbort(soc, OutOfSynchAbort, syncMsg, inPbi) ] ] ReleasePBI(inPbi) if soc>>EFTPSoc.TransferNotStarted resultis EFTPNotFirstSynch loop //wait for next input ] // ReceiveEFTPPacket (cont'd) // Packet has passed all filters. Now process it. switchon inPbi>>PBI.pup.type into [ case typeEFTPData: [ let seq=CheckSequence(soc, inPbi) switchon seq into [ case 1: loop; case 0: endcase; default: resultis seq ] soc>>EFTPSoc.SeqNum = soc>>EFTPSoc.SeqNum+1 @lvPbi = inPbi resultis inPbi>>PBI.pup.length - pupOvBytes //and return ] case typeEFTPEnd: [ let seq=CheckSequence(soc, inPbi) switchon seq into [ case 1: loop; case 0: endcase; default: resultis seq ] ReleasePBI(inPbi) soc>>EFTPSoc.SeqNum = soc>>EFTPSoc.SeqNum+1 let dallyTimer = nil; SetTimer(lv dallyTimer, dallyTimeout) [ // repeat Block() if TimerHasExpired(lv dallyTimer) resultis EFTPEndReceived inPbi = Dequeue(lv soc>>EFTPSoc.iQ) if inPbi eq 0 loop if inPbi>>PBI.pup.type ne typeEFTPEnd then [ ReleasePBI(inPbi); loop ] if soc>>EFTPSoc.SeqNum eq inPbi>>PBI.pup.id↑2 then [ ReleasePBI(inPbi); resultis EFTPEndReceived ] // Was a retransmission of first end, ack it AckEFTPPacket(soc, inPbi); ReleasePBI(inPbi) ] repeat endcase ] case typeEFTPAbort: case typeError: // low-level error pup, if "no such port" treat as abort else ignore [ if inPbi>>PBI.pup.words↑11 ne ecNoSuchPort endcase // ignore the packet if soc>>EFTPSoc.AbortPBI ne 0 then ReleasePBI(soc>>EFTPSoc.AbortPBI) soc>>EFTPSoc.AbortPBI = inPbi // includes error Pups? resultis EFTPAbortReceived ] default: // unrecognized Pup on current connection, abort [ SendEFTPAbort(soc, ExternalSenderAbort, "Unrecognized Pup type on EFTP connection", inPbi) ReleasePBI(inPbi); resultis EFTPAbortSent ] ] ReleasePBI(inPbi) ] repeat ] and CheckSequence(soc, inPbi) = valof [ let inSeqNum=inPbi>>PBI.pup.id↑2 // Check the sequence number -- should be expected or expected-1 // Acknowledge it. Then, if expected-1, release and return 1 // If expected, return 0 -- next data packet // If not expected sequence, issue appropriate abort and return its code. let dif=(soc>>EFTPSoc.SeqNum-inSeqNum) if (dif rshift 1) eq 0 then [ AckEFTPPacket(soc, inPbi) if dif eq 1 then ReleasePBI(inPbi) resultis dif // 0 if expected sequence #, 1 if previous one ] // Sequence number incorrect. // If we receive a data packet with sequence number 0 // from our partner, then assume he wants to restart. // Otherwise abort the transfer and return an error. unless inSeqNum eq 0 do SendEFTPAbort(soc, OutOfSynchAbort, "Your sender is out of sync.", inPbi) ReleasePBI(inPbi) resultis inSeqNum eq 0? EFTPResetReceived, EFTPAbortSent ] //---------------------------------------------------------------------------- and AckEFTPPacket(soc, pbi) be //---------------------------------------------------------------------------- [ // construct the outgoing ack packet let ackPbi = GetPBI(soc) ackPbi>>PBI.pup.id↑2 = pbi>>PBI.pup.id↑2 CompletePup(ackPbi, typeEFTPAck, pupOvBytes) ]