diff --git a/libtorrent/src/kademlia/node.cpp b/libtorrent/src/kademlia/node.cpp index ce5d006e..2715157c 100644 --- a/libtorrent/src/kademlia/node.cpp +++ b/libtorrent/src/kademlia/node.cpp @@ -1081,12 +1081,18 @@ void node_impl::incoming_request(msg const& m, entry& e) } // target id is hash of bencoded dict "target" - std::pair targetbuf = msg_keys[1]->data_section(); + std::pair targetbuf = msg_keys[mk_target]->data_section(); sha1_hash target = hasher(targetbuf.first,targetbuf.second).final(); - fprintf(stderr, "PUT target: %s = {%s,%s,%s}\n" +#ifdef TORRENT_DHT_VERBOSE_LOGGING + std::string target_str(targetbuf.first,targetbuf.second); + fprintf(stderr, "PUT target: %s = {%s,%s,%s} = '%s'\n" , to_hex(target.to_string()).c_str() - , msg_keys[mk_n], msg_keys[mk_r], msg_keys[mk_t]); + , msg_keys[mk_n]->string_value().c_str() + , msg_keys[mk_r]->string_value().c_str() + , msg_keys[mk_t]->string_value().c_str() + , target_str.c_str()); +#endif // verify the write-token. tokens are only valid to write to // specific target hashes. it must match the one we got a "get" for @@ -1111,8 +1117,8 @@ void node_impl::incoming_request(msg const& m, entry& e) return; } - if (!multi || !msg_keys[mk_seq] || msg_keys[mk_seq]->int_value() <= 0) { - incoming_error(e, "seq is required"); + if (!multi && (!msg_keys[mk_seq] || msg_keys[mk_seq]->int_value() <= 0)) { + incoming_error(e, "seq is required for single"); return; } @@ -1211,10 +1217,15 @@ void node_impl::incoming_request(msg const& m, entry& e) bool justtoken = false; if (msg_keys[mk_justtoken] && msg_keys[mk_justtoken]->int_value() != 0) justtoken = true; - fprintf(stderr, "GET target: %s = {%s,%s,%s}\n" +#ifdef TORRENT_DHT_VERBOSE_LOGGING + std::string target_str(targetbuf.first,targetbuf.second); + fprintf(stderr, "GET target: %s = {%s,%s,%s} = '%s'\n" , to_hex(target.to_string()).c_str() - , msg_keys[mk_n], msg_keys[mk_r], msg_keys[mk_t]); - + , msg_keys[mk_n]->string_value().c_str() + , msg_keys[mk_r]->string_value().c_str() + , msg_keys[mk_t]->string_value().c_str() + , target_str.c_str()); +#endif reply["token"] = generate_token(m.addr, target.to_string().c_str()); nodes_t n; diff --git a/libtorrent/test/test_dht.cpp b/libtorrent/test/test_dht.cpp index 0377c1f5..803e86db 100644 --- a/libtorrent/test/test_dht.cpp +++ b/libtorrent/test/test_dht.cpp @@ -44,6 +44,8 @@ POSSIBILITY OF SUCH DAMAGE. #include "test.hpp" #include "setup_transfer.hpp" +#include "../../src/twister.h" + using namespace libtorrent; using namespace libtorrent::dht; @@ -177,6 +179,252 @@ struct announce_item } }; + +void send_put_dht(node_impl& node, udp::endpoint const& ep + , lazy_entry* reply, char const* t + , char const* name, char const* resource, bool multi + , std::string const token + , entry const* value + , std::string const sig_user + , int seq = -1, int timeutc = 0, int height = 0) +{ + // we're about to clear out the backing buffer + // for this lazy_entry, so we better clear it now + reply->clear(); + entry e; + e["q"] = "putData"; + e["t"] = t; + e["z"] = "q"; + + entry::dictionary_type& a = e["x"].dict(); + a["id"] = generate_id(ep.address()).to_string(); + a["token"] = token; + + entry::dictionary_type& p = a["p"].dict(); + entry::dictionary_type& target = p["target"].dict(); + target["n"] = name; + target["r"] = resource; + target["t"] = (multi) ? "m" : "s"; + if (seq >= 0) p["seq"] = seq; + p["v"] = *value; + if (timeutc) p["time"] = timeutc; + if (height) p["height"] = height; + + std::vector pbuf; + bencode(std::back_inserter(pbuf), p); + std::string sig_p = createSignature(std::string(pbuf.data(),pbuf.size()), sig_user); + + a["sig_p"] = sig_p; + a["sig_user"] = sig_user; + + char msg_buf[1500]; + int size = bencode(msg_buf, e); +#if defined TORRENT_DEBUG && TORRENT_USE_IOSTREAM +// this yields a lot of output. too much +// std::cerr << "sending: " << e << "\n"; +#endif + //fprintf(stderr, "sending: %s\n", msg_buf); + + lazy_entry decoded; + error_code ec; + lazy_bdecode(msg_buf, msg_buf + size, decoded, ec); + if (ec) fprintf(stderr, "lazy_bdecode failed: %s\n", ec.message().c_str()); + + dht::msg m(decoded, ep); + node.incoming(m); + + // by now the node should have invoked the send function and put the + // response in g_responses + + std::list >::iterator i + = std::find_if(g_responses.begin(), g_responses.end() + , boost::bind(&std::pair::first, _1) == ep); + if (i == g_responses.end()) + { + TEST_ERROR("not response from DHT node"); + return; + } + + static char inbuf[1500]; + int len = bencode(inbuf, i->second); + g_responses.erase(i); + int ret = lazy_bdecode(inbuf, inbuf + len, *reply, ec); + TEST_CHECK(ret == 0); +} + +void send_get_dht(node_impl& node, udp::endpoint const& ep + , lazy_entry* reply, char const* t + , char const* name, char const* resource, bool multi + , bool justtoken = false) +{ + // we're about to clear out the backing buffer + // for this lazy_entry, so we better clear it now + reply->clear(); + entry e; + e["q"] = "getData"; + e["t"] = t; + e["z"] = "q"; + + entry::dictionary_type& a = e["x"].dict(); + a["id"] = generate_id(ep.address()).to_string(); + + entry::dictionary_type& target = a["target"].dict(); + target["n"] = name; + target["r"] = resource; + target["t"] = (multi) ? "m" : "s"; + + if (justtoken) a["justtoken"] = 1; + + char msg_buf[1500]; + int size = bencode(msg_buf, e); +#if defined TORRENT_DEBUG && TORRENT_USE_IOSTREAM +// this yields a lot of output. too much +// std::cerr << "sending: " << e << "\n"; +#endif + //fprintf(stderr, "sending: %s\n", msg_buf); + + lazy_entry decoded; + error_code ec; + lazy_bdecode(msg_buf, msg_buf + size, decoded, ec); + if (ec) fprintf(stderr, "lazy_bdecode failed: %s\n", ec.message().c_str()); + + dht::msg m(decoded, ep); + node.incoming(m); + + // by now the node should have invoked the send function and put the + // response in g_responses + + std::list >::iterator i + = std::find_if(g_responses.begin(), g_responses.end() + , boost::bind(&std::pair::first, _1) == ep); + if (i == g_responses.end()) + { + TEST_ERROR("not response from DHT node"); + return; + } + + static char inbuf[1500]; + int len = bencode(inbuf, i->second); + g_responses.erase(i); + int ret = lazy_bdecode(inbuf, inbuf + len, *reply, ec); + TEST_CHECK(ret == 0); +} + +void get_put_get(node_impl& node, udp::endpoint const* eps + , announce_item const* items, int num_items) +{ + std::string username("username"); + std::string resource("res"); + bool multi = false; + std::string sig_user("username"); + int seq=1; + + std::string token; + for (int i = 0; i < 1; ++i) + { + for (int j = 0; j < num_items; ++j) + { + //if ((i % items[j].num_peers) == 0) continue; + lazy_entry response; + send_get_dht(node, eps[i], &response, "10", + username.c_str(), resource.c_str(), multi, true); + + key_desc_t desc[] = + { + { "r", lazy_entry::dict_t, 0, key_desc_t::parse_children }, + { "id", lazy_entry::string_t, 20, 0}, + { "token", lazy_entry::string_t, 0, 0}, + { "ip", lazy_entry::string_t, 0, key_desc_t::optional | key_desc_t::last_child}, + { "z", lazy_entry::string_t, 1, 0}, + }; + + lazy_entry const* parsed[5]; + char error_string[200]; + + //fprintf(stderr, "msg: %s\n", print_entry(response).c_str()); + int ret = verify_message(&response, desc, parsed, 5, error_string, sizeof(error_string)); + if (ret) + { + TEST_EQUAL(parsed[4]->string_value(), "r"); + token = parsed[2]->string_value(); + //fprintf(stderr, "got token: %s\n", token.c_str()); + } + else + { + fprintf(stderr, "msg: %s\n", print_entry(response).c_str()); + fprintf(stderr, " invalid get response: %s\n", error_string); + TEST_ERROR(error_string); + } + + if (parsed[3]) + { + address_v4::bytes_type b; + memcpy(&b[0], parsed[3]->string_ptr(), b.size()); + address_v4 addr(b); + TEST_EQUAL(addr, eps[i].address()); + } + + send_put_dht(node, eps[i], &response, "10", + username.c_str(), resource.c_str(), multi, + token, &items[j].ent, sig_user, seq++, 1000, getBestHeight()); + + key_desc_t desc2[] = + { + { "z", lazy_entry::string_t, 1, 0 } + }; + + ret = verify_message(&response, desc2, parsed, 1, error_string, sizeof(error_string)); + if (ret) + { + if (parsed[0]->string_value() != "r") + fprintf(stderr, "msg: %s\n", print_entry(response).c_str()); + + TEST_EQUAL(parsed[0]->string_value(), "r"); + } + else + { + fprintf(stderr, "msg: %s\n", print_entry(response).c_str()); + fprintf(stderr, " invalid put response: %s\n", error_string); + TEST_ERROR(error_string); + } + } + } + + std::set items_num; + for (int j = 0; j < num_items; ++j) + { + lazy_entry response; + send_get_dht(node, eps[j], &response, "10", + username.c_str(), resource.c_str(), multi, false); + + key_desc_t desc[] = + { + { "r", lazy_entry::dict_t, 0, key_desc_t::parse_children }, + { "values", lazy_entry::list_t, 0, 0}, + { "id", lazy_entry::string_t, 20, key_desc_t::last_child}, + { "z", lazy_entry::string_t, 1, 0}, + }; + + lazy_entry const* parsed[4]; + char error_string[200]; + + int ret = verify_message(&response, desc, parsed, 4, error_string, sizeof(error_string)); + if (ret) + { + items_num.insert(items_num.begin(), j); + } + } + + TEST_EQUAL(items_num.size(), 8); + + // items_num should contain 1,2 and 3 + // #error this doesn't quite hold +// TEST_CHECK(items_num.find(1) != items_num.end()); +// TEST_CHECK(items_num.find(2) != items_num.end()); +// TEST_CHECK(items_num.find(3) != items_num.end()); +} + + void announce_immutable_items(node_impl& node, udp::endpoint const* eps , announce_item const* items, int num_items) { @@ -658,6 +906,9 @@ int test_main() #endif } + printf("\n\n\n*** get_put_get test ***\n"); + get_put_get(node, eps, items, sizeof(items)/sizeof(items[0])); + return 0; } @@ -670,7 +921,7 @@ int test_main() #endif -std::string createSignature(std::string &strMessage, std::string &strUsername) +std::string createSignature(std::string const &strMessage, std::string const &strUsername) { return std::string("signature!"); } diff --git a/src/twister.cpp b/src/twister.cpp index 20133703..386df728 100644 --- a/src/twister.cpp +++ b/src/twister.cpp @@ -188,7 +188,7 @@ void stopSessionTorrent() printf("libtorrent + dht stopped\n"); } -std::string createSignature(std::string &strMessage, std::string &strUsername) +std::string createSignature(std::string const &strMessage, std::string const &strUsername) { if (pwalletMain->IsLocked()) { printf("createSignature: Error please enter the wallet passphrase with walletpassphrase first.\n"); diff --git a/src/twister.h b/src/twister.h index c4afb8fc..333076ad 100644 --- a/src/twister.h +++ b/src/twister.h @@ -14,7 +14,7 @@ public: void startSessionTorrent(boost::thread_group& threadGroup); void stopSessionTorrent(); -std::string createSignature(std::string &strMessage, std::string &strUsername); +std::string createSignature(std::string const &strMessage, std::string const &strUsername); bool verifySignature(std::string const &strMessage, std::string const &strUsername, std::string const &strSign); int getBestHeight();