<> <> <> <> <> DIRECTORY Basics USING[ BITSHIFT, BITXOR ], ConvertUnsafe USING[ ToRope ], GVBasics USING[ GVString, maxGVStringLength, oldestTime, Password, RName, Timestamp], GVProtocol USING[ bpw, FailureReason, GVSocket, Handle, ReceiveCount, ReceiveRC, ReceiveRName, ReceiveTimestamp, ReturnCode, RSOperation, SendCount, SendRName, SendRSOperation, SendTimestamp, StringSize ], IO USING[ EndOfStream, Flush, GetChar, PutChar, PutFR, PutRope, STREAM, UnsafeBlock, UnsafeGetBlock, UnsafePutBlock ], PupDefs USING[ AnyLocalPupAddress, PupPackageMake, SecondsToTocks ], PupStream USING[ PupAddress, PupByteStreamCreate, StreamClosing, TimeOut ], PupTypes USING[ Byte, fillInSocketID, PupAddress, PupSocketID ], Rope USING[ Fetch, Length, ROPE ]; GVProtocolImpl: CEDAR MONITOR IMPORTS Basics, ConvertUnsafe, GVProtocol, IO, PupDefs, PupStream, Rope EXPORTS GVBasics, GVProtocol = BEGIN OPEN GVProtocol; MakeKey: PUBLIC PROC[password: Rope.ROPE] RETURNS[ key: GVBasics.Password ] = BEGIN key _ ALL[0]; FOR i: CARDINAL IN CARDINAL[0..password.Length[]) DO j: [0..LENGTH[key]) = (i/bpw) MOD LENGTH[key]; c: WORD = LOOPHOLE[ IF password.Fetch[i] IN ['A..'Z] THEN password.Fetch[i] - 'A + 'a ELSE password.Fetch[i] ]; key[j] _ Basics.BITXOR[ key[j], Basics.BITSHIFT[c, IF (i MOD 2) = 0 THEN 9 ELSE 1]]; ENDLOOP; END; RopeFromTimestamp: PUBLIC PROC[stamp: GVBasics.Timestamp] RETURNS[Rope.ROPE] = { RETURN[ IO.PutFR["%b#%b@%g", [integer[stamp.net]], [integer[stamp.host]], [integer[stamp.time]] ] ] }; bpw: INT = GVProtocol.bpw; sockets: ARRAY GVProtocol.GVSocket OF PupTypes.PupSocketID _ [ none: [0,0], RSEnquiry: [0, 50B], RSPoll: [0, 52B], Lily: [0, 53B], MSPoll: [0, 54B], MSForward: [0, 55B], MSSend: [0, 56B], MSRetrieve: [0, 57B] ]; SetTestingMode: PUBLIC ENTRY PROCEDURE = BEGIN FOR s: GVProtocol.GVSocket IN GVProtocol.GVSocket DO sockets[s].a _ 1 ENDLOOP; END; GetSocket: PUBLIC ENTRY PROC[gv: GVSocket] RETURNS[PupTypes.PupSocketID] = { RETURN[ sockets[gv] ] }; myAddr: PupTypes.PupAddress; IsLocal: PUBLIC PROCEDURE[addr: PupTypes.PupAddress] RETURNS[ BOOLEAN ] = BEGIN RETURN[ addr.net = myAddr.net AND addr.host = myAddr.host ] END; Failed: PUBLIC SIGNAL[why: FailureReason, text: Rope.ROPE] = CODE; CreateStream: PUBLIC PROCEDURE[host: PupTypes.PupAddress, socket: GVProtocol.GVSocket, secs: CARDINAL _ 120 ] RETURNS[ GVProtocol.Handle ] = BEGIN ENABLE PupStream.StreamClosing => ERROR Failed[communicationError, text]; IF socket # none THEN host.socket _ sockets[socket]; RETURN[ PupStream.PupByteStreamCreate[host, PupDefs.SecondsToTocks[secs] ] ] END; SendNow: PUBLIC PROCEDURE[ str: GVProtocol.Handle ] = BEGIN ENABLE PupStream.StreamClosing => ERROR Failed[communicationError, text]; str.Flush[]; END; Byte: TYPE = [0..256); SendByte: PUBLIC PROCEDURE[ str: GVProtocol.Handle, byte: Byte ] = BEGIN ENABLE PupStream.StreamClosing => ERROR Failed[communicationError, text]; str.PutChar[LOOPHOLE[byte]]; END; ReceiveByte: PUBLIC PROCEDURE[ str: GVProtocol.Handle ] RETURNS[ byte: Byte ] = BEGIN ENABLE BEGIN PupStream.StreamClosing => ERROR Failed[communicationError, text]; PupStream.TimeOut => SIGNAL Failed[noData, "Server not sending data"]; IO.EndOfStream => ERROR Failed[protocolError, "Unexpected \"mark\""]; END; byte _ LOOPHOLE[str.GetChar[]]; END; SendBytes: PUBLIC PROC[str: GVProtocol.Handle, block: IO.UnsafeBlock] = BEGIN ENABLE PupStream.StreamClosing => ERROR Failed[communicationError, text]; str.UnsafePutBlock[block]; END; ReceiveBytes: PUBLIC UNSAFE PROC[str: GVProtocol.Handle, block: IO.UnsafeBlock] = TRUSTED BEGIN ENABLE BEGIN PupStream.StreamClosing => ERROR Failed[communicationError, text]; PupStream.TimeOut => SIGNAL Failed[noData, "Server not sending data"]; IO.EndOfStream => ERROR Failed[protocolError, "Protocol error: unexpected \"mark\""]; END; nBytes: INT = str.UnsafeGetBlock[block]; IF nBytes # block.count THEN ERROR Failed[protocolError, "Protocol error: unexpected \"mark\""]; END; SendGVString: PUBLIC PROC[ str: GVProtocol.Handle, rope: GVBasics.GVString] = BEGIN length: INT = rope.Length[]; IF length > GVBasics.maxGVStringLength THEN ERROR Failed[clientError, "Excessive rope length"]; GVProtocol.SendCount[str, length]; GVProtocol.SendCount[str, 0--ignored--]; SendRope[str, rope]; IF length MOD 2 # 0 THEN SendByte[str,0]; END; ReceiveGVString: PUBLIC PROC[ str: GVProtocol.Handle] RETURNS[GVBasics.GVString] = TRUSTED BEGIN string: STRING = [GVBasics.maxGVStringLength]; string.length _ GVProtocol.ReceiveCount[str]; [] _ GVProtocol.ReceiveCount[str]; IF string.length > string.maxlength THEN ERROR Failed[protocolError, "Protocol error: too many characters"]; ReceiveBytes[str, [LOOPHOLE[LONG[@string.text]], 0, bpw*(SIZE[StringBody[string.length]] - SIZE[StringBody[0]])]]; RETURN[ConvertUnsafe.ToRope[string]] END; SendRope: PUBLIC PROC[ str: GVProtocol.Handle, rope: Rope.ROPE] = BEGIN str.PutRope[rope ! PupStream.StreamClosing => ERROR Failed[communicationError, text]]; END; Enquire: PUBLIC PROCEDURE[str: GVProtocol.Handle, op: GVProtocol.RSOperation, name: GVBasics.RName, oldStamp: GVBasics.Timestamp _ GVBasics.oldestTime ] RETURNS[ rc: GVProtocol.ReturnCode, stamp: GVBasics.Timestamp ] = BEGIN GVProtocol.SendRSOperation[str, op]; GVProtocol.SendRName[str, name]; IF op IN [Expand .. CheckStamp] THEN GVProtocol.SendTimestamp[str, oldStamp]; SendNow[str]; rc _ GVProtocol.ReceiveRC[str]; IF rc.code = done AND op IN [Expand .. CheckStamp] THEN stamp _ GVProtocol.ReceiveTimestamp[str] ELSE stamp _ oldStamp; END; ReceiveRList: PUBLIC PROCEDURE[str: GVProtocol.Handle, work: PROCEDURE[GVBasics.RName] ] = BEGIN length: INT _ ReceiveCount[str]; WHILE length > 0 DO name: GVBasics.RName = GVProtocol.ReceiveRName[str]; length _ length - GVProtocol.StringSize[name]; work[name]; ENDLOOP; END; Init: PROC = TRUSTED BEGIN PupDefs.PupPackageMake[]; myAddr _ PupDefs.AnyLocalPupAddress[PupTypes.fillInSocketID]; END; Init[]; END.