diff --git a/doc/rtorrent.1.xml b/doc/rtorrent.1.xml index 51a4388c..20447673 100644 --- a/doc/rtorrent.1.xml +++ b/doc/rtorrent.1.xml @@ -241,6 +241,20 @@ + + k + +Disconnect peer. + + + + + * + +Choke/Snubb peer. + + + diff --git a/rak/address_info.h b/rak/address_info.h new file mode 100644 index 00000000..26d22681 --- /dev/null +++ b/rak/address_info.h @@ -0,0 +1,98 @@ +// rak - Rakshasa's toolbox +// Copyright (C) 2005-2006, Jari Sundell +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// In addition, as a special exception, the copyright holders give +// permission to link the code of portions of this program with the +// OpenSSL library under certain conditions as described in each +// individual source file, and distribute linked combinations +// including the two. +// +// You must obey the GNU General Public License in all respects for +// all of the code used other than OpenSSL. If you modify file(s) +// with this exception, you may extend this exception to your version +// of the file(s), but you are not obligated to do so. If you do not +// wish to do so, delete this exception statement from your version. +// If you delete this exception statement from all source files in the +// program, then also delete it here. +// +// Contact: Jari Sundell +// +// Skomakerveien 33 +// 3185 Skoppum, NORWAY + +// Wrapper for addrinfo with focus on zero-copy conversion to and from +// the c-type and wrapper. +// +// Do use the wrapper on a pre-existing struct addrinfo, cast the +// pointer rather than the base type. + +#ifndef RAK_ADDRESS_INFO_H +#define RAK_ADDRESS_INFO_H + +#include +#include + +namespace rak { + +class address_info { +public: + void clear() { std::memset(this, 0, sizeof(address_info)); } + + int flags() const { return m_addrinfo.ai_flags; } + void set_flags(int f) { m_addrinfo.ai_flags = f; } + + int family() const { return m_addrinfo.ai_family; } + void set_family(int f) { m_addrinfo.ai_family = f; } + + int socket_type() const { return m_addrinfo.ai_socktype; } + void set_socket_type(int t) { m_addrinfo.ai_socktype = t; } + + int protocol() const { return m_addrinfo.ai_protocol; } + void set_protocol(int p) { m_addrinfo.ai_protocol = p; } + + size_t length() const { return m_addrinfo.ai_addrlen; } + + socket_address* address() { return reinterpret_cast(m_addrinfo.ai_addr); } + + addrinfo* c_addrinfo() { return &m_addrinfo; } + const addrinfo* c_addrinfo() const { return &m_addrinfo; } + + address_info* next() { return reinterpret_cast(m_addrinfo.ai_next); } + + static int get_address_info(const char* node, int domain, int type, address_info** ai); + + static void free_address_info(address_info* ai) { ::freeaddrinfo(ai->c_addrinfo()); } + + static const char* strerror(int err) { return gai_strerror(err); } + +private: + addrinfo m_addrinfo; +}; + +inline int +address_info::get_address_info(const char* node, int pfamily, int stype, address_info** ai) { + address_info hints; + hints.clear(); + hints.set_family(pfamily); + hints.set_socket_type(stype); + + return ::getaddrinfo(node, NULL, hints.c_addrinfo(), reinterpret_cast(ai)); +} + +} + +#endif diff --git a/rak/functional_fun.h b/rak/functional_fun.h index 32928ac3..c8ba1c5e 100644 --- a/rak/functional_fun.h +++ b/rak/functional_fun.h @@ -34,7 +34,7 @@ // Skomakerveien 33 // 3185 Skoppum, NORWAY -// This file contains functors that wrap function points and member +// This file contains functors that wrap function pointers and member // function pointers. // // 'fn' functors are polymorphic and derives from 'rak::function' and diff --git a/rak/ranges.h b/rak/ranges.h index b954b6c7..a2440ceb 100644 --- a/rak/ranges.h +++ b/rak/ranges.h @@ -1,4 +1,4 @@ -// libTorrent - BitTorrent library +// rak - Rakshasa's toolbox // Copyright (C) 2005-2006, Jari Sundell // // This program is free software; you can redistribute it and/or modify diff --git a/rak/socket_address.h b/rak/socket_address.h new file mode 100644 index 00000000..c567ba17 --- /dev/null +++ b/rak/socket_address.h @@ -0,0 +1,335 @@ +// rak - Rakshasa's toolbox +// Copyright (C) 2005-2006, Jari Sundell +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// In addition, as a special exception, the copyright holders give +// permission to link the code of portions of this program with the +// OpenSSL library under certain conditions as described in each +// individual source file, and distribute linked combinations +// including the two. +// +// You must obey the GNU General Public License in all respects for +// all of the code used other than OpenSSL. If you modify file(s) +// with this exception, you may extend this exception to your version +// of the file(s), but you are not obligated to do so. If you do not +// wish to do so, delete this exception statement from your version. +// If you delete this exception statement from all source files in the +// program, then also delete it here. +// +// Contact: Jari Sundell +// +// Skomakerveien 33 +// 3185 Skoppum, NORWAY + +// Wrappers for the various sockaddr types with focus on zero-copy +// casting between the original type and the wrapper class. +// +// The default ctor does not initialize any data. +// +// _n suffixes indicate that the argument or return value is in +// network byte order, _h that they are in hardware byte order. + +// Add define for inet6 scope id? + +#ifndef RAK_SOCKET_ADDRESS_H +#define RAK_SOCKET_ADDRESS_H + +#include +#include +#include +#include +#include +#include +#include + +namespace rak { + +class socket_address_inet; +class socket_address_inet6; + +class socket_address { +public: + static const sa_family_t af_local = AF_LOCAL; + static const sa_family_t af_unix = AF_UNIX; + static const sa_family_t af_file = AF_FILE; + static const sa_family_t af_inet = AF_INET; + static const sa_family_t af_inet6 = AF_INET6; + static const sa_family_t af_unspec = AF_UNSPEC; + + bool is_valid() const; + bool is_bindable() const; + bool is_address_any() const; + + // Should we need to set AF_UNSPEC? + void clear() { std::memset(this, 0, sizeof(socket_address)); set_family(); } + + sa_family_t family() const { return m_sa.m_sockaddr.sa_family; } + void set_family() { m_sa.m_sockaddr.sa_family = af_unspec; } + + uint16_t port() const; + void set_port(uint16_t p); + + std::string address_str() const; + bool address_c_str(char* buf, socklen_t size) const; + + // Attemts to set it as an inet, then an inet6 address. It will + // never set anything but net addresses, no local/unix. + bool set_address_str(const std::string& a) { return set_address_c_str(a.c_str()); } + bool set_address_c_str(const char* a); + + socket_address_inet* sa_inet() { return reinterpret_cast(this); } + socket_address_inet6* sa_inet6() { return reinterpret_cast(this); } + + const socket_address_inet* sa_inet() const { return reinterpret_cast(this); } + const socket_address_inet6* sa_inet6() const { return reinterpret_cast(this); } + + sockaddr* c_sockaddr() { return &m_sa.m_sockaddr; } + sockaddr_in* c_sockaddr_inet() { return &m_sa.m_sockaddrInet; } + sockaddr_in6* c_sockaddr_inet6() { return &m_sa.m_sockaddrInet6; } + + const sockaddr* c_sockaddr() const { return &m_sa.m_sockaddr; } + const sockaddr_in* c_sockaddr_inet() const { return &m_sa.m_sockaddrInet; } + const sockaddr_in6* c_sockaddr_inet6() const { return &m_sa.m_sockaddrInet6; } + + // Copy a socket address which has the length 'length. Zero out any + // extranous bytes and ensure it does not go beyond the size of this + // struct. + void copy(const socket_address& src, size_t length); + + // The different families will be sorted according to the + // sa_family_t's numeric value. + bool operator == (const socket_address& rhs) const; + bool operator < (const socket_address& rhs) const; + +private: + union sa_union { + sockaddr m_sockaddr; + sockaddr_in m_sockaddrInet; + sockaddr_in6 m_sockaddrInet6; + }; + + sa_union m_sa; +}; + +// Remeber to set the AF_INET. + +class socket_address_inet { +public: + bool is_any() const { return is_port_any() && is_address_any(); } + bool is_valid() const { return !is_port_any() && !is_address_any(); } + bool is_port_any() const { return port() == 0; } + bool is_address_any() const { return m_sockaddr.sin_addr.s_addr == htonl(INADDR_ANY); } + + void clear() { std::memset(this, 0, sizeof(socket_address_inet)); set_family(); } + + uint16_t port() const { return ntohs(m_sockaddr.sin_port); } + uint16_t port_n() const { return m_sockaddr.sin_port; } + void set_port(uint16_t p) { m_sockaddr.sin_port = htons(p); } + void set_port_n(uint16_t p) { m_sockaddr.sin_port = p; } + + // Should address() return the uint32_t? + in_addr address() const { return m_sockaddr.sin_addr; } + uint32_t address_h() const { return ntohl(m_sockaddr.sin_addr.s_addr); } + uint32_t address_n() const { return m_sockaddr.sin_addr.s_addr; } + std::string address_str() const; + bool address_c_str(char* buf, socklen_t size) const; + + void set_address(in_addr a) { m_sockaddr.sin_addr = a; } + void set_address_h(uint32_t a) { m_sockaddr.sin_addr.s_addr = htonl(a); } + void set_address_n(uint32_t a) { m_sockaddr.sin_addr.s_addr = a; } + bool set_address_str(const std::string& a) { return set_address_c_str(a.c_str()); } + bool set_address_c_str(const char* a); + + void set_address_any() { set_port(0); set_address_h(INADDR_ANY); } + + sa_family_t family() const { return m_sockaddr.sin_family; } + void set_family() { m_sockaddr.sin_family = AF_INET; } + + sockaddr* c_sockaddr() { return reinterpret_cast(&m_sockaddr); } + sockaddr_in* c_sockaddr_inet() { return &m_sockaddr; } + + const sockaddr* c_sockaddr() const { return reinterpret_cast(&m_sockaddr); } + const sockaddr_in* c_sockaddr_inet() const { return &m_sockaddr; } + + bool operator == (const socket_address_inet& rhs) const; + bool operator < (const socket_address_inet& rhs) const; + +private: + struct sockaddr_in m_sockaddr; +}; + +inline bool +socket_address::is_valid() const { + switch (family()) { + case af_inet: + return sa_inet()->is_valid(); +// case af_inet6: +// return sa_inet6().is_valid(); + default: + return false; + } +} + +inline bool +socket_address::is_bindable() const { + switch (family()) { + case af_inet: + return !sa_inet()->is_address_any(); + default: + return false; + } +} + +inline bool +socket_address::is_address_any() const { + switch (family()) { + case af_inet: + return sa_inet()->is_address_any(); + default: + return true; + } +} + +inline uint16_t +socket_address::port() const { + switch (family()) { + case af_inet: + return sa_inet()->port(); + default: + return 0; + } +} + +inline void +socket_address::set_port(uint16_t p) { + switch (family()) { + case af_inet: + return sa_inet()->set_port(p); + default: + break; + } +} + +inline std::string +socket_address::address_str() const { + switch (family()) { + case af_inet: + return sa_inet()->address_str(); + default: + return std::string(); + } +} + +inline bool +socket_address::address_c_str(char* buf, socklen_t size) const { + switch (family()) { + case af_inet: + return sa_inet()->address_c_str(buf, size); + default: + return false; + } +} + +inline bool +socket_address::set_address_c_str(const char* a) { + if (sa_inet()->set_address_c_str(a)) { + sa_inet()->set_family(); + return true; + + } else { + return false; + } +} + +inline void +socket_address::copy(const socket_address& src, size_t length) { + length = std::min(length, sizeof(socket_address)); + + // Does this get properly optimized? + std::memset(this, 0, sizeof(socket_address)); + std::memcpy(this, &src, length); +} + +// Should we be able to compare af_unspec? + +inline bool +socket_address::operator == (const socket_address& rhs) const { + if (family() != rhs.family()) + return false; + + switch (family()) { + case af_inet: + return *sa_inet() == *rhs.sa_inet(); +// case af_inet6: +// return *sa_inet6() == *rhs.sa_inet6(); + default: + throw std::logic_error("socket_address::operator == (rhs) invalid type comparison."); + } +} + +inline bool +socket_address::operator < (const socket_address& rhs) const { + if (family() != rhs.family()) + return family() < rhs.family(); + + switch (family()) { + case af_inet: + return *sa_inet() < *rhs.sa_inet(); +// case af_inet6: +// return *sa_inet6() < *rhs.sa_inet6(); + default: + throw std::logic_error("socket_address::operator < (rhs) invalid type comparison."); + } +} + +inline std::string +socket_address_inet::address_str() const { + char buf[INET_ADDRSTRLEN]; + + if (!address_c_str(buf, INET_ADDRSTRLEN)) + return std::string(); + + return std::string(buf); +} + +inline bool +socket_address_inet::address_c_str(char* buf, socklen_t size) const { + return inet_ntop(family(), &m_sockaddr.sin_addr, buf, size); +} + +inline bool +socket_address_inet::set_address_c_str(const char* a) { + return inet_pton(AF_INET, a, &m_sockaddr.sin_addr); +} + +inline bool +socket_address_inet::operator == (const socket_address_inet& rhs) const { + return + m_sockaddr.sin_addr.s_addr == rhs.m_sockaddr.sin_addr.s_addr && + m_sockaddr.sin_port == rhs.m_sockaddr.sin_port; +} + +inline bool +socket_address_inet::operator < (const socket_address_inet& rhs) const { + return + m_sockaddr.sin_addr.s_addr < rhs.m_sockaddr.sin_addr.s_addr || + (m_sockaddr.sin_addr.s_addr == rhs.m_sockaddr.sin_addr.s_addr && + m_sockaddr.sin_port < rhs.m_sockaddr.sin_port); +} + +} + +#endif diff --git a/rak/string_manip.h b/rak/string_manip.h index 85c1f169..5ed3942f 100644 --- a/rak/string_manip.h +++ b/rak/string_manip.h @@ -130,6 +130,19 @@ split_iterator(__UNUSED const Sequence& seq) { return split_iterator_t(); } +// Could optimize this abit. +inline char +hexchar_to_value(char c) { + if (c >= '0' && c <= '9') + return c - '0'; + + else if (c >= 'A' && c <= 'F') + return 10 + c - 'A'; + + else + return 10 + c - 'a'; +} + template inline char value_to_hexchar(Value v) { diff --git a/rak/unordered_vector.h b/rak/unordered_vector.h index 36f71fdf..c47727dc 100644 --- a/rak/unordered_vector.h +++ b/rak/unordered_vector.h @@ -75,8 +75,12 @@ public: using Base::push_back; using Base::pop_back; + // Use the range erase function, the single element erase gets + // overloaded. + using Base::erase; + iterator insert(iterator position, const value_type& x); - iterator erase(iterator position); + iterator erase(iterator position); private: }; diff --git a/src/display/client_info.cc b/src/display/client_info.cc index 470090ff..b2e787e7 100644 --- a/src/display/client_info.cc +++ b/src/display/client_info.cc @@ -38,6 +38,7 @@ #include #include +#include #include #include "client_info.h" @@ -85,17 +86,17 @@ ClientInfo::ClientInfo() { insert(TYPE_AZUREUS, "SZ", "Shareaza"); insert(TYPE_AZUREUS, "RT", "Retriever"); - m_containers[TYPE_THREE_COMPACT].reserve(10); + m_containers[TYPE_COMPACT].reserve(10); - insert(TYPE_THREE_COMPACT, "A", "ABC"); - insert(TYPE_THREE_COMPACT, "T", "BitTornado"); - insert(TYPE_THREE_COMPACT, "S", "Shadow's client"); - insert(TYPE_THREE_COMPACT, "U", "UPnP NAT Bit Torrent"); - insert(TYPE_THREE_COMPACT, "O", "Osprey Permaseed"); + insert(TYPE_COMPACT, "A", "ABC"); + insert(TYPE_COMPACT, "T", "BitTornado"); + insert(TYPE_COMPACT, "S", "Shadow's client"); + insert(TYPE_COMPACT, "U", "UPnP NAT Bit Torrent"); + insert(TYPE_COMPACT, "O", "Osprey Permaseed"); - m_containers[TYPE_THREE_SPARSE].reserve(4); + m_containers[TYPE_MAINLINE].reserve(4); - insert(TYPE_THREE_SPARSE, "M", "Mainline"); + insert(TYPE_MAINLINE, "M", "Mainline"); } void @@ -108,21 +109,20 @@ ClientInfo::insert(Type t, const char* key, const char* name) { if (keySize != std::strlen(key)) throw torrent::input_error("Client info key size not what was expected."); - // Check if it is already present. + // Check if it is already present, not entirely optimal when + // initializing but this only get run once. + iterator itr = std::find_if(m_containers[t].begin(), m_containers[t].end(), client_info_equal(key, sizeof_key(t))); + + if (itr == m_containers[t].end()) + itr = m_containers[t].insert(m_containers[t].end(), value_type()); - value_type v; - - std::memcpy(v.first, key, keySize); - v.second = name; - - m_containers[t].push_back(v); + std::memcpy(itr->first, key, keySize); + itr->second = name; } char* ClientInfo::print(char* first, char* last, const char* id) { - // Start with an UDP0 test. - if (id[0] == '-' && id[7] == '-' && std::isalpha(id[1]) && std::isalpha(id[2]) && std::isxdigit(id[3]) && std::isxdigit(id[4]) && std::isxdigit(id[5]) && std::isxdigit(id[6])) { @@ -132,38 +132,52 @@ ClientInfo::print(char* first, char* last, const char* id) { client_info_equal(id + 1, sizeof_key(TYPE_AZUREUS))); if (itr != m_containers[TYPE_AZUREUS].end()) - first = print_buffer(first, last, "%s %c.%c.%c.%c", itr->second, id[3], id[4], id[5], id[6]); + first = print_buffer(first, last, "%s %hhu.%hhu.%hhu.%hhu", itr->second, + rak::hexchar_to_value(id[3]), rak::hexchar_to_value(id[4]), + rak::hexchar_to_value(id[5]), rak::hexchar_to_value(id[6])); else - first = print_buffer(first, last, "unknown %c%c %c.%c.%c.%c", id[1], id[2], id[3], id[4], id[5], id[6]); + first = print_buffer(first, last, "unknown %c%c %hhu.%hhu.%hhu.%hhu", id[1], id[2], + rak::hexchar_to_value(id[3]), rak::hexchar_to_value(id[4]), + rak::hexchar_to_value(id[5]), rak::hexchar_to_value(id[6])); } else if (std::isalpha(id[0]) && id[4] == '-' && std::isxdigit(id[1]) && std::isxdigit(id[2]) && std::isxdigit(id[3])) { // TYPE_THREE_COMPACT. - iterator itr = std::find_if(m_containers[TYPE_THREE_COMPACT].begin(), m_containers[TYPE_THREE_COMPACT].end(), - client_info_equal(id, sizeof_key(TYPE_THREE_COMPACT))); + iterator itr = std::find_if(m_containers[TYPE_COMPACT].begin(), m_containers[TYPE_COMPACT].end(), + client_info_equal(id, sizeof_key(TYPE_COMPACT))); - if (itr != m_containers[TYPE_THREE_COMPACT].end()) - first = print_buffer(first, last, "%s %c.%c.%c", itr->second, id[1], id[2], id[3]); + if (itr != m_containers[TYPE_COMPACT].end()) + first = print_buffer(first, last, "%s %hhu.%hhu.%hhu", itr->second, + rak::hexchar_to_value(id[1]), rak::hexchar_to_value(id[2]), rak::hexchar_to_value(id[3])); else - first = print_buffer(first, last, "unknown %c %c.%c.%c", id[0], id[1], id[2], id[3]); + first = print_buffer(first, last, "unknown %c %hhu.%hhu.%hhu", id[0], + rak::hexchar_to_value(id[1]), rak::hexchar_to_value(id[2]), rak::hexchar_to_value(id[3])); } else if (std::isalpha(id[0]) && id[2] == '-' && id[4] == '-' && id[6] == '-' && std::isxdigit(id[1]) && std::isxdigit(id[3]) && std::isxdigit(id[5])) { // TYPE_THREE_SPARSE. - iterator itr = std::find_if(m_containers[TYPE_THREE_SPARSE].begin(), m_containers[TYPE_THREE_SPARSE].end(), - client_info_equal(id, sizeof_key(TYPE_THREE_SPARSE))); + iterator itr = std::find_if(m_containers[TYPE_MAINLINE].begin(), m_containers[TYPE_MAINLINE].end(), + client_info_equal(id, sizeof_key(TYPE_MAINLINE))); - if (itr != m_containers[TYPE_THREE_SPARSE].end()) - first = print_buffer(first, last, "%s %c.%c.%c", itr->second, id[1], id[3], id[5]); + if (itr != m_containers[TYPE_MAINLINE].end()) + first = print_buffer(first, last, "%s %hhu.%hhu.%hhu", itr->second, + rak::hexchar_to_value(id[1]), rak::hexchar_to_value(id[3]), rak::hexchar_to_value(id[5])); else - first = print_buffer(first, last, "unknown %c %c.%c.%c", id[0], id[1], id[3], id[5]); + first = print_buffer(first, last, "unknown %c %hhu.%hhu.%hhu", id[0], + rak::hexchar_to_value(id[1]), rak::hexchar_to_value(id[3]), rak::hexchar_to_value(id[5])); + // And then the incompatible idiots that make life difficult for us + // others. (There's '3' schemes to choose from already...) + + // Well... fuck this... I don't feel like adding the rest of the + // checks as they wouldn't be possible to remove/modify. + } else { first = print_buffer(first, last, "unknown"); } diff --git a/src/display/client_info.h b/src/display/client_info.h index 362eec44..7ff1efb0 100644 --- a/src/display/client_info.h +++ b/src/display/client_info.h @@ -54,8 +54,8 @@ public: typedef enum { TYPE_AZUREUS, - TYPE_THREE_COMPACT, - TYPE_THREE_SPARSE, + TYPE_COMPACT, + TYPE_MAINLINE, TYPE_MAXSIZE } Type; @@ -67,10 +67,10 @@ public: size_type sizeof_key(Type t) { switch (t) { - case TYPE_AZUREUS: return 2; - case TYPE_THREE_COMPACT: return 1; - case TYPE_THREE_SPARSE: return 1; - case TYPE_MAXSIZE: return 0; + case TYPE_AZUREUS: return 2; + case TYPE_COMPACT: return 1; + case TYPE_MAINLINE: return 1; + case TYPE_MAXSIZE: return 0; } } diff --git a/src/option_parser.cc b/src/option_parser.cc index 93ac2a1a..eb54f735 100644 --- a/src/option_parser.cc +++ b/src/option_parser.cc @@ -37,6 +37,7 @@ #include "config.h" #include +#include #include #include #include diff --git a/src/ui/download.cc b/src/ui/download.cc index 0b0370d4..32628431 100644 --- a/src/ui/download.cc +++ b/src/ui/download.cc @@ -171,6 +171,16 @@ Download::receive_prev() { mark_dirty(); } +void +Download::receive_disconnect_peer() { + if (m_focus == m_peers.end()) + return; + + m_download->get_download().disconnect_peer(*m_focus); + + mark_dirty(); +} + void Download::receive_peer_connected(torrent::Peer p) { m_peers.push_back(p); @@ -250,6 +260,8 @@ Download::bind_keys() { (*m_bindings)['+'] = sigc::mem_fun(*this, &Download::receive_next_priority); (*m_bindings)['-'] = sigc::mem_fun(*this, &Download::receive_prev_priority); + (*m_bindings)['k'] = sigc::mem_fun(*this, &Download::receive_disconnect_peer); + (*m_bindings)['t'] = sigc::bind(sigc::mem_fun(m_download->get_download(), &torrent::Download::tracker_manual_request), false); (*m_bindings)['T'] = sigc::bind(sigc::mem_fun(m_download->get_download(), &torrent::Download::tracker_manual_request), true); diff --git a/src/ui/download.h b/src/ui/download.h index fdbbd1b7..6fd1b18f 100644 --- a/src/ui/download.h +++ b/src/ui/download.h @@ -98,6 +98,8 @@ private: void receive_next(); void receive_prev(); + void receive_disconnect_peer(); + void receive_peer_connected(torrent::Peer p); void receive_peer_disconnected(torrent::Peer p);