7.3 Checking if an Option Is Supported and Obtaining the Default


We now write a program to check whether most of the options defined in Figures 7.1 and 7.2 are supported, and if so, print their default value. Figure 7.3 contains the declarations for our program.

Declare union of possible values

3 “8 Our union contains one member for each possible return value from getsockopt .

Define function prototypes

9 “12 We define function prototypes for four functions that are called to print the value for a given socket option.

Define structure and initialize array

13 “52 Our sock_opts structure contains all the information necessary to call getsockopt for each socket option and then print its current value. The final member, opt_val_str , is a pointer to one of our four functions that will print the option value. We allocate and initialize an array of these structures, one element for each socket option.

Not all implementations support all socket options. The way to determine if a given option is supported is to use an #ifdef or a #if defined , as we show for SO_REUSEPORT . For completeness, every element of the array should be compiled similarly to what we show for SO_REUSEPORT , but we omit these because the #ifdefs just lengthen the code that we show and add nothing to the discussion.

Figure 7.3 Declarations for our program to check the socket options.

sockopt/checkopts.c

 1 #include "unp.h" 2 #include <netinet/tcp.h> /* for TCP_xxx defines */ 3 union val { 4 int i_val; 5 long l_val; 6 struct linger linger_val; 7 struct timeval timeval_val; 8 } val; 9 static char *sock_str_flag(union val *, int); 10 static char *sock_str_int(union val *, int); 11 static char *sock_str_linger(union val *, int); 12 static char *sock_str_timeval(union val *, int); 13 struct sock_opts { 14 const char *opt_str; 15 int opt_level; 16 int opt_name; 17 char *(*opt_val_str) (union val *, int); 18 } sock_opts[] = { 19 { "SO_BROADCAST", SOL_SOCKET, SO_BROADCAST, sock_str_flag }, 20 { "SO_DEBUG", SOL_SOCKET, SO_DEBUG, sock_str_flag }, 21 { "SO_DONTROUTE", SOL_SOCKET, SO_DONTROUTE, sock_str_flag }, 22 { "SO_ERROR", SOL_SOCKET, SO_ERROR, sock_str_int }, 23 { "SO_KEEPALIVE", SOL_SOCKET, SO_KEEPALIVE, sock_str_flag }, 24 { "SO_LINGER", SOL_SOCKET, SO_LINGER, sock_str_linger }, 25 { "SO_OOBINLINE", SOL_SOCKET, SO_OOBINLINE, sock_str_flag }, 26 { "SO_RCVBUF", SOL_SOCKET, SO_RCVBUF, sock_str_int }, 27 { "SO_SNDBUF", SOL_SOCKET, SO_SNDBUF, sock_str_int }, 28 { "SO_RCVLOWAT", SOL_SOCKET, SO_RCVLOWAT, sock_str_int }, 29 { "SO_SNDLOWAT", SOL_SOCKET, SO_SNDLOWAT, sock_str_int }, 30 { "SO_RCVTIMEO", SOL_SOCKET, SO_RCVTIMEO, sock_str_timeval }, 31 { "SO_SNDTIMEO", SOL_SOCKET, SO_SNDTIMEO, sock_str_timeval }, 32 { "SO_REUSEADDR", SOL_SOCKET, SO_REUSEADDR, sock_str_flag }, 33 #ifdef SO_REUSEPORT 34 { "SO_REUSEPORT", SOL_SOCKET, SO_REUSEPORT, sock_str_flag }, 35 #else 36 { "SO_REUSEPORT", 0, 0, NULL }, 37 #endif 38 { "SO_TYPE", SOL_SOCKET, SO_TYPE, sock_str_int }, 39 { "SO_USELOOPBACK", SOL_SOCKET, SO_USELOOPBACK, sock_str_flag }, 40 { "IP_TOS", IPPROTO_IP, IP_TOS, sock_str_int }, 41 { "IP_TTL", IPPROTO_IP, IP_TTL, sock_str_int }, 42 { "IPV6_DONTFRAG", IPPROTO_IPV6,IPV6_DONTFRAG, sock_str_flag }, 43 { "IPV6_UNICAST_HOPS", IPPROTO_IPV6,IPV6_UNICAST_HOPS,sock_str_int }, 44 { "IPV6_V6ONLY", IPPROTO_IPV6,IPV6_V6ONLY, sock_str_flag }, 45 { "TCP_MAXSEG", IPPROTO_TCP,TCP_MAXSEG, sock_str_int }, 46 { "TCP_NODELAY", IPPROTO_TCP,TCP_NODELAY, sock_str_flag }, 47 { "SCTP_AUTOCLOSE", IPPROTO_SCTP,SCTP_AUTOCLOSE,sock_str_int }, 48 { "SCTP_MAXBURST", IPPROTO_SCTP,SCTP_MAXBURST, sock_str_int }, 49 { "SCTP_MAXSEG", IPPROTO_SCTP,SCTP_MAXSEG, sock_str_int }, 50 { "SCTP_NODELAY", IPPROTO_SCTP,SCTP_NODELAY, sock_str_flag }, 51 { NULL, 0, 0, NULL } 52 }; 

Figure 7.4 shows our main function.

Figure 7.4 main function to check all socket options.

sockopt/checkopts.c

 53 int 54 main(int argc, char **argv) 55 { 56 int fd; 57 socklen_t len; 58 struct sock_opts *ptr; 59 for (ptr = sock_opts; ptr->opt_str != NULL; ptr++) { 60 printf("%s: ", ptr->opt_str); 61 if (ptr->opt_val_str == NULL) 62 printf("(undefined)\n"); 63 else { 64 switch (ptr->opt_level) { 65 case SOL_SOCKET: 66 case IPPROTO_IP: 67 case IPPROTO_TCP: 68 fd = Socket(AF_INET, SOCK_STREAM, 0); 69 break; 70 #ifdef IPV6 71 case IPPROTO_IPV6: 72 fd = Socket(AF_INET6, SOCK_STREAM, 0); 73 break; 74 #endif 75 #ifdef IPPROTO_SCTP 76 case IPPROTO_SCTP: 77 fd = Socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP); 78 break; 79 #endif 80 default: 81 err_quit("Can't create fd for level %d\n", ptr->opt_level); 82 } 83 len = sizeof(val); 84 if (getsockopt(fd, ptr->opt_level, ptr->opt_name, 85 &val, &len) == -1) { 86 err_ret("getsockopt error"); 87 } else { 88 printf("default = %s\n", (*ptr->opt_val_str) (&val, len)); 89 } 90 close(fd); 91 } 92 } 93 exit(0); 94 } 

Go through all options

59 “63 We go through all elements in our array. If the opt_val_str pointer is null, the option is not defined by the implementation (which we showed for SO_REUSEPORT ).

Create socket

63 “82 We create a socket on which to try the option. To try socket, IPv4, and TCP layer socket options, we use an IPv4 TCP socket. To try IPv6 layer socket options, we use an IPv6 TCP socket, and to try SCTP layer socket options, we use an IPv4 SCTP socket.

Call getsockopt

83 “87 We call getsockopt but do not terminate if an error is returned. Many implementations define some of the socket option names even though they do not support the option. Unsupported options should elicit an error of ENOPROTOOPT .

Print option's default value

88 “89 If getsockopt returns success, we call our function to convert the option value to a string and print the string.

In Figure 7.3, we showed four function prototypes, one for each type of option value that is returned. Figure 7.5 shows one of these four functions, sock_str_flag , which prints the value of a flag option. The other three functions are similar.

Figure 7.5 sock_str_flag function: convert flag option to a string.

sockopt/checkopts.c

 95 static char strres[128]; 96 static char * 97 sock_str_flag(union val *ptr, int len) 98 { 99 if (len != sizeof(int)) 100 snprintf(strres, sizeof(strres), "size (%d) not sizeof(int)", len); 101 else 102 snprintf (strres, sizeof(strres), 103 "%s", (ptr->i_val == 0) ? "off" : "on"); 104 return(strres); 105 } 

99 “104 Recall that the final argument to getsockopt is a value-result argument. The first check we make is that the size of the value returned by getsockopt is the expected size. The string returned is off or on , depending on whether the value of the flag option is zero or nonzero, respectively.

Running this program under FreeBSD 4.8 with KAME SCTP patches gives the following output:

 
 freebsd %  checkopts  SO_BROADCAST: default = off SO_DEBUG: default = off SO_DONTROUTE: default = off SO_ERROR: default = 0 SO_KEEPALIVE: default = off SO_LINGER: default = l_onoff = 0, l_linger = 0 SO_OOBINLINE: default = off SO_RCVBUF: default = 57344 SO_SNDBUF: default = 32768 SO_RCVLOWAT: default = 1 SO_SNDLOWAT: default = 2048 SO_RCVTIMEO: default = 0 sec, 0 usec SO_SNDTIMEO: default = 0 sec, 0 usec SO_REUSEADDR: default = off SO_REUSEPORT: default = off SO_TYPE: default = 1 SO_USELOOPBACK: default = off IP_TOS: default = 0 IP_TTL: default = 64 IPV6_DONTFRAG: default = off IPV6_UNICAST_HOPS: default = -1 IPV6_V6ONLY: default = off TCP_MAXSEG: default = 512 TCP_NODELAY: default = off SCTP_AUTOCLOSE: default = 0 SCTP_MAXBURST: default = 4 SCTP_MAXSEG: default = 1408 SCTP_NODELAY: default = off 

The value of 1 returned for the SO_TYPE option corresponds to SOCK_STREAM for this implementation.



UNIX Network Programming Volume 1, Third Edition
Unix Network Programming, Volume 1: The Sockets Networking API (3rd Edition)
ISBN: 0131411551
EAN: 2147483647
Year: 2003
Pages: 441

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net