Check out the new USENIX Web site. next up previous
Next: State of Deployment Up: New Interfaces Previous: Name Resolution

Socket Addresses

Figure 7 shows a brief summary of the new socket address interfaces. The major new addition is the sockaddr_storage, which is defined as a structure that is big enough to hold any socket address that the system supports or might support in the future, and provides sufficient alignment for any socket address that the system supports or might support in the future. In practice, the size of the structure is bounded on many systems by the capacity of the eight bit integer used in the sa_len field of all socket addresses. On other systems, the bound might be provided by other structures' fields. The bound actually chosen can be selected by the systems' authors, but the sockaddr_storage is defined to have whatever size is needed. The alignment provided by the sockaddr_storage will typically be the largest alignment available on the system, though again the exact choice is up to the systems' implementors.

Note that the sockaddr_storage is required to have fields of the same type and in the same place as the sa_len and sa_family fields in the systems' sockaddrs, but that the standards that specify this data structure don not actually require those fields to have a known name and give examples with names that makes them ``hidden.'' While it is hoped that the long term solution will be to fix this problem in the standards, the short term most portable way to use these fields is to cast a sockaddr_storage to a sockaddr and to use the fields through the latter type.

Figure 7: New Socket Address Interfaces
struct sockaddr_storage { /* Slightly nonstandard - See text for a warning */
    u_int8_t    ss_len;        /* address length */
    sa_family_t ss_family;     /* address family */
    /* other fields guarantee size and padding */

#define SA_LEN(sa) ((sa)->sa_len) /* Nonstandard */

Figure 8: Use of a sockaddr_storage to Store Arbitrary Addresses
        struct sockaddr_storage ss;
        if (logging) {
                sval = sizeof(sockaddr_storage);
                if (getpeername(0, (struct sockaddr *)&ss, &sval) < 0)
                        err("getpeername: %s", strerror(errno));

The sockaddr_storage is used where a socket address needs to be stored before its exact length is known. Figure 8 shows some of the example in Figure 3, changed to take advantage of this structure as well as getnameinfo(). The code is not very different, but the use of the sockaddr_storage guarantees that any protocol-specific socket address can be safely stored in the buffer.

A controversial API extension that was used heavily in the NRL code is the SA_LEN() macro. On systems whose sockaddr has a sa_len field, this expands to return the contents of that field and has the same semantics except that it is only defined to be an rvalue. On systems whose sockaddr does not, this expands into an operation that returns the correct value based on the value of the sa_family field. This macro solves the problem of needing a sockaddr's length for many function calls well after existing code has lost the length information. It is frequently far easier to replace a hard coded value such as sizeof(struct sockaddr_in) with a macro use like SA_LEN(sa) than it is to gut an entire program and fix this. Using the macro, this technique is portable to systems with and without sa_len support. Authors who have used this technique extensively have been quite supportive of it, while authors of systems that don't have sa_len fields have been opposed to it.

next up previous
Next: State of Deployment Up: New Interfaces Previous: Name Resolution
Craig Metz 2000-05-08