libnet.so

10/08の続き。
作成したnative libraryはロードできてアプリケーションも動作するようになったが、何故か起動時にエラーになる環境もある。
エラーログを見ると、libnet.soをロードしているところでSEGVが発生していた。
libnet.soは、java.net.*のnative libraryで、今回作成したnative libraryからリンクしている。

 $(CC) -shared $(NATIVE_OBJS) -L$(JDK_HOME)/jre/lib/i386 -lnet -ljava -o $@

JDKのソースを読んで、SEGVしている場所がわかった。
$JDK16_SOURCE/j2se/src/solaris/native/java/net/net_util_md.cの中にあるinitLocalIfs()関数は、二回呼び出されると、二度目に呼んだとき必ずSEGVが起きる。(Linuxの場合のみ)
この関数はnative libraryをロードしたときに自動的に呼び出されるJNI_OnLoad()の中から呼ばれるようになっている。Javaの起動時点で一度呼び出され、その後、作成したnative libraryをロードしたときに、リンクしているlibnet.soが再度ロードされるのでSEGVするようになってしまった。

libnet.soはJava Native Interfaceの範囲外だから、リンクして使用することが間違っていると言われればそれまでだが、これを使用しないでネットワーク関係のnative libraryを実装するのも難しい。
簡単な対処方法は見つかった。initLocalIfs()の最初のところで以下のように/proc/net/if_inet6をopenできなければ処理を実行せずにreturnしているので、OSレベルでIPv6を無効にすればSEGVしなくなる筈。

    if ((f = fopen("/proc/net/if_inet6", "r")) == NULL) {
	return ;
    }