Linux Socket Programming by Example - Warren Gay


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.


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.


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
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
        Protocol: 0
        Aliases:  IP 
        Protocol: 1
        Aliases:  ICMP 
        Protocol: 2
        Aliases:  IGMP 

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.


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.


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.


Index terms contained in this section

      setprotoent(3) function
      protoent. c program
      etc/protocols file 2nd 3rd
endprotoent(3) function
      getprotoent(3) function
etc/protocols file 2nd 3rd
      getprotoent(3) function 2nd
      etc/protocols 2nd 3rd
            by name
            by number 2nd
      getprotobynumber(3) 2nd
      getprotoent(3) 2nd
getprotobyname(3) function
getprotobynumber(3) function 2nd
getprotoent(3) function 2nd
      example protoent. c program 2nd
      running protoent. c program
            by name
            by number 2nd
looking up
            by name
            by number 2nd
     protoent. c
            example 2nd
            by number 2nd
     looking up
            by name
protoent. c program
      protoent. c program
setprotoent(3) function
struct protoent program structure