-- File: EFTPSend.mesa, Last Edit: -- MAS April 17, 1980 8:49 PM -- HGM October 16, 1979 7:38 PM -- Copyright Xerox Corporation 1979, 1980 DIRECTORY InlineDefs: FROM "InlineDefs" USING [COPY], CommUtilDefs: FROM "CommUtilDefs" USING [ SetTimeout, MsecToTicks, AllocateHeapString, FreeHeapString], PupDefs: FROM "PupDefs" USING [ DataWordsPerPupBuffer, GetFreePupBuffer, ReturnFreePupBuffer, GetPupContentsBytes, SetPupContentsBytes, PupAddress, PupBuffer, PupSocketID, PupSocket, PupSocketMake, PupSocketDestroy, SecondsToTocks, UniqueLocalPupSocketID], PupTypes: FROM "PupTypes" USING [ maxDataBytesPerGatewayPup, noProcessPupErrorCode], EFTPDefs: FROM "EFTPDefs" USING [ EFTPAbortCode, eftpExternalSenderAbort, eftpOK, eftpRejected], DriverDefs: FROM "DriverDefs" USING [Network], BufferDefs: FROM "BufferDefs"; EFTPSend: MONITOR IMPORTS InlineDefs, CommUtilDefs, PupDefs EXPORTS EFTPDefs SHARES BufferDefs = BEGIN OPEN PupDefs, EFTPDefs; EFTPTimeOut: PUBLIC SIGNAL = CODE; EFTPAlreadySending: PUBLIC ERROR = CODE; EFTPNotSending: PUBLIC ERROR = CODE; EFTPTroubleSending: PUBLIC ERROR [e: EFTPAbortCode, s: STRING] = CODE; send: CONDITION; senderStop: BOOLEAN; senderFork: PROCESS; sendSocket: PupSocket _ NIL; sendHim: PupAddress; sendSeqNumber: CARDINAL; sendAbortCode: EFTPAbortCode; sendState: {acked, waitingForAck}; sendErrorText: STRING _ NIL; retransmissions: CARDINAL; dataBytesPerPup: CARDINAL; EFTPSetSendTimeout: PUBLIC PROCEDURE [ms, tries: CARDINAL] = BEGIN retransmissions _ tries; CommUtilDefs.SetTimeout[@send,CommUtilDefs.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: 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]; InlineDefs.COPY[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] _ 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: DriverDefs.Network _ b.network; IF sendHim.net=0 THEN sendHim.net _ [network.netNumber]; RETURN[b.source=sendHim]; END; -- extra procedure to get lock EFTPReplyForSenderLocked: ENTRY PROCEDURE [b: PupBuffer] = BEGIN i, len: CARDINAL; 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 len _ GetPupContentsBytes[b]-2; len _ MIN[len,100]; sendErrorText _ CommUtilDefs.AllocateHeapString[len]; FOR i IN [0..len) DO sendErrorText[i] _ b.pupChars[i+2]; ENDLOOP; sendErrorText.length _ len; END; END; error => IF b.errorCode=PupTypes.noProcessPupErrorCode THEN BEGIN sendState _ acked; NOTIFY send; sendAbortCode _ eftpRejected; IF sendErrorText=NIL THEN BEGIN len _ GetPupContentsBytes[b]-2*(10+1+1); len _ MIN[len,100]; sendErrorText _ CommUtilDefs.AllocateHeapString[len]; FOR i IN [0..len) DO sendErrorText[i] _ b.errorText[i]; ENDLOOP; sendErrorText.length _ len; 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; IF sendErrorText#NIL THEN BEGIN CommUtilDefs.FreeHeapString[sendErrorText]; sendErrorText _ NIL; END; END; -- initialization EFTPSetSendTimeout[1000,25]; END.(2048)\1223t10 9t0 204b18B150b18B188b13B74t10 11t0 3t10 23t0 380b14B583b13B871b16B132b22B395b17B87b23B958b18B279b11B225b24B1135b1i42I24i18I15B