さて、前回記事では、Cでの setsocopt 関数の optval にはRubyの同メソッドからオプションのデータを渡した際には文字列データを渡していることまでを確認した。では、Cの仕様としては指定の構造体を渡すところで、なぜ文字列でも問題ないのか、本当に問題ないのか、といったあたりを探っていこうと思う。
まずは、文字列データを渡しても本当に良いのかということを確認するため、Cで構造体を渡すときと、文字列データを渡すときとで動作の違いを確認しようと思う。setsocopt はシステムコールなので、Cの関数で実行されたら最終的にはシステムコールとして実行されるはずだ。
そこで、両者を実行し、 strace コマンドで実行されるシステムコールの内容を比べてみることとした。
まずは普通に packet_mreq
構造体で実行するパターンで用意し、 strace sudo ./soc
のように strace 付きでプログラムを実行する。
sock = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); struct packet_mreq mreq; mreq.mr_ifindex = 2; // eth0 mreq.mr_type = PACKET_MR_PROMISC; // 1 mreq.mr_alen = 0; mreq.mr_address[0] ='\0'; setsockopt(sock, SOL_PACKET, PACKET_ADD_MEMBERSHIP, mreq, sizeof(mreq));
すると、以下のシステムコールが確認できた。
setsockopt(3, SOL_PACKET, PACKET_ADD_MEMBERSHIP, {mr_ifindex=if_nametoindex("eth0"), mr_type=PACKET_MR_PROMISC, mr_alen=0, mr_address=}, 16) = 0
次に代わりに以下のような文字列データを用意する。内容、サイズとも packet_mreq
構造体で指定したものの、上の要素から順番に並べたものだ。前回記事でRubyのソース中で printf で確認した内容と同じものと言っても良い。
char mreq2[16] = {3, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; setsockopt(sock, SOL_PACKET, PACKET_ADD_MEMBERSHIP, mreq2, sizeof(mreq2));
strace 付きで実行すると、以下の内容が確認できた。 packet_mreq
構造体で指定した内容と全く同じであった!
setsockopt(3, SOL_PACKET, PACKET_ADD_MEMBERSHIP, {mr_ifindex=if_nametoindex("eth0"), mr_type=PACKET_MR_PROMISC, mr_alen=0, mr_address=}, 16) = 0
これにより、 setsockopt では optval に構造体で指定したときでも、文字列データで指定したときでも同じ結果が得られると確認できた。
しかし、それは任意のオプションのときにも言えることなのだろうか?( PACKET_ADD_MEMBERSHIP
の時だけでは無いだろうか?)
なぜ、文字列データでも問題ないのだろうか?
長くなってきたので、続きは次回に。