DIRECTORY Arpa USING [Address], ArpaExtras USING [MyAddress], ArpaTCP, ArpaTCPOps USING [Open, Close, Abort, TCPHandle, TCPRcvBuffer, SetUrgent, WaitForUrgentData, GetNextDatagram, SendCurrentDatagram, WaitForListenerOpen], IO USING [CreateStream, CreateStreamProcs, EndOfStream, Error, STREAM, StreamProcs, UnsafeBlock, UnsafeGetBlock, UnsafePutBlock], PrincOpsUtils USING [ByteBlt]; ArpaTCPMain: CEDAR PROGRAM IMPORTS ArpaExtras, IO, PrincOpsUtils, ArpaTCPOps EXPORTS ArpaTCP = BEGIN OPEN ArpaTCP; TCPStreamProcs: REF IO.StreamProcs = IO.CreateStreamProcs[ variety: inputOutput, class: $TCP, getChar: GetChar, endOf: EndOf, charsAvail: CharsAvail, getBlock: GetBlock, unsafeGetBlock: UnsafeGetBlock, putChar: PutChar, putBlock: PutBlock, unsafePutBlock: UnsafePutBlock, flush: Flush, close: Close, getIndex: GetIndex ]; Error: PUBLIC ERROR [reason: Reason] = CODE; Timeout: PUBLIC --INFORMATIONAL-- SIGNAL = CODE; CreateTCPStream: PUBLIC PROC [tcpInfo: TCPInfo] RETURNS [s: STREAM] ~ { handle: ArpaTCPOps.TCPHandle _ ArpaTCPOps.Open[tcpInfo]; s _ IO.CreateStream[streamProcs: TCPStreamProcs, streamData: handle]; }; AbortTCPStream: PUBLIC PROC [s: STREAM] ~ { handle: ArpaTCPOps.TCPHandle _ NARROW[s.streamData]; IF handle # NIL THEN ArpaTCPOps.Abort[handle]; }; WaitForListenerOpen: PUBLIC PROC [s: STREAM, timeout: INT _ neverTimeout] ~ { handle: ArpaTCPOps.TCPHandle _ NARROW[s.streamData]; ArpaTCPOps.WaitForListenerOpen[handle, timeout]; }; GetRemoteSocket: PUBLIC PROC [s: STREAM] RETURNS [addr: Arpa.Address, port: Port] ~ { handle: ArpaTCPOps.TCPHandle _ NARROW[s.streamData]; addr _ handle.foreignAddr; port _ handle.foreignPort; }; GetLocalSocket: PUBLIC PROC [s: STREAM] RETURNS [addr: Arpa.Address, port: Port] ~ { handle: ArpaTCPOps.TCPHandle _ NARROW[s.streamData]; addr _ ArpaExtras.MyAddress[]; port _ handle.localPort; }; SendNow: PUBLIC PROC [s: STREAM] ~ { handle: ArpaTCPOps.TCPHandle _ NARROW[s.streamData]; handle.SendCurrentDatagram[FALSE ! Error => {handle.reason _ reason; GOTO error}]; EXITS error => ERROR IO.Error[$Failure, s]; }; SetUrgent: PUBLIC PROC [s: STREAM] ~ { handle: ArpaTCPOps.TCPHandle _ NARROW[s.streamData]; handle.SetUrgent[]; }; WaitForUrgentData: PUBLIC PROC [s: STREAM] RETURNS [urgentIndex: INT] ~ { handle: ArpaTCPOps.TCPHandle _ NARROW[s.streamData]; RETURN [handle.WaitForUrgentData[] - handle.irs - 1]; }; ErrorFromStream: PUBLIC PROC [s: STREAM] RETURNS [reason: Reason] ~ { handle: ArpaTCPOps.TCPHandle _ NARROW[s.streamData]; RETURN [handle.reason]; }; GetChar: PROC [self: STREAM] RETURNS [c: CHAR] ~ { handle: ArpaTCPOps.TCPHandle _ NARROW[self.streamData]; rb: REF ArpaTCPOps.TCPRcvBuffer _ handle.currentInputBuffer; IF rb # NIL AND rb.dataByteCount > 0 THEN { c _ LOOPHOLE[rb.datagramPtr.body.bytes[rb.dataOffset]]; rb.dataOffset _ rb.dataOffset + 1; rb.dataByteCount _ rb.dataByteCount - 1; } ELSE TRUSTED { buff: PACKED ARRAY [0..1] OF CHAR; n: INT = IO.UnsafeGetBlock[self, [base: LOOPHOLE[LONG[@buff]], startIndex: 0, count: 1]]; IF n = 0 THEN ERROR IO.EndOfStream[self]; RETURN[buff[0]]; }; }; EndOf: PROC [self: STREAM] RETURNS [BOOL] ~ { handle: ArpaTCPOps.TCPHandle _ NARROW[self.streamData]; RETURN [(SELECT handle.state FROM closed, closing, closeWait, timeWait, lastAck => TRUE, ENDCASE => FALSE) AND (handle.currentInputBuffer=NIL OR handle.currentInputBuffer.dataByteCount<=0) AND handle.readyToReadQueue=NIL]; }; CharsAvail: PROC [self: STREAM, wait: BOOL _ FALSE] RETURNS [INT] ~ { handle: ArpaTCPOps.TCPHandle _ NARROW[self.streamData]; WHILE handle.currentInputBuffer=NIL OR handle.currentInputBuffer.dataByteCount<=0 DO IF handle.readyToReadQueue=NIL AND ~wait THEN RETURN [0]; handle.GetNextDatagram[ ! Error => GOTO error]; ENDLOOP; RETURN [handle.currentInputBuffer.dataByteCount]; EXITS error => RETURN[1]; -- will cause client to read the stream and get the error }; GetBlock: PROC [self: STREAM, block: REF TEXT, startIndex: NAT, count: NAT] RETURNS [nBytesRead: NAT] ~ TRUSTED { nBytesRead _ self.UnsafeGetBlock[[ base: LOOPHOLE[BASE[DESCRIPTOR[block]]], startIndex: startIndex, count: MIN[count, block.maxLength-startIndex] ] ]; block.length _ startIndex+nBytesRead; }; UnsafeGetBlock: UNSAFE PROC [self: STREAM, block: IO.UnsafeBlock] RETURNS [nBytesRead: INT] ~ UNCHECKED { handle: ArpaTCPOps.TCPHandle _ NARROW[self.streamData]; rb: REF ArpaTCPOps.TCPRcvBuffer _ handle.currentInputBuffer; nBytes: INT; nBytesRead _ 0; WHILE block.count>0 DO IF rb = NIL OR rb.dataByteCount <= 0 THEN handle.GetNextDatagram[ ! Error => {handle.reason _ reason; GOTO error}]; rb _ handle.currentInputBuffer; nBytes _ IF block.base = NIL -- means "discard data" THEN MIN[block.count, rb.dataByteCount] ELSE PrincOpsUtils.ByteBlt[ to: [blockPointer: block.base, startIndex: block.startIndex, stopIndexPlusOne: block.startIndex+block.count], from: [blockPointer: @rb.datagramPtr.body, startIndex: rb.dataOffset, stopIndexPlusOne: rb.dataOffset+rb.dataByteCount] ]; block.startIndex _ block.startIndex + nBytes; block.count _ block.count - nBytes; nBytesRead _ nBytesRead + nBytes; rb.dataOffset _ rb.dataOffset + nBytes; rb.dataByteCount _ rb.dataByteCount - nBytes; REPEAT error => IF handle.reason # localClose AND handle.reason # remoteClose THEN ERROR IO.Error[$Failure, self]; ENDLOOP; }; PutChar: PROC [self: STREAM, char: CHAR] ~ { handle: ArpaTCPOps.TCPHandle _ NARROW[self.streamData]; IF handle.currentOutputDatagram # NIL AND handle.currentOutputPtr < handle.currentOutputLimit THEN { handle.currentOutputDatagram.body.bytes[handle.currentOutputPtr] _ LOOPHOLE[char]; handle.currentOutputPtr _ handle.currentOutputPtr + 1; } ELSE TRUSTED { buff: PACKED ARRAY [0..1] OF CHAR; buff[0] _ char; IO.UnsafePutBlock[self, [base: LOOPHOLE[LONG[@buff]], startIndex: 0, count: 1]]; }; }; PutBlock: PROC [self: STREAM, block: REF READONLY TEXT, startIndex: NAT, count: NAT] ~ TRUSTED { self.UnsafePutBlock[[ base: LOOPHOLE[BASE[DESCRIPTOR[block]]], startIndex: startIndex, count: MIN[count, block.length-startIndex] ] ]; }; UnsafePutBlock: PROC [self: STREAM, block: IO.UnsafeBlock] ~ TRUSTED { handle: ArpaTCPOps.TCPHandle _ NARROW[self.streamData]; nBytes: INT; WHILE block.count>0 DO IF handle.currentOutputDatagram = NIL OR handle.currentOutputPtr >= handle.currentOutputLimit THEN handle.SendCurrentDatagram[FALSE ! Error => {handle.reason _ reason; GOTO error}]; nBytes _ IF block.base = NIL -- means "ignore data" THEN MIN[block.count, handle.currentOutputLimit - handle.currentOutputPtr] ELSE PrincOpsUtils.ByteBlt[ from: [blockPointer: block.base, startIndex: block.startIndex, stopIndexPlusOne: block.startIndex+block.count], to: [blockPointer: @handle.currentOutputDatagram.body, startIndex: handle.currentOutputPtr, stopIndexPlusOne: handle.currentOutputLimit] ]; block.startIndex _ block.startIndex + nBytes; block.count _ block.count - nBytes; handle.currentOutputPtr _ handle.currentOutputPtr + nBytes; ENDLOOP; EXITS error => ERROR IO.Error[$Failure, self]; }; Flush: PROC [self: STREAM] ~ { handle: ArpaTCPOps.TCPHandle _ NARROW[self.streamData]; handle.SendCurrentDatagram[TRUE ! Error => {handle.reason _ reason; GOTO error}]; EXITS error => ERROR IO.Error[$Failure, self]; }; Close: PROC [self: STREAM, abort: BOOL _ FALSE] ~ { handle: ArpaTCPOps.TCPHandle _ NARROW[self.streamData]; handle.Close[ ! Error => {handle.reason _ reason; GOTO error}]; EXITS error => ERROR IO.Error[$Failure, self]; }; GetIndex: PROC [self: STREAM] RETURNS [INT] ~ { handle: ArpaTCPOps.TCPHandle _ NARROW[self.streamData]; RETURN [handle.rcvNxt - handle.irs - 1]; }; END. ΆArpaTCPMain.mesa Copyright (C) 1983, 1985 by Xerox Corporation. All rights reserved. The following program was created in 1983 but has not been published within the meaning of the copyright law, is furnished under license, and may not be used, copied and/or disclosed except in accordance with the terms of said license. Last Edited by: Nichols, September 1, 1983 4:39 pm Last Edited by: Taft, January 2, 1984 4:18 pm Last Edited by: HGM, April 17, 1984 7:06:25 pm PST Weiser, October 19, 1987 10:44:49 pm PDT Doug Terry, November 16, 1987 10:28:40 am PST Hal Murray May 16, 1985 3:13:52 am PDT John Larson, October 11, 1987 9:40:30 pm PDT Like IO.Flush[s], except that Flush waits for the packets to be acknowledged and SendNow doesn't. Treat remoteClose or localClose as EndOfStream; that is, just exit the loop and return the number of bytes successfully transferred (which might be zero). This gives the input index, not the output index. ΚΈ– "cedar" style˜head™Icode2šœ―™―Icode™2J™-J™2M™(M™-J™&M™,J™šΟk ˜ Lšœœ ˜Lšœ œ ˜Lšœ˜Lšœ œ‡˜˜Lšœœ7œ<˜Lšœœ ˜——J˜šΟn œœ˜Lšœ œ˜1Lšœ ˜Lšœœ ˜šžœœœœ˜:L˜L˜ L˜L˜ L˜L˜L˜L˜L˜L˜L˜ L˜ L˜L˜—Lšžœœœœ˜,Lš žœœΟcœœœ˜0š žœœœœœ˜GLšœ8˜8LšœœB˜H—šžœœœœ˜+Lšœœ˜4Lšœ œœ˜1—š žœœœœ œ˜MLšœœ˜4Lšœ3˜3—š žœœœœœ%˜ULšœœ˜4Lšœ˜Lšœ˜Lšœ˜L˜—š žœœœœœ%˜TMšœœ˜4Lšœ˜M˜M˜—šžœœœœ˜$L™aLšœœ˜4Lšœœ%œ ˜Rš˜Lšœ œœ˜%—L˜—šž œœœœ˜&Lšœœ˜4L˜L˜—š žœœœœœœ˜ILšœœ˜4Lšœ/˜5L˜—š žœœœœœ˜ELšœœ˜4Lšœ˜L˜—š žœœœœœ˜2Lšœœ˜7Lšœœ5˜<šœœœœ˜+Lšœœ+˜7L˜"Lšœ*˜*—šœœ˜Lš œœœœœ˜"Lš œœœœœ$˜YLšœœœœ˜)Lšœ ˜—L˜—š žœœœœœ˜-Lšœœ˜7šœœ˜!Lšœ1œ˜6Lšœœœœœ-œœ˜…—L˜—šž œœœœœœœ˜ELšœœ˜7šœœœ,˜TLš œœœœœ˜9Lšœ#œ˜/Lšœ˜—Lšœ+˜1š˜Lšœ œŸ9˜M—L˜—šžœœœ œœœ œœœœ˜qšœ"˜"Lšœœœ œ ˜(Lšœ˜Lšœœ(˜2—Lšœ%˜%L˜—šžœœœœ œœœ œ˜iLšœœ˜7Lšœœ5˜