为什么我从对等端接收的数据与预期输出不匹配?

时间:2011-09-18 17:07:22

标签: c hex bittorrent

在业余时间,我一直致力于在C中实现BitTorrent客户端。目前它与跟踪器通信,连接到群,从对等端请求torrent文件,并接收torrent文件的各个部分。但是,当要验证收到的片段是否正确时(通过获取SHA1哈希值并将其与.torrent元数据中提供的哈希值进行比较),它总是会失败。

为了调试这个,我下载了一个带有已知工作BitTorrent客户端的torrent,然后修改了我自己的BitTorrent实现来请求和下载torrent的第一部分(第一部分)。然后我将这两个文件与Emacs的hexl-mode进行了比较。

已知的好处:

00000000: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000010: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000020: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000030: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000040: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000050: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000060: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000070: 0000 0000 0000 0000 0000 0000 0000 0000  ................
...
00008000: 0143 4430 3031 0100 4c49 4e55 5820 2020  .CD001..LINUX   
00008010: 2020 2020 2020 2020 2020 2020 2020 2020                  
00008020: 2020 2020 2020 2020 5562 756e 7475 2031          Ubuntu 1
00008030: 312e 3034 2069 3338 3620 2020 2020 2020  1.04 i386

我的实施:

00000000: a616 f132 7f00 0080 5066 0000 0000 0080  ...2....Pf......
00000010: 5066 0000 0000 0060 3b62 0000 0000 0098  Pf.....`;b......
00000020: 3b62 0000 0000 00d0 3b62 0000 0000 0008  ;b......;b......
00000030: 3c62 0000 0000 0040 3c62 0000 0000 0078  <b.....@<b.....x
00000040: 3c62 0000 0000 00b0 3c62 0000 0000 00e8  <b......<b......
00000050: 3c62 0000 0000 0020 3d62 0000 0000 0058  <b..... =b.....X
00000060: 3d62 0000 0000 0090 3d62 0000 0000 00c8  =b......=b......
00000070: 3d62 0000 0000 0000 3e62 0000 0000 0038  =b......>b.....8
...
0000d000: 0243 4430 3031 0100 004c 0049 004e 0055  .CD001...L.I.N.U
0000d010: 0058 0020 0020 0020 0020 0020 0020 0020  .X. . . . . . . 
0000d020: 0020 0020 0020 0020 0055 0062 0075 006e  . . . . .U.b.u.n
0000d030: 0074 0075 0020 0031 0031 002e 0030 0034  .t.u. .1.1...0.4
0000d040: 0020 0069 0033 0038 0000 0000 0000 0000  . .i.3.8........

然后,我想,我必须将收到的文件写入不正确的偏移量,导致在文件中错误的位置出现正确的数据。为了验证这一点,我启动了gdb并在从对等端接收到它之后检查了第一块的开头,期望它包含所有零,就像已知良好文件的开头一样。

(gdb) break network.c:40
Breakpoint 1 at 0x402fe7: file network.c, line 40.
(gdb) run
Starting program: /home/robb/slug/slug 
[Thread debugging using libthread_db enabled]
[New Thread 0x7fffcb58d700 (LWP 12936)]
[Thread 0x7fffcb58d700 (LWP 12936) exited]
ANNOUNCE: 50 peers.
CONNECTED: 62.245.41.28
CONNECTED: 89.178.142.45
CONNECTED: 66.65.166.17
...
UNCHOKE: 95.26.0.1
Requested piece 0 from peer 95.26.0.1.
UNCHOKE: 202.231.116.163
PIECE: #0 from 95.26.0.1

Breakpoint 1, handle_piece (p=0x42d7e0) at network.c:41
41       memcpy(p->torrent->mmap + length, &p->message[9], REQUEST_LENGTH);
(gdb) p off
$1 = 0
(gdb) p index
$2 = 0
(gdb) p p->message[9]
$3 = 46 '.'
(gdb) p p->message[10]
$4 = 67 'C'
(gdb) p p->message[11]
$5 = 0 '\000'
(gdb) p p->message[12]
$6 = 0 '\000'
(gdb) p p->message[13]
$7 = 0 '\000'
(gdb) p p->message[14]
$8 = 0 '\000'
(gdb) p p->message[15]
$9 = 0 '\000'
(gdb) p p->message[16]
$10 = 128 '\200'
(gdb) p p->message[17]
$11 = 46 '.'
(gdb) p p->message[18]
$12 = 67 'C'

正如您所看到的,我从对等方收到的数据不包含所有零,例如已知良好文件的开头。为什么呢?

我的计划的完整来源是https://github.com/robertseaton/slug

2 个答案:

答案 0 :(得分:1)

这没有考虑到bufferevent_read可能会失败并返回负数:

void get_msg (struct bufferevent* bufev, struct Peer* p)
{
     uint64_t amount_read = p->message_length - p->amount_pending;
     int64_t message_length = bufferevent_read(bufev, &p->message[amount_read],  p->amount_pending);

替换为:

void get_msg (struct bufferevent* bufev, struct Peer* p)
{
 uint64_t amount_read = p->message_length - p->amount_pending;
 int64_t message_length = bufferevent_read(bufev, &p->message[amount_read], p->amount_pending);

 /* possible bufferevent_read found nothing */
 if (message_length < 0)
      message_length = 0;

答案 1 :(得分:0)

阅读我在network.c中找到的源代码:

memcpy(&index, &p->message[1], sizeof(index));
memcpy(&off, &p->message[5], sizeof(off));

index = ntohl(index);
off = ntohl(off);
length = index * p->torrent->piece_length + off;

#ifdef DEBUG
if (off == 0)
   printf("PIECE: #%d from %s\n", index, inet_ntoa(p->addr.sin_addr));
#endif

memcpy(p->torrent->mmap + length, &p->message[9], REQUEST_LENGTH);
p->torrent->pieces[index].amount_downloaded += REQUEST_LENGTH;

我认为最后两行是:

memcpy(p->torrent->mmap + length, &p->message[9], length);
p->torrent->pieces[index].amount_downloaded += length;

BTW REQUEST_LENGTH = 16K。 更可能这个“长度事物”应该是p-&gt; message_length,或者(p-&gt; message_length - 9)

另一个bug可能是strlen()+ 1类型的bug。