11.12 UDP Server Design

11.12 UDP Server Design

There are some implications in using UDP that affect the design and implementation of a server. The design and implementation of clients is usually easier than that of servers, which is why we talk about server design and not client design. Servers typically interact with the operating system and most servers need a way to handle multiple clients at the same time.

Normally a client starts, immediately communicates with a single server, and is done. Servers, on the other hand, start and then go to sleep, waiting for a client's request to arrive . In the case of UDP, the server wakes up when a client's datagram arrives, probably containing a request message of some form from the client.

Our interest here is not in the programming aspects of clients and servers ([Stevens 1990] covers all those details), but in the protocol features of UDP that affect the design and implementation of a server using UDP. (We examine the details of TCP server design in Section 18.11.) Although some of the features we describe depend on the implementation of UDP being used, the features are common to most implementations .

Client IP Address and Port Number

What arrives from the client is a UDP datagram. The IP header contains the source and destination IP addresses, and the UDP header contains the source and destination UDP port numbers . When an application receives a UDP datagram, it must be told by the operating system who sent the message ”the source IP address and port number.

This feature allows an iterative UDP server to handle multiple clients. Each reply is sent back to the client that sent the request.

Destination IP Address

Some applications need to know who the datagram was sent to, that is, the destination IP address. For example, the Host Requirements RFC states that a TFTP server should ignore received datagrams that are sent to a broadcast address. (We describe broadcasting in Chapter 12 and TFTP in Chapter 15.)

This requires the operating system to pass the destination IP address from the received UDP datagram to the application. Unfortunately, not all implementations provide this capability.

The sockets API provides this capability with the IP_RECVDSTADDR socket option. Of the systems used in the text, only BSD/386, 4.4BSD, and AIX 3.2.2 support this option. SVR4, SunOS 4.x, and Solaris 2.x don't support it.

UDP Input Queue

We said in Section 1.8 that most UDP servers are iterative servers. This means a single server process handles all the client requests on a single UDP port (the server's well-known port).

Normally there is a limited size input queue associated with each UDP port that an application is using. This means that requests that arrive at about the same time from different clients are automatically queued by UDP. The received UDP datagrams are passed to the application (when it asks for the next one) in the order they were received.

It is possible, however, for this queue to overflow, causing the kernel's UDP module to discard incoming datagrams. We can see this with the following experiment. We start our sock program on the host bsdi running as a UDP server:

 bsdi %  sock -  s  -u -v -E -R256 -r256 -P30 6666  from 140.252.13.33, to 140.252.13.63: 1111111111  from  sun,  to broadcast address  from 140.252.13.34, to 140.252.13.35: 4444444444444  from  svr4,  to unicast address  

We specify the following flags: “s to run as a server, -u for UDP, “v to print the client's IP address, and -E to print the destination IP address (which is supported by this system). Additionally we set the UDP receive buffer for this port to 256 bytes ( “R ), along with the size of each application read ( “r ). The flag “P30 tells it to pause for 30 seconds after creating the UDP port, before reading the first datagram. This gives us time to start the clients on two other hosts , send some datagrams, and see how the receive queueing works.

Once the server is started, and is in its 30-second pause, we start one client on the host sun and send three datagrams:

 sun  % sock -u -v 140.252.13.63 6666   to Ethernet broadcast address  connected on 140.252.13.33.1252 to 140.252.13.63.6666  1111111111   11 bytes of data (with newline)   222222222   10 bytes of data (with newline)   33333333333   12 bytes of data (with newline)  

The destination address is the broadcast address (140.252.13.63). We also start a second client on the host svr4 and send another three datagrams:

 svr4 %  sock -u -v bsdi 6666  connected on 0.0.0.0.1042 to 140.252.13.35.6666  4444444444444   14 bytes of data (with newline)   555555555555555   16 bytes of data (with newline)   66666666  9  bytes of data (with newline)  

The first thing we notice in the interactive output shown earlier on bsdi is that only two datagrams were received by the application: the first one from sun with all 1s, and the first one from svr4 with all 4s. The other four datagrams appear to have been thrown away.

The tcpdump output in Figure 11.20 shows that all six datagrams were delivered to the destination host. The datagrams were typed on the two clients in alternating order: first from sun, then from svr4, and so on. We can also see that all six were delivered in about 12 seconds, within the 30-second period while the server was sleeping

Figure 11.20. tcpdump for UDP datagrams sent by two clients.
graphics/11fig20.gif

We can also see the server's “E option lets it know the destination IP address of each datagram. If it wanted to, it could choose what to do with the first datagram it receives, which was sent to a broadcast address.

We can see several points in this example. First, the application is not told when its input queue overflows. The excess datagrams are just discarded by UDP. Also, from the tcpdump output we see that nothing is sent back to the client to tell it that its datagram was discarded. There is nothing like an ICMP source quench sent back to the sender. Finally, it appears that the UDP input queue is FIFO (first-in, first-out), whereas we saw that the ARP input queue in Section 11.9 was LIFO (last-in, first-out).

Restricting Local IP Address

Most UDP servers wildcard their local IP address when they create a UDP end point. This means that an incoming UDP datagram destined for the server's port will be accepted on any local interface. For example, we can start a UDP server on port 7777:

 sun %  sock -u -s 7777  

We then use the netstat command to see the state of the end point:

 sun %  netstat -a -n -f inet  Active Internet connections (including servers)     Proto Recv-Q Send-Q  Local Address        Foreign Address         (state)     udp        0      0  *.7777               *.* 

We have deleted many lines of output other than the one in which we're interested. The “a flag reports on all network end points. The “n flag prints IP addresses as dotted -decimal numbers, instead of trying to use the DNS to convert the address to a name , and prints numeric port numbers instead of service names . The “f inet option reports only TCP and UDP end points.

The local address is printed as *.7777 where the asterisk means the local IP address has been wildcarded.

When the server creates its end point it can specify one of the host's local IP addresses, including one of its broadcast addresses, as the local IP address for the end point. Incoming UDP datagrams will then be passed to this end point only if the destination IP address matches the specified local address. With our sock program, if we specify an IP address before the port number, that IP address becomes the local IP address for the end point. For example,

 sun %  sock -u -s 140.252.1.29 7777  

restricts the server to datagrams arriving on the SLIP interface (140.252.1.29). The netstat output shows this:

 Proto Recv-Q Send-Q  Local Address        Foreign Address        (state)     udp        0      0  140.252.1.29.7777    *.* 

If we try to send this server a datagram from a host on the Ethernet, bsdi at address 140.252.13.35, an ICMP port unreachable is returned. The server never sees the datagram. Figure 11.21 shows this scenario.

Figure 11.21. Rejection of UDP datagram caused by server's local address binding.
graphics/11fig21.gif

It is possible to start different servers at the same port, each with a different local IP address. Normally, however, the system must be told by the application that it is OK to reuse the same port number.

With the sockets API the SO_REUSEADDR socket option must be specified. This is done by our sock program by specifying the “A option.

On our host sun we can start five different servers on the same UDP port (8888):

 sun %  sock u -s 140.252.1.29 8888   for SLIP link  sun %  sock u -s -A 140.252.13.33 8888   for Ethernet  sun %  sock u -s -A 127.0.0.1 8888   for loopback interface  sun %  sock u -s -A 140.252.13.63 8888   for Ethernet broadcasts  sun %  sock u -s -A 8888   everything else (wildcard IP address)  

All except the first of the servers must be started with the “A flag, telling the system that it's OK to reuse the same port number. The netstat output shows the five servers:

 Proto Recv-Q  Send-Q   Local Address          Foreign Address          (state)     udp        0       0   *.8888                 *.*     udp        0       0   140.252.13.63.8888     *.*     udp        0       0   127.0.0.1.8888         *.*     udp        0       0   140.252.13.33.8888     *.*     udp        0       0   140.252.1.29.8888      *.* 

In this scenario, the only datagrams that will go to the server with the wildcarded local IP address are those destined to 140.252.1.255, because the other four servers cover all other possibilities.

There is a priority implied when an end point with a wildcard address exists. An end point with a specific IP address that matches the destination IP address is always chosen over a wildcard. The wildcard end point is used only when a specific match is not found.

Restricting Foreign IP Address

In all the netstat output that we showed earlier, the foreign IP address and foreign port number are shown as * . * meaning the end point will accept an incoming UDP datagram from any IP address and any port number. Most implementations allow a UDP end point to restrict the foreign address.

This means the end point will only receive UDP datagrams from that specific IP address and port number. Our sock program uses the “f option to specify the foreign IP address and port number:

 sun %  sock -u -s -f 140.252.13.35.4444 5555  

This sets the foreign IP address to 140.252.13.35 (our host bsdi ) and the foreign port number to 4444. The server's well-known port is 5555. If we run netstat we see that the local IP address has also been set, even though we didn't specify it:

 Proto Recv-Q Send-Q  Local Address         Foreign Address          (state)     udp        0      0  140.252.13.33.5555    140.252.13.35.4444 

This is a side effect of specifying the foreign IP address and foreign port on Berkeley-derived systems: if the local address has not been chosen when the foreign address is specified, the local address is chosen automatically. Its value becomes the IP address of the interface chosen by IP routing to reach the specified foreign IP address. Indeed, in this example the IP address on sun for the Ethernet that is connected to the foreign address is 140.252.13.33.

Figure 11.22 summarizes the three types of address bindings that a UDP server can establish for itself.

Figure 11.22. Specification of local and foreign IP addresses and port number for UDP server.
graphics/11fig22.gif

In all cases, lport is the server's well-known port and localIP must be the IP address of a local interface. The ordering of the three rows in the table is the order that the UDP module applies when trying to determine which local end point receives an incoming datagram. The most specific binding (the first row) is tried first, and the least specific (the last row with both IP addresses wildcarded) is tried last.

Multiple Recipients per Port

Although it's not specified in the RFCs, most implementations allow only one application end point at a time to be associated with any one local IP address and UDP port number. When a UDP datagram arrives at a host destined for that IP address and port number, one copy is delivered to that single end point. The IP address of the end point can be the wildcard, as shown earlier.

For example, under SunOS 4.1.3 we start one server on port 9999 with a wildcarded local IP address:

 sun %  sock -u -s 9999  

If we then try to start another server with the same wildcarded local address and the same port, it doesn't work, even if we specify the “A option:

 sun %  sock -u -s 9999   we expect this to fail  can't bind local address: Address already in use     sun  % sock -u -s -A 9999   so we try -A flag this time  can't bind local address: Address already in use 

On systems that support multicasting (Chapter 12), this changes. Multiple end points can use the same local IP address and UDP port number, although the application normally must tell the API that this is OK (i.e., our “A flag to specify the SO_REUSEADDR socket option).

4.4BSD, which supports multicasting, requires the application to set a different socket option ( SO_REUSEPORT ) to allow multiple end points to share the same port. Furthermore each end point must specify this option, including the first one to use the port.

When a UDP datagram arrives whose destination IP address is a broadcast or multicast address, and there are multiple end points at the destination IP address and port number, one copy of the incoming datagram is passed to each end point. (The end point's local IP address can be the wildcard, which matches any destination IP address.) But if a UDP datagram arrives whose destination IP address is a unicast address, only a single copy of the datagram is delivered to one of the end points. Which end point gets the unicast datagram is implementation dependent.



TCP.IP Illustrated, Volume 1. The Protocols
TCP/IP Illustrated, Vol. 1: The Protocols (Addison-Wesley Professional Computing Series)
ISBN: 0201633469
EAN: 2147483647
Year: 1993
Pages: 378

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net