inetd(1M) デーモンは起動時に呼び出され、待機するサービスを /etc/inet/inetd.conf ファイルから取得します。デーモンは /etc/inet/inetd.conf ファイルに記述されている各サービスごとに 1 つのソケットを作成し、各ソケットに適切なポート番号の割り当てを行います。inetd(1M) についての詳細は、マニュアルページを参照してください。
inetd(1M) デーモンは各ソケットをポーリングして、そのソケットに対応するサービスへのコネクション要求を待機します。SOCK_STREAM タイプのソケットの場合、inetd(1M) は待機ソケット上で受け入れ (accept(3SOCKET))、フォークし (fork(2))、新しいソケットをファイル記述子 0 および 1 (stdin および stdout) に複製し (dup(2))、ほかの開いているファイル記述子を閉じて、適切なサーバーを実行します (exec(2))。
inetd(1M) を使用する主な利点は、使用していないサービスがシステムの資源を消費しない点にあります。また、コネクションの確立に関する処理の大部分を inetd(1M) が行う点も大きな利点の 1 つです。inetd(1M) によって起動されたサーバーのソケットはファイル記述子 0 と 1 上のクライアントに接続されます。したがって、サーバーはすぐに、読み取り、書き込み、送信、または受信を行うことができます。fflush(3C) を適宜使用する限り、サーバーは stdio の規定に従って提供されるバッファリングされた入出力を使用できます。
getpeername(3SOCKET) ルーチンは、ソケットに接続されたピア (プロセス) のアドレスを返します。このルーチンは、inetd(1M) によって起動されたサーバーで使用すると便利です。たとえば、このルーチンを使用すると、クライアントの IPv6 アドレスを表現するときに使用される fec0::56:a00:20ff:fe7d:3dd2 のようなインターネットアドレスを記録できます。次に、inetd(1M) サーバーが使用するコードの例を示します。
struct sockaddr_storage name; int namelen = sizeof (name); char abuf[INET6_ADDRSTRLEN]; struct in6_addr addr6; struct in_addr addr; if (getpeername(fd, (struct sockaddr *) &name, &namelen) == -1) { perror("getpeername"); exit(1); } else { addr = ((struct sockaddr_in *)&name)->sin_addr; addr6 = ((struct sockaddr_in6 *)&name)->sin6_addr; if (name.ss_family == AF_INET) { (void) inet_ntop(AF_INET, &addr, abuf, sizeof (abuf)); } else if (name.ss_family == AF_INET6 && IN6_IS_ADDR_V4MAPPED(&addr6)) { /* this is a IPv4-mapped IPv6 address */ IN6_MAPPED_TO_IN(&addr6, &addr); (void) inet_ntop(AF_INET, &addr, abuf, sizeof (abuf)); } else if (name.ss_family == AF_INET6) { (void) inet_ntop(AF_INET6, &addr6, abuf, sizeof (abuf)); } syslog("Connection from %s\n", abuf); }