Sun Microsystems, Inc.
spacer |
black dot
6.  Socket Interfaces Standard Routines Host Names - hostent  Previous   Contents   Next 

Maps an Internet host name to a hostent structure


Maps an Internet host address to a hostent structure


Frees the memory of a hostent structure


Maps an Internet host address to a displayable string

The routines return a hostent structure containing the name of the host, its aliases, the address type (address family), and a NULL-terminated list of variable length addresses. The list of addresses is required because a host can have many addresses. The h_addr definition is for backward compatibility and is the first address in the list of addresses in the hostent structure.

Network Names - netent

The routines to map network names to numbers and the reverse return a netent structure:
 * Assumes that a network number fits in 32 bits.
struct netent {
   char     *n_name;      /* official name of net */
   char     **n_aliases;  /* alias list */
   int      n_addrtype;   /* net address type */
   int      n_net;        /* net number, host byte order */

getnetbyname(3SOCKET), getnetbyaddr_r(3SOCKET), and getnetent(3SOCKET) are the network counterparts to the host routines described above.

Protocol Names - protoent

The protoent structure defines the protocol-name mapping used with getprotobyname(3SOCKET), getprotobynumber(3SOCKET), and getprotoent(3SOCKET) and defined in getprotoent(3SOCKET):
struct protoent {
   char     *p_name;          /* official protocol name */
   char     **p_aliases       /* alias list */
   int      p_proto;          /* protocol number */

Service Names - servent

An Internet family service resides at a specific, well-known port and uses a particular protocol. A service-name-to-port-number mapping is described by the servent structure defined in getprotoent(3SOCKET):

struct servent {
   char     *s_name;         /* official service name */
   char     **s_aliases;     /* alias list */
   int      s_port;          /* port number, network byte order */
   char     *s_proto;        /* protocol to use */

getservbyname(3SOCKET) maps service names and, optionally, a qualifying protocol to a servent structure. The call:
sp = getservbyname("telnet", (char *) 0);
returns the service specification of a telnet server using any protocol. The call:

sp = getservbyname("telnet", "tcp");

returns the telnet server that uses the TCP protocol. getservbyport(3SOCKET) and getservent(3SOCKET) are also provided. getservbyport(3SOCKET) has an interface similar to that of getservbyname(3SOCKET); you can specify an optional protocol name to qualify lookups.

Other Routines

In addition to address-related database routines, there are several other routines that simplify manipulating names and addresses. The following table summarizes the routines for manipulating variable-length byte strings and byte-swapping network addresses and values.

Table 6-2 Runtime Library Routines




Compares byte-strings; 0 if same, not 0 otherwise


Copies n bytes from s2 to s1


Sets n bytes to value starting at base


32-bit quantity from host into network byte order


16-bit quantity from host into network byte order


32-bit quantity from network into host byte order


16-bit quantity from network into host byte order

The byte-swapping routines are provided because the operating system expects addresses to be supplied in network order. On some architectures, the host byte ordering is different from network byte order, so programs must sometimes byte-swap values. Routines that return network addresses do so in network order. Byte-swapping problems occur only when interpreting network addresses. For example, the following code formats a TCP or UDP port:
printf("port number %d\n", ntohs(sp->s_port));

On certain machines where these routines are not needed, they are defined as null macros.

Client-Server Programs

The most common form of distributed application is the client/server model. In this scheme, client processes request services from a server process.

An alternate scheme is a service server that can eliminate dormant server processes. An example is inetd(1M), the Internet service daemon. inetd(1M) listens at a variety of ports, determined at startup by reading a configuration file. When a connection is requested on an inetd(1M) serviced port, inetd(1M) spawns the appropriate server to serve the client. Clients are unaware that an intermediary has played any part in the connection. inetd(1M) is described in more detail in "inetd Daemon".

Sockets and Servers

Most servers are accessed at well-known Internet port numbers or UNIX family names. The service rlogin is an example of a well-known UNIX family name. The main loop of a remote login server is shown in Example 6-6.

The server dissociates from the controlling terminal of its invoker unless it is operating in DEBUG mode.

   (void) close(0);
   (void) close(1);
   (void) close(2);
   (void) open("/", O_RDONLY);
   (void) dup2(0);
   (void) dup2(0);

Dissociating prevents the server from receiving signals from the process group of the controlling terminal. After a server has dissociated from the controlling terminal, the server cannot send reports of errors to the terminal and must log errors with syslog(3C).

The server gets its service definition by calling getaddrinfo(3SOCKET).

    bzero(&hints, sizeof (hints));
    hints.ai_flags = AI_ALL|AI_ADDRCONFIG;
    hints.ai_socktype = SOCK_STREAM;
    error = getaddrinfo(NULL, "rlogin", &hints, &aip);

The result, returned in aip, defines the Internet port at which the program listens for service requests. Some standard port numbers are defined in /usr/include/netinet/in.h.

The server next creates a socket and listens for service requests. The bind(3SOCKET) routine ensures that the server listens at the expected location. Because the remote login server listens at a restricted port number, the server runs as superuser. The main body of the server is the following loop.

Example 6-6 Server Main Loop

    /* Wait for a connection request. */
    for (;;) {
        faddrlen = sizeof (faddr);
        new_sock = accept(sock, (struct sockaddr *)&faddr, &faddrlen);
        if (new_sock == -1) {
            if (errno != EINTR && errno != ECONNABORTED) {
                perror("rlogind: accept");
        if (fork() == 0) {
            close (sock);
            doit (new_sock, &faddr);
        close (new_sock);

accept(3SOCKET) blocks messages until a client requests service. Furthermore, accept(3SOCKET) returns a failure indication if it is interrupted by a signal, such as SIGCHLD. The return value from accept(3SOCKET) is checked and an error is logged with syslog(3C) if an error occurs.

The server then forks a child process and invokes the main body of the remote login protocol processing. The socket used by the parent to queue connection requests is closed in the child. The socket created by accept(3SOCKET) is closed in the parent. The address of the client is passed to the server application's doit() routine, which authenticates the client.

  Previous   Contents   Next