-- 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.