DIRECTORY Endian USING [FFromInt, FWORD], Rope USING [ROPE], PrincOpsUtils USING [ByteBlt], Process USING [SetTimeout, MsecToTicks], Pup USING [Address], PupBuffer USING [maxDataBytes], PupHop USING [InitialTimeout], PupSocket USING [AllocBuffer, AppendRope, Buffer, CreateEphemeral, Destroy, ExtractAbortRope, FreeBuffer, Get, GetRemoteAddress, Put, SetGetTimeout, SetUserBytes, SetUserHWords, Socket], EFTP USING [AbortCode, Milliseconds]; EFTPImpl: CEDAR MONITOR LOCKS handle USING handle: Handle IMPORTS Endian, PrincOpsUtils, Process, PupHop, PupSocket EXPORTS EFTP = { Handle: TYPE = REF Object; Object: PUBLIC TYPE = MONITORED RECORD [ mode: {send, recv, dead}, sequenceNumber: INT, socket: PupSocket.Socket, buffer: PupSocket.Buffer, tries: NAT, code: EFTP.AbortCode, err: Rope.ROPE, cond: CONDITION ]; BlockTooBig: PUBLIC ERROR = CODE; InvalidCallSequence: PUBLIC ERROR = CODE; Timeout: PUBLIC SIGNAL = CODE; Trouble: PUBLIC ERROR [code: EFTP.AbortCode, err: Rope.ROPE] = CODE; CreateSender: PUBLIC PROC [him: Pup.Address, waitForAck: BOOL] RETURNS [Handle] = { timeout: INT _ PupHop.InitialTimeout[him.net, 1000]; handle: Handle _ NEW[Object]; handle.mode _ send; handle.sequenceNumber _ 0; handle.socket _ PupSocket.CreateEphemeral[ remote: him, sendBuffers: 1, recvBuffers: 1, getTimeout: timeout ]; handle.buffer _ PupSocket.AllocBuffer[handle.socket]; handle.tries _ 10; handle.code _ ok; handle.err _ NIL; TRUSTED { Process.SetTimeout[@handle.cond, Process.MsecToTicks[timeout]]; }; IF waitForAck THEN PutBlock[handle, ""]; RETURN[handle]; }; CreateReceiver: PUBLIC PROC [me: Pup.Address] RETURNS [Handle] = { handle: Handle _ NEW[Object]; handle.mode _ recv; RETURN[handle]; }; GetHisAddress: PUBLIC PROC [handle: Handle] RETURNS [Pup.Address] = { IF handle.socket = NIL THEN ERROR InvalidCallSequence; RETURN[PupSocket.GetRemoteAddress[handle.socket]]; }; Abort: PUBLIC PROC [handle: Handle, rope: Rope.ROPE] = { ENABLE UNWIND => NULL; IF handle.err # NIL THEN ERROR Trouble[handle.code, handle.err]; SELECT handle.mode FROM send => { IF handle.buffer = NIL THEN handle.buffer _ PupSocket.AllocBuffer[handle.socket]; handle.code _ externalSenderAbort; handle.err _ rope; handle.buffer.type _ eAbort; handle.buffer.id _ Endian.FFromInt[handle.sequenceNumber]; handle.buffer.hWord[0] _ handle.code.ORD; PupSocket.SetUserHWords[handle.buffer, 1]; PupSocket.AppendRope[handle.buffer, handle.err]; PupSocket.Put[handle.socket, handle.buffer]; handle.buffer _ NIL; }; recv => ERROR; -- ??? dead => RETURN; ENDCASE => ERROR; }; Finish: PUBLIC ENTRY PROC [handle: Handle] = { ENABLE UNWIND => NULL; IF handle.err # NIL THEN ERROR Trouble[handle.code, handle.err]; SELECT handle.mode FROM send => { id: Endian.FWORD _ Endian.FFromInt[handle.sequenceNumber]; DO FOR i: NAT IN [0..handle.tries) DO IF handle.buffer = NIL THEN handle.buffer _ PupSocket.AllocBuffer[handle.socket]; handle.buffer.type _ eEnd; handle.buffer.id _ id; PupSocket.SetUserBytes[handle.buffer, 0]; PupSocket.Put[handle.socket, handle.buffer]; handle.buffer _ NIL; handle.buffer _ PupSocket.Get[handle.socket]; IF handle.buffer = NIL THEN LOOP; SELECT handle.buffer.type FROM eAck => IF handle.buffer.id = id THEN GOTO Done; eAbort => { handle.code _ VAL[handle.buffer.hWord[0]]; handle.err _ PupSocket.ExtractAbortRope[handle.buffer]; ERROR Trouble[handle.code, handle.err]; }; ENDCASE => NULL; ENDLOOP; SIGNAL Timeout; REPEAT Done => NULL; ENDLOOP; }; recv => ERROR; -- ??? dead => RETURN; ENDCASE => ERROR; IF handle.buffer # NIL THEN PupSocket.FreeBuffer[handle.buffer]; handle.buffer _ NIL; PupSocket.Destroy[handle.socket]; handle.socket _ NIL; handle.err _ NIL; handle.mode _ dead; }; SetSendTimeout: PUBLIC PROC [handle: Handle, milliseconds: EFTP.Milliseconds, tries: NAT] = { ENABLE UNWIND => NULL; SELECT handle.mode FROM send => { TRUSTED { Process.SetTimeout[@handle.cond, Process.MsecToTicks[milliseconds]]; }; PupSocket.SetGetTimeout[handle.socket, milliseconds]; handle.tries _ tries; }; recv => ERROR InvalidCallSequence; dead => ERROR InvalidCallSequence; ENDCASE => ERROR; }; PutBlock: PUBLIC ENTRY PROC [handle: Handle, text: REF TEXT] = { ENABLE UNWIND => NULL; IF handle.err # NIL THEN ERROR Trouble[handle.code, handle.err]; SELECT handle.mode FROM send => { id: Endian.FWORD _ Endian.FFromInt[handle.sequenceNumber]; DO FOR i: NAT IN [0..handle.tries) DO IF handle.buffer = NIL THEN handle.buffer _ PupSocket.AllocBuffer[handle.socket]; handle.buffer.type _ eData; handle.buffer.id _ id; IF text.length > PupBuffer.maxDataBytes THEN ERROR BlockTooBig; TRUSTED { base: LONG POINTER = LOOPHOLE[text, LONG POINTER]+TEXT[0].SIZE; [] _ PrincOpsUtils.ByteBlt[ to: [ blockPointer: @handle.buffer.byte, startIndex: 0, stopIndexPlusOne: text.length], from: [ blockPointer: base, startIndex: 0, stopIndexPlusOne: text.length] ]; }; PupSocket.SetUserBytes[handle.buffer, text.length]; PupSocket.Put[handle.socket, handle.buffer]; handle.buffer _ NIL; handle.buffer _ PupSocket.Get[handle.socket]; IF handle.buffer = NIL THEN LOOP; SELECT handle.buffer.type FROM eAck => IF handle.buffer.id = id THEN GOTO Done; eAbort => { handle.code _ VAL[handle.buffer.hWord[0]]; handle.err _ PupSocket.ExtractAbortRope[handle.buffer]; ERROR Trouble[handle.code, handle.err]; }; ENDCASE => NULL; ENDLOOP; SIGNAL Timeout; REPEAT Done => NULL; ENDLOOP; }; recv => ERROR InvalidCallSequence; dead => ERROR InvalidCallSequence; ENDCASE => ERROR; IF handle.buffer # NIL THEN PupSocket.FreeBuffer[handle.buffer]; handle.buffer _ NIL; handle.sequenceNumber _ handle.sequenceNumber.SUCC; }; }. EFTPImpl.mesa Copyright c 1985 by Xerox Corporation. All rights reserved. Hal Murray, June 3, 1986 2:43:48 pm PDT Errors Create/Delete EFTP Abort packet happens to be the same format as a BSP Abort. Sending EFTP Abort packet happens to be the same format as a BSP Abort. Κφ˜codešœ ™ Kšœ Οmœ1™