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鈥?8
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.
|