Linux Socket Programming by Example - Warren Gay

< BACKCONTINUE >
159231153036212041242100244042145096184016146223183074028121223009001092206132159183236237144

Consulting the /etc/protocols File

Earlier, in Table 7.1, there was mention made that the protocol used there must appear in the protocols(5) table. The text file /etc/protocols acts as a mini-database of various defined Internet protocol values. There is a set of functions, which perform in a very similar manner to the service entry functions that were just covered. These act as convenience functions, should you need them. These functions are so similar, in fact, that they do not need to be covered in detail. The function synopsis of getprotoent(3) is as follows:

					
#include <netdb.h>

struct protoent *getprotoent(void);

				

The getprotoent(3) function returns one /etc/protocols entry with each call. A NULL pointer is returned when end-of-file or an error has been encountered. Listing 7.4 shows the protoent structure that is returned by the function call.

CAUTION

The pointer returned by getprotoent(3) is only valid until the next call to the same function.


Example 7.4. The struct protoent Structure
struct protoent {
    char   *p_name; /* official protocol name */
    char   **p_aliases;          /* alias list */
    int    p_proto;         /* protocol number */
}

The structure members are more fully described as follows:

  • The structure member p_name contains a pointer to a C string that names the protocol (for example "tcp").

  • The member p_aliases is a pointer to an array of C string pointers, of which the last entry is a NULL pointer. If pp points to this structure, then pp->p_aliases[0] contains the first C string (or is NULL when there are no aliases). An example of an alias might be "TCP" (the uppercase name of the protocol is often specified as an alias).

  • The member p_proto contains the protocol number. For example, the protocol number found in /etc/protocols for entry "tcp" should agree with the C macro constant IPPROTO_TCP. If you check with /usr/include/netinet/in.h and with the value in /etc/protocols, you will indeed see that they both have the value 6.

CAUTION

The getprotoent(3) function suffers from the same flaw as the getservent(3) function under Linux. Even when the value of errno is zeroed prior to calling getprotoent(3), when end-of-file is reached and indicated by a NULL return pointer, the errno value for Red Hat Linux 6.0 is ENOENT.

Under other UNIX operating systems, such as HP-UX 10.2 and Sun Solaris 5.5.1, the errno value is left at zero when end-of-file is returned. This leads the author to speculate that this behavior is a bug, which might be corrected in a later release of Linux.


The getprotoent(3) function returns a NULL pointer when end-of-file is reached or when an error has been encountered.

Listing 7.5 shows a demonstration program that iterates through all of the /etc/protocols database entries.

Example 7.5. protoent.cóThe getprotoent(3) Demo Program
 <$nopage>
001 1:   /* protoent.c:
002 2:    * 
003 3:    * Example getprotoent(3) program:
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 <netdb.h>
011 11:  
012 12:  int
013 13:  main(int argc,char **argv) {
014 14:      int x;
015 15:      struct protoent *pp;
016 16:  
017 17:      for (;;) {
018 18:          errno = 0;
019 19:          if ( !(pp = getprotoent()) )
020 20:              break;
021 21:  
022 22:           printf("%s:\n"
023 23:               "\tProtocol: %d\n"
024 24:               "\tAliases:  ",
025 25:               pp->p_name,
026 26:               pp->p_proto);
027 27:           for ( x=0; pp->p_aliases[x] != NULL; ++x )
028 28:               printf("%s ",pp->p_aliases[x]);
029 29:           putchar('\n');
030 30:      }
031 31:  
032 32:      if ( errno != 0 
033 33:      &&   errno != ENOENT ) /* For RH-6.0 */
034 34:          fprintf(stderr,
035 35:              "%s: getprotoent(3) %d\n",
036 36:              strerror(errno),errno);
037 37:  
038 38:      return 0;
039 39:  }
040  <$nopage>

The program code in Listing 7.5 is so similar to the program in Listing 7.2 that only the basic steps need to be repeated here. They are

  1. Call getprotoent(3) to obtain an entry from the /etc/protocols file.

  2. Print the protocol name and the protocol number.

  3. In an internal loop, print all protocol alias names, if any.

  4. Repeat step 1 until there are no more protocol entries.

Listing 7.6 shows how to compile and run the demonstration program.

Example 7.6. Compiling and Running the protoent.c Program
$ make protoent
gcc -c  -D_GNU_SOURCE -Wall protoent.c
gcc protoent.o -o protoent
$ ./protoent | head
ip:
        Protocol: 0
        Aliases:  IP 
icmp:
        Protocol: 1
        Aliases:  ICMP 
igmp:
        Protocol: 2
        Aliases:  IGMP 
ggp: 
$

The example command session in Listing 7.6 had its output piped to the head command to keep the listing short. Notice the protocol name of the first entry shown was "ip" and its one and only alias was the uppercase name "IP".

Using the setprotoent(3) Function

The file that is opened implicitly for getprotoent(3) can be rewound by calling the setprotoent(3) function. The function synopsis for it is as follows:

						
#include <netdb.h>

void setprotoent(int stayopen);

					

This function accepts one argument, stayopen, which is interpreted as a Boolean value:

  • When stayopen is non-zero (TRUE), this indicates that the implicitly opened file is left opened and merely rewound to the start of the file.

  • When stayopen is zero (FALSE) this indicates that the implicitly opened file is closed and then re-opened, effectively rewinding the file.

Best performance is obtained by setting stayopen as TRUE.

Using the endprotoent(3) Function

When your program is finished consulting with the /etc/protocols file, it can request that the implicitly opened file be closed. This is especially important for server programs to do, because file descriptors are often scarce. The function prototype for endprotoent(3) is given as follows:

						
#include <netdb.h>

void endprotoent(void);

					

There are no arguments to this function, and there are no return value or errors to check.

Looking Up a Protocol by Name

Sometimes it is necessary for an application program or utility program, which can work with multiple protocols, to look up a protocol by name. While this can be done by using the previous functions, getprotobyname(3) saves the programmer some effort. The function prototype is as follows:

						
#include <netdb.h>

struct protoent *getprotobyname(const char *name);

					

The one input argument is a C string containing the protocol name ("udp", for example). The value returned is a pointer to the protoent structure, or is a NULL pointer, indicating that it could not be found.

CAUTION

The pointer returned by getprotobyname(3) is only valid until the next call to the same function.


Looking Up a Protocol by Number

When your application has the protocol number, and it needs to display it in human readable terms, the getprotobynumber(3) routine is used. The function prototype is as follows:

						
#include <netdb.h>

struct protoent *getprotobynumber(int proto);

					

This function accepts the protocol number as the input argument, and returns the pointer to a protoent structure if a match is found. Otherwise, the NULL pointer is returned to indicate that the protocol is not known by the mini-database. For example, if the input argument is 6 (or the C macro constant IPPROTO_TCP), then you should get a structure pointer returned that has the value "tcp" in the member p_name.

CAUTION

The pointer returned by getprotobynumber(3) is only valid until the next call to the same function.


This brings you to the end of the getservent(3) and the getprotoent(3) function families. Now that you know how to look up Internet-related services and protocols, it is time to write a connection-oriented client program using TCP/IP.

< BACKCONTINUE >

Index terms contained in this section

arguments
      setprotoent(3) function
compiling
      protoent. c program
consulting
      etc/protocols file 2nd 3rd
endprotoent(3) function
errors
      getprotoent(3) function
etc/protocols file 2nd 3rd
examples
      getprotoent(3) function 2nd
files
      etc/protocols 2nd 3rd
finding
     protocols
            by name
            by number 2nd
functions
      endprotoent(3)
      getprotobyname(3)
      getprotobynumber(3) 2nd
      getprotoent(3) 2nd
      setprotoent(3)
getprotobyname(3) function
getprotobynumber(3) function 2nd
getprotoent(3) function 2nd
      errors
      example protoent. c program 2nd
      running protoent. c program
locating
     protocols
            by name
            by number 2nd
looking up
     protocol
            by name
     protocols
            by number 2nd
programs
     protoent. c
            example 2nd
protocols
     finding
            by number 2nd
     looking up
            by name
protoent. c program
      compiling
      running
running
      protoent. c program
setprotoent(3) function
      arguments
struct protoent program structure