[ Team LiB ] Previous Section Next Section

15.2 Unix Domain Socket Address Structure

Figure 15.1 shows the Unix domain socket address structure, which is defined by including the <sys/un.h> header.

Figure 15.1 Unix domain socket address structure: sockaddr_un.
struct sockaddr_un {
  sa_family_t sun_family;     /* AF_LOCAL */
  char        sun_path[104];  /* null-terminated pathname */
};

The POSIX specification does not define the length of the sun_path array and it specifically warns that applications should not assume a particular length. Use the sizeof operator to find the length at run-time and to verify that a pathname fits into the array. The length is likely to be between 92 and 108 rather than a larger value big enough to hold any pathname. The reason for these limits is an implementation artifact dating back to 4.2BSD requiring that this structure fit in a 128-byte mbuf (a kernel memory buffer).

The pathname stored in the sun_path array must be null-terminated. The macro SUN_LEN is provided and it takes a pointer to a sockaddr_un structure and returns the length of the structure, including the number of non-null bytes in the pathname. The unspecified address is indicated by a null string as the pathname, that is, a structure with sun_path[0] equal to 0. This is the Unix domain equivalent of the IPv4 INADDR_ANY constant and the IPv6 IN6ADDR_ANY_INIT constant.

POSIX renames the Unix domain protocols as "local IPC," to remove the dependence on the Unix OS. The historical constant AF_UNIX becomes AF_LOCAL. Nevertheless, we still use the term "Unix domain" as that has become its de facto name, regardless of the underlying OS. Also, even with POSIX attempting to make these OS-independent, the socket address structure still retains the _un suffix!

Example: bind of Unix Domain Socket

The program in Figure 15.2 creates a Unix domain socket, binds a pathname to it, and then calls getsockname and prints the bound pathname.

Figure 15.2 bind of a pathname to a Unix domain socket.

unixdomain/unixbind.c

 1 #include     "unp.h"

 2 int
 3 main(int argc, char **argv)
 4 {
 5     int     sockfd;
 6     socklen_t len;
 7     struct sockaddr_un addr1, addr2;

 8     if (argc != 2)
 9         err_quit("usage: unixbind <pathname>");

10     sockfd = Socket(AF_LOCAL, SOCK_STREAM, 0);

11     unlink(argv[1]);            /* OK if this fails */

12     bzero(&addr1, sizeof(addr1));
13     addr1.sun_family = AF_LOCAL;
14     strncpy(addr1.sun_path, argv[1], sizeof(addr1.sun_path) - 1);
15     Bind(sockfd, (SA *) &addr1, SUN_LEN(&addr1));

16     len = sizeof(addr2);
17     Getsockname(sockfd, (SA *) &addr2, &len);
18     printf("bound name = %s, returned len = %d\n", addr2.sun_path, len);

19     exit(0);
20 }
Remove pathname first

11 The pathname that we bind to the socket is the command-line argument. But the bind will fail if the pathname already exists in the filesystem. Therefore, we call unlink to delete the pathname, in case it already exists. If it does not exist, unlink returns an error, which we ignore.

bind and then getsockname

12–18 We copy the command-line argument using strncpy, to avoid overflowing the structure if the pathname is too long. Since we initialize the structure to zero and then subtract one from the size of the sun_path array, we know the pathname is null-terminated. bind is called and we use the macro SUN_LEN to calculate the length argument for the function. We then call getsockname to fetch the name that was just bound and print the result.

If we run this program under Solaris, we obtain the following results:


solaris % umask                           first print our umask value
022                                         shells print this value in octal
solaris % unixbind /tmp/moose
bound name = /tmp/moose, returned len = 13
solaris % unixbind /tmp/moose              run it again
bound name = /tmp/moose, returned len = 13
solaris % ls -l /tmp/moose
srwxr-xr-x 1 andy     staff       0 Aug 10 13:13 /tmp/moose
solaris %unixbind /tmp/moose
srwxr-xr-x 1 andy     staff       0 Aug 10 13:13 /tmp/moose

We first print our umask value because POSIX specifies that the file access permissions of the resulting pathname should be modified by this value. Our value of 22 turns off the group-write and other-write bits. We then run the program and see that the length returned by getsockname is 13: 2 bytes for the sun_family member and 11 bytes for the actual pathname (excluding the terminating null byte). This is an example of a value-result argument whose result when the function returns differs from its value when the function was called. We can output the pathname using the %s format of printf because the pathname is null-terminated in the sun_path member. We then run the program again, to verify that calling unlink removes the pathname.

We run ls -l to see the file permissions and file type. Under Solaris (and most Unix variants), the file type is a socket, which is printed as s. We also notice that the permission bits were modified as appropriate by the umask value. Finally, we run ls again, with the -F option, which causes Solaris to append an equals sign to the pathname.

Historically, the umask value did not apply to the creation of Unix domain sockets, but over time, most Unix vendors have fixed this so the permissions fit expectations. Systems still exist where the file permission bits may show either all permissions or no permissions (regardless of the umask setting). In addition, some systems show the file as a FIFO, which is printed as p, and not all systems show the equals sign with ls -F. The behavior we show above is the most common.

    [ Team LiB ] Previous Section Next Section