gpt4 book ai didi

c - 这个 BitTorrent 客户端的片段验证过程中的错误在哪里?

转载 作者:太空宇宙 更新时间:2023-11-04 04:04:40 25 4
gpt4 key购买 nike

我一直在利用业余时间用 C 编写 BitTorrent 客户端。然而——似乎是随机的——我的客户将无法验证收到的 torrent 片段与消息是否正确:

Failed to verify piece: #4

背景:一个 .torrent 文件包含要下载的文件的相关元数据,包括每个片段的 SHA1 哈希值(要下载的文件的一个 block ),所以 -- 下载完一个piece -- 我获取它的 SHA1 哈希值并将其与 torrent 元数据文件提供的哈希值进行比较。

这是处理验证的代码:

 int verify_piece (void* addr, uint64_t piece_length, unsigned char* piece_sha)
{
SHA_CTX sha;
unsigned char sha1result[20];

SHA1_Init(&sha);
SHA1_Update(&sha, addr, piece_length);
SHA1_Final(sha1result, &sha);

if (memcmp(sha1result, piece_sha, 20)) {
printf("Expected: ");
print_sha1(piece_sha);
printf("Received: ");
print_sha1(sha1result);
return 0;
} else
return 1;
}

为了找出错误,我设置了两个函数:write_incorrect_piece()write_correct_piece()。第一个函数 write_incorrect_piece()verify_piece() 失败时被调用。它将验证失败的部分写入文件,以便我可以使用 hexdump 检查它。

 void write_incorrect_piece (void* piece, uint32_t piece_length, uint32_t index)
{
FILE* failed_piece = fopen("failed_piece.out", "w+");

write(fileno(failed_piece), piece, piece_length);
fclose(failed_piece);
printf("ERROR: Wrote piece #%d to failed_piece.out for inspection with hexdump.\n",
index);

write_correct_piece(piece_length, index);
exit(1);
}

如您所见,write_incorrect_piece() 接受参数void* piece,这是一个指向未通过验证的片段的指针,uint32_t piece_length,这是片段的长度,uint32_t index,这是未通过验证的片段的索引。然后它将不正确的片段复制到名为 failed_piece.out 的文件中。

您会注意到,在调用 exit() 之前,write_incorrect_piece() 调用了函数 write_correct_piece()。这是我为帮助调试此错误而编写的第二个函数。它采用 torrent 客户端尝试下载的文件的已知良好版本 (known_good.iso),然后将相关片段复制到文件 (correct_piece.out),以便我可以将其与包含错误片段的文件进行比较。

void write_correct_piece (uint32_t piece_length, uint32_t index)
{
FILE* known_good = fopen("known_good.iso", "r+");
FILE* correct_piece = fopen("correct_piece.out", "w+");

/* get file size for MMAPing */
struct stat st;
stat("known_good.iso", &st);
long size = st.st_size;

void* addr = mmap(0,
size,
PROT_READ | PROT_WRITE,
MAP_SHARED,
fileno(known_good),
0);

write(fileno(correct_piece), addr + piece_length * index, piece_length);
munmap(addr, size);
fclose(known_good);
fclose(correct_piece);
}

然后我把两个写入的文件用 hexdump 格式化,这样输出就可以被人类阅读,然后尝试通过 diff 比较它们,就像这样

$ hexdump failed_piece.out > failed_piece.dump
$ hexdump correct_piece.out > correct_piece.dump
$ diff correct_piece.dump failed_piece.dump

令我惊讶的是,diff 没有输出任何东西。这些文件完全相同。那么,为什么该片段的 SHA1 哈希与 torrent 文件预期的不同?也许,我当时想,元数据文件中的 SHA1 散列值是不正确的。如果是这样的话,我希望客户端总是无法验证第 4 部分,因此我修改了 torrent 客户端的调度程序,使其仅尝试下载第 4 部分以查看它是否确实如此,事实上,总是验证失败。

Successfully downloaded piece: #4

什么鬼?现在我陷入了僵局。我认为有几种不同的原因可能导致此问题:

  • 在客户端的网络代码中确实存在一个错误,但我在write_incorrect_piece()write_correct_piece() 中引入了一个错误,因此无论怎样它都会生成两个相同的文件输入的完整性。
  • verify_piece() 中存在错误,导致它偶尔会失败。
  • 我没有考虑到一些事情。

然而,就我的生活而言,我找不到上述任何代码的任何问题,所以我希望你们这些好人能指出我遗漏的地方。

客户端的完整源代码在https://github.com/robertseaton/slug。 .

编辑:将 verify_piece() 中的 strncmp() 替换为 memcmp() 并清理了 write_incorrect_piece()write_correct_piece()

编辑:这是一个失败片段的 SHA1 散列示例,当我手动比较它时它看起来是正确的。如您所见,哈希值根本不相似:

Expected: 239 66 216 164 16 120 73 24 1 236 116 173 144 85 243 152 160 165 64 231 
Received: 214 94 49 185 54 159 255 201 214 137 102 23 223 76 102 138 89 94 154 69
Failed to verify piece: #13

最佳答案

好的,如果我们看一下 verify_piece() 的调用,我们会看到:

 if (verify_piece(p->torrent->mmap + index * p->torrent->piece_length,
p->torrent->piece_length, p->torrent->pieces[index].sha1)) {

现在,很简单,我们知道第一个和第二个参数是正确的,因为它稍后在程序调用 write_incorrect_piece() 时被重用,并且我们已经验证了它的输出是正确的。因此,我们可以自由地关注第三个参数,p->torrent->pieces[index].sha1

乍一看,参数看起来是正确的,因为我们在整个函数中使用了 index。但是,考虑一下,如果 index —— 虽然在正确排序的数组上完全有效 —— 被用作不再包含假定顺序的片段的数组的索引怎么办?

中提琴!这是罪魁祸首(在 __schedule() 中):

qsort(t->pieces, t->num_pieces, sizeof(struct Piece), rarest);

注释掉对 qsort() 的调用,客户端按预期运行。

关于c - 这个 BitTorrent 客户端的片段验证过程中的错误在哪里?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7572656/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com