プログラミングインタフェース

標準ルーチン

この節では、ネットワークアドレスを検出したり、構築したりするルーチンについて説明します。特に明記しない限り、インターネットファミリだけに適用されます。

リモートホスト上のサービスを検出するには、クライアントとサーバーが通信を行う前にさまざまなレベルの割り当てを行う必要があります。サービスには、人が使用するための名前が付いています。サービス名とホスト名は、ネットワークアドレスに変換され、そのネットワークアドレスを使用してホストを検出し、ホストへの経路を指定します。割り当ての細部は、ネットワークアーキテクチャーによって異なります。

標準ルーチンは、ホスト名をネットワークアドレスに、ネットワーク名をネットワーク番号に、プロトコル名をプロトコル番号に、サービス名をポート番号にマッピングします。標準ルーチンはまた、サーバープロセスとの通信で使用するために適切なプロトコルも指定します。標準ルーチンを使用する場合は、ファイル netdb.h を組み込む必要があります。

ホスト名とサービス名

インタフェース getaddrinfo(3SOCKET)getnameinfo(3SOCKET)gai_strerror(3SOCKET)、および freeaddrinfo(3SOCKET) を使用すると、ホスト上のサービスの名前とアドレスを簡単に変換できます。これらは、getipnodebyname(3SOCKET)gethostbyname(3NSL)、および getservbyname(3SOCKET) の API よりも新しいインタフェースです。IPv6 アドレスと IPv4 アドレスは、どちらも透過的に処理されます。

getaddrinfo(3SOCKET) ルーチンは、指定されたホスト名とサービス名に結合アドレスとポート番号を返します。getaddrinfo(3SOCKET) が返す情報は動的に割り当てられるので、この情報は freeaddrinfo(3SOCKET) を使用して解放し、メモリーリークを回避する必要があります。getnameinfo(3SOCKET) は、指定されたアドレスとポート番号に関連付けられたホスト名とサービス名を返します。gai_strerror(3SOCKET) を呼び出すと、getaddrinfo(3SOCKET)getnameinfo(3SOCKET) から返される EAI_xxx コードに基づくエラーメッセージが出力されます。

次に、getaddrinfo(3SOCKET) の使用例を示します。

struct addrinfo        *res, *aip;
struct addrinfo        hints;
int                    error;

/* Get host address.  Any type of address will do. */
bzero(&hints, sizeof (hints));
hints.ai_flags = AI_ALL|AI_ADDRCONFIG;
hints.ai_socktype = SOCK_STREAM;

error = getaddrinfo(hostname, servicename, &hints, &res);
if (error != 0) {
    (void) fprintf(stderr, "getaddrinfo: %s for host %s service %s\n",
    gai_strerror(error), hostname, servicename);
    return (-1);
}

res が指す構造体の getaddrinfo(3SOCKET) が返す情報を処理したあと、freeaddrinfo(res) を使用して記憶領域を解放する必要があります。

次の例に示すように、getnameinfo(3SOCKET) ルーチンはエラーの原因を識別するときに特に便利です。

struct sockaddr_storage faddr;
int                     sock, new_sock, sock_opt;
socklen_t               faddrlen;
int                     error;
char                    hname[NI_MAXHOST];
char                    sname[NI_MAXSERV];
...
faddrlen = sizeof (faddr);
new_sock = accept(sock, (struct sockaddr *)&faddr, &faddrlen);
if (new_sock == -1) {
    if (errno != EINTR && errno != ECONNABORTED) {
        perror("accept");
    }
    continue;
}
error = getnameinfo((struct sockaddr *)&faddr, faddrlen, hname, 
    sizeof (hname), sname, sizeof (sname), 0);
if (error) {
    (void) fprintf(stderr, "getnameinfo: %s\n",
        gai_strerror(error));
} else {
    (void) printf("Connection from %s/%s\n", hname, sname);
}

ホスト名 – hostent

インターネットホスト名とアドレスのマッピングは、gethostent(3NSL) に定義するように hostent 構造体によって表現されます。

struct hostent {
    char  *h_name;            /* official name of host */
    char  **h_aliases;        /* alias list */
    int   h_addrtype;         /* hostaddrtype(e.g.,AF_INET6) */
    int   h_length;           /* length of address */
    char  **h_addr_list;      /* list of addrs, null terminated */
};
/*1st addr, net byte order*/
#define h_addr h_addr_list[0]
getipnodebyname(3SOCKET)

インターネットホスト名を hostent 構造体にマッピングする

getipnodebyaddr(3SOCKET)

インターネットホストアドレスを hostent 構造体にマッピングする

freehostent(3SOCKET)

hostent 構造体のメモリーを解放する

inet_ntop(3SOCKET)

インターネットホストアドレスを文字列にマッピングする

このルーチンは、ホストの名前、その別名、アドレスタイプ、および NULL で終了する可変長アドレスのリストを含む hostent 構造体を返します。このアドレスリストが必要なのは、ホストが多くのアドレスを持つことができるためです。h_addr 定義は下位互換性のためであり、この定義は hostent 構造体のアドレスリストの最初のアドレスです。

ネットワーク名 – netent

ネットワーク名をネットワーク番号にマッピングし、netent 構造体を返すルーチンです。

/*
 * 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)、および getnetent(3SOCKET) は、前述のホストルーチンに対応するネットワーク側のルーチンです。

プロトコル名 – protoent

protoent 構造体は、getprotobyname(3SOCKET)getprotobynumber(3SOCKET)、および getprotoent(3SOCKET) で使用され、getprotoent(3SOCKET) で定義されるプロトコル名マッピングを定義します。

struct protoent {
    char    *p_name;       /* official protocol name */
    char    **p_aliases    /* alias list */
    int     p_proto;       /* protocol number */
};

サービス名 – servent

インターネットファミリサービスは、特定の既知のポートに常駐し、特定のプロトコルを使用します。サービス名とポート番号のマッピングは、getprotoent(3SOCKET) で定義される servent 構造体によって記述されます。

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) は、サービス名、およびオプションとして修飾プロトコルを servent 構造体にマッピングします。次の呼び出しは、

sp = getservbyname("telnet", (char *) 0);

任意のプロトコルを使用する Telnet サーバーのサービス仕様を返します。次の呼び出しは、

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

TCP プロトコルを使用する Telnet サーバーを返します。getservbyport(3SOCKET)getservent(3SOCKET) も提供されます。getservbyport(3SOCKET) には、getservbyname(3SOCKET) によって使用されるインタフェースに似たインタフェースがあります。つまり、オプションのプロトコル名を指定して、ルックアップを修飾できます。

その他のルーチン

その他にも、名前とアドレスの操作を簡易化するルーチンはいくつかあります。次の表に、可変長のバイト列、およびバイトスワッピングのネットワークアドレスと値を要約します。

表 8–2 実行時ライブラリルーチン

インタフェース 

機能説明 

memcmp(3C)

バイト列を比較する。同じ場合は 0、異なる場合は 0 以外の値を返す

memcpy(3C)

s2n バイトを s1 にコピーする

memset(3C)

base の最初の n バイトの領域に値 value を割り当てる

htonl(3SOCKET)

ホストからネットワークへの 32 ビット整数バイトオーダー変換 

htons(3SOCKET)

ホストからネットワークへの 16 ビット整数バイトオーダー変換 

ntohl(3SOCKET)

ネットワークからホストへの 32 ビット整数バイトオーダー変換 

ntohs(3SOCKET)

ネットワークからホストへの 16 ビット整数バイトオーダー変換 

バイトスワッピングルーチンを使用するのは、アドレスはネットワークオーダーで供給されるとオペレーティングシステムが考えるためです。一部のアーキテクチャーでは、ホストバイトオーダーがネットワークバイトオーダーと異なるため、プログラムは必要に応じて値をバイトスワップする必要があります。そのため、ネットワークアドレスを返すルーチンは、ネットワークオーダーで返します。バイトスワッピング問題が発生するのは、ネットワークアドレスを解釈する場合だけです。たとえば、次のコードは TCP ポートまたは UDP ポートをフォーマットします。

printf("port number %d\n", ntohs(sp->s_port));

これらのルーチンを必要としないマシンでは、アドレスは NULL マクロとして定義されます。