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] ~ {
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
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] ~ {
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
equal => {
g ← g.rest;
};
ENDCASE => {
ERROR; -- not here!
};
ENDLOOP;
};
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: BOOLEAN ← FALSE;
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[];