-- 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.