DriverInterceptImpl.mesa
Copyright © 1986 by Xerox Corporation. All rights reserved.
Hal Murray, May 12, 1986 11:10:04 pm PDT
DIRECTORY
Driver USING [Buffer, Network, NoThankYou, RecvInterceptor, RecvProc, RecvType, SendInterceptor, SendProc, SendType],
Process USING [Pause];
DriverInterceptImpl: CEDAR MONITOR
IMPORTS Driver, Process
EXPORTS Driver = {
Buffer: TYPE = Driver.Buffer;
Network: TYPE = Driver.Network;
networks: Network ← NIL;
numberOfNetworks: CARDINAL ← 0;
defaultRecvProcs: ARRAY Driver.RecvType OF Driver.RecvProc ← ALL[Driver.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.ip.recv ← defaultRecvProcs[ip];
network.ip.recvTranslate ← defaultRecvProcs[ipTranslate];
network.ns.recv ← defaultRecvProcs[ns];
network.ns.recvTranslate ← defaultRecvProcs[nsTranslate];
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: Driver.RecvType,
proc: Driver.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: Driver.RecvType,
proc: Driver.RecvProc] = {
interceptor: Interceptor ← network.interceptor;
IF interceptor = NIL THEN { -- normal case, no interception in progress
previous: Driver.RecvProc;
SELECT type FROM
ip => previous ← network.ip.recv;
ipTranslate => previous ← network.ip.recvTranslate;
ns => previous ← network.ns.recv;
nsTranslate => previous ← network.ns.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 # Driver.NoThankYou THEN SIGNAL SlotAlreadyCaptured;
SELECT type FROM
ip => network.ip.recv ← proc;
ipTranslate => network.ip.recvTranslate ← proc;
ns => network.ns.recv ← proc;
nsTranslate => network.ns.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] # Driver.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 Driver.SendType OF BOOL,
sendProc: Driver.SendInterceptor,
recvMask: PACKED ARRAY Driver.RecvType OF BOOL,
recvProc: Driver.RecvInterceptor,
data: REF ANY,
promiscuous: BOOL ];
Procs: TYPE = RECORD [
send: ARRAY Driver.SendType OF Driver.SendProc,
recv: ARRAY Driver.RecvType OF Driver.RecvProc ];
CreateInterceptor: PUBLIC ENTRY PROC [
network: Network,
sendMask: PACKED ARRAY Driver.SendType OF BOOL,
sendProc: Driver.SendInterceptor,
recvMask: PACKED ARRAY Driver.RecvType OF BOOL,
recvProc: Driver.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: [
ip: network.ip.send,
ipReturn: network.ip.return,
ipTranslate: network.ip.sendTranslate,
ns: network.ns.send,
nsReturn: network.ns.return,
nsTranslate: network.ns.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: [
ip: network.ip.recv,
ipTranslate: network.ip.recvTranslate,
ns: network.ns.recv,
nsTranslate: network.ns.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.ip.send ← IPSend;
network.ip.return ← IPReturn;
network.ip.recv ← IPRecv;
network.ip.sendTranslate ← IPSendTranslate;
network.ip.recvTranslate ← IPRecvTranslate;
network.ns.send ← NSSend;
network.ns.return ← NSReturn;
network.ns.recv ← NSRecv;
network.ns.sendTranslate ← NSSendTranslate;
network.ns.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.ip.send ← procs.send[ip];
network.ip.return ← procs.send[ipReturn];
network.ip.sendTranslate ← procs.send[ipTranslate];
network.ns.send ← procs.send[ns];
network.ns.return ← procs.send[nsReturn];
network.ns.sendTranslate ← procs.send[nsTranslate];
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.ip.recv ← procs.recv[ip];
network.ip.recvTranslate ← procs.recv[ipTranslate];
network.ns.recv ← procs.recv[ns];
network.ns.recvTranslate ← procs.recv[nsTranslate];
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: Driver.SendProc = {
SendOne[ip, network, buffer, bytes];
};
IPReturn: Driver.SendProc = {
SendOne[ipReturn, network, buffer, bytes];
};
IPSendTranslate: Driver.SendProc = {
SendOne[ipTranslate, network, buffer, bytes];
};
NSSend: Driver.SendProc = {
SendOne[ns, network, buffer, bytes];
};
NSReturn: Driver.SendProc = {
SendOne[nsReturn, network, buffer, bytes];
};
NSSendTranslate: Driver.SendProc = {
SendOne[nsTranslate, network, buffer, bytes];
};
PupSend: Driver.SendProc = {
SendOne[pup, network, buffer, bytes];
};
PupReturn: Driver.SendProc = {
SendOne[pupReturn, network, buffer, bytes];
};
PupSendTranslate: Driver.SendProc = {
SendOne[pupTranslate, network, buffer, bytes];
};
OtherSend: Driver.SendProc = {
SendOne[other, network, buffer, bytes];
};
OtherReturn: Driver.SendProc = {
SendOne[otherReturn, network, buffer, bytes];
};
OtherSendTranslate: Driver.SendProc = {
SendOne[otherTranslate, network, buffer, bytes];
};
RawSend: Driver.SendProc = {
SendOne[raw, network, buffer, bytes];
};
SendOne: PROC [send: Driver.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: Driver.RecvProc = {
RETURN[RecvOne[ip, network, buffer, bytes]];
};
IPRecvTranslate: Driver.RecvProc = {
RETURN[RecvOne[ipTranslate, network, buffer, bytes]];
};
NSRecv: Driver.RecvProc = {
RETURN[RecvOne[ns, network, buffer, bytes]];
};
NSRecvTranslate: Driver.RecvProc = {
RETURN[RecvOne[nsTranslate, network, buffer, bytes]];
};
PupRecv: Driver.RecvProc = {
RETURN[RecvOne[pup, network, buffer, bytes]];
};
PupRecvTranslate: Driver.RecvProc = {
RETURN[RecvOne[pupTranslate, network, buffer, bytes]];
};
OtherRecv: Driver.RecvProc = {
RETURN[RecvOne[other, network, buffer, bytes]];
};
OtherRecvTranslate: Driver.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: Driver.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]];
};
}.