<> <> <> <> <> <> DIRECTORY IPConfig USING [ourLocalAddress], IPDefs USING [Datagram, Error, Errorcode, InternetHandle, InternetHandleRec, neverTimeout, nullAddress, RequestData], IPQueue, List USING [Nconc1, Remove], Process USING [SetTimeout, MsecToTicks]; IPQueueImpl: CEDAR MONITOR IMPORTS IPConfig, IPDefs, List, Process EXPORTS IPQueue ~ BEGIN OPEN IPQueue; handleQueue: LIST OF REF ANY _ NIL; -- only contains IPDefs.InternetHandles. Has to be REF ANY for List. CreateIPHandle: PUBLIC ENTRY PROC [requestData: IPDefs.RequestData] RETURNS [handle: IPDefs.InternetHandle] ~ { <> ENABLE UNWIND => NULL; q: LIST OF REF ANY _ handleQueue; thisHandle: IPDefs.InternetHandle; WHILE q # NIL DO -- check for conflicting requests thisHandle _ NARROW[q.first]; IF (requestData.matchProtocol AND thisHandle^.matchProtocol AND requestData.protocol # thisHandle^.protocol) OR (requestData.matchAddr AND thisHandle^.matchAddr AND requestData.address # thisHandle^.address) THEN -- no conflict, check next request q _ q.rest ELSE RETURN [NIL]; ENDLOOP; IF NOT requestData.matchLocalAddr OR requestData.localAddress = IPDefs.nullAddress THEN <> requestData.localAddress _ IPConfig.ourLocalAddress; <> <> <> <<{SetReceiveAllPkts[]; >> <> <> handle _ NEW[IPDefs.InternetHandleRec]; handle^.matchProtocol _ requestData.matchProtocol; handle^.protocol _ requestData.protocol; handle^.matchAddr _ requestData.matchAddr; handle^.address _ requestData.address; handle^.matchLocalAddr _ requestData.matchLocalAddr; handle^.localAddress _ requestData.localAddress; handle^.printPkts _ requestData.printPkts; handle^.logPkts _ requestData.logPkts; <> handleQueue _ List.Nconc1[handleQueue, handle]; }; DestroyIPHandle: PUBLIC ENTRY PROC [handle: IPDefs.InternetHandle] ~ { <> ENABLE UNWIND => NULL; handleQueue _ List.Remove[handle, handleQueue]; handle.waitingDatagrams _ handle.lastWaitingElement _ NIL; handle.handleDestroyed _ TRUE; BROADCAST handle.newDatagram; }; Receive: PUBLIC ENTRY PROC [handle: IPDefs.InternetHandle, timeout: INT _ IPDefs.neverTimeout] RETURNS [data: IPDefs.Datagram] ~ { <> ENABLE UNWIND => NULL; IF handle.handleDestroyed THEN RETURN WITH ERROR IPDefs.Error[handleDestroyed]; IF timeout = 0 AND handle.waitingDatagrams = NIL THEN RETURN [NIL]; IF timeout # 0 THEN TRUSTED {Process.SetTimeout[@handle.newDatagram, Process.MsecToTicks[IF timeout > 0 THEN timeout ELSE 5000]]}; IF handle.waitingDatagrams = NIL THEN DO WAIT handle.newDatagram; IF handle.handleDestroyed THEN RETURN WITH ERROR IPDefs.Error[handleDestroyed]; IF handle.waitingDatagrams # NIL THEN EXIT; IF timeout > 0 THEN RETURN [NIL]; ENDLOOP; data _ handle.waitingDatagrams.first; handle.waitingDatagrams _ handle.waitingDatagrams.rest; IF handle.waitingDatagrams = NIL THEN handle.lastWaitingElement _ NIL; -- actually don't need this, but I feel better this way. }; QueueDatagram: PUBLIC ENTRY PROC [data: IPDefs.Datagram] ~ { <> ENABLE UNWIND => NULL; q: LIST OF REF ANY _ handleQueue; thisHandle: IPDefs.InternetHandle; WHILE q # NIL DO -- look at every handle. thisHandle _ NARROW[q.first]; IF (NOT thisHandle^.matchProtocol OR thisHandle^.protocol = data^.inHdr.protocol) AND (NOT thisHandle^.matchAddr OR thisHandle^.address = data^.inHdr.source) AND (NOT thisHandle^.matchLocalAddr OR thisHandle^.localAddress = data^.inHdr.destination) THEN GO TO Found -- found one ELSE q _ q.rest; -- try again REPEAT Found => AddNewDatagram[thisHandle, data]; FINISHED => NULL; ENDLOOP; }; AddNewDatagram: INTERNAL PROC [handle: IPDefs.InternetHandle, data: IPDefs.Datagram] ~ { <> IF handle.waitingDatagrams = NIL THEN { handle.waitingDatagrams _ LIST[data]; handle.lastWaitingElement _ handle.waitingDatagrams; } ELSE { handle.lastWaitingElement.rest _ CONS[data, NIL]; handle.lastWaitingElement _ handle.lastWaitingElement.rest; }; NOTIFY handle.newDatagram; }; END.