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 ANY ← NIL; -- 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
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.