Linux Socket Programming by Example - Warren Gay

< BACKCONTINUE >
159231153036212041242100244042145096184016146223183074028121223008110134179037184086247159103

Getting Socket Options

Oftentimes, an application needs to determine what the current option settings are for a socket. This is especially true of a subroutine library function, which will have no prior knowledge of what was done with the socket, which was passed to it as an argument. The application might also need to know things such as the optimal buffer size to use, which is determined by the system defaults.

The function that permits you to inspect socket option values is the getsockopt(2) function. Its function synopsis is given as follows:

					
#include <sys/types.h>
#include <sys/socket.h>

int getsockopt(int s,
    int level,
    int optname,
    void *optval,
    socklen_t *optlen);

				

The five arguments are described as follows:

  1. The socket s from which to inspect the option.

  2. The protocol level at which the option is to be inspected.

  3. The option optname to inspect.

  4. The pointer optval pointing to the receiving buffer for the option value.

  5. The pointer optlen pointing to both the input buffer length, and the returned option length values.

The return value from this function returns zero when successful. When an error occurs, -1 is returned and the external variable errno contains the nature of the error.

The protocol level argument indicates where in the protocol stack you want to access an option. Usually, you will use one of these:

  • SOL_SOCKET to access socket level options

  • SOL_TCP to access TCP level options

The discussion in this chapter will center strictly on the use of SOL_SOCKET level options.

The optname argument is an integer value. The value used here will be determined first by the choice of the level argument value used. Within a specified protocol level, the optname argument will determine which option you want to access. Table 12.1 shows some of the level and option combinations that are possible.

Table†12.1. Protocol Level and Option Names
Protocol Level Option Name
SOL_SOCKET SO_REUSEADDR
SOL_SOCKET SO_KEEPALIVE
SOL_SOCKET SO_LINGER
SOL_SOCKET SO_BROADCAST
SOL_SOCKET SO_OOBINLINE
SOL_SOCKET SO_SNDBUF
SOL_SOCKET SO_RCVBUF
SOL_SOCKET SO_TYPE
SOL_SOCKET SO_ERROR
SOL_TCP SO_NODELAY

Most of the options listed in the table are socket level options, where the level was given as SOL_SOCKET. One TCP level socket option was included for comparison purposes, where its level is specified as SOL_TCP.

Many socket options are retrieved into an int data type. When looking at the manual pages, data type int can usually be assumed unless otherwise indicated. When a Boolean value is used, the int value indicates TRUE when the value is nonzero and indicates FALSE when it is zero.

Applying getsockopt(2)

In this section, you'll compile and run a program getsndrcv.c, which will fetch and report the sending and receiving buffer sizes for a socket. The example in Listing 12.1 illustrates the code.

Example 12.1. getsndrcv.cóGet and Report SO_SNDBUF and SO_RCVBUF Options
 <$nopage>
001 1:   /* getsndrcv.c:
002 2:    *
003 3:    * Get SO_SNDBUF & SO_RCVBUF Options:
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/socket.h>
012 12:  #include <assert.h> <$nopage>
013 					 <$nopage>
014 13:
015 14:  /*
016 15:   * This function reports the error and
017 16:   * exits back to the shell:
018 17:   */
019 18:  static void
020 19:  bail(const char *on_what) {
021 20:      if ( errno != 0 ) {
022 21:          fputs(strerror(errno),stderr);
023 22:          fputs(": ",stderr);
024 23:      }
025 24:      fputs(on_what,stderr);
026 25:      fputc('\n',stderr);
027 26:      exit(1);
028 27:  }
029 28:
030 29:  int
031 30:  main(int argc,char **argv) {
032 31:      int z;
033 32:      int s = -1;                /* Socket */
034 33:      int sndbuf=0;   /* Send buffer size */
035 34:      int rcvbuf=0;/* Receive buffer size */
036 35:      socklen_t optlen;  /* Option length */
037 36:
038 37:      /*
039 38:       * Create a TDP/IP socket to use:
040 39:       */
041 40:      s = socket(PF_INET,SOCK_STREAM,0);
042 41:      if ( s == -1 )
043 42:          bail("socket(2)");
044 43:
045 44:      /*
046 45:       * Get socket option SO_SNDBUF:
047 46:       */
048 47:      optlen = sizeof sndbuf;
049 48:      z = getsockopt(s,SOL_SOCKET,SO_SNDBUF,
050 49:          &sndbuf,&optlen);
051 50:      if ( z )
052 51:          bail("getsockopt(s,SOL_SOCKET,"
053 52:              "SO_SNDBUF)");
054 53:
055 54:      assert(optlen == sizeof sndbuf);
056 55:
057 56:      /*
058 57:       * Get socket option SO_SNDBUF:
059 58:       */
060 59:      optlen = sizeof rcvbuf;
061 60:      z = getsockopt(s,SOL_SOCKET,SO_RCVBUF,
062 61:          &rcvbuf,&optlen);
063 62:      if ( z )
064 63:          bail("getsockopt(s,SOL_SOCKET,"
065 64:              "SO_RCVBUF)");
066 65:
067 66:      assert(optlen == sizeof rcvbuf);
068 67:
069 68:      /*
070 69:       * Report the buffer sizes: <$nopage>
071 					 <$nopage>
072 					 <$nopage>
073 70:       */
074 71:      printf("Socket s : %d\n",s);
075 72:      printf(" Send buf: %d bytes\n",
076 73:          sndbuf);
077 74:      printf(" Recv buf: %d bytes\n",
078 75:          rcvbuf);
079 76:
080 77:      close(s);
081 78:      return 0;
082 79:  }
083  <$nopage>

The getsockopt(2) steps used were as follows:

  1. The options SO_SNDBUF and SO_RCVBUF are received into an int data type. Consequently, storage for these values was declared in lines 33 and 34.

  2. The getsockopt(2) function requires an option length argument that acts as both an input value and a return value. Storage for this was allocated in line 35 and named optlen. Note that the data type for this variable is socklen_t.

  3. A socket for testing purposes is created in line 40.

  4. The length of the receiving option buffer sndbuf is established in variable optlen (line 47).

  5. The option is fetched by calling getsockopt(2) in line 48. The socket level was SOL_SOCKET and the option name was specified as SO_SNDBUF. Note the pointer to sndbuf was given as the receiving buffer.

  6. The length of the result returned in sndbuf is placed into variable optlen by the function getsockopt(2). Line 54 uses the assert(3) macro to ensure that it matches the return length that was expected.

  7. Lines 59 to 66 repeat the process for the option SO_RCVBUF into variable rcvbuf.

  8. Lines 71 to 75 report the socket file descriptor, and the corresponding buffer sizes that were retrieved.

The following output shows a compile and execute session for this program on a Red Hat Linux 6.0 distribution, using a 2.2.10 kernel:

						
$ make getsndrcv
gcc -c  -D_GNU_SOURCE -Wall -Wreturn-type getsndrcv.c
gcc getsndrcv.o -o getsndrcv
$ ./getsndrcv
Socket s : 3
 Send buf: 65535 bytes
 Recv buf: 65535 bytes
$

					

The session shows that the socket was created on file descriptor 3, and that the sending and receiving buffer sizes were 65535 bytes in size.

< BACKCONTINUE >

Index terms contained in this section

arguments
      getsockopt(2) function 2nd
functions
     getsockopt(2)
            arguments 2nd
            code example 2nd 3rd 4th
            syntax
getsockopt(2) function
      arguments 2nd
      code example 2nd 3rd 4th
      syntax
listings
      getsockopt(2) code example 2nd
retrieving
      socket options 2nd 3rd 4th
     sockets
            options
sockets
     options
            retrieving 2nd 3rd 4th 5th
syntax
      getsockopt(2) function