// PupEFTPReceive.bcpl -- by J. Shoch // Copyright Xerox Corporation 1979 // Last modified June 5, 1979 12:12 PM by Taft 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 has gotten 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 inSeqNum = inPbi>>PBI.pup.id^2 // 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 inPbi>>PBI.pup.type eq typeEFTPData & inSeqNum eq 0 & (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 test inPbi>>PBI.pup.type eq typeEFTPData & inSeqNum eq 0 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 ] // Check the sequence number -- should be expected or expected-1 if (soc>>EFTPSoc.SeqNum-inSeqNum) rshift 1 ne 0 then [ // 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, syncMsg, inPbi) ReleasePBI(inPbi) resultis inSeqNum eq 0? EFTPResetReceived, EFTPAbortSent ] // ReceiveEFTPPacket (cont'd) // Packet has passed all filters. Now process it. switchon inPbi>>PBI.pup.type into [ case typeEFTPData: [ AckEFTPPacket(soc, inPbi) if inSeqNum ne soc>>EFTPSoc.SeqNum then [ ReleasePBI(inPbi); loop ] //retransmission soc>>EFTPSoc.SeqNum = soc>>EFTPSoc.SeqNum+1 @lvPbi = inPbi resultis inPbi>>PBI.pup.length - pupOvBytes //and return ] case typeEFTPEnd: [ AckEFTPPacket(soc, inPbi); ReleasePBI(inPbi) if inSeqNum ne soc>>EFTPSoc.SeqNum loop //retransmission 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: [ if soc>>EFTPSoc.AbortPBI ne 0 then ReleasePBI(soc>>EFTPSoc.AbortPBI) soc>>EFTPSoc.AbortPBI = inPbi resultis EFTPAbortReceived ] ] ReleasePBI(inPbi) ] repeat ] //---------------------------------------------------------------------------- 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) ]