Copyright (C) 1983, 1985 by Xerox Corporation. All rights reserved. The following program was created in 1983 but has not been published within the meaning of the copyright law, is furnished under license, and may not be used, copied and/or disclosed except in accordance with the terms of said license.
IPQueueImpl.mesa
Last Edited by: Nichols, August 24, 1983 6:56 pm
Last Edited by: Taft, January 5, 1984 5:15 pm
John Larson, June 12, 1987 11:24:44 pm PDT
Hal Murray May 16, 1985 2:40:40 am PDT
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 ANYNIL; -- only contains IPDefs.InternetHandles. Has to be REF ANY for List.
CreateIPHandle: PUBLIC ENTRY PROC [requestData: IPDefs.RequestData] RETURNS [handle: IPDefs.InternetHandle] ~ {
Add a new request for incoming packets. Returns a handle on the Internet. If the reqest conflicts with an existing one, then CreateIPHandle returns NIL.
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
Default to local address.
requestData.localAddress ← IPConfig.ourLocalAddress;
This code checks for a new local address and sets promiscuous mode. Not yet.
IF requestData.LocalAddress # IPInfoPtr^.CurrentLocalAddr AND
NOT IPInfoPtr^.ReceiveAllPkts THEN
{SetReceiveAllPkts[];
IPInfoPtr^.ReceiveAllPkts ← TRUE};
no conflict found, add request
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;
Add this request to the list.
handleQueue ← List.Nconc1[handleQueue, handle];
};
DestroyIPHandle: PUBLIC ENTRY PROC [handle: IPDefs.InternetHandle] ~ {
Removes the request and flushes all waiting datagrams.
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] ~ {
Waits for a datagram that matches the request that was used to create the handle. Returns the datagram or NIL if timeout milliseconds (?) pass with no packet arriving. A value of neverTimeout for timeout will cause Receive to wait forever.
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] ~ {
Find a home for this datagram and queue it.
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] ~ {
Add a Datagram to the queue of waiting ones on a handle.
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.