// PupEFTPSend.bcpl -- by J. Shoch // Copyright Xerox Corporation 1979 // Last modified June 3, 1979 12:45 PM by Taft get "PupEFTP.decl" external [ // outgoing procedures SendEFTPBlock; SendEFTPEnd // incoming procedures SendEFTPAbort GetPBI; ReleasePBI; CompletePup SetTimer; TimerHasExpired; Block Dequeue; MultEq; Max; Min; MoveBlock ] //---------------------------------------------------------------------------- let SendEFTPBlock(soc, addr, byteCnt, timeout) = valof //---------------------------------------------------------------------------- [ let result = SendEFTPPacket(soc, addr, byteCnt, timeout, typeEFTPData) if result ge 0 then soc>>EFTPSoc.SeqNum = soc>>EFTPSoc.SeqNum +1 resultis result ] //---------------------------------------------------------------------------- and SendEFTPEnd(soc, timeout) = valof //---------------------------------------------------------------------------- //The end sequence requires a complete ack for the first // outgoing end, and then an extra end is sent, as part of the // three way handshake. [ if SendEFTPPacket(soc, 0, 0, timeout, typeEFTPEnd) ls 0 resultis false //first end sent and acked ok. Send second End but don't wait for ack soc>>EFTPSoc.SeqNum = soc>>EFTPSoc.SeqNum +1 SendEFTPPacket(soc, 0, 0, 0, typeEFTPEnd) resultis true ] //---------------------------------------------------------------------------- and SendEFTPPacket(soc, addr, dataBytes, timeout, type) = valof //---------------------------------------------------------------------------- // This is a general routine, usable for data or end packets // Will handle retransmissions here. Passes in a long timeout // Returns the number of data bytes sent (>=0) if OK; // Returns an error code (< 0) if there was an error [ SetTimer(lv soc>>EFTPSoc.startTime, 0) //remember start time let longTimer = nil; SetTimer(lv longTimer, timeout) [ // repeat // construct the outgoing packet let pbi = GetPBI(soc) pbi>>PBI.pup.id↑2 = soc>>EFTPSoc.SeqNum MoveBlock(lv pbi>>PBI.pup.words↑1, addr, (dataBytes+1) rshift 1) CompletePup(pbi, type, dataBytes+pupOvBytes) let shortTimer = nil SetTimer(lv shortTimer, soc>>EFTPSoc.currentTimeout) [ // repeat Block() if timeout ne -1 & TimerHasExpired(lv longTimer) then resultis EFTPTimeout //he is not answering now if TimerHasExpired(lv shortTimer) then [ //exponentially age retransmission interval AgeTimeout(soc); break //re-transmit ] pbi = Dequeue(lv soc>>EFTPSoc.iQ); if pbi eq 0 loop //Check the source of this packet unless MultEq(lv soc>>EFTPSoc.frnPort.socket, lv pbi>>PBI.pup.sPort.socket) do [ ReleasePBI(pbi); loop ] //Got a packet really for us from our partner AgeTimeout(soc) switchon pbi>>PBI.pup.type into [ case typeEFTPAck: [ if pbi>>PBI.pup.id↑2 eq soc>>EFTPSoc.SeqNum then [ ReleasePBI(pbi); resultis dataBytes ] if pbi>>PBI.pup.id↑2 gr soc>>EFTPSoc.SeqNum then [ SendEFTPAbort(soc, OutOfSynchAbort, "Your receiver has gotten out of synch.", pbi) ReleasePBI(pbi) resultis EFTPAbortSent ] ReleasePBI(pbi) endcase ] case typeEFTPAbort: [ if soc>>EFTPSoc.AbortPBI ne 0 then ReleasePBI(soc>>EFTPSoc.AbortPBI) soc>>EFTPSoc.AbortPBI = pbi resultis EFTPAbortReceived // bail out ] default: ReleasePBI(pbi) ] ] repeat ] repeat ] //---------------------------------------------------------------------------- and AgeTimeout(soc) be //---------------------------------------------------------------------------- //update the adaptive timeout // = 2 times the average response time, exponentially aged over // the last 8 samples. [ let t = nil; SetTimer(lv t, 0) compiletest alto ifso [ t = (t-soc>>EFTPSoc.startTime) lshift 3 +4 ] ifnot [ t = (t-soc>>EFTPSoc.startTime) lshift 1 +1 ] soc>>EFTPSoc.currentTimeout = (7*soc>>EFTPSoc.currentTimeout + Max(minTimeout, Min(maxTimeout, t))) rshift 3 ]