-- Copyright (C) 1984  by Xerox Corporation. All rights reserved. 
-- GateControlServer.mesa, HGM, 19-Apr-84 17:04:29

DIRECTORY
  Inline USING [LowHalf],
  Process USING [Detach],
  String USING [AppendString, AppendDecimal],
  System USING [IsUtilityPilot],
  Time USING [Current],
  Volume USING [GetAttributes, SystemID],
  Window USING [Handle],

  Buffer USING [ReturnBuffer],
  BufferOps USING [GetStatistics, Statistics],
  GateDefs USING [GetVersionText],
  GateControlDefs USING [
    gateControlStatsSend, gateControlStatsAck,
    gateControlExamine, gateControlDeposit, gateControlRestart, gateControlHalt,
    GateControlStatsEntry, gateControlVersion, RestartGateway, HaltGateway],
  CpuIdle USING [GetSmoothedCpuUtilization],
  PupWireFormat USING [MesaToBcplLongNumber, BcplSTRING],
  PupDefs USING [
    PupAddress, PupBuffer, GetPupContentsBytes,
    SetPupContentsWords, PupRouterSendThis, SwapPupSourceAndDest, PupSocket,
    PupSocketMake, veryLongWait],
  PupTypes USING [fillInPupAddress],
  Stats;

GateControlServer: PROGRAM
  IMPORTS
    Inline, Process, String, System, Time, Volume,
    Buffer, BufferOps, GateDefs, GateControlDefs, CpuIdle, Stats,
    PupWireFormat, PupDefs
  EXPORTS GateControlDefs =
  BEGIN OPEN Stats, PupDefs;

  msg: PUBLIC Window.Handle ← NIL;

  version: LONG STRING ← GateDefs.GetVersionText[];

  statsCounters: LONG POINTER TO ARRAY StatCounterIndex OF LONG CARDINAL =
    StatsGetCounters[];

  soc: PupSocket;

  GateControlServerOn: PUBLIC PROCEDURE =
    BEGIN Process.Detach[FORK Server[]]; END;

  Server: PROCEDURE =
    BEGIN
    b: PupBuffer;
    soc ← PupSocketMake[[31415, 9265], PupTypes.fillInPupAddress, veryLongWait];
    DO
      -- forever
      IF (b ← soc.get[]) # NIL THEN
        BEGIN OPEN GateControlDefs;
        IF b.pup.pupID.a # 27182 THEN GOTO Ignore;
        SELECT b.pup.pupType FROM
          gateControlStatsSend =>
            BEGIN
            info: ARRAY BufferOps.Statistics OF CARDINAL ← BufferOps.GetStatistics[];
	    temp: STRING = [200];
            gse: LONG POINTER TO GateControlStatsEntry;
            now: LONG CARDINAL ← Time.Current[];
            free: LONG CARDINAL ← 0;
	    IF ~System.IsUtilityPilot[] THEN
	      free ← Volume.GetAttributes[Volume.SystemID[]].freePageCount;
            Stats.StatUpdate[];  -- be sure statSeconds is up-to-date
            IF GetPupContentsBytes[b] # 0 THEN GOTO Ignore;
            gse ← LOOPHOLE[@b.pup.pupBody];
            -- Beware: Constructor needs space for a copy on the frame
            gse.version ← GateControlDefs.gateControlVersion;
            gse.startTime ← PupWireFormat.MesaToBcplLongNumber[
              -- we can't just save the start time since we might not know the time yet
              LOOPHOLE[LOOPHOLE[now, LONG INTEGER] - statsCounters[statSeconds]]];
            gse.ftpStatus ← 0;
            gse.freeBuffers ← info[available];
            gse.freeDiskPages ←
              IF free < 50000 THEN Inline.LowHalf[free] ELSE 50000;
	    String.AppendString[temp, version];
	    String.AppendString[temp, ", "L];
	    String.AppendDecimal[temp, CpuIdle.GetSmoothedCpuUtilization[]];
	    String.AppendString[temp, "%"L];
            CopyString[temp, @gse.versionText];
            -- This sends more than we need to
            SetPupContentsWords[b, SIZE[GateControlStatsEntry]];
            GOTO Send;
            END;
          gateControlExamine =>
            BEGIN
            p: POINTER TO ARRAY [0..0) OF WORD ← LOOPHOLE[b.pup.pupWords[0]];
            i, words: CARDINAL;
            Stats.StatUpdate[];  -- might look at the time
            IF GetPupContentsBytes[b] # 2*2 THEN GOTO Ignore;
            words ← b.pup.pupWords[1];
            FOR i IN [0..words) DO b.pup.pupWords[2 + i] ← p[i]; ENDLOOP;
            SetPupContentsWords[b, (words + 2)];
            GOTO Send;
            END;
          gateControlDeposit =>
            BEGIN  -- I hope you know what you are doing
            p: POINTER TO ARRAY [0..0) OF WORD ← LOOPHOLE[b.pup.pupWords[0]];
            i, words: CARDINAL;
            words ← b.pup.pupWords[1];
            IF GetPupContentsBytes[b] # 2*(words + 2) THEN GOTO Ignore;
            FOR i IN [0..b.pup.pupWords[1]) DO p[i] ← b.pup.pupWords[2 + i]; ENDLOOP;
            SetPupContentsWords[b, 0];
            GOTO Send;
            END;
          gateControlRestart =>
            BEGIN
            GateControlDefs.RestartGateway[b];
            SetPupContentsWords[b, 0];
            GOTO Send;
            END;
          gateControlHalt =>
            BEGIN
            GateControlDefs.HaltGateway[b];
            SetPupContentsWords[b, 0];
            GOTO Send;
            END;
          error => GOTO Ignore;
          ENDCASE => GOTO Ignore;
        EXITS
          Send =>
            BEGIN  -- pupLength already setup
            b.pup.pupType ← gateControlStatsAck;
            SwapPupSourceAndDest[b];
            PupRouterSendThis[b];
            END;
          Ignore => BEGIN Buffer.ReturnBuffer[b]; END;
        END;
      ENDLOOP;
    END;

  CopyString: PROCEDURE [
    s: LONG STRING, d: LONG POINTER TO PupWireFormat.BcplSTRING] =
    BEGIN
    i: CARDINAL;
    d.length ← s.length;
    FOR i IN [0..s.length) DO d.char[i] ← s[i]; ENDLOOP;
    END;

  -- initialization

  GateControlServerOn[];
  END.