-- Copyright (C) 1981, 1984, 1985  by Xerox Corporation. All rights reserved. 
-- GateInit.mesa, HGM,  5-Oct-85 19:44:27

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, Network, ReturnBuffer],
  Driver USING [GetDeviceChain, Network],
  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 [
    CaptureErrors, GetDoStats, PupBuffer,
    PupPackageMake, PupSocket, PupSocketDestroy, PupSocketMake,
    SecondsToTocks, SetPupContentsWords,
    UniqueLocalPupSocketID],
  PupTypes USING [gatewaySoc, fillInPupAddress, allHosts, PupHostID, 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, Protocol1, PupRouterDefs, PupDefs,
    ForwarderDefs, Indirect, GateDefs, Trouble
  EXPORTS Buffer, IRSNetMgtInternal, GateDefs
  SHARES Driver, Buffer =
  BEGIN OPEN GateDefs;

  Network: PUBLIC TYPE = Driver.Network;

  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[];
    firstNetwork: Driver.Network ← 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 Buffer.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: Driver.Network ← firstNetwork, network.next UNTIL network = NIL DO
        allHosts: PupTypes.PupHostID ← PupTypes.allHosts;
        context: PupRouterDefs.NetworkContext ← Protocol1.GetContext[network, pup];
        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 ← [context.pupHostNumber];
        b.pup.source.socket ← me;
        SetPupContentsWords[b, 0];
        PupRouterDefs.SetPupChecksum[b];
	b.context ← context;
	b.network ← network;
        Protocol1.EncapsulateAndTransmit[b, @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.