EFTPSend.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Levin 9-Mar-82 10:55:50
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;
EXPORTed TYPEs
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.ROPENIL;
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;
send the second END to keep the receiver from dallying any more
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;
internal procedures
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;
kludge to get around net0 troubles
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;
extra procedure to get lock
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;
Don't call this if you have the lock. EFTPReplyForSenderLocked may need it too.
EFTPKillSending: PROCEDURE =
BEGIN
senderStop ← TRUE;
JOIN senderFork;
IF sendSocket # NIL THEN PupSocketDestroy[sendSocket];
sendSocket ← NIL;
END;
initialization
EFTPSetSendTimeout[1000, 25];
END.