システムに装備されているデーモンの 1 つが inetd(1M) です。システムの起動時に呼び出され、 /etc/inet/inetd.conf ファイルを読み、その内容に従いサービスを取得します。デーモンは /etc/inet/inetd.conf ファイルに記述されている各サービスごとに 1 つのソケットを作成し、各ソケットに適切なポート番号の割り当てを行います。inetd(1M) に関するより詳しい情報は、マニュアルページを参照してください。
inetd(1M) は各ソケットのポーリングを行い、そのソケットに対するサービスの接続要求待ちを行います。SOCK_STREAM
タイプのソケットの場合、inetd(1M) は待機ソケットに対し accept(3SOCKET) を実行、新しいファイル記述子 0 および 1 (stdin および stdout) において、新しいソケットに対して fork(2)、dup(2) を実行し、その他の開かれているファイル記述子を終了させ適切なサーバーに対し exec(2) を実行します。
inetd(1M) の主な利点は、使用されていないサービスがシステム資源を使用しない点にあります。また、接続の確立に関する処理の大部分を inetd(1M) が請け負う点も大きな利点の 1 つです。inetd(1M) によって開始されたサーバーのソケットは、ファイル記述子 0 および 1 においてクライアントに接続され、ただちに read(2)、write(2)、send(3SOCKET)、または recv(3SOCKET) の実行が可能です。サーバーは stdio の取り決めに従い、必要な場合に fflush(3C) を利用する限りバッファー入出力の使用が可能です。
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)) { /* これは IPv4 によりマップされた IPv6 アドレスです。*/ 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); }