-- File: GateInit.mesa - last edit:
-- AOF                 15-Feb-88 11:09:26
-- HGM                  5-Oct-85 19:44:27
-- Copyright (C) 1981, 1984, 1985, 1988 by Xerox Corporation. All rights reserved. 

DIRECTORY
  Event USING [aboutToSwap],
  EventTypes USING [aboutToBoot, aboutToBootPhysicalVolume],
  Format USING [HostNumber],
  Process USING [Priority, SetPriority, Pause, priorityNormal],
  Put USING [Text],
  Runtime USING [GetBcdTime],
  SpecialSystem USING [GetProcessorID],
  String USING [AppendChar, AppendString],
  Supervisor USING [
    AddDependency, AgentProcedure, CreateSubsystem, SubsystemHandle],
  System USING [GetClockPulses, HostNumber, Pulses, PulsesToMicroseconds],
  Time USING [AppendCurrent, Append, Packed, Unpack, Unpacked],
  Version USING [Append],

  NSName USING [maxLocalLength, Name, NameRecord],
  NSString USING [String, StringFromMesaString],
  IRSNetMgtInternal USING [],

  Buffer USING [],
  Driver USING [GetDeviceChain, Device],
  ForwarderDefs USING [PupForwarderOn, PeekAtRoutingPup, SetupForwarderThings],
  Indirect USING [GetParmFileName],
  GateDefs USING [ScanParameterFile, SetupWindow],
  EchoServer USING [CreateServer, DeleteServer],
  Protocol1 USING [EncapsulateAndTransmit, GetContext],
  PupRouterDefs USING [DoForwardPupBuffer, NetworkContext, SetPupForwarder, SetPupChecksum],
  PupDefs USING [
    Body, PupBuffer, PupPackageMake, PupSocket, PupSocketDestroy, PupSocketMake,
    SecondsToTocks, SetPupContentsWords, UniqueLocalPupSocketID,
    AccessHandle, DestroyPool, GetBuffer, MakePool, ReturnBuffer],
  PupTypes USING [gatewaySoc, fillInPupAddress, allHosts, PupHostID, PupSocketID],
  StatsOpsExtras USING[CaptureErrors, GetDoStats],
  Inr USING [ActivateINR],
  Trouble USING [PupGlitchTrap, SetUncaughtSignalTrap];

GateInit: PROGRAM
  IMPORTS
    Event, Format, Process, Put, Runtime, SpecialSystem, String, Supervisor,
    System, Time, Version, NSString, Buffer, Driver, EchoServer, StatsOpsExtras,
    Inr, Protocol1, PupRouterDefs, PupDefs, ForwarderDefs, Indirect, GateDefs,
    Trouble
  EXPORTS Buffer, IRSNetMgtInternal, GateDefs =
  BEGIN OPEN GateDefs;

  Device: PUBLIC <<Buffer>> TYPE = Driver.Device;

  version: STRING = [75];  -- "Pup Gateway 14.0 of 15-Feb-88 11:07:23 on nnnnnnnnnnnnnnnn"

  broom: Supervisor.SubsystemHandle = Supervisor.CreateSubsystem[Broom];

  name: STRING = [NSName.maxLocalLength];
  nameRecord: NSName.NameRecord;
  
  GetInrName: PUBLIC PROCEDURE RETURNS [NSName.Name] =
    BEGIN
    parmFileName: LONG STRING ← Indirect.GetParmFileName[];
    IF parmFileName = NIL THEN parmFileName ← "NoName"L;
    name.length ← 0;
    FOR i: CARDINAL IN [0..parmFileName.length) DO
      SELECT parmFileName[i] FROM
        '. => EXIT;
	'[, '], '<, '> => name.length ← 0;
	ENDCASE => {
        String.AppendChar[name, parmFileName[i]];
        IF name.length = NSName.maxLocalLength THEN EXIT; };
      ENDLOOP;
    nameRecord.org ← NSString.StringFromMesaString["Xerox"];
    nameRecord.domain ← NSString.StringFromMesaString["Pup"];
    nameRecord.local ← NSString.StringFromMesaString[name];
    RETURN[@nameRecord];
    END;

  GetVersionText: PUBLIC PROCEDURE RETURNS [LONG STRING] =
    BEGIN RETURN[version]; END;

  CheckNetworks: PROCEDURE =
    BEGIN OPEN PupRouterDefs, PupDefs;
    pool: PupDefs.AccessHandle ← PupDefs.MakePool[send: 1, receive: 0];
    b: PupBuffer;
    me: PupTypes.PupSocketID ← UniqueLocalPupSocketID[];
    firstDevice: Device ← Driver.GetDeviceChain[];
    pupGateSoc: PupSocket;
    time: System.Pulses;
    stop: BOOLEAN ← FALSE;
    checker: PROCESS;
    FlushAnswers: PROCEDURE =
      BEGIN
      b: PupBuffer;
      UNTIL stop DO
        -- If we get an answer here, it is probably ok.
        -- The screwup case will look like it should get forwarded.
        IF (b ← pupGateSoc.get[]) # NIL THEN PupDefs.ReturnBuffer[b]; ENDLOOP;
      END;
    pupGateSoc ← PupSocketMake[me, PupTypes.fillInPupAddress, SecondsToTocks[1]];
    checker ← FORK FlushAnswers[];
    FOR i: CARDINAL IN [0..5) DO
      time ← System.GetClockPulses[];
      -- We can't just broadcast a request because the answer that we are really looking for would go back to the wrong network.
      FOR network: Device ← firstDevice, network.next
        UNTIL network = NIL DO
	body: PupDefs.Body;
        allHosts: PupTypes.PupHostID ← PupTypes.allHosts;
        context: PupRouterDefs.NetworkContext ← Protocol1.GetContext[network, pup];
        b ← PupDefs.GetBuffer[pool, send];
	body ← b.pup;
        body.pupTransportControl ← 0;
        body.pupType ← gatewayRequest;
        body.pupID ← [0, i];
        body.dest.net ← [0];
        body.dest.host ← PupTypes.allHosts;
        body.dest.socket ← PupTypes.gatewaySoc;
        body.source.net ← [0];
        body.source.host ← [context.pupHostNumber];
        body.source.socket ← me;
        SetPupContentsWords[b, 0];
        PupRouterDefs.SetPupChecksum[b];
	b.fo.context ← context;
	b.fo.network ← network;
        Protocol1.EncapsulateAndTransmit[LOOPHOLE[b], @allHosts];
        ENDLOOP;
      UNTIL System.PulsesToMicroseconds[[System.GetClockPulses[] - time]] >
        1000000 DO Process.Pause[1]; ENDLOOP;
      ENDLOOP;
    stop ← TRUE;
    JOIN checker;
    PupSocketDestroy[pupGateSoc];
    PupDefs.DestroyPool[pool];
    END;

  StartupGateway: PUBLIC PROCEDURE =
    BEGIN
    me: System.HostNumber = LOOPHOLE[SpecialSystem.GetProcessorID[]];
    priority: Process.Priority;
    disableNSRouting: BOOLEAN;
    packed: Time.Packed;
    unpacked: Time.Unpacked;
    String.AppendString[version, "Pup Gateway "L];
    Version.Append[version];
    String.AppendString[version, " of "L];
    packed ← Runtime.GetBcdTime[];
    unpacked ← Time.Unpack[packed, [useThese[[west, 0, 0, 366, 366]]]];
    Time.Append[version, unpacked, TRUE];
    String.AppendString[version, " on "L];
    BEGIN
    Append: PROCEDURE [s: LONG STRING, clientData: LONG POINTER] =
      BEGIN String.AppendString[version, s]; END;
    Format.HostNumber[Append, me, productSoftware];
    END;

    GateDefs.SetupWindow[];
    Message["starting"L];  -- PupGateway.typescript

    [] ← StatsOpsExtras.GetDoStats[];  -- Be sure it has been started
    StatsOpsExtras.CaptureErrors[Trouble.PupGlitchTrap];
    Trouble.SetUncaughtSignalTrap[];
    [priority, disableNSRouting] ← GateDefs.ScanParameterFile[];
    
    Process.SetPriority[priority];
    ForwarderDefs.SetupForwarderThings[];
    [] ← PupDefs.PupPackageMake[];

    EchoServer.DeleteServer[];
    EchoServer.CreateServer[buffers: 20];
    IF ~disableNSRouting THEN Inr.ActivateINR[];

    PupRouterDefs.SetPupForwarder[ForwarderDefs.PeekAtRoutingPup];
    CheckNetworks[];
    ForwarderDefs.PupForwarderOn[];
    PupRouterDefs.SetPupForwarder[PupRouterDefs.DoForwardPupBuffer];

    Process.SetPriority[Process.priorityNormal];
    Message["in operation"L];

    END;
  
  Message: PROCEDURE [s: LONG STRING] =
    BEGIN
    text: STRING = [125];
    Time.AppendCurrent[text];
    String.AppendString[text, "  "L];
    String.AppendString[text, version];
    String.AppendChar[text, ' ];
    String.AppendString[text, s];
    String.AppendChar[text, '.];
    String.AppendChar[text, '\n];
    LogString[text];
    END;

  LogString: PROCEDURE [text: LONG STRING] = BEGIN Put.Text[NIL, text]; END;

  Broom: Supervisor.AgentProcedure =
    BEGIN
    SELECT event FROM
      EventTypes.aboutToBoot, EventTypes.aboutToBootPhysicalVolume => Message["finished"L];
      ENDCASE => NULL;
    END;

  -- initialization
  Supervisor.AddDependency[client: broom, implementor: Event.aboutToSwap];
  StartupGateway[];
  END.