UnboundのJavaによるプロトタイプ実装をビルドする。

UnboundはJavaでプロトタイピングした後に、Cで書き直す等という凄いプロセスを経て実装されたリゾルバです。
きっととんでもなくハイパフォーマンスなのでしょう。僕としては少々悲しいですが。
プロトタイプを作る為の環境としてのJavaってそんなに使い易いとも思えないのですけども…。
いきなりCのコードをガツガツ読んだりすると、魂が燃え尽きたりする危険があるので、
使い慣れたJavaのコードをまずは読みます。

どうやらdnsjavaと言うプロダクトをどうこうして作った様です。
Unboundのプロトタイプが参照しているdnsjavaのバージョンは、2.0ですが、
本家では、2.0.8がリリースされています。


プロトタイプも公開リポジトリ上に置かれています。色々な意味でフェアですね。

svn co http://svn.verisignlabs.com/unbound/proto/trunk unbound-prototype

build.xmlがあるのでapache-antを使ってビルドします。
Javaに関連する僕の環境は、SUNというかOracleJavaをインストールしています。gcjではありません。

java version "1.6.0_21"
Java(TM) SE Runtime Environment (build 1.6.0_21-b06)
Java HotSpot(TM) 64-Bit Server VM (build 17.0-b16, mixed mode)

apache-antは、apache-ant-1.8.1を使っています。

ant

いい感じにエラーが出ますね。互換性の問題の様です。
j2sdk1.4で実装されていたのでしょう。java6になって、
sun.net.spi.nameservice.NameServiceと言うインターフェースのシグネチャが変わっている様です。

dnsjava:
    [javac] /home/taichi/tmp/unbound-prototype/build.xml:75: warning: 'includeantruntime' was not set, defaulting to build.sysclasspath=last; set to false for repeatable builds
    [javac] Compiling 1 source file to /home/taichi/tmp/unbound-prototype/build/classes
    [javac] /home/taichi/tmp/unbound-prototype/dnsjava/org/xbill/DNS/spi/DNSJavaNameService.java:24: 警告:sun.net.spi.nameservice.NameService は Sun が所有する API であり、今後のリリースで削除される可能性があります。
    [javac] public class DNSJavaNameService implements NameService {
    [javac]                                            ^
    [javac] /home/taichi/tmp/unbound-prototype/dnsjava/org/xbill/DNS/spi/DNSJavaNameService.java:24: org.xbill.DNS.spi.DNSJavaNameService は abstract でなく、sun.net.spi.nameservice.NameService 内の abstract メソッド lookupAllHostAddr(java.lang.String) をオーバーライドしません。
    [javac] public class DNSJavaNameService implements NameService {
    [javac]        ^
    [javac] /home/taichi/tmp/unbound-prototype/dnsjava/org/xbill/DNS/spi/DNSJavaNameService.java:81: org.xbill.DNS.spi.DNSJavaNameService の lookupAllHostAddr(java.lang.String) は sun.net.spi.nameservice.NameService の lookupAllHostAddr(java.lang.String) を実装できません。互換性のない戻り値の型を使おうとしました。
    [javac] 検出値  : byte[][]
    [javac] 期待値  : java.net.InetAddress[]
    [javac] lookupAllHostAddr(String host) throws UnknownHostException {
    [javac] ^
    [javac] エラー 2 個
    [javac] 警告 1 個

当該部分のコードを抜き出してみます。

public byte [][]
lookupAllHostAddr(String host) throws UnknownHostException {
	Name name = null;

	try {
		name = new Name(host);
	}
	catch (TextParseException e) {
		throw new UnknownHostException(host);
	}

	Record [] records = null;
	if (preferV6)
		records = new Lookup(name, Type.AAAA).run();
	if (records == null)
		records = new Lookup(name, Type.A).run();
	if (records == null && !preferV6)
		records = new Lookup(name, Type.AAAA).run();
	if (records == null)
		throw new UnknownHostException(host);

	byte[][] array = new byte[records.length][];
	for (int i = 0; i < records.length; i++) {
		Record record = records[i];
		if (records[i] instanceof ARecord) {
			ARecord a = (ARecord) records[i];
			array[i] = a.getAddress().getAddress();
		} else {
			AAAARecord aaaa = (AAAARecord) records[i];
			array[i] = aaaa.getAddress().getAddress();
		}
	}
	return array;
}

java6に含まれているインターフェースのシグネチャを抜き出してみます。

public abstract java.net.InetAddress[] lookupAllHostAddr(java.lang.String arg0) throws java.net.UnknownHostException;

きっとおかしいのは直接的にはこの辺でしょう。

array[i] = a.getAddress().getAddress();
array[i] = aaaa.getAddress().getAddress();

念の為、ARecord#getAddressを確認します。
どうもインデントが不可思議なのがさっきから気になっていますが無視します。

public InetAddress
getAddress() {
	try {
		return InetAddress.getByAddress(toArray(addr));
	} catch (UnknownHostException e) {
		return null;
	}
}

どういう状態なのか分かったので、コードを修正します。

public InetAddress[]
lookupAllHostAddr(String host) throws UnknownHostException {
	Name name = null;

	try {
		name = new Name(host);
	}
	catch (TextParseException e) {
		throw new UnknownHostException(host);
	}

	Record [] records = null;
	if (preferV6)
		records = new Lookup(name, Type.AAAA).run();
	if (records == null)
		records = new Lookup(name, Type.A).run();
	if (records == null && !preferV6)
		records = new Lookup(name, Type.AAAA).run();
	if (records == null)
		throw new UnknownHostException(host);

	InetAddress[] array = new InetAddress[records.length];
	for (int i = 0; i < records.length; i++) {
		Record record = records[i];
		if (records[i] instanceof ARecord) {
			ARecord a = (ARecord) records[i];
			array[i] = a.getAddress();
		} else {
			AAAARecord aaaa = (AAAARecord) records[i];
			array[i] = aaaa.getAddress();
		}
	}
	return array;
}
ant

エラー箇所を修正したので、antによるビルドも若干の互換性に関連したワーニングは出力されますが、正常終了します。

ls -lR build/lib
-rw-rw-r--. 1 taichi taichi 188726 2010-08-04 20:37 dnsjava-unbound.jar
-rw-rw-r--. 1 taichi taichi 116210 2010-08-04 20:10 unbound-prototype.jar

jarファイルが二つばかしビルドの結果出力されていますね。