Declared in: <net/netdb.h>
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 "Network Sockets."
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 three-element "machine.domain.extension" case-insensitive text name:
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 Provider Service (IPS).
You can also provide host information by adding to your computer's /boot/system/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/system/hosts entries 192.0.0.1 phaedo.racine.com fido phydough 205.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.
struct hostent *gethostbyname(const char *name) struct hostent *gethostbyaddr(const char *address, int length, int type) void herror(const char *string)
The two gethostby...() 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/system/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.
Note: Because gethostbyname() and gethostbyaddr() use a global structure to return information, the functions are not thread safe.
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:
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((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((char *)&addr, 4, AF_INET);
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:
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.
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.
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.
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; };
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.
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).
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:
Macro | Meaning |
---|---|
ntohs() | network short to host short |
ntohl() | network long to host long |
htons() | host short to network short |
htonl() | host long to network long |
Network byte order is big-endian; the host byte order is machine-dependent. The current BeBox is big-endian, so these macros are, essentially, no-ops: They return their respective arguments without conversion. To be scrupulous, however, you should convert all multi- byte values that you write to or get from the Internet. For example, a truly "safe" call to gethostbyaddr() (for example) would look like this:
ulong addr = htonl(inet_addr("192.0.0.1"); struct hostent *theHost; theHost = gethostbyaddr((char *)&addr, 4, AF_INET);
The Be Book, HTML Edition, for Developer Release 8 of the Be Operating System.
Copyright © 1996 Be, Inc. All rights reserved.
Be, the Be logo, BeBox, BeOS, BeWare, and GeekPort are trademarks of Be, Inc.
Last modified September 6, 1996.