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

ブロードキャストとネットワーク構成の判断

ブロードキャストは IPv6 ではサポートされません。ブロードキャストがサポートされているのは IPv4 のみです。

データグラムソケットにより送信されたメッセージは、接続されているネットワークのすべてのホストに届くようにブロードキャストを行うことができます。システムはブロードキャストのシミュレーションをソフトウェアで行わないため、ネットワークがブロードキャストをサポートする必要があります。ブロードキャストメッセージを使用すると、ネットワーク上のすべてのホストがブロードキャストメッセージをサービスする必要があるので、ブロードキャストメッセージはネットワークに大きな負荷をかける可能性があります。ブロードキャストは主に次の 2 つの目的に使用されます。

ブロードキャストメッセージを送信するには、次のようにインターネットデータグラムソケットを作成します。

s = socket(AF_INET, SOCK_DGRAM, 0);

次に、ポート番号をソケットにバインドします。

sin.sin_family = AF_INET;
sin.sin_addr.s_addr = htonl(INADDR_ANY);
sin.sin_port = htons(MYPORT);
bind(s, (struct sockaddr *) &sin, sizeof sin);

ネットワークのブロードキャストアドレスに送信することにより、データグラムは 1 つのネットワーク上のみでブロードキャストを行うことができます。また、netinet/in.h 内で定義されている特別なアドレス INADDR_BROADCAST に送信することにより、接続されているすべてのネットワークに対して、データグラムのブロードキャストを行うことができます。

システムは、システム上のネットワークインタフェースについての情報の数を判断するメカニズムを提供します。この情報には、IP アドレスおよびブロードキャストアドレスが含まれます。SIOCGIFCONF ioctl(2) 呼び出しは、ホストのインタフェース構成を単一の ifconf 構造体で返します。この構造体には ifreq 構造体の配列が含まれます。ifreq 構造体は、ホストに接続されているすべてのネットワークインタフェースがサポートするアドレス群ごとに 1 つずつ存在します。

次の例では、net/if.h で定義されている ifreq 構造体を示します。


例 8–14 net/if.h ヘッダーファイル

struct ifreq {
    #define IFNAMSIZ 16
    char ifr_name[IFNAMSIZ]; /* if name, e.g., "en0" */
    union {
        struct sockaddr ifru_addr;
        struct sockaddr ifru_dstaddr;
        char ifru_oname[IFNAMSIZ]; /* other if name */
        struct sockaddr ifru_broadaddr;
        short ifru_flags;
        int ifru_metric;
        char ifru_data[1]; /* interface dependent data */
        char ifru_enaddr[6];
    } ifr_ifru;
    #define ifr_addr ifr_ifru.ifru_addr
    #define ifr_dstaddr ifr_ifru.ifru_dstaddr
    #define ifr_oname ifr_ifru.ifru_oname
    #define ifr_broadaddr ifr_ifru.ifru_broadaddr
    #define ifr_flags ifr_ifru.ifru_flags
    #define ifr_metric ifr_ifru.ifru_metric
    #define ifr_data ifr_ifru.ifru_data
    #define ifr_enaddr ifr_ifru.ifru_enaddr
};

インタフェース構成を取得する呼び出しは以下の通りです。

/*
 * Do SIOCGIFNUM ioctl to find the number of interfaces
 *
 * Allocate space for number of interfaces found
 *
 * Do SIOCGIFCONF with allocated buffer
 *
 */
if (ioctl(s, SIOCGIFNUM, (char *)&numifs) == -1) {
    numifs = MAXIFS;
}
bufsize = numifs * sizeof(struct ifreq);
reqbuf = (struct ifreq *)malloc(bufsize);
if (reqbuf == NULL) {
    fprintf(stderr, "out of memory\n");
    exit(1);
}
ifc.ifc_buf = (caddr_t)&reqbuf[0];
ifc.ifc_len = bufsize;
if (ioctl(s, SIOCGIFCONF, (char *)&ifc) == -1) {
    perror("ioctl(SIOCGIFCONF)");
    exit(1);
}

この呼び出しの後、buf には ifreq 構造体の配列が含まれます。ホストに接続されているすべてのネットワークはそれぞれ、関連付けられた ifreq 構造体を 1 つ持っています。これらの構造体のソート順は次のとおりです。

ifc.ifc_len の値は ifreq 構造体が使用したバイト数に設定されます。

各構造体は、対応するネットワークが稼働または停止しているか、ポイントツーポイントまたはブロードキャストのどちらであるか、などを示すインタフェースフラグセットを持ちます。次の例では、ifreq 構造体が指定するインタフェース用の SIOCGIFFLAGS フラグを返す ioctl(2) を示します。


例 8–15 インタフェースフラグの取得

struct ifreq *ifr;
ifr = ifc.ifc_req;
for (n = ifc.ifc_len/sizeof (struct ifreq); --n >= 0; ifr++) {
    /*
     * Be careful not to use an interface devoted to an address
     * family other than those intended.
     */
    if (ifr->ifr_addr.sa_family != AF_INET)
        continue;
    if (ioctl(s, SIOCGIFFLAGS, (char *) ifr) < 0) {
        ...
    }
    /* Skip boring cases */
    if ((ifr->ifr_flags & IFF_UP) == 0 ||
            (ifr->ifr_flags & IFF_LOOPBACK) ||
            (ifr->ifr_flags & (IFF_BROADCAST | IFF_POINTOPOINT)) == 0)
        continue;
}

次の例では、インタフェースのブロードキャストアドレスを取得するための SIOGGIFBRDADDR ioctl(2) コマンドを示します。


例 8–16 インタフェースのブロードキャストアドレス

if (ioctl(s, SIOCGIFBRDADDR, (char *) ifr) < 0) {
    ...
}
memcpy((char *) &dst, (char *) &ifr->ifr_broadaddr,
    sizeof ifr->ifr_broadaddr);

また、SIOGGIFBRDADDR ioctl(2) を使用すると、ポイントツーポイントインタフェースの着信先アドレスを取得できます。

インタフェースのブロードキャストアドレスを取得したあと、sendto(3SOCKET) を使用してブロードキャストデータグラムを送信します。

sendto(s, buf, buflen, 0, (struct sockaddr *)&dst, sizeof dst);

ホストのインタフェースがブロードキャストまたはポイントツーポイントアドレスをサポートする場合、そのホストが接続されているインタフェースごとに 1 つの sendto(3SOCKET) を使用します。