std::string Cmerkle_tree::compute_root(const_memory_range r) { typedef std::map<int, std::string> t_map; t_map map; char d[1025]; for (; r.size(); r += 1024) { *d = 0; memcpy(d + 1, r, min(r.size(), 1024)); std::string h = Csha1(const_memory_range(d, min(r.size(), 1024) + 1)).read(); *d = 1; int i; for (i = 0; map.find(i) != map.end(); i++) { memcpy(d + 1, map.find(i)->second.c_str(), 20); memcpy(d + 21, h.c_str(), 20); h = Csha1(const_memory_range(d, 41)).read(); map.erase(i); } map[i] = h; } *d = 1; while (map.size() > 1) { memcpy(d + 21, map.begin()->second.c_str(), 20); map.erase(map.begin()); memcpy(d + 1, map.begin()->second.c_str(), 20); map.erase(map.begin()); map[0] = Csha1(const_memory_range(d, 41)).read(); } return map.empty() ? "" : map.begin()->second; }
std::string internal_hash(const_memory_range a, const_memory_range b) { assert(a.size() == 20); assert(b.size() == 20); char d[41]; *d = 1; memcpy(d + 1, a, 20); memcpy(d + 21, b, 20); return Csha1(const_memory_range(d, 41)).read(); }
long long Ctransaction::connection_id() const { const int cb_s = 12; char s[cb_s]; write_int(8, s, m_server.secret()); write_int(4, s + 8, m_a.sin_addr.s_addr); char d[20]; (Csha1(data_ref(s, cb_s))).read(d); return read_int(8, d); }
t_user* find_user_by_torrent_pass(str_ref v, str_ref info_hash) { if (v.size() != 32) return NULL; if (t_user* user = find_user_by_uid(read_int(4, hex_decode(v.substr(0, 8))))) { if (Csha1((boost::format("%s %d %d %s") % m_config.m_torrent_pass_private_key % user->torrent_pass_version % user->uid % info_hash).str()).read().substr(0, 12) == hex_decode(v.substr(8, 24))) return user; } return find_ptr2(m_users_torrent_passes, to_array<char, 32>(v)); }
void Cdlg_make_torrent::OnSave() { if (!UpdateData()) return; m_name.TrimRight(" "); m_tracker.TrimRight(" "); CFileDialog dlg(false, "torrent", m_name + ".torrent", OFN_ENABLESIZING | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST, "Torrents|*.torrent|", this); if (IDOK != dlg.DoModal()) return; CWaitCursor wc; AfxGetApp()->WriteProfileString(m_strRegStore, "tracker", m_tracker); AfxGetApp()->WriteProfileString(m_strRegStore, "trackers", m_trackers); AfxGetApp()->WriteProfileInt(m_strRegStore, "use_merkle", m_use_merkle); int cb_piece = 1 << 20; if (!m_use_merkle) { long long cb_total = 0; for (t_map::const_iterator i = m_map.begin(); i != m_map.end(); i++) cb_total += i->second.size; cb_piece = 256 << 10; while (cb_total / cb_piece > 4 << 10) cb_piece <<= 1; } typedef std::set<std::string> t_set; t_set set; for (t_map::const_iterator i = m_map.begin(); i != m_map.end(); i++) set.insert(i->second.name); Cbvalue files; std::string pieces; Cvirtual_binary d; byte* w = d.write_start(cb_piece); for (t_set::const_iterator i = set.begin(); i != set.end(); i++) { int f = open(i->c_str(), _O_BINARY | _O_RDONLY); if (!f) continue; long long cb_f = 0; std::string merkle_hash; int cb_d; if (m_use_merkle) { typedef std::map<int, std::string> t_map; t_map map; char d[1025]; while (cb_d = read(f, d + 1, 1024)) { if (cb_d < 0) break; *d = 0; std::string h = Csha1(const_memory_range(d, cb_d + 1)).read(); *d = 1; int i; for (i = 0; map.find(i) != map.end(); i++) { memcpy(d + 1, map.find(i)->second.c_str(), 20); memcpy(d + 21, h.c_str(), 20); h = Csha1(const_memory_range(d, 41)).read(); map.erase(i); } map[i] = h; cb_f += cb_d; } *d = 1; while (map.size() > 1) { memcpy(d + 21, map.begin()->second.c_str(), 20); map.erase(map.begin()); memcpy(d + 1, map.begin()->second.c_str(), 20); map.erase(map.begin()); map[0] = Csha1(const_memory_range(d, 41)).read(); } if (!map.empty()) merkle_hash = map.begin()->second; } else { while (cb_d = read(f, w, d.end() - w)) { if (cb_d < 0) break; w += cb_d; if (w == d.end()) { pieces += Csha1(const_memory_range(d, w - d)).read(); w = d.data_edit(); } cb_f += cb_d; } } close(f); files.l(merkle_hash.empty() ? Cbvalue().d(bts_length, cb_f).d(bts_path, Cbvalue().l(base_name(*i))) : Cbvalue().d(bts_merkle_hash, merkle_hash).d(bts_length, cb_f).d(bts_path, Cbvalue().l(base_name(*i)))); } if (w != d) pieces += Csha1(const_memory_range(d, w - d)).read(); Cbvalue info; info.d(bts_piece_length, cb_piece); if (!pieces.empty()) info.d(bts_pieces, pieces); if (m_map.size() == 1) { if (m_use_merkle) info.d(bts_merkle_hash, files.l().front()[bts_merkle_hash]); info.d(bts_length, files.l().front()[bts_length]); info.d(bts_name, files.l().front()[bts_path].l().front()); } else { info.d(bts_files, files); info.d(bts_name, static_cast<std::string>(m_name)); } Cbvalue torrent; torrent.d(bts_announce, static_cast<std::string>(m_tracker)); if (!m_trackers.IsEmpty()) torrent.d(bts_announce_list, parse_trackers(static_cast<std::string>(m_trackers))); torrent.d(bts_info, info); Cvirtual_binary s = torrent.read(); if (m_use_merkle) s = gzip(s); s.save(static_cast<std::string>(dlg.GetPathName())); m_torrent_fname = dlg.GetPathName(); EndDialog(IDOK); }
int main(int argc, char* argv[]) { time_t t = time(NULL); if (argc < 2) { std::cerr << "Usage: " << argv[0] << " <file> <tracker> [--v1]" << std::endl; return 1; } std::string tracker = argc >= 3 ? argv[2] : "udp://localhost:2710"; bool use_merkle = argc >= 4 ? strcmp(argv[3], "--v1") : true; // set to false for a non-merkle torrent insert(argv[1]); // use 1 mbyte pieces by default int cb_piece = 1 << 20; if (!use_merkle) { // find optimal piece size for a non-merkle torrent long long cb_total = 0; for (t_map::const_iterator i = g_map.begin(); i != g_map.end(); i++) cb_total += i->second.size; cb_piece = 256 << 10; while (cb_total / cb_piece > 4 << 10) cb_piece <<= 1; } Cbvalue files; std::string pieces; Cvirtual_binary d; byte* w = d.write_start(cb_piece); for (t_map::const_iterator i = g_map.begin(); i != g_map.end(); i++) { int f = open(i->second.name.c_str(), O_BINARY | O_RDONLY); if (!f) continue; long long cb_f = 0; std::string merkle_hash; int cb_d; if (use_merkle) { // calculate merkle root hash as explained in XBT Make Merkle Tree.cpp typedef std::map<int, std::string> t_map; t_map map; char d[1025]; while (cb_d = read(f, d + 1, 1024)) { if (cb_d < 0) break; *d = 0; std::string h = Csha1(const_memory_range(d, cb_d + 1)).read(); *d = 1; int i; for (i = 0; map.find(i) != map.end(); i++) { memcpy(d + 1, map.find(i)->second.c_str(), 20); memcpy(d + 21, h.c_str(), 20); h = Csha1(const_memory_range(d, 41)).read(); map.erase(i); } map[i] = h; cb_f += cb_d; } *d = 1; while (map.size() > 1) { memcpy(d + 21, map.begin()->second.c_str(), 20); map.erase(map.begin()); memcpy(d + 1, map.begin()->second.c_str(), 20); map.erase(map.begin()); map[0] = Csha1(const_memory_range(d, 41)).read(); } if (!map.empty()) merkle_hash = map.begin()->second; } else { // calculate piece hashes while (cb_d = read(f, w, d.data_end() - w)) { if (cb_d < 0) break; w += cb_d; if (w == d.data_end()) { pieces += Csha1(const_memory_range(d, w - d)).read(); w = d.data_edit(); } cb_f += cb_d; } } close(f); // add file to files key files.l(merkle_hash.empty() ? Cbvalue().d(bts_length, cb_f).d(bts_path, Cbvalue().l(base_name(i->second.name))) : Cbvalue().d(bts_merkle_hash, merkle_hash).d(bts_length, cb_f).d(bts_path, Cbvalue().l(base_name(i->second.name)))); } if (w != d) pieces += Csha1(const_memory_range(d, w - d)).read(); Cbvalue info; info.d(bts_piece_length, cb_piece); if (!pieces.empty()) info.d(bts_pieces, pieces); if (g_map.size() == 1) { // single-file torrent if (use_merkle) info.d(bts_merkle_hash, files.l().front().d(bts_merkle_hash)); info.d(bts_length, files.l().front().d(bts_length)); info.d(bts_name, files.l().front().d(bts_path).l().front()); } else { // multi-file torrent info.d(bts_files, files); info.d(bts_name, g_name); } Cbvalue torrent; torrent.d(bts_announce, tracker); torrent.d(bts_info, info); Cvirtual_binary s = torrent.read(); if (use_merkle) s = gzip(s); s.save(g_name + ".torrent"); std::cout << time(NULL) - t << " s" << std::endl; return 0; }
bool Cbt_hasher::run(Cbt_file& f) { if (m_i >= f.m_pieces.size()) return false; if (!m_i) m_sub_file = f.m_sub_files.begin(); Cbt_piece& piece = f.m_pieces[m_i]; Cvirtual_binary d; if (m_validate) { if (f.m_merkle) { bool root_valid = m_sub_file->merkle_tree().root().string() == m_sub_file->merkle_hash(); d.write_start(piece.size()); piece.valid(!f.read_data(f.mcb_piece * m_i, d)); for (const byte* r = d; r < d.end(); r += 0x8000) { std::string h = Cmerkle_tree::compute_root(const_memory_range(r, std::min(r + 0x8000, d.end()))); if (root_valid) { if (piece.valid() && (!m_sub_file->merkle_tree().has(m_j) || h != m_sub_file->merkle_tree().get(m_j).string())) piece.valid(false); } else m_sub_file->merkle_tree().set(m_j, h); m_j++; } } else { d.write_start(piece.size()); piece.valid(!f.read_data(f.mcb_piece * m_i, d) && !memcmp(Csha1(d).read().data(), piece.m_hash, 20)); } } if (!piece.valid()) f.m_left += piece.size(); int cb0 = piece.size(); while (cb0) { int cb1 = min(cb0, m_sub_file->size() - m_offset); if (!piece.valid()) m_sub_file->left(m_sub_file->left() + cb1); cb0 -= cb1; m_offset += cb1; if (m_offset == m_sub_file->size()) { if (f.m_merkle && m_sub_file->merkle_tree().root().string() != m_sub_file->merkle_hash()) { Cbt_piece* piece = &f.m_pieces.front() + m_sub_file->offset() / f.mcb_piece; for (int i = 0; i < m_sub_file->c_pieces(f.mcb_piece); i++) { if (piece->valid()) f.m_left += piece->size(); piece->valid(false); piece++; } m_sub_file->left(m_sub_file->size()); m_sub_file->merkle_tree().invalidate(); m_sub_file->merkle_tree().root(m_sub_file->merkle_hash()); } if (!m_sub_file->left()) { m_sub_file->close(); m_sub_file->open(f.m_name, O_RDONLY); } m_j = 0; m_offset = 0; m_sub_file++; } } m_i++; return true; }