-- File: ListenerImpl.mesa - last edit: -- AOF 15-Feb-88 19:30:05 -- KAM 9-Apr-85 10:05:41 -- Copyright (C) 1984, 1985, 1986, 1987, 1988 by Xerox Corporation. All rights reserved. DIRECTORY CourierInternal USING [ExchWords], CourierProtocol USING [ProtocolRange, RejectCode], Driver USING [NetworkNonExistent], EthernetDriverFriends, Heap USING [systemZone], HostNumbers USING [HostNumber, IsMulticastID], Listener USING [InfoProc, PacketType], NSBuffer USING [Buffer], PhysicalVolume USING [GetAttributes, GetContainingPhysicalVolume], Profile USING [GetUser], Router USING [FindMyHostID], Runtime USING [GetBuildTime, IsBound], Socket USING [ ChannelHandle, Delete, PutPacket, ReturnBuffer, SetPacketWords, SwapSourceAndDestination], SocketInternal USING [CreateListen, ListenerProcType], SpecialSystem USING [timeBooted], String USING [StringBoundsFault], System USING [HostNumber], Time USING [Current], Version USING [Append], Volume USING [GetLabelString, nullID, systemID], WSInfo USING [ Message, PacketType, pexOverhead, procedure, program, Request, Response, sizeLocateReply, sizePilotData, sizePilotInfoReply, sizeXdeData, sizeXdeInfoReply, socket, strMax, verMax, version], WSInfoExtras; ListenerImpl: MONITOR IMPORTS CourierInternal, Driver, EthernetDriverFriends, Heap, HostNumbers, PhysicalVolume, Profile, Router, Runtime, Socket, SocketInternal, SpecialSystem, String, Time, Version, Volume, WSInfoExtras EXPORTS Listener = BEGIN myAddress: System.HostNumber ← Router.FindMyHostID[]; myAddr: LONG POINTER ← @myAddress; zone: UNCOUNTED ZONE = Heap.systemZone; listenerRunning: PUBLIC BOOLEAN ← FALSE; ch: Socket.ChannelHandle; Range: CourierProtocol.ProtocolRange = [protocol3, protocol3]; Watcher: SocketInternal.ListenerProcType = { h: LONG POINTER TO WSInfo.Message ← LOOPHOLE[@b.ns.exchangeBody]; WITH messageBody: h↑ SELECT FROM call => SELECT TRUE FROM messageBody.program # CourierInternal.ExchWords[WSInfo.program] => SendErrorReply[b, noSuchProgramNumber, messageBody.transaction]; messageBody.procedure # WSInfo.procedure => SendErrorReply[b, noSuchProcedureValue, messageBody.transaction]; messageBody.version # WSInfo.version => SendErrorReply[b, noSuchVersionNumber, messageBody.transaction]; ENDCASE => WITH body: messageBody.request SELECT FROM locateRequest => IF InRange[@body.first, @body.last] AND NOT InSequence[@body] THEN SendReply[b, locateReply, messageBody.transaction] ELSE Socket.ReturnBuffer[b]; pilotInfoRequest => SendReply[b, pilotInfoReply, messageBody.transaction]; xdeInfoRequest => SendReply[b, xdeInfoReply, messageBody.transaction]; ENDCASE => SendReply[b, messageBody.request.type, messageBody.transaction]; ENDCASE => Socket.ReturnBuffer[b]}; SendErrorReply: PROCEDURE [ b: NSBuffer.Buffer, type: CourierProtocol.RejectCode, trans: CARDINAL] = { msg: LONG POINTER TO reject WSInfo.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, WSInfo.pexOverhead + SIZE[ noSuchProgramNumber reject WSInfo.Message]]}; noSuchProcedureValue => { msg.rejectBody ← noSuchProcedureValue[]; Socket.SetPacketWords[ b, WSInfo.pexOverhead + SIZE[ noSuchProcedureValue reject WSInfo.Message]]}; invalidArguments => { msg.rejectBody ← invalidArguments[]; Socket.SetPacketWords[ b, WSInfo.pexOverhead + SIZE[invalidArguments reject WSInfo.Message]]}; noSuchVersionNumber => { msg.rejectBody ← noSuchVersionNumber[[WSInfo.version, WSInfo.version]]; Socket.SetPacketWords[ b, WSInfo.pexOverhead + SIZE[ noSuchVersionNumber reject WSInfo.Message]]}; ENDCASE; Socket.PutPacket[ch, b]}; DataRec: TYPE = MACHINE DEPENDENT RECORD[ type(0): Listener.PacketType, size(1): CARDINAL, data(2): ARRAY [0..0) OF UNSPECIFIED]; SendReply: PROCEDURE [ b: NSBuffer.Buffer, type: WSInfo.PacketType, trans: CARDINAL] = { msg: LONG POINTER TO return WSInfo.Message ← LOOPHOLE[@b.ns.exchangeBody]; msg↑ ← [Range, return[transaction: trans, response:]]; Socket.SwapSourceAndDestination[b]; SELECT type FROM pilotInfoReply => { Socket.SetPacketWords[b, WSInfo.sizePilotInfoReply]; msg.response ← [ pilotInfoReply[ size: WSInfo.sizePilotData, time:, timeBooted:, bfCreateDate:, sysVolName:, pVName:]]; GetPilotInfo[LOOPHOLE[@msg.response]]}; xdeInfoReply => { Socket.SetPacketWords[b, WSInfo.sizeXdeInfoReply]; msg.response ← [xdeInfoReply[ size: WSInfo.sizeXdeData, loggedIn:, bfVersion:, userName:]]; GetXDEInfo[LOOPHOLE[@msg.response]]}; locateReply => { Socket.SetPacketWords[b, WSInfo.sizeLocateReply]; msg.response ← [locateReply[size:0]]}; LOOPHOLE[WSInfoExtras.PacketType[ethernetInfo]] => BEGIN OPEN etherReq: LOOPHOLE[msg, WSInfoExtras.EthernetRequest], etherRes: LOOPHOLE[msg, WSInfoExtras.EthernetResponse]; ENABLE Driver.NetworkNonExistent => GOTO nodevice; unit: NATURAL = etherReq.unit; --copy this out before resusing buffer Socket.SetPacketWords[b, SIZE[EthernetDriverFriends.EtherStatsInfo]]; etherRes ← [ethernetInfo[ info: EthernetDriverFriends.GetEthernetStats[unit]]]; WSInfoExtras.SwapLongsInPlace[@etherRes.info.packetsRecv, SIZE[EthernetDriverFriends.EtherStatsInfo] / SIZE[LONG CARDINAL]]; EXITS nodevice => SendErrorReply[b, invalidArguments, trans]; END; LOOPHOLE[WSInfoExtras.PacketType[ethernetOneInfo]] => BEGIN OPEN etherReq: LOOPHOLE[msg, WSInfoExtras.EthernetOneRequest], etherRes: LOOPHOLE[msg, WSInfoExtras.EthernetOneResponse]; ENABLE Driver.NetworkNonExistent => GOTO nodevice; unit: NATURAL = etherReq.unit; --copy this out before resusing buffer Socket.SetPacketWords[b, SIZE[EthernetDriverFriends.EtherStatsInfo]]; etherRes ← [ethernetOneInfo[ info: EthernetDriverFriends.GetEthernetOneStats[unit]]]; WSInfoExtras.SwapLongsInPlace[@etherRes.info.packetsRecv, SIZE[EthernetDriverFriends.EtherStatsInfo] / SIZE[LONG CARDINAL]]; EXITS nodevice => SendErrorReply[b, invalidArguments, trans]; END; ENDCASE => { proc: Listener.InfoProc; clientData: LONG POINTER; lp: LONG POINTER TO DataRec ← LOOPHOLE[@msg.response]; [proc, clientData] ← FindProc[type]; IF proc = NIL THEN { SendErrorReply[b, invalidArguments, trans]; RETURN} ELSE { lp.type ← type; lp.size ← proc[type, @lp.data, clientData]; Socket.SetPacketWords[b, WSInfo.sizeLocateReply + lp.size]; }; }; Socket.PutPacket[ch, b]}; Length: CARDINAL = SIZE[System.HostNumber]; LOP: TYPE = LONG POINTER TO ARRAY [0..Length) OF CARDINAL; InRange: PROCEDURE [first, last: LONG POINTER] RETURNS [yes: BOOLEAN ← TRUE] = { i: CARDINAL ← 0; it: LOP ← first; me: LOP ← myAddr; FOR i IN [0..Length) DO IF it[i] > me[i] THEN RETURN[FALSE] ELSE IF it[i] < me[i] THEN EXIT; ENDLOOP; it ← last; FOR i IN [0..Length) DO IF it[i] < me[i] THEN RETURN[FALSE] ELSE IF it[i] > me[i] THEN EXIT; ENDLOOP}; InSequence: PROCEDURE [seq: LONG POINTER TO locateRequest WSInfo.Request] RETURNS [yes: BOOLEAN ← FALSE] = { me: LOP = myAddr; FOR i: CARDINAL IN [0..seq.count) DO it: LOP = LOOPHOLE[@seq.hosts[i]]; FOR j: CARDINAL IN [0..Length) DO IF it[j] > me[j] THEN RETURN[FALSE] ELSE IF it[j] < me[j] THEN EXIT; REPEAT FINISHED => RETURN[TRUE]; ENDLOOP; ENDLOOP}; GetPilotInfo: PROCEDURE [p: LONG POINTER TO pilotInfoReply WSInfo.Response] = { sysVol: LONG STRING ← [WSInfo.strMax]; pVol: LONG STRING ← [WSInfo.strMax]; length, i: CARDINAL ← 0; IF Volume.systemID # Volume.nullID THEN { Volume.GetLabelString[Volume.systemID, sysVol]; [] ← PhysicalVolume.GetAttributes[ PhysicalVolume.GetContainingPhysicalVolume[Volume.systemID], pVol]}; p.sysVolName.length ← WSInfo.strMax; length ← MIN[sysVol.length, WSInfo.strMax]; FOR i IN [0..length) DO p.sysVolName.string[i] ← sysVol[i] ENDLOOP; FOR i IN [length..WSInfo.strMax) DO p.sysVolName.string[i] ← 0C ENDLOOP; p.pVName.length ← WSInfo.strMax; length ← MIN[pVol.length, WSInfo.strMax]; FOR i IN [0..length) DO p.pVName.string[i] ← pVol[i] ENDLOOP; FOR i IN [length..WSInfo.strMax) DO p.pVName.string[i] ← 0C ENDLOOP; p.time ← [CourierInternal.ExchWords[Time.Current[]]]; p.timeBooted ← [CourierInternal.ExchWords[SpecialSystem.timeBooted]]; p.bfCreateDate ← [CourierInternal.ExchWords[Runtime.GetBuildTime[]]]}; GetXDEInfo: PROCEDURE [p: LONG POINTER TO xdeInfoReply WSInfo.Response] = { version: LONG STRING ← [WSInfo.verMax]; length, i: CARDINAL ← 0; Get: PROCEDURE [name: LONG STRING, password: LONG STRING] = { p.userName.length ← WSInfo.strMax; length ← IF name = NIL THEN 0 ELSE MIN[name.length, 40]; FOR i IN [0..length) DO p.userName.string[i] ← name[i] ENDLOOP; FOR i IN [length..40) DO p.userName.string[i] ← 0C ENDLOOP; p.loggedIn ← NOT (password = NIL OR password.length = 0); }; IF Runtime.IsBound[LOOPHOLE[Profile.GetUser]] THEN Profile.GetUser[Get] ELSE Get[NIL, NIL]; IF Runtime.IsBound[LOOPHOLE[Version.Append]] THEN Version.Append[version ! String.StringBoundsFault => {ns ← NIL; RESUME}]; p.bfVersion.length ← WSInfo.verMax; length ← MIN[version.length, WSInfo.verMax]; FOR i IN [0..length) DO p.bfVersion.string[i] ← version[i] ENDLOOP; FOR i IN [length..WSInfo.verMax) DO p.bfVersion.string[i] ← 0C ENDLOOP}; StartListener: PUBLIC ENTRY PROCEDURE = { ENABLE UNWIND => NULL; IF listenerRunning THEN RETURN; ch ← SocketInternal.CreateListen[WSInfo.socket, Watcher, NIL]; listenerRunning ← TRUE}; StopListener: PUBLIC ENTRY PROCEDURE = { IF NOT listenerRunning THEN RETURN; Socket.Delete[ch]; listenerRunning ← FALSE}; ProcList: TYPE = LONG POINTER TO ProcRecord; ProcRecord: TYPE = RECORD [ proc: Listener.InfoProc, packetType: Listener.PacketType, clientData: LONG POINTER, link: ProcList]; procs: ProcList ← NIL; Register: PUBLIC ENTRY PROC[ packetType: Listener.PacketType, proc: Listener.InfoProc, clientData: LONG POINTER ← NIL] = { ENABLE UNWIND => NULL; p: ProcList; FOR p ← procs, p.link UNTIL p = NIL DO IF p.packetType = packetType THEN { p.proc ← proc; p.clientData ← clientData; RETURN}; ENDLOOP; procs ← zone.NEW[ProcRecord ← [ proc: proc, packetType: packetType, clientData: clientData, link: procs]]}; Unregister: PUBLIC ENTRY PROC[ packetType: Listener.PacketType] RETURNS [proc: Listener.InfoProc] = { ENABLE UNWIND => NULL; p: LONG POINTER TO ProcList; FOR p ← @procs, @p.link WHILE p↑ # NIL DO IF p.packetType = packetType THEN { flush: ProcList ← p↑; proc ← flush.proc; p↑ ← p.link; zone.FREE[@flush]; RETURN}; ENDLOOP; RETURN[NIL]; }; FindProc: ENTRY PROC[ packetType: Listener.PacketType] RETURNS [ proc: Listener.InfoProc, clientData: LONG POINTER] = { ENABLE UNWIND => NULL; p: ProcList; FOR p ← procs, p.link UNTIL p = NIL DO IF p.packetType = packetType THEN { proc ← p.proc; clientData ← p.clientData; RETURN}; ENDLOOP; RETURN[NIL, NIL]; }; StartListener[]; END... LOG 3-Sep-87 16:47:25 AOF Put in same fix as I did for BWS (aka StringBoundsFault) 23-Sep-87 15:01:16 AOF ENABLE UNWIND => NULL in StartListener