Tuesday, September 6, 2011

SO_REUSEADDR example


Setting the SO_REUSEADDR Option

In the first part of Chapter 11, “Concurrent Client Servers” a server design using the fork(2) system call was presented and tested. Figure 12.1 shows three processes that exist after a telnet command has established contact with the server.
Figure 12.1:
This graphic illustrates the connection of the telnet command to a forked server process.

The client is being serviced by process ID 927. This means that you can kill process ID 926 and the client will continue to be serviced. However, no new connections to the server can be made, because there will be no server listening for new connections (listening server PID 926 was killed).

Now, if you were to restart the server to listen for new connections, a problem would develop. When the new server process attempts to bind the IP address 192.168.0.1 port 9099, the bind(2) function will return the error EADDRINUSE. This error code indicates that the IP address is already in use with port 9099. This occurs because process ID 927 is still engaged in servicing a client. Address 192.168.0.1 port 9099 is still being used by that process (review Figure 12.1).

The solution to this problem is to kill off process 927, which will close that socket and release the IP address and port. However, if the client being serviced is the CEO of the company you work for, this will not be an option (this might be a career-limiting move). In the meantime, you'll be bugged by other departments, wondering why you haven't restarted the server.

A better solution to the problem just presented is to use the SO_REUSEADDR socket option. All servers should make use of this option, unless there is a good reason not to. To make effective use of this option, perform the following in the server, which listens for connections:
  1. Create your listening socket as usual with socket(2). 
  2. Call setsockopt(2) setting SO_REUSEADDR option to TRUE. 
  3. Now call bind(2) as usual.
The socket will now be marked as reusable. If the listening server process (PID 926 in Figure 12.1) terminates for any reason, you will be able to be restart it. This will be true even when a client has another server process engaged using the same IP address and port number.

In order for SO_REUSEADDR option to be effective, the following conditions must be met:
  • No other socket with the same IP address and port can be in a listen mode. 
  • All sockets with the same IP address and port number must have the SO_REUSEADDR option set to TRUE.
What this means is that there can be only one listener at a specific IP address and port number pair. If one such socket already exists, then setting the option will not accomplish your goal. Setting SO_REUSEADDR to TRUE can be effective only if all existing sockets with the same address and port number have this option set. If any existing socket does not have this option set, then bind (2) will continue to return an error.

The following code shows how to set the option to TRUE:

Example

#define TRUE 1

#define FALSE 0

int z;    /* Status code */
int s;    /* Socket number */

int so_reuseaddr = TRUE;

z = setsockopt(s,
               SOL_SOCKET,
               SO_REUSEADDR,
               &so_reuseaddr,
               sizeof so_reuseaddr);

The SO_REUSEADDR option can be queried with the getsockopt(2) function if required.

See Also
SO_PASSCRED & SO_PEERCRED, SO_BROADCAST, SO_KEEPALIVE, SO_LINGERSO_OBINLINE, SO_TYPE

No comments:

Post a Comment