-- Copyright (C) 1984, 1985 by Xerox Corporation. All rights reserved. -- BootServerNoDisk.mesa, HGM, 25-Jun-85 1:54:24 DIRECTORY AddressTranslation USING [Error, PrintError, StringToNetworkAddress], Ascii USING [CR], CmFile USING [Handle, TableError], Format USING [NetworkAddress, NetworkNumber, StringProc], Heap USING [systemZone], Process USING [Detach], Put USING [Text], String USING [AppendChar, AppendString], StringLookUp USING [noMatch], System USING [ NetworkAddress, NetworkNumber, nullNetworkAddress, nullSocketNumber, SocketNumber], Token USING [FreeTokenString, Item, NetworkNumber], Unformat USING [Error, NetworkAddress], BootServer USING [Counters], BootServerTypes USING [BootFileRequest], Buffer USING [NSBuffer, ReturnBuffer], Driver USING [Network], Indirect USING [Close, OpenSection, NextValue], NSConstants USING [bootServerSocket], RouterInternal USING [SendPacket], RoutingTable USING [NetworkContext], Socket USING [ ChannelHandle, Create, GetPacket, SetDestination, SetWaitTime, TimeOut], Stats USING [StatCounterIndex, StatIncr, StatsStringToIndex]; BootServerNoDisk: MONITOR IMPORTS CmFile, Format, Heap, Indirect, Process, Put, String, Token, Unformat, AddressTranslation, Buffer, RouterInternal, Socket, Stats EXPORTS Buffer = BEGIN Network: PUBLIC TYPE = Driver.Network; counters: BootServer.Counters ← [0, 0, 0, 0, 0, 0]; simpleBootRequests: Stats.StatCounterIndex; streamBootRequests: Stats.StatCounterIndex; pleaseStop: BOOLEAN ← FALSE; remote: Chain ← NIL; z: UNCOUNTED ZONE = Heap.systemZone; Chain: TYPE = LONG POINTER TO ChainSlot; ChainSlot: TYPE = RECORD [ next: Chain, source: System.NetworkNumber, dest: System.NetworkAddress, target: LONG STRING]; ActivateServer: PUBLIC ENTRY PROCEDURE = BEGIN ScanParameterFile[]; IF remote = NIL THEN RETURN; pleaseStop ← FALSE; Process.Detach[FORK Server[]]; END; Server: PROCEDURE = BEGIN soc: Socket.ChannelHandle; b: Buffer.NSBuffer; soc ← Socket.Create[NSConstants.bootServerSocket, 0, 2]; Socket.SetWaitTime[soc, 10000--ms--]; DO b ← NIL; b ← Socket.GetPacket[soc ! Socket.TimeOut => CONTINUE]; IF b = NIL THEN LOOP; IF b.ns.packetType = bootServerPacket THEN BEGIN context: RoutingTable.NetworkContext = b.context; header: LONG POINTER TO BootServerTypes.BootFileRequest = LOOPHOLE[@b.ns.nsWords[0]]; FOR finger: Chain ← remote, finger.next UNTIL finger = NIL DO IF context.netNumber = finger.source THEN BEGIN IF finger.dest = System.nullNetworkAddress THEN GOTO Reject; Socket.SetDestination[b, finger.dest]; EXIT; END; REPEAT FINISHED => GOTO Reject; ENDLOOP; SELECT header.etherBootPacketType FROM simpleRequest => BEGIN Stats.StatIncr[simpleBootRequests]; counters.microcodeBootFilesRequested ← counters.microcodeBootFilesRequested + 1; END; sppRequest => BEGIN Stats.StatIncr[streamBootRequests]; counters.bootFilesRequested ← counters.bootFilesRequested + 1; END; ENDCASE => GOTO Reject; RouterInternal.SendPacket[b]; -- Socket.PutPacket smashes b.ns.source b ← NIL; EXITS Reject => NULL; END; IF b # NIL THEN Buffer.ReturnBuffer[b]; ENDLOOP; END; ScanParameterFile: PROCEDURE = BEGIN cmFile: CmFile.Handle; Option: TYPE = {remote}; NextValue: PROCEDURE [ h: CmFile.Handle, table: LONG DESCRIPTOR FOR ARRAY Option OF LONG STRING] RETURNS [Option] = LOOPHOLE[Indirect.NextValue]; optionTable: ARRAY Option OF LONG STRING ← [remote: "Remote"L]; cmFile ← Indirect.OpenSection["BootServer"L]; IF cmFile = NIL THEN RETURN; DO option: Option; option ← NextValue[ cmFile, DESCRIPTOR[optionTable] ! CmFile.TableError => BEGIN IF name[0] # '; THEN Message["Unrecognized parameter: ", name]; RETRY; END]; SELECT option FROM LOOPHOLE[StringLookUp.noMatch] => EXIT; remote => BEGIN source: System.NetworkNumber = Token.NetworkNumber[cmFile]; temp: LONG STRING ← Token.Item[cmFile, FALSE]; new: Chain ← z.NEW[ChainSlot]; new↑ ← [NIL, source, System.nullNetworkAddress, z.NEW[StringBody[temp.length]]]; String.AppendString[new.target, temp]; [] ← Token.FreeTokenString[temp]; new.dest ← GetAddress[new.target, NSConstants.bootServerSocket ! Trouble => CONTINUE]; IF remote = NIL THEN remote ← new ELSE BEGIN FOR finger: Chain ← remote, finger.next DO IF finger.next = NIL THEN BEGIN finger.next ← new; EXIT; END; ENDLOOP; END; MessageNet[new]; END; ENDCASE => ERROR; ENDLOOP; Indirect.Close[cmFile]; END; ForgetParameters: PROCEDURE = BEGIN UNTIL remote = NIL DO temp: Chain ← remote; remote ← remote.next; z.FREE[@temp.target]; z.FREE[@temp]; ENDLOOP; END; MessageNet: PROCEDURE [new: Chain] = BEGIN text: STRING = [200]; String.AppendString[text, "Forwarding NS Boot requests from "L]; AppendNetNumber[text, new.source]; String.AppendString[text, " to "L]; String.AppendString[text, new.target]; String.AppendString[text, " ("L]; AppendNetworkAddress[text, new.dest]; String.AppendString[text, ")"L]; LogString[text]; END; Message: PROCEDURE [one, two, three, four: LONG STRING ← NIL] = BEGIN text: STRING = [200]; String.AppendString[text, one]; IF two # NIL THEN String.AppendString[text, two]; IF three # NIL THEN String.AppendString[text, three]; IF four # NIL THEN String.AppendString[text, four]; LogString[text]; END; AppendNetNumber: PROCEDURE [string: LONG STRING, net: System.NetworkNumber] = BEGIN Append: PROCEDURE [s: LONG STRING, clientData: LONG POINTER] = BEGIN String.AppendString[string, s]; END; Format.NetworkNumber[Append, net, productSoftware]; END; AppendNetworkAddress: PROCEDURE [string: LONG STRING, addr: System.NetworkAddress] = BEGIN Append: PROCEDURE [s: LONG STRING, clientData: LONG POINTER] = BEGIN String.AppendString[string, s]; END; Format.NetworkAddress[Append, addr, productSoftware]; END; LogString: PROCEDURE [text: LONG STRING] = BEGIN String.AppendChar[text, '.]; String.AppendChar[text, Ascii.CR]; Put.Text[NIL, text]; END; Trouble: ERROR [reason: LONG STRING] = CODE; GetAddress: PROCEDURE [host: LONG STRING, socket: System.SocketNumber] RETURNS [addr: System.NetworkAddress] = BEGIN localFailed: BOOLEAN ← FALSE; IF host = NIL THEN ERROR Trouble ["NIL => Address Fault"L]; addr ← Unformat.NetworkAddress[host, octal ! Unformat.Error => BEGIN localFailed ← TRUE; CONTINUE; END ]; IF localFailed THEN BEGIN addr ← AddressTranslation.StringToNetworkAddress[host ! AddressTranslation.Error => BEGIN temp: STRING = [200]; proc: Format.StringProc = {String.AppendString[temp, s]}; AddressTranslation.PrintError[errorRecord, proc]; ERROR Trouble[temp]; END].addr; addr.socket ← socket; -- CH returns trash in socket END; IF addr.socket = System.nullSocketNumber THEN addr.socket ← socket; END; simpleBootRequests ← Stats.StatsStringToIndex["Simple Boot Requests"]; streamBootRequests ← Stats.StatsStringToIndex["Stream Boot Requests"]; ActivateServer[]; END.