DIRECTORY ConvertUnsafe USING [ToRope], Rope USING [ROPE], Process USING [SetTimeout, MsecToTicks], CommUtilDefs USING [CopyLong], PupDefs USING [DataWordsPerPupBuffer, GetFreePupBuffer, ReturnFreePupBuffer, GetPupContentsBytes, SetPupContentsBytes, PupAddress, PupBuffer, PupSocketID, PupSocket, PupSocketMake, PupSocketDestroy, SecondsToTocks, UniqueLocalPupSocketID], PupTypes USING [maxDataBytesPerGatewayPup], EFTPDefs USING [EFTPAbortCode], DriverDefs USING [Network], BufferDefs; EFTPSend: MONITOR IMPORTS ConvertUnsafe, Process, CommUtilDefs, PupDefs EXPORTS BufferDefs, EFTPDefs SHARES BufferDefs = BEGIN OPEN PupDefs, EFTPDefs; Network: PUBLIC TYPE = DriverDefs.Network; EFTPTimeOut: PUBLIC SIGNAL = CODE; EFTPAlreadySending: PUBLIC ERROR = CODE; EFTPNotSending: PUBLIC ERROR = CODE; EFTPTroubleSending: PUBLIC ERROR [e: EFTPAbortCode, s: Rope.ROPE] = CODE; send: CONDITION; senderStop: BOOLEAN; senderFork: PROCESS; sendSocket: PupSocket _ NIL; sendHim: PupAddress; sendSeqNumber: CARDINAL; sendAbortCode: EFTPAbortCode; sendState: {acked, waitingForAck}; sendErrorText: Rope.ROPE _ NIL; retransmissions: CARDINAL; dataBytesPerPup: CARDINAL; EFTPSetSendTimeout: PUBLIC PROCEDURE [ms, tries: CARDINAL] = BEGIN retransmissions _ tries; Process.SetTimeout[@send, Process.MsecToTicks[ms]]; END; EFTPOpenForSending: PUBLIC PROCEDURE [who: PupAddress, waitForAck: BOOLEAN] = BEGIN EFTPOpenCheck[who]; BEGIN ENABLE UNWIND => EFTPKillSending[]; IF waitForAck THEN EFTPOpenLocked[]; END; END; EFTPOpenCheck: ENTRY PROCEDURE [to: PupAddress] = BEGIN ENABLE UNWIND => NULL; me: PupSocketID _ UniqueLocalPupSocketID[]; IF sendSocket # NIL THEN ERROR EFTPAlreadySending; dataBytesPerPup _ MIN[ 2*DataWordsPerPupBuffer[], PupTypes.maxDataBytesPerGatewayPup]; sendHim _ to; sendSocket _ PupSocketMake[me, sendHim, SecondsToTocks[1]]; sendSeqNumber _ LAST[CARDINAL]; sendAbortCode _ eftpOK; sendState _ acked; senderStop _ FALSE; senderFork _ FORK EFTPReplyForSender[]; END; EFTPOpenLocked: ENTRY PROCEDURE = BEGIN ENABLE UNWIND => NULL; b: PupBuffer; sendState _ waitingForAck; sendSeqNumber _ sendSeqNumber + 1; UNTIL sendState = acked DO THROUGH [0..10) UNTIL sendState = acked DO b _ GetFreePupBuffer[]; b.pupType _ eData; b.pupID _ [0, sendSeqNumber]; SetPupContentsBytes[b, 0]; sendSocket.put[b]; WAIT send; -- 10*1 sec ENDLOOP; IF sendState = acked THEN EXIT; SIGNAL EFTPTimeOut; ENDLOOP; IF sendAbortCode # eftpOK THEN BEGIN ERROR EFTPTroubleSending[sendAbortCode, sendErrorText]; END; END; EFTPSendBlock: PUBLIC ENTRY PROCEDURE [p: LONG POINTER, l: CARDINAL] = BEGIN ENABLE UNWIND => NULL; n: CARDINAL; b: PupBuffer; IF sendSocket = NIL THEN ERROR EFTPNotSending; UNTIL l = 0 DO sendSeqNumber _ sendSeqNumber + 1; sendState _ waitingForAck; n _ MIN[l, dataBytesPerPup]; DO THROUGH [0..retransmissions) UNTIL sendState = acked DO b _ GetFreePupBuffer[]; b.pupType _ eData; b.pupID _ [0, sendSeqNumber]; CommUtilDefs.CopyLong[from: p, nwords: (n + 1)/2, to: @b.pupBytes]; SetPupContentsBytes[b, n]; sendSocket.put[b]; WAIT send; -- 25*1 sec ENDLOOP; IF sendAbortCode # eftpOK THEN BEGIN ERROR EFTPTroubleSending[sendAbortCode, sendErrorText]; END; IF sendState = acked THEN EXIT; SIGNAL EFTPTimeOut; ENDLOOP; p _ p + (n + 1)/2; l _ l - n; ENDLOOP; END; EFTPAbortSending: PUBLIC PROCEDURE [s: STRING] = BEGIN IF sendSocket = NIL THEN RETURN; EFTPAbortSendingLocked[s]; EFTPKillSending[]; END; EFTPAbortSendingLocked: ENTRY PROCEDURE [s: STRING] = BEGIN i, end: CARDINAL; b: PupBuffer; IF sendAbortCode = eftpOK THEN BEGIN b _ GetFreePupBuffer[]; b.pupType _ eAbort; b.pupWords[0] _ LOOPHOLE[EFTPAbortCode[eftpExternalSenderAbort]]; end _ MIN[s.length + 2, dataBytesPerPup]; FOR i _ 2, i + 1 UNTIL i = end DO b.pupChars[i] _ s[i - 2]; ENDLOOP; SetPupContentsBytes[b, end]; sendSocket.put[b]; END; END; EFTPFinishSending: PUBLIC PROCEDURE = BEGIN EFTPFinishSendingLocked[]; EFTPKillSending[]; END; EFTPFinishSendingLocked: ENTRY PROCEDURE = BEGIN ENABLE UNWIND => NULL; b: PupBuffer; IF sendSocket = NIL THEN ERROR EFTPNotSending; sendSeqNumber _ sendSeqNumber + 1; sendState _ waitingForAck; UNTIL sendState = acked DO THROUGH [0..10) UNTIL sendState = acked DO b _ GetFreePupBuffer[]; b.pupType _ eEnd; b.pupID _ [0, sendSeqNumber]; SetPupContentsBytes[b, 0]; sendSocket.put[b]; WAIT send; -- 10*1 sec ENDLOOP; IF sendAbortCode # eftpOK THEN ERROR EFTPTroubleSending[sendAbortCode, sendErrorText]; IF sendState = acked THEN EXIT; SIGNAL EFTPTimeOut; ENDLOOP; sendSeqNumber _ sendSeqNumber + 1; b _ GetFreePupBuffer[]; b.pupType _ eEnd; b.pupID _ [0, sendSeqNumber]; SetPupContentsBytes[b, 0]; sendSocket.put[b]; IF sendAbortCode # eftpOK THEN ERROR EFTPTroubleSending[sendAbortCode, sendErrorText]; END; EFTPReplyForSender: PROCEDURE = BEGIN b: PupBuffer; UNTIL senderStop DO b _ sendSocket.get[]; IF b # NIL AND (b.source = sendHim OR CheckSource[b]) THEN EFTPReplyForSenderLocked[b]; IF b # NIL THEN ReturnFreePupBuffer[b]; ENDLOOP; END; CheckSource: PROCEDURE [b: PupBuffer] RETURNS [BOOLEAN] = BEGIN network: Network _ b.network; IF sendHim.net = 0 THEN sendHim.net _ [network.netNumber.b]; RETURN[b.source = sendHim]; END; EFTPReplyForSenderLocked: ENTRY PROCEDURE [b: PupBuffer] = BEGIN SELECT b.pupType FROM eAck => IF b.pupID = [0, sendSeqNumber] THEN BEGIN sendState _ acked; NOTIFY send; END; eAbort => BEGIN sendState _ acked; NOTIFY send; sendAbortCode _ LOOPHOLE[b.pupWords[0]]; IF sendErrorText = NIL THEN BEGIN s: STRING = [100]; FOR i: CARDINAL IN [0..MIN[GetPupContentsBytes[b] - 2,s.maxlength]) DO s[i] _ b.pupChars[i + 2] ENDLOOP; sendErrorText _ ConvertUnsafe.ToRope[s]; END; END; error => IF b.errorCode = noProcessPupErrorCode THEN BEGIN sendState _ acked; NOTIFY send; sendAbortCode _ eftpRejected; IF sendErrorText = NIL THEN BEGIN s: STRING = [100]; FOR i: CARDINAL IN [0..MIN[GetPupContentsBytes[b] - 2*(10 + 1 + 1),s.maxlength]) DO s[i] _ b.errorText[i] ENDLOOP; sendErrorText _ ConvertUnsafe.ToRope[s]; END; END; ENDCASE; END; EFTPKillSending: PROCEDURE = BEGIN senderStop _ TRUE; JOIN senderFork; IF sendSocket # NIL THEN PupSocketDestroy[sendSocket]; sendSocket _ NIL; END; EFTPSetSendTimeout[1000, 25]; END. lEFTPSend.mesa Copyright c 1985 by Xerox Corporation. All rights reserved. Levin 9-Mar-82 10:55:50 EXPORTed TYPEs send the second END to keep the receiver from dallying any more internal procedures kludge to get around net0 troubles extra procedure to get lock Don't call this if you have the lock. EFTPReplyForSenderLocked may need it too. initialization Ê $˜codešœ ™ Kšœ Ïmœ1™