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