Linux Socket Programming by Example - Warren Gay

< BACKCONTINUE >
159231153036212041242100244042145096184016146223183074028121223009001095120030133080039095053

Manipulating IP Numbers

To ease the programming burden of turning IP numbers in string form into usable socket addresses, a number of conversion functions have been provided. These and other useful functions will be presented in the following sections.

Using the inet_addr(3) Function

The first function that you will learn about is an older function, which should probably no longer be used in new code. However, you will find it in a lot of existing network code, and so you should become familiar with it and know its limitations.

The synopsis for inet_addr(3) is as follows:

						
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

unsigned long inet_addr(const char *string);

					

This function accepts an input C string argument string and parses the dotted-quad notation into a 32-bit Internet address value. The 32-bit value returned is in network byte order.

If the input argument string does not represent a valid dotted-quad address, the value INADDR_NONE is returned. Any other returned value represents the converted value.

NOTE

The 32-bit value returned by inet_addr(3) is in network byte order. Do not use htonl(3) on the returned value, because it is already in network byte order.


CAUTION

The inet_addr(3) does not establish a reason code in errno when INADDR_NONE is returned. So, do not test errno or report it when an error indication is returned by this function.


The program shown in Listing 3.3 is an example of how you would use this function. To compile and run the program, perform the following:

						
$ make inetaddr
gcc -c  -D_GNU_SOURCE -Wall inetaddr.c
gcc inetaddr.o -o inetaddr
$ ./inetaddr

					

The program in Listing 3.3, when it is run, converts a C string constant containing an IP number into a network sequenced 32-bit IP address. This value is then placed into an AF_INET socket address and bound to the socket.

Example 3.3. inetaddr.cóExample Program Using inet_addr(3)
 <$nopage>
001 1:   /* inetaddr.c:
002 2:    *
003 3:    * Example using inet_addr(3):
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 <netinet/in.h>
013 13:  #include <arpa/inet.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:      fputs(on_what,stderr);
022 22:      fputc('\n',stderr);
023 23:      exit(1);
024 24:  }
025 25:
026 26:  int
027 27:  main(int argc,char **argv) {
028 28:      int z;
029 29:      struct sockaddr_in adr_inet;/* AF_INET */
030 30:      int len_inet;                /* length  */
031 31:      int sck_inet;                 /* Socket */
032 32:
033 33:      /* Create a Socket */
034 34:      sck_inet = socket(AF_INET,SOCK_STREAM,0);
035 35:
036 36:      if ( sck_inet == -1 )
037 37:          bail("socket()");
038 38:
039 39:      /* Establish address */
040 40:      memset(&adr_inet,0,sizeof adr_inet);
041 41:
042 42:      adr_inet.sin_family = AF_INET;
043 43:      adr_inet.sin_port = htons(9000);
044 44:
045 45:      adr_inet.sin_addr.s_addr =
046 46:          inet_addr("127.0.0.95");
047 47:
048 48:      if ( adr_inet.sin_addr.s_addr == INADDR_NONE )
049 49:          bail("bad address.");
050 50:
051 51:      len_inet = sizeof adr_inet;
052 52:
053 53:      /* Bind it to the socket */
054 54:      z = bind(sck_inet,
055 55:          (struct sockaddr *)&adr_inet,
056 56:          len_inet);
057 57:
058 58:      if ( z == -1 )
059 59:          bail("bind()");
060 60:
061 61:      /* Display our socket address */
062 62:      system("netstat -pa --tcp 2>/dev/null"
063 63:          "| grep inetaddr");
064 64:
065 65:      return 0;
066 66:  } <$nopage>
067  <$nopage>

NOTE

If netstat(1) command on your system does not support the options used in lines 62 and 63 of Listing 3.3, substitute the following call if you have lsof installed:

							
system("lsof -i tcp | grep inetaddr");

						


The general program structure is very similar to the ones used in the previous chapter. However, the steps used to set up the socket address are a bit different. They are

  1. The socket address structure is zeroed out in line 40. This is an optional step, but many find that this helps debugging should it become necessary.

  2. The address family is established as AF_INET in line 42.

  3. The port number has been established as port 9000 in this example (line 43).

  4. The function inet_addr(3) is called in line 46 to convert the string constant "127.0.0.95" into a network 32-bit address. This value is stored into the socket address member adr_inet.sin_addr.s_addr.

  5. The value returned from the conversion in step 4 is tested to see whether it matches the value INADDR_NONE in line 48. If it does, this indicates that the value provided in the C string was not a good Internet IP number (the program bails out in line 49 if this happens).

  6. Finally, the length of the socket address is established in line 51 as before.

The above procedure has established the socket address in the variable adr_inet. This is later passed to bind(2) in line 54, which has not been covered yet. The bind(3) call just applies the address to the socket (the full discussion will otherwise be deferred for now).

The important thing that you accomplish with the use of the inet_addr(3) function is that you are spared from performing all parsing and testing of the input IP number.

TIP

Avoid using inet_addr(3) in new programs. Use the function inet_aton(3) instead.

The inet_addr(3) function has the limitation that it returns the value INADDR_NONE if the input argument is an invalid IP number. The limitation is that it also returns the value INADDR_NONE if you pass it the valid IP address of 255.255.255.255.

This creates a problem for programs like the ping(8) command where this is a valid broadcast address to use.


Running the program yields the following output:

						
$ ./inetaddr
tcp 0 0 127.0.0.95:9000  *:*  CLOSE  992/inetaddr
$

					

The program invokes netstat(1) using grep to look for the program name inetaddr. Consequently, you see one output line showing the address established for the socket as 127.0.0.95:9000. You'll remember that the program arbitrarily chose the port number 9000 for this experiment.

The inet_aton(3) Function

The inet_aton(3) is an improved way to convert a string IP number into a 32-bit networked sequenced IP number. The synopsis of the function is given as follows:

						
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

int inet_aton(const char *string, struct in_addr *addr);

					

The inet_aton(3) function accepts two arguments. They are

  1. The input argument string, which contains the ASCII representation of the dotted-quad IP number.

  2. The output argument addr is the structure that will be updated with the new IP address.

The return value of the function is nonzero (true) if the conversion succeeds. The value zero (false) is returned if the input address is incorrect. There is no error code established in errno, so its value should be ignored.

What is a little bit confusing about this function is the pointer required for argument two of this function call. If you define an AF_INET socket address as

						
struct sockaddr_in adr_inet; /* AF_INET */

					

the pointer that should be supplied as argument two of the inet_aton(3) function is the following:

						
&adr_inet.sin_addr

					

? Review Listing 2.7 in Chapter 2, "Domains and Address Families," if this does not seem clear to you. It will make more sense when you review the definition of the sockaddr_in structure.

Listing 3.4 shows a program that calls upon inet_aton(3) instead of the older inet_addr(3) function that you learned about in the previous section. This program operates the same way, except that it is compiled and executed as follows:

						
$ make inetaton
gcc -c  -D_GNU_SOURCE -Wall inetaton.c
gcc inetaton.o -o inetaton
$ ./inetaton

					

Now, spend a few moments examining Listing 3.4. You'll find that the new function is invoked in lines 45 to 47.

Example 3.4. inetaton.cóUsing inet_aton(3)
 <$nopage>
001 1:   /* inetaton.c:
002 2:    *
003 3:    * Example using inet_aton(3) :
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 <netinet/in.h>
013 13:  #include <arpa/inet.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:      fputs(on_what,stderr);
022 22:      fputc('\n',stderr);
023 23:      exit(1);
024 24:  }
025 25:
026 26:  int
027 27:  main(int argc,char **argv) {
028 28:      int z;
029 29:      struct sockaddr_in adr_inet;/* AF_INET */
030 30:      int len_inet;                /* length  */
031 31:      int sck_inet;                 /* Socket */
032 32:
033 33:      /* Create a Socket */
034 34:      sck_inet = socket(AF_INET,SOCK_STREAM,0);
035 35:
036 36:      if ( sck_inet == -1 )
037 37:          bail("socket()");
038 38:
039 39:      /* Establish address */
040 40:      memset(&adr_inet,0,sizeof adr_inet);
041 41:
042 42:      adr_inet.sin_family = AF_INET;
043 43:      adr_inet.sin_port = htons(9000);
044 44:
045 45:      if ( !inet_aton("127.0.0.23",
046 46:                &adr_inet.sin_addr) )
047 47:          bail("bad address.");
048 48:
049 49:      len_inet = sizeof adr_inet;
050 50:
051 51:      /* Bind it to the socket */
052 52:      z = bind(sck_inet,
053 53:          (struct sockaddr *)&adr_inet,
054 54:          len_inet);
055 55:
056 56:      if ( z == -1 )
057 57:          bail("bind()");
058 58:
059 59:      /* Display our socket address */
060 60:      system("netstat -pa --tcp 2>/dev/null"
061 61:          "| grep inetaton");
062 62:
063 63:      return 0;
064 64:  }
065  <$nopage>

Running this program yields the following results:

						
$ ./inetaton
tcp 0 0 127.0.0.23:9000  *:*  CLOSE  1007/inetaton
$

					

NOTE

If netstat(1) command on your system does not support the options used in lines 60 and 61 of Listing 3.4, substitute the following call if you have lsof installed:

							
system("lsof -i tcp | grep inetaton");

						


While the bulk of the program was the same as the previous one in Listing 3.3, the following steps are of particular importance:

  1. The new function inet_aton(3) is invoked from within the if statement in line 45.

  2. Note the second argument in line 46, given as the value &adr_inet.sin_addr. This is the required pointer for argument two.

  3. If the return value of the function in line 45 is zero, this indicates the conversion failed, and line 47 is executed.

The program in Listing 3.4 shows you how easily the newer function inet_aton(3) can be put to work in place of the older function inet_addr(3). There are perhaps three things that you need to remember about this function:

  • The pointer in argument two always refers to the sockaddr_in member sin_addr (&adr_inet.sin_addr in the example program).

  • The return value indicates a Boolean success value. A return value of true (nonzero) means that the call succeeded, whereas false (zero) means that it failed.

  • Do not consult the value in errno. No meaningful code is established by inet_aton(3) for errno.

In the next section, you'll see how you can take a socket IP address and convert it back to a string for reporting purposes.

Using the inet_ntoa(3) Function

There are times when a socket address represents the address of a user that has connected to your server, or represents the sender of a UDP packet. The job of converting a network sequenced 32-bit value into dotted-quad notation is inconvenient. Hence, the inet_ntoa(3) function has been provided. The synopsis of the function is as follows:

						
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

char *inet_ntoa(struct in_addr addr);

					

The function requires only one input argument addr. Note that the struct in_addr is an internal part of the Internet socket address. The address is converted into a static buffer, which is internal to the function. This character array pointer is returned as the return value. The results will be valid only until the next call to this function.

? Review the sockaddr_in structure in Figure 2.3 of Chapter 2, "Domains and Address Families," This will help you visualize the physical address structure that you are working with.

If a socket address addr exists in your program as a sockaddr_in structure, then the following code shows how to use inet_ntoa(3) to perform the conversion. The IP number is converted to a string and reported, using the printf(3) function:

						
struct sockaddr_in addr;   /* Socket Address */

printf("IP ADDR: %s\n",
    inet_ntoa(addr.sin_addr));

					

A complete example program is provided in Listing 3.5. To compile and run this program, the following steps are required:

						
$ make inetntoa
gcc -c  -D_GNU_SOURCE -Wall inetntoa.c
gcc inetntoa.o -o inetntoa
$ ./inetntoa

					

The program in Listing 3.5 uses the same steps to set up the address as did the previous example program. The function inet_ntoa(3) is called upon to allow the IP number to be displayed.

Example 3.5. inetntoa.cóDemonstration of inet_ntoa(3) Function
 <$nopage>
001 1:   /* inetntoa.c:
002 2:    *
003 3:    * Example using inet_ntoa(3):
004 4:    */
005 5:   #include <stdio.h>
006 6:   #include <unistd.h>
007 7:   #include <stdlib.h>
008 8:   #include <sys/types.h>
009 9:   #include <sys/socket.h>
010 10:  #include <netinet/in.h>
011 11:  #include <arpa/inet.h>
012 12:
013 13:  int
014 14:  main(int argc,char **argv) {
015 15:      struct sockaddr_in adr_inet;/* AF_INET */
016 16:      int len_inet;               /* length  */
017 17:
018 18:      /*
019 19:       * Establish address (pretend we got
020 20:       * this address from a connecting
021 21:       * client):
022 22:       */
023 23:      memset(&adr_inet,0,sizeof adr_inet);
024 24:
025 25:      adr_inet.sin_family = AF_INET;
026 26:      adr_inet.sin_port = htons(9000);
027 27:
028 28:      if ( !inet_aton("127.0.0.23",
029 29:                &adr_inet.sin_addr) )
030 30:          puts("bad address.");
031 31:
032 32:      len_inet = sizeof adr_inet;
033 33:
034 34:      /*
035 35:       * Demonstrate use of inet_ntoa(3):
036 36:       */
037 37:      printf("The IP Address is %s\n",
038 38:          inet_ntoa(adr_inet.sin_addr));
039 39:
040 40:      return 0;
041 41:  }
042  <$nopage>

Now, review the steps that were taken in the program:

  1. The structure adr_inet is declared as a sockaddr_in type in line 15. This is the form of the address that you'll work with most of the time.

  2. Lines 23 to 32 set up the address, just as before. In this example, the socket(2) and bind(2) calls were omitted because they don't help in this illustration.

  3. Line 37 shows a call to printf(3). Here, the statement calls upon inet_ntoa(3) in line 38 to convert the IP address in adr_inet to string form so that it can be printed.

NOTE

The results returned from inet_ntoa(3) are valid only until the next call to this function.


CAUTION

Due to the limitation given in the previous note, if you use this function in threaded code, you must make certain that only one thread at a time calls this function. Failure to heed this advice will result in returned results being overwritten by other threads.


The program's output is shown as follows:

						
$ ./inetntoa
The IP Address is 127.0.0.23
$

					

You know, because of the initialization in line 28, that this is the correct result. Line 38 converts this value back into a string.

Using inet_network(3)

There might be occasions in which it is more convenient to have the dotted-quad IP number converted into a 32-bit host-ordered value. This is more convenient when you are applying mask values to extract host or network bits from the addresses.

The function synopsis for inet_network(3) is as follows:

						
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

unsigned long inet_network(const char *addr);

					

This function takes one input string containing a dotted quad address in argument addr. The return value is the 32-bit value of the IP address, but in host-order format. However, if the input value is malformed, the returned result will be 0xFFFFFFFF (all 1 bits).

Having the returned value in host-endian order means that you can safely assume constants for mask values and bit positions. If the returned value were in network-endian order, the constants and code would then be different for different CPU platforms.

An example of how inet_network(3) might be used is shown next. The following shows how to extract the network address from a class C address:

						
unsigned long net_addr;

net_addr =
    inet_network("192.168.9.1") & 0xFFFFFF00;

					

The value assigned to net_addr would be the value 0xC0A80900 (or 192.168.9.0 in dotted-quad notation). The logical and operation masked out the low-order eight bits to arrive at the network ID without the host ID.

The example shown in Listing 3.6 illustrates how the inet_network(3) function can be used. The program also calls upon the htonl(3) function to display how the value looks in network-endian order.

Example 3.6. network.cóDemonstration of the inet_network(3) Function
1:   /* network.c:
2:    *
3:    * Example using inet_network(3):
4:    */
5:   #include <stdio.h>
6:   #include <unistd.h>
7:   #include <stdlib.h>
8:   #include <sys/types.h>
9:   #include <sys/socket.h>
10:  #include <netinet/in.h>
11:  #include <arpa/inet.h>
12:
13:  int
14:  main(int argc,char **argv) {
15:      int x;
16:      const char *addr[] = {
17:          "44.135.86.12",
18:          "127.0.0.1",
19:          "172.16.23.95",
20:          "192.168.9.1"
21:      };
22:      unsigned long net_addr;
23:
24:      for ( x=0; x<4; ++x ) {
25:          net_addr = inet_network(addr[x]);
26:          printf("%14s = 0x%08lX net 0x%08lX\n",
27:              addr[x],net_addr,
28:              (unsigned long)htonl(net_addr));
29:      }
30:
31:      return 0;
32:  }

This program is compiled and run as follows:

						
$ make network
gcc -c  -D_GNU_SOURCE -Wall network.c
gcc network.o -o network
$

					

The steps used in the program shown in Listing 3.6 are as follows:

  1. Four arbitrarily picked IP numbers are declared in lines 17 to 20 to initialize the array addr[].

  2. Lines 24 to 29 loop through each of the four strings in the addr[] array, starting with the first.

  3. The inet_network(3) function is called in line 25 to convert the string into a host-endian ordered 32-bit value representing the IP number given.

  4. The printf(3) function is called in line 26 to illustrate the output values. The first is the original string that was given to inet_network(3) in line 25. The second value printed is the value returned by inet_network(3), which is in host-endian form. The last value displayed on the line is the network-endian ordered value. For Intel CPU platforms, the last two columns will display differently.

The program is run as follows:

						
$ ./network
  44.135.86.12 = 0x2C87560C net 0x0C56872C
     127.0.0.1 = 0x7F000001 net 0x0100007F
  172.16.23.95 = 0xAC10175F net 0x5F1710AC
   192.168.9.1 = 0xC0A80901 net 0x0109A8C0
$

					

This program was run on an Intel CPU running Linux. Consequently, because an Intel CPU is little-endian by design, its host-ordered value (second column) and the networked-ordered value (last column) appear different. If you run this same program on a big-endian machine, the last two columns will be identical.

Using the inet_lnaof(3) Function

The inet_lnaof(3) function converts the IP number contained in a socket address, which is in network byte order, to a host ID number with the network ID removed. The return value is in host-endian order.

This function saves you from having to determine the class of the IP number and then extracting the host ID portion. The function synopsis for inet_lnaof(3) is given as follows:

						
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

unsigned long inet_lnaof(struct in_addr addr);

					

The input argument addr must be the struct in_addr member of the socket address that you will normally be working with. This value will be in network byte sequence, which is what the function expects. An example of how to invoke the function using a sockaddr_in address is given as follows:

						
struct sockaddr_in addr;   /* Socket Address */
unsigned long host_id;     /* Host ID number */

host_id = inet_lnaof(addr.sin_addr);

					

Table 3.5 shows some example values that can be supplied to the input of inet_lnaof(3) and the values that result. To make the reasons for the results clearer, the class of each example address is included in the table.

Table†3.5. Example Values Returned from inet_lnaof(3) (the Hexadecimal Values Are Host-Endian Ordered)
IP Number Class Hexadecimal Dotted-Quad
44.135.86.12 A 0087560C 0.135.86.12
127.0.0.1 A 00000001 0.0.0.1
172.16.23.95 B 0000175F 0.0.23.95
192.168.9.1 C 00000001 0.0.0.1

You should notice in the table's class A examples only the first byte is zeroed in the returned result (review Figure 3.1 to visualize the class boundaries again if you need to). In the class B example, the upper 16 bits are zeroed in the returned result. Finally, the class C example in Table 3.5 zeroes out the upper 3 bytes of the address, leaving the host ID behind in the last byte.

NOTE

The input is in network-endian sequence. The returned value is in host-endian sequence.


Using the inet_netof(3) Function

The inet_netof(3) function is the companion to the inet_lnaof(3) function. The inet_netof(3) function returns the network ID instead of the host ID value. In all other respects, these functions are the same. The following lists the function synopsis:

						
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

unsigned long inet_netof(struct in_addr addr);

					

Again, the input is the struct in_addr member of the socket address sockaddr_in structure that you'll normally be working with. An example of its use is given as follows:

						
struct sockaddr_in addr;   /* Socket Address */
unsigned long net_id;      /* Network ID number */

net_id = inet_netof(addr.sin_addr);

					

Table 3.6 shows the same example IP numbers used in Table 3.5. Table 3.6 shows the values returned for the function inet_netof(3) function, however.

Table†3.6. Example Values Returned from inet_netof(3) (the Hexadecimal Values Are Host-Endian Ordered)
IP Number Class Hexadecimal Dotted-Quad
44.135.86.12 A 0000002C 0.0.0.44
127.0.0.1 A 0000007F 0.0.0.127
172.16.23.95 B 0000AC10 0.0.172.16
192.168.9.1 C 00C0A809 0.192.168.9

You might find the values in Table 3.6 to be a bit of a surprise. These return values are the network bits shifted right, in order to eliminate the host ID bits. What you are left with is the right-justified network ID number.

NOTE

The return values from inet_netof(3) are right-justified. The host ID bits are shifted out.


Using the inet_makeaddr(3) Function

With the functions inet_lnaof(3) and inet_netof(3), you have the ability to extract host and network ID values. To re-create a consolidated IP address with the network and host ID values combined, you need to use the inet_makeaddr(3) function. Its function synopsis is as follows:

						
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

struct in_addr inet_makeaddr(int net,int host);

					

The arguments to the inet_makeaddr(3) function are described as follows:

  1. The net argument is the network ID, right-justified and in host-endian order. This same value is returned from the function inet_netof(3).

  2. The host argument is the host ID, which is in host-endian order. This same value is returned from the function inet_lnaof(3).

The value returned in the struct in_addr member of the sockaddr_in socket address. This value is in network-endian sequence, which is correct for the socket address.

A program has been provided in Listing 3.7 that uses the three functions inet_lnaof(3), inet_netof(3), and inet_makeaddr(3). The IP address is split apart from a sockaddr_in structure into its network and host ID parts. Then, the socket address is zeroed out and reconstructed from just the network and host ID parts.

Example 3.7. makeaddr.cóDemonstration of inet_netof(3), inet_lnaof(3), and inet_makeaddr(3)
 <$nopage>
001 1:   /* makeaddr.c:
002 2:    *
003 3:    * Demonstrate inet_lnaof, inet_netof
004 4:    * and inet_makeaddr(3) functions;
005 5:    */
006 6:   #include <stdio.h>
007 7:   #include <unistd.h>
008 8:   #include <stdlib.h>
009 9:   #include <sys/types.h>
010 10:  #include <sys/socket.h>
011 11:  #include <netinet/in.h>
012 12:  #include <arpa/inet.h>
013 13:
014 14:  int
015 15:  main(int argc,char **argv) {
016 16:      int x;
017 17:      struct sockaddr_in adr_inet;/* AF_INET */
018 18:      const char *addr[] = {
019 19:          "44.135.86.12",
020 20:          "127.0.0.1",
021 21:          "172.16.23.95",
022 22:          "192.168.9.1"
023 23:      };
024 24:      unsigned long net, hst;
025 25:
026 26:      for ( x=0; x<4; ++x ) {
027 27:          /*
028 28:           * Create a socket address:
029 29:           */
030 30:          memset(&adr_inet,0,sizeof adr_inet);
031 31:          adr_inet.sin_family = AF_INET;
032 32:          adr_inet.sin_port = htons(9000);
033 33:          if ( !inet_aton(addr[x],
034 34:                    &adr_inet.sin_addr) )
035 35:              puts("bad address.");
036 36:
037 37:          /*
038 38:           * Split address into Host & Net ID
039 39:           */
040 40:          hst = inet_lnaof(adr_inet.sin_addr);
041 41:          net = inet_netof(adr_inet.sin_addr);
042 42:
043 43:          printf("%14s : net=0x%08lX host=0x%08lX\n",
044 44:              inet_ntoa(adr_inet.sin_addr),net,hst);
045 45:
046 46:          /*
047 47:           * Zero the address to prove later that
048 48:           * we can reconstruct this value:
049 49:           */
050 50:          memset(&adr_inet,0,sizeof adr_inet);
051 51:          adr_inet.sin_family = AF_INET;
052 52:          adr_inet.sin_port = htons(9000);
053 53:
054 54:          adr_inet.sin_addr =
055 55:              inet_makeaddr(net,hst);
056 56:
057 57:          /*
058 58:           * Now display the reconstructed
059 59:           * address:
060 60:           */
061 61:          printf("%14s : %s\n\n",
062 62:              "inet_makeaddr",
063 63:              inet_ntoa(adr_inet.sin_addr));
064 64:      }
065 65:
066 66:      return 0;
067 67:  }
068  <$nopage>

To compile the program in Listing 3.7, perform the following:

						
$ make makeaddr
gcc -c  -D_GNU_SOURCE -Wall makeaddr.c
gcc makeaddr.o -o makeaddr
$

					

The procedure used in Listing 3.7 is as follows:

  1. The socket address is declared in line 17 as a sockaddr_in structure. This is the form of the socket address that you'll normally work with.

  2. Four example addresses are declared in lines 18 to 23.

  3. The loop starts in line 26, and iterates through each of the four example IP numbers declared in step 2.

  4. Lines 30 to 35 set up a sockaddr_in socket address. Port 9000 was just an arbitrary port number used as an example.

  5. The host ID is extracted from the socket address adr_inet in line 40.

  6. The network ID is extracted from the socket address adr_inet in line 41.

  7. The example IP number, network ID, and host ID numbers are reported in lines 43 and 44.

  8. The entire socket address adr_inet is zeroed out in line 50. This was done to eliminate any doubt that the socket address is re-created later.

  9. The address family and example port number are re-established in lines 51 and 52.

  10. The IP number is reconstructed by calling inet_makeaddr(3) in lines 54 and 55. The input values are the extracted values net and hst from steps 5 and 6.

  11. The reconstructed address is reported in lines 61 to 63.

Running the program yields the following results:

						
$ ./makeaddr
  44.135.86.12 : net=0x0000002C host=0x0087560C
 inet_makeaddr : 44.135.86.12

     127.0.0.1 : net=0x0000007F host=0x00000001
 inet_makeaddr : 127.0.0.1

  172.16.23.95 : net=0x0000AC10 host=0x0000175F
 inet_makeaddr : 172.16.23.95

   192.168.9.1 : net=0x00C0A809 host=0x00000001
 inet_makeaddr : 192.168.9.1

$

					

In each case, you can see for yourself that the program did indeed re-create the final IP numbers from the extracted host and network ID numbers.

What's Next

The beginning of this chapter might have been review to some, but perhaps new to you. However, you can see now that this topic was important to cover, because the makeup of IP numbers and their classification plays quite a large role when working with IP addresses. You also learned about private IP number ranges, which might help you set up your own network.

One example program was described early in this chapter, which classified IP numbers. From this example, you learned how this can be done. However, toward the end of this chapter, you also learned that you do not always have to do this yourself. The functions inet_lnaof(3) and inet_netof(3) were able to do this for you and extract the parts that you were interested in.

The remainder of this chapter dealt with conversion from strings to addresses, and addresses back to strings. These are important functions for the network application designer to know. These functions ease your workload and provide reliability and consistency. This is accomplished by having these operations done in the same manner in each program that they are used in.

The next chapter will introduce you to socket types and protocols. With this knowledge, you will learn how to create sockets to match your networking needs using the socket(2) function call.

< BACKCONTINUE >

Index terms contained in this section

examples
      inet addr (3) function 2nd 3rd
      inet aton (3) 2nd 3rd
      inet lnaof (3) function 2nd
      inet lnaof (3) function values
      inet makeaddr (3) function 2nd
      inet netof (3) function 2nd
      inet netof (3) function values
      inet network (3) function 2nd
      inet ntoa (3) function 2nd
functions
      inet addr (3) 2nd
            example 2nd 3rd
      inet aton (3) 2nd 3rd 4th 5th
      inet lnaof (3)
      inet makeaddr (3)
      inet netof (3) 2nd
      inet network (3) 2nd 3rd
      inet ntoa (3) 2nd 3rd 4th
inet addr (3) function
      example program 2nd 3rd
inet addr(3) function 2nd
inet aton (3) function 2nd
      example 2nd 3rd
inet lnaof (3) function
      example 2nd
      values
inet makeaddr (3) function
      example 2nd
inet neof (3) functions
      example 2nd
inet netof (3) function 2nd
      value examples
inet network (3) function
      example 2nd
inet ntoa (3) function 2nd
      example 2nd
IP addresses
      manipulating 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th
manipulating IP numbers 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th
values
      inet lnaof (3) function
      inet netof (3) function examples