-- Pupwatch: Calling name-lookup server
-- [Indigo]<Grapevine>PupWatch>GetAddress.mesa
-- Stolen from <Mesa>System>MesaInit.mesa of August 27, 1980 10:01 AM
-- Andrew Birrell 12-Nov-81 9:30:44
DIRECTORY
LookerDefs USING [LookupOutcome],
Mopcodes USING [zSTARTIO],
OsStaticDefs USING [OsStatics],
ProcessDefs USING[CV, InterruptLevel];
GetAddress: MONITOR EXPORTS LookerDefs =
BEGIN
Byte: TYPE = [0..255];
PupHeader: TYPE = MACHINE DEPENDENT RECORD [
eDest, eSource: Byte,
eWord2, pupLength: CARDINAL,
transportControl, pupType: Byte,
pupID1, pupID2: CARDINAL,
destNet, destHost: Byte,
destSocket1, destSocket2: CARDINAL,
sourceNet, sourceHost: Byte,
sourceSocket1, sourceSocket2: CARDINAL];
Pup: TYPE = MACHINE DEPENDENT RECORD [
header: PupHeader, data: PACKED ARRAY [0..130) OF CHARACTER];
EthernetDeviceBlock: TYPE = MACHINE DEPENDENT RECORD [
EPLocMicrocodeStatus, EPLocHardwareStatus: Byte,
EBLocInterruptBit: WORD,
EELocInputFinishCount: CARDINAL,
ELLocCollisionMagic: WORD,
EILocInputCount: CARDINAL,
EILocInputPointer: POINTER,
EOLocOutputCount: CARDINAL,
EOLocOutputPointer: POINTER];
myNet: Byte ← 0;
myID: CARDINAL ← 0;
Broadcast: ENTRY PROC[length: CARDINAL, socket: CARDINAL, type: Byte,
request, response: POINTER TO Pup]
RETURNS[outcome: LookerDefs.LookupOutcome,
responseBytes: CARDINAL] =
BEGIN
etherLevel: ProcessDefs.InterruptLevel;
etherMask: CARDINAL ← 1;
myHost: Byte ← OsStaticDefs.OsStatics.SerialNumber;
device: POINTER TO EthernetDeviceBlock ← LOOPHOLE[600B];
StartIO: PROCEDURE [WORD] = MACHINE CODE BEGIN Mopcodes.zSTARTIO END;
outputCommand: WORD = 1;
inputCommand: WORD = 2;
resetCommand: WORD = 3;
request.header ←
[eDest: 0, eSource: myHost, eWord2: 1000B, pupLength: 22+length,
transportControl: 0, pupType: type,
pupID1: 0, pupID2: (myID ← myID+1),
destNet: 0, destHost: 0,
destSocket1: 0, destSocket2: socket,
sourceNet: myNet, sourceHost: myHost,
sourceSocket1: 0, sourceSocket2: 101010B];
BEGIN
x: POINTER TO CARDINAL = LOOPHOLE[@request.data+(1+length)/2];
x↑ ← 177777B;-- => don't checksum --
END;
FOR i: ProcessDefs.InterruptLevel IN ProcessDefs.InterruptLevel
DO IF ProcessDefs.CV[i] = NIL THEN { etherLevel ← i; EXIT };
etherMask ← etherMask + etherMask;
REPEAT FINISHED => ERROR
ENDLOOP;
THROUGH [0..5) DO
etherCV: CONDITION ← [timeout:30];
status: Byte; -- for debugging --
device.EBLocInterruptBit ← etherMask;
device.EPLocMicrocodeStatus ← 0;
ProcessDefs.CV[etherLevel] ← @etherCV;
StartIO[resetCommand];
DO WAIT etherCV;
IF (status←device.EPLocMicrocodeStatus) = 5 --reset-- THEN EXIT;
ENDLOOP;
device↑ ← EthernetDeviceBlock[
EPLocMicrocodeStatus: 0, EPLocHardwareStatus: 0,
EBLocInterruptBit: etherMask, EELocInputFinishCount: 0,
ELLocCollisionMagic: 0, EILocInputCount: 0,
EILocInputPointer: response, EOLocOutputCount: 2+11+(1+length)/2,
EOLocOutputPointer: request];
StartIO[outputCommand];
WAIT etherCV;
IF (status←device.EPLocMicrocodeStatus) = 1 -- outputDone --
AND device.EPLocHardwareStatus = 377B -- ok --
THEN -- output ok, so wait for input --
DO device↑ ← EthernetDeviceBlock[
EPLocMicrocodeStatus: 0, EPLocHardwareStatus: 0,
EBLocInterruptBit: etherMask, EELocInputFinishCount: 0,
ELLocCollisionMagic: 0, EILocInputCount: SIZE[Pup],
EILocInputPointer: response, EOLocOutputCount: 0,
EOLocOutputPointer: NIL];
StartIO[inputCommand];
WAIT etherCV;
IF device.EPLocHardwareStatus = 0 THEN EXIT -- timeout --;
IF (status←device.EPLocMicrocodeStatus) = 0 -- inputDone --
AND device.EPLocHardwareStatus = 377B -- ok --
AND response.header.eWord2 = 1000B -- Pup packet --
AND device.EILocInputCount = device.EELocInputFinishCount +
2+(1+response.header.pupLength)/2
AND response.header.destSocket1 = request.header.sourceSocket1
AND response.header.destSocket2 = request.header.sourceSocket2
AND response.header.pupID1 = request.header.pupID1
AND response.header.pupID2 = request.header.pupID2
THEN BEGIN
IF myNet = 0 THEN myNet ← response.header.sourceNet;
ProcessDefs.CV[etherLevel] ← NIL;
RETURN[ok, response.header.pupLength-22]
END
--ELSE ignore the packet--;
ENDLOOP;
ProcessDefs.CV[etherLevel] ← NIL;
ENDLOOP;
StartIO[resetCommand];
RETURN[noResponse,];
END;
ParseConstant: PROC[name: STRING]
RETURNS[outcome: LookerDefs.LookupOutcome, net, host: Byte] =
BEGIN
-- Syntax (I didn't invent it!) is one of:
-- socket
-- host#socket
-- net#host#socket
-- Any field may be empty, meaning 0.
temp1: Byte ← 0;
temp2: Byte ← 0;
i: CARDINAL ← 0;
WHILE i < name.length
DO IF name[i] IN ['0..'7] THEN temp1 ← temp1*8 + name[i]-'0 ELSE EXIT;
i ← i+1;
REPEAT FINISHED => RETURN[outcome:ok, net:0, host:0]
ENDLOOP;
IF name[i] # '# THEN RETURN[badName,,] ELSE i ← i+1;
WHILE i < name.length
DO IF name[i] IN ['0..'7] THEN temp2 ← temp2*8 + name[i]-'0 ELSE EXIT;
i ← i+1;
REPEAT FINISHED => RETURN[outcome:ok, net:0, host:temp1]
ENDLOOP;
IF name[i] # '# THEN RETURN[badName,,] ELSE i ← i+1;
RETURN[outcome:ok, net:temp1, host:temp2]
END;
Lookup: PUBLIC PROCEDURE[name: STRING]
RETURNS[outcome: LookerDefs.LookupOutcome,
net, host: Byte] =
BEGIN
request, response: Pup;
responseLength: CARDINAL;
[outcome, net, host] ← ParseConstant[name];
IF outcome = ok THEN RETURN;
FOR i: CARDINAL IN [0..name.length)
DO request.data[i] ← name[i]; ENDLOOP;
DO [outcome, responseLength]
← Broadcast[name.length,4,220B,@request,@response];
IF outcome # ok THEN RETURN;
SELECT response.header.pupType FROM
221B =>
IF responseLength >= 6
THEN RETURN[ok,
LOOPHOLE[response.data[0]],
LOOPHOLE[response.data[1]]]
ELSE RETURN[badName,,];
222B => RETURN[badName,,];
ENDCASE => NULL --ignore it! --;
ENDLOOP;
END;
END.