-- Copyright (C) 1983, 1985  by Xerox Corporation. All rights reserved. 
-- PupEchoServerNoDisk.mesa, HGM, 25-Jun-85  1:14:13

DIRECTORY
  Process USING [Yield],

  Buffer USING [ReturnBuffer],
  PupWireFormat USING [MesaToBcplLongNumber],
  PupEchoServerDefs USING [
    echoStatsRequest, echoStatsReply, EchoStatsEntry, echoVersion],
  Stats USING [StatIncr, StatBump],
  PupDefs USING [
    PupBuffer, PupPackageMake, PupPackageDestroy,
    PupRouterSendThis, ReturnPup, SwapPupSourceAndDest, GetPupContentsBytes,
    PupSocket, PupSocketMake, PupSocketDestroy, PupSocketKick, veryLongWait],
  PupTypes USING [echoSoc, fillInPupAddress];

PupEchoServerNoDisk: PROGRAM
  IMPORTS Process, Buffer, PupWireFormat, Stats, PupDefs
  EXPORTS PupEchoServerDefs =
  BEGIN

  pupsEchoed: LONG CARDINAL ← 0;
  useCount, hits: CARDINAL ← 0;
  pleaseStop, running, verbose: BOOLEAN ← FALSE;
  echoFork: PROCESS;
  echoSocket: PupDefs.PupSocket;

  EchoServerOn: PUBLIC PROCEDURE =
    BEGIN
    IF (useCount ← useCount + 1) = 1 THEN
      BEGIN
      running ← TRUE;
      Starter[];
      END;
    END;

  Starter: PROCEDURE =
    BEGIN
    pleaseStop ← FALSE;
    [] ← PupDefs.PupPackageMake[];
    echoSocket ← PupDefs.PupSocketMake[
      PupTypes.echoSoc, PupTypes.fillInPupAddress, PupDefs.veryLongWait];
    echoFork ← FORK Echoer[];
    END;

  EchoServerOff: PUBLIC PROCEDURE =
    BEGIN
    IF useCount # 0 AND (useCount ← useCount - 1) = 0 THEN
      BEGIN
      running ← FALSE;
      Stopper[];
      END;
    END;

  Stopper: PROCEDURE =
    BEGIN
    pleaseStop ← TRUE;
    PupDefs.PupSocketKick[echoSocket];
    JOIN echoFork[];
    PupDefs.PupSocketDestroy[echoSocket];
    PupDefs.PupPackageDestroy[];
    END;

  Echoer: PROCEDURE =
    BEGIN
    b: PupDefs.PupBuffer;
    UNTIL pleaseStop DO
      IF (b ← echoSocket.get[]) # NIL THEN
        BEGIN
        SELECT b.pup.pupType FROM
          echoMe =>
            BEGIN
	    pupsEchoed ← pupsEchoed + 1;
            Stats.StatIncr[pupsEchoed];
            Stats.StatBump[pupBytesEchoed, PupDefs.GetPupContentsBytes[b]];
            b.pup.pupType ← iAmEcho;
            PupDefs.SwapPupSourceAndDest[b];
            PupDefs.PupRouterSendThis[b];
            END;
          PupEchoServerDefs.echoStatsRequest =>
            BEGIN OPEN PupEchoServerDefs;
            ese: LONG POINTER TO EchoStatsEntry ← LOOPHOLE[@b.pup.pupWords];
            ese↑ ← [
              version: echoVersion,
              pupsEchoed: PupWireFormat.MesaToBcplLongNumber[pupsEchoed] ];
            PupDefs.ReturnPup[
              b, PupEchoServerDefs.echoStatsReply, 2*SIZE[EchoStatsEntry]];
            END;
          ENDCASE => Buffer.ReturnBuffer[b];
        END;
      Process.Yield[];  -- avoid hogging machine
      ENDLOOP;
    END;


  -- initialization

  EchoServerOn[];
  END.