159231153036212041242100244042145096184016146223183074028121215138254097035120148146118136
Forming Local Addresses
This address format is used by sockets that are local to your host (your PC running Linux). For example, when you queue a file to be printed using the lpr(1) command, it uses a local socket to communicate with the spooling service on your PC. While it is also possible to use TCP/IP for local communication, it turns out that this is less efficient.
Traditionally, the local address family has been referred to as the AF_UNIX domain (for example, a UNIX socket address). This is because these addresses use local UNIX filenames to act as the socket name. Linux kernels 2.2.0 and later support abstract socket names, which you'll learn about shortly.
The structure name for AF_LOCAL or AF_UNIX addresses is sockaddr_un. This structure is defined by including the following statement in your C program:
#include <sys/un.h>
An example of the sockaddr_un structure is shown in Listing 2.2.
Example 2.2. The sockaddr_un Address Structure
struct sockaddr_un {
sa_family_t sun_family;/* Address Family */
char sun_path[108]; /* Pathname */
};
The structure member sun_family must have the value AF_LOCAL or AF_UNIX assigned to it (these macros represent the same value, though usage of AF_LOCAL is now being encouraged). This value indicates the structure is formatted according to the structure sockaddr_un rules.
The structure member sun_path[108] contains a valid UNIX pathname. There is no null byte required at the end of the character array, as you will find out.
CAUTION
Note that the total size for the sockaddr_un address is much larger than the 16 bytes of the generic address structure. Make sure you allocate sufficient storage to accommodate the AF_LOCAL/AF_UNIX address if you are working with multiple address families within your code.
In the next sections, you will learn how to initialize an AF_LOCAL address and define its length.
TIP
Information about local socket addresses can be found in the unix(4)
man page.
Forming Traditional Local Addresses
The address name space for traditional local addresses are file system pathnames. A process might name its local socket by any valid pathname. To be valid, however, the process naming the socket must have access to all directory components of the pathname and permissions to create the final socket object in the directory named. Figure 2.2 shows the physical layout of a socket /dev/printer, which you may have active on your system. The lpd printer daemon listens on this local socket address.
Figure 2.2. Here is the AF_LOCAL/AF_UNIX Socket Address for /dev/printer.
Notice that the first two bytes indicate the address type of AF_LOCAL. The remaining bytes are the characters /dev/printer with no null byte present. Now you'll turn your attention to the C code to initialize such an address.
Some programmers like to initialize the address structure completely to zero before filling it in. This is often done using the memset(3) function and is probably a good idea:
struct sockaddr_un uaddr;
memset(&uaddr,0,sizeof uaddr);
This function call will zero out all bytes of the address structure for you.
NOTE
Zeroing out the address structure is not required if you properly initialize the mandatory address elements. However, it does make debugging easier because it eliminates any leftover data that might otherwise remain.
In this chapter, memset(3) is used to zero the address structures, as a demonstration of how it would be done.
Listing 2.3 illustrates a small C program that initializes the sockaddr_un structure and then invokes the netstat(1) command to prove that it worked. Keep in mind that the program calls upon the functions socket(2) and bind(2), which have not been covered yet. The socket(2) function is covered in detail in Chapter 4. The bind(2) function is covered in Chapter 5, "Binding Addresses to a Socket."
Example 2.3. af_unix.c—Initializing an AF_LOCAL/AF_UNIX Socket Address to /dev/printer
1: /* af_unix.c:
2: *
3: * AF_UNIX Socket Example:
4: */
5: #include <stdio.h>
6: #include <unistd.h>
7: #include <stdlib.h>
8: #include <errno.h>
9: #include <string.h>
10: #include <sys/types.h>
11: #include <sys/stat.h>
12: #include <sys/socket.h>
13: #include <sys/un.h>
14:
15: /*
16: * This function reports the error and
17: * exits back to the shell:
18: */
19: static void
20: bail(const char *on_what) {
21: perror(on_what);
22: exit(1);
23: }
24:
25: int
26: main(int argc,char **argv,char **envp) {
27: int z; /* Status return code */
28: int sck_unix; /* Socket */
29: struct sockaddr_un adr_unix;/* AF_UNIX */
30: int len_unix; /* length */
31: const char pth_unix[] /* pathname */
32: = "/tmp/my_sock";
33:
34: /*
35: * Create a AF_UNIX (aka AF_LOCAL) socket:
36: */
37: sck_unix = socket(AF_UNIX,SOCK_STREAM,0);
38:
39: if ( sck_unix == -1 )
40: bail("socket()");
41:
42: /*
43: * Here we remove the pathname for the
44: * socket, in case it existed from a
45: * prior run. Ignore errors (it might
46: * not exist).
47: */
48: unlink(pth_unix);
49:
50: /*
51: * Form an AF_UNIX Address:
52: */
53: memset(&adr_unix,0,sizeof adr_unix);
54:
55: adr_unix.sun_family = AF_UNIX;
56:
57: strncpy(adr_unix.sun_path,pth_unix,
58: sizeof adr_unix.sun_path-1)
59: [sizeof adr_unix.sun_path-1] = 0;
60:
61: len_unix = SUN_LEN(&adr_unix);
62:
63: /*
64: * Now bind the address to the socket:
65: */
66: z = bind(sck_unix,
67: (struct sockaddr *)&adr_unix,
68: len_unix);
69:
70: if ( z == -1 )
71: bail("bind()");
72:
73: /*
74: * Display all of our bound sockets:
75: */
76: system("netstat -pa --unix 2>/dev/null| "
77: "sed -n '/^Active UNIX/,/^Proto/p;"
78: "/af_unix/p'");
79:
80: /*
81: * Close and unlink our socket path:
82: */
83: close(sck_unix);
84: unlink(pth_unix);
85:
86: return 0;
87: }
The steps used in Listing 2.3 are as follows:
Variable sck_unix is defined in line 28 to hold the file descriptor for the created socket.
The local address structure is defined in line 29 and named adr_unix. The program will populate this structure with an AF_LOCAL socket address.
A socket is created in line 37 by calling upon the function socket(2). Errors are tested in line 39 and reported if necessary.
The unlink(2) function is called in line 48. Because the AF_UNIX address results in a file system object being created, it must be removed when it is no longer required. This statement attempts to remove it, in case it was not removed the last time this program was run.
The address structure adr_unix is cleared to zero bytes in line 53.
The address family is initialized as AF_UNIX in line 55.
Lines 57 to 59 copies the pathname "/tmp/my_sock" into the address structure. The code used here, also places a null byte into the structure, because the Linux-provided macro SUN_LEN() in line 61 needs it.
The length of the address is computed in line 61. The program presented uses the Linux-provided macro for this. The macro depends upon a null-terminated string being present in the adr_unix.sun_path[] structure member, however.
The function bind(2) is called (lines 66 to 68) to assign the address that was formed to the socket that was created in line 37.
The netstat(1) command is invoked in line 76 to prove that our address was bound to our socket.
The socket is closed in line 83.
The UNIX pathname created for the socket when bind(2) was called in line 66 is removed (unlinked).
The length that is assigned to len_unix in line 61, using the SUN_LEN() macro, does not count the null byte that was copied into the adr_unix.sun_path[] character array. However, it was necessary to place the null byte there, because the SUN_LEN() macro calls upon strlen(3) to compute the string length of the UNIX pathname.
To compile and run the program, you can take advantage of the supplied Makefile. Perform the following:
$ make af_unix
gcc -c -D_GNU_SOURCE -Wall af_unix.c
gcc af_unix.o -o af_unix
$
After the program has been compiled, you can simply invoke it as follows without any arguments:
$ ./af_unix
Listing 2.4 shows a modified view of the output you would receive from running the command.
Example 2.4. The Output from the af_unix Demonstration Program
$ ./af_unix
Active UNIX domain sockets (servers and established)
Proto RefCnt Flags Type State I-Node PID/Program name Path
unix 0 [ ] STREAM 104129 800/af_unix /tmp/my_sock
$
Listing 2.4 shows that there was a unix socket created, of type STREAM (SOCK_STREAM), and that af_unix was the name of the program that created it. At the right end of the line, you will see that indeed the socket name was /tmp/my_sock as it was expected to be.
Forming Abstract Local Addresses
One of the annoyances of the traditional AF_UNIX socket name was that a file system object was always involved. This was often unnecessary and inconvenient. If the original file system object was not removed and the same name was used in a call to bind(2), the name assignment would fail.
Linux kernel version 2.2 has made it possible to create an abstract name for a local socket. The trick to this is to make the first byte of the pathname a null byte. Only the bytes that follow that first null byte in the pathname then become part of the abstract name.
The example in Listing 2.5 shows a modified version of the last program. This program takes some different steps to create the abstract name.
Example 2.5. af_unix2.c—Program Creating an Abstract Named AF_LOCAL/AF_UNIX Socket
<$nopage>
001 1: /* af_unix2.c:
002 2: *
003 3: * AF_UNIX Socket Example:
004 4: */
005 5: #include <stdio.h>
006 6: #include <unistd.h>
007 7: #include <stdlib.h>
008 8: #include <errno.h>
009 9: #include <string.h>
010 10: #include <sys/types.h>
011 11: #include <sys/stat.h>
012 12: #include <sys/socket.h>
013 13: #include <sys/un.h>
014 14:
015 15: /*
016 16: * This function reports the error and
017 17: * exits back to the shell:
018 18: */
019 19: static void
020 20: bail(const char *on_what) {
021 21: perror(on_what);
022 22: exit(1);
023 23: }
024 24:
025 25: int
026 26: main(int argc,char **argv,char **envp) {
027 27: int z; /* Status return code */
028 28: int sck_unix; /* Socket */
029 29: struct sockaddr_un adr_unix;/* AF_UNIX */
030 30: int len_unix; /* length */
031 31: const char pth_unix[] /* Abs. Name */
032 32: = "Z*MY-SOCKET*";
033 33:
034 34: /*
035 35: * Create an AF_UNIX (aka AF_LOCAL) socket:
036 36: */
037 37: sck_unix = socket(AF_UNIX,SOCK_STREAM,0);
038 38:
039 39: if ( sck_unix == -1 )
040 40: bail("socket()");
041 41:
042 42: /*
043 43: * Form an AF_UNIX Address:
044 44: */ <$nopage>
045 45: memset(&adr_unix,0,sizeof adr_unix);
046 46:
047 47: adr_unix.sun_family = AF_UNIX;
048 48:
049 49: strncpy(adr_unix.sun_path,pth_unix,
050 50: sizeof adr_unix.sun_path-1)
051 51: [sizeof adr_unix.sun_path-1] = 0;
052 52:
053 53: len_unix = SUN_LEN(&adr_unix);
054 54:
055 55: /* Now make first byte null */
056 56: adr_unix.sun_path[0] = 0;
057 57:
058 58: /*
059 59: * Now bind the address to the socket:
060 60: */
061 61: z = bind(sck_unix,
062 62: (struct sockaddr *)&adr_unix,
063 63: len_unix);
064 64:
065 65: if ( z == -1 )
066 66: bail("bind()");
067 67:
068 68: /*
069 69: * Display all of our bound sockets:
070 70: */
071 71: system("netstat -pa --unix 2>/dev/null| "
072 72: "sed -n '/^Active UNIX/,/^Proto/p;"
073 73: "/af_unix/p'");
074 74:
075 75: /*
076 76: * Close and unlink our socket path:
077 77: */
078 78: close(sck_unix);
079 79: return 0;
080 80: }
081 <$nopage>
To make and run the program in Listing 2.5, perform the following commands:
$ make af_unix2
gcc -c -D_GNU_SOURCE -Wall af_unix2.c
gcc af_unix2.o -o af_unix2
$ ./af_unix2
The output from the running the program is shown in Listing 2.6.
Example 2.6. Output of the af_unix2 Example Program
$ ./af_unix2
Active UNIX domain sockets (servers and established)
Proto RefCnt Flags Type State I-Node PID/Program name Path
unix 0 [ ] STREAM 104143 5186/af_unix2 @*MY-SOCKET*
$
From Listing 2.6, you can see the socket address appears as the name @*MY-SOCKET*. The leading @ sign is used by netstat(1) to indicate abstract UNIX socket names. The remaining characters are the ones that were copied into the rest of the character array. Notice that the @ character appears where our placeholder 'Z' character was (see line 32 in Listing 2.5).
The overall program steps were the same as the earlier program in Listing 2.3. However, the address initialization steps were a bit different in Listing 2.5. Those steps will be described here:
The abstract name of the socket is defined as a string constant in lines 31 and 32. Notice the first character of the string is Z. This extra character is just a placeholder in this string, because it will be eventually replaced by a null byte in step 6.
The optional zeroing of the structure was done in line 45 by calling upon memset(3).
The address family was set to AF_UNIX in line 47.
The abstract pathname is copied to adr_unix.sun_path in line 49 using the strncpy(3) function as before. Notice again, that the terminating null byte is placed into the destination character array for the benefit of the Linux SUN_LEN() macro. Otherwise, the terminating null byte is not required.
The length of the address is computed with the help of the Linux provided SUN_LEN() C macro in line 53. This macro invokes strlen(3) on sun_path[], so it is necessary that a terminating null byte is present.
This is new: The first byte of the sun_path[] array is set to a null byte. This step must be performed last, if the SUN_LEN() macro is used (step 5).
CAUTION
If you use the Linux-provided SUN_LEN() macro to compute the length of an abstract AF_LOCAL or AF_UNIX socket address, be sure to check that the first byte is not yet null. Make the sun_path[0] byte null after the address length has been computed; otherwise, the computed length will be incorrect.
In this section, you have learned what you need to know about creating AF_LOCAL and AF_UNIX socket addresses. To compute the length of the socket address, you use the SUN_LEN() macro that is provided. Special attention must be paid, however, when computing the length of abstract socket names.
|