-- XTransportTCPImpl.mesa DIRECTORY ArpaRouter, Environment, Heap, TcpStream, XConnection, XTransport, XTransportTCP; XTransportTCPImpl: PROGRAM IMPORTS Heap, TcpStream EXPORTS XTransportTCP = BEGIN xReq:TYPE = MACHINE DEPENDENT RECORD [ reqType:[0..256), data:[0..256), length:CARDINAL ]; xTcpPortNumber:PUBLIC ArpaRouter.Port = LOOPHOLE[6000]; zone:UNCOUNTED ZONE = Heap.systemZone; Listener:PUBLIC PROCEDURE = BEGIN handle:TcpStream.Handle; h:XTransport.Handle; DO handle ← TcpStream.Listen[localPort:xTcpPortNumber, listenTimeout:LAST[LONG CARDINAL]]; h ← zone.NEW[XTransport.Handle ← [ClientListener, Close, Destroy, Write, LOOPHOLE[handle, LONG CARDINAL]]]; XConnection.EnQueueConnection[h]; ENDLOOP; END; ClientListener:PRIVATE PROCEDURE[h:Handle, client:LONG CARDINAL, swapped:BOOLEAN] = BEGIN handle:TcpStream.Handle ← LOOPHOLE[h.priv, TcpStream.Handle]; 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] ← handle.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] ← handle.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; Close:PRIVATE PROCEDURE[h:Handle] = BEGIN handle:TcpStream.Handle ← LOOPHOLE[h.priv, TcpStream.Handle]; handle.close[!TcpStream.Closed => CONTINUE; TcpStream.Suspended => CONTINUE]; END; Destroy:PRIVATE PROCEDURE[h:Handle] = BEGIN handle:TcpStream.Handle ← LOOPHOLE[h.priv, TcpStream.Handle]; handle.destroy[handle]; END; Write:PRIVATE PROCEDURE[h:Handle, client:LONG CARDINAL, data:Environment.Block] = BEGIN handle:TcpStream.Handle ← LOOPHOLE[h.priv, TcpStream.Handle]; pad:PACKED ARRAY [0..4) OF Environment.Byte ← [0,0,0,0]; handle.put[data, TRUE, FALSE! TcpStream.Suspended => GOTO noconnect]; IF ( ( data.stopIndexPlusOne - data.startIndex ) MOD 4 ) > 0 THEN handle.put[ [@pad, 0, 4 - ( ( data.stopIndexPlusOne - data.startIndex ) MOD 4 )], TRUE, FALSE!TcpStream.Suspended => GOTO noconnect]; EXITS noconnect => BEGIN XConnection.ClosingConnection[client]; END; END; END.