-- 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; ]; IF status = closing THEN 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; ]; IF status = closing THEN GOTO closing; block.startIndex ¬ block.startIndex + n; ENDLOOP; XConnection.EnQueueRequest[client,data,len*2]; ENDLOOP; EXITS closing => BEGIN XConnection.ClosingConnection[client]; 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...