POS39-C. システム間でデータを送受信するときは正しいバイトオーダーを使用する
バイトオーダーにはリトルエンディアン(最下位バイトが先)とビッグエンディアン(最上位バイトが先)があり、どちらが採用されているかはシステムのアーキテクチャによって異なる。IA-32 は、バイトオーダーにリトルエンディアンを使用するアーキテクチャの一例である。一方、PowerPC やネットワークプロトコル(TCP や IP など)はビッグエンディアンを使用する。
エンディアンの異なるシステム間でデータを送受信するときは、データを解釈する前にバイトオーダーを反転させる必要がある。
関数 htonl()
、htons()
、ntohl()
、ntohs()
を使うことで、ネットワークバイトオーダー(ビッグエンディアン)とホストバイトオーダーの間の変換を行うことができる。ビッグエンディアンを採用するシステムでは、これらの関数は何もしない。また、これらは関数ではなくマクロとして実装されることもある。
違反コード
次の違反コード例では、接続済みのネットワークソケットから符号無し32ビット整数を読み取ろうとしている。
なお、ネットワーク経由でデータをやりとりする場合、データ型のサイズはアーキテクチャによって異なる場合があるため、扱うデータ型のサイズを正しく知っておくことが重要である。このコードでは int
ではなく uint32_t
を用いてデータを交換している。詳細は「FIO09-C. システム間でのバイナリデータ転送に注意する」を参照。
/* sock は接続済み TCP ソケット */ uint32_t num; if (recv(sock, (void *)&num, sizeof(uint32_t), 0) < (int)sizeof(uint32_t)) { /* エラー処理 */ } printf("We received %u from the network!\n", (unsigned int)num);
このプログラムは、ソケットから受信した整数型データを間違ったバイトオーダーで出力する。たとえば、ビッグエンディアンのシステムから値4が送信され、受信側のシステムがリトルエンディアンの場合、読み取られる値は 536,870,912 となる。この問題は、ネットワークバイトオーダーでデータを送受信することで解決する。
適合コード
次の適合コードでは、ntohl()
関数を使って、受信した整数データをネットワークバイトオーダーからホストバイトオーダーに変換している。
/* sock は接続済み TCP ソケット */ uint32_t num; if (recv(sock, (void *)&num, sizeof(uint32_t), 0) < (int)sizeof(uint32_t)) { /* エラー処理 */ } num = ntohl(num); printf("We received %u from the network!\n", (unsigned int)num);
ntohl()
関数(network to host long) は、uint32_t
型の値をネットワークバイトオーダーからホストバイトオーダーへ変換する。この関数はシステムのバイトオーダーに対応して実装され、どのアーキテクチャにおいても適切に動作する。例えばビッグエンディアンのアーキテクチャでは、ntohl()
は何もしない。
ネットワーク上の他のシステムにデータを送る場合には、ntohl()
とは逆の変換を行う htonl()
関数(host to network long)を使用してデータをビッグエンディアンに変換してから送信する必要がある。
可搬性に関する詳細
ntohs()
、ntohl()
、htons()
、htonl()
は C 標準の一部ではない。それゆえ、POSIX 準拠でないシステムにおいて可搬性は保証されていない。- POSIX の
ntohs()
、ntohl()
、htons()
、htonl()
の実装は、uint16_t
型およびuint32_t
型の引数をとり、ヘッダファイル<arpa/inet.h>
で定義されている。 - Windows の実装では、
unsigned short
およびunsigned long
を使用し、ヘッダファイル<winsock2.h>
に定義されている。 ntoht()
とhtont()
のバリエーションとして、ntohi()
/htoni()
やntohll()
/htonll()
なども存在する。
リスク評価
プログラマが注意深くない場合このようなバグが作り込まれやすい。しかし、間違った結果が出力されプログラムは即座に中断するため、デバッグやテストの初期段階で発見されるだろう。しかし、データの型や大きさによっては、バイトオーダーが逆であることに気づくのは難しいかもしれない。
レコメンデーション |
深刻度 |
可能性 |
>修正コスト |
優先度 |
レベル |
---|---|---|---|---|---|
POS39-C |
中 |
高 |
低 |
P18 |
L1 |
参考資料
[MSDN] | "Winsock Functions" |
[Open Group 2004] | htonl, htons, ntohl, ntohs—Convert Values between Host and Network Byte Order |
翻訳元
これは以下のページを翻訳したものです。
POS39-C. Use the correct byte ordering when transferring data between systems (revision 39)