# The Network Kit: Network Names, Addresses, and Services

Declared in: be/kit/net/netdb.h

Library: libnet.so

## Overview

The functions described below let you look up the names, addresses, and other information about the computers and services that the local computer knows about, and let you retrieve information about the current user's account. Also defined here are functions that perform Internet Protocol (IP) address format conversion.

You use the functions defined here to find the information you need so you can form a connection to some other machine. Connecting to other machines is described in The Network Kit: Sockets .

### Terms and Tools

Throughout the following function descriptions, an IP address is the familiar four-byte, dot-separated numeric identifier. For example,

192.0.0.1

The bytes in a multi-byte address are always given in network byte order (big-endian). The current BeBox is also big-endian, so you don't have to convert IP address values--but for portability and forward-compatibility, you may want to. See the group of functions with the obsessively shortened names (`ntohs()`, `htohl()`, etc.) for more information on such transformations.

An IP name is the two-or-more-element "machine.domain.extension" case-insensitive text name. For example:

- be.com

- decca.be.com

The two most important functions described below, `gethostbyname()` and `gethostbyaddr()`, retrieve information about computers ("hosts") that can be reached through the network. Host information is typically (and primarily) gotten from the Domain Name Server (DNS), a service that's usually provided by a server computer that's responsible for tasks such as mail distribution and direct communication with the Internet Service Provider (ISP).

You can also provide host information by adding to your computer's /boot/beos/etc/hosts file. This is a text file that contains the IP addresses and names of the hosts that you want your computer to know about. Each entry in the file lists, in order on a single line, a host's IP address, IP name, and other names (aliases) by which it's also known. For example:

       # Example /boot/beos/etc/hosts entries
       192.0.0.1 phaedo.racine.com fido phydough
       204.123.5.12 playdo.mess.com plywood funfactory

The amount of whitespace separating the elements is arbitrary. The only killing point is that there mustn't be any leading whitespace before the IP address.

If you're connected to DNS, then you shouldn't need the hosts file. If you're not connected to a network at all, the only way to get information about other machines is through the hosts file, but it won't do you much good--you won't be able to use the information to connect to other machines. The archetypal situation in which the hosts file becomes useful is if your BeBox is connected to some other machine (we'll call it Brand X), and the Brand X machine is supposed to be connected to a DNS machine, but this latter connection is down (or the DNS machine isn't running). If you have an entry in your BeBox hosts file that identifies the Brand X machine, you'll still be able to look up the machine's address and connect to it, despite the absence of DNS.

## Functions

### gethostbyname(), gethostbyaddr(), herror()

          struct hostent *gethostbyname(const char *name)

          struct hostent *gethostbyaddr(const char *address, int length, int type)

          void herror(const char *string)

The `gethostbyname()` and `gethostbyaddr()` functions retrieve information about a particular host machine, stuff the information into a global "host entry" structure, and then return a pointer to that structure. To get this information, the functions talks to the Domain Name Server. If DNS doesn't respond or doesn't know the desired host, the functions then look for an entry in the file /boot/beos/system/etc/hosts. See Terms and Tools for more information on DNS and the hosts file.

`herror()` generates a human-readable message that describes the most recent `gethostby...()` error, and prints it to standard error.

|  | Because `gethostbyname()` and `gethostbyaddr()` use a global structure to return information, the functions are not thread safe.

#### The gethostbyname() Function

`gethostbyname()`'s name argument is a `NULL`-terminated, case-insensitive host name that must be no longer than `MAXHOSTNAMELEN` (64) characters (not counting the `NULL`). The name can be:

- An entire "machine.domain.extension" IP name--"mybox.me.com", for example.

- Just the machine name portion--"mybox" (DNS only). In this case, the domain and extension of the local machine are automatically appended. (If you're looking up an IP name in the hosts file, the domain and extension aren't appended for you.)

- A host name alias. Aliases are alternate names by which a host is known. Your DNS should provide a means for declaring aliases; you can also declare them in your hosts file.

#### The gethostbyaddr() Function

`gethostbyaddr()`'s address argument is a pointer to a complete IP address given in its natural format (but cast to a `char *`; note that the argument's type declaration doesn't mean that the function wants the address converted to a string). length is the length of address in bytes; type is a constant that gives the format of the address.

For IP format, the first argument is a four-byte integer, length is always 4, and type is `AF_INET` ("Address Format: InterNET"). The following gets the `hostent` for a hard-coded address:

       /* This is the hex equivalent of 192.0.0.1
       ulong addr = 0xc0000001;
       struct hostent *theHost;
       theHost = gethostbyaddr((const char *)&addr, 4, AF_INET);

If you have an address stored as a string, you can use the `inet_addr()` function to convert it to an integer:

       ulong addr = inet_addr("192.0.0.1");
       struct hostent *theHost;
       theHost = gethostbyaddr((const char *)&addr, 4, AF_INET);

#### The hostent Structure

If a `gethostby...()` function fails, it returns `NULL`; otherwise, it returns a pointer to a global `hostent` structure. The `hostent` structure (which isn't `typedef`'d) looks like this:

       struct hostent
          char *h_name;
          char **h_aliases;
          int h_addrtype;
          int h_length;
          char **h_addr_list;
       };

The fields are:

- `h_name` is the IP name of the host (or the "official" name given in the hosts file).

- `h_aliases` is a `NULL`-terminated array of other names by which the host is known. These names aren't necessarily in IP name format; typically, they're single-word names.

- `h_addrtype` identifies the format of the addresses listed in `h_addr_list`. Currently, the type is always `AF_INET`.

- `h_length` is the length, in bytes, of the host's address. In `AF_INET` format, the address is four bytes long

- `h_addr_list` is a `NULL`-terminated array of pointers to the addresses by which the host is known. Host addresses are given in network byte order.

As a convenience, the global `h_addr` constant is a fake field that points to the first item in the `h_addr_list` field. Keep in mind that `h_addr` must be treated as a structure field--it must point off a `hostent` structure. Also, make sure you dereference the `h_addr` "field" properly. For example:

       ulong ip_address;
       struct hostent *theHost;

       theHost = gethostbyname("fido");
       ip_address = *(ulong *)theHost->h_addr;

As a demonstration of the `h_addr` definition, the final line is the same as

       ip_address = *(ulong *)theHost->h_addr_list[0];

`Keep in mind that the hostent structure that's pointed to by the gethostby...() functions is global to your application's address space. If you want to cache the structure, you should copy it as soon as it's returned to you.`

#### h_errno and the herror() Function

The host look-up functions use a global error variable (an integer), called `h_errno`, to register errors. You can look at the `h_errno` value directly in your code after a host function fails (the potential `h_errno` values are listed below). Alternatively, you can use the `herror()` function which prints, to standard error, its argument followed by a system-generated string that describes the current state of `h_errno`.

The values that `h_errno` can take, and the corresponding `herror()` strings, are:

Value | Meaning
`HOST_NOT_FOUND` | "unknown host name"
`TRY_AGAIN` | "host name server busy"
`NO_RECOVERY` | "unrecoverable system error"
`NO_DATA` | "no address data is available for this host name"
anything else | "unknown error"

Note that while `h_errno` is set when something goes wrong, it isn't cleared if all is well. For example, if `gethostbyname()` can't find the named host, `h_errno` is set to `HOST_NOT_FOUND` and the function returns `NULL`. If, in an immediately subsequent call, the function succeeds, a pointer to a valid `hostent` is returned, but `h_errno` will still report `HOST_NOT_FOUND`.

The moral of this tale is that you should only check `h_errno` (or call `herror()`) if the network function call has failed, or clear it yourself before each `gethostby...()` call. Or both:

       struct hostent *host_ent;

       h_errno = 0;
       if ( !(host_ent = gethostbyname("a.b.c")) {
          herror("Error");
       }

Furthermore, `h_errno` might be legitimately set to a new error code even if the`gethostby...()` function succeeds. For example, if DNS can't be reached but the desired host is found in the hosts file, `h_errno` will be set to `TRY_AGAIN`, yet the returned `hostent` will be legitimate (it won't be `NULL`).

Be aware that `TRY_AGAIN` is used as a blanket "DNS doesn't know" state, regardless of the reason why. In other words, `h_errno` is set to `TRY_AGAIN` if DNS is actually down, if your machine isn't connected to the network, or if DNS simply doesn't know the requested host. You can use this fact to tell whether a (successful) look-up was performed through DNS or the hosts file:

       struct hostent *host_ent;

       h_errno = 0;
       if ( !(host_ent = gethostbyname("a.b.c")) {
          herror("Error");
       }
       else {
          if (h_errno == TRY_AGAIN)
             /* The hosts file was used. */
          else
             /* DNS was used. */
       }

Keep in mind that `h_errno` is global; be careful if you're using it in a multi-threaded program.

### gethostname(), getusername(), getpassword()

          int gethostname(char *name, unsigned int length)

          int getusername(char *name, unsigned int length)

          int getpassword(char *password, unsigned int length)

These functions retrieve, and copy into their first arguments, the name of the local computer, the name of the current user, and the current user's encoded password, respectively. In all three case, length gives the maximum number of characters that the functions should copy. If the length of the desired element is less than length, the copied string will be `NULL`-terminated.

The functions return the number of characters that were actually copied (not counting the `NULL` terminator). If there's an error--and such should be rare--the `gethostname()` and `getusername()` functions return 0 and point their respective name arguments to `NULL`. `getpassword()`, sensing an error, copies "*" into the password argument and`` returns -1 (thus you can tell the difference between a `NULL` password--which would legitimately return 0--and an error).

All three bits of information (host name, user name, and password) are taken from the settings that are declared through the Network preferences application.

A typical use of `gethostname()` is to follow the call with `gethostbyname()` in order to retrieve the address of the local host, as shown below:

       /* To fill a need, we invent the gethostaddr() function. */
       long gethostaddr(void) {
          struct hostent *host_ent;
          char host_name[MAXHOSTNAMELEN];

          if (gethostname(host_name, MAXHOSTNAMELEN) == 0) {
             return -1;
          }

          if ((host_ent = gethostbyname(host_name)) == NULL) {
             return -1;
          }

          return *(long *)host_ent.h_addr;
       }

Keep in mind that since host name information is taken from Network preferences, there's no guarantee that the name that's returned by `gethostname()` will match an entry that DNS or the hosts file knows about.

### getservbyname()

          struct servent *getservbyname(const char *name, const char *protocol)

You pass in the name of a service (such as "ftp") that runs under a particular protocol (such as "tcp"), and `getservbyname()` returns a pointer to a `servent` structure that describes the service.

The `servent` structure is:

       struct servent {
          char *s_name;
          char **s_aliases;
          int s_port;
          char *s_proto;
       };

- `s_name` is the name of the service.

- `s_aliases` is a `NULL`-terminated array of other names by which the services is known.

- `s_port` is the port number on which the service runs (given in network byte order)

- `s_proto` names the protocol ("tcp", "udp", etc.) that supports the service.

Currently, the function recognizes only two services: "ftp" and "telnet". Both run under the "tcp" protocol; thus, the only valid calls to`getservbyname()` are:

       getservbyname("ftp", "tcp");

and

       getservbyname("telnet", "tcp");

Such calls point to (separate) pre-defined `servent` structures that look like this:

field | ftp structure | telnet structure
`s_name` | "ftp" | "telnet"
`s_aliases` | `NULL` | `NULL`
`s_port` | 21 | 23
`s_proto` | "tcp" | "tcp"

If you ask for a service other than these two, the function returns `NULL`. Although the two `servent` structures are separate entities, they are both global to your application. In theory, this means the `getservbyname()` function isn't thread-safe. However, since the structures are hard-coded and separate, there's little danger in using them unprotected in a multi-threaded program.

### inet_addr(), inet_ntoa()

          unsigned long inet_addr(const char *addr)

          char *inet_ntoa(struct in_addr addr)

These functions convert addresses from ASCII to IP format and vice versa. Neither of them consults the DNS or the hosts file to perform the conversion--in other words, they perform the conversions without regard for an address' correspondence to an actual machine.

`inet_addr()` converts from ASCII to IP:

       ulong addr = inet_addr("192.0.0.1");

The result of this call (`addr`) would be appropriate as the initial argument to `gethostbyaddr()` (for example). The returned address is in network byte order.

`inet_ntoa()` converts the other way: It takes an IP address and converts it into an ASCII string. Note that the address that you pass in must first be placed in the `s_addr` field of the argument `in_addr` structure (`s_addr` is the structure's only field). For example:

       in_addr addr;
       char addr_buf[16];

       addr.s_addr = 0xc0000001;
       strcpy(addr_buf, inet_ntoa(addr));

Here, `addr_buf` will contain the (`NULL`-terminated) string "192.0.0.1". `inet_ntoa()` isn't thread-safe; if you want to cache the string that it returns you must copy it, as shown in the example. Given the IP format, the string that `inet_ntoa()` returns is guaranteed to be no more than 16 characters long (four 3-character address components, three dots, and a `NULL`).

### ntohs(), ntohl(), htons(), htonl()

          short ntohs(short val)

          long ntohl(long val)

          short htons(short val)

          long htonl(long val)

These macros convert values between host and network byte order; `ntohs()` and `ntohl()` convert 16-bit and 32-bit integers from network byte order to host byte order, and `htons()` and `htonl()` convert from host byte order to network byte order.

The BeBox and Power Macintosh versions of the BeOS are both big-endian--they normally operate in the same byte order as the network. The Intel version of BeOS operates in little-endian order. Because of this, you must use these functions to ensure compatibility of your source code with all platforms supported by BeOS.

There are other functions available for converting between big-endian and little-endian form, but these four guarantee that the correct network and host order is used, regardless of the processor for which your application is compiled.

The Be Book, in lovely HTML, for BeOS Release 3.

Copyright © 1998 Be, Inc. All rights reserved.

Last modified March 26, 1998.