From c6f1e0bd7bd46ba77c5ba35701919d9dfb89eeb4 Mon Sep 17 00:00:00 2001 From: Steven Siloti Date: Sat, 5 Dec 2015 17:27:01 -0800 Subject: [PATCH] export verify_message and incoming_error Also move these functions to a new msg.cpp. They are useful for plugins which implement DHT extensions. --- CMakeLists.txt | 1 + Jamfile | 1 + include/libtorrent/kademlia/msg.hpp | 43 +++++++- include/libtorrent/kademlia/node.hpp | 30 ------ src/Makefile.am | 3 +- src/kademlia/msg.cpp | 141 +++++++++++++++++++++++++++ src/kademlia/node.cpp | 104 -------------------- 7 files changed, 184 insertions(+), 139 deletions(-) create mode 100644 src/kademlia/msg.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index c6afa06ee..547f25e6d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -122,6 +122,7 @@ set(kademlia_sources dht_storage dos_blocker dht_tracker + msg node node_entry refresh diff --git a/Jamfile b/Jamfile index d513f3ecd..6aa6a4dc8 100644 --- a/Jamfile +++ b/Jamfile @@ -694,6 +694,7 @@ SOURCES = KADEMLIA_SOURCES = dht_storage dht_tracker + msg node node_entry refresh diff --git a/include/libtorrent/kademlia/msg.hpp b/include/libtorrent/kademlia/msg.hpp index 7ffafbac5..03de861bc 100644 --- a/include/libtorrent/kademlia/msg.hpp +++ b/include/libtorrent/kademlia/msg.hpp @@ -30,16 +30,17 @@ POSSIBILITY OF SUCH DAMAGE. */ -#ifndef MSG_HPP -#define MSG_HPP +#ifndef TORRENT_KADEMLIA_MSG_HPP +#define TORRENT_KADEMLIA_MSG_HPP #include -#include -#include +#include "libtorrent/socket.hpp" +#include "libtorrent/kademlia/node_id.hpp" namespace libtorrent { struct bdecode_node; +struct entry; namespace dht { @@ -61,6 +62,40 @@ private: msg& operator=(msg const&); }; +struct key_desc_t +{ + char const* name; + int type; + int size; + int flags; + + enum { + // this argument is optional, parsing will not + // fail if it's not present + optional = 1, + // for dictionaries, the following entries refer + // to child nodes to this node, up until and including + // the next item that has the last_child flag set. + // these flags are nestable + parse_children = 2, + // this is the last item in a child dictionary + last_child = 4, + // the size argument refers to that the size + // has to be divisible by the number, instead + // of having that exact size + size_divisible = 8 + }; +}; + +// verifies that a message has all the required +// entries and returns them in ret +bool TORRENT_EXPORT verify_message(bdecode_node const& msg, key_desc_t const desc[] + , bdecode_node ret[], int size, char* error, int error_size); + +// generate an error response message +void TORRENT_EXPORT incoming_error(entry& e, char const* msg, int error_code = 203); + + } } #endif diff --git a/include/libtorrent/kademlia/node.hpp b/include/libtorrent/kademlia/node.hpp index ae18994c1..2075fb8b4 100644 --- a/include/libtorrent/kademlia/node.hpp +++ b/include/libtorrent/kademlia/node.hpp @@ -73,38 +73,8 @@ namespace libtorrent { namespace dht struct traversal_algorithm; struct dht_observer; -struct key_desc_t -{ - char const* name; - int type; - int size; - int flags; - - enum { - // this argument is optional, parsing will not - // fail if it's not present - optional = 1, - // for dictionaries, the following entries refer - // to child nodes to this node, up until and including - // the next item that has the last_child flag set. - // these flags are nestable - parse_children = 2, - // this is the last item in a child dictionary - last_child = 4, - // the size argument refers to that the size - // has to be divisible by the number, instead - // of having that exact size - size_divisible = 8 - }; -}; - -bool TORRENT_EXTRA_EXPORT verify_message(bdecode_node const& msg, key_desc_t const desc[] - , bdecode_node ret[], int size , char* error, int error_size); - void TORRENT_EXTRA_EXPORT write_nodes_entry(entry& r, nodes_t const& nodes); -void incoming_error(entry& e, char const* msg, int error_code = 203); - struct null_type {}; class announce_observer : public observer diff --git a/src/Makefile.am b/src/Makefile.am index a3a523f02..e47481878 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -7,7 +7,8 @@ KADEMLIA_SOURCES = \ kademlia/dht_storage.cpp \ kademlia/dht_tracker.cpp \ kademlia/find_data.cpp \ - kademlia/put_data.cpp \ + kademlia/put_data.cpp \ + kademlia/msg.cpp \ kademlia/node.cpp \ kademlia/node_entry.cpp \ kademlia/node_id.cpp \ diff --git a/src/kademlia/msg.cpp b/src/kademlia/msg.cpp new file mode 100644 index 000000000..0a524038e --- /dev/null +++ b/src/kademlia/msg.cpp @@ -0,0 +1,141 @@ +/* + +Copyright (c) 2003-2015, Arvid Norberg +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +* Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in +the documentation and/or other materials provided with the distribution. +* Neither the name of the author nor the names of its +contributors may be used to endorse or promote products derived +from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +*/ + +#include "libtorrent/kademlia/msg.hpp" +#include "libtorrent/bdecode.hpp" +#include "libtorrent/entry.hpp" + +namespace libtorrent { namespace dht { + +bool verify_message(bdecode_node const& message, key_desc_t const desc[] + , bdecode_node ret[], int size, char* error, int error_size) +{ + // get a non-root bdecode_node that still + // points to the root. message should not be copied + bdecode_node msg = message.non_owning(); + + // clear the return buffer + for (int i = 0; i < size; ++i) + ret[i].clear(); + + // when parsing child nodes, this is the stack + // of bdecode_nodes to return to + bdecode_node stack[5]; + int stack_ptr = -1; + + if (msg.type() != bdecode_node::dict_t) + { + snprintf(error, error_size, "not a dictionary"); + return false; + } + ++stack_ptr; + stack[stack_ptr] = msg; + for (int i = 0; i < size; ++i) + { + key_desc_t const& k = desc[i]; + + // fprintf(stderr, "looking for %s in %s\n", k.name, print_entry(*msg).c_str()); + + ret[i] = msg.dict_find(k.name); + // none_t means any type + if (ret[i] && ret[i].type() != k.type && k.type != bdecode_node::none_t) + ret[i].clear(); + if (ret[i] == 0 && (k.flags & key_desc_t::optional) == 0) + { + // the key was not found, and it's not an optional key + snprintf(error, error_size, "missing '%s' key", k.name); + return false; + } + + if (k.size > 0 + && ret[i] + && k.type == bdecode_node::string_t) + { + bool invalid = false; + if (k.flags & key_desc_t::size_divisible) + invalid = (ret[i].string_length() % k.size) != 0; + else + invalid = ret[i].string_length() != k.size; + + if (invalid) + { + // the string was not of the required size + ret[i].clear(); + if ((k.flags & key_desc_t::optional) == 0) + { + snprintf(error, error_size, "invalid value for '%s'", k.name); + return false; + } + } + } + if (k.flags & key_desc_t::parse_children) + { + TORRENT_ASSERT(k.type == bdecode_node::dict_t); + + if (ret[i]) + { + ++stack_ptr; + TORRENT_ASSERT(stack_ptr < int(sizeof(stack) / sizeof(stack[0]))); + msg = ret[i]; + stack[stack_ptr] = msg; + } + else + { + // skip all children + while (i < size && (desc[i].flags & key_desc_t::last_child) == 0) ++i; + // if this assert is hit, desc is incorrect + TORRENT_ASSERT(i < size); + } + } + else if (k.flags & key_desc_t::last_child) + { + TORRENT_ASSERT(stack_ptr > 0); + // this can happen if the specification passed + // in is unbalanced. i.e. contain more last_child + // nodes than parse_children + if (stack_ptr == 0) return false; + --stack_ptr; + msg = stack[stack_ptr]; + } + } + return true; +} + +void incoming_error(entry& e, char const* msg, int error_code) +{ + e["y"] = "e"; + entry::list_type& l = e["e"].list(); + l.push_back(entry(error_code)); + l.push_back(entry(msg)); +} + +} } diff --git a/src/kademlia/node.cpp b/src/kademlia/node.cpp index b7ee97c2d..dd0a9bf9c 100644 --- a/src/kademlia/node.cpp +++ b/src/kademlia/node.cpp @@ -745,110 +745,6 @@ void TORRENT_EXTRA_EXPORT write_nodes_entry(entry& r, nodes_t const& nodes) } } -// verifies that a message has all the required -// entries and returns them in ret -bool verify_message(bdecode_node const& message, key_desc_t const desc[] - , bdecode_node ret[], int size , char* error, int error_size) -{ - // get a non-root bdecode_node that still - // points to the root. message should not be copied - bdecode_node msg = message.non_owning(); - - // clear the return buffer - for (int i = 0; i < size; ++i) - ret[i].clear(); - - // when parsing child nodes, this is the stack - // of bdecode_nodes to return to - bdecode_node stack[5]; - int stack_ptr = -1; - - if (msg.type() != bdecode_node::dict_t) - { - snprintf(error, error_size, "not a dictionary"); - return false; - } - ++stack_ptr; - stack[stack_ptr] = msg; - for (int i = 0; i < size; ++i) - { - key_desc_t const& k = desc[i]; - -// fprintf(stderr, "looking for %s in %s\n", k.name, print_entry(*msg).c_str()); - - ret[i] = msg.dict_find(k.name); - // none_t means any type - if (ret[i] && ret[i].type() != k.type && k.type != bdecode_node::none_t) - ret[i].clear(); - if (ret[i] == 0 && (k.flags & key_desc_t::optional) == 0) - { - // the key was not found, and it's not an optional key - snprintf(error, error_size, "missing '%s' key", k.name); - return false; - } - - if (k.size > 0 - && ret[i] - && k.type == bdecode_node::string_t) - { - bool invalid = false; - if (k.flags & key_desc_t::size_divisible) - invalid = (ret[i].string_length() % k.size) != 0; - else - invalid = ret[i].string_length() != k.size; - - if (invalid) - { - // the string was not of the required size - ret[i].clear(); - if ((k.flags & key_desc_t::optional) == 0) - { - snprintf(error, error_size, "invalid value for '%s'", k.name); - return false; - } - } - } - if (k.flags & key_desc_t::parse_children) - { - TORRENT_ASSERT(k.type == bdecode_node::dict_t); - - if (ret[i]) - { - ++stack_ptr; - TORRENT_ASSERT(stack_ptr < int(sizeof(stack)/sizeof(stack[0]))); - msg = ret[i]; - stack[stack_ptr] = msg; - } - else - { - // skip all children - while (i < size && (desc[i].flags & key_desc_t::last_child) == 0) ++i; - // if this assert is hit, desc is incorrect - TORRENT_ASSERT(i < size); - } - } - else if (k.flags & key_desc_t::last_child) - { - TORRENT_ASSERT(stack_ptr > 0); - // this can happen if the specification passed - // in is unbalanced. i.e. contain more last_child - // nodes than parse_children - if (stack_ptr == 0) return false; - --stack_ptr; - msg = stack[stack_ptr]; - } - } - return true; -} - -void incoming_error(entry& e, char const* msg, int error_code) -{ - e["y"] = "e"; - entry::list_type& l = e["e"].list(); - l.push_back(entry(error_code)); - l.push_back(entry(msg)); -} - // build response void node::incoming_request(msg const& m, entry& e) {