-- File: ArpaEchoServerImpl.mesa - last edit:
-- AOF 11-Mar-87 16:25:45
-- SMA 11-Dec-85 11:58:39
-- Copyright (C) 1985, 1987 by Xerox Corporation. All rights reserved.
DIRECTORY
ArpaConstants USING [echoPort],
ArpaEchoServer,
ArpaPort USING [WaitTime],
CommHeap USING [zone],
Environment USING [Block],
Process USING [Abort],
TcpStream USING [CompletionCode, Failed, Handle, Listen, Suspended],
TcpStreamInternal USING [minTcpHeaderBytes, maxTcpDataBytes];
ArpaEchoServerImpl: PROGRAM
IMPORTS CommHeap, Process, TcpStream
EXPORTS ArpaEchoServer =
BEGIN
echoServerFork: PROCESS;
--udpEchoH: ArpaPort.Handle;
echoPackets : LONG CARDINAL ← 0;
echoBytes: LONG CARDINAL ← 0;
tmo: ArpaPort.WaitTime = LAST[ArpaPort.WaitTime]; --equates to disabled
CreateServer: PUBLIC PROC [buffers: CARDINAL] =
BEGIN
<<udpEchoH ← ArpaPort.Create[
port: ArpaConstants.echoPort, receive: buffers, portType: listen];
ArpaPort.SetWaitTime[echoCH, tmo]; --really disables timeouts>>
echoServerFork ← FORK EchoServer[];
END; -- CreateServer
DeleteServer: PUBLIC PROC =
BEGIN
Process.Abort[echoServerFork];
JOIN echoServerFork;
<<ArpaPort.Delete[udpEchoH];>>
END; --DeleteServer
EchoServer: PROC =
BEGIN
block: Environment.Block;
tsH: TcpStream.Handle ← NIL;
BEGIN ENABLE ABORTED =>
BEGIN
IF tsH # NIL THEN
{CommHeap.zone.FREE[@block.blockPointer]; tsH.destroy[tsH]};
GOTO exit;
END;
n: CARDINAL ← 0;
outcome: TcpStream.CompletionCode;
maxBytes: CARDINAL = TcpStreamInternal.maxTcpDataBytes;
Block: TYPE = PACKED ARRAY[0..maxBytes) OF CHARACTER;
DO
<<b ← NIL; b ← ArpaPort.GetPacket[echoCH ! ABORTED => EXIT];
SELECT b.arpa.protocol FROM
(udp) =>
BEGIN
ArpaPort.SwapSourceAndDestination[b];
echoPackets ← echoPackets + 1;
echoBytes ← echoBytes + b.arpa.length;
IF CommFlags.doStats THEN ArpaStats.Incr[udpsEchoed];
IF CommFlags.doStats THEN ArpaStats.Bump[bytesEchoed, b.arpa.length];
ArpaPort.PutPacket[echoCH, b];
END
END;
(tcp) => Process.Detach[FORK TcpEcho[b]];
ENDCASE => {--**ICMP error packet here?--};>>
<<There are some unspoken conventions here - that the data will be pushed
by both ends, and the max size of data to be echoed is one full packet.>>
tsH ← TcpStream.Listen[ArpaConstants.echoPort, tmo !
TcpStream.Failed => LOOP];
--build the input data block.
block.blockPointer ← LOOPHOLE[CommHeap.zone.NEW[Block]];
block.startIndex ← 0;
DO --until other end gets bored.
ENABLE TcpStream.Suspended => GOTO finished; --whoops
block.stopIndexPlusOne ← maxBytes;
[n, outcome] ← tsH.get[block];
echoPackets ← echoPackets + 1;
IF outcome = timeout THEN GOTO finished; --give up.
--'cause SPP echo counts packet headers. Estimate (ignore options).
echoBytes ← echoBytes + n + TcpStreamInternal.minTcpHeaderBytes;
block.stopIndexPlusOne ← n;
tsH.put[block, TRUE, FALSE];
IF outcome = closing THEN {tsH.close[]; GOTO finished};
REPEAT
finished =>
BEGIN
CommHeap.zone.FREE[@block.blockPointer];
tsH.destroy[tsH];
tsH ← NIL;
END;
ENDLOOP; --end of the echo session.
ENDLOOP;
END; --enabled scope.
EXITS exit => NULL;
END; -- EchoServer
GetCounters: PUBLIC PROC RETURNS [packets, bytes: LONG CARDINAL] =
{RETURN[echoPackets, echoBytes]};
END...
LOG
14-Oct-85 9:31:18 SMA Created file.
11-Mar-87 16:20:45 AOF Use CommHeap.