web で公開しているファイル群を BitTorrent で配布するにはのつづき.
前の記事で書いたように BitTorrent の metainfo ファイルを作り,Vuze でのダウンロードに成功したように見えたのだが,問題が見つかった.400 点弱のファイル群を 1 つの metainfo で配布しようとしたのだが,何度試してもある piece でダウンロードが停止してしまい,以降の piece はどれもダウンロードされなかった.Vuze のログを見たところ「IP Filters」でブロックされてしまっていた.デフォルト設定では「Block peers that consistently send bad data」するようになっており,これによって web server が peer としてブロックされていたようだ.「Tools」---「IP Filters」メニューで示される「Blocked IPs」ウィンドウ中の「IPs that have sent bad data - banned if limits exceeded」に web server が加えられていた.
なぜ不正なデータを送っていると見なされたのだろうか.Vuze Forums: Problems with http seeded torrents ... によると,SHA1 ハッシュ値が合致しないとそう扱われるとある.
ファイルに問題があるのかと考え,ls -1
を ls -1r
に替えてファイル順を逆にして metainfo を生成してみた.その結果,まったく同じ位置の piece から後がダウンロードされなかった.このことから,ファイルに問題はないと考えた.
また,おもしろい現象があった.Buildtorrent は -L
オプションの引数で piece の大きさを 2引数 bytes に指定できる.これを 17 と 20 にして試したところ,17 では 16384 番とその後の piece が,20 では 2048 番とその後がダウンロードできなかった.つまり,丁度 2 Gbytes = 231 bytes までしかダウンロードできなかった.このファイル群とは別のファイル群でも試した.合計 2 GB 未満のファイル群 2 点はいずれもダウンロードできた.合計 2 GB を超えるファイル群 2 点はいずれも丁度 2 GB となる piece までしかダウンロードできなかった.
Buildtorrent で生成した metainfo 中のハッシュ値が誤っているのだろうか.別の方法でハッシュ値を計算して比較してみよう.metainfo 中では,全ファイルをリストされる順序に連結したものを piece 長に切り分けたものに対する binary SHA1 ハッシュ値 20 bytes を piece 順に連結したものが格納される.以下の 2 つのプログラムを書いた.
#!/bin/bash
piecesize=262144
if [ $# -lt 1 ]; then
echo "Usage: $0 file ..." >&2
exit 1
fi
totallength=`cat "$@" | wc -c`
numberpieces=`expr ${totallength} / ${piecesize}`
for (( cursor=0; cursor<=${numberpieces}; cursor++ ))
do
cursorbyte=`expr ${cursor} '*' ${piecesize}`
cat "$@" ¥
| tail -c `expr ${totallength} - ${cursor} '*' ${piecesize}` ¥
| head -c "${piecesize}" ¥
| openssl dgst -binary -sha1
done
もちろんこの bash のコードは効率が悪い.
#!/usr/bin/perl -w
use strict;
use Digest::SHA1 qw(sha1);
my @files = @ARGV;
my $size = 2**18;
my $carryover;
foreach my $file ( @files ) {
open( FILE, "< $file" ) or next;
while( my $length = read( FILE, my $piece, ( $carryover? $size - length( $carryover ): $size ) ) ) {
$carryover and $piece = $carryover . $piece;
undef( $carryover );
if ( length( $piece ) < $size ) {
$carryover = $piece;
last;
}
print sha1( $piece );
}
close( FILE ) or die;
}
$carryover and print sha1( $carryover );
perl モジュール Digest::SHA1 での計算結果は,Buildtorrent のものと等しかった.bash から呼んだ openssl dgst での計算結果も等しかった.
また,ついでだが,Buildtorrent で必須とされているためダミーの値を与えていた Announce URL は,生成した metainfo を sed 's|8:announce30:dht://trackerless.dht/announce||'
して除去できることがわかった.metainfo ファイルは bencode (びーえんこーど) されている.