-- Copyright (C) 1981, 1984  by Xerox Corporation. All rights reserved. 
-- GateInit.mesa, HGM,  7-Jan-85 19:45:22

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 [AccessHandle, DestroyPool, GetBuffer, MakePool, ReturnBuffer],
  Driver USING [GetDeviceChain, Network],
  ForwarderDefs USING [PupForwarderOn, PeekAtRoutingPup, SetupForwarderThings],
  Indirect USING [GetParmFileName],
  GateDefs USING [ScanParameterFile, SetupWindow],
  EchoServer USING [CreateServer, DeleteServer],
  PupRouterDefs USING [DoForwardPupBuffer, SetPupForwarder, SetPupChecksum],
  PupDefs USING [
    CaptureErrors, GetDoStats, PupBuffer,
    PupPackageMake, PupSocket, PupSocketDestroy, PupSocketMake,
    SecondsToTocks, SetPupContentsWords,
    UniqueLocalPupSocketID],
  PupTypes USING [gatewaySoc, fillInPupAddress, allHosts, PupSocketID],
  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,
    Inr, PupRouterDefs, PupDefs,
    ForwarderDefs, Indirect, GateDefs, Trouble
  EXPORTS IRSNetMgtInternal, GateDefs
  SHARES Driver, Buffer =
  BEGIN OPEN GateDefs;

  version: STRING = [75];  -- "Pup Gateway 8.0c of 13-Oct-81 20:57:07 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: Buffer.AccessHandle ← Buffer.MakePool[send: 1, receive: 0];
    b: PupBuffer;
    me: PupTypes.PupSocketID ← UniqueLocalPupSocketID[];
    network, firstNetwork: Driver.Network;
    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 Buffer.ReturnBuffer[b]; ENDLOOP;
      END;
    firstNetwork ← Driver.GetDeviceChain[];
    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 ← firstNetwork, network.next UNTIL network = NIL DO
        b ← Buffer.GetBuffer[pup, pool, send];
        b.pup.pupTransportControl ← 0;
        b.pup.pupType ← gatewayRequest;
        b.pup.pupID ← [0, i];
        b.pup.dest.net ← [0];
        b.pup.dest.host ← PupTypes.allHosts;
        b.pup.dest.socket ← PupTypes.gatewaySoc;
        b.pup.source.net ← [0];
        b.pup.source.host ← [network.pupHostNumber];
        b.pup.source.socket ← me;
        SetPupContentsWords[b, 0];
        PupRouterDefs.SetPupChecksum[b];
        network.encapsulateAndSendPup[b, PupTypes.allHosts];
        ENDLOOP;
      UNTIL System.PulsesToMicroseconds[[System.GetClockPulses[] - time]] >
        1000000 DO Process.Pause[1]; ENDLOOP;
      ENDLOOP;
    stop ← TRUE;
    JOIN checker;
    PupSocketDestroy[pupGateSoc];
    Buffer.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

    [] ← PupDefs.GetDoStats[];  -- Be sure it has been started
    PupDefs.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.