ArpaUDP.mesa
Copyright © 1986 by Xerox Corporation. All rights reserved.
Demers, September 4, 1987 6:37:46 pm PDT
Arpa UDP protocol.
DIRECTORY
Arpa USING [Address, nullAddress],
ArpaUDPBuf USING [Buffer, nullPort, Port]
;
ArpaUDP: CEDAR DEFINITIONS
~ {
Address: TYPE ~ Arpa.Address;
unknownAddress: Address ~ Arpa.nullAddress;
Port: TYPE ~ ArpaUDPBuf.Port;
nullPort: Port ~ ArpaUDPBuf.nullPort;
Buffer: TYPE ~ ArpaUDPBuf.Buffer;
Buffers: TYPE ~ ArpaUDPBuf.Buffer; -- Chain of buffers
Handle: TYPE ~ REF Object;
Object: TYPE;
Creation and parameter setting
Milliseconds: TYPE = CARD;
dontWait: Milliseconds = 0;
waitForever: Milliseconds = INT.LAST;
Get timeout units are milliseconds.
Process machinery has a limit of an hour or so.
Create: PROC [
remoteAddress: Address ← unknownAddress,
remotePort: Port ← nullPort,
localPort: Port ← nullPort,
sendBuffers: CARDINAL ← 1,
recvBuffers: CARDINAL ← 5,
getTimeout: Milliseconds ← 10000,
acceptErrors: BOOLFALSE,
acceptLongDatagrams: BOOLFALSE
]
RETURNS [h: Handle];
Creating a handle with a local port number that is already in use simply pushes the previous handle. It can still be used to send packets, but the newer handle will receive all incoming packets. This would be pretty frustrating for a user but you are unlikely to know his port number anyway. For a server, this allows you to capture the server's port temporarily, for example to test some new code.
If acceptError is TRUE, receipt of an ICMP message (generated for a datagram originating at this handle) will cause ERROR ReceivedError[...] on the next Get or CheckError.
If acceptLongDatagrams is FALSE, any received datagram that won't fit in a single buffer is dropped silently.
GetLocalPort: PROC [h: Handle] RETURNS [port: Port];
GetRemoteAddress: PROC [h: Handle] RETURNS [address: Address, port: Port];
SetRemoteAddress: PROC [h: Handle, address: Address, port: Port];
Don't call SetRemoteAddress while any other send activity is in progress.
SetGetTimeout: PROC [h: Handle, timeout: Milliseconds];
Don't call SetGetTimeout while any other receive activity is in progress.
SetSoftwareChecksumming: PROC [h: Handle, send, recv: BOOL];
FALSE => Faster
BEWARE: Hardware and Gateways occasionally mash packets.
Don't turn these off if you are transferring valuable data.
Kick: PROC [h: Handle];
Wakeup any processes waiting in Get. Normally only used just before Destroy.
Destroy: PROC [h: Handle];
Dropping on the floor is safe, but may waste resources. This recycles the socket slot sooner.
Sending
AllocBuffers: PROC [h: Handle, howMany: CARDINAL ← 1] RETURNS [b: Buffers];
Allocate a chain of buffers of the specified length.
! Error[$requestTooLarge]
SetUserBytes: PROC [b: Buffer, bytes: CARDINAL];
Set the UDP and IP header length fields. The 'bytes' argument counts only the data portion of the UDP datagram.
Put: PROC [b: Buffers];
Send a datagram.
Client should fill in length using SetUserBytes; UDP package fills in source and dest (from handle from which buffer was allocated), software checksum, and other necessities.
The (UDP and IP) headers of b will be "fixed" for sending, but the data will not be changed.
Call FreeBuffers after Put if you don't want to keep the buffers around (e.g. for retransmission).
SetCacheRefresh: PROC [h: Handle, interval: CARDINAL];
Set the refresh interval between routing cache flushes.
Setting interval to 0 disables cacheing.
Calling SetCacheRefresh or SetRemoteAddress flushes the cache.
Send: PROC [b: Buffers, address: Address, port: Port];
Like Put, but sends to the given destination rather than to the remote address and port specified when the handle was created.
SendToSelf: PROC [b: Buffers, address: Address, port: Port];
Caller asserts that address is one of the addresses of the local machine.
The buffers are passed to the receiving process. Don't call FreeBuffers.
ReturnToSender: PROC [b: Buffers];
This is the normal way for a server to answer a single-datagram query.
ReturnToSender swaps source and dest (addresses and ports), then sends datagram back where it came from.
Receiving
Get: PROC [h: Handle] RETURNS [b: Buffers];
NIL if none before timeout
Use Kick or Process.Abort if you get impatient
! ReceivedError[...]
CheckError: PROC [h: Handle];
Do nothing but possibly raise ...
! ReceivedError[...]
GetUserBytes: PROC [b: Buffer] RETURNS [bytes: CARDINAL];
Get number of bytes of data in body of UDP datagram. Should be called only on the first buffer of a chain.
GetSource: PROC [b: Buffers] RETURNS [address: Address, port: Port];
Get source address and port of b.
FreeBuffers: PROC [b: Buffers];
Dropping on the floor is safe, but very risky/evil/antisocial.
Error
Error: ERROR [code: ATOM];
Codes:
$handleDestroyed : you can't send on a handle after calling Destroy.
$requestTooLarge : AllocBuffer asked for more buffers than were specified in Create.
$badRemoteAddress : attempt to set remote address of handle to broadcast.
$destUnreachable : raised by Put or Send.
ReceivedError: ERROR [code: ATOM, remoteAddress: Address, remotePort: Port];
Codes:
$netUnreachable
$hostUnreachable
$portUnreachable
$mustFragment
$sourceRouteFailure
$timeoutTimeToLive
$timeoutReassembly
$parameterProblem
$sourceQuench
}.