-- XConnectionMgrImpl.mesa -- Created by Jeff Weinstein on 3-May-87 0:49:16 DIRECTORY ArpaRouter, XCRoutines, Environment, Heap, Inline, Process, TcpStream, XConnection, XConnectionMgr, XEventQ, XQueue; XConnectionMgrImpl:PROGRAM IMPORTS Heap, Inline, Process, TcpStream, XConnection, XCRoutines, XEventQ EXPORTS XConnectionMgr = BEGIN xConnClientPrefix:TYPE = MACHINE DEPENDENT RECORD [ byteOrder(0:0..7):[0..256), pad(0:8..15):[0..256), majorVersion(1):CARDINAL, minorVersion(2):CARDINAL, nbytesAuthProto(3):CARDINAL, nbytesAuthString(4):CARDINAL, pad2(5):CARDINAL]; xReq:TYPE = MACHINE DEPENDENT RECORD [ reqType:[0..256), data:[0..256), length:CARDINAL ]; xTcpPortNumber:PUBLIC ArpaRouter.Port = LOOPHOLE[6000]; GrabFlag:BOOLEAN ← FALSE; GrabClient:XConnection.Client; Error:LONG POINTER TO UNSPECIFIED = LOOPHOLE[LONG[-1]]; zone:UNCOUNTED ZONE ← Heap.Create[initial:16]; whichByteIsFirst:CHARACTER = 'l; clientArray:ARRAY [0..XConnection.MaxClients) OF LONG POINTER; ReadRequestFromClient:PUBLIC PROCEDURE[who:LONG CARDINAL, status:LONG POINTER TO INTEGER, oldbuf:LONG POINTER TO UNSPECIFIED] RETURNS [request:LONG POINTER TO UNSPECIFIED] = BEGIN Heap.FreeNode[zone,oldbuf]; [request, status↑] ← XConnection.DeQueueRequest[who! XConnection.QueueEmpty => BEGIN request ← NIL; status↑ ← 0; CONTINUE; END; XConnection.ConnectionNotOpen => BEGIN request ← NIL; status↑ ← -1; CONTINUE; END; ]; END; WriteToClient:PUBLIC PROCEDURE[who:LONG CARDINAL, remaining:INTEGER, buf:LONG POINTER TO UNSPECIFIED] RETURNS [status:INTEGER] = BEGIN status ← remaining; XConnection.SendToClient[who, [buf, 0, remaining]! XConnection.ConnectionNotOpen => BEGIN status ← -1; CONTINUE; END; ]; END; OnlyListenToOneClient:PUBLIC PROCEDURE[who:LONG CARDINAL] = BEGIN IF GrabFlag = FALSE THEN BEGIN GrabFlag ← TRUE; GrabClient ← who; END; END; ListenToAllClients:PUBLIC PROCEDURE = BEGIN GrabFlag ← FALSE; END; CloseDownConnection:PUBLIC PROCEDURE[who:LONG CARDINAL] = BEGIN XConnection.ClosingConnection[who]; XConnection.DestroyConnection[who]; END; ReallyMarkConnectionClosed: PUBLIC PROCEDURE[who:LONG CARDINAL] = BEGIN -- XConnection.DestroyConnection[who]; END; WaitForSomething:PUBLIC PROCEDURE[pClientsReady:LONG POINTER TO ARRAY[0..0) OF XConnectionMgr.ClientPtr, nready:LONG POINTER TO INTEGER, pNewClients:LONG POINTER TO ARRAY[0..0) OF XConnectionMgr.ClientPtr, nnew:LONG POINTER TO INTEGER] = BEGIN Looping:BOOLEAN ← TRUE; readyClients:ARRAY [0..XConnection.MaxClients) OF BOOLEAN; nready↑ ← 0; nnew↑ ← 0; WHILE Looping DO XConnection.WaitForEventOrClient[]; [clients:readyClients] ← XConnection.PendingRequests[]; FOR i:INTEGER IN [0..XConnection.MaxClients) DO IF readyClients[i] THEN BEGIN Looping ← FALSE; pClientsReady[nready↑] ← clientArray[i]; nready↑ ← nready↑ + 1; END; ENDLOOP; IF XEventQ.EventCount[] # 0 THEN Looping ← FALSE; CreateNewConnections[pNewClients,nnew]; IF nnew↑ > 0 THEN Looping ← FALSE; ENDLOOP; END; CreateNewConnections:PROCEDURE [pNewClients:LONG POINTER TO ARRAY[0..0) OF XConnectionMgr.ClientPtr, nnew:LONG POINTER TO INTEGER] = BEGIN connection:TcpStream.Handle; client:XConnectionMgr.ClientPtr; swapped:BOOLEAN; p:PROCESS; DO connection ← XConnection.DeQueueConnection[!XConnection.QueueEmpty => EXIT;]; swapped ← CheckSwapped[connection]; client ← NextAvailableClientID[]; clientArray[client.index] ← client; XConnection.CreateConnection[client.index, connection]; p ← FORK ClientListener[client.index, connection, swapped]; pNewClients[nnew↑] ← client; IF swapped THEN client.swapped ← 1 ELSE client.swapped ← 0; nnew↑ ← nnew↑ + 1; ENDLOOP; END; CheckSwapped:PROCEDURE[h:TcpStream.Handle] RETURNS [swapped:BOOLEAN] = BEGIN dummy:Environment.Byte; prefix:xConnClientPrefix; n:CARDINAL; block:Environment.Block; block ← [LOOPHOLE[LONG[@prefix]], 0, 12]; WHILE block.startIndex # block.stopIndexPlusOne DO [byteCount:n] ← h.get[block]; block.startIndex ← block.startIndex + n; ENDLOOP; IF prefix.byteOrder # LOOPHOLE[whichByteIsFirst] THEN swapped ← TRUE ELSE swapped ← FALSE; IF NOT swapped THEN n ← Inline.BITSHIFT[Inline.LowByte[prefix.nbytesAuthString],8] + Inline.HighByte[prefix.nbytesAuthString] ELSE n ← prefix.nbytesAuthString; IF NOT swapped THEN n ← n + Inline.BITSHIFT[Inline.LowByte[prefix.nbytesAuthProto],8] + Inline.HighByte[prefix.nbytesAuthProto] ELSE n ← n + prefix.nbytesAuthProto; FOR i:CARDINAL IN [0..n) DO [] ← h.get[[LOOPHOLE[LONG[@dummy]],0,1]]; ENDLOOP; END; NextAvailableClientID:PROCEDURE RETURNS[client:XConnectionMgr.ClientPtr] = BEGIN client ← XCRoutines.NextAvailableClient[]; END; ClientListener:PROCEDURE[client:LONG CARDINAL, h:TcpStream.Handle, swapped:BOOLEAN] = BEGIN req:xReq; len:CARDINAL; data:XQueue.Data; n:CARDINAL; status:TcpStream.CompletionCode; Process.Detach[Process.GetCurrent[]]; DO block:Environment.Block; block ← [LOOPHOLE[LONG[@req],LONG POINTER TO UNSPECIFIED],0,SIZE[xReq]*2]; WHILE block.startIndex # block.stopIndexPlusOne DO [n,status] ← h.get[block! TcpStream.Suspended => GOTO closing; TcpStream.Closed => GOTO closing; ]; block.startIndex ← block.startIndex + n; ENDLOOP; -- IF swapped THEN -- len ← Inline.BITSHIFT[Inline.LowByte[req.length],8] + Inline.HighByte[req.length] -- ELSE len ← req.length * 2; -- len ← ( len * 2 ) - ( SIZE[xReq] ); data ← Heap.MakeNode[zone,len]; Inline.LongCOPY[from:@req,nwords:SIZE[xReq],to:data]; block ← [data,SIZE[xReq]*2,len*2]; WHILE block.startIndex # block.stopIndexPlusOne DO [n,status] ← h.get[block! TcpStream.Suspended => GOTO closing; TcpStream.Closed => GOTO closing; ]; block.startIndex ← block.startIndex + n; ENDLOOP; XConnection.EnQueueRequest[client,data,len*2]; ENDLOOP; EXITS closing => BEGIN END; END; CreateWellKnownSockets:PUBLIC PROCEDURE = BEGIN p:PROCESS; p ← FORK ConnectionListener[]; END; ConnectionListener:PROCEDURE = BEGIN h:TcpStream.Handle; DO h ← TcpStream.Listen[localPort:xTcpPortNumber, listenTimeout:LAST[LONG CARDINAL]]; XConnection.EnQueueConnection[h]; ENDLOOP; END; END...