-- File: PupListeners.mesa, Last Edit: HGM August 23, 1980 7:19 PM

-- Copyright Xerox Corporation 1979, 1980

DIRECTORY
Stream: FROM "Stream" USING [Handle],
CommUtilDefs: FROM "CommUtilDefs" USING [
GlobalFrame, MyGlobalFrame, Copy, UnNew, Detach],
PupRouterDefs: FROM "PupRouterDefs" USING [GetFirstPupSocket, PupRouterSocket],
PupPktDefs: FROM "PupPktDefs" USING [PupPktStreamMake, PupPktStream],
PupStream: FROM "PupStream" USING [
PupByteStreamMake, PupListener, PupListenerObject, RejectThisRequest],
PupDefs: FROM "PupDefs" USING [
PupAddress, PupBuffer, PupSocketID, Tocks,
PupRouterSendThis, SendErrorPup, SwapPupSourceAndDest,
PupSocket, PupSocketMake, PupSocketKick, PupSocketDestroy, veryLongWait,
SetPupContentsBytes, AppendStringBodyToPupBuffer, ReturnFreePupBuffer],
PupTypes: FROM "PupTypes" USING [fillInPupAddress];

PupListeners: MONITOR
IMPORTS CommUtilDefs, PupRouterDefs, PupPktDefs, PupStream, PupDefs
EXPORTS PupPktDefs, PupStream =
BEGIN OPEN PupRouterDefs, PupStream, PupDefs;

myPupListener: PupListenerObject ← [LOOPHOLE[Listen]];

socket: PupSocket;

timeout: Tocks;
stop: BOOLEAN ← FALSE;
proc: PROCESS;
who: PROCEDURE [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 [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 [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 [PupListener] =
BEGIN
him: POINTER TO FRAME[PupListeners];
him ← CommUtilDefs.Copy[CommUtilDefs.MyGlobalFrame[]];
START him; -- Do initialization code
him.socket ← PupSocketMake[local,PupTypes.fillInPupAddress,veryLongWait];
him.kind ← k;
him.who ← w;
him.check ← f;
him.timeout ← ticks;
him.proc ← FORK him.Listen[local];
RETURN[@him.myPupListener];
END;

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

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


-- initialization
END. -- of PupListeners