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