CourierBindingServerImpl.mesa
Copyright (C) 1985, 1986 by Xerox Corporation. All rights reserved.
kam 17-Jan-86 11:14:30
Bill Jackson (bj) June 23, 1986 1:50:48 am PDT
DIRECTORY
CrRPC USING [Handle, PutArgsProc],
Rope USING [ROPE],
CourierBinding USING [Address, Predicate, Range, Registration, RegistrationObject],
CourierBindingProtocol USING [program, version, socket];
CourierBindingServerImpl: CEDAR MONITOR
EXPORTS CourierBinding ~ {
Copied Types
Address: TYPE ~ CourierBinding.Address;
Handle: TYPE ~ CrRPC.Handle;
Predicate: TYPE ~ CourierBinding.Predicate;
PutArgsProc: TYPE ~ CrRPC.PutArgsProc;
Range: TYPE ~ CourierBinding.Range;
Registration: TYPE ~ CourierBinding.Registration;
RegistrationObject: TYPE ~ CourierBinding.RegistrationObject;
ROPE: TYPE ~ Rope.ROPE;
Types
RegistrationList: TYPE ~ LIST OF Registration;
Global State (Monitored)
registered: RegistrationList;
Inline Procs
Intersect: PROC [a, b: Range]RETURNS [Range] ~ INLINE {
RETURN[[MAX[a.lowVersion, b.lowVersion], MIN[a.highVersion, b.highVersion]]];
};
LegalRange: PROC [r: Range] RETURNS [BOOLEAN] ~ INLINE {
RETURN[r.lowVersion <= r.highVersion];
};
Error Routines
Error: ERROR[r: ROPE] ~ CODE;
RaiseError: PROC [r: ROPE] ~ {
Error[r]
};
RegistrationList Procs
Compare: PROC [i, j: Registration] RETURNS [x: {less, equal, greater}] ~ {
SELECT TRUE FROM
(i.program < j.program) => {
RETURN [less];
};
(i.program = j.program) => {
SELECT TRUE FROM
(i.range.lowVersion < j.range.lowVersion) => {
RETURN [less];
};
(i.range.lowVersion = j.range.lowVersion) => {
this should be illegal
SELECT TRUE FROM
(i.range.highVersion < j.range.highVersion) => {
RETURN [less];
};
(i.range.highVersion = j.range.highVersion) => {
RETURN [equal];
};
ENDCASE => {
RETURN [greater];
};
};
ENDCASE => {
RETURN [greater];
};
};
ENDCASE => {
RETURN [greater];
};
};
InsertInternal: INTERNAL PROC [n: Registration] ~ {
g: RegistrationList;
New Head
IF (registered = NIL) OR (Compare[n, registered.first] = greater) THEN {
registered ← CONS[n, registered];
RETURN;
};
New Internal Node (trick is that g.first is already less)
FOR g ← registered, g.rest UNTIL (g.rest = NIL) DO
SELECT Compare[g.rest.first, n] FROM
less => {
NULL;
};
equal => {
this is pretty nasty! What if (when!) they collide?
RaiseError["Abort to smash old Registration"
! ABORTED => {
g.rest ← CONS[n, g.rest];
CONTINUE;
}
];
};
ENDCASE => {
g.rest ← CONS[n, g.rest];
};
ENDLOOP;
New Tail
g.rest ← CONS[n, NIL];
};
Locate: INTERNAL PROC [program: CARD, version: CARDINAL] ~ {
};
RemoveInternal: INTERNAL PROC [n: Registration] ~ {
g: RegistrationList;
Delete Head
IF (registered = NIL) THEN ERROR;
IF (Compare[n, registered.first] = equal) THEN {
registered ← registered.rest;
RETURN;
};
Delete Internal Node (trick is that g.first is already less)
FOR g ← registered, g.rest UNTIL (g.rest = NIL) DO
SELECT Compare[g.rest.first, n] FROM
less => {
NULL;
};
equal => {
g ← g.rest;
};
ENDCASE => {
ERROR; -- not here!
};
ENDLOOP;
Reached Tail
ERROR;
};
Dispatcher & Worker Bees
Dispatcher: PROC [h: Handle, program: CARD, version: CARDINAL] ~ {
};
Init: PROC ~ {
token: Server ← CreateServer[$EXCHANGE, program, [version, version], socket, Dispatcher];
StartListener[];
};
Funny Procs
MaybeSendReply: PROC [b: Buffer.NSBuffer, trans: CARDINAL, program: LONG CARDINAL, sH: Stream.Handle] ~ {
intersection: Courier.VersionRange ← Exports[program, sH];
IF LegalRange[intersection] THEN {
msg: REF return CourierBindingProtocol.Message ← LOOPHOLE[@b.ns.exchangeBody];
Socket.SwapSourceAndDestination[b];
Socket.SetPacketWords[b, CourierBindingProtocol.sizeReply];
msg^ ← [
range, return[
transaction: trans,
response: [versions: intersection, me: Courier.LocalSystemElement[]]]];
Socket.PutPacket[ch, b]
}
ELSE Socket.ReturnBuffer[b];
};
SendErrorReply: PROC [b: Buffer.NSBuffer, type: CourierProtocol.RejectCode, trans: CARDINAL] ~ {
msg: REF reject CourierBindingProtocol.Message ← LOOPHOLE[@b.ns.exchangeBody];
IF HostNumbers.IsMulticastID[LOOPHOLE[@b.ns.destination.host]] THEN {
Socket.ReturnBuffer[b];
RETURN
};
Socket.SwapSourceAndDestination[b];
msg^ ← [protRange: range, body: reject[transaction: trans, rejectBody:]];
SELECT type FROM
noSuchProgramNumber => {
msg.rejectBody ← noSuchProgramNumber[];
Socket.SetPacketWords[
b,
CourierBindingProtocol.pexOverhead + SIZE[
noSuchProgramNumber reject CourierBindingProtocol.Message]]};
noSuchProcedureValue => {
msg.rejectBody ← noSuchProcedureValue[];
Socket.SetPacketWords[
b,
CourierBindingProtocol.pexOverhead + SIZE[
noSuchProcedureValue reject CourierBindingProtocol.Message]]};
invalidArguments => {
msg.rejectBody ← invalidArguments[];
Socket.SetPacketWords[
b,
CourierBindingProtocol.pexOverhead + SIZE[
invalidArguments reject CourierBindingProtocol.Message]]};
noSuchVersionNumber => {
msg.rejectBody ← noSuchVersionNumber[
[CourierBindingProtocol.version, CourierBindingProtocol.version]];
Socket.SetPacketWords[
b,
CourierBindingProtocol.pexOverhead + SIZE[
noSuchVersionNumber reject CourierBindingProtocol.Message]]};
ENDCASE;
Socket.PutPacket[ch, b];
};
StartListener: PROC ~ {
Socket.SetWaitTime[(ch ← Socket.Create[CourierBindingProtocol.socket]), Socket.WaitTime.LAST];
Process.Detach[FORK Watcher[]];
};
Watcher: PROC ~ {
DO
ENABLE ABORTED => EXIT;
b ← Socket.GetPacket[ch];
h ← LOOPHOLE[@b.ns.exchangeBody];
WITH messageBody: h^ SELECT FROM
call =>
SELECT TRUE FROM
messageBody.program # CourierInternal.ExchWords[
CourierBindingProtocol.program] AND
messageBody.program # CourierInternal.ExchWords[
CourierBindingProtocol.oldProgram] =>
SendErrorReply[b, noSuchProgramNumber, messageBody.transaction];
messageBody.procedure # CourierBindingProtocol.procedure =>
SendErrorReply[b, noSuchProcedureValue, messageBody.transaction];
messageBody.version # CourierBindingProtocol.version =>
SendErrorReply[b, noSuchVersionNumber, messageBody.transaction];
ENDCASE => {
block: Environment.Block ← [
LOOPHOLE[@messageBody.request],
0,
Socket.GetPacketBytes[b] - (CourierBindingProtocol.pexOverhead + CourierBindingProtocol.callOverhead) * Environment.bytesPerWord
];
sH: Stream.Handle ← MemoryStream.Create[block];
MaybeSendReply[b, messageBody.transaction, CourierInternal.ExchWords[messageBody.request.program], sH];
MemoryStream.Destroy[sH];
};
ENDCASE => Socket.ReturnBuffer[b];
ENDLOOP;
};
Entry Procs
Exports: ENTRY PROC [program: LONG CARDINAL, sH: Stream.Handle] RETURNS [exported: Courier.VersionRange ← [1, 0]] ~ {
ENABLE UNWIND => NULL;
Description: Courier.Description ~ {
data: REF ArgRecord ← notes.noteSize[SIZE[ArgRecord]];
notes.noteLongCardinal[@data.program];
notes.noteDisjointData[@data.user, (IF reg = NIL OR argProblem THEN NIL ELSE reg.description)];
};
arg: ArgRecord;
argProblem: BOOLEANFALSE;
exports: REF Courier.Exports ← Courier.EnumerateExports[];
i: CARDINAL;
reg: REF Registered ← registered;
UNTIL ((reg = NIL) OR (reg.program = program)) DO reg ← reg.next ENDLOOP;
Courier.DeserializeParameters[[@arg, Description], sH
! Courier.Error => {argProblem ← TRUE; CONTINUE}];
FOR i IN [0..exports.LENGTH) DO
IF (exports[i].programNumber = program)
AND LegalRange[(exported ← Intersect[arg.range, exports[i].versionRange])]
AND(argProblem OR (reg = NIL) OR (reg.predicate = NIL) OR reg.predicate[program, exported, arg.user]) THEN {
EXIT;
};
REPEAT
FINISHED => { exported ← [1, 0]; };
ENDLOOP;
};
Register: PUBLIC ENTRY PROC [program: CARD, range: Range, predicate: Predicate, clientData: REF] RETURNS [r: Registration] ~ {
ENABLE UNWIND => NULL;
r ← NEW [RegistrationObject ← [clientData, predicate, program, range]];
InsertInternal[r];
};
UnRegister: PUBLIC ENTRY PROC [r: Registration] ~ {
ENABLE UNWIND => NULL;
RemoveInternal[r];
};
Init[];
}...