POSIX::Socketのテストがこける理由

Monoceros等で利用される POSIX::Socketのテストが
こける理由のメモ. RTに登録すべきなんだろうけど、手元の環境ではうまくいかないので
ここにメモっておきます(サーバサイドの問題??).

問題となるテスト

t/10send.tの 2つめのテストが通りません(#2となっているテスト)

sub setsockopt_test($) {
  my ($buflen) = @_;
  my $sock;
  my $ret;

  $sock = _socket(AF_INET, SOCK_DGRAM, 0) or die "socket: $!\n";
  my $rv1 = _setsockopt($sock, SOL_SOCKET, SO_RCVBUF, pack("L", $buflen));
  my $rv2 = _getsockopt($sock, SOL_SOCKET, SO_RCVBUF, $ret, 4);
  _close($sock);
  
  return (($rv1 != -1) && ($rv2 != -1) && (unpack("L", $ret) == $buflen*2));
}

# 2
ok(setsockopt_test("1000"), "setsockopt/getsockopt test");

問題 1

subsockopt_testの returnの最後の式を見ると, setsockopt(SO_RCVBUF)で設定した値の
2倍の値が getsockoptで取得できることになっていますが、これがまず問題です. 2倍の値を
返すのは Linuxの仕様であり, FreeBSD等他の OSではそのような仕様ではなく,
setsockopt(SO_RCVBUF)で設定したバッファ長がそのまま返ります. なので 2倍の値が返って
くることを期待するのは, Linux以外の環境で動作させる場合良くないでしょう.

問題 2

setsockopt(SO_RCVBUF)に指定するバッファ長が短すぎる問題です.
Linuxのコードを確認したところ, setsockopt(SO_RCVBUF)で設定できる値には
下限があります(procfs等で変更できるかと思われますが, 未確認). 下限以下の
値を設定した場合, それは無視され下限の値の 2倍の値が getsockopt(SO_RCVBUF)で
返ることになります. デフォルトでは下限の値は 1000より大きいので, getsockoptから
返る値は 1000でも 2000でもない値となっています. なので数十KB等のサイズに
するのが妥当でしょう(下限の値をあらかじめチェックするというのが本当は
良いと思います).


問題 1だけでは Linuxはパスしますが, 問題 2もあり, 大半の環境でテストを
パスしないという事態になっているという次第です. Linux::Socketだったら
まああれなんでしょうけど, POSIX::となっているので気になりました.

おわりに

github等にコードが置いてないとレポートがめんどくさいので
なんとかならないものでしょうか・・・。