GrapevineUser (Cedar) - subroutines for mail and reg server protocols
GVProtocolImpl.mesa
Andrew Birrell 23-Jan-81 17:07:47
Last Edited by: Levin, June 24, 1983 5:29 pm
DIRECTORY
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 ],
PrincOpsUtils USING[ BITSHIFT, BITXOR ],
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 ConvertUnsafe, GVProtocol, IO, PrincOpsUtils, 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] ← PrincOpsUtils.BITXOR[ key[j],
PrincOpsUtils.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.stopIndexPlusOne-block.startIndex)
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];
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, [string, bpw*SIZE[StringBody[0]], bpw*SIZE[StringBody[string.length]]]];
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.