IPv6 ソケット API プログラミングの基礎知識 (シリーズ第 2 回)

IPv6 ソケット API を使うための構造体を紹介した前回に続きまして、第 2 回はサーバーでは必須となる特定ポートへのバインドの基本的なやり方について書いてみます。

まず、sockaddr_in6 構造体を用意しなくてはなりませんが、今回はよく利用されるバインドするアドレスを指定しないやり方を扱うことにします。一般的なソケット API プログラミングと同様に <netinet/in.h> ヘッダーをインクルードすると (前回は書きましたっけ? ^^;)、in6addr_any オブジェクトを利用することができます。

const struct in6_addr in6addr_any;

このオブジェクトは IPv4 での INADDR_ANY に相当するものですが、IPv6 では構造体になので少しばかり勝手が異なります。例としてはこのように使います:

#include <netinet/in.h>
#include <arpa/inet.h> /* htons のため */

#define PORT ポート番号

int bind_in6_example1(int socket_fd) {
    struct sockaddr_in6 sa = {0}; /* 全メンバーを 0 に初期化 */
    sa.sin6_family = AF_INET6;
    sa.sin6_port = htohs(PORT);
    sa.sin6_flowinfo = 0; /* 初期化済みなので実際には不要 */
    sa.sin6_addr = in6addr_any;
    sa.sin6_scope_id = 0; /* 初期化済みなので実際には不要 */
    return bind(socket_fd, (const struct sockaddr *) &sa,
            sizeof (struct sockaddr_in6));
}

in6addr_any はオブジェクトですが、初期化子として利用する場合のために IN6ADDR_ANY_INIT マクロも用意されています。C99 で導入された記法を使うと、例えば次のように書くことができます:

#include <netinet/in.h>
#include <arpa/inet.h> /* for htons */

#define PORT ポート番号

static const struct sockaddr_in6 sa_init = {
    .sin6_family = AF_INET6,
    .sin6_flowinfo = 0, /* 暗黙的に初期化されるので実際には不要 */
    .sin6_addr = INADDR6_ANY_INIT,
    .sin6_scope_id = 0, /* 暗黙的に初期化されるので実際には不要 */
};

int bind_in6_example2(int socket_fd) {
    struct sockaddr_in6 sa = sa_init;
    sa.sin6_port = htohs(PORT);
    return bind(socket_fd, (const struct sockaddr *) &sa,
            sizeof (struct sockaddr_in6));
}

IPv4 の INADDR_ANY とは違って、初期化と代入で書き方が異なることに注目してくださいね。

それでは第 2 回はここまでです。例によって次回も期待しないで待っていてください。

IPv6 ソケット API プログラミングの基礎知識 (シリーズ第 1 回)

xllmnrd を製作する過程で習得した IPv6 ソケット API に関する知見を、少しずつ書いていこうという不定期連載企画です。反応が薄ければ うやむやにするかもしれませんが…。

さて記念すべき第 1 回ですが、まずは sockaddr_in6 構造体の紹介で始めたいと思います。IPv4 の sockaddr_in 構造体に対応するものですが、この構造体には以下のメンバーがあります (OS によっては他のメンバーがあることもありますが ここでは触れません):

sa_family_t sin6_family;
アドレスファミリーです。IPv6 では AF_INET6 を指定します。
in_port_t sin6_port;
ポート番号です。IPv4 と同様にネットワーク バイト オーダーで指定します。
uint32_t sin6_flowinfo;
これは IPv6 に特有のメンバーで、トラフィック クラスとフロー情報を指定します。とりあえず 0 としておきましょう。
struct in6_addr sin6_addr;
お待ちかね、IPv6 アドレスです。in6_addr 構造体については後述します。
uint32_t sin6_scope_id;
これも IPv6 に特有のメンバーで、スコープ ID を指定します。スコープを指定する必要がない場合は 0 としておきます。

IPv6 アドレスを指定する in6_addr 構造体には以下のメンバーがあります:

uint8_t s6_addr[16];
IPv6 アドレスをバイト列で指定します。IPv4 とは違ってバイト列なので、バイト オーダーは意識する必要がありません。

第 1 回はここまでにしておきます。次回はいつになるか分かりませんが、期待しないで待っていてください。