-- File: PupListeners.mesa - last edit:
-- AOF                 17-Feb-88 15:22:39
-- SMA                  1-Sep-83 20:56:59
-- Copyright (C) 1983, 1986, 1988 by Xerox Corporation. All rights reserved. 

DIRECTORY
  Process USING [Detach],
  Runtime USING [GlobalFrame],
  Stream USING [Handle],
  PrincOpsMinus USING [NewSelf],
  PupRouterDefs USING [GetFirstPupSocket, PupRouterSocket],
  PupPktDefs USING [PupPktStreamMake, PupPktStream],
  PupStream USING [
    PupByteStreamMake, PupListener, PupListenerObject, RejectThisRequest],
  PupDefs USING [
    PupAddress, PupBuffer, PupSocketID, Tocks, PupRouterSendThis, SendErrorPup,
    SwapPupSourceAndDest, PupSocket, PupSocketMake, ReturnBuffer,
    PupSocketKick, PupSocketDestroy, veryLongWait, SetPupContentsBytes,
    AppendStringBodyToPupBuffer],
  PupTypes USING [fillInPupAddress];

PupListeners: MONITOR
  IMPORTS
    Runtime, PrincOpsMinus, Process, PupRouterDefs, PupPktDefs, PupStream,
    PupDefs
  EXPORTS PupPktDefs, PupStream =
  BEGIN OPEN PupRouterDefs, PupDefs;

  -- Manager data
  
  Listen: PROCEDURE [local: PupSocketID] ← RealListen;
  -- The procedure variable for getting linkage to the instance's RealListen.
  
  free: LONG POINTER TO FRAME[PupListeners] ← 
    LOOPHOLE[Runtime.GlobalFrame[LOOPHOLE[Listen]]];

  GetInstance: ENTRY PROCEDURE RETURNS [him: LONG POINTER TO FRAME[PupListeners]] =
    BEGIN
    IF free = NIL THEN
      BEGIN
      him ← --NEW PupListeners-- PrincOpsMinus.NewSelf[];  
      START him;  -- Do initialization code
      RETURN;
      END;
    him ← free;
    free ← free.next;
    END;

  FreeInstance: ENTRY PROCEDURE [him: LONG POINTER TO FRAME[PupListeners]] =
    BEGIN him.next ← free; free ← him; END;


  next: LONG POINTER TO FRAME[PupListeners] ← NIL;

  myPupListener: PupStream.PupListenerObject ← LOOPHOLE[Listen];

  socket: PupSocket;

  timeout: Tocks;
  stop: BOOLEAN;
  proc: PROCESS;
  who: PROCEDURE [LONG UNSPECIFIED, PupAddress];
  check: PROCEDURE [PupAddress];
  Kind: TYPE = {pkt, byte};
  kind: Kind;

  DontReject: PUBLIC PROCEDURE [PupAddress] = BEGIN END;

  CreatePupByteStreamListener: PUBLIC PROCEDURE [
    local: PupSocketID, proc: PROCEDURE [Stream.Handle, PupAddress], ticks: Tocks,
    filter: PROCEDURE [PupAddress]] RETURNS [PupStream.PupListener] =
    BEGIN RETURN[CreatePupListener[local, proc, ticks, byte, filter]]; END;

  CreatePupPktStreamListener: PUBLIC PROCEDURE [
    local: PupSocketID, proc: PROCEDURE [PupPktDefs.PupPktStream, PupAddress],
    ticks: Tocks, filter: PROCEDURE [PupAddress]] 
    RETURNS [PupStream.PupListener] =
    BEGIN RETURN[CreatePupListener[local, proc, ticks, pkt, filter]]; END;

  CreatePupListener: PROCEDURE [
    local: PupSocketID, w: PROCEDURE [UNSPECIFIED, PupAddress], ticks: Tocks,
    k: Kind, f: PROCEDURE [PupAddress]] RETURNS [PupStream.PupListener] =
    BEGIN
    him: LONG POINTER TO FRAME[PupListeners] ← GetInstance[];
    him.socket ← PupSocketMake[local, PupTypes.fillInPupAddress, veryLongWait];
    him.kind ← k;
    him.who ← w;
    him.check ← f;
    him.timeout ← ticks;
    him.stop ← FALSE;
    him.proc ← FORK him.Listen[local];
    RETURN[@him.myPupListener];
    END;

  DestroyPupListener: PUBLIC PROCEDURE [listener: PupStream.PupListener] =
    BEGIN
    him: LONG POINTER TO FRAME[PupListeners] ← LOOPHOLE[Runtime.GlobalFrame[
      LOOPHOLE[listener↑]]];
    him.stop ← TRUE;
    PupSocketKick[him.socket];
    JOIN him.proc;
    PupSocketDestroy[him.socket];
    FreeInstance[him];
    END;

    
  RealListen: PROCEDURE [local: PupSocketID] =
    BEGIN
    soc: PupRouterSocket;
    arg: LONG UNSPECIFIED;
    b: PupBuffer;
    UNTIL stop DO
      b ← socket.get[];
      IF b # NIL THEN
        BEGIN
        SELECT b.pup.pupType FROM
          rfc =>
            BEGIN OPEN PupStream;
            FOR soc ← GetFirstPupSocket[], soc.next UNTIL soc = NIL DO
              -- check for duplicate
              IF soc.remote # b.pup.source THEN LOOP;
              IF soc.id # b.pup.pupID THEN LOOP;
              b.pup.address ← soc.local;
              SwapPupSourceAndDest[b];
              PupRouterSendThis[b];
              EXIT;
              ENDLOOP;
            IF soc = NIL THEN
              BEGIN  -- not a duplicate, make a new connection
              him: PupAddress ← b.pup.address;
              check[
                him !
                PupStream.RejectThisRequest =>
                  BEGIN
                  b.pup.pupType ← abort;
                  SwapPupSourceAndDest[b];
                  SetPupContentsBytes[b, 2];
                  AppendStringBodyToPupBuffer[b, error];
                  PupRouterSendThis[b];
                  GOTO Reject;
                  END];
              SELECT kind FROM
                pkt =>
                  arg ← PupPktDefs.PupPktStreamMake[
                    local, him, timeout, alreadyOpened, b.pup.pupID];
                byte =>
                  arg ← PupStream.PupByteStreamMake[
                    local, him, timeout, alreadyOpened, b.pup.pupID];
                ENDCASE => ERROR;
              PupDefs.ReturnBuffer[b];
              Process.Detach[FORK who[arg, him]];
              END;
            EXITS Reject => NULL;
            END;
          echoMe =>
            BEGIN
            b.pup.pupType ← iAmEcho;
            SwapPupSourceAndDest[b];
            PupRouterSendThis[b];
            END;
          ENDCASE => SendErrorPup[b, LOOPHOLE[100B], "RFC expected"L];
        END;
      ENDLOOP;
    END;


  END.
  
LOG

19-May-83  9:59:26  By: SMA  Action: Converted to new BufferMgr.
11-Jul-83 17:17:36  By: SMA  Action: Changes for 32-bit procs.
 1-Sep-83 20:57:12  By: SMA  Action: Fixed initialized <free>.
 2-Sep-86 14:44:19  By: AOF  Action: New Buffer mgmt package.
17-Feb-88 15:22:07  By: AOF  Action: Patch for compiler bug NEWing self.