diff --git a/src/torrent/peer/peer_list.cc b/src/torrent/peer/peer_list.cc index 23ca651a2..aa60939a0 100644 --- a/src/torrent/peer/peer_list.cc +++ b/src/torrent/peer/peer_list.cc @@ -146,7 +146,11 @@ PeerList::insert_address(const sockaddr* sa, int flags) { PeerInfo* peerInfo = new PeerInfo(sa); peerInfo->set_listen_port(address->port()); - peerInfo->set_flags(m_ipv4_table.at(address->sa_inet()->address_h()) & PeerInfo::mask_ip_table); + uint32_t host_byte_order_ipv4_addr = address->sa_inet()->address_h(); + + // IPv4 addresses stored in host byte order in ipv4_table so they are comparable. ntohl has been called + if(m_ipv4_table.defined(host_byte_order_ipv4_addr)) + peerInfo->set_flags(m_ipv4_table.at(host_byte_order_ipv4_addr) & PeerInfo::mask_ip_table); manager->client_list()->retrieve_unknown(&peerInfo->mutable_client_info()); @@ -264,12 +268,25 @@ PeerList::connected(const sockaddr* sa, int flags) { !socket_address_key::is_comparable_sockaddr(sa)) return NULL; - int filter_value = m_ipv4_table.at(address->sa_inet()->address_h()); + uint32_t host_byte_order_ipv4_addr = address->sa_inet()->address_h(); + int filter_value = 0; + + // IPv4 addresses stored in host byte order in ipv4_table so they are comparable. ntohl has been called + if(m_ipv4_table.defined(host_byte_order_ipv4_addr)) + filter_value = m_ipv4_table.at(host_byte_order_ipv4_addr); // We should also remove any PeerInfo objects already for this // address. - if ((filter_value & PeerInfo::flag_unwanted)) + if ((filter_value & PeerInfo::flag_unwanted)) { + char ipv4_str[INET_ADDRSTRLEN]; + uint32_t net_order_addr = htonl(host_byte_order_ipv4_addr); + + inet_ntop(AF_INET, &net_order_addr, ipv4_str, INET_ADDRSTRLEN); + + lt_log_print(LOG_PEER_INFO, "Peer %s is unwanted: preventing connection", ipv4_str); + return NULL; + } PeerInfo* peerInfo; range_type range = base_type::equal_range(sock_key); diff --git a/src/torrent/peer/peer_list.h b/src/torrent/peer/peer_list.h index a3b409cb9..4c2f707da 100644 --- a/src/torrent/peer/peer_list.h +++ b/src/torrent/peer/peer_list.h @@ -46,7 +46,7 @@ namespace torrent { class DownloadInfo; -typedef extents ipv4_table; +typedef extents ipv4_table; class LIBTORRENT_EXPORT PeerList : private std::multimap { public: diff --git a/src/torrent/utils/extents.h b/src/torrent/utils/extents.h index 8ec1e6009..c2b887b15 100644 --- a/src/torrent/utils/extents.h +++ b/src/torrent/utils/extents.h @@ -37,191 +37,150 @@ #ifndef LIBTORRENT_UTILS_EXTENTS_H #define LIBTORRENT_UTILS_EXTENTS_H -#include lt_tr1_array -#include +#include +#include namespace torrent { -template -struct extents_base { - typedef Key key_type; - typedef std::pair range_type; - typedef std::pair mapped_type; - typedef Tp mapped_value_type; - - typedef std::array table_type; - - extents_base(key_type pos, unsigned int mb, mapped_value_type val); - extents_base(extents_base* parent, typename table_type::const_iterator itr); - ~extents_base(); - - bool is_divisible(key_type key) const { return key % mask_bits == 0; } - bool is_leaf_branch() const { return mask_bits == 0; } - bool is_equal_range(key_type first, key_type last, const mapped_value_type& val) const; - - unsigned int sizeof_data() const; - - typename table_type::iterator partition_at(key_type key) { return table.begin() + ((key >> mask_bits) & (TableSize - 1)); } - typename table_type::const_iterator partition_at(key_type key) const { return table.begin() + ((key >> mask_bits) & (TableSize - 1)); } - - unsigned int mask_distance(unsigned int mb) { return (~(~key_type() << mb) >> mask_bits); } - - key_type partition_pos(typename table_type::const_iterator part) const { return position + (std::distance(table.begin(), part) << mask_bits); } - - void insert(key_type pos, unsigned int mb, const mapped_value_type& val); - - const mapped_value_type& at(key_type key) const; - - unsigned int mask_bits; - key_type position; - table_type table; -}; - -template -class extents : private extents_base { +template > +class extents { public: - typedef extents_base base_type; - - typedef typename base_type::key_type key_type; - typedef base_type value_type; - typedef typename base_type::range_type range_type; - typedef typename base_type::mapped_type mapped_type; - typedef typename base_type::mapped_value_type mapped_value_type; - typedef typename base_type::table_type table_type; - - static const key_type mask_bits = MaskBits; - static const key_type table_bits = TableBits; - static const key_type table_size = TableSize; - - using base_type::at; - using base_type::sizeof_data; + typedef Address key_type; // start address + typedef Value mapped_value_type; // The value mapped to the ip range + typedef std::pair mapped_type; // End address, value mapped to ip range + typedef std::map range_map_type; // The map itself extents(); + ~extents(); - bool is_equal_range(key_type first, key_type last, const mapped_value_type& val) const; - - void insert(key_type pos, unsigned int mb, const mapped_value_type& val); + void insert(key_type address_start, key_type address_end, mapped_value_type value); + bool defined(key_type address_start, key_type address_end); + bool defined(key_type address); + key_type get_matching_key(key_type address_start, key_type address_end); // throws error on not defined. test with defined() + mapped_value_type at(key_type address_start, key_type address_end); // throws error on not defined. test with defined() + mapped_value_type at(key_type address); // throws error on not defined. test with defined() + unsigned int sizeof_data() const; - base_type* data() { return this; } + range_map_type range_map; }; -template -extents_base::extents_base(key_type pos, unsigned int mb, mapped_value_type val) : - mask_bits(mb), position(pos) { - std::fill(table.begin(), table.end(), mapped_type(NULL, mapped_value_type())); +/////////////////////////////////////// +// CONSTRUCTOR [PLACEHOLDER] +/////////////////////////////////////// +template +extents::extents() { + //nothing to do + return; } -template -extents_base::extents_base(extents_base* parent, typename table_type::const_iterator itr) : - mask_bits(parent->mask_bits - TableBits), position(parent->partition_pos(itr)) { - std::fill(table.begin(), table.end(), mapped_type(NULL, itr->second)); +/////////////////////////////////////// +// DESTRUCTOR [PLACEHOLDER] +/////////////////////////////////////// +template +extents::~extents() { + //nothing to do. map destructor can handle cleanup. + return; } -template -extents::extents() : - base_type(key_type(), mask_bits - table_bits, mapped_value_type()) -{ -} +////////////////////////////////////////////////////////////////////////////////// +// INSERT O(log N) assuming no overlapping ranges +///////////////////////////////////////////////////////////////////////////////// +template +void extents::insert(key_type address_start, key_type address_end, mapped_value_type value) { + //we allow overlap ranges though not 100% overlap but only if mapped values are the same. first remove any overlap range that has a different value. + typename range_map_type::iterator iter = range_map.upper_bound(address_start); + if( iter != range_map.begin() ) { iter--; } + bool ignore_due_to_total_overlap = false; + while( iter->first <= address_end && iter != range_map.end() ) { + key_type delete_key = iter->first; + bool do_delete_due_to_overlap = iter->first <= address_end && (iter->second).first >= address_start && (iter->second).second != value; + bool do_delete_due_to_total_overlap = address_start <= iter->first && address_end >= (iter->second).first; + iter++; + if(do_delete_due_to_overlap || do_delete_due_to_total_overlap) { + range_map.erase (delete_key); + } + else { + ignore_due_to_total_overlap = ignore_due_to_total_overlap || ( iter->first <= address_start && (iter->second).first >= address_end ); + } + } -template -extents_base::~extents_base() { - for (typename table_type::const_iterator itr = table.begin(), last = table.end(); itr != last; itr++) - delete itr->first; + if(!ignore_due_to_total_overlap) { + mapped_type entry; + entry.first = address_end; + entry.second = value; + range_map.insert( std::pair(address_start, entry) ); + } } -template -unsigned int -extents_base::sizeof_data() const { - unsigned int sum = sizeof(*this); - - for (typename table_type::const_iterator itr = table.begin(), last = table.end(); itr != last; itr++) - if (itr->first != NULL) - sum += itr->first->sizeof_data(); - - return sum; +////////////////////////////////////////////////////////////////////// +// DEFINED O(log N) assuming no overlapping ranges +////////////////////////////////////////////////////////////////////// +template +bool extents::defined(key_type address_start, key_type address_end) { + bool defined = false; + typename range_map_type::iterator iter = range_map.upper_bound(address_start); + if( iter != range_map.begin() ) { iter--; } + while( iter->first <= address_end && !defined && iter != range_map.end() ) { + defined = iter->first <= address_end && (iter->second).first >= address_start; + iter++; + } + return defined; } - -template -void -extents::insert(key_type pos, unsigned int mb, const mapped_value_type& val) { - key_type mask = ~key_type() << mb; - - base_type::insert(pos & mask, mb, val); +template +bool extents::defined(key_type address) { + return defined(address, address); } -template -void -extents_base::insert(key_type pos, unsigned int mb, const mapped_value_type& val) { - // RESTRICTED - typename table_type::iterator first = partition_at(pos); - typename table_type::iterator last = partition_at(pos) + mask_distance(mb) + 1; - - if (mb < mask_bits) { - if (first->first == NULL) - first->first = new extents_base(this, first); +////////////////////////////////////////////////////////////////////// +// GET_MATCHING_KEY O(log N) assuming no overlapping ranges +////////////////////////////////////////////////////////////////////// +template +typename extents::key_type extents::get_matching_key(key_type address_start, key_type address_end) { + key_type key; + bool defined = false; + typename range_map_type::iterator iter = range_map.upper_bound(address_start); + if( iter != range_map.begin() ) { iter--; } + while( iter->first <= address_end && !defined && iter != range_map.end() ) { + defined = iter->first <= address_end && (iter->second).first >= address_start; + if(defined) + key = iter->first; - first->first->insert(pos, mb, val); - return; + iter++; } - - while (first != last) { - if (first->first != NULL) { - delete first->first; - first->first = NULL; - } - - (first++)->second = val; + // this will cause exception to be thrown + if(!defined) { + std::out_of_range e("nothing defined for specified key"); + throw e; } + return key; } -template -bool -extents::is_equal_range(key_type first, key_type last, const mapped_value_type& val) const { - // RESTRICTED - first = std::max(first, key_type()); - last = std::min(last, key_type() + (~key_type() >> (sizeof(key_type) * 8 - MaskBits))); - - if (first <= last) - return base_type::is_equal_range(first, last, val); - else - return true; +////////////////////////////////////////////////////////////////////// +// AT O(log N) assuming no overlapping ranges +////////////////////////////////////////////////////////////////////// +template +typename extents::mapped_value_type extents::at(key_type address_start, key_type address_end) { + key_type key = get_matching_key(address_start, address_end); + mapped_type entry = range_map.at(key); + return entry.second; } - -template -bool -extents_base::is_equal_range(key_type key_first, key_type key_last, const mapped_value_type& val) const { - // RESTRICTED - typename table_type::const_iterator first = partition_at(key_first); - typename table_type::const_iterator last = partition_at(key_last) + 1; - - do { - // std::cout << "shift_amount " << key_first << ' ' << key_last << std::endl; - - if (first->first == NULL && val != first->second) - return false; - - if (first->first != NULL && !first->first->is_equal_range(std::max(key_first, partition_pos(first)), - std::min(key_last, partition_pos(first + 1) - 1), val)) - return false; - - } while (++first != last); - - return true; +template +typename extents::mapped_value_type extents::at(key_type address) { + return at(address, address); } -// Assumes 'key' is within the range of the range. -template -const typename extents_base::mapped_value_type& -extents_base::at(key_type key) const { - typename table_type::const_iterator itr = partition_at(key); - - while (itr->first != NULL) - itr = itr->first->partition_at(key); - - return itr->second; +////////////////////////////////////////////////////////////////////// +// SIZEOF_DATA O(1) +////////////////////////////////////////////////////////////////////// +template +unsigned int extents::sizeof_data() const { + // we don't know overhead on map, so this won't be accurate. just estimate. + unsigned int entry_size = sizeof(key_type) + sizeof(mapped_type); + return entry_size * range_map.size(); } + } #endif