CommDriverInterceptImpl.mesa
Copyright © 1986 by Xerox Corporation. All rights reserved.
Hal Murray, May 29, 1986 2:43:44 am PDT
DIRECTORY
CommDriver USING [Buffer, Network, NoThankYou, RecvInterceptor, RecvProc, RecvType, SendInterceptor, SendProc, SendType],
Process USING [Pause];
CommDriverInterceptImpl: CEDAR MONITOR
IMPORTS CommDriver, Process
EXPORTS CommDriver = {
Buffer: TYPE = CommDriver.Buffer;
Network: TYPE = CommDriver.Network;
networks: Network ← NIL;
numberOfNetworks: CARDINAL ← 0;
defaultRecvProcs: ARRAY CommDriver.RecvType OF CommDriver.RecvProc ← ALL[CommDriver.NoThankYou];
GetNetworkChain: PUBLIC PROC RETURNS [Network] = {
RETURN[networks];
};
GetNumberOfNetworks: PUBLIC PROC RETURNS [CARDINAL] = {
RETURN[numberOfNetworks];
};
AddNetwork: PUBLIC ENTRY PROC [network: Network] = {
IF network.next # NIL THEN ERROR;
network.arpa.recv ← defaultRecvProcs[arpa];
network.arpa.recvTranslate ← defaultRecvProcs[arpaTranslate];
network.xns.recv ← defaultRecvProcs[xns];
network.xns.recvTranslate ← defaultRecvProcs[xnsTranslate];
network.pup.recv ← defaultRecvProcs[pup];
network.pup.recvTranslate ← defaultRecvProcs[pupTranslate];
network.other.recv ← defaultRecvProcs[other];
network.other.recvTranslate ← defaultRecvProcs[otherTranslate];
network.error.recv ← defaultRecvProcs[error];
IF networks = NIL THEN networks ← network
ELSE {
FOR finger: Network ← networks, finger.next DO
IF finger.next # NIL THEN LOOP;
finger.next ← network;
EXIT;
ENDLOOP;
};
numberOfNetworks ← numberOfNetworks + 1;
network.index ← numberOfNetworks;
};
InsertReceiveProc: PUBLIC ENTRY PROC [
network: Network, -- NIL => all networks
type: CommDriver.RecvType,
proc: CommDriver.RecvProc] = {
ENABLE UNWIND => NULL;
IF network # NIL THEN { InsertReceiveInner[network, type, proc]; RETURN; };
FOR network: Network ← networks, network.next UNTIL network = NIL DO
InsertReceiveInner[network, type, proc];
ENDLOOP;
defaultRecvProcs[type] ← proc; -- only if all networks
};
SlotAlreadyCaptured: SIGNAL = CODE;
InsertReceiveInner: INTERNAL PROC [
network: Network,
type: CommDriver.RecvType,
proc: CommDriver.RecvProc] = {
interceptor: Interceptor ← network.interceptor;
IF interceptor = NIL THEN { -- normal case, no interception in progress
previous: CommDriver.RecvProc;
SELECT type FROM
arpa => previous ← network.arpa.recv;
arpaTranslate => previous ← network.arpa.recvTranslate;
xns => previous ← network.xns.recv;
xnsTranslate => previous ← network.xns.recvTranslate;
pup => previous ← network.pup.recv;
pupTranslate => previous ← network.pup.recvTranslate;
other => previous ← network.other.recv;
otherTranslate => previous ← network.other.recvTranslate;
error => previous ← network.error.recv;
ENDCASE => ERROR;
IF previous # CommDriver.NoThankYou THEN SIGNAL SlotAlreadyCaptured;
SELECT type FROM
arpa => network.arpa.recv ← proc;
arpaTranslate => network.arpa.recvTranslate ← proc;
xns => network.xns.recv ← proc;
xnsTranslate => network.xns.recvTranslate ← proc;
pup => network.pup.recv ← proc;
pupTranslate => network.pup.recvTranslate ← proc;
other => network.other.recv ← proc;
otherTranslate => network.other.recvTranslate ← proc;
error => network.error.recv ← proc;
ENDCASE => ERROR; }
ELSE { -- Interesting case, interception in progress
procs: REF Procs ← interceptor.procs;
IF procs.recv[type] # CommDriver.NoThankYou THEN SIGNAL SlotAlreadyCaptured;
procs.recv[type] ← proc; };
};
Interceptor: TYPE = REF InterceptorRep;
InterceptorRep: PUBLIC TYPE = RECORD [
next: Interceptor,
alive: BOOL,
procs: REF Procs,
network: Network,
sendMask: PACKED ARRAY CommDriver.SendType OF BOOL,
sendProc: CommDriver.SendInterceptor,
recvMask: PACKED ARRAY CommDriver.RecvType OF BOOL,
recvProc: CommDriver.RecvInterceptor,
data: REF ANY,
promiscuous: BOOL ];
Procs: TYPE = RECORD [
send: ARRAY CommDriver.SendType OF CommDriver.SendProc,
recv: ARRAY CommDriver.RecvType OF CommDriver.RecvProc ];
CreateInterceptor: PUBLIC ENTRY PROC [
network: Network,
sendMask: PACKED ARRAY CommDriver.SendType OF BOOL,
sendProc: CommDriver.SendInterceptor,
recvMask: PACKED ARRAY CommDriver.RecvType OF BOOL,
recvProc: CommDriver.RecvInterceptor,
data: REF ANY,
promiscuous: BOOL]
RETURNS [interceptor: Interceptor] = {
others: Interceptor ← network.interceptor;
procs: REF Procs;
IF others # NIL THEN procs ← others.procs
ELSE
procs ← NEW[Procs ← [
send: [
arpa: network.arpa.send,
arpaReturn: network.arpa.return,
arpaTranslate: network.arpa.sendTranslate,
xns: network.xns.send,
xnsReturn: network.xns.return,
xnsTranslate: network.xns.sendTranslate,
pup: network.pup.send,
pupReturn: network.pup.return,
pupTranslate: network.pup.sendTranslate,
other: network.other.send,
otherReturn: network.other.return,
otherTranslate: network.other.sendTranslate,
raw: network.raw.send],
recv: [
arpa: network.arpa.recv,
arpaTranslate: network.arpa.recvTranslate,
xns: network.xns.recv,
xnsTranslate: network.xns.recvTranslate,
pup: network.pup.recv,
pupTranslate: network.pup.recvTranslate,
other: network.other.recv,
otherTranslate: network.other.recvTranslate,
error: network.error.recv] ]];
interceptor ← NEW[InterceptorRep ← [
next: others,
alive: TRUE,
procs: procs,
network: network,
sendMask: sendMask,
sendProc: sendProc,
recvMask: recvMask,
recvProc: recvProc,
data: data,
promiscuous: promiscuous] ];
network.interceptor ← interceptor;
IF others = NIL THEN {
network.arpa.send ← IPSend;
network.arpa.return ← IPReturn;
network.arpa.recv ← IPRecv;
network.arpa.sendTranslate ← IPSendTranslate;
network.arpa.recvTranslate ← IPRecvTranslate;
network.xns.send ← NSSend;
network.xns.return ← NSReturn;
network.xns.recv ← NSRecv;
network.xns.sendTranslate ← NSSendTranslate;
network.xns.recvTranslate ← NSRecvTranslate;
network.pup.send ← PupSend;
network.pup.return ← PupReturn;
network.pup.recv ← PupRecv;
network.pup.sendTranslate ← PupSendTranslate;
network.pup.recvTranslate ← PupRecvTranslate;
network.other.send ← OtherSend;
network.other.return ← OtherReturn;
network.other.recv ← OtherRecv;
network.other.sendTranslate ← OtherSendTranslate;
network.other.recvTranslate ← OtherRecvTranslate;
network.raw.send ← RawSend;
network.error.recv ← ErrorRecv; };
IF promiscuous THEN network.setPromiscuous[network, TRUE];
};
DestroyInterceptor: PUBLIC ENTRY PROC [interceptor: Interceptor] = {
network: Network ← interceptor.network;
IF ~interceptor.alive THEN RETURN;
interceptor.alive ← FALSE;
IF network.interceptor = interceptor THEN {
IF interceptor.next = NIL THEN {
procs: REF Procs ← interceptor.procs;
network.setPromiscuous[network, FALSE];
Yetch. There is a race on turning off Promiscuous vs setting the procs back to normal.
Process.Pause[5];
network.arpa.send ← procs.send[arpa];
network.arpa.return ← procs.send[arpaReturn];
network.arpa.sendTranslate ← procs.send[arpaTranslate];
network.xns.send ← procs.send[xns];
network.xns.return ← procs.send[xnsReturn];
network.xns.sendTranslate ← procs.send[xnsTranslate];
network.pup.send ← procs.send[pup];
network.pup.return ← procs.send[pupReturn];
network.pup.sendTranslate ← procs.send[pupTranslate];
network.other.send ← procs.send[other];
network.other.return ← procs.send[otherReturn];
network.other.sendTranslate ← procs.send[otherTranslate];
network.raw.send ← procs.send[raw];
network.arpa.recv ← procs.recv[arpa];
network.arpa.recvTranslate ← procs.recv[arpaTranslate];
network.xns.recv ← procs.recv[xns];
network.xns.recvTranslate ← procs.recv[xnsTranslate];
network.pup.recv ← procs.recv[pup];
network.pup.recvTranslate ← procs.recv[pupTranslate];
network.other.recv ← procs.recv[other];
network.other.recvTranslate ← procs.recv[otherTranslate];
network.error.recv ← procs.recv[error]; };
network.interceptor ← interceptor.next; }
ELSE {
first: Interceptor ← network.interceptor;
FOR finger: Interceptor ← first, finger.next DO -- NIL fault if not found
IF finger.next # interceptor THEN LOOP;
finger.next ← interceptor.next;
EXIT;
ENDLOOP; };
};
IPSend: CommDriver.SendProc = {
SendOne[arpa, network, buffer, bytes];
};
IPReturn: CommDriver.SendProc = {
SendOne[arpaReturn, network, buffer, bytes];
};
IPSendTranslate: CommDriver.SendProc = {
SendOne[arpaTranslate, network, buffer, bytes];
};
NSSend: CommDriver.SendProc = {
SendOne[xns, network, buffer, bytes];
};
NSReturn: CommDriver.SendProc = {
SendOne[xnsReturn, network, buffer, bytes];
};
NSSendTranslate: CommDriver.SendProc = {
SendOne[xnsTranslate, network, buffer, bytes];
};
PupSend: CommDriver.SendProc = {
SendOne[pup, network, buffer, bytes];
};
PupReturn: CommDriver.SendProc = {
SendOne[pupReturn, network, buffer, bytes];
};
PupSendTranslate: CommDriver.SendProc = {
SendOne[pupTranslate, network, buffer, bytes];
};
OtherSend: CommDriver.SendProc = {
SendOne[other, network, buffer, bytes];
};
OtherReturn: CommDriver.SendProc = {
SendOne[otherReturn, network, buffer, bytes];
};
OtherSendTranslate: CommDriver.SendProc = {
SendOne[otherTranslate, network, buffer, bytes];
};
RawSend: CommDriver.SendProc = {
SendOne[raw, network, buffer, bytes];
};
SendOne: PROC [send: CommDriver.SendType, network: Network, buffer: Buffer, bytes: NAT] = {
first: Interceptor ← network.interceptor;
kill: BOOLFALSE;
IF first = NIL THEN RETURN; -- Race with DeleteInterceptor
FOR interceptor: Interceptor ← first, interceptor.next UNTIL interceptor = NIL DO
IF ~interceptor.sendMask[send] THEN LOOP;
kill ← kill OR interceptor.sendProc[send, interceptor.data, network, buffer, bytes];
ENDLOOP;
IF kill THEN RETURN;
first.procs.send[send][network, buffer, bytes];
};
IPRecv: CommDriver.RecvProc = {
RETURN[RecvOne[arpa, network, buffer, bytes]];
};
IPRecvTranslate: CommDriver.RecvProc = {
RETURN[RecvOne[arpaTranslate, network, buffer, bytes]];
};
NSRecv: CommDriver.RecvProc = {
RETURN[RecvOne[xns, network, buffer, bytes]];
};
NSRecvTranslate: CommDriver.RecvProc = {
RETURN[RecvOne[xnsTranslate, network, buffer, bytes]];
};
PupRecv: CommDriver.RecvProc = {
RETURN[RecvOne[pup, network, buffer, bytes]];
};
PupRecvTranslate: CommDriver.RecvProc = {
RETURN[RecvOne[pupTranslate, network, buffer, bytes]];
};
OtherRecv: CommDriver.RecvProc = {
RETURN[RecvOne[other, network, buffer, bytes]];
};
OtherRecvTranslate: CommDriver.RecvProc = {
RETURN[RecvOne[otherTranslate, network, buffer, bytes]];
};
ErrorRecv: PROC [network: Network, buffer: Buffer, bytes: NAT] RETURNS [Buffer] = {
RETURN[RecvOne[error, network, buffer, bytes]];
};
RecvOne: PROC [recv: CommDriver.RecvType, network: Network, buffer: Buffer, bytes: NAT] RETURNS [Buffer] = {
first: Interceptor ← network.interceptor;
forMe: BOOL ← network.isThisForMe[network, buffer];
kill: BOOLFALSE;
IF first = NIL THEN RETURN[buffer]; -- Race with DeleteInterceptor
FOR interceptor: Interceptor ← first, interceptor.next UNTIL interceptor = NIL DO
IF ~interceptor.recvMask[recv] THEN LOOP;
IF ~forMe AND ~interceptor.promiscuous THEN LOOP;
kill ← kill OR interceptor.recvProc[recv, interceptor.data, network, buffer, bytes];
ENDLOOP;
IF kill THEN RETURN[buffer];
IF ~forMe THEN RETURN[buffer];
RETURN[first.procs.recv[recv][network, buffer, bytes]];
};
}.