TCP and UDP use a 4-tuple of local IP address, local port number, foreign IP address, and foreign port number to do their addressing. TCP requires these 4-tuples to be unique. UDP does not. It is unrealistic to expect user programs to always know proper values to use for the local address and local port, since a host can reside on multiple networks and the set of allocated port numbers is not directly accessible to a user. To avoid these problems, you can leave parts of the address unspecified and let the system assign the parts appropriately when needed. Various portions of these tuples may be specified by various parts of the sockets API.
A call to accept(3SOCKET) retrieves connection information from a foreign client, so it causes the local address and port to be specified to the system (even though the caller of accept(3SOCKET) didn't specify anything), and the foreign address and port to be returned.
A service that resides at a particular port, but which does not care what local address is chosen, can bind(3SOCKET) itself to its port and leave the local address unspecified (set to in6addr_any, a variable with a constant value in <netinet/in.h>). If the local port need not be fixed, a call to listen(3SOCKET) causes a port to be chosen. Specifying an address of in6addr_any or a port number of 0 is known as wildcarding. (For AF_INET, INADDR_ANY is used in place of in6addr_any.)
The wildcard address simplifies local address binding in the Internet family. The sample code below binds a specific port number, MYPORT, to a socket, and leaves the local address unspecified.
#include <sys/types.h> #include <netinet/in.h> ... struct sockaddr_in6 sin; ... s = socket(AF_INET6, SOCK_STREAM, 0); bzero (&sin6, sizeof (sin6)); sin.sin6_family = AF_INET6; sin.sin6_addr.s6_addr = in6addr_any; sin.sin6_port = htons(MYPORT); bind(s, (struct sockaddr *) &sin, sizeof sin);
Each network interface on a host typically has a unique IP address. Sockets with wildcard local addresses can receive messages directed to the specified port number and sent to any of the possible addresses assigned to a host. For example, if a host has two interfaces with addresses 22.214.171.124 and 10.0.0.78, and a socket is bound as in Example 2-17, the process can accept connection requests addressed to 126.96.36.199 or 10.0.0.78. To allow only hosts on a specific network to connect to it, a server binds the address of the interface on the appropriate network.
Similarly, a local port number can be left unspecified (specified as 0), in which case the system selects a port number. For example, to bind a specific local address to a socket, but to leave the local port number unspecified:
bzero (&sin, sizeof (sin)); (void) inet_pton (AF_INET6, ":ffff:127.0.0.1", sin.sin6_addr.s6_addr); sin.sin6_family = AF_INET6; sin.sin6_port = htons(0); bind(s, (struct sockaddr *) &sin, sizeof sin);
The system uses two criteria to select the local port number:
The first is that Internet port numbers less than 1024 (IPPORT_RESERVED) are reserved for privileged users (that is, the superuser). Nonprivileged users can use any Internet port number greater than 1024. The largest Internet port number is 65535.
The second criterion is that the port number is not currently bound to some other socket.
In certain cases, the algorithm used by the system to select port numbers is unsuitable for an application. This is because associations are created in a two-step process. For example, the Internet file transfer protocol specifies that data connections must always originate from the same local port. However, duplicate associations are avoided by connecting to different foreign ports. In this situation, the system would disallow binding the same local address and port number to a socket if a previous data connection's socket still existed. To override the default port selection algorithm, you must perform an option call before address binding:
... int on = 1; ... setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof on); bind(s, (struct sockaddr *) &sin, sizeof sin);
With this call, local addresses already in use can be bound. This does not violate the uniqueness requirement, because the system still verifies at connect time that any other sockets with the same local address and port do not have the same foreign address and port. If the association already exists, the error EADDRINUSE is returned.