bind(2) における sin_lan の謎TCP ソケットでの bind(2) では、アドレス構造体として sockaddr_in 構造体を使います(IPv4 の場合)。 この sockaddr_in 構造体ですが、FreeBSD の場合、 /usr/include/netinet/in.h で以下のように定義されてます。
ソケットプログラミングに慣れた人なら、sin_len というメンバを、見慣れないメンバと感じるかもしれません。 Solaris8 の sockaddr_in 構造体には sin_len は含まれません。 Linux や HP-UX の sockaddr_in 構造体も同様です。 W.Richard Stevens の『UNIX ネットワークプログラミング 第 2 版 Vol.1』によると、『長さメンバ sin_len は、OSI プロトコルのサポートが導入された 4.3BSD-Reno で追加された』のだそうです。 ただし『ソケットアドレス構造体の長さメンバはすべてのベンダーがサポートしているわけではなく、 Posix.1g でもこのメンバは要求されていない』とも述べられています。 さて、この sin_len はどうやら、 アドレス構造体のサイズを示すメンバとして用いられるようですが、 ソケット API でアドレス構造体を使用するシステムコールの引数には、 必ず、アドレス構造体のサイズが含まれています。 例えば、bind(2) の第 3 引数は、第 2 引数で示すアドレス構造体のサイズを指定します。 では、実際のところ、sin_len が有効に機能するのか、 それとも多くの OS 同様引数渡しのサイズが有効になるのか、ソースを追って確認してみましょう。 bind(2) の入り口は /usr/src/sys/kern/uipc_syscall.c の bind() です。bind() は以下のようになっています。
bind() から getsockaddr() が呼ばれます。 この時、getsockaddr() の第 2 引数が bind(2) の第 2 引数、 getsockaddr() の第 3 引数が bind(2) の第 3 引数に対応しています。 getsockaddr() は bind() と同じく /usr/src/sys/kern/uipc_syscall.c に含まれており、 ソースは以下のようになっています。
最後の方で sa->len に第 3 引数で受け取った len、 すなわち bind(2) の第 3 引数をアドレス構造体の sin_len として採用しています。 ですので、bind(2) 実行時に sockaddr_in 構造体の sin_len を設定するのは意味がありません。 TCP ソケットでの bind(2) 処理で実際にこの sin_len が参照されるのは、 /usr/src/sys/netinet/in_pcb.c の in_pcbbind() の以下の処理になります。
sa_len (つまり sin_len) の値が適切でなかった場合、 in_pcbbind() が EINVAL で return するので、bind(2) が EINVAL エラーになります。 というわけで、FreeBSD の bind(2) での sin_len には意味がありません。 おそらく、過去のアプリケーションのソースコードレベルでの互換性のために残されたメンバだと思われますが、 これから新規にソケットプログラミングを行う場合は、無視した方が良いでしょう。 TetsuoSTREAMS > FreeBSD > bind(2) における sin_len の謎 |