From 7007973c76bf9e593e404293cb2020649ade70f3 Mon Sep 17 00:00:00 2001 From: rakshasa Date: Thu, 14 Aug 2014 20:56:20 +0900 Subject: [PATCH 01/65] Added ipv6 patch. --- rak/socket_address.h | 174 ++++++++++++++++++++++++++++++-- src/command_download.cc | 10 ++ src/command_network.cc | 7 +- src/command_peer.cc | 8 +- src/core/curl_get.cc | 18 +++- src/core/curl_get.h | 7 ++ src/core/curl_stack.cc | 19 +++- src/core/manager.cc | 11 ++ src/display/window_peer_list.cc | 19 +++- src/utils/socket_fd.cc | 76 ++++++++++++++ src/utils/socket_fd.h | 4 + 11 files changed, 339 insertions(+), 14 deletions(-) diff --git a/rak/socket_address.h b/rak/socket_address.h index 25fdb37f9..d38533e55 100644 --- a/rak/socket_address.h +++ b/rak/socket_address.h @@ -145,7 +145,7 @@ class socket_address { }; }; -// Remeber to set the AF_INET. +// Remember to set the AF_INET. class socket_address_inet { public: @@ -184,6 +184,10 @@ class socket_address_inet { const sockaddr* c_sockaddr() const { return reinterpret_cast(&m_sockaddr); } const sockaddr_in* c_sockaddr_inet() const { return &m_sockaddr; } + +#ifdef RAK_USE_INET6 + socket_address_inet6 to_mapped_address() const; +#endif bool operator == (const socket_address_inet& rhs) const; bool operator < (const socket_address_inet& rhs) const; @@ -192,6 +196,52 @@ class socket_address_inet { struct sockaddr_in m_sockaddr; }; +#ifdef RAK_USE_INET6 +// Remember to set the AF_INET6. + +class socket_address_inet6 { +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 std::memcmp(&m_sockaddr.sin6_addr, &in6addr_any, sizeof(in6_addr)) == 0; } + + void clear() { std::memset(this, 0, sizeof(socket_address_inet6)); set_family(); } + + uint16_t port() const { return ntohs(m_sockaddr.sin6_port); } + uint16_t port_n() const { return m_sockaddr.sin6_port; } + void set_port(uint16_t p) { m_sockaddr.sin6_port = htons(p); } + void set_port_n(uint16_t p) { m_sockaddr.sin6_port = p; } + + in6_addr address() const { return m_sockaddr.sin6_addr; } + std::string address_str() const; + bool address_c_str(char* buf, socklen_t size) const; + + void set_address(in6_addr a) { m_sockaddr.sin6_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(in6addr_any); } + + sa_family_t family() const { return m_sockaddr.sin6_family; } + void set_family() { m_sockaddr.sin6_family = AF_INET6; } + + sockaddr* c_sockaddr() { return reinterpret_cast(&m_sockaddr); } + sockaddr_in6* c_sockaddr_inet6() { return &m_sockaddr; } + + const sockaddr* c_sockaddr() const { return reinterpret_cast(&m_sockaddr); } + const sockaddr_in6* c_sockaddr_inet6() const { return &m_sockaddr; } + + socket_address normalize_address() const; + + bool operator == (const socket_address_inet6& rhs) const; + bool operator < (const socket_address_inet6& rhs) const; + +private: + struct sockaddr_in6 m_sockaddr; +}; +#endif + // Unique key for the address, excluding port numbers etc. class socket_address_key { public: @@ -241,8 +291,10 @@ socket_address::is_valid() const { switch (family()) { case af_inet: return sa_inet()->is_valid(); -// case af_inet6: -// return sa_inet6().is_valid(); +#ifdef RAK_USE_INET6 + case af_inet6: + return sa_inet6()->is_valid(); +#endif default: return false; } @@ -253,6 +305,10 @@ socket_address::is_bindable() const { switch (family()) { case af_inet: return !sa_inet()->is_address_any(); +#ifdef RAK_USE_INET6 + case af_inet6: + return !sa_inet6()->is_address_any(); +#endif default: return false; } @@ -263,6 +319,10 @@ socket_address::is_address_any() const { switch (family()) { case af_inet: return sa_inet()->is_address_any(); +#ifdef RAK_USE_INET6 + case af_inet6: + return sa_inet6()->is_address_any(); +#endif default: return true; } @@ -273,6 +333,10 @@ socket_address::port() const { switch (family()) { case af_inet: return sa_inet()->port(); +#ifdef RAK_USE_INET6 + case af_inet6: + return sa_inet6()->port(); +#endif default: return 0; } @@ -283,6 +347,10 @@ socket_address::set_port(uint16_t p) { switch (family()) { case af_inet: return sa_inet()->set_port(p); +#ifdef RAK_USE_INET6 + case af_inet6: + return sa_inet6()->set_port(p); +#endif default: break; } @@ -293,6 +361,10 @@ socket_address::address_str() const { switch (family()) { case af_inet: return sa_inet()->address_str(); +#ifdef RAK_USE_INET6 + case af_inet6: + return sa_inet6()->address_str(); +#endif default: return std::string(); } @@ -303,6 +375,10 @@ socket_address::address_c_str(char* buf, socklen_t size) const { switch (family()) { case af_inet: return sa_inet()->address_c_str(buf, size); +#ifdef RAK_USE_INET6 + case af_inet6: + return sa_inet6()->address_c_str(buf, size); +#endif default: return false; } @@ -314,6 +390,12 @@ socket_address::set_address_c_str(const char* a) { sa_inet()->set_family(); return true; +#ifdef RAK_USE_INET6 + } else if (sa_inet6()->set_address_c_str(a)) { + sa_inet6()->set_family(); + return true; +#endif + } else { return false; } @@ -325,6 +407,10 @@ socket_address::length() const { switch(family()) { case af_inet: return sizeof(sockaddr_in); +#ifdef RAK_USE_INET6 + case af_inet6: + return sizeof(sockaddr_in6); +#endif default: return 0; } @@ -349,8 +435,10 @@ socket_address::operator == (const socket_address& rhs) const { switch (family()) { case af_inet: return *sa_inet() == *rhs.sa_inet(); -// case af_inet6: -// return *sa_inet6() == *rhs.sa_inet6(); +#ifdef RAK_USE_INET6 + case af_inet6: + return *sa_inet6() == *rhs.sa_inet6(); +#endif default: throw std::logic_error("socket_address::operator == (rhs) invalid type comparison."); } @@ -364,8 +452,10 @@ socket_address::operator < (const socket_address& rhs) const { switch (family()) { case af_inet: return *sa_inet() < *rhs.sa_inet(); -// case af_inet6: -// return *sa_inet6() < *rhs.sa_inet6(); +#ifdef RAK_USE_INET6 + case af_inet6: + return *sa_inet6() < *rhs.sa_inet6(); +#endif default: throw std::logic_error("socket_address::operator < (rhs) invalid type comparison."); } @@ -391,6 +481,23 @@ socket_address_inet::set_address_c_str(const char* a) { return inet_pton(AF_INET, a, &m_sockaddr.sin_addr); } +#ifdef RAK_USE_INET6 +inline socket_address_inet6 +socket_address_inet::to_mapped_address() const { + uint32_t addr32[4]; + addr32[0] = 0; + addr32[1] = 0; + addr32[2] = htonl(0xffff); + addr32[3] = m_sockaddr.sin_addr.s_addr; + + socket_address_inet6 sa; + sa.clear(); + sa.set_address(*reinterpret_cast(addr32)); + sa.set_port_n(m_sockaddr.sin_port); + return sa; +} +#endif + inline bool socket_address_inet::operator == (const socket_address_inet& rhs) const { return @@ -406,6 +513,59 @@ socket_address_inet::operator < (const socket_address_inet& rhs) const { m_sockaddr.sin_port < rhs.m_sockaddr.sin_port); } +#ifdef RAK_USE_INET6 + +inline std::string +socket_address_inet6::address_str() const { + char buf[INET6_ADDRSTRLEN]; + + if (!address_c_str(buf, INET6_ADDRSTRLEN)) + return std::string(); + + return std::string(buf); +} + +inline bool +socket_address_inet6::address_c_str(char* buf, socklen_t size) const { + return inet_ntop(family(), &m_sockaddr.sin6_addr, buf, size); +} + +inline bool +socket_address_inet6::set_address_c_str(const char* a) { + return inet_pton(AF_INET6, a, &m_sockaddr.sin6_addr); +} + +inline socket_address +socket_address_inet6::normalize_address() const { + const uint32_t *addr32 = reinterpret_cast(m_sockaddr.sin6_addr.s6_addr); + if (addr32[0] == 0 && addr32[1] == 0 && addr32[2] == htonl(0xffff)) { + socket_address addr4; + addr4.sa_inet()->set_family(); + addr4.sa_inet()->set_address_n(addr32[3]); + addr4.sa_inet()->set_port_n(m_sockaddr.sin6_port); + return addr4; + } + return *reinterpret_cast(this); +} + +inline bool +socket_address_inet6::operator == (const socket_address_inet6& rhs) const { + return + memcmp(&m_sockaddr.sin6_addr, &rhs.m_sockaddr.sin6_addr, sizeof(in6_addr)) == 0 && + m_sockaddr.sin6_port == rhs.m_sockaddr.sin6_port; +} + +inline bool +socket_address_inet6::operator < (const socket_address_inet6& rhs) const { + int addr_comp = memcmp(&m_sockaddr.sin6_addr, &rhs.m_sockaddr.sin6_addr, sizeof(in6_addr)); + return + addr_comp < 0 || + (addr_comp == 0 || + m_sockaddr.sin6_port < rhs.m_sockaddr.sin6_port); +} + +#endif + } #endif diff --git a/src/command_download.cc b/src/command_download.cc index 5a1b2ed32..4d63215d1 100644 --- a/src/command_download.cc +++ b/src/command_download.cc @@ -308,7 +308,13 @@ apply_d_add_peer(core::Download* download, const std::string& arg) { if (download->download()->info()->is_private()) throw torrent::input_error("Download is private."); +#ifdef RAK_USE_INET6 + ret = std::sscanf(arg.c_str(), "[%64[^]]]:%i%c", host, &port, &dummy); + if (ret < 1) + ret = std::sscanf(arg.c_str(), "%1023[^:]:%i%c", host, &port, &dummy); +#else ret = std::sscanf(arg.c_str(), "%1023[^:]:%i%c", host, &port, &dummy); +#endif if (ret == 1) port = 6881; @@ -318,7 +324,11 @@ apply_d_add_peer(core::Download* download, const std::string& arg) { if (port < 1 || port > 65535) throw torrent::input_error("Invalid port number."); +#ifdef RAK_USE_INET6 + torrent::connection_manager()->resolver()(host, (int)rak::socket_address::pf_unspec, SOCK_STREAM, call_add_d_peer_t(download, port)); +#else torrent::connection_manager()->resolver()(host, (int)rak::socket_address::pf_inet, SOCK_STREAM, call_add_d_peer_t(download, port)); +#endif } torrent::Object diff --git a/src/command_network.cc b/src/command_network.cc index 93af73bc1..77c294ece 100644 --- a/src/command_network.cc +++ b/src/command_network.cc @@ -170,8 +170,13 @@ apply_scgi(const std::string& arg, int type) { lt_log_print(torrent::LOG_RPC_EVENTS, "The SCGI socket has not been bound to any address and likely poses a security risk."); +#ifdef RAK_USE_INET6 + } else if (std::sscanf(arg.c_str(), "%1023[^:]:%i%c", address, &port, &dummy) == 2 || + std::sscanf(arg.c_str(), "[%64[^]]]:%i%c", address, &port, &dummy) == 2) { // [xx::xx]:port format +#else } else if (std::sscanf(arg.c_str(), "%1023[^:]:%i%c", address, &port, &dummy) == 2) { - if ((err = rak::address_info::get_address_info(address, PF_INET, SOCK_STREAM, &ai)) != 0) +#endif + if ((err = rak::address_info::get_address_info(address,PF_UNSPEC, SOCK_STREAM, &ai)) != 0) throw torrent::input_error("Could not bind address: " + std::string(rak::address_info::strerror(err)) + "."); saPtr = ai->address(); diff --git a/src/command_peer.cc b/src/command_peer.cc index 0cf103b52..abf0daeb0 100644 --- a/src/command_peer.cc +++ b/src/command_peer.cc @@ -69,7 +69,13 @@ retrieve_p_id_html(torrent::Peer* peer) { torrent::Object retrieve_p_address(torrent::Peer* peer) { - return rak::socket_address::cast_from(peer->peer_info()->socket_address())->address_str(); + const rak::socket_address *addr = rak::socket_address::cast_from(peer->peer_info()->socket_address()); +#ifdef RAK_USE_INET6 + if (addr->family() == rak::socket_address::af_inet6) + return "[" + addr->address_str() + "]"; + else +#endif + return addr->address_str(); } torrent::Object diff --git a/src/core/curl_get.cc b/src/core/curl_get.cc index 3179b7347..0cbc1384e 100644 --- a/src/core/curl_get.cc +++ b/src/core/curl_get.cc @@ -91,8 +91,13 @@ CurlGet::start() { curl_easy_setopt(m_handle, CURLOPT_NOSIGNAL, (long)1); curl_easy_setopt(m_handle, CURLOPT_FOLLOWLOCATION, (long)1); curl_easy_setopt(m_handle, CURLOPT_MAXREDIRS, (long)5); - curl_easy_setopt(m_handle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); + + curl_easy_setopt(m_handle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_WHATEVER); + curl_easy_setopt(m_handle, CURLOPT_ENCODING, ""); +#ifdef RAK_USE_INET6 + m_ipv6 = false; +#endif m_stack->add_get(this); } @@ -110,6 +115,17 @@ CurlGet::close() { m_handle = NULL; } +#ifdef RAK_USE_INET6 +void +CurlGet::retry_ipv6() { + CURL* nhandle = curl_easy_duphandle(m_handle); + curl_easy_setopt(nhandle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6); + curl_easy_cleanup(m_handle); + m_handle = nhandle; + m_ipv6 = true; +} +#endif + void CurlGet::receive_timeout() { return m_stack->transfer_done(m_handle, "Timed out"); diff --git a/src/core/curl_get.h b/src/core/curl_get.h index 88339c886..b8ad54513 100644 --- a/src/core/curl_get.h +++ b/src/core/curl_get.h @@ -57,6 +57,10 @@ class CurlGet : public torrent::Http { void start(); void close(); +#ifdef RAK_USE_INET6 + bool is_using_ipv6() { return m_ipv6; } + void retry_ipv6(); +#endif bool is_busy() const { return m_handle; } bool is_active() const { return m_active; } @@ -75,6 +79,9 @@ class CurlGet : public torrent::Http { void receive_timeout(); bool m_active; +#ifdef RAK_USE_INET6 + bool m_ipv6; +#endif rak::priority_item m_taskTimeout; diff --git a/src/core/curl_stack.cc b/src/core/curl_stack.cc index e220fccfc..05b628e0f 100644 --- a/src/core/curl_stack.cc +++ b/src/core/curl_stack.cc @@ -132,8 +132,23 @@ CurlStack::process_done_handle() { if (msg->msg != CURLMSG_DONE) throw torrent::internal_error("CurlStack::receive_action() msg->msg != CURLMSG_DONE."); - transfer_done(msg->easy_handle, - msg->data.result == CURLE_OK ? NULL : curl_easy_strerror(msg->data.result)); + if (msg->data.result == CURLE_COULDNT_RESOLVE_HOST) { + iterator itr = std::find_if(begin(), end(), rak::equal(msg->easy_handle, std::mem_fun(&CurlGet::handle))); + + if (itr == end()) + throw torrent::internal_error("Could not find CurlGet when calling CurlStack::receive_action."); + + if (!(*itr)->is_using_ipv6()) { + (*itr)->retry_ipv6(); + + if (curl_multi_add_handle((CURLM*)m_handle, (*itr)->handle()) > 0) + throw torrent::internal_error("Error calling curl_multi_add_handle."); + } + + } else { + transfer_done(msg->easy_handle, + msg->data.result == CURLE_OK ? NULL : curl_easy_strerror(msg->data.result)); + } return remaining_msgs != 0; } diff --git a/src/core/manager.cc b/src/core/manager.cc index 2c2bd3b4b..cdd1f88da 100644 --- a/src/core/manager.cc +++ b/src/core/manager.cc @@ -228,7 +228,13 @@ Manager::set_bind_address(const std::string& addr) { int err; rak::address_info* ai; + +#ifdef RAK_USE_INET6 + if ((err = rak::address_info::get_address_info(addr.c_str(), PF_INET, SOCK_STREAM, &ai)) != 0 && + (err = rak::address_info::get_address_info(addr.c_str(), PF_INET6, SOCK_STREAM, &ai)) != 0) +#else if ((err = rak::address_info::get_address_info(addr.c_str(), PF_INET, SOCK_STREAM, &ai)) != 0) +#endif throw torrent::input_error("Could not set bind address: " + std::string(rak::address_info::strerror(err)) + "."); try { @@ -262,7 +268,12 @@ Manager::set_local_address(const std::string& addr) { int err; rak::address_info* ai; +#ifdef RAK_USE_INET6 + if ((err = rak::address_info::get_address_info(addr.c_str(), PF_INET, SOCK_STREAM, &ai)) != 0 && + (err = rak::address_info::get_address_info(addr.c_str(), PF_INET6, SOCK_STREAM, &ai)) != 0) +#else if ((err = rak::address_info::get_address_info(addr.c_str(), PF_INET, SOCK_STREAM, &ai)) != 0) +#endif throw torrent::input_error("Could not set local address: " + std::string(rak::address_info::strerror(err)) + "."); try { diff --git a/src/display/window_peer_list.cc b/src/display/window_peer_list.cc index db3fbba34..76d2fd971 100644 --- a/src/display/window_peer_list.cc +++ b/src/display/window_peer_list.cc @@ -68,7 +68,11 @@ WindowPeerList::redraw() { int x = 2; int y = 0; - m_canvas->print(x, y, "IP"); x += 16; +#ifdef RAK_USE_INET6 + m_canvas->print(x, y, "IP"); x += 25; +#else + m_canvas->print(x, y, "IP"); x += 16; +#endif m_canvas->print(x, y, "UP"); x += 7; m_canvas->print(x, y, "DOWN"); x += 7; m_canvas->print(x, y, "PEER"); x += 7; @@ -99,10 +103,21 @@ WindowPeerList::redraw() { x = 0; + std::string ip_address = rak::socket_address::cast_from(p->address())->address_str(); +#ifdef RAK_USE_INET6 + if (ip_address.size() >= 24) { + ip_address.replace(ip_address.begin() + 21, ip_address.end(), "..."); + } +#endif + m_canvas->print(x, y, "%c %s", range.first == *m_focus ? '*' : ' ', - rak::socket_address::cast_from(p->address())->address_str().c_str()); + ip_address.c_str()); +#ifdef RAK_USE_INET6 + x += 27; +#else x += 18; +#endif m_canvas->print(x, y, "%.1f", (double)p->up_rate()->rate() / 1024); x += 7; m_canvas->print(x, y, "%.1f", (double)p->down_rate()->rate() / 1024); x += 7; diff --git a/src/utils/socket_fd.cc b/src/utils/socket_fd.cc index 338519d31..9cae67794 100644 --- a/src/utils/socket_fd.cc +++ b/src/utils/socket_fd.cc @@ -71,6 +71,11 @@ SocketFd::set_priority(priority_type p) { check_valid(); int opt = p; +#ifdef RAK_USE_INET6 + if (m_ipv6_socket) + return setsockopt(m_fd, IPPROTO_IPV6, IPV6_TCLASS, &opt, sizeof(opt)) == 0; + else +#endif return setsockopt(m_fd, IPPROTO_IP, IP_TOS, &opt, sizeof(opt)) == 0; } @@ -130,12 +135,36 @@ SocketFd::get_error() const { bool SocketFd::open_stream() { +#ifdef RAK_USE_INET6 + m_fd = socket(rak::socket_address::pf_inet6, SOCK_STREAM, IPPROTO_TCP); + if (m_fd == -1) { + m_ipv6_socket = false; + return (m_fd = socket(rak::socket_address::pf_inet, SOCK_STREAM, IPPROTO_TCP)) != -1; + } + m_ipv6_socket = true; + + int zero = 0; + return setsockopt(m_fd, IPPROTO_IPV6, IPV6_V6ONLY, &zero, sizeof(zero)) != -1; +#else return (m_fd = socket(rak::socket_address::pf_inet, SOCK_STREAM, IPPROTO_TCP)) != -1; +#endif } bool SocketFd::open_datagram() { +#ifdef RAK_USE_INET6 + m_fd = socket(rak::socket_address::pf_inet6, SOCK_DGRAM, 0); + if (m_fd == -1) { + m_ipv6_socket = false; + return (m_fd = socket(rak::socket_address::pf_inet, SOCK_DGRAM, 0)) != -1; + } + m_ipv6_socket = true; + + int zero = 0; + return setsockopt(m_fd, IPPROTO_IPV6, IPV6_V6ONLY, &zero, sizeof(zero)) != -1; +#else return (m_fd = socket(rak::socket_address::pf_inet, SOCK_DGRAM, 0)) != -1; +#endif } bool @@ -153,6 +182,12 @@ bool SocketFd::bind(const rak::socket_address& sa) { check_valid(); +#ifdef RAK_USE_INET6 + if (m_ipv6_socket && sa.family() == rak::socket_address::pf_inet) { + rak::socket_address_inet6 sa_mapped = sa.sa_inet()->to_mapped_address(); + return !::bind(m_fd, sa_mapped.c_sockaddr(), sizeof(sa_mapped)); + } +#endif return !::bind(m_fd, sa.c_sockaddr(), sa.length()); } @@ -160,6 +195,12 @@ bool SocketFd::bind(const rak::socket_address& sa, unsigned int length) { check_valid(); +#ifdef RAK_USE_INET6 + if (m_ipv6_socket && sa.family() == rak::socket_address::pf_inet) { + rak::socket_address_inet6 sa_mapped = sa.sa_inet()->to_mapped_address(); + return !::bind(m_fd, sa_mapped.c_sockaddr(), sizeof(sa_mapped)); + } +#endif return !::bind(m_fd, sa.c_sockaddr(), length); } @@ -167,9 +208,33 @@ bool SocketFd::connect(const rak::socket_address& sa) { check_valid(); +#ifdef RAK_USE_INET6 + if (m_ipv6_socket && sa.family() == rak::socket_address::pf_inet) { + rak::socket_address_inet6 sa_mapped = sa.sa_inet()->to_mapped_address(); + return !::connect(m_fd, sa_mapped.c_sockaddr(), sizeof(sa_mapped)) || errno == EINPROGRESS; + } +#endif return !::connect(m_fd, sa.c_sockaddr(), sa.length()) || errno == EINPROGRESS; } +bool +SocketFd::getsockname(rak::socket_address *sa) { + check_valid(); + + socklen_t len = sizeof(rak::socket_address); + if (::getsockname(m_fd, sa->c_sockaddr(), &len)) { + return false; + } + +#ifdef RAK_USE_INET6 + if (m_ipv6_socket && sa->family() == rak::socket_address::af_inet6) { + *sa = sa->sa_inet6()->normalize_address(); + } +#endif + + return true; +} + bool SocketFd::listen(int size) { check_valid(); @@ -182,7 +247,18 @@ SocketFd::accept(rak::socket_address* sa) { check_valid(); socklen_t len = sizeof(rak::socket_address); +#ifdef RAK_USE_INET6 + if (sa == NULL) { + return SocketFd(::accept(m_fd, NULL, &len)); + } + int fd = ::accept(m_fd, sa->c_sockaddr(), &len); + if (fd != -1 && m_ipv6_socket && sa->family() == rak::socket_address::af_inet6) { + *sa = sa->sa_inet6()->normalize_address(); + } + return SocketFd(fd); +#else return SocketFd(::accept(m_fd, sa != NULL ? sa->c_sockaddr() : NULL, &len)); +#endif } // unsigned int diff --git a/src/utils/socket_fd.h b/src/utils/socket_fd.h index 137665343..21ab19c0c 100644 --- a/src/utils/socket_fd.h +++ b/src/utils/socket_fd.h @@ -80,6 +80,7 @@ class SocketFd { bool bind(const rak::socket_address& sa); bool bind(const rak::socket_address& sa, unsigned int length); bool connect(const rak::socket_address& sa); + bool getsockname(rak::socket_address* sa); bool listen(int size); SocketFd accept(rak::socket_address* sa); @@ -91,6 +92,9 @@ class SocketFd { inline void check_valid() const; int m_fd; +#ifdef RAK_USE_INET6 + bool m_ipv6_socket; +#endif }; } From 6c39da6943fe2e77c6e97c32e0dadaff245f1368 Mon Sep 17 00:00:00 2001 From: rakshasa Date: Mon, 15 Sep 2014 16:03:10 +0900 Subject: [PATCH 02/65] Updated authors and readme. --- AUTHORS | 2 +- README | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/AUTHORS b/AUTHORS index 195fc222b..f9bdb537d 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1 +1 @@ -Jari Sundell +Jari Sundell diff --git a/README b/README index 6db6b254a..1dbceaa66 100644 --- a/README +++ b/README @@ -32,5 +32,10 @@ DEPENDENCIES CONTACT - Send bug reports, suggestions and patches to or -to the mailinglist. + Jari Sundell + + Skomakerveien 33 + 3185 Skoppum, NORWAY + + Send bug reports, suggestions and patches to + or to the mailinglist. From 0df0a6650dcd75653543a3f00a71f30293015392 Mon Sep 17 00:00:00 2001 From: rakshasa Date: Tue, 23 Sep 2014 18:56:29 +0900 Subject: [PATCH 03/65] Removed ifdef for ipv6. --- rak/socket_address.h | 83 +-------------------------------- src/command_download.cc | 9 +--- src/command_network.cc | 4 -- src/command_peer.cc | 5 +- src/core/curl_get.cc | 7 ++- src/core/curl_get.h | 5 +- src/core/manager.cc | 9 ---- src/display/window_peer_list.cc | 11 +---- src/utils/socket_fd.cc | 29 +++--------- src/utils/socket_fd.h | 2 - 10 files changed, 15 insertions(+), 149 deletions(-) diff --git a/rak/socket_address.h b/rak/socket_address.h index d38533e55..d1d5b7224 100644 --- a/rak/socket_address.h +++ b/rak/socket_address.h @@ -109,13 +109,11 @@ class socket_address { const sockaddr* c_sockaddr() const { return &m_sockaddr; } const sockaddr_in* c_sockaddr_inet() const { return &m_sockaddrInet; } -#ifdef RAK_USE_INET6 socket_address_inet6* sa_inet6() { return reinterpret_cast(this); } const socket_address_inet6* sa_inet6() const { return reinterpret_cast(this); } sockaddr_in6* c_sockaddr_inet6() { return &m_sockaddrInet6; } const sockaddr_in6* c_sockaddr_inet6() const { return &m_sockaddrInet6; } -#endif // 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 @@ -139,9 +137,7 @@ class socket_address { union { sockaddr m_sockaddr; sockaddr_in m_sockaddrInet; -#ifdef RAK_USE_INET6 sockaddr_in6 m_sockaddrInet6; -#endif }; }; @@ -185,9 +181,7 @@ class socket_address_inet { const sockaddr* c_sockaddr() const { return reinterpret_cast(&m_sockaddr); } const sockaddr_in* c_sockaddr_inet() const { return &m_sockaddr; } -#ifdef RAK_USE_INET6 socket_address_inet6 to_mapped_address() const; -#endif bool operator == (const socket_address_inet& rhs) const; bool operator < (const socket_address_inet& rhs) const; @@ -196,9 +190,6 @@ class socket_address_inet { struct sockaddr_in m_sockaddr; }; -#ifdef RAK_USE_INET6 -// Remember to set the AF_INET6. - class socket_address_inet6 { public: bool is_any() const { return is_port_any() && is_address_any(); } @@ -214,6 +205,7 @@ class socket_address_inet6 { void set_port_n(uint16_t p) { m_sockaddr.sin6_port = p; } in6_addr address() const { return m_sockaddr.sin6_addr; } + const in6_addr* address_ptr() const { return &m_sockaddr.sin6_addr; } std::string address_str() const; bool address_c_str(char* buf, socklen_t size) const; @@ -240,61 +232,14 @@ class socket_address_inet6 { private: struct sockaddr_in6 m_sockaddr; }; -#endif - -// Unique key for the address, excluding port numbers etc. -class socket_address_key { -public: -// socket_address_host_key() {} - - socket_address_key(const socket_address& sa) { - *this = sa; - } - - socket_address_key& operator = (const socket_address& sa) { - if (sa.family() == 0) { - std::memset(this, 0, sizeof(socket_address_key)); - - } else if (sa.family() == socket_address::af_inet) { - // Using hardware order as we use operator < to compare when - // using inet only. - m_addr.s_addr = sa.sa_inet()->address_h(); - - } else { - // When we implement INET6 handling, embed the ipv4 address in - // the ipv6 address. - throw std::logic_error("socket_address_key(...) received an unsupported protocol family."); - } - - return *this; - } - -// socket_address_key& operator = (const socket_address_key& sa) { -// } - - bool operator < (const socket_address_key& sa) const { - // Compare the memory area instead. - return m_addr.s_addr < sa.m_addr.s_addr; - } - -private: - union { - in_addr m_addr; -// #ifdef RAK_USE_INET6 -// in_addr6 m_addr6; -// #endif - }; -}; inline bool socket_address::is_valid() const { switch (family()) { case af_inet: return sa_inet()->is_valid(); -#ifdef RAK_USE_INET6 case af_inet6: return sa_inet6()->is_valid(); -#endif default: return false; } @@ -305,10 +250,8 @@ socket_address::is_bindable() const { switch (family()) { case af_inet: return !sa_inet()->is_address_any(); -#ifdef RAK_USE_INET6 case af_inet6: return !sa_inet6()->is_address_any(); -#endif default: return false; } @@ -319,10 +262,8 @@ socket_address::is_address_any() const { switch (family()) { case af_inet: return sa_inet()->is_address_any(); -#ifdef RAK_USE_INET6 case af_inet6: return sa_inet6()->is_address_any(); -#endif default: return true; } @@ -333,10 +274,8 @@ socket_address::port() const { switch (family()) { case af_inet: return sa_inet()->port(); -#ifdef RAK_USE_INET6 case af_inet6: return sa_inet6()->port(); -#endif default: return 0; } @@ -347,10 +286,8 @@ socket_address::set_port(uint16_t p) { switch (family()) { case af_inet: return sa_inet()->set_port(p); -#ifdef RAK_USE_INET6 case af_inet6: return sa_inet6()->set_port(p); -#endif default: break; } @@ -361,10 +298,8 @@ socket_address::address_str() const { switch (family()) { case af_inet: return sa_inet()->address_str(); -#ifdef RAK_USE_INET6 case af_inet6: return sa_inet6()->address_str(); -#endif default: return std::string(); } @@ -375,10 +310,8 @@ socket_address::address_c_str(char* buf, socklen_t size) const { switch (family()) { case af_inet: return sa_inet()->address_c_str(buf, size); -#ifdef RAK_USE_INET6 case af_inet6: return sa_inet6()->address_c_str(buf, size); -#endif default: return false; } @@ -390,11 +323,9 @@ socket_address::set_address_c_str(const char* a) { sa_inet()->set_family(); return true; -#ifdef RAK_USE_INET6 } else if (sa_inet6()->set_address_c_str(a)) { sa_inet6()->set_family(); return true; -#endif } else { return false; @@ -407,10 +338,8 @@ socket_address::length() const { switch(family()) { case af_inet: return sizeof(sockaddr_in); -#ifdef RAK_USE_INET6 case af_inet6: return sizeof(sockaddr_in6); -#endif default: return 0; } @@ -435,10 +364,8 @@ socket_address::operator == (const socket_address& rhs) const { switch (family()) { case af_inet: return *sa_inet() == *rhs.sa_inet(); -#ifdef RAK_USE_INET6 case af_inet6: return *sa_inet6() == *rhs.sa_inet6(); -#endif default: throw std::logic_error("socket_address::operator == (rhs) invalid type comparison."); } @@ -452,10 +379,8 @@ socket_address::operator < (const socket_address& rhs) const { switch (family()) { case af_inet: return *sa_inet() < *rhs.sa_inet(); -#ifdef RAK_USE_INET6 case af_inet6: return *sa_inet6() < *rhs.sa_inet6(); -#endif default: throw std::logic_error("socket_address::operator < (rhs) invalid type comparison."); } @@ -481,7 +406,6 @@ socket_address_inet::set_address_c_str(const char* a) { return inet_pton(AF_INET, a, &m_sockaddr.sin_addr); } -#ifdef RAK_USE_INET6 inline socket_address_inet6 socket_address_inet::to_mapped_address() const { uint32_t addr32[4]; @@ -496,7 +420,6 @@ socket_address_inet::to_mapped_address() const { sa.set_port_n(m_sockaddr.sin_port); return sa; } -#endif inline bool socket_address_inet::operator == (const socket_address_inet& rhs) const { @@ -513,8 +436,6 @@ socket_address_inet::operator < (const socket_address_inet& rhs) const { m_sockaddr.sin_port < rhs.m_sockaddr.sin_port); } -#ifdef RAK_USE_INET6 - inline std::string socket_address_inet6::address_str() const { char buf[INET6_ADDRSTRLEN]; @@ -564,8 +485,6 @@ socket_address_inet6::operator < (const socket_address_inet6& rhs) const { m_sockaddr.sin6_port < rhs.m_sockaddr.sin6_port); } -#endif - } #endif diff --git a/src/command_download.cc b/src/command_download.cc index 4d63215d1..3694066b5 100644 --- a/src/command_download.cc +++ b/src/command_download.cc @@ -308,13 +308,10 @@ apply_d_add_peer(core::Download* download, const std::string& arg) { if (download->download()->info()->is_private()) throw torrent::input_error("Download is private."); -#ifdef RAK_USE_INET6 ret = std::sscanf(arg.c_str(), "[%64[^]]]:%i%c", host, &port, &dummy); + if (ret < 1) ret = std::sscanf(arg.c_str(), "%1023[^:]:%i%c", host, &port, &dummy); -#else - ret = std::sscanf(arg.c_str(), "%1023[^:]:%i%c", host, &port, &dummy); -#endif if (ret == 1) port = 6881; @@ -324,11 +321,7 @@ apply_d_add_peer(core::Download* download, const std::string& arg) { if (port < 1 || port > 65535) throw torrent::input_error("Invalid port number."); -#ifdef RAK_USE_INET6 torrent::connection_manager()->resolver()(host, (int)rak::socket_address::pf_unspec, SOCK_STREAM, call_add_d_peer_t(download, port)); -#else - torrent::connection_manager()->resolver()(host, (int)rak::socket_address::pf_inet, SOCK_STREAM, call_add_d_peer_t(download, port)); -#endif } torrent::Object diff --git a/src/command_network.cc b/src/command_network.cc index 77c294ece..dc61997bb 100644 --- a/src/command_network.cc +++ b/src/command_network.cc @@ -170,12 +170,8 @@ apply_scgi(const std::string& arg, int type) { lt_log_print(torrent::LOG_RPC_EVENTS, "The SCGI socket has not been bound to any address and likely poses a security risk."); -#ifdef RAK_USE_INET6 } else if (std::sscanf(arg.c_str(), "%1023[^:]:%i%c", address, &port, &dummy) == 2 || std::sscanf(arg.c_str(), "[%64[^]]]:%i%c", address, &port, &dummy) == 2) { // [xx::xx]:port format -#else - } else if (std::sscanf(arg.c_str(), "%1023[^:]:%i%c", address, &port, &dummy) == 2) { -#endif if ((err = rak::address_info::get_address_info(address,PF_UNSPEC, SOCK_STREAM, &ai)) != 0) throw torrent::input_error("Could not bind address: " + std::string(rak::address_info::strerror(err)) + "."); diff --git a/src/command_peer.cc b/src/command_peer.cc index abf0daeb0..0b0e7a6ba 100644 --- a/src/command_peer.cc +++ b/src/command_peer.cc @@ -70,12 +70,11 @@ retrieve_p_id_html(torrent::Peer* peer) { torrent::Object retrieve_p_address(torrent::Peer* peer) { const rak::socket_address *addr = rak::socket_address::cast_from(peer->peer_info()->socket_address()); -#ifdef RAK_USE_INET6 + if (addr->family() == rak::socket_address::af_inet6) return "[" + addr->address_str() + "]"; else -#endif - return addr->address_str(); + return addr->address_str(); } torrent::Object diff --git a/src/core/curl_get.cc b/src/core/curl_get.cc index 0cbc1384e..30e461b0b 100644 --- a/src/core/curl_get.cc +++ b/src/core/curl_get.cc @@ -95,9 +95,8 @@ CurlGet::start() { curl_easy_setopt(m_handle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_WHATEVER); curl_easy_setopt(m_handle, CURLOPT_ENCODING, ""); -#ifdef RAK_USE_INET6 + m_ipv6 = false; -#endif m_stack->add_get(this); } @@ -115,16 +114,16 @@ CurlGet::close() { m_handle = NULL; } -#ifdef RAK_USE_INET6 void CurlGet::retry_ipv6() { CURL* nhandle = curl_easy_duphandle(m_handle); + curl_easy_setopt(nhandle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6); curl_easy_cleanup(m_handle); + m_handle = nhandle; m_ipv6 = true; } -#endif void CurlGet::receive_timeout() { diff --git a/src/core/curl_get.h b/src/core/curl_get.h index b8ad54513..4ecedb921 100644 --- a/src/core/curl_get.h +++ b/src/core/curl_get.h @@ -57,10 +57,9 @@ class CurlGet : public torrent::Http { void start(); void close(); -#ifdef RAK_USE_INET6 + bool is_using_ipv6() { return m_ipv6; } void retry_ipv6(); -#endif bool is_busy() const { return m_handle; } bool is_active() const { return m_active; } @@ -79,9 +78,7 @@ class CurlGet : public torrent::Http { void receive_timeout(); bool m_active; -#ifdef RAK_USE_INET6 bool m_ipv6; -#endif rak::priority_item m_taskTimeout; diff --git a/src/core/manager.cc b/src/core/manager.cc index cdd1f88da..b00fe6d43 100644 --- a/src/core/manager.cc +++ b/src/core/manager.cc @@ -228,13 +228,8 @@ Manager::set_bind_address(const std::string& addr) { int err; rak::address_info* ai; - -#ifdef RAK_USE_INET6 if ((err = rak::address_info::get_address_info(addr.c_str(), PF_INET, SOCK_STREAM, &ai)) != 0 && (err = rak::address_info::get_address_info(addr.c_str(), PF_INET6, SOCK_STREAM, &ai)) != 0) -#else - if ((err = rak::address_info::get_address_info(addr.c_str(), PF_INET, SOCK_STREAM, &ai)) != 0) -#endif throw torrent::input_error("Could not set bind address: " + std::string(rak::address_info::strerror(err)) + "."); try { @@ -268,12 +263,8 @@ Manager::set_local_address(const std::string& addr) { int err; rak::address_info* ai; -#ifdef RAK_USE_INET6 if ((err = rak::address_info::get_address_info(addr.c_str(), PF_INET, SOCK_STREAM, &ai)) != 0 && (err = rak::address_info::get_address_info(addr.c_str(), PF_INET6, SOCK_STREAM, &ai)) != 0) -#else - if ((err = rak::address_info::get_address_info(addr.c_str(), PF_INET, SOCK_STREAM, &ai)) != 0) -#endif throw torrent::input_error("Could not set local address: " + std::string(rak::address_info::strerror(err)) + "."); try { diff --git a/src/display/window_peer_list.cc b/src/display/window_peer_list.cc index 76d2fd971..aa1701d94 100644 --- a/src/display/window_peer_list.cc +++ b/src/display/window_peer_list.cc @@ -68,11 +68,7 @@ WindowPeerList::redraw() { int x = 2; int y = 0; -#ifdef RAK_USE_INET6 m_canvas->print(x, y, "IP"); x += 25; -#else - m_canvas->print(x, y, "IP"); x += 16; -#endif m_canvas->print(x, y, "UP"); x += 7; m_canvas->print(x, y, "DOWN"); x += 7; m_canvas->print(x, y, "PEER"); x += 7; @@ -104,20 +100,15 @@ WindowPeerList::redraw() { x = 0; std::string ip_address = rak::socket_address::cast_from(p->address())->address_str(); -#ifdef RAK_USE_INET6 + if (ip_address.size() >= 24) { ip_address.replace(ip_address.begin() + 21, ip_address.end(), "..."); } -#endif m_canvas->print(x, y, "%c %s", range.first == *m_focus ? '*' : ' ', ip_address.c_str()); -#ifdef RAK_USE_INET6 x += 27; -#else - x += 18; -#endif m_canvas->print(x, y, "%.1f", (double)p->up_rate()->rate() / 1024); x += 7; m_canvas->print(x, y, "%.1f", (double)p->down_rate()->rate() / 1024); x += 7; diff --git a/src/utils/socket_fd.cc b/src/utils/socket_fd.cc index 9cae67794..e30594dc4 100644 --- a/src/utils/socket_fd.cc +++ b/src/utils/socket_fd.cc @@ -71,12 +71,10 @@ SocketFd::set_priority(priority_type p) { check_valid(); int opt = p; -#ifdef RAK_USE_INET6 if (m_ipv6_socket) return setsockopt(m_fd, IPPROTO_IPV6, IPV6_TCLASS, &opt, sizeof(opt)) == 0; else -#endif - return setsockopt(m_fd, IPPROTO_IP, IP_TOS, &opt, sizeof(opt)) == 0; + return setsockopt(m_fd, IPPROTO_IP, IP_TOS, &opt, sizeof(opt)) == 0; } bool @@ -135,24 +133,21 @@ SocketFd::get_error() const { bool SocketFd::open_stream() { -#ifdef RAK_USE_INET6 m_fd = socket(rak::socket_address::pf_inet6, SOCK_STREAM, IPPROTO_TCP); + if (m_fd == -1) { m_ipv6_socket = false; return (m_fd = socket(rak::socket_address::pf_inet, SOCK_STREAM, IPPROTO_TCP)) != -1; } + m_ipv6_socket = true; int zero = 0; return setsockopt(m_fd, IPPROTO_IPV6, IPV6_V6ONLY, &zero, sizeof(zero)) != -1; -#else - return (m_fd = socket(rak::socket_address::pf_inet, SOCK_STREAM, IPPROTO_TCP)) != -1; -#endif } bool SocketFd::open_datagram() { -#ifdef RAK_USE_INET6 m_fd = socket(rak::socket_address::pf_inet6, SOCK_DGRAM, 0); if (m_fd == -1) { m_ipv6_socket = false; @@ -162,9 +157,6 @@ SocketFd::open_datagram() { int zero = 0; return setsockopt(m_fd, IPPROTO_IPV6, IPV6_V6ONLY, &zero, sizeof(zero)) != -1; -#else - return (m_fd = socket(rak::socket_address::pf_inet, SOCK_DGRAM, 0)) != -1; -#endif } bool @@ -182,12 +174,11 @@ bool SocketFd::bind(const rak::socket_address& sa) { check_valid(); -#ifdef RAK_USE_INET6 if (m_ipv6_socket && sa.family() == rak::socket_address::pf_inet) { rak::socket_address_inet6 sa_mapped = sa.sa_inet()->to_mapped_address(); return !::bind(m_fd, sa_mapped.c_sockaddr(), sizeof(sa_mapped)); } -#endif + return !::bind(m_fd, sa.c_sockaddr(), sa.length()); } @@ -195,12 +186,11 @@ bool SocketFd::bind(const rak::socket_address& sa, unsigned int length) { check_valid(); -#ifdef RAK_USE_INET6 if (m_ipv6_socket && sa.family() == rak::socket_address::pf_inet) { rak::socket_address_inet6 sa_mapped = sa.sa_inet()->to_mapped_address(); return !::bind(m_fd, sa_mapped.c_sockaddr(), sizeof(sa_mapped)); } -#endif + return !::bind(m_fd, sa.c_sockaddr(), length); } @@ -208,12 +198,11 @@ bool SocketFd::connect(const rak::socket_address& sa) { check_valid(); -#ifdef RAK_USE_INET6 if (m_ipv6_socket && sa.family() == rak::socket_address::pf_inet) { rak::socket_address_inet6 sa_mapped = sa.sa_inet()->to_mapped_address(); return !::connect(m_fd, sa_mapped.c_sockaddr(), sizeof(sa_mapped)) || errno == EINPROGRESS; } -#endif + return !::connect(m_fd, sa.c_sockaddr(), sa.length()) || errno == EINPROGRESS; } @@ -226,11 +215,9 @@ SocketFd::getsockname(rak::socket_address *sa) { return false; } -#ifdef RAK_USE_INET6 if (m_ipv6_socket && sa->family() == rak::socket_address::af_inet6) { *sa = sa->sa_inet6()->normalize_address(); } -#endif return true; } @@ -247,7 +234,6 @@ SocketFd::accept(rak::socket_address* sa) { check_valid(); socklen_t len = sizeof(rak::socket_address); -#ifdef RAK_USE_INET6 if (sa == NULL) { return SocketFd(::accept(m_fd, NULL, &len)); } @@ -256,9 +242,6 @@ SocketFd::accept(rak::socket_address* sa) { *sa = sa->sa_inet6()->normalize_address(); } return SocketFd(fd); -#else - return SocketFd(::accept(m_fd, sa != NULL ? sa->c_sockaddr() : NULL, &len)); -#endif } // unsigned int diff --git a/src/utils/socket_fd.h b/src/utils/socket_fd.h index 21ab19c0c..60101820d 100644 --- a/src/utils/socket_fd.h +++ b/src/utils/socket_fd.h @@ -92,9 +92,7 @@ class SocketFd { inline void check_valid() const; int m_fd; -#ifdef RAK_USE_INET6 bool m_ipv6_socket; -#endif }; } From d1e807acc5bada95dc9515a6c5d8ffecef06590d Mon Sep 17 00:00:00 2001 From: salorium Date: Tue, 7 Oct 2014 08:20:57 +0200 Subject: [PATCH 04/65] d.timestamp.finished for create torrent MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit English (translate): Adding initialization d.timestamp.finished at the torrent download but is not set seeding. For example when we create a torrent, it is not downloaded. French: Ajout de l'initialisation d.timestamp.finished lors que le torrent n'est pas télécharger mais mis en seeding. Par exemple lors que l'on créer un torrent, celui ci n'est pas télécharger. --- src/main.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main.cc b/src/main.cc index 5f4e2c33d..99ac1e7a2 100644 --- a/src/main.cc +++ b/src/main.cc @@ -273,6 +273,7 @@ main(int argc, char** argv) { "method.set_key = event.download.resumed, !_timestamp, ((d.timestamp.started.set_if_z, ((system.time)) ))\n" "method.set_key = event.download.finished, !_timestamp, ((d.timestamp.finished.set_if_z, ((system.time)) ))\n" + "method.set_key = event.download.hash_done, !_timestamp, {(branch,((d.complete)),((d.timestamp.finished.set_if_z,(system.time))))}\n" "method.insert.c_simple = group.insert_persistent_view," "((view.add,((argument.0)))),((view.persistent,((argument.0)))),((group.insert,((argument.0)),((argument.0))))\n" From b68d4c2db9ca68c2dbc5a32fd5a60a0e34c2579e Mon Sep 17 00:00:00 2001 From: yate Date: Sun, 15 May 2016 22:58:16 -0400 Subject: [PATCH 05/65] use whatever unit necessary in peer list info --- src/ui/element_peer_list.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ui/element_peer_list.cc b/src/ui/element_peer_list.cc index a8c2fc8d5..8e3ff09de 100644 --- a/src/ui/element_peer_list.cc +++ b/src/ui/element_peer_list.cc @@ -118,8 +118,8 @@ ElementPeerList::create_info() { element->push_back(""); element->push_column("Snubbed:", te_command("if=$p.is_snubbed=,yes,no")); element->push_column("Done:", te_command("p.completed_percent=")); - element->push_column("Rate:", te_command("cat=$convert.kb=$p.up_rate=,\\ KB\\ ,$convert.kb=$p.down_rate=,\\ KB")); - element->push_column("Total:", te_command("cat=$convert.kb=$p.up_total=,\\ KB\\ ,$convert.kb=$p.down_total=,\\ KB")); + element->push_column("Rate:", te_command("cat=$convert.xb=$p.up_rate=,\\ ,$convert.xb=$p.down_rate=")); + element->push_column("Total:", te_command("cat=$convert.xb=$p.up_total=,\\ ,$convert.xb=$p.down_total=")); element->set_column_width(element->column_width() + 1); element->set_error_handler(new display::TextElementCString("No peer selected.")); From 0797d636fbde0a13e839923361fc2945b3a9f3f9 Mon Sep 17 00:00:00 2001 From: jmdevince Date: Wed, 15 Jun 2016 09:46:33 -0400 Subject: [PATCH 06/65] Show non-preloaded pieces stats --- src/ui/download.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ui/download.cc b/src/ui/download.cc index 5f5d21021..6058fe771 100644 --- a/src/ui/download.cc +++ b/src/ui/download.cc @@ -194,7 +194,7 @@ Download::create_info() { element->push_column("Upload:", te_command("cat=$convert.kb=$d.up.rate=,\" KB / \",$convert.xb=$d.up.total=")); element->push_column("Download:", te_command("cat=$convert.kb=$d.down.rate=,\" KB / \",$convert.xb=$d.down.total=")); element->push_column("Skipped:", te_command("cat=$convert.kb=$d.skip.rate=,\" KB / \",$convert.xb=$d.skip.total=")); - element->push_column("Preload:", te_command("cat=$pieces.preload.type=,\" / \",$pieces.stats_preloaded=,\" / \",$pieces.stats_preloaded=")); + element->push_column("Preload:", te_command("cat=$pieces.preload.type=,\" / \",$pieces.stats_preloaded=,\" / \",$pieces.stats_not_preloaded=")); element->set_column_width(element->column_width() + 1); From c01709fa27de80def528ba77a12f8895b9ce9624 Mon Sep 17 00:00:00 2001 From: zp Date: Sun, 19 Jun 2016 02:06:30 -0500 Subject: [PATCH 07/65] Allow rtorrent to run as a daemon, slightly modified version of the PR provided by sallyswiss --- src/command_local.cc | 2 + src/control.cc | 8 +++- src/display/canvas.cc | 88 +++++++++++++++++++++++++------------------ src/display/canvas.h | 71 ++++++++++++++++++---------------- 4 files changed, 99 insertions(+), 70 deletions(-) diff --git a/src/command_local.cc b/src/command_local.cc index 67545870b..ccd879458 100644 --- a/src/command_local.cc +++ b/src/command_local.cc @@ -265,6 +265,8 @@ initialize_command_local() { CMD2_ANY ("system.time_usec", std::bind(&rak::timer::current_usec)); CMD2_ANY_VALUE_V ("system.umask.set", std::bind(&umask, std::placeholders::_2)); + + CMD2_VAR_BOOL ("system.use_daemon", false); CMD2_ANY ("system.cwd", std::bind(&system_get_cwd)); CMD2_ANY_STRING ("system.cwd.set", std::bind(&system_set_cwd, std::placeholders::_2)); diff --git a/src/control.cc b/src/control.cc index fc1b61b65..ed0331021 100644 --- a/src/control.cc +++ b/src/control.cc @@ -118,7 +118,9 @@ Control::initialize() { m_ui->init(this); - m_inputStdin->insert(torrent::main_thread()->poll()); + if(!display::Canvas::daemon()) { + m_inputStdin->insert(torrent::main_thread()->poll()); + } } void @@ -128,7 +130,9 @@ Control::cleanup() { priority_queue_erase(&taskScheduler, &m_taskShutdown); - m_inputStdin->remove(torrent::main_thread()->poll()); + if(!display::Canvas::daemon()) { + m_inputStdin->remove(torrent::main_thread()->poll()); + } m_core->download_store()->disable(); diff --git a/src/display/canvas.cc b/src/display/canvas.cc index 31db4ad44..ea2eb73b1 100644 --- a/src/display/canvas.cc +++ b/src/display/canvas.cc @@ -41,54 +41,63 @@ #include #include +#include "rpc/parse_commands.h" + #include "canvas.h" namespace display { bool Canvas::m_isInitialized = false; +bool Canvas::m_isDaemon = false; -Canvas::Canvas(int x, int y, int width, int height) : - m_window(newwin(height, width, y, x)) { +Canvas::Canvas(int x, int y, int width, int height) { + if (!m_isDaemon) { + m_window = newwin(height, width, y, x); - if (m_window == NULL) - throw torrent::internal_error("Could not allocate ncurses canvas."); + if (m_window == NULL) + throw torrent::internal_error("Could not allocate ncurses canvas."); + } } void Canvas::resize(int x, int y, int w, int h) { - wresize(m_window, h, w); - mvwin(m_window, y, x); + if (!m_isDaemon) { + wresize(m_window, h, w); + mvwin(m_window, y, x); + } } void Canvas::print_attributes(unsigned int x, unsigned int y, const char* first, const char* last, const attributes_list* attributes) { - move(x, y); + if (!m_isDaemon) { + move(x, y); - attr_t org_attr; - short org_pair; - wattr_get(m_window, &org_attr, &org_pair, NULL); + attr_t org_attr; + short org_pair; + wattr_get(m_window, &org_attr, &org_pair, NULL); - attributes_list::const_iterator attrItr = attributes->begin(); - wattr_set(m_window, Attributes::a_normal, Attributes::color_default, NULL); + attributes_list::const_iterator attrItr = attributes->begin(); + wattr_set(m_window, Attributes::a_normal, Attributes::color_default, NULL); - while (first != last) { - const char* next = last; + while (first != last) { + const char* next = last; - if (attrItr != attributes->end()) { - next = attrItr->position(); + if (attrItr != attributes->end()) { + next = attrItr->position(); - if (first >= next) { - wattr_set(m_window, attrItr->attributes(), attrItr->colors(), NULL); - ++attrItr; + if (first >= next) { + wattr_set(m_window, attrItr->attributes(), attrItr->colors(), NULL); + ++attrItr; + } } + + print("%.*s", next - first, first); + first = next; } - print("%.*s", next - first, first); - first = next; + // Reset the color. + wattr_set(m_window, org_attr, org_pair, NULL); } - - // Reset the color. - wattr_set(m_window, org_attr, org_pair, NULL); } void @@ -96,14 +105,18 @@ Canvas::initialize() { if (m_isInitialized) return; + m_isDaemon = rpc::call_command_value("system.use_daemon"); + m_isInitialized = true; - initscr(); - raw(); - noecho(); - nodelay(stdscr, TRUE); - keypad(stdscr, TRUE); - curs_set(0); + if (!m_isDaemon) { + initscr(); + raw(); + noecho(); + nodelay(stdscr, TRUE); + keypad(stdscr, TRUE); + curs_set(0); + } } void @@ -113,18 +126,21 @@ Canvas::cleanup() { m_isInitialized = false; - noraw(); - endwin(); + if (!m_isDaemon) { + noraw(); + endwin(); + } } std::pair Canvas::term_size() { struct winsize ws; - if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == 0) - return std::pair(ws.ws_col, ws.ws_row); - else - return std::pair(80, 24); + if (!m_isDaemon) { + if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == 0) + return std::pair(ws.ws_col, ws.ws_row); + } + return std::pair(80, 24); } } diff --git a/src/display/canvas.h b/src/display/canvas.h index 7023cadac..50da0fd8c 100644 --- a/src/display/canvas.h +++ b/src/display/canvas.h @@ -49,37 +49,37 @@ class Canvas { typedef std::vector attributes_list; Canvas(int x = 0, int y = 0, int width = 0, int height = 0); - ~Canvas() { delwin(m_window); } + ~Canvas() { if (!m_isDaemon) { delwin(m_window); } } - void refresh() { wnoutrefresh(m_window); } - static void refresh_std() { wnoutrefresh(stdscr); } - void redraw() { redrawwin(m_window); } - static void redraw_std() { redrawwin(stdscr); } + void refresh() { if (!m_isDaemon) { wnoutrefresh(m_window); } } + static void refresh_std() { if (!m_isDaemon) { wnoutrefresh(stdscr); } } + void redraw() { if (!m_isDaemon) { redrawwin(m_window); } } + static void redraw_std() { if (!m_isDaemon) { redrawwin(stdscr); } } - void resize(int w, int h) { wresize(m_window, h, w); } + void resize(int w, int h) { if (!m_isDaemon) { wresize(m_window, h, w); } } void resize(int x, int y, int w, int h); - static void resize_term(int x, int y) { resizeterm(y, x); } - static void resize_term(std::pair dim) { resizeterm(dim.second, dim.first); } + static void resize_term(int x, int y) { if (!m_isDaemon) { resizeterm(y, x); } } + static void resize_term(std::pair dim) { if (!m_isDaemon) { resizeterm(dim.second, dim.first); } } - unsigned int get_x() { int x, __UNUSED y; getyx(m_window, y, x); return x; } - unsigned int get_y() { int x, y; getyx(m_window, y, x); return y; } + unsigned int get_x() { int x, __UNUSED y; if (!m_isDaemon) { getyx(m_window, y, x); } else { x=1; } return x; } + unsigned int get_y() { int x, y; if (!m_isDaemon) { getyx(m_window, y, x); } else { y=1; } return y; } - unsigned int width() { int x, __UNUSED y; getmaxyx(m_window, y, x); return x; } - unsigned int height() { int x, y; getmaxyx(m_window, y, x); return y; } + unsigned int width() { int x, __UNUSED y; if (!m_isDaemon) { getmaxyx(m_window, y, x); } else { x=80; } return x; } + unsigned int height() { int x, y; if (!m_isDaemon) { getmaxyx(m_window, y, x); } else { y=24; } return y; } - void move(unsigned int x, unsigned int y) { wmove(m_window, y, x); } + void move(unsigned int x, unsigned int y) { if (!m_isDaemon) { wmove(m_window, y, x); } } - chtype get_background() { return getbkgd(m_window); } - void set_background(chtype c) { return wbkgdset(m_window, c); } + chtype get_background() { chtype bg=0; if (!m_isDaemon) { bg=getbkgd(m_window); } return bg; } + void set_background(chtype c) { if (!m_isDaemon) { return wbkgdset(m_window, c); } } - void erase() { werase(m_window); } - static void erase_std() { werase(stdscr); } + void erase() { if (!m_isDaemon) { werase(m_window); } } + static void erase_std() { if (!m_isDaemon) { werase(stdscr); } } void print_border(chtype ls, chtype rs, chtype ts, chtype bs, chtype tl, chtype tr, - chtype bl, chtype br) { wborder(m_window, ls, rs, ts, bs, tl, tr, bl, br); } + chtype bl, chtype br) { if (!m_isDaemon) { wborder(m_window, ls, rs, ts, bs, tl, tr, bl, br); } } // The format string is non-const, but that will not be a problem // since the string shall always be a C string choosen at @@ -90,29 +90,32 @@ class Canvas { void print_attributes(unsigned int x, unsigned int y, const char* first, const char* last, const attributes_list* attributes); - void print_char(const chtype ch) { waddch(m_window, ch); } - void print_char(unsigned int x, unsigned int y, const chtype ch) { mvwaddch(m_window, y, x, ch); } + void print_char(const chtype ch) { if (!m_isDaemon) { waddch(m_window, ch); } } + void print_char(unsigned int x, unsigned int y, const chtype ch) { if (!m_isDaemon) { mvwaddch(m_window, y, x, ch); } } - void set_attr(unsigned int x, unsigned int y, unsigned int n, int attr, int color) { mvwchgat(m_window, y, x, n, attr, color, NULL); } + void set_attr(unsigned int x, unsigned int y, unsigned int n, int attr, int color) { if (!m_isDaemon) { mvwchgat(m_window, y, x, n, attr, color, NULL); } } - void set_default_attributes(int attr) { (void)wattrset(m_window, attr); } + void set_default_attributes(int attr) { if (!m_isDaemon) { (void)wattrset(m_window, attr); } } // Initialize stdscr. static void initialize(); static void cleanup(); - static int get_screen_width() { int x, __UNUSED y; getmaxyx(stdscr, y, x); return x; } - static int get_screen_height() { int x, y; getmaxyx(stdscr, y, x); return y; } + static int get_screen_width() { int x, __UNUSED y; if (!m_isDaemon) { getmaxyx(stdscr, y, x); } else { x=80; } return x; } + static int get_screen_height() { int x, y; if (!m_isDaemon) { getmaxyx(stdscr, y, x); } else { y=24;} return y; } static std::pair term_size(); - static void do_update() { doupdate(); } + static void do_update() { if (!m_isDaemon) { doupdate(); } } + + static bool daemon() { return m_isDaemon; } private: Canvas(const Canvas&); void operator = (const Canvas&); static bool m_isInitialized; + static bool m_isDaemon; WINDOW* m_window; }; @@ -121,19 +124,23 @@ inline void Canvas::print(const char* str, ...) { va_list arglist; - va_start(arglist, str); - vw_printw(m_window, const_cast(str), arglist); - va_end(arglist); + if (!m_isDaemon) { + va_start(arglist, str); + vw_printw(m_window, const_cast(str), arglist); + va_end(arglist); + } } inline void Canvas::print(unsigned int x, unsigned int y, const char* str, ...) { va_list arglist; - va_start(arglist, str); - wmove(m_window, y, x); - vw_printw(m_window, const_cast(str), arglist); - va_end(arglist); + if (!m_isDaemon) { + va_start(arglist, str); + wmove(m_window, y, x); + vw_printw(m_window, const_cast(str), arglist); + va_end(arglist); + } } } From 7ea572967600a196a16e6c98768c6b57d7716682 Mon Sep 17 00:00:00 2001 From: zp Date: Sun, 19 Jun 2016 07:04:23 -0500 Subject: [PATCH 08/65] trim modified files --- src/command_local.cc | 16 ++++++++-------- src/control.cc | 6 +++--- src/display/canvas.cc | 8 ++++---- src/display/canvas.h | 6 +++--- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/command_local.cc b/src/command_local.cc index ccd879458..beeead5a3 100644 --- a/src/command_local.cc +++ b/src/command_local.cc @@ -5,12 +5,12 @@ // 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 @@ -135,7 +135,7 @@ check_name(const std::string& str) { throw torrent::input_error("Non-alphanumeric characters found."); return str; -} +} torrent::Object group_insert(const torrent::Object::list_type& args) { @@ -158,7 +158,7 @@ group_insert(const torrent::Object::list_type& args) { if (rpc::call_command_value("method.use_intermediate") == 1) { // Deprecated in 0.7.0: - + CMD2_REDIRECT_GENERIC_STR("group." + name + ".view", "group2." + name + ".view"); CMD2_REDIRECT_GENERIC_STR("group." + name + ".view.set", "group2." + name + ".view.set"); CMD2_REDIRECT_GENERIC_STR("group." + name + ".ratio.min", "group2." + name + ".ratio.min"); @@ -170,7 +170,7 @@ group_insert(const torrent::Object::list_type& args) { } if (rpc::call_command_value("method.use_intermediate") == 2) { // Deprecated in 0.7.0: - + CMD2_REDIRECT_GENERIC_STR_NO_EXPORT("group." + name + ".view", "group2." + name + ".view"); CMD2_REDIRECT_GENERIC_STR_NO_EXPORT("group." + name + ".view.set", "group2." + name + ".view.set"); CMD2_REDIRECT_GENERIC_STR_NO_EXPORT("group." + name + ".ratio.min", "group2." + name + ".ratio.min"); @@ -215,9 +215,9 @@ torrent::Object cmd_file_append(const torrent::Object::list_type& args) { if (args.empty()) throw torrent::input_error("Invalid number of arguments."); - + FILE* output = fopen(args.front().as_string().c_str(), "a"); - + if (output == NULL) throw torrent::input_error("Could not append to file '" + args.front().as_string() + "': " + rak::error_number::current().c_str()); @@ -265,7 +265,7 @@ initialize_command_local() { CMD2_ANY ("system.time_usec", std::bind(&rak::timer::current_usec)); CMD2_ANY_VALUE_V ("system.umask.set", std::bind(&umask, std::placeholders::_2)); - + CMD2_VAR_BOOL ("system.use_daemon", false); CMD2_ANY ("system.cwd", std::bind(&system_get_cwd)); diff --git a/src/control.cc b/src/control.cc index ed0331021..8e28da0dc 100644 --- a/src/control.cc +++ b/src/control.cc @@ -5,12 +5,12 @@ // 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 @@ -138,7 +138,7 @@ Control::cleanup() { m_ui->cleanup(); m_core->cleanup(); - + display::Canvas::erase_std(); display::Canvas::refresh_std(); display::Canvas::do_update(); diff --git a/src/display/canvas.cc b/src/display/canvas.cc index ea2eb73b1..02bdc193d 100644 --- a/src/display/canvas.cc +++ b/src/display/canvas.cc @@ -5,12 +5,12 @@ // 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 @@ -104,7 +104,7 @@ void Canvas::initialize() { if (m_isInitialized) return; - + m_isDaemon = rpc::call_command_value("system.use_daemon"); m_isInitialized = true; @@ -123,7 +123,7 @@ void Canvas::cleanup() { if (!m_isInitialized) return; - + m_isInitialized = false; if (!m_isDaemon) { diff --git a/src/display/canvas.h b/src/display/canvas.h index 50da0fd8c..b324d81a2 100644 --- a/src/display/canvas.h +++ b/src/display/canvas.h @@ -5,12 +5,12 @@ // 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 @@ -107,7 +107,7 @@ class Canvas { static std::pair term_size(); static void do_update() { if (!m_isDaemon) { doupdate(); } } - + static bool daemon() { return m_isDaemon; } private: From efc9097d62cd93e2d139d6d321b5a71d1b169502 Mon Sep 17 00:00:00 2001 From: rakshasa Date: Mon, 27 Jun 2016 01:46:54 +0900 Subject: [PATCH 09/65] Renamed system.use_daemon to system.daemon. --- src/command_local.cc | 2 +- src/display/canvas.cc | 2 +- src/main.cc | 6 ++++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/command_local.cc b/src/command_local.cc index beeead5a3..9236f9bb2 100644 --- a/src/command_local.cc +++ b/src/command_local.cc @@ -266,7 +266,7 @@ initialize_command_local() { CMD2_ANY_VALUE_V ("system.umask.set", std::bind(&umask, std::placeholders::_2)); - CMD2_VAR_BOOL ("system.use_daemon", false); + CMD2_VAR_BOOL ("system.daemon", false); CMD2_ANY ("system.cwd", std::bind(&system_get_cwd)); CMD2_ANY_STRING ("system.cwd.set", std::bind(&system_set_cwd, std::placeholders::_2)); diff --git a/src/display/canvas.cc b/src/display/canvas.cc index 02bdc193d..fc24bbc3f 100644 --- a/src/display/canvas.cc +++ b/src/display/canvas.cc @@ -105,7 +105,7 @@ Canvas::initialize() { if (m_isInitialized) return; - m_isDaemon = rpc::call_command_value("system.use_daemon"); + m_isDaemon = rpc::call_command_value("system.daemon"); m_isInitialized = true; diff --git a/src/main.cc b/src/main.cc index bfc34ff63..2bd73815f 100644 --- a/src/main.cc +++ b/src/main.cc @@ -190,8 +190,10 @@ main(int argc, char** argv) { control = new Control; - srandom(cachedTime.usec() ^ (getpid() << 16) ^ getppid()); - srand48(cachedTime.usec() ^ (getpid() << 16) ^ getppid()); + unsigned int random_seed = cachedTime.seconds() ^ cachedTime.usec() ^ (getpid() << 16) ^ getppid(); + + srandom(random_seed); + srand48(random_seed); SignalHandler::set_ignore(SIGPIPE); SignalHandler::set_handler(SIGINT, std::bind(&Control::receive_normal_shutdown, control)); From a8c67b4aab1dd95bc2e06f0f1105f74efe86b8aa Mon Sep 17 00:00:00 2001 From: chros Date: Wed, 6 Jul 2016 23:15:04 +0100 Subject: [PATCH 10/65] Fix scheduled sorting/filtering bug on started and stopped views in rtorrent (See #3) --- src/core/view.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/core/view.cc b/src/core/view.cc index c57c0f0e8..842fdbbfd 100644 --- a/src/core/view.cc +++ b/src/core/view.cc @@ -257,6 +257,10 @@ View::sort() { void View::filter() { + // Do NOT allow filter STARTED and STOPPED views: they are special + if (m_name == "started" || m_name == "stopped") + return; + // Parition the list in two steps so we know which elements changed. iterator splitVisible = std::stable_partition(begin_visible(), end_visible(), view_downloads_filter(m_filter)); iterator splitFiltered = std::stable_partition(begin_filtered(), end_filtered(), view_downloads_filter(m_filter)); From 3f698b3b3992039ec8dfeb8575d5180e7b95036a Mon Sep 17 00:00:00 2001 From: Speeddymon Date: Sat, 9 Jul 2016 13:59:08 -0500 Subject: [PATCH 11/65] Update example rtorrent.rc to 0.9 format --- doc/rtorrent.rc | 52 ++++++++++++++++++++++++------------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/doc/rtorrent.rc b/doc/rtorrent.rc index f58ef4b3b..9c70d424f 100644 --- a/doc/rtorrent.rc +++ b/doc/rtorrent.rc @@ -3,61 +3,61 @@ # uncomment the options you wish to enable. # Maximum and minimum number of peers to connect to per torrent. -#min_peers = 40 -#max_peers = 100 +#throttle.min_peers.normal.set = 40 +#throttle.max_peers.normal.set = 100 # Same as above but for seeding completed torrents (-1 = same as downloading) -#min_peers_seed = 10 -#max_peers_seed = 50 +#throttle.min_peers.seed.set = 10 +#throttle.max_peers.seed.set = 50 # Maximum number of simultanious uploads per torrent. -#max_uploads = 15 +#throttle.max_uploads.set = 15 # Global upload and download rate in KiB. "0" for unlimited. -#download_rate = 0 -#upload_rate = 0 +#throttle.global_down.max_rate.set_kb = 0 +#throttle.global_up.max_rate.set_kb = 0 # Default directory to save the downloaded torrents. -#directory = ./ +#directory.default.set = ./ # Default session directory. Make sure you don't run multiple instance # of rtorrent using the same session directory. Perhaps using a # relative path? -#session = ./session +#session.path.set = ./session # Watch a directory for new torrents, and stop those that have been # deleted. -#schedule = watch_directory,5,5,load.start=./watch/*.torrent -#schedule = untied_directory,5,5,stop_untied= +#schedule2 = watch_directory,5,5,load.start=./watch/*.torrent +#schedule2 = untied_directory,5,5,stop_untied= # Close torrents when diskspace is low. -#schedule = low_diskspace,5,60,close_low_diskspace=100M +#schedule2 = low_diskspace,5,60,close_low_diskspace=100M # The ip address reported to the tracker. -#ip = 127.0.0.1 -#ip = rakshasa.no +#network.local_address.set = 127.0.0.1 +#network.local_address.set = rakshasa.no # The ip address the listening socket and outgoing connections is # bound to. -#bind = 127.0.0.1 -#bind = rakshasa.no +#network.bind_address.set = 127.0.0.1 +#network.bind_address.set = rakshasa.no # Port range to use for listening. -#port_range = 6890-6999 +#network.port_range.set = 6890-6999 # Start opening ports at a random position within the port range. -#port_random = no +#network.port_random.set = no # Check hash for finished torrents. Might be usefull until the bug is # fixed that causes lack of diskspace not to be properly reported. -#check_hash = no +#pieces.hash.on_completion.set = no # Set whether the client should try to connect to UDP trackers. -#use_udp_trackers = yes +#trackers.use_udp.set = yes # Alternative calls to bind and ip that should handle dynamic ip's. -#schedule = ip_tick,0,1800,ip=rakshasa -#schedule = bind_tick,0,1800,bind=rakshasa +#schedule2 = ip_tick,0,1800,ip=rakshasa +#schedule2 = bind_tick,0,1800,bind=rakshasa # Encryption options, set to none (default) or any combination of the following: # allow_incoming, try_outgoing, require, require_RC4, enable_retry, prefer_plaintext @@ -66,19 +66,19 @@ # outgoing connections but retries with encryption if they fail, preferring # plaintext to RC4 encryption after the encrypted handshake # -# encryption = allow_incoming,enable_retry,prefer_plaintext +# protocol.encryption.set = allow_incoming,enable_retry,prefer_plaintext # Enable DHT support for trackerless torrents or when all trackers are down. # May be set to "disable" (completely disable DHT), "off" (do not start DHT), # "auto" (start and stop DHT as needed), or "on" (start DHT immediately). # The default is "off". For DHT to work, a session directory must be defined. # -# dht = auto +# dht.mode.set = auto # UDP port to use for DHT. # -# dht_port = 6881 +# dht.port.set = 6881 # Enable peer exchange (for torrents not marked private) # -# peer_exchange = yes +# protocol.pex.set = yes From f24154e7727b11848070ebe28f1963ad4bfd1e95 Mon Sep 17 00:00:00 2001 From: Speeddymon Date: Sat, 9 Jul 2016 14:02:31 -0500 Subject: [PATCH 12/65] Fix travis config --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index e2c5df1bf..9641c06e4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,7 +14,7 @@ before_install: # prevent `macro `AM_PATH_CPPUNIT' not found in library` in `autogen.sh` - sudo apt-get install libcppunit-dev - - git clone https://github.com/rakshasa/libtorrent.git && cd libtorrent && ./autogen.sh && configure && make -j12 && sudo make install && cd .. + - git clone https://github.com/rakshasa/libtorrent.git && cd libtorrent && ./autogen.sh && ./configure && make -j12 && sudo make install && cd .. # Figure out how to fix the issue running 'make check'. script: ./autogen.sh && ./configure && make -j12 && sudo make install From 8385957b0684d5bd7d36b958f1d698eb411d4d55 Mon Sep 17 00:00:00 2001 From: netpok Date: Fri, 15 Jul 2016 11:52:33 +0200 Subject: [PATCH 13/65] Fix warning message of deprecated commands --- src/main.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.cc b/src/main.cc index 2bd73815f..c66247d03 100644 --- a/src/main.cc +++ b/src/main.cc @@ -233,7 +233,7 @@ main(int argc, char** argv) { if (OptionParser::has_flag('D', argc, argv)) { rpc::call_command_set_value("method.use_deprecated.set", true); - lt_log_print(torrent::LOG_WARN, "Disabled deprecated commands."); + lt_log_print(torrent::LOG_WARN, "Enabled deprecated commands."); } if (OptionParser::has_flag('I', argc, argv)) { From 8140c3fe07489b88dfdb571c4dd64314597dfe46 Mon Sep 17 00:00:00 2001 From: chros Date: Thu, 21 Jul 2016 18:50:42 +0100 Subject: [PATCH 14/65] Expose meta property of downloads (See #5) --- src/command_download.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/command_download.cc b/src/command_download.cc index 5a1b2ed32..40cc5dea3 100644 --- a/src/command_download.cc +++ b/src/command_download.cc @@ -683,6 +683,7 @@ initialize_command_download() { CMD2_DL ("d.is_pex_active", CMD2_ON_INFO(is_pex_active)); CMD2_DL ("d.is_partially_done", CMD2_ON_DATA(is_partially_done)); CMD2_DL ("d.is_not_partially_done", CMD2_ON_DATA(is_not_partially_done)); + CMD2_DL ("d.is_meta", CMD2_ON_INFO(is_meta_download)); CMD2_DL_V ("d.resume", std::bind(&core::DownloadList::resume_default, control->core()->download_list(), std::placeholders::_1)); CMD2_DL_V ("d.pause", std::bind(&core::DownloadList::pause_default, control->core()->download_list(), std::placeholders::_1)); From d111594d2031545e45ffd5b14b819b61c562dc2c Mon Sep 17 00:00:00 2001 From: rakshasa Date: Wed, 3 Aug 2016 23:01:28 +0900 Subject: [PATCH 15/65] Added merzlya's torrent status display changes. --- doc/rtorrent.rc | 25 ++++++- src/command_ui.cc | 2 + src/display/utils.cc | 104 ++++++++++++++++++++++++++++ src/display/utils.h | 1 + src/display/window_download_list.cc | 39 +++++++---- src/main.cc | 5 ++ src/ui/element_download_list.cc | 6 ++ src/ui/element_download_list.h | 2 + 8 files changed, 168 insertions(+), 16 deletions(-) diff --git a/doc/rtorrent.rc b/doc/rtorrent.rc index 9c70d424f..78186a792 100644 --- a/doc/rtorrent.rc +++ b/doc/rtorrent.rc @@ -3,59 +3,74 @@ # uncomment the options you wish to enable. # Maximum and minimum number of peers to connect to per torrent. +# #throttle.min_peers.normal.set = 40 #throttle.max_peers.normal.set = 100 # Same as above but for seeding completed torrents (-1 = same as downloading) +# #throttle.min_peers.seed.set = 10 #throttle.max_peers.seed.set = 50 # Maximum number of simultanious uploads per torrent. +# #throttle.max_uploads.set = 15 # Global upload and download rate in KiB. "0" for unlimited. +# #throttle.global_down.max_rate.set_kb = 0 #throttle.global_up.max_rate.set_kb = 0 # Default directory to save the downloaded torrents. +# #directory.default.set = ./ # Default session directory. Make sure you don't run multiple instance # of rtorrent using the same session directory. Perhaps using a # relative path? +# #session.path.set = ./session # Watch a directory for new torrents, and stop those that have been # deleted. +# #schedule2 = watch_directory,5,5,load.start=./watch/*.torrent #schedule2 = untied_directory,5,5,stop_untied= # Close torrents when diskspace is low. +# #schedule2 = low_diskspace,5,60,close_low_diskspace=100M # The ip address reported to the tracker. +# #network.local_address.set = 127.0.0.1 #network.local_address.set = rakshasa.no # The ip address the listening socket and outgoing connections is # bound to. +# #network.bind_address.set = 127.0.0.1 #network.bind_address.set = rakshasa.no # Port range to use for listening. +# #network.port_range.set = 6890-6999 # Start opening ports at a random position within the port range. +# #network.port_random.set = no # Check hash for finished torrents. Might be usefull until the bug is # fixed that causes lack of diskspace not to be properly reported. +# #pieces.hash.on_completion.set = no # Set whether the client should try to connect to UDP trackers. +# #trackers.use_udp.set = yes # Alternative calls to bind and ip that should handle dynamic ip's. +# #schedule2 = ip_tick,0,1800,ip=rakshasa #schedule2 = bind_tick,0,1800,bind=rakshasa @@ -76,9 +91,13 @@ # dht.mode.set = auto # UDP port to use for DHT. -# -# dht.port.set = 6881 +# +#dht.port.set = 6881 # Enable peer exchange (for torrents not marked private) # -# protocol.pex.set = yes +#protocol.pex.set = yes + +# Set downlad list layout style (default - 0, compact - 1) +# +#download_list_layout = 1 diff --git a/src/command_ui.cc b/src/command_ui.cc index bc9124dcd..88a2f8738 100644 --- a/src/command_ui.cc +++ b/src/command_ui.cc @@ -523,6 +523,8 @@ void initialize_command_ui() { CMD2_VAR_STRING("keys.layout", "qwerty"); + CMD2_VAR_VALUE("download.list.layout", 0); + CMD2_ANY_STRING("view.add", object_convert_void(std::bind(&core::ViewManager::insert_throw, control->view_manager(), std::placeholders::_2))); CMD2_ANY_L ("view.list", std::bind(&apply_view_list)); diff --git a/src/display/utils.cc b/src/display/utils.cc index 2ab4c1a75..640a7226c 100644 --- a/src/display/utils.cc +++ b/src/display/utils.cc @@ -182,6 +182,110 @@ print_download_info(char* first, char* last, core::Download* d) { return first; } +char* +print_download_info2(char* first, char* last, core::Download* d) { + //Name + std::string name = "Name"; + if(d) name = d->info()->name(); + name.resize(64,' '); + first = print_buffer(first, last, " %s", name.c_str()); + + //Status + first = print_buffer(first, last, "|"); + if (!d) + first = print_buffer(first, last, " Status "); + else if (!d->download()->info()->is_open()) + first = print_buffer(first, last, " CLOSED "); + else if (!d->download()->info()->is_active()) + first = print_buffer(first, last, " OPEN "); + else + first = print_buffer(first, last, " "); + + //Downloaded + first = print_buffer(first, last, "|"); + if (!d) + first = print_buffer(first, last, " Downloaded "); + else + first = print_buffer(first, last, " %7.1f MB ", (double)d->download()->bytes_done() / (double)(1 << 20)); + + //Size + first = print_buffer(first, last, "|"); + if (!d) + first = print_buffer(first, last, " Size "); + else + first = print_buffer(first, last, " %7.1f MB ", (double)d->download()->file_list()->size_bytes() / (double)(1 << 20)); + + //Done + first = print_buffer(first, last, "|"); + if (!d) + first = print_buffer(first, last, " Done "); + else if (d->is_done()) + first = print_buffer(first, last, " 100%% "); + else if (d->is_open()) + first = print_buffer(first, last, " %2u%% ",(d->download()->file_list()->completed_chunks() * 100) / d->download()->file_list()->size_chunks()); + else + first = print_buffer(first, last, " "); + + //Rate Up + first = print_buffer(first, last, "|"); + if (!d) + first = print_buffer(first, last, " Up Rate "); + else + first = print_buffer(first, last, " %6.1f KB ", (double)d->info()->up_rate()->rate() / (1 << 10)); + + //Rate Down + first = print_buffer(first, last, "|"); + if (!d) + first = print_buffer(first, last, " Down Rate "); + else + first = print_buffer(first, last, " %6.1f KB ", (double)d->info()->down_rate()->rate() / (1 << 10)); + + //Uploaded + first = print_buffer(first, last, "|"); + if (!d) + first = print_buffer(first, last, " Uploaded "); + else + first = print_buffer(first, last, " %7.1f MB ", (double)d->info()->up_rate()->total() / (1 << 20)); + + //ETA + first = print_buffer(first, last, "| "); + if (!d) + first = print_buffer(first, last, " ETA "); + else if (d->download()->info()->is_active() && !d->is_done()) + first = print_download_time_left(first, last, d); + else + first = print_buffer(first, last, " "); + + //Ratio + first = print_buffer(first, last, " |"); + if (!d) + first = print_buffer(first, last, " Ratio"); + else + first = print_buffer(first, last, " %4.2f ", (double)rpc::call_command_value("d.ratio", rpc::make_target(d)) / 1000.0); + + //Misc + first = print_buffer(first, last, "|"); + if (!d) { + first = print_buffer(first, last, " Misc "); + } else { + first = print_buffer(first, last, " %c%c", + rpc::call_command_string("d.tied_to_file", rpc::make_target(d)).empty() ? ' ' : 'T', + rpc::call_command_value("d.ignore_commands", rpc::make_target(d)) == 0 ? ' ' : 'I', + (double)rpc::call_command_value("d.ratio", rpc::make_target(d)) / 1000.0); + + if (d->priority() != 2) + first = print_buffer(first, last, " %s", rpc::call_command_string("d.priority_str", rpc::make_target(d)).c_str()); + + if (!d->bencode()->get_key("rtorrent").get_key_string("throttle_name").empty()) + first = print_buffer(first, last , " %s", rpc::call_command_string("d.throttle_name", rpc::make_target(d)).c_str()); + } + + if (first > last) + throw torrent::internal_error("print_download_info(...) wrote past end of the buffer."); + + return first; +} + char* print_download_status(char* first, char* last, core::Download* d) { if (d->is_active()) diff --git a/src/display/utils.h b/src/display/utils.h index 7f75425c0..ccb392d1a 100644 --- a/src/display/utils.h +++ b/src/display/utils.h @@ -67,6 +67,7 @@ char* print_ddmmyyyy(char* first, char* last, time_t t); char* print_download_title(char* first, char* last, core::Download* d); char* print_download_info(char* first, char* last, core::Download* d); +char* print_download_info2(char* first, char* last, core::Download* d); char* print_download_status(char* first, char* last, core::Download* d); char* print_download_time_left(char* first, char* last, core::Download* d); char* print_download_percentage_done(char* first, char* last, core::Download* d); diff --git a/src/display/window_download_list.cc b/src/display/window_download_list.cc index 138ea8c98..b490c5572 100644 --- a/src/display/window_download_list.cc +++ b/src/display/window_download_list.cc @@ -40,6 +40,7 @@ #include "core/download.h" #include "core/view.h" +#include "rpc/parse_commands.h" #include "canvas.h" #include "globals.h" @@ -73,6 +74,8 @@ WindowDownloadList::set_view(core::View* l) { void WindowDownloadList::redraw() { + const int layout = rpc::call_command_value("download.list.layout"); + m_slotSchedule(this, (cachedTime + rak::timer::from_seconds(1)).round_seconds()); m_canvas->erase(); @@ -90,7 +93,7 @@ WindowDownloadList::redraw() { Range range = rak::advance_bidirectional(m_view->begin_visible(), m_view->focus() != m_view->end_visible() ? m_view->focus() : m_view->begin_visible(), m_view->end_visible(), - m_canvas->height() / 3); + m_canvas->height()/(layout ? 1 : 3)); // Make sure we properly fill out the last lines so it looks like // there are more torrents, yet don't hide it if we got the last one @@ -99,20 +102,30 @@ WindowDownloadList::redraw() { ++range.second; int pos = 1; + char buffer[m_canvas->width() + 1]; + char* last = buffer + m_canvas->width() - 2 + 1; - while (range.first != range.second) { - char buffer[m_canvas->width() + 1]; - char* last = buffer + m_canvas->width() - 2 + 1; - - print_download_title(buffer, last, *range.first); - m_canvas->print(0, pos++, "%c %s", range.first == m_view->focus() ? '*' : ' ', buffer); - - print_download_info(buffer, last, *range.first); - m_canvas->print(0, pos++, "%c %s", range.first == m_view->focus() ? '*' : ' ', buffer); - - print_download_status(buffer, last, *range.first); - m_canvas->print(0, pos++, "%c %s", range.first == m_view->focus() ? '*' : ' ', buffer); + if(layout) { + print_download_info2(buffer, last, NULL); + m_canvas->set_default_attributes(A_BOLD); + m_canvas->print(0, pos++, " %s", buffer); + } + while (range.first != range.second) { + if(layout) { + print_download_info2(buffer, last, *range.first); + m_canvas->set_default_attributes(range.first == m_view->focus() ? A_REVERSE : A_NORMAL); + m_canvas->print(0, pos++, "%c %s", range.first == m_view->focus() ? '*' : ' ', buffer); + } else { + print_download_title(buffer, last, *range.first); + m_canvas->print(0, pos++, "%c %s", range.first == m_view->focus() ? '*' : ' ', buffer); + + print_download_info(buffer, last, *range.first); + m_canvas->print(0, pos++, "%c %s", range.first == m_view->focus() ? '*' : ' ', buffer); + + print_download_status(buffer, last, *range.first); + m_canvas->print(0, pos++, "%c %s", range.first == m_view->focus() ? '*' : ' ', buffer); + } ++range.first; } } diff --git a/src/main.cc b/src/main.cc index c66247d03..2735dc841 100644 --- a/src/main.cc +++ b/src/main.cc @@ -416,6 +416,11 @@ main(int argc, char** argv) { CMD2_REDIRECT_GENERIC("to_xb", "convert.xb"); CMD2_REDIRECT_GENERIC("to_throttle", "convert.throttle"); + // TODO: Rename to something with 'ui.fooobar.....' and put + // together with the other ui options. In fact, add redirect for + // that other new ui option. + CMD2_REDIRECT ("download_list_layout", "download.list.layout.set"); + // Deprecated commands. Don't use these anymore. if (rpc::call_command_value("method.use_intermediate") == 1) { diff --git a/src/ui/element_download_list.cc b/src/ui/element_download_list.cc index bc40e7e25..5a782751a 100644 --- a/src/ui/element_download_list.cc +++ b/src/ui/element_download_list.cc @@ -99,6 +99,8 @@ ElementDownloadList::ElementDownloadList() : m_bindings[KEY_UP] = m_bindings['P' - '@'] = std::bind(&ElementDownloadList::receive_prev, this); m_bindings[KEY_DOWN] = m_bindings['N' - '@'] = std::bind(&ElementDownloadList::receive_next, this); + + m_bindings['L'] = std::bind(&ElementDownloadList::toggle_layout, this); } void @@ -221,4 +223,8 @@ ElementDownloadList::receive_change_view(const std::string& name) { set_view(*itr); } +void +ElementDownloadList::toggle_layout() { + rpc::call_command("download.list.layout.set", (rpc::call_command_value("download.list.layout") + 1)%2); +} } diff --git a/src/ui/element_download_list.h b/src/ui/element_download_list.h index 20185b50d..5bf4f08f7 100644 --- a/src/ui/element_download_list.h +++ b/src/ui/element_download_list.h @@ -77,6 +77,8 @@ class ElementDownloadList : public ElementBase { void receive_change_view(const std::string& name); + void toggle_layout(); + private: WDownloadList* m_window; core::View* m_view; From 2c60226bd2f4a366fb4de63d9cb38db01df94616 Mon Sep 17 00:00:00 2001 From: rakshasa Date: Wed, 3 Aug 2016 23:57:02 +0900 Subject: [PATCH 16/65] Cleaned up compact display. --- doc/rtorrent.rc | 4 +- src/command_ui.cc | 5 +- src/display/utils.cc | 170 +++++++++-------------- src/display/utils.h | 7 +- src/display/window_download_list.cc | 48 ++++--- src/display/window_download_statusbar.cc | 2 +- src/main.cc | 5 +- 7 files changed, 108 insertions(+), 133 deletions(-) diff --git a/doc/rtorrent.rc b/doc/rtorrent.rc index 78186a792..9c940ebe3 100644 --- a/doc/rtorrent.rc +++ b/doc/rtorrent.rc @@ -98,6 +98,6 @@ # #protocol.pex.set = yes -# Set downlad list layout style (default - 0, compact - 1) +# Set downlad list layout style. ("full", "compact") # -#download_list_layout = 1 +#torrent_list_layout = "full" diff --git a/src/command_ui.cc b/src/command_ui.cc index 88a2f8738..69ee2f540 100644 --- a/src/command_ui.cc +++ b/src/command_ui.cc @@ -523,8 +523,6 @@ void initialize_command_ui() { CMD2_VAR_STRING("keys.layout", "qwerty"); - CMD2_VAR_VALUE("download.list.layout", 0); - CMD2_ANY_STRING("view.add", object_convert_void(std::bind(&core::ViewManager::insert_throw, control->view_manager(), std::placeholders::_2))); CMD2_ANY_L ("view.list", std::bind(&apply_view_list)); @@ -557,6 +555,9 @@ initialize_command_ui() { CMD2_ANY ("ui.current_view", std::bind(&cmd_ui_current_view)); CMD2_ANY_STRING("ui.current_view.set", std::bind(&cmd_ui_set_view, std::placeholders::_2)); + // TODO: Add 'option_string' for rtorrent-specific options. + CMD2_VAR_STRING("ui.torrent_list.layout", "full"); + // Move. CMD2_ANY("print", &apply_print); CMD2_ANY("cat", &apply_cat); diff --git a/src/display/utils.cc b/src/display/utils.cc index 640a7226c..93011e827 100644 --- a/src/display/utils.cc +++ b/src/display/utils.cc @@ -133,7 +133,7 @@ print_download_title(char* first, char* last, core::Download* d) { } char* -print_download_info(char* first, char* last, core::Download* d) { +print_download_info_full(char* first, char* last, core::Download* d) { if (!d->download()->info()->is_open()) first = print_buffer(first, last, "[CLOSED] "); else if (!d->download()->info()->is_active()) @@ -177,111 +177,7 @@ print_download_info(char* first, char* last, core::Download* d) { first = print_buffer(first, last , "]"); if (first > last) - throw torrent::internal_error("print_download_info(...) wrote past end of the buffer."); - - return first; -} - -char* -print_download_info2(char* first, char* last, core::Download* d) { - //Name - std::string name = "Name"; - if(d) name = d->info()->name(); - name.resize(64,' '); - first = print_buffer(first, last, " %s", name.c_str()); - - //Status - first = print_buffer(first, last, "|"); - if (!d) - first = print_buffer(first, last, " Status "); - else if (!d->download()->info()->is_open()) - first = print_buffer(first, last, " CLOSED "); - else if (!d->download()->info()->is_active()) - first = print_buffer(first, last, " OPEN "); - else - first = print_buffer(first, last, " "); - - //Downloaded - first = print_buffer(first, last, "|"); - if (!d) - first = print_buffer(first, last, " Downloaded "); - else - first = print_buffer(first, last, " %7.1f MB ", (double)d->download()->bytes_done() / (double)(1 << 20)); - - //Size - first = print_buffer(first, last, "|"); - if (!d) - first = print_buffer(first, last, " Size "); - else - first = print_buffer(first, last, " %7.1f MB ", (double)d->download()->file_list()->size_bytes() / (double)(1 << 20)); - - //Done - first = print_buffer(first, last, "|"); - if (!d) - first = print_buffer(first, last, " Done "); - else if (d->is_done()) - first = print_buffer(first, last, " 100%% "); - else if (d->is_open()) - first = print_buffer(first, last, " %2u%% ",(d->download()->file_list()->completed_chunks() * 100) / d->download()->file_list()->size_chunks()); - else - first = print_buffer(first, last, " "); - - //Rate Up - first = print_buffer(first, last, "|"); - if (!d) - first = print_buffer(first, last, " Up Rate "); - else - first = print_buffer(first, last, " %6.1f KB ", (double)d->info()->up_rate()->rate() / (1 << 10)); - - //Rate Down - first = print_buffer(first, last, "|"); - if (!d) - first = print_buffer(first, last, " Down Rate "); - else - first = print_buffer(first, last, " %6.1f KB ", (double)d->info()->down_rate()->rate() / (1 << 10)); - - //Uploaded - first = print_buffer(first, last, "|"); - if (!d) - first = print_buffer(first, last, " Uploaded "); - else - first = print_buffer(first, last, " %7.1f MB ", (double)d->info()->up_rate()->total() / (1 << 20)); - - //ETA - first = print_buffer(first, last, "| "); - if (!d) - first = print_buffer(first, last, " ETA "); - else if (d->download()->info()->is_active() && !d->is_done()) - first = print_download_time_left(first, last, d); - else - first = print_buffer(first, last, " "); - - //Ratio - first = print_buffer(first, last, " |"); - if (!d) - first = print_buffer(first, last, " Ratio"); - else - first = print_buffer(first, last, " %4.2f ", (double)rpc::call_command_value("d.ratio", rpc::make_target(d)) / 1000.0); - - //Misc - first = print_buffer(first, last, "|"); - if (!d) { - first = print_buffer(first, last, " Misc "); - } else { - first = print_buffer(first, last, " %c%c", - rpc::call_command_string("d.tied_to_file", rpc::make_target(d)).empty() ? ' ' : 'T', - rpc::call_command_value("d.ignore_commands", rpc::make_target(d)) == 0 ? ' ' : 'I', - (double)rpc::call_command_value("d.ratio", rpc::make_target(d)) / 1000.0); - - if (d->priority() != 2) - first = print_buffer(first, last, " %s", rpc::call_command_string("d.priority_str", rpc::make_target(d)).c_str()); - - if (!d->bencode()->get_key("rtorrent").get_key_string("throttle_name").empty()) - first = print_buffer(first, last , " %s", rpc::call_command_string("d.throttle_name", rpc::make_target(d)).c_str()); - } - - if (first > last) - throw torrent::internal_error("print_download_info(...) wrote past end of the buffer."); + throw torrent::internal_error("print_download_info_full(...) wrote past end of the buffer."); return first; } @@ -322,6 +218,68 @@ print_download_status(char* first, char* last, core::Download* d) { return first; } +char* +print_download_column_compact(char* first, char* last) { + first = print_buffer(first, last, " %-64.64s", "Name"); + first = print_buffer(first, last, "| Status | Downloaded | Size | Done | Up Rate | Down Rate | Uploaded | ETA | Ratio| Misc "); + + if (first > last) + throw torrent::internal_error("print_download_column_compact(...) wrote past end of the buffer."); + + return first; +} + +char* +print_download_info_compact(char* first, char* last, core::Download* d) { + first = print_buffer(first, last, " %-64.64s", d->info()->name().c_str()); + first = print_buffer(first, last, "|"); + + if (!d->download()->info()->is_open()) + first = print_buffer(first, last, " CLOSED "); + else if (!d->download()->info()->is_active()) + first = print_buffer(first, last, " OPEN "); + else + first = print_buffer(first, last, " "); + + first = print_buffer(first, last, "| %7.1f MB ", (double)d->download()->bytes_done() / (double)(1 << 20)); + first = print_buffer(first, last, "| %7.1f MB ", (double)d->download()->file_list()->size_bytes() / (double)(1 << 20)); + first = print_buffer(first, last, "|"); + + if (d->is_done()) + first = print_buffer(first, last, " 100%% "); + else if (d->is_open()) + first = print_buffer(first, last, " %2u%% ",(d->download()->file_list()->completed_chunks() * 100) / d->download()->file_list()->size_chunks()); + else + first = print_buffer(first, last, " "); + + first = print_buffer(first, last, "| %6.1f KB ", (double)d->info()->up_rate()->rate() / (1 << 10)); + first = print_buffer(first, last, "| %6.1f KB ", (double)d->info()->down_rate()->rate() / (1 << 10)); + first = print_buffer(first, last, "| %7.1f MB ", (double)d->info()->up_rate()->total() / (1 << 20)); + first = print_buffer(first, last, "| "); + + if (d->download()->info()->is_active() && !d->is_done()) + first = print_download_time_left(first, last, d); + else + first = print_buffer(first, last, " "); + + first = print_buffer(first, last, "| %4.2f ", (double)rpc::call_command_value("d.ratio", rpc::make_target(d)) / 1000.0); + first = print_buffer(first, last, "| %c%c", + rpc::call_command_string("d.tied_to_file", rpc::make_target(d)).empty() ? ' ' : 'T', + rpc::call_command_value("d.ignore_commands", rpc::make_target(d)) == 0 ? ' ' : 'I', + (double)rpc::call_command_value("d.ratio", rpc::make_target(d)) / 1000.0); + + if (d->priority() != 2) + first = print_buffer(first, last, " %s", rpc::call_command_string("d.priority_str", rpc::make_target(d)).c_str()); + + if (!d->bencode()->get_key("rtorrent").get_key_string("throttle_name").empty()) + first = print_buffer(first, last , " %s", rpc::call_command_string("d.throttle_name", rpc::make_target(d)).c_str()); + + if (first > last) + throw torrent::internal_error("print_download_info_compact(...) wrote past end of the buffer."); + + return first; +} + char* print_download_time_left(char* first, char* last, core::Download* d) { uint32_t rate = d->info()->down_rate()->rate(); diff --git a/src/display/utils.h b/src/display/utils.h index ccb392d1a..eb2daf8ed 100644 --- a/src/display/utils.h +++ b/src/display/utils.h @@ -66,9 +66,12 @@ char* print_ddhhmm(char* first, char* last, time_t t); char* print_ddmmyyyy(char* first, char* last, time_t t); char* print_download_title(char* first, char* last, core::Download* d); -char* print_download_info(char* first, char* last, core::Download* d); -char* print_download_info2(char* first, char* last, core::Download* d); +char* print_download_info_full(char* first, char* last, core::Download* d); char* print_download_status(char* first, char* last, core::Download* d); + +char* print_download_column_compact(char* first, char* last); +char* print_download_info_compact(char* first, char* last, core::Download* d); + char* print_download_time_left(char* first, char* last, core::Download* d); char* print_download_percentage_done(char* first, char* last, core::Download* d); diff --git a/src/display/window_download_list.cc b/src/display/window_download_list.cc index b490c5572..749115555 100644 --- a/src/display/window_download_list.cc +++ b/src/display/window_download_list.cc @@ -74,8 +74,6 @@ WindowDownloadList::set_view(core::View* l) { void WindowDownloadList::redraw() { - const int layout = rpc::call_command_value("download.list.layout"); - m_slotSchedule(this, (cachedTime + rak::timer::from_seconds(1)).round_seconds()); m_canvas->erase(); @@ -88,12 +86,24 @@ WindowDownloadList::redraw() { if (m_view->empty_visible() || m_canvas->width() < 5 || m_canvas->height() < 2) return; + int layout_height; + const std::string layout_name = rpc::call_command_string("ui.torrent_list.layout"); + + if (layout_name == "full") { + layout_height = 3; + } else if (layout_name == "compact") { + layout_height = 1; + } else { + m_canvas->print(0, 0, "INVALID ui.torrent_list.layout '%s'", layout_name.c_str()); + return; + } + typedef std::pair Range; Range range = rak::advance_bidirectional(m_view->begin_visible(), m_view->focus() != m_view->end_visible() ? m_view->focus() : m_view->begin_visible(), m_view->end_visible(), - m_canvas->height()/(layout ? 1 : 3)); + m_canvas->height() / layout_height); // Make sure we properly fill out the last lines so it looks like // there are more torrents, yet don't hide it if we got the last one @@ -105,29 +115,35 @@ WindowDownloadList::redraw() { char buffer[m_canvas->width() + 1]; char* last = buffer + m_canvas->width() - 2 + 1; - if(layout) { - print_download_info2(buffer, last, NULL); + // Add a proper 'column info' method. + if (layout_name == "compact") { + print_download_column_compact(buffer, last); + m_canvas->set_default_attributes(A_BOLD); m_canvas->print(0, pos++, " %s", buffer); } - while (range.first != range.second) { - if(layout) { - print_download_info2(buffer, last, *range.first); - m_canvas->set_default_attributes(range.first == m_view->focus() ? A_REVERSE : A_NORMAL); - m_canvas->print(0, pos++, "%c %s", range.first == m_view->focus() ? '*' : ' ', buffer); - } else { + if (layout_name == "full") { + while (range.first != range.second) { print_download_title(buffer, last, *range.first); m_canvas->print(0, pos++, "%c %s", range.first == m_view->focus() ? '*' : ' ', buffer); - - print_download_info(buffer, last, *range.first); + print_download_info_full(buffer, last, *range.first); m_canvas->print(0, pos++, "%c %s", range.first == m_view->focus() ? '*' : ' ', buffer); - print_download_status(buffer, last, *range.first); m_canvas->print(0, pos++, "%c %s", range.first == m_view->focus() ? '*' : ' ', buffer); + + range.first++; + } + + } else { + while (range.first != range.second) { + print_download_info_compact(buffer, last, *range.first); + m_canvas->set_default_attributes(range.first == m_view->focus() ? A_REVERSE : A_NORMAL); + m_canvas->print(0, pos++, "%c %s", range.first == m_view->focus() ? '*' : ' ', buffer); + + range.first++; } - ++range.first; - } + } } } diff --git a/src/display/window_download_statusbar.cc b/src/display/window_download_statusbar.cc index bbf0379f4..284b8b54a 100644 --- a/src/display/window_download_statusbar.cc +++ b/src/display/window_download_statusbar.cc @@ -66,7 +66,7 @@ WindowDownloadStatusbar::redraw() { char buffer[m_canvas->width()]; char* last = buffer + m_canvas->width() - 2; - print_download_info(buffer, last, m_download); + print_download_info_full(buffer, last, m_download); m_canvas->print(0, 0, "%s", buffer); snprintf(buffer, last - buffer, "Peers: %i(%i) Min/Max: %i/%i Slots: U:%i/%i D:%i/%i U/I/C/A: %i/%i/%i/%i Unchoked: %u/%u Failed: %i", diff --git a/src/main.cc b/src/main.cc index 2735dc841..58d31a236 100644 --- a/src/main.cc +++ b/src/main.cc @@ -416,10 +416,7 @@ main(int argc, char** argv) { CMD2_REDIRECT_GENERIC("to_xb", "convert.xb"); CMD2_REDIRECT_GENERIC("to_throttle", "convert.throttle"); - // TODO: Rename to something with 'ui.fooobar.....' and put - // together with the other ui options. In fact, add redirect for - // that other new ui option. - CMD2_REDIRECT ("download_list_layout", "download.list.layout.set"); + CMD2_REDIRECT ("torrent_list_layout", "ui.torrent_list.layout.set"); // Deprecated commands. Don't use these anymore. From 66619840d89d1c093cd24567aea970a1ca0ebafe Mon Sep 17 00:00:00 2001 From: rakshasa Date: Sat, 6 Aug 2016 03:02:14 +0900 Subject: [PATCH 17/65] Increased max file size to 512GB. --- src/command_local.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/command_local.cc b/src/command_local.cc index 9236f9bb2..741b3000f 100644 --- a/src/command_local.cc +++ b/src/command_local.cc @@ -242,7 +242,7 @@ initialize_command_local() { CMD2_VAR_C_STRING("system.client_version", PACKAGE_VERSION); CMD2_VAR_C_STRING("system.library_version", torrent::version()); CMD2_VAR_VALUE ("system.file.allocate", 0); - CMD2_VAR_VALUE ("system.file.max_size", (int64_t)128 << 30); + CMD2_VAR_VALUE ("system.file.max_size", (int64_t)512 << 30); CMD2_VAR_VALUE ("system.file.split_size", -1); CMD2_VAR_STRING ("system.file.split_suffix", ".part"); From 51c5190eb1b630c1066fbb555d894a26ae0dd95f Mon Sep 17 00:00:00 2001 From: rakshasa Date: Sat, 6 Aug 2016 05:24:43 +0900 Subject: [PATCH 18/65] Removed commands that were deprecated in version 0.7.0. --- src/main.cc | 393 ---------------------------------------------------- 1 file changed, 393 deletions(-) diff --git a/src/main.cc b/src/main.cc index 58d31a236..687e57c88 100644 --- a/src/main.cc +++ b/src/main.cc @@ -436,399 +436,6 @@ main(int argc, char** argv) { #if LT_SLIM_VERSION != 1 if (rpc::call_command_value("method.use_deprecated")) { - // Deprecated in 0.7.0: - - CMD2_REDIRECT_GENERIC("system.method.insert", "method.insert"); - CMD2_REDIRECT_GENERIC("system.method.erase", "method.erase"); - CMD2_REDIRECT_GENERIC("system.method.get", "method.get"); - CMD2_REDIRECT_GENERIC("system.method.set", "method.set"); - CMD2_REDIRECT_GENERIC("system.method.list_keys", "method.list_keys"); - CMD2_REDIRECT_GENERIC("system.method.has_key", "method.has_key"); - CMD2_REDIRECT_GENERIC("system.method.set_key", "method.set_key"); - - CMD2_REDIRECT ("get_directory", "directory.default"); - CMD2_REDIRECT_GENERIC("set_directory", "directory.default.set"); - - CMD2_REDIRECT ("get_session", "session.path"); - CMD2_REDIRECT_GENERIC("set_session", "session.path.set"); - - CMD2_REDIRECT ("session_save", "session.save"); - - CMD2_REDIRECT ("get_name", "session.name"); - CMD2_REDIRECT_GENERIC("set_name", "session.name.set"); - - CMD2_REDIRECT ("system.file_allocate", "system.file.allocate"); - CMD2_REDIRECT ("system.file_allocate.set", "system.file.allocate.set"); - CMD2_REDIRECT ("get_max_file_size", "system.file.max_size"); - CMD2_REDIRECT_GENERIC("set_max_file_size", "system.file.max_size.set"); - CMD2_REDIRECT ("get_split_file_size", "system.file.split_size"); - CMD2_REDIRECT_GENERIC("set_split_file_size", "system.file.split_size.set"); - CMD2_REDIRECT ("get_split_suffix", "system.file.split_suffix"); - CMD2_REDIRECT_GENERIC("set_split_suffix", "system.file.split_suffix.set"); - - CMD2_REDIRECT ("get_timeout_sync", "pieces.sync.timeout"); - CMD2_REDIRECT_GENERIC("set_timeout_sync", "pieces.sync.timeout.set"); - CMD2_REDIRECT ("get_timeout_safe_sync", "pieces.sync.timeout_safe"); - CMD2_REDIRECT_GENERIC("set_timeout_safe_sync", "pieces.sync.timeout_safe.set"); - - CMD2_REDIRECT_GENERIC("get_preload_type", "pieces.preload.type"); - CMD2_REDIRECT_GENERIC("get_preload_min_size", "pieces.preload.min_size"); - CMD2_REDIRECT_GENERIC("get_preload_required_rate", "pieces.preload.min_rate"); - CMD2_REDIRECT_GENERIC("set_preload_type", "pieces.preload.type.set"); - CMD2_REDIRECT_GENERIC("set_preload_min_size", "pieces.preload.min_size.set"); - CMD2_REDIRECT_GENERIC("set_preload_required_rate", "pieces.preload.min_rate.set"); - CMD2_REDIRECT_GENERIC("get_stats_preloaded", "pieces.stats_preloaded"); - CMD2_REDIRECT_GENERIC("get_stats_not_preloaded", "pieces.stats_not_preloaded"); - - CMD2_REDIRECT_GENERIC("get_safe_sync", "pieces.sync.always_safe"); - CMD2_REDIRECT_GENERIC("set_safe_sync", "pieces.sync.always_safe.set"); - - CMD2_REDIRECT ("get_memory_usage", "pieces.memory.current"); - CMD2_REDIRECT_GENERIC("get_max_memory_usage", "pieces.memory.max"); - CMD2_REDIRECT_GENERIC("set_max_memory_usage", "pieces.memory.max.set"); - - CMD2_REDIRECT_GENERIC("load", "load.normal"); - CMD2_REDIRECT_GENERIC("load_verbose", "load.verbose"); - CMD2_REDIRECT_GENERIC("load_start", "load.start"); - CMD2_REDIRECT_GENERIC("load_start_verbose", "load.start_verbose"); - - CMD2_REDIRECT_GENERIC("load_raw", "load.raw"); - CMD2_REDIRECT_GENERIC("load_raw_start", "load.raw_start"); - CMD2_REDIRECT_GENERIC("load_raw_verbose", "load.raw_verbose"); - - CMD2_REDIRECT_GENERIC("get_connection_leech", "protocol.connection.leech"); - CMD2_REDIRECT_GENERIC("get_connection_seed", "protocol.connection.seed"); - CMD2_REDIRECT_GENERIC("set_connection_leech", "protocol.connection.leech.set"); - CMD2_REDIRECT_GENERIC("set_connection_seed", "protocol.connection.seed.set"); - - // - // Throttle: - // - - CMD2_REDIRECT_GENERIC("throttle_up", "throttle.up"); - CMD2_REDIRECT_GENERIC("throttle_down", "throttle.down"); - CMD2_REDIRECT_GENERIC("throttle_ip", "throttle.ip"); - - CMD2_REDIRECT_GENERIC("get_throttle_up_max", "throttle.up.max"); - CMD2_REDIRECT_GENERIC("get_throttle_up_rate", "throttle.up.rate"); - CMD2_REDIRECT_GENERIC("get_throttle_down_max", "throttle.down.max"); - CMD2_REDIRECT_GENERIC("get_throttle_down_rate", "throttle.down.rate"); - - CMD2_REDIRECT_GENERIC("set_min_peers", "throttle.min_peers.normal.set"); - CMD2_REDIRECT_GENERIC("set_max_peers", "throttle.max_peers.normal.set"); - CMD2_REDIRECT_GENERIC("set_min_peers_seed", "throttle.min_peers.seed.set"); - CMD2_REDIRECT_GENERIC("set_max_peers_seed", "throttle.max_peers.seed.set"); - - CMD2_REDIRECT_GENERIC("set_max_uploads", "throttle.max_uploads.set"); - - CMD2_REDIRECT_GENERIC("set_max_uploads_div", "throttle.max_uploads.div.set"); - CMD2_REDIRECT_GENERIC("set_max_uploads_global", "throttle.max_uploads.global.set"); - CMD2_REDIRECT_GENERIC("set_max_downloads_div", "throttle.max_downloads.div.set"); - CMD2_REDIRECT_GENERIC("set_max_downloads_global", "throttle.max_downloads.global.set"); - - CMD2_REDIRECT ("get_min_peers", "throttle.min_peers.normal"); - CMD2_REDIRECT ("get_max_peers", "throttle.max_peers.normal"); - CMD2_REDIRECT ("get_min_peers_seed", "throttle.min_peers.seed"); - CMD2_REDIRECT ("get_max_peers_seed", "throttle.max_peers.seed"); - - CMD2_REDIRECT ("get_max_uploads", "throttle.max_uploads"); - - CMD2_REDIRECT ("get_max_uploads_div", "throttle.max_uploads.div"); - CMD2_REDIRECT ("get_max_uploads_global", "throttle.max_uploads.global"); - CMD2_REDIRECT ("get_max_downloads_div", "throttle.max_downloads.div"); - CMD2_REDIRECT ("get_max_downloads_global", "throttle.max_downloads.global"); - - CMD2_REDIRECT ("get_up_rate", "throttle.global_up.rate"); - CMD2_REDIRECT ("get_up_total", "throttle.global_up.total"); - CMD2_REDIRECT ("get_upload_rate", "throttle.global_up.max_rate"); - CMD2_REDIRECT_GENERIC("set_upload_rate", "throttle.global_up.max_rate.set"); - CMD2_REDIRECT ("get_down_rate", "throttle.global_down.rate"); - CMD2_REDIRECT ("get_down_total", "throttle.global_down.total"); - CMD2_REDIRECT ("get_download_rate", "throttle.global_down.max_rate"); - CMD2_REDIRECT_GENERIC("set_download_rate", "throttle.global_down.max_rate.set"); - - // - // Network: - // - - CMD2_REDIRECT ("get_send_buffer_size", "network.send_buffer.size"); - CMD2_REDIRECT_GENERIC("set_send_buffer_size", "network.send_buffer.size.set"); - CMD2_REDIRECT ("get_receive_buffer_size", "network.receive_buffer.size"); - CMD2_REDIRECT_GENERIC("set_receive_buffer_size", "network.receive_buffer.size.set"); - - CMD2_REDIRECT_GENERIC("set_bind", "network.bind_address.set"); - CMD2_REDIRECT ("get_bind", "network.bind_address"); - - CMD2_REDIRECT_GENERIC("set_ip", "network.local_address.set"); - CMD2_REDIRECT ("get_ip", "network.local_address"); - - CMD2_REDIRECT ("get_port_range", "network.port_range"); - CMD2_REDIRECT_GENERIC("set_port_range", "network.port_range.set"); - - CMD2_REDIRECT ("get_port_random", "network.port_random"); - CMD2_REDIRECT_GENERIC("set_port_random", "network.port_random.set"); - - CMD2_REDIRECT ("port_open", "network.port_open.set"); - CMD2_REDIRECT ("get_port_open", "network.port_open"); - CMD2_REDIRECT_GENERIC("set_port_open", "network.port_open.set"); - - CMD2_REDIRECT_GENERIC("set_proxy_address", "network.proxy_address.set"); - CMD2_REDIRECT ("get_proxy_address", "network.proxy_address"); - - CMD2_REDIRECT_GENERIC("set_scgi_dont_route", "network.scgi.dont_route.set"); - CMD2_REDIRECT ("get_scgi_dont_route", "network.scgi.dont_route"); - - CMD2_REDIRECT ("get_max_open_sockets", "network.max_open_sockets"); - - CMD2_REDIRECT ("get_max_open_files", "network.max_open_files"); - CMD2_REDIRECT_GENERIC("set_max_open_files", "network.max_open_files.set"); - - // - // XMLRPC stuff: - // - - CMD2_REDIRECT_GENERIC("xmlrpc_dialect", "network.xmlrpc.dialect.set"); - CMD2_REDIRECT_GENERIC("set_xmlrpc_dialect", "network.xmlrpc.dialect.set"); - - CMD2_REDIRECT_GENERIC("xmlrpc_size_limit", "network.xmlrpc.size_limit.set"); - CMD2_REDIRECT ("get_xmlrpc_size_limit", "network.xmlrpc.size_limit"); - CMD2_REDIRECT_GENERIC("set_xmlrpc_size_limit", "network.xmlrpc.size_limit.set"); - - // - // HTTP stuff: - // - - CMD2_REDIRECT_GENERIC("http_capath", "network.http.capath.set"); - CMD2_REDIRECT ("get_http_capath", "network.http.capath"); - CMD2_REDIRECT_GENERIC("set_http_capath", "network.http.capath.set"); - - CMD2_REDIRECT_GENERIC("http_cacert", "network.http.cacert.set"); - CMD2_REDIRECT ("get_http_cacert", "network.http.cacert"); - CMD2_REDIRECT_GENERIC("set_http_cacert", "network.http.cacert.set"); - - CMD2_REDIRECT ("get_max_open_http", "network.http.max_open"); - CMD2_REDIRECT_GENERIC("set_max_open_http", "network.http.max_open.set"); - - CMD2_REDIRECT_GENERIC("http_proxy", "network.http.proxy_address.set"); - CMD2_REDIRECT ("get_http_proxy", "network.http.proxy_address"); - CMD2_REDIRECT_GENERIC("set_http_proxy", "network.http.proxy_address.set"); - - CMD2_REDIRECT ("peer_exchange", "protocol.pex.set"); - CMD2_REDIRECT ("get_peer_exchange", "protocol.pex"); - CMD2_REDIRECT_GENERIC("set_peer_exchange", "protocol.pex.set"); - - // - // Trackers: - // - - CMD2_REDIRECT ("tracker_numwant", "trackers.numwant.set"); - CMD2_REDIRECT ("get_tracker_numwant", "trackers.numwant"); - CMD2_REDIRECT_GENERIC("set_tracker_numwant", "trackers.numwant.set"); - - CMD2_REDIRECT ("use_udp_trackers", "trackers.use_udp.set"); - CMD2_REDIRECT ("get_use_udp_trackers", "trackers.use_udp"); - CMD2_REDIRECT_GENERIC("set_use_udp_trackers", "trackers.use_udp.set"); - - // - // DHT stuff - // - - CMD2_REDIRECT ("dht_add_node", "dht.add_node"); - CMD2_REDIRECT ("dht_statistics", "dht.statistics"); - CMD2_REDIRECT ("get_dht_port", "dht.port"); - CMD2_REDIRECT_GENERIC("set_dht_port", "dht.port.set"); - CMD2_REDIRECT ("get_dht_throttle", "dht.throttle.name"); - CMD2_REDIRECT_GENERIC("set_dht_throttle", "dht.throttle.name.set"); - - // - // Various system stuff: - // - - CMD2_REDIRECT ("get_session_lock", "session.use_lock"); - CMD2_REDIRECT_GENERIC("set_session_lock", "session.use_lock.set"); - CMD2_REDIRECT ("get_session_on_completion", "session.on_completion"); - CMD2_REDIRECT_GENERIC("set_session_on_completion", "session.on_completion.set"); - - CMD2_REDIRECT ("get_check_hash", "pieces.hash.on_completion"); - CMD2_REDIRECT_GENERIC("set_check_hash", "pieces.hash.on_completion.set"); - - // - // Download: - // - - CMD2_REDIRECT ("d.get_hash", "d.hash"); - CMD2_REDIRECT ("d.get_local_id", "d.local_id"); - CMD2_REDIRECT ("d.get_local_id_html", "d.local_id_html"); - CMD2_REDIRECT ("d.get_bitfield", "d.bitfield"); - CMD2_REDIRECT ("d.get_base_path", "d.base_path"); - CMD2_REDIRECT ("d.get_base_filename", "d.base_filename"); - - CMD2_REDIRECT ("d.get_name", "d.name"); - CMD2_REDIRECT ("d.get_creation_date", "d.creation_date"); - - CMD2_REDIRECT ("d.get_peer_exchange", "d.peer_exchange"); - - CMD2_REDIRECT ("d.get_up_rate", "d.up.rate"); - CMD2_REDIRECT ("d.get_up_total", "d.up.total"); - CMD2_REDIRECT ("d.get_down_rate", "d.down.rate"); - CMD2_REDIRECT ("d.get_down_total", "d.down.total"); - CMD2_REDIRECT ("d.get_skip_rate", "d.skip.rate"); - CMD2_REDIRECT ("d.get_skip_total", "d.skip.total"); - - // - CMD2_REDIRECT ("d.get_bytes_done", "d.bytes_done"); - CMD2_REDIRECT ("d.get_chunk_size", "d.chunk_size"); - CMD2_REDIRECT ("d.get_chunks_hashed", "d.chunks_hashed"); - CMD2_REDIRECT ("d.get_complete", "d.complete"); - CMD2_REDIRECT ("d.get_completed_bytes", "d.completed_bytes"); - CMD2_REDIRECT ("d.get_completed_chunks", "d.completed_chunks"); - CMD2_REDIRECT ("d.get_connection_current", "d.connection_current"); - CMD2_REDIRECT ("d.get_connection_leech", "d.connection_leech"); - CMD2_REDIRECT ("d.get_connection_seed", "d.connection_seed"); - CMD2_REDIRECT ("d.get_custom", "d.custom"); - CMD2_REDIRECT ("d.get_custom1", "d.custom1"); - CMD2_REDIRECT ("d.get_custom2", "d.custom2"); - CMD2_REDIRECT ("d.get_custom3", "d.custom3"); - CMD2_REDIRECT ("d.get_custom4", "d.custom4"); - CMD2_REDIRECT ("d.get_custom5", "d.custom5"); - CMD2_REDIRECT ("d.get_custom_throw", "d.custom_throw"); - CMD2_REDIRECT ("d.get_directory", "d.directory"); - CMD2_REDIRECT ("d.get_directory_base", "d.directory_base"); - CMD2_REDIRECT ("d.get_free_diskspace", "d.free_diskspace"); - CMD2_REDIRECT ("d.get_hashing", "d.hashing"); - CMD2_REDIRECT ("d.get_hashing_failed", "d.hashing_failed"); - CMD2_REDIRECT ("d.get_ignore_commands", "d.ignore_commands"); - CMD2_REDIRECT ("d.get_left_bytes", "d.left_bytes"); - CMD2_REDIRECT ("d.get_loaded_file", "d.loaded_file"); - CMD2_REDIRECT ("d.get_max_file_size", "d.max_file_size"); - CMD2_REDIRECT ("d.get_max_size_pex", "d.max_size_pex"); - CMD2_REDIRECT ("d.get_message", "d.message"); - CMD2_REDIRECT ("d.get_mode", "d.mode"); - CMD2_REDIRECT ("d.get_peers_accounted", "d.peers_accounted"); - CMD2_REDIRECT ("d.get_peers_complete", "d.peers_complete"); - CMD2_REDIRECT ("d.get_peers_connected", "d.peers_connected"); - CMD2_REDIRECT ("d.get_peers_max", "d.peers_max"); - CMD2_REDIRECT ("d.get_peers_min", "d.peers_min"); - CMD2_REDIRECT ("d.get_peers_not_connected", "d.peers_not_connected"); - CMD2_REDIRECT ("d.get_priority", "d.priority"); - CMD2_REDIRECT ("d.get_priority_str", "d.priority_str"); - CMD2_REDIRECT ("d.get_ratio", "d.ratio"); - CMD2_REDIRECT ("d.get_size_bytes", "d.size_bytes"); - CMD2_REDIRECT ("d.get_size_chunks", "d.size_chunks"); - CMD2_REDIRECT ("d.get_size_files", "d.size_files"); - CMD2_REDIRECT ("d.get_size_pex", "d.size_pex"); - CMD2_REDIRECT ("d.get_state", "d.state"); - CMD2_REDIRECT ("d.get_state_changed", "d.state_changed"); - CMD2_REDIRECT ("d.get_state_counter", "d.state_counter"); - CMD2_REDIRECT ("d.get_throttle_name", "d.throttle_name"); - CMD2_REDIRECT ("d.get_tied_to_file", "d.tied_to_file"); - CMD2_REDIRECT ("d.get_tracker_focus", "d.tracker_focus"); - CMD2_REDIRECT ("d.get_tracker_numwant", "d.tracker_numwant"); - CMD2_REDIRECT ("d.get_tracker_size", "d.tracker_size"); - CMD2_REDIRECT ("d.get_uploads_max", "d.uploads_max"); - - CMD2_REDIRECT ("d.set_connection_current", "d.connection_current.set"); - CMD2_REDIRECT ("d.set_custom", "d.custom.set"); - CMD2_REDIRECT ("d.set_custom1", "d.custom1.set"); - CMD2_REDIRECT ("d.set_custom2", "d.custom2.set"); - CMD2_REDIRECT ("d.set_custom3", "d.custom3.set"); - CMD2_REDIRECT ("d.set_custom4", "d.custom4.set"); - CMD2_REDIRECT ("d.set_custom5", "d.custom5.set"); - CMD2_REDIRECT ("d.set_directory", "d.directory.set"); - CMD2_REDIRECT ("d.set_directory_base", "d.directory_base.set"); - CMD2_REDIRECT ("d.set_hashing_failed", "d.hashing_failed.set"); - CMD2_REDIRECT ("d.set_ignore_commands", "d.ignore_commands.set"); - CMD2_REDIRECT ("d.set_max_file_size", "d.max_file_size.set"); - CMD2_REDIRECT ("d.set_message", "d.message.set"); - CMD2_REDIRECT ("d.set_peers_max", "d.peers_max.set"); - CMD2_REDIRECT ("d.set_peers_min", "d.peers_min.set"); - CMD2_REDIRECT ("d.set_priority", "d.priority.set"); - CMD2_REDIRECT ("d.set_throttle_name", "d.throttle_name.set"); - CMD2_REDIRECT ("d.set_tied_to_file", "d.tied_to_file.set"); - CMD2_REDIRECT ("d.set_tracker_numwant", "d.tracker_numwant.set"); - CMD2_REDIRECT ("d.set_uploads_max", "d.uploads_max.set"); - - CMD2_REDIRECT ("create_link", "d.create_link"); - CMD2_REDIRECT ("delete_link", "d.delete_link"); - CMD2_REDIRECT ("delete_tied", "d.delete_tied"); - - // - // Tracker: - // - - CMD2_REDIRECT_TRACKER("t.get_group", "t.group"); - CMD2_REDIRECT_TRACKER("t.get_id", "t.id"); - CMD2_REDIRECT_TRACKER("t.get_min_interval", "t.min_interval"); - CMD2_REDIRECT_TRACKER("t.get_normal_interval", "t.normal_interval"); - CMD2_REDIRECT_TRACKER("t.get_scrape_complete", "t.scrape_complete"); - CMD2_REDIRECT_TRACKER("t.get_scrape_downloaded", "t.scrape_downloaded"); - CMD2_REDIRECT_TRACKER("t.get_scrape_incomplete", "t.scrape_incomplete"); - CMD2_REDIRECT_TRACKER("t.get_scrape_time_last", "t.scrape_time_last"); - CMD2_REDIRECT_TRACKER("t.get_type", "t.type"); - CMD2_REDIRECT_TRACKER("t.get_url", "t.url"); - CMD2_REDIRECT_TRACKER("t.set_enabled", "t.is_enabled.set"); - - // - // File: - // - - CMD2_REDIRECT_FILE ("f.get_completed_chunks", "f.completed_chunks"); - CMD2_REDIRECT_FILE ("f.get_frozen_path", "f.frozen_path"); - CMD2_REDIRECT_FILE ("f.get_last_touched", "f.last_touched"); - CMD2_REDIRECT_FILE ("f.get_match_depth_next", "f.match_depth_next"); - CMD2_REDIRECT_FILE ("f.get_match_depth_prev", "f.match_depth_prev"); - CMD2_REDIRECT_FILE ("f.get_offset", "f.offset"); - CMD2_REDIRECT_FILE ("f.get_path", "f.path"); - CMD2_REDIRECT_FILE ("f.get_path_components", "f.path_components"); - CMD2_REDIRECT_FILE ("f.get_path_depth", "f.path_depth"); - CMD2_REDIRECT_FILE ("f.get_priority", "f.priority"); - CMD2_REDIRECT_FILE ("f.get_range_first", "f.range_first"); - CMD2_REDIRECT_FILE ("f.get_range_second", "f.range_second"); - CMD2_REDIRECT_FILE ("f.get_size_bytes", "f.size_bytes"); - CMD2_REDIRECT_FILE ("f.get_size_chunks", "f.size_chunks"); - CMD2_REDIRECT_FILE ("f.set_priority", "f.priority.set"); - CMD2_REDIRECT_FILE ("fi.get_filename_last", "fi.filename_last"); - - // - // Peer: - // - - CMD2_REDIRECT ("p.get_address", "p.address"); - CMD2_REDIRECT ("p.get_client_version", "p.client_version"); - CMD2_REDIRECT ("p.get_completed_percent", "p.completed_percent"); - CMD2_REDIRECT ("p.get_down_rate", "p.down_rate"); - CMD2_REDIRECT ("p.get_down_total", "p.down_total"); - CMD2_REDIRECT ("p.get_id", "p.id"); - CMD2_REDIRECT ("p.get_id_html", "p.id_html"); - CMD2_REDIRECT ("p.get_options_str", "p.options_str"); - CMD2_REDIRECT ("p.get_peer_rate", "p.peer_rate"); - CMD2_REDIRECT ("p.get_peer_total", "p.peer_total"); - CMD2_REDIRECT ("p.get_port", "p.port"); - CMD2_REDIRECT ("p.get_up_rate", "p.up_rate"); - CMD2_REDIRECT ("p.get_up_total", "p.up_total"); - - // - // View: - // - - CMD2_REDIRECT_GENERIC("view_add", "view.add"); - CMD2_REDIRECT_GENERIC("view_filter", "view.filter"); - CMD2_REDIRECT_GENERIC("view_filter_on", "view.filter_on"); - CMD2_REDIRECT_GENERIC("view_list", "view.list"); - CMD2_REDIRECT_GENERIC("view_set", "view.set"); - CMD2_REDIRECT_GENERIC("view_sort", "view.sort"); - CMD2_REDIRECT_GENERIC("view_sort_current", "view.sort_current"); - CMD2_REDIRECT_GENERIC("view_sort_new", "view.sort_new"); - - // Rename these to avoid conflicts with old style. - CMD2_REDIRECT_GENERIC("d.multicall", "d.multicall2"); - - CMD2_REDIRECT_GENERIC("execute_throw", "execute.throw"); - CMD2_REDIRECT_GENERIC("execute_nothrow", "execute.nothrow"); - CMD2_REDIRECT_GENERIC("execute_raw", "execute.raw"); - CMD2_REDIRECT_GENERIC("execute_raw_nothrow", "execute.raw_nothrow"); - CMD2_REDIRECT_GENERIC("execute_capture", "execute.capture"); - CMD2_REDIRECT_GENERIC("execute_capture_nothrow", "execute.capture_nothrow"); } #endif From a194da08b0e8d5f423daabb9ed1cab7aeba6cc4d Mon Sep 17 00:00:00 2001 From: mvucBmM0 Date: Sat, 6 Aug 2016 03:08:13 +0100 Subject: [PATCH 19/65] Fix Merzlya display (PR #474) --- src/ui/element_download_list.cc | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/ui/element_download_list.cc b/src/ui/element_download_list.cc index 5a782751a..3f34bb90b 100644 --- a/src/ui/element_download_list.cc +++ b/src/ui/element_download_list.cc @@ -225,6 +225,12 @@ ElementDownloadList::receive_change_view(const std::string& name) { void ElementDownloadList::toggle_layout() { - rpc::call_command("download.list.layout.set", (rpc::call_command_value("download.list.layout") + 1)%2); + const std::string layout_name = rpc::call_command_string("ui.torrent_list.layout"); + + if (layout_name == "full") { + rpc::call_command("ui.torrent_list.layout.set", "compact"); + } else if (layout_name == "compact") { + rpc::call_command("ui.torrent_list.layout.set", "full"); + } } } From 55c61e9099f7e6d73e7578bab55386d0953e1fe3 Mon Sep 17 00:00:00 2001 From: kannibalox Date: Sat, 6 Aug 2016 18:41:11 -0400 Subject: [PATCH 20/65] Expose the number of current HTTP connections --- src/command_network.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/command_network.cc b/src/command_network.cc index 93af73bc1..760645f62 100644 --- a/src/command_network.cc +++ b/src/command_network.cc @@ -264,6 +264,7 @@ initialize_command_network() { CMD2_ANY_STRING_V("network.http.capath.set", std::bind(&core::CurlStack::set_http_capath, httpStack, std::placeholders::_2)); CMD2_ANY ("network.http.dns_cache_timeout", std::bind(&core::CurlStack::dns_timeout, httpStack)); CMD2_ANY_VALUE_V ("network.http.dns_cache_timeout.set", std::bind(&core::CurlStack::set_dns_timeout, httpStack, std::placeholders::_2)); + CMD2_ANY ("network.http.current_open", std::bind(&core::CurlStack::active, httpStack)); CMD2_ANY ("network.http.max_open", std::bind(&core::CurlStack::max_active, httpStack)); CMD2_ANY_VALUE_V ("network.http.max_open.set", std::bind(&core::CurlStack::set_max_active, httpStack, std::placeholders::_2)); CMD2_ANY ("network.http.proxy_address", std::bind(&core::CurlStack::http_proxy, httpStack)); From 41a059c999339cefd2c1077be9fce4106f3a7869 Mon Sep 17 00:00:00 2001 From: pyroscope Date: Sat, 13 Aug 2016 14:45:00 +0200 Subject: [PATCH 21/65] scale integer values with given unit, not only converted strings (closes #484) --- src/rpc/command.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rpc/command.cc b/src/rpc/command.cc index 1057071c8..6d6233c83 100644 --- a/src/rpc/command.cc +++ b/src/rpc/command.cc @@ -77,7 +77,7 @@ command_base_call_value_base(command_base* rawCommand, target_type target, const return command_base::_call::type, T>(rawCommand, target, val); } - return command_base::_call::type, T>(rawCommand, target, arg.as_value()); + return command_base::_call::type, T>(rawCommand, target, unit * arg.as_value()); } template const torrent::Object From 5838b8e68ce51264a0047e48883f2e503b01edc8 Mon Sep 17 00:00:00 2001 From: chros Date: Thu, 25 Aug 2016 12:47:14 +0100 Subject: [PATCH 22/65] Fix fast resume script breaking single file torrents (See #7) --- doc/rtorrent_fast_resume.pl | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/doc/rtorrent_fast_resume.pl b/doc/rtorrent_fast_resume.pl index e01849f57..ea9daa8fe 100755 --- a/doc/rtorrent_fast_resume.pl +++ b/doc/rtorrent_fast_resume.pl @@ -85,7 +85,7 @@ my $mtime = (stat "$d$files[$f]")[9]; # Compute number of chunks per file - my $fsize = $t->{info}{files}[$f]{length}; + my $fsize = (exists $t->{info}{files}) ? $t->{info}{files}[$f]{length} : 1; my $fchunks = ($pmod ? 1 : 0); if ($pmod >= $fsize) { ($fsize, $pmod ) = (0, $pmod-$fsize); } else { ($pmod, $fsize) = (0, $fsize-$pmod); } @@ -101,7 +101,10 @@ $t->{libtorrent_resume}{'uncertain_pieces.timestamp'} = time; # Some extra information to re-enforce the fact that this is a finished torrent -$d .= $t->{info}{name}; +if (exists $t->{info}{files}) { + $d .= $t->{info}{name}; +} + $t->{rtorrent} = { state => 1, # started state_changed => time, From dfdbf5e69cd5ad0d930c6f36f76553322e0392be Mon Sep 17 00:00:00 2001 From: chros Date: Thu, 25 Aug 2016 18:38:58 +0100 Subject: [PATCH 23/65] Add init scripts into doc directory (See #10) --- doc/scripts/init/rtorrentInitScreen.bash | 164 ++++++++++++++++++++++ doc/scripts/init/rtorrentInitScreen.sh | 137 +++++++++++++++++++ doc/scripts/init/rtorrentInitTmux.bash | 167 +++++++++++++++++++++++ 3 files changed, 468 insertions(+) create mode 100755 doc/scripts/init/rtorrentInitScreen.bash create mode 100755 doc/scripts/init/rtorrentInitScreen.sh create mode 100755 doc/scripts/init/rtorrentInitTmux.bash diff --git a/doc/scripts/init/rtorrentInitScreen.bash b/doc/scripts/init/rtorrentInitScreen.bash new file mode 100755 index 000000000..75636a039 --- /dev/null +++ b/doc/scripts/init/rtorrentInitScreen.bash @@ -0,0 +1,164 @@ +#!/bin/bash +############# +###### +############# +# This script depends on screen. +# For the stop function to work, you must set an +# explicit session directory using absolute paths (no, ~ is not absolute) in your rtorrent.rc. +# If you typically just start rtorrent with just "rtorrent" on the +# command line, all you need to change is the "user" option. +# Attach to the screen session as your user with +# "screen -dr rtorrent". Change "rtorrent" with srnname option. +# Licensed under the GPLv2 by lostnihilist: lostnihilist _at_ gmail _dot_ com +############## +###### +############## + +####################### +##Start Configuration## +####################### +# You can specify your configuration in a different file +# (so that it is saved with upgrades, saved in your home directory, +# or whatever reason you want to) +# by commenting out/deleting the configuration lines and placing them +# in a text file (say /home/user/.rtorrent.init.conf) exactly as you would +# have written them here (you can leave the comments if you desire +# and then uncommenting the following line correcting the path/filename +# for the one you used. note the space after the ".". +# . /etc/rtorrent.init.conf + + +#Do not put a space on either side of the equal signs e.g. +# user = user +# will not work +# system user to run as (can only use one) +user="user" + +# system user to run as # not implemented, see d_start for beginning implementation +# group=$(id -ng "$user") + +# the full path to the filename where you store your rtorrent configuration +# must keep parentheses around the entire statement, quotations around each config file +config=("$(su -c 'echo $HOME' $user)/.rtorrent.rc") +# Examples: +# config=("/home/user/.rtorrent.rc") +# config=("/home/user/.rtorrent.rc" "/mnt/some/drive/.rtorrent2.rc") +# config=("/home/user/.rtorrent.rc" +# "/mnt/some/drive/.rtorrent2.rc" +# "/mnt/another/drive/.rtorrent3.rc") + +# set of options to run with each instance, separated by a new line +# must keep parentheses around the entire statement +#if no special options, specify with: "" +options=("") +# Examples: +# starts one instance, sourcing both .rtorrent.rc and .rtorrent2.rc +# options=("-o import=~/.rtorrent2.rc") +# starts two instances, ignoring .rtorrent.rc for both, and using +# .rtorrent2.rc for the first, and .rtorrent3.rc for the second +# we do not check for valid options +# options=("-n -o import=~/.rtorrent2.rc" "-n -o import=~/rtorrent3.rc") + +# default directory for screen, needs to be an absolute path +base=$(su -c 'echo $HOME' $user) + +# name of screen session +srnname="rtorrent" + +# file to log to (makes for easier debugging if something goes wrong) +logfile="/var/log/rtorrentInit.log" +####################### +###END CONFIGURATION### +####################### + +PATH=/usr/bin:/usr/local/bin:/usr/local/sbin:/sbin:/bin:/usr/sbin +DESC="rtorrent" +NAME=rtorrent +DAEMON=$NAME +SCRIPTNAME=/etc/init.d/$NAME + +checkcnfg() { + exists=0 + for i in `echo "$PATH" | tr ':' '\n'` ; do + if [ -f $i/$NAME ] ; then + exists=1 + break + fi + done + if [ $exists -eq 0 ] ; then + echo "cannot find $NAME binary in PATH: $PATH" | tee -a "$logfile" >&2 + exit 3 + fi + for (( i=0 ; i < ${#config[@]} ; i++ )) ; do + if ! [ -r "${config[i]}" ] ; then + echo "cannot find readable config ${config[i]}. check that it is there and permissions are appropriate" | tee -a "$logfile" >&2 + exit 3 + fi + session=$(getsession "${config[i]}") + if ! [ -d "${session}" ] ; then + echo "cannot find readable session directory ${session} from config ${config[i]}. check permissions" | tee -a "$logfile" >&2 + exit 3 + fi + done +} + +d_start() { + [ -d "${base}" ] && cd "${base}" + stty stop undef && stty start undef + su -c "screen -S "${srnname}" -X screen rtorrent ${options} 2>&1 1>/dev/null" ${user} | tee -a "$logfile" >&2 + # this works for the screen command, but starting rtorrent below adopts screen session gid + # even if it is not the screen session we started (e.g. running under an undesirable gid + #su -c "screen -ls | grep -sq "\.${srnname}[[:space:]]" " ${user} || su -c "sg \"$group\" -c \"screen -fn -dm -S ${srnname} 2>&1 1>/dev/null\"" ${user} | tee -a "$logfile" >&2 + for (( i=0 ; i < ${#options[@]} ; i++ )) ; do + sleep 3 + su -c "screen -S "${srnname}" -X screen rtorrent ${options[i]} 2>&1 1>/dev/null" ${user} | tee -a "$logfile" >&2 + done +} + +d_stop() { + for (( i=0 ; i < ${#config[@]} ; i++ )) ; do + session=$(getsession "${config[i]}") + if ! [ -s ${session}/rtorrent.lock ] ; then + return + fi + pid=$(cat ${session}/rtorrent.lock | awk -F: '{print($2)}' | sed "s/[^0-9]//g") + # make sure the pid doesn't belong to another process + if ps -A | grep -sq ${pid}.*rtorrent ; then + kill -s INT ${pid} + fi + done +} + +getsession() { + session=$(cat "$1" | grep "^[[:space:]]*session[[:space:]]*=" | sed "s/^[[:space:]]*session[[:space:]]*=[[:space:]]*//" ) + #session=${session/#~/`getent passwd ${user}|cut -d: -f6`} + echo $session +} + +checkcnfg + +case "$1" in + start) + echo -n "Starting $DESC: $NAME" + d_start + echo "." + ;; + stop) + echo -n "Stopping $DESC: $NAME" + d_stop + echo "." + ;; + restart|force-reload) + echo -n "Restarting $DESC: $NAME" + d_stop + sleep 1 + d_start + echo "." + ;; + *) + echo "Usage: $SCRIPTNAME {start|stop|restart|force-reload}" >&2 + exit 1 + ;; +esac + +exit 0 diff --git a/doc/scripts/init/rtorrentInitScreen.sh b/doc/scripts/init/rtorrentInitScreen.sh new file mode 100755 index 000000000..cb71212a9 --- /dev/null +++ b/doc/scripts/init/rtorrentInitScreen.sh @@ -0,0 +1,137 @@ +#!/bin/sh +############# +###### +############# +# This script depends on screen. +# For the stop function to work, you must set an +# explicit session directory using ABSOLUTE paths (no, ~ is not absolute) in your rtorrent.rc. +# If you typically just start rtorrent with just "rtorrent" on the +# command line, all you need to change is the "user" option. +# Attach to the screen session as your user with +# "screen -dr rtorrent". Change "rtorrent" with srnname option. +# Licensed under the GPLv2 by lostnihilist: lostnihilist _at_ gmail _dot_ com +############## +###### +############## + +####################### +##Start Configuration## +####################### +# You can specify your configuration in a different file +# (so that it is saved with upgrades, saved in your home directory, +# or whateve reason you want to) +# by commenting out/deleting the configuration lines and placing them +# in a text file (say /home/user/.rtorrent.init.conf) exactly as you would +# have written them here (you can leave the comments if you desire +# and then uncommenting the following line correcting the path/filename +# for the one you used. note the space after the ".". +# . /etc/rtorrent.init.conf + +#Do not put a space on either side of the equal signs e.g. +# user = user +# will not work +# system user to run as +user="user" + +# the system group to run as, not implemented, see d_start for beginning implementation +# group=`id -ng "$user"` + +# the full path to the filename where you store your rtorrent configuration +config="`su -c 'echo $HOME' $user`/.rtorrent.rc" + +# set of options to run with +options="" + +# default directory for screen, needs to be an absolute path +base="`su -c 'echo $HOME' $user`" + +# name of screen session +srnname="rtorrent" + +# file to log to (makes for easier debugging if something goes wrong) +logfile="/var/log/rtorrentInit.log" +####################### +###END CONFIGURATION### +####################### +PATH=/usr/bin:/usr/local/bin:/usr/local/sbin:/sbin:/bin:/usr/sbin +DESC="rtorrent" +NAME=rtorrent +DAEMON=$NAME +SCRIPTNAME=/etc/init.d/$NAME + +checkcnfg() { + exists=0 + for i in `echo "$PATH" | tr ':' '\n'` ; do + if [ -f $i/$NAME ] ; then + exists=1 + break + fi + done + if [ $exists -eq 0 ] ; then + echo "cannot find rtorrent binary in PATH $PATH" | tee -a "$logfile" >&2 + exit 3 + fi + if ! [ -r "${config}" ] ; then + echo "cannot find readable config ${config}. check that it is there and permissions are appropriate" | tee -a "$logfile" >&2 + exit 3 + fi + session=`getsession "$config"` + if ! [ -d "${session}" ] ; then + echo "cannot find readable session directory ${session} from config ${config}. check permissions" | tee -a "$logfile" >&2 + exit 3 + fi +} + +d_start() { + [ -d "${base}" ] && cd "${base}" + stty stop undef && stty start undef + su -c "screen -ls | grep -sq "\.${srnname}[[:space:]]" " ${user} || su -c "screen -dm -S ${srnname} 2>&1 1>/dev/null" ${user} | tee -a "$logfile" >&2 + # this works for the screen command, but starting rtorrent below adopts screen session gid + # even if it is not the screen session we started (e.g. running under an undesirable gid + #su -c "screen -ls | grep -sq "\.${srnname}[[:space:]]" " ${user} || su -c "sg \"$group\" -c \"screen -fn -dm -S ${srnname} 2>&1 1>/dev/null\"" ${user} | tee -a "$logfile" >&2 + su -c "screen -S "${srnname}" -X screen rtorrent ${options} 2>&1 1>/dev/null" ${user} | tee -a "$logfile" >&2 +} + +d_stop() { + session=`getsession "$config"` + if ! [ -s ${session}/rtorrent.lock ] ; then + return + fi + pid=`cat ${session}/rtorrent.lock | awk -F: '{print($2)}' | sed "s/[^0-9]//g"` + if ps -A | grep -sq ${pid}.*rtorrent ; then # make sure the pid doesn't belong to another process + kill -s INT ${pid} + fi +} + +getsession() { + session=`cat "$1" | grep "^[[:space:]]*session[[:space:]]*=" | sed "s/^[[:space:]]*session[[:space:]]*=[[:space:]]*//" ` + echo $session +} + +checkcnfg + +case "$1" in + start) + echo -n "Starting $DESC: $NAME" + d_start + echo "." + ;; + stop) + echo -n "Stopping $DESC: $NAME" + d_stop + echo "." + ;; + restart|force-reload) + echo -n "Restarting $DESC: $NAME" + d_stop + sleep 1 + d_start + echo "." + ;; + *) + echo "Usage: $SCRIPTNAME {start|stop|restart|force-reload}" >&2 + exit 1 + ;; +esac + +exit 0 diff --git a/doc/scripts/init/rtorrentInitTmux.bash b/doc/scripts/init/rtorrentInitTmux.bash new file mode 100755 index 000000000..5af843372 --- /dev/null +++ b/doc/scripts/init/rtorrentInitTmux.bash @@ -0,0 +1,167 @@ +#!/bin/bash +### BEGIN INIT INFO +# Provides: rtorrent_autostart +# Required-Start: $local_fs $remote_fs $network $syslog $netdaemons +# Required-Stop: $local_fs $remote_fs +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: rtorrent script using tmux +# Description: rtorrent script using tmux +### END INIT INFO + +############# +###### +############# +# This script depends on tmux and is based on 'rtorrentInitScreen.sh' script +# with the following enhancements: +# - init script 'start' option can be called without breaking anything +# - init script 'status' option can be used in scripts to determine whether rtorrent is running or not +# - auto removes damaged/stuck 'rtorrent.lock' file if necessary +# - saves session (just in case) before stopping with 'rtxmlrp' if it exists +# - provides examples how to script tmux windows +# +# For the stop function to work, you must set an explicit session directory +# using ABSOLUTE paths (no, ~ is not absolute) in your rtorrent.rc and with +# "sessiondir" option. +# If you typically just start rtorrent with just "rtorrent" on the +# command line, all you need to change is the "user" and "sessiondir" option. +# Attach to the tmux session as your user with +# "tmux -2u new-session -A -s rtorrent". Change "rtorrent" with "tmuxname" option. +# Licensed under the GPLv2 by lostnihilist: lostnihilist _at_ gmail _dot_ com +############## +###### +############## + +####################### +##Start Configuration## +####################### +# You can specify your configuration in a different file. +# (so that it is saved with upgrades, saved in your home directory, +# or whatever reason you want to) +# by commenting out/deleting the configuration lines and placing them +# in a text file (say /home/user/.rtorrent.init.conf) exactly as you would +# have written them here (you can leave the comments if you desire +# and then uncommenting the following line correcting the path/filename. +# for the one you used. note the space after the ".". +# . /etc/rtorrent.init.conf + +# system user to run as +user="username" + +# default directory for tmux, needs to be an absolute path +base=$(su -c 'echo $HOME' $user) + +# the full path to the filename where you store your rtorrent configuration +config="$base/.rtorrent.rc" + +# the full path to the session directory of rtorrent +sessiondir="/mnt/Torrents/.rtorrent/.session" + +# options to pass to rtorrent; e.g. don't read config from $HOME but load alternate +#options="-n -O import=$config" +options="" + +# name of tmux session +tmuxname="rtorrent" + +# name of window in tmux session +DESC="rT" +####################### +###END CONFIGURATION### +####################### +PATH=/usr/bin:/usr/local/bin:/usr/local/sbin:/sbin:/bin:/usr/sbin +NAME=rtorrent +DDIR="/opt/rtorrent/bin" +DAEMON=$NAME +SCRIPTNAME=/etc/init.d/$NAME +RTXMLRPCBIN="$base/bin/rtxmlrpc" + + +checkcnfg() { + if [ -z "$(which $DAEMON)" ] ; then + echo "Cannot find $DAEMON binary in PATH: $PATH" + exit 3 + fi + if ! [ -r "$config" ] ; then + echo "Cannot find readable config $config. Check that it is there and permissions are appropriate" + exit 3 + fi + if ! [ -d "$sessiondir" ] ; then + echo "Cannot find readable session directory $sessiondir from config $config. Check permissions" + exit 3 + fi +} + + +status() { + if [ -e "${sessiondir}/rtorrent.lock" ] ; then + pid=`cat ${sessiondir}/rtorrent.lock | awk -F: '{print($2)}' | sed "s/[^0-9]//g"` + # make sure the pid isn't empty and doesn't belong to another process : this will match lines containing rtorrent, which grep '[r]torrent' does not! + # if there is no process as the 'pid' suggests then delete the stuck "rtorrent.lock" file (to be able to start rtorrent) + [[ -n "$pid" ]] && ps aux | grep -sq ${pid}.*[r]torrent && echo -e ${pid} || rm -f "${sessiondir}/rtorrent.lock" + fi +} + + +d_start() { + [ -d "$base" ] && cd "$base" + # if STDIN is a terminal (we are using interactive mode) + [ -t 0 ] && stty stop undef && stty start undef + # start the default 2 tmux window (bash and mc) if there isn't tmux session called "tmuxname" option (rtorrent) + if ! su -c "tmux ls | grep -sq ${tmuxname}: " $user ; then + # 1st window (0): split it into 3 panes, display 'date' in the last one + su -c "tmux -2u new-session -d -s ${tmuxname} -n 'shell1'" $user + su -c "tmux -2u split-window -v -t ${tmuxname}:0 'bash'" $user + su -c "tmux -2u split-window -h -t ${tmuxname}:0 'date; bash'" $user + # 2nd window (1): start 'mc' if it exists + su -c "tmux -2u new-window -t ${tmuxname}:1 -n 'mc1' 'command which mc && mc ~/; bash'" $user + fi + # start rtorrent always in the 3rd tmux window (2) if it's not running and leave shell behind to be able to see reason of a crash + if [ "$(status)" == "" ]; then + su -c "tmux -2u list-panes -t ${tmuxname}:2 &>/dev/null && tmux -2u respawn-pane -t ${tmuxname}:2 -k \"${DDIR}/${DAEMON} ${options}; bash\" || tmux -2u new-window -t ${tmuxname}:2 -n ${DESC} \"${DDIR}/${DAEMON} ${options}; bash\"" $user + fi +} + + +d_stop() { + pid=$(status) + if [ "$pid" != "" ]; then + # save session before stopping explicitly (just in case) if rtxmlrpc util exists then wait for 5 seconds to be able to complete it + [ -L "$RTXMLRPCBIN" ] && "$RTXMLRPCBIN" session.save &>/dev/null && sleep 5 + # INT (2, Interrupt from keyboard): normal shutdown + kill -s INT $pid + fi +} + + +checkcnfg + + +case "$1" in + start) + echo -n "Starting $DESC: $NAME" + d_start + echo "." + ;; + stop) + echo -n "Stopping $DESC: $NAME" + d_stop + echo "." + ;; + restart|force-reload) + echo -n "Restarting $DESC: $NAME" + d_stop + sleep 1 + d_start + echo "." + ;; + status) + status + ;; + *) + echo "Usage: $SCRIPTNAME {start|stop|restart|force-reload|status}" >&2 + exit 1 + ;; +esac + +exit 0 From 017cb1bd591750accb92e88023b84b69feba91aa Mon Sep 17 00:00:00 2001 From: chros Date: Thu, 25 Aug 2016 19:04:11 +0100 Subject: [PATCH 24/65] Fixing variables in rtorrentInitTmux.bash script (See #10) --- doc/scripts/init/rtorrentInitTmux.bash | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/doc/scripts/init/rtorrentInitTmux.bash b/doc/scripts/init/rtorrentInitTmux.bash index 5af843372..1b93cc79a 100755 --- a/doc/scripts/init/rtorrentInitTmux.bash +++ b/doc/scripts/init/rtorrentInitTmux.bash @@ -65,13 +65,12 @@ options="" tmuxname="rtorrent" # name of window in tmux session -DESC="rT" +tmuxwindowname="rT" ####################### ###END CONFIGURATION### ####################### PATH=/usr/bin:/usr/local/bin:/usr/local/sbin:/sbin:/bin:/usr/sbin NAME=rtorrent -DDIR="/opt/rtorrent/bin" DAEMON=$NAME SCRIPTNAME=/etc/init.d/$NAME RTXMLRPCBIN="$base/bin/rtxmlrpc" @@ -118,7 +117,7 @@ d_start() { fi # start rtorrent always in the 3rd tmux window (2) if it's not running and leave shell behind to be able to see reason of a crash if [ "$(status)" == "" ]; then - su -c "tmux -2u list-panes -t ${tmuxname}:2 &>/dev/null && tmux -2u respawn-pane -t ${tmuxname}:2 -k \"${DDIR}/${DAEMON} ${options}; bash\" || tmux -2u new-window -t ${tmuxname}:2 -n ${DESC} \"${DDIR}/${DAEMON} ${options}; bash\"" $user + su -c "tmux -2u list-panes -t ${tmuxname}:2 &>/dev/null && tmux -2u respawn-pane -t ${tmuxname}:2 -k \"${DAEMON} ${options}; bash\" || tmux -2u new-window -t ${tmuxname}:2 -n ${tmuxwindowname} \"${DAEMON} ${options}; bash\"" $user fi } @@ -139,17 +138,17 @@ checkcnfg case "$1" in start) - echo -n "Starting $DESC: $NAME" + echo -n "Starting $tmuxwindowname: $NAME" d_start echo "." ;; stop) - echo -n "Stopping $DESC: $NAME" + echo -n "Stopping $tmuxwindowname: $NAME" d_stop echo "." ;; restart|force-reload) - echo -n "Restarting $DESC: $NAME" + echo -n "Restarting $tmuxwindowname: $NAME" d_stop sleep 1 d_start From bdb0d99c5c6f9380455d22db2b9a3c4b8d1af6b8 Mon Sep 17 00:00:00 2001 From: chros Date: Mon, 29 Aug 2016 11:04:51 +0100 Subject: [PATCH 25/65] Fix type of m_ssl_verify_host variable (See #12) --- src/core/curl_stack.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/curl_stack.h b/src/core/curl_stack.h index ace12abd2..ebcfbcf70 100644 --- a/src/core/curl_stack.h +++ b/src/core/curl_stack.h @@ -142,7 +142,7 @@ class CurlStack : std::deque { std::string m_httpCaPath; std::string m_httpCaCert; - long m_ssl_verify_host; + bool m_ssl_verify_host; bool m_ssl_verify_peer; long m_dns_timeout; }; From d7529d3b8493c0df0951b2ea9ecd7a61dbcc177b Mon Sep 17 00:00:00 2001 From: Speeddymon Date: Fri, 9 Sep 2016 01:57:07 -0500 Subject: [PATCH 26/65] Correct Download list layout style to 0.9 format. Blame @rakshasa for using old style. --- doc/rtorrent.rc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/rtorrent.rc b/doc/rtorrent.rc index 9c940ebe3..543831763 100644 --- a/doc/rtorrent.rc +++ b/doc/rtorrent.rc @@ -100,4 +100,4 @@ # Set downlad list layout style. ("full", "compact") # -#torrent_list_layout = "full" +#ui.torrent_list.layout.set = "full" From 89b02f275e0d17ec356d882ca83c0fd2d098276a Mon Sep 17 00:00:00 2001 From: rakshasa Date: Fri, 23 Sep 2016 08:22:24 +0900 Subject: [PATCH 27/65] Added "system.shutdown", "system.shutdown.normal" and "system.shutdown.quick". --- src/command_local.cc | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/command_local.cc b/src/command_local.cc index 741b3000f..553368af3 100644 --- a/src/command_local.cc +++ b/src/command_local.cc @@ -230,10 +230,10 @@ cmd_file_append(const torrent::Object::list_type& args) { void initialize_command_local() { - torrent::ChunkManager* chunkManager = torrent::chunk_manager(); - torrent::FileManager* fileManager = torrent::file_manager(); core::DownloadList* dList = control->core()->download_list(); core::DownloadStore* dStore = control->core()->download_store(); + torrent::ChunkManager* chunkManager = torrent::chunk_manager(); + torrent::FileManager* fileManager = torrent::file_manager(); CMD2_ANY ("system.hostname", std::bind(&system_hostname)); CMD2_ANY ("system.pid", std::bind(&getpid)); @@ -268,6 +268,10 @@ initialize_command_local() { CMD2_VAR_BOOL ("system.daemon", false); + CMD2_ANY_V ("system.shutdown.normal", std::bind(&Control::receive_normal_shutdown, control)); + CMD2_ANY_V ("system.shutdown.quick", std::bind(&Control::receive_quick_shutdown, control)); + CMD2_REDIRECT_GENERIC_NO_EXPORT("system.shutdown", "system.shutdown.normal"); + CMD2_ANY ("system.cwd", std::bind(&system_get_cwd)); CMD2_ANY_STRING ("system.cwd.set", std::bind(&system_set_cwd, std::placeholders::_2)); From 84913766d531c5181e01331b3a7359f47d829fa8 Mon Sep 17 00:00:00 2001 From: rakshasa Date: Fri, 23 Sep 2016 08:25:40 +0900 Subject: [PATCH 28/65] Removed unneeded parameter. --- src/main.cc | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/main.cc b/src/main.cc index 687e57c88..8cafcec81 100644 --- a/src/main.cc +++ b/src/main.cc @@ -89,7 +89,7 @@ void do_nothing() {} void do_nothing_str(const std::string&) {} int -parse_options(Control* c, int argc, char** argv) { +parse_options(int argc, char** argv) { try { OptionParser optionParser; @@ -117,8 +117,8 @@ parse_options(Control* c, int argc, char** argv) { } void -load_session_torrents(Control* c) { - utils::Directory entries = c->core()->download_store()->get_formated_entries(); +load_session_torrents() { + utils::Directory entries = control->core()->download_store()->get_formated_entries(); for (utils::Directory::const_iterator first = entries.begin(), last = entries.end(); first != last; ++first) { // We don't really support session torrents that are links. These @@ -127,7 +127,7 @@ load_session_torrents(Control* c) { if (!first->is_file()) continue; - core::DownloadFactory* f = new core::DownloadFactory(c->core()); + core::DownloadFactory* f = new core::DownloadFactory(control->core()); // Replace with session torrent flag. f->set_session(true); @@ -138,10 +138,10 @@ load_session_torrents(Control* c) { } void -load_arg_torrents(Control* c, char** first, char** last) { - //std::for_each(begin, end, std::bind1st(std::mem_fun(&core::Manager::insert), &c->get_core())); +load_arg_torrents(char** first, char** last) { + //std::for_each(begin, end, std::bind1st(std::mem_fun(&core::Manager::insert), &control->get_core())); for (; first != last; ++first) { - core::DownloadFactory* f = new core::DownloadFactory(c->core()); + core::DownloadFactory* f = new core::DownloadFactory(control->core()); // Replace with session torrent flag. f->set_start(true); @@ -152,9 +152,9 @@ load_arg_torrents(Control* c, char** first, char** last) { } static uint64_t -client_next_timeout(Control* c) { +client_next_timeout() { if (taskScheduler.empty()) - return (c->is_shutdown_started() ? rak::timer::from_milliseconds(100) : rak::timer::from_seconds(60)).usec(); + return (control->is_shutdown_started() ? rak::timer::from_milliseconds(100) : rak::timer::from_seconds(60)).usec(); else if (taskScheduler.top()->time() <= cachedTime) return 0; else @@ -222,7 +222,7 @@ main(int argc, char** argv) { torrent::initialize(); torrent::main_thread()->slot_do_work() = std::bind(&client_perform); - torrent::main_thread()->slot_next_timeout() = std::bind(&client_next_timeout, control); + torrent::main_thread()->slot_next_timeout() = std::bind(&client_next_timeout); worker_thread = new ThreadWorker(); worker_thread->init_thread(); @@ -439,7 +439,7 @@ main(int argc, char** argv) { } #endif - int firstArg = parse_options(control, argc, argv); + int firstArg = parse_options(argc, argv); if (OptionParser::has_flag('n', argc, argv)) { lt_log_print(torrent::LOG_WARN, "Ignoring rtorrent.rc."); @@ -462,10 +462,10 @@ main(int argc, char** argv) { // Load session torrents and perform scheduled tasks to ensure // session torrents are loaded before arg torrents. control->dht_manager()->load_dht_cache(); - load_session_torrents(control); + load_session_torrents(); rak::priority_queue_perform(&taskScheduler, cachedTime); - load_arg_torrents(control, argv + firstArg, argv + argc); + load_arg_torrents(argv + firstArg, argv + argc); // Make sure we update the display before any scheduled tasks can // run, so that loading of torrents doesn't look like it hangs on From e2c769f459fc2920518d1a4f5ea478f75acd287b Mon Sep 17 00:00:00 2001 From: rakshasa Date: Sat, 22 Oct 2016 10:51:41 +0900 Subject: [PATCH 29/65] Improved logging of dht manager. --- src/core/dht_manager.cc | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/src/core/dht_manager.cc b/src/core/dht_manager.cc index 8c4b7b1b8..27bf7d005 100644 --- a/src/core/dht_manager.cc +++ b/src/core/dht_manager.cc @@ -54,6 +54,9 @@ #include "download_store.h" #include "manager.h" +#define LT_LOG_THIS(log_fmt, ...) \ + lt_log_print_subsystem(torrent::LOG_DHT_ALL, "dht_manager", log_fmt, __VA_ARGS__); + namespace core { const char* DhtManager::dht_settings[dht_settings_num] = { "disable", "off", "auto", "on" }; @@ -65,8 +68,10 @@ DhtManager::~DhtManager() { void DhtManager::load_dht_cache() { - if (m_start == dht_disable || !control->core()->download_store()->is_enabled()) + if (m_start == dht_disable || !control->core()->download_store()->is_enabled()) { + LT_LOG_THIS("ignoring cache file", 0); return; + } torrent::Object cache = torrent::Object::create_map(); std::fstream cache_file((control->core()->download_store()->path() + "rtorrent.dht_cache").c_str(), std::ios::in | std::ios::binary); @@ -77,8 +82,10 @@ DhtManager::load_dht_cache() { // If the cache file is corrupted we will just discard it with an // error message. if (cache_file.fail()) { - lt_log_print(torrent::LOG_DHT_WARN, "DHT cache file corrupted, discarding."); + LT_LOG_THIS("cache file corrupted, discarding", 0); cache = torrent::Object::create_map(); + } else { + LT_LOG_THIS("cache file loaded", 0); } } @@ -89,7 +96,7 @@ DhtManager::load_dht_cache() { start_dht(); } catch (torrent::local_error& e) { - lt_log_print(torrent::LOG_DHT_WARN, "DHT failed: %s", e.what()); + LT_LOG_THIS("initialization failed (error:%s)", e.what()); } } @@ -97,18 +104,21 @@ void DhtManager::start_dht() { priority_queue_erase(&taskScheduler, &m_stopTimeout); - if (!torrent::dht_manager()->is_valid() || torrent::dht_manager()->is_active()) + if (!torrent::dht_manager()->is_valid() || torrent::dht_manager()->is_active()) { + LT_LOG_THIS("server start skipped", 0); return; + } torrent::ThrottlePair throttles = control->core()->get_throttle(m_throttleName); torrent::dht_manager()->set_upload_throttle(throttles.first); torrent::dht_manager()->set_download_throttle(throttles.second); int port = rpc::call_command_value("dht.port"); + if (port <= 0) return; - lt_log_print(torrent::LOG_DHT_INFO, "Starting DHT server on port %d.", port); + LT_LOG_THIS("starting server (port:%d)", port); try { torrent::dht_manager()->start(port); @@ -125,7 +135,7 @@ DhtManager::start_dht() { m_dhtPrevBytesDown = 0; } catch (torrent::local_error& e) { - lt_log_print(torrent::LOG_DHT_ERROR, "DHT start failed: %s", e.what()); + LT_LOG_THIS("server start failed (error:%s)", e.what()); m_start = dht_off; } } @@ -136,8 +146,9 @@ DhtManager::stop_dht() { priority_queue_erase(&taskScheduler, &m_stopTimeout); if (torrent::dht_manager()->is_active()) { + LT_LOG_THIS("stopping server", 0); + log_statistics(true); - lt_log_print(torrent::LOG_DHT_INFO, "Stopping DHT server."); torrent::dht_manager()->stop(); } } @@ -219,7 +230,7 @@ DhtManager::log_statistics(bool force) { // We should have had clients ping us at least but have received // nothing, that means the UDP port is probably unreachable. if (torrent::dht_manager()->can_receive_queries()) - lt_log_print(torrent::LOG_DHT_WARN, "DHT port appears to be unreachable, no queries received."); + LT_LOG_THIS("listening port appears to be unreachable, no queries received", 0); torrent::dht_manager()->set_can_receive(false); } @@ -227,7 +238,7 @@ DhtManager::log_statistics(bool force) { if (stats.queries_sent - m_dhtPrevQueriesSent > stats.num_nodes * 2 + 20 && stats.replies_received == m_dhtPrevRepliesReceived) { // No replies to over 20 queries plus two per node we have. Probably firewalled. if (!m_warned) - lt_log_print(torrent::LOG_DHT_WARN, "DHT port appears to be firewalled, no replies received."); + LT_LOG_THIS("listening port appears to be firewalled, no replies received", 0); m_warned = true; return false; From e02c6b29fa6b0dfc2e0da563a39458d0eff9e94d Mon Sep 17 00:00:00 2001 From: rakshasa Date: Sat, 22 Oct 2016 11:21:56 +0900 Subject: [PATCH 30/65] More logging stuff. --- src/core/dht_manager.cc | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/src/core/dht_manager.cc b/src/core/dht_manager.cc index 27bf7d005..ab3790489 100644 --- a/src/core/dht_manager.cc +++ b/src/core/dht_manager.cc @@ -55,7 +55,7 @@ #include "manager.h" #define LT_LOG_THIS(log_fmt, ...) \ - lt_log_print_subsystem(torrent::LOG_DHT_ALL, "dht_manager", log_fmt, __VA_ARGS__); + lt_log_print_subsystem(torrent::LOG_DHT_MANAGER, "dht_manager", log_fmt, __VA_ARGS__); namespace core { @@ -73,20 +73,25 @@ DhtManager::load_dht_cache() { return; } + std::string cache_filename = control->core()->download_store()->path() + "rtorrent.dht_cache"; + std::fstream cache_stream(cache_filename.c_str(), std::ios::in | std::ios::binary); + torrent::Object cache = torrent::Object::create_map(); - std::fstream cache_file((control->core()->download_store()->path() + "rtorrent.dht_cache").c_str(), std::ios::in | std::ios::binary); - if (cache_file.is_open()) { - cache_file >> cache; + if (cache_stream.is_open()) { + cache_stream >> cache; // If the cache file is corrupted we will just discard it with an // error message. - if (cache_file.fail()) { - LT_LOG_THIS("cache file corrupted, discarding", 0); + if (cache_stream.fail()) { + LT_LOG_THIS("cache file corrupted, discarding (path:%s)", cache_filename.c_str()); cache = torrent::Object::create_map(); } else { - LT_LOG_THIS("cache file loaded", 0); + LT_LOG_THIS("cache file loaded (path:%s)", cache_filename.c_str()); } + + } else { + LT_LOG_THIS("could not open cache file (path:%s)", cache_filename.c_str()); } try { @@ -104,8 +109,13 @@ void DhtManager::start_dht() { priority_queue_erase(&taskScheduler, &m_stopTimeout); - if (!torrent::dht_manager()->is_valid() || torrent::dht_manager()->is_active()) { - LT_LOG_THIS("server start skipped", 0); + if (!torrent::dht_manager()->is_valid()) { + LT_LOG_THIS("server start skipped, manager is invalid", 0); + return; + } + + if (torrent::dht_manager()->is_active()) { + LT_LOG_THIS("server start skipped, already active", 0); return; } From 008561ef47fa39d4c63582d8c54a856ade7598b6 Mon Sep 17 00:00:00 2001 From: rakshasa Date: Sat, 22 Oct 2016 12:33:31 +0900 Subject: [PATCH 31/65] More dht manager logging. --- src/core/dht_manager.cc | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/src/core/dht_manager.cc b/src/core/dht_manager.cc index ab3790489..24a52a36b 100644 --- a/src/core/dht_manager.cc +++ b/src/core/dht_manager.cc @@ -87,22 +87,17 @@ DhtManager::load_dht_cache() { LT_LOG_THIS("cache file corrupted, discarding (path:%s)", cache_filename.c_str()); cache = torrent::Object::create_map(); } else { - LT_LOG_THIS("cache file loaded (path:%s)", cache_filename.c_str()); + LT_LOG_THIS("cache file read (path:%s)", cache_filename.c_str()); } } else { LT_LOG_THIS("could not open cache file (path:%s)", cache_filename.c_str()); } - try { - torrent::dht_manager()->initialize(cache); - - if (m_start == dht_on) - start_dht(); + torrent::dht_manager()->initialize(cache); - } catch (torrent::local_error& e) { - LT_LOG_THIS("initialization failed (error:%s)", e.what()); - } + if (m_start == dht_on) + start_dht(); } void @@ -110,7 +105,7 @@ DhtManager::start_dht() { priority_queue_erase(&taskScheduler, &m_stopTimeout); if (!torrent::dht_manager()->is_valid()) { - LT_LOG_THIS("server start skipped, manager is invalid", 0); + LT_LOG_THIS("server start skipped, manager is uninitialized", 0); return; } From 2aa130eda967981073aa8a5eb2d99d5b523c7120 Mon Sep 17 00:00:00 2001 From: rakshasa Date: Sat, 22 Oct 2016 14:19:46 +0900 Subject: [PATCH 32/65] More work on dht manager. --- src/core/dht_manager.cc | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/src/core/dht_manager.cc b/src/core/dht_manager.cc index 24a52a36b..5628cb2b7 100644 --- a/src/core/dht_manager.cc +++ b/src/core/dht_manager.cc @@ -123,26 +123,22 @@ DhtManager::start_dht() { if (port <= 0) return; - LT_LOG_THIS("starting server (port:%d)", port); + if (!torrent::dht_manager()->start(port)) { + m_start = dht_off; + return; + } - try { - torrent::dht_manager()->start(port); - torrent::dht_manager()->reset_statistics(); + torrent::dht_manager()->reset_statistics(); - m_updateTimeout.slot() = std::bind(&DhtManager::update, this); - priority_queue_insert(&taskScheduler, &m_updateTimeout, (cachedTime + rak::timer::from_seconds(60)).round_seconds()); + m_updateTimeout.slot() = std::bind(&DhtManager::update, this); + priority_queue_insert(&taskScheduler, &m_updateTimeout, (cachedTime + rak::timer::from_seconds(60)).round_seconds()); - m_dhtPrevCycle = 0; - m_dhtPrevQueriesSent = 0; - m_dhtPrevRepliesReceived = 0; - m_dhtPrevQueriesReceived = 0; - m_dhtPrevBytesUp = 0; - m_dhtPrevBytesDown = 0; - - } catch (torrent::local_error& e) { - LT_LOG_THIS("server start failed (error:%s)", e.what()); - m_start = dht_off; - } + m_dhtPrevCycle = 0; + m_dhtPrevQueriesSent = 0; + m_dhtPrevRepliesReceived = 0; + m_dhtPrevQueriesReceived = 0; + m_dhtPrevBytesUp = 0; + m_dhtPrevBytesDown = 0; } void From 71a52bfac2e43bce46827c769a7135744982c2f3 Mon Sep 17 00:00:00 2001 From: rakshasa Date: Sun, 23 Oct 2016 08:53:11 +0900 Subject: [PATCH 33/65] Use pkg-config for cppunit test. --- configure.ac | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index a121c06e9..58166ccf1 100644 --- a/configure.ac +++ b/configure.ac @@ -4,7 +4,6 @@ AC_DEFINE(API_VERSION, 9, api version) AM_INIT_AUTOMAKE AC_CONFIG_HEADERS(config.h) -AM_PATH_CPPUNIT(1.9.6) AC_PROG_CXX AC_PROG_LIBTOOL @@ -36,9 +35,11 @@ if test "x$ax_cv_ncursesw" != xyes && test "x$ax_cv_ncurses" != xyes; then AC_MSG_ERROR([requires either NcursesW or Ncurses library]) fi -CFLAGS="$CFLAGS $PTHREAD_CFLAGS $CURSES_CFLAGS" -CXXFLAGS="$CXXFLAGS $PTHREAD_CFLAGS $CURSES_CFLAGS" -LIBS="$PTHREAD_LIBS $CURSES_LIB $LIBS" +PKG_CHECK_MODULES([CPPUNIT], [cppunit],, [no_cppunit="yes"]) + +CFLAGS="$CFLAGS $PTHREAD_CFLAGS $CPPUNIT_CFLAGS $CURSES_CFLAGS" +CXXFLAGS="$CXXFLAGS $PTHREAD_CFLAGS $CPPUNIT_CFLAGS $CURSES_CFLAGS" +LIBS="$PTHREAD_LIBS $CURSES_LIB $CPPUNIT_LIBS $LIBS" PKG_CHECK_MODULES([libcurl], libcurl >= 7.15.4, CXXFLAGS="$CXXFLAGS $libcurl_CFLAGS"; From c7c5a00f664f8e0b18a2a5d6dfd87684becaff45 Mon Sep 17 00:00:00 2001 From: rakshasa Date: Sun, 23 Oct 2016 09:21:40 +0900 Subject: [PATCH 34/65] Cleaned up check for dependencies. --- configure.ac | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/configure.ac b/configure.ac index 58166ccf1..f06290380 100644 --- a/configure.ac +++ b/configure.ac @@ -36,19 +36,11 @@ if test "x$ax_cv_ncursesw" != xyes && test "x$ax_cv_ncurses" != xyes; then fi PKG_CHECK_MODULES([CPPUNIT], [cppunit],, [no_cppunit="yes"]) +PKG_CHECK_MODULES([DEPENDENCIES], [libcurl >= 7.15.4 libtorrent >= 0.13.6]) -CFLAGS="$CFLAGS $PTHREAD_CFLAGS $CPPUNIT_CFLAGS $CURSES_CFLAGS" -CXXFLAGS="$CXXFLAGS $PTHREAD_CFLAGS $CPPUNIT_CFLAGS $CURSES_CFLAGS" -LIBS="$PTHREAD_LIBS $CURSES_LIB $CPPUNIT_LIBS $LIBS" - -PKG_CHECK_MODULES([libcurl], libcurl >= 7.15.4, - CXXFLAGS="$CXXFLAGS $libcurl_CFLAGS"; - LIBS="$LIBS $libcurl_LIBS") - -PKG_CHECK_MODULES([libtorrent], libtorrent >= 0.13.6, - CXXFLAGS="$CXXFLAGS $libtorrent_CFLAGS"; - LIBS="$LIBS $libtorrent_LIBS", - [AC_MSG_ERROR([libtorrent >= 0.13.6 not found. Install from https://github.com/rakshasa/libtorrent.git])]) +CFLAGS="$CFLAGS $PTHREAD_CFLAGS $CPPUNIT_CFLAGS $DEPENDENCIES_CFLAGS $CURSES_CFLAGS" +CXXFLAGS="$CXXFLAGS $PTHREAD_CFLAGS $CPPUNIT_CFLAGS $DEPENDENCIES_CFLAGS $CURSES_CFLAGS" +LIBS="$PTHREAD_LIBS $CURSES_LIB $CPPUNIT_LIBS $DEPENDENCIES_LIBS $LIBS" AC_LANG_PUSH(C++) TORRENT_WITH_XMLRPC_C From 74bd0be5d8c7011ea38475873d7f2da295dad285 Mon Sep 17 00:00:00 2001 From: rakshasa Date: Sun, 23 Oct 2016 12:23:29 +0900 Subject: [PATCH 35/65] Travis improvements. --- .travis.yml | 86 +++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 70 insertions(+), 16 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9641c06e4..10bff99e4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,20 +1,74 @@ language: cpp -compiler: - - gcc - - clang -before_install: - - sudo add-apt-repository --yes ppa:ubuntu-toolchain-r/test - - sudo apt-get update -qq - - sudo apt-get build-dep rtorrent libtorrent-dev - - - if [ "$CXX" = "g++" ]; then sudo apt-get install -qq g++-4.7; fi - - if [ "$CXX" = "g++" ]; then export CXX="g++-4.7" CC="gcc-4.7"; fi +matrix: + include: + - compiler: clang + env: COMPILER=clang++ SKIP_CHECK=true + - compiler: clang + env: COMPILER=clang++ + addons: + apt: + packages: + - libcppunit-dev + - compiler: clang + env: COMPILER=clang++-3.6 + addons: + apt: + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-precise-3.6 + packages: + - clang-3.6 + - libcppunit-dev + - compiler: clang + env: COMPILER=clang++-3.7 + addons: + apt: + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-precise-3.7 + packages: + - clang-3.7 + - libcppunit-dev + - compiler: clang + env: COMPILER=clang++-3.8 + addons: + apt: + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-precise-3.8 + packages: + - clang-3.8 + - libcppunit-dev + - compiler: gcc + env: COMPILER=g++-4.7 SKIP_CHECK=true + addons: + apt: + sources: ubuntu-toolchain-r-test + packages: + - g++-4.7 + - compiler: gcc + env: COMPILER=g++-4.7 + addons: + apt: + sources: ubuntu-toolchain-r-test + packages: + - g++-4.7 + - libcppunit-dev + - compiler: gcc + env: COMPILER=g++-4.8 + addons: + apt: + sources: ubuntu-toolchain-r-test + packages: + - g++-4.8 + - libcppunit-dev -# prevent `macro `AM_PATH_CPPUNIT' not found in library` in `autogen.sh` - - sudo apt-get install libcppunit-dev - - - git clone https://github.com/rakshasa/libtorrent.git && cd libtorrent && ./autogen.sh && ./configure && make -j12 && sudo make install && cd .. +# TODO: Use the same branch name if libtorrent has it. +before_install: + - git clone https://github.com/rakshasa/libtorrent.git + - cd libtorrent && ./autogen.sh && CXX="$COMPILER" ./configure && make -j12 && sudo make install -# Figure out how to fix the issue running 'make check'. -script: ./autogen.sh && ./configure && make -j12 && sudo make install +script: +- ./autogen.sh && CXX="$COMPILER" ./configure && make -j12 +- if [ ! $SKIP_CHECK ]; then make -j12 check; fi From 10ce6864b81aaf2a7e43e9959940696b47aac2bc Mon Sep 17 00:00:00 2001 From: rakshasa Date: Sat, 5 Nov 2016 06:58:44 +0900 Subject: [PATCH 36/65] Added non-pkgconfig check for curl as macosx doesn't include the 'pc' file. --- configure.ac | 11 +- scripts/libcurl.m4 | 272 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 278 insertions(+), 5 deletions(-) create mode 100644 scripts/libcurl.m4 diff --git a/configure.ac b/configure.ac index f06290380..6198ff10b 100644 --- a/configure.ac +++ b/configure.ac @@ -32,15 +32,16 @@ AX_PTHREAD([], AC_MSG_ERROR([requires pthread])) AX_WITH_CURSES if test "x$ax_cv_ncursesw" != xyes && test "x$ax_cv_ncurses" != xyes; then - AC_MSG_ERROR([requires either NcursesW or Ncurses library]) + AC_MSG_ERROR([requires either NcursesW or Ncurses library]) fi +PKG_CHECK_MODULES([LIBCURL], [libcurl], , [LIBCURL_CHECK_CONFIG]) PKG_CHECK_MODULES([CPPUNIT], [cppunit],, [no_cppunit="yes"]) -PKG_CHECK_MODULES([DEPENDENCIES], [libcurl >= 7.15.4 libtorrent >= 0.13.6]) +PKG_CHECK_MODULES([DEPENDENCIES], [libtorrent >= 0.13.6]) -CFLAGS="$CFLAGS $PTHREAD_CFLAGS $CPPUNIT_CFLAGS $DEPENDENCIES_CFLAGS $CURSES_CFLAGS" -CXXFLAGS="$CXXFLAGS $PTHREAD_CFLAGS $CPPUNIT_CFLAGS $DEPENDENCIES_CFLAGS $CURSES_CFLAGS" -LIBS="$PTHREAD_LIBS $CURSES_LIB $CPPUNIT_LIBS $DEPENDENCIES_LIBS $LIBS" +LIBS="$PTHREAD_LIBS $CURSES_LIB $CPPUNIT_LIBS $LIBCURL $LIBCURL_LIBS $DEPENDENCIES_LIBS $LIBS" +CFLAGS="$CFLAGS $PTHREAD_CFLAGS $CPPUNIT_CFLAGS $LIBCURL_CPPFLAGS $LIBCURL_CFLAGS $DEPENDENCIES_CFLAGS $CURSES_CFLAGS" +CXXFLAGS="$CXXFLAGS $PTHREAD_CFLAGS $CPPUNIT_CFLAGS $LIBCURL_CPPFLAGS $LIBCURL_CFLAGS $DEPENDENCIES_CFLAGS $CURSES_CFLAGS" AC_LANG_PUSH(C++) TORRENT_WITH_XMLRPC_C diff --git a/scripts/libcurl.m4 b/scripts/libcurl.m4 new file mode 100644 index 000000000..53d694d0a --- /dev/null +++ b/scripts/libcurl.m4 @@ -0,0 +1,272 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) 2006, David Shaw +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.haxx.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +########################################################################### +# LIBCURL_CHECK_CONFIG ([DEFAULT-ACTION], [MINIMUM-VERSION], +# [ACTION-IF-YES], [ACTION-IF-NO]) +# ---------------------------------------------------------- +# David Shaw May-09-2006 +# +# Checks for libcurl. DEFAULT-ACTION is the string yes or no to +# specify whether to default to --with-libcurl or --without-libcurl. +# If not supplied, DEFAULT-ACTION is yes. MINIMUM-VERSION is the +# minimum version of libcurl to accept. Pass the version as a regular +# version number like 7.10.1. If not supplied, any version is +# accepted. ACTION-IF-YES is a list of shell commands to run if +# libcurl was successfully found and passed the various tests. +# ACTION-IF-NO is a list of shell commands that are run otherwise. +# Note that using --without-libcurl does run ACTION-IF-NO. +# +# This macro #defines HAVE_LIBCURL if a working libcurl setup is +# found, and sets @LIBCURL@ and @LIBCURL_CPPFLAGS@ to the necessary +# values. Other useful defines are LIBCURL_FEATURE_xxx where xxx are +# the various features supported by libcurl, and LIBCURL_PROTOCOL_yyy +# where yyy are the various protocols supported by libcurl. Both xxx +# and yyy are capitalized. See the list of AH_TEMPLATEs at the top of +# the macro for the complete list of possible defines. Shell +# variables $libcurl_feature_xxx and $libcurl_protocol_yyy are also +# defined to 'yes' for those features and protocols that were found. +# Note that xxx and yyy keep the same capitalization as in the +# curl-config list (e.g. it's "HTTP" and not "http"). +# +# Users may override the detected values by doing something like: +# LIBCURL="-lcurl" LIBCURL_CPPFLAGS="-I/usr/myinclude" ./configure +# +# For the sake of sanity, this macro assumes that any libcurl that is +# found is after version 7.7.2, the first version that included the +# curl-config script. Note that it is very important for people +# packaging binary versions of libcurl to include this script! +# Without curl-config, we can only guess what protocols are available, +# or use curl_version_info to figure it out at runtime. + +AC_DEFUN([LIBCURL_CHECK_CONFIG], +[ + AH_TEMPLATE([LIBCURL_FEATURE_SSL],[Defined if libcurl supports SSL]) + AH_TEMPLATE([LIBCURL_FEATURE_KRB4],[Defined if libcurl supports KRB4]) + AH_TEMPLATE([LIBCURL_FEATURE_IPV6],[Defined if libcurl supports IPv6]) + AH_TEMPLATE([LIBCURL_FEATURE_LIBZ],[Defined if libcurl supports libz]) + AH_TEMPLATE([LIBCURL_FEATURE_ASYNCHDNS],[Defined if libcurl supports AsynchDNS]) + AH_TEMPLATE([LIBCURL_FEATURE_IDN],[Defined if libcurl supports IDN]) + AH_TEMPLATE([LIBCURL_FEATURE_SSPI],[Defined if libcurl supports SSPI]) + AH_TEMPLATE([LIBCURL_FEATURE_NTLM],[Defined if libcurl supports NTLM]) + + AH_TEMPLATE([LIBCURL_PROTOCOL_HTTP],[Defined if libcurl supports HTTP]) + AH_TEMPLATE([LIBCURL_PROTOCOL_HTTPS],[Defined if libcurl supports HTTPS]) + AH_TEMPLATE([LIBCURL_PROTOCOL_FTP],[Defined if libcurl supports FTP]) + AH_TEMPLATE([LIBCURL_PROTOCOL_FTPS],[Defined if libcurl supports FTPS]) + AH_TEMPLATE([LIBCURL_PROTOCOL_FILE],[Defined if libcurl supports FILE]) + AH_TEMPLATE([LIBCURL_PROTOCOL_TELNET],[Defined if libcurl supports TELNET]) + AH_TEMPLATE([LIBCURL_PROTOCOL_LDAP],[Defined if libcurl supports LDAP]) + AH_TEMPLATE([LIBCURL_PROTOCOL_DICT],[Defined if libcurl supports DICT]) + AH_TEMPLATE([LIBCURL_PROTOCOL_TFTP],[Defined if libcurl supports TFTP]) + AH_TEMPLATE([LIBCURL_PROTOCOL_RTSP],[Defined if libcurl supports RTSP]) + AH_TEMPLATE([LIBCURL_PROTOCOL_POP3],[Defined if libcurl supports POP3]) + AH_TEMPLATE([LIBCURL_PROTOCOL_IMAP],[Defined if libcurl supports IMAP]) + AH_TEMPLATE([LIBCURL_PROTOCOL_SMTP],[Defined if libcurl supports SMTP]) + + AC_ARG_WITH(libcurl, + AS_HELP_STRING([--with-libcurl=PREFIX],[look for the curl library in PREFIX/lib and headers in PREFIX/include]), + [_libcurl_with=$withval],[_libcurl_with=ifelse([$1],,[yes],[$1])]) + + if test "$_libcurl_with" != "no" ; then + + AC_PROG_AWK + + _libcurl_version_parse="eval $AWK '{split(\$NF,A,\".\"); X=256*256*A[[1]]+256*A[[2]]+A[[3]]; print X;}'" + + _libcurl_try_link=yes + + if test -d "$_libcurl_with" ; then + LIBCURL_CPPFLAGS="-I$withval/include" + _libcurl_ldflags="-L$withval/lib" + AC_PATH_PROG([_libcurl_config],[curl-config],[], + ["$withval/bin"]) + else + AC_PATH_PROG([_libcurl_config],[curl-config],[],[$PATH]) + fi + + if test x$_libcurl_config != "x" ; then + AC_CACHE_CHECK([for the version of libcurl], + [libcurl_cv_lib_curl_version], + [libcurl_cv_lib_curl_version=`$_libcurl_config --version | $AWK '{print $[]2}'`]) + + _libcurl_version=`echo $libcurl_cv_lib_curl_version | $_libcurl_version_parse` + _libcurl_wanted=`echo ifelse([$2],,[0],[$2]) | $_libcurl_version_parse` + + if test $_libcurl_wanted -gt 0 ; then + AC_CACHE_CHECK([for libcurl >= version $2], + [libcurl_cv_lib_version_ok], + [ + if test $_libcurl_version -ge $_libcurl_wanted ; then + libcurl_cv_lib_version_ok=yes + else + libcurl_cv_lib_version_ok=no + fi + ]) + fi + + if test $_libcurl_wanted -eq 0 || test x$libcurl_cv_lib_version_ok = xyes ; then + if test x"$LIBCURL_CPPFLAGS" = "x" ; then + LIBCURL_CPPFLAGS=`$_libcurl_config --cflags` + fi + if test x"$LIBCURL" = "x" ; then + LIBCURL=`$_libcurl_config --libs` + + # This is so silly, but Apple actually has a bug in their + # curl-config script. Fixed in Tiger, but there are still + # lots of Panther installs around. + case "${host}" in + powerpc-apple-darwin7*) + LIBCURL=`echo $LIBCURL | sed -e 's|-arch i386||g'` + ;; + esac + fi + + # All curl-config scripts support --feature + _libcurl_features=`$_libcurl_config --feature` + + # Is it modern enough to have --protocols? (7.12.4) + if test $_libcurl_version -ge 461828 ; then + _libcurl_protocols=`$_libcurl_config --protocols` + fi + else + _libcurl_try_link=no + fi + + unset _libcurl_wanted + fi + + if test $_libcurl_try_link = yes ; then + + # we didn't find curl-config, so let's see if the user-supplied + # link line (or failing that, "-lcurl") is enough. + LIBCURL=${LIBCURL-"$_libcurl_ldflags -lcurl"} + + AC_CACHE_CHECK([whether libcurl is usable], + [libcurl_cv_lib_curl_usable], + [ + _libcurl_save_cppflags=$CPPFLAGS + CPPFLAGS="$LIBCURL_CPPFLAGS $CPPFLAGS" + _libcurl_save_libs=$LIBS + LIBS="$LIBCURL $LIBS" + + AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]],[[ +/* Try and use a few common options to force a failure if we are + missing symbols or can't link. */ +int x; +curl_easy_setopt(NULL,CURLOPT_URL,NULL); +x=CURL_ERROR_SIZE; +x=CURLOPT_WRITEFUNCTION; +x=CURLOPT_WRITEDATA; +x=CURLOPT_ERRORBUFFER; +x=CURLOPT_STDERR; +x=CURLOPT_VERBOSE; +if (x) {;} +]])],libcurl_cv_lib_curl_usable=yes,libcurl_cv_lib_curl_usable=no) + + CPPFLAGS=$_libcurl_save_cppflags + LIBS=$_libcurl_save_libs + unset _libcurl_save_cppflags + unset _libcurl_save_libs + ]) + + if test $libcurl_cv_lib_curl_usable = yes ; then + + # Does curl_free() exist in this version of libcurl? + # If not, fake it with free() + + _libcurl_save_cppflags=$CPPFLAGS + CPPFLAGS="$CPPFLAGS $LIBCURL_CPPFLAGS" + _libcurl_save_libs=$LIBS + LIBS="$LIBS $LIBCURL" + + AC_CHECK_FUNC(curl_free,, + AC_DEFINE(curl_free,free, + [Define curl_free() as free() if our version of curl lacks curl_free.])) + + CPPFLAGS=$_libcurl_save_cppflags + LIBS=$_libcurl_save_libs + unset _libcurl_save_cppflags + unset _libcurl_save_libs + + AC_DEFINE(HAVE_LIBCURL,1, + [Define to 1 if you have a functional curl library.]) + AC_SUBST(LIBCURL_CPPFLAGS) + AC_SUBST(LIBCURL) + + for _libcurl_feature in $_libcurl_features ; do + AC_DEFINE_UNQUOTED(AS_TR_CPP(libcurl_feature_$_libcurl_feature),[1]) + eval AS_TR_SH(libcurl_feature_$_libcurl_feature)=yes + done + + if test "x$_libcurl_protocols" = "x" ; then + + # We don't have --protocols, so just assume that all + # protocols are available + _libcurl_protocols="HTTP FTP FILE TELNET LDAP DICT TFTP" + + if test x$libcurl_feature_SSL = xyes ; then + _libcurl_protocols="$_libcurl_protocols HTTPS" + + # FTPS wasn't standards-compliant until version + # 7.11.0 (0x070b00 == 461568) + if test $_libcurl_version -ge 461568; then + _libcurl_protocols="$_libcurl_protocols FTPS" + fi + fi + + # RTSP, IMAP, POP3 and SMTP were added in + # 7.20.0 (0x071400 == 463872) + if test $_libcurl_version -ge 463872; then + _libcurl_protocols="$_libcurl_protocols RTSP IMAP POP3 SMTP" + fi + fi + + for _libcurl_protocol in $_libcurl_protocols ; do + AC_DEFINE_UNQUOTED(AS_TR_CPP(libcurl_protocol_$_libcurl_protocol),[1]) + eval AS_TR_SH(libcurl_protocol_$_libcurl_protocol)=yes + done + else + unset LIBCURL + unset LIBCURL_CPPFLAGS + fi + fi + + unset _libcurl_try_link + unset _libcurl_version_parse + unset _libcurl_config + unset _libcurl_feature + unset _libcurl_features + unset _libcurl_protocol + unset _libcurl_protocols + unset _libcurl_version + unset _libcurl_ldflags + fi + + if test x$_libcurl_with = xno || test x$libcurl_cv_lib_curl_usable != xyes ; then + # This is the IF-NO path + ifelse([$4],,:,[$4]) + else + # This is the IF-YES path + ifelse([$3],,:,[$3]) + fi + + unset _libcurl_with +])dnl From 2097c9ca3e35fb5611c615f9f9995dbba65ff2c5 Mon Sep 17 00:00:00 2001 From: Shivaram Lingamneni Date: Fri, 30 Dec 2016 09:19:34 -0800 Subject: [PATCH 37/65] unfocus_download should always redraw the download list --- src/ui/download_list.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ui/download_list.cc b/src/ui/download_list.cc index 7a070f62d..055fbbaf8 100644 --- a/src/ui/download_list.cc +++ b/src/ui/download_list.cc @@ -127,12 +127,12 @@ DownloadList::set_current_view(const std::string& name) { // This should also do focus_next() or something. void DownloadList::unfocus_download(core::Download* d) { - if (current_view()->focus() >= current_view()->end_visible() || *current_view()->focus() != d) - return; - if (m_state == DISPLAY_DOWNLOAD) activate_display(DISPLAY_DOWNLOAD_LIST); + if (current_view()->focus() >= current_view()->end_visible() || *current_view()->focus() != d) + return; + current_view()->next_focus(); } From 321147cdb886bb3a01474819fef5bffc01dbf493 Mon Sep 17 00:00:00 2001 From: Shivaram Lingamneni Date: Sun, 8 Jan 2017 14:49:54 -0800 Subject: [PATCH 38/65] only redraw the download list if the deleted download was onscreen --- src/ui/download.h | 3 ++- src/ui/download_list.cc | 15 ++++++++------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/ui/download.h b/src/ui/download.h index c896c5288..d4ba0a7ff 100644 --- a/src/ui/download.h +++ b/src/ui/download.h @@ -89,7 +89,8 @@ class Download : public ElementBase { void adjust_up_throttle(int throttle); void adjust_down_throttle(int throttle); - display::Window* window() { return NULL; } + display::Window* window() { return NULL; } + core::Download* download() { return m_download; }; private: Download(const Download&); diff --git a/src/ui/download_list.cc b/src/ui/download_list.cc index 055fbbaf8..08ed13bed 100644 --- a/src/ui/download_list.cc +++ b/src/ui/download_list.cc @@ -124,16 +124,17 @@ DownloadList::set_current_view(const std::string& name) { return dynamic_cast(m_uiArray[DISPLAY_DOWNLOAD_LIST])->receive_change_view(name); } -// This should also do focus_next() or something. void DownloadList::unfocus_download(core::Download* d) { - if (m_state == DISPLAY_DOWNLOAD) - activate_display(DISPLAY_DOWNLOAD_LIST); - - if (current_view()->focus() >= current_view()->end_visible() || *current_view()->focus() != d) - return; + if (m_state == DISPLAY_DOWNLOAD) { + if (d == static_cast(m_uiArray[DISPLAY_DOWNLOAD])->download()) { + activate_display(DISPLAY_DOWNLOAD_LIST); + } + } - current_view()->next_focus(); + if (*current_view()->focus() == d && current_view()->focus() < current_view()->end_visible()) { + current_view()->next_focus(); + } } void From 9590949fa752d823ac32624dd92f3be2d3f3f5d6 Mon Sep 17 00:00:00 2001 From: chros Date: Mon, 6 Mar 2017 13:06:59 +0000 Subject: [PATCH 39/65] Add support for basic arithmetic operators (See #14) --- src/command_ui.cc | 59 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/src/command_ui.cc b/src/command_ui.cc index 69ee2f540..a40a41002 100644 --- a/src/command_ui.cc +++ b/src/command_ui.cc @@ -519,6 +519,56 @@ apply_elapsed_greater(const torrent::Object::list_type& args) { return (int64_t)(start_time != 0 && rak::timer::current_seconds() - start_time > rpc::convert_to_value(args.back())); } +int64_t +apply_math_basic(const std::function op, const torrent::Object::list_type& args) { + if (args.size() == 0) + throw torrent::input_error("Wrong argument count."); + + int64_t val = 0; + + for (torrent::Object::list_const_iterator itr = args.begin(), last = args.end(); itr != last; itr++) { + + if (itr->is_value()) { + val = itr == args.begin() ? itr->as_value() : op(val, itr->as_value()); + } else if (itr->is_string()) { + val = itr == args.begin() ? rpc::convert_to_value(itr->as_string()) : op(val, rpc::convert_to_value(itr->as_string())); + } else if (itr->is_list()) { + val = itr == args.begin() ? apply_math_basic(op, itr->as_list()) : op(val, apply_math_basic(op, itr->as_list())); + } else { + throw torrent::input_error("Wrong type supplied to apply_math_basic."); + } + + } + + return val; +} + +int64_t +apply_arith_basic(const std::function op, const torrent::Object::list_type& args) { + if (args.size() == 0) + throw torrent::input_error("Wrong argument count."); + + int64_t val = 0; + + for (torrent::Object::list_const_iterator itr = args.begin(), last = args.end(); itr != last; itr++) { + + if (itr->is_value()) { + val = itr == args.begin() ? itr->as_value() : (op(val, itr->as_value()) ? val : itr->as_value()); + } else if (itr->is_string()) { + int64_t cval = rpc::convert_to_value(itr->as_string()); + val = itr == args.begin() ? cval : (op(val, cval) ? val : cval); + } else if (itr->is_list()) { + int64_t fval = apply_arith_basic(op, itr->as_list()); + val = itr == args.begin() ? fval : (op(val, fval) ? val : fval); + } else { + throw torrent::input_error("Wrong type supplied to apply_arith_basic."); + } + + } + + return val; +} + void initialize_command_ui() { CMD2_VAR_STRING("keys.layout", "qwerty"); @@ -585,6 +635,15 @@ initialize_command_ui() { CMD2_ANY_VALUE("convert.xb", std::bind(&apply_to_xb, std::placeholders::_2)); CMD2_ANY_VALUE("convert.throttle", std::bind(&apply_to_throttle, std::placeholders::_2)); + CMD2_ANY_LIST("math.add", std::bind(&apply_math_basic, std::plus(), std::placeholders::_2)); + CMD2_ANY_LIST("math.subtract", std::bind(&apply_math_basic, std::minus(), std::placeholders::_2)); + CMD2_ANY_LIST("math.multiply", std::bind(&apply_math_basic, std::multiplies(), std::placeholders::_2)); + CMD2_ANY_LIST("math.divide", std::bind(&apply_math_basic, std::divides(), std::placeholders::_2)); + CMD2_ANY_LIST("math.modulo", std::bind(&apply_math_basic, std::modulus(), std::placeholders::_2)); + + CMD2_ANY_LIST("math.min", std::bind(&apply_arith_basic, std::less(), std::placeholders::_2)); + CMD2_ANY_LIST("math.max", std::bind(&apply_arith_basic, std::greater(), std::placeholders::_2)); + CMD2_ANY_LIST ("elapsed.less", std::bind(&apply_elapsed_less, std::placeholders::_2)); CMD2_ANY_LIST ("elapsed.greater", std::bind(&apply_elapsed_greater, std::placeholders::_2)); } From 3002c95b2c4122890f8a4e4ec7ef933ab68cf3c3 Mon Sep 17 00:00:00 2001 From: chros Date: Mon, 6 Mar 2017 19:41:49 +0000 Subject: [PATCH 40/65] Rename couple of arithmetic commands (See #14) --- src/command_ui.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/command_ui.cc b/src/command_ui.cc index a40a41002..54a121d7d 100644 --- a/src/command_ui.cc +++ b/src/command_ui.cc @@ -636,10 +636,10 @@ initialize_command_ui() { CMD2_ANY_VALUE("convert.throttle", std::bind(&apply_to_throttle, std::placeholders::_2)); CMD2_ANY_LIST("math.add", std::bind(&apply_math_basic, std::plus(), std::placeholders::_2)); - CMD2_ANY_LIST("math.subtract", std::bind(&apply_math_basic, std::minus(), std::placeholders::_2)); - CMD2_ANY_LIST("math.multiply", std::bind(&apply_math_basic, std::multiplies(), std::placeholders::_2)); - CMD2_ANY_LIST("math.divide", std::bind(&apply_math_basic, std::divides(), std::placeholders::_2)); - CMD2_ANY_LIST("math.modulo", std::bind(&apply_math_basic, std::modulus(), std::placeholders::_2)); + CMD2_ANY_LIST("math.sub", std::bind(&apply_math_basic, std::minus(), std::placeholders::_2)); + CMD2_ANY_LIST("math.mul", std::bind(&apply_math_basic, std::multiplies(), std::placeholders::_2)); + CMD2_ANY_LIST("math.div", std::bind(&apply_math_basic, std::divides(), std::placeholders::_2)); + CMD2_ANY_LIST("math.mod", std::bind(&apply_math_basic, std::modulus(), std::placeholders::_2)); CMD2_ANY_LIST("math.min", std::bind(&apply_arith_basic, std::less(), std::placeholders::_2)); CMD2_ANY_LIST("math.max", std::bind(&apply_arith_basic, std::greater(), std::placeholders::_2)); From 8b6a1ad07967f3c664e8323d7c6c391f1bb3f666 Mon Sep 17 00:00:00 2001 From: chros Date: Tue, 7 Mar 2017 12:57:31 +0000 Subject: [PATCH 41/65] Add count and average commands (See #14) --- src/command_ui.cc | 41 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/src/command_ui.cc b/src/command_ui.cc index 54a121d7d..bbb07a4d6 100644 --- a/src/command_ui.cc +++ b/src/command_ui.cc @@ -569,6 +569,44 @@ apply_arith_basic(const std::function op, const torren return val; } +int64_t +apply_arith_count(const torrent::Object::list_type& args) { + if (args.size() == 0) + throw torrent::input_error("Wrong argument count in apply_arith_count."); + + int64_t val = 0; + + for (torrent::Object::list_const_iterator itr = args.begin(), last = args.end(); itr != last; itr++) { + + switch (itr->type()) { + case torrent::Object::TYPE_VALUE: + case torrent::Object::TYPE_STRING: + val++; + break; + case torrent::Object::TYPE_LIST: + val += apply_arith_count(itr->as_list()); + break; + default: + throw torrent::input_error("Wrong type supplied to apply_arith_count."); + } + + } + + return val; +} + +int64_t +apply_arith_other(const char* op, const torrent::Object::list_type& args) { + if (args.size() == 0) + throw torrent::input_error("Wrong argument count in apply_arith_other."); + + if (op == "average") + return (int64_t)(apply_math_basic(std::plus(), args) / apply_arith_count(args)); + else + throw torrent::input_error("Wrong operation supplied to apply_arith_other."); + +} + void initialize_command_ui() { CMD2_VAR_STRING("keys.layout", "qwerty"); @@ -640,9 +678,10 @@ initialize_command_ui() { CMD2_ANY_LIST("math.mul", std::bind(&apply_math_basic, std::multiplies(), std::placeholders::_2)); CMD2_ANY_LIST("math.div", std::bind(&apply_math_basic, std::divides(), std::placeholders::_2)); CMD2_ANY_LIST("math.mod", std::bind(&apply_math_basic, std::modulus(), std::placeholders::_2)); - CMD2_ANY_LIST("math.min", std::bind(&apply_arith_basic, std::less(), std::placeholders::_2)); CMD2_ANY_LIST("math.max", std::bind(&apply_arith_basic, std::greater(), std::placeholders::_2)); + CMD2_ANY_LIST("math.cnt", std::bind(&apply_arith_count, std::placeholders::_2)); + CMD2_ANY_LIST("math.avg", std::bind(&apply_arith_other, "average", std::placeholders::_2)); CMD2_ANY_LIST ("elapsed.less", std::bind(&apply_elapsed_less, std::placeholders::_2)); CMD2_ANY_LIST ("elapsed.greater", std::bind(&apply_elapsed_greater, std::placeholders::_2)); From 6cb176ada3d411cdb8a9ffb3b9ed956c436f9810 Mon Sep 17 00:00:00 2001 From: chros Date: Tue, 7 Mar 2017 13:12:18 +0000 Subject: [PATCH 42/65] Add more info to throw message in math commands (See #14) --- src/command_ui.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/command_ui.cc b/src/command_ui.cc index bbb07a4d6..a558de640 100644 --- a/src/command_ui.cc +++ b/src/command_ui.cc @@ -522,7 +522,7 @@ apply_elapsed_greater(const torrent::Object::list_type& args) { int64_t apply_math_basic(const std::function op, const torrent::Object::list_type& args) { if (args.size() == 0) - throw torrent::input_error("Wrong argument count."); + throw torrent::input_error("Wrong argument count in apply_math_basic."); int64_t val = 0; @@ -546,7 +546,7 @@ apply_math_basic(const std::function op, const torrent int64_t apply_arith_basic(const std::function op, const torrent::Object::list_type& args) { if (args.size() == 0) - throw torrent::input_error("Wrong argument count."); + throw torrent::input_error("Wrong argument count in apply_arith_basic."); int64_t val = 0; From 13676f06e5398b83f05e13d9f60288f1c0eba1ef Mon Sep 17 00:00:00 2001 From: chros Date: Sat, 11 Mar 2017 11:40:08 +0000 Subject: [PATCH 43/65] Add median command (See #14) --- rak/algorithm.h | 20 ++++++++++++++++++++ src/command_ui.cc | 36 +++++++++++++++++++++++++++++++++--- 2 files changed, 53 insertions(+), 3 deletions(-) diff --git a/rak/algorithm.h b/rak/algorithm.h index ad8e71589..986138201 100644 --- a/rak/algorithm.h +++ b/rak/algorithm.h @@ -176,6 +176,26 @@ inline int popcount_wrapper(T t) { #endif } +// Get the median of an unordered set of numbers of arbitrary +// type by modifing the underlying dataset +template +T median(_InputIter __first, _InputIter __last) { + T __med; + + unsigned int __size = __last - __first; + unsigned int __middle = __size / 2; + _InputIter __target1 = __first + __middle; + std::nth_element(__first, __target1, __last); + __med = *__target1; + + if (__size % 2 == 0) { + _InputIter __target2 = std::max_element(__first, __target1); + __med = (__med + *__target2) / 2.0; + } + + return __med; +} + } #endif diff --git a/src/command_ui.cc b/src/command_ui.cc index a558de640..d0646bd1f 100644 --- a/src/command_ui.cc +++ b/src/command_ui.cc @@ -39,6 +39,7 @@ #include #include +#include #include #include @@ -519,6 +520,31 @@ apply_elapsed_greater(const torrent::Object::list_type& args) { return (int64_t)(start_time != 0 && rak::timer::current_seconds() - start_time > rpc::convert_to_value(args.back())); } +inline std::vector +as_vector(const torrent::Object::list_type& args) { + if (args.size() == 0) + throw torrent::input_error("Wrong argument count in as_list."); + + std::vector result; + + for (torrent::Object::list_const_iterator itr = args.begin(), last = args.end(); itr != last; itr++) { + + if (itr->is_value()) { + result.push_back(itr->as_value()); + } else if (itr->is_string()) { + result.push_back(rpc::convert_to_value(itr->as_string())); + } else if (itr->is_list()) { + std::vector subResult = as_vector(itr->as_list()); + result.insert(result.end(), subResult.begin(), subResult.end()); + } else { + throw torrent::input_error("Wrong type supplied to as_list."); + } + + } + + return result; +} + int64_t apply_math_basic(const std::function op, const torrent::Object::list_type& args) { if (args.size() == 0) @@ -600,11 +626,14 @@ apply_arith_other(const char* op, const torrent::Object::list_type& args) { if (args.size() == 0) throw torrent::input_error("Wrong argument count in apply_arith_other."); - if (op == "average") + if (op == "average") { return (int64_t)(apply_math_basic(std::plus(), args) / apply_arith_count(args)); - else + } else if (op == "median") { + std::vector result = as_vector(args); + return (int64_t)rak::median(result.begin(), result.end()); + } else { throw torrent::input_error("Wrong operation supplied to apply_arith_other."); - + } } void @@ -682,6 +711,7 @@ initialize_command_ui() { CMD2_ANY_LIST("math.max", std::bind(&apply_arith_basic, std::greater(), std::placeholders::_2)); CMD2_ANY_LIST("math.cnt", std::bind(&apply_arith_count, std::placeholders::_2)); CMD2_ANY_LIST("math.avg", std::bind(&apply_arith_other, "average", std::placeholders::_2)); + CMD2_ANY_LIST("math.med", std::bind(&apply_arith_other, "median", std::placeholders::_2)); CMD2_ANY_LIST ("elapsed.less", std::bind(&apply_elapsed_less, std::placeholders::_2)); CMD2_ANY_LIST ("elapsed.greater", std::bind(&apply_elapsed_greater, std::placeholders::_2)); From 63dfe341a69719d52b7fa307ff8ba48f14b9fd1b Mon Sep 17 00:00:00 2001 From: pyroscope Date: Fri, 17 Mar 2017 20:25:11 +0100 Subject: [PATCH 44/65] handle SIGHUP like SIGINT (closes #578) --- src/main.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main.cc b/src/main.cc index 1a06b6665..369f8d6da 100644 --- a/src/main.cc +++ b/src/main.cc @@ -197,6 +197,7 @@ main(int argc, char** argv) { SignalHandler::set_ignore(SIGPIPE); SignalHandler::set_handler(SIGINT, std::bind(&Control::receive_normal_shutdown, control)); + SignalHandler::set_handler(SIGHUP, std::bind(&Control::receive_normal_shutdown, control)); SignalHandler::set_handler(SIGTERM, std::bind(&Control::receive_quick_shutdown, control)); SignalHandler::set_handler(SIGWINCH, std::bind(&display::Manager::force_redraw, control->display())); SignalHandler::set_handler(SIGSEGV, std::bind(&do_panic, SIGSEGV)); From 2ec90c6892befcc919782ee4bce84e6a7a3ac055 Mon Sep 17 00:00:00 2001 From: pyroscope Date: Fri, 17 Mar 2017 21:43:41 +0100 Subject: [PATCH 45/65] no // at start of expanded paths (closes #319) --- src/core/manager.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/manager.cc b/src/core/manager.cc index b00fe6d43..2130b453e 100644 --- a/src/core/manager.cc +++ b/src/core/manager.cc @@ -416,7 +416,7 @@ path_expand(std::vector* paths, const std::string& pattern) { itr->update((r.pattern()[0] != '.') ? utils::Directory::update_hide_dot : 0); itr->erase(std::remove_if(itr->begin(), itr->end(), rak::on(rak::mem_ref(&utils::directory_entry::d_name), std::not1(r))), itr->end()); - std::transform(itr->begin(), itr->end(), std::back_inserter(nextCache), rak::bind1st(std::ptr_fun(&path_expand_transform), itr->path() + "/")); + std::transform(itr->begin(), itr->end(), std::back_inserter(nextCache), rak::bind1st(std::ptr_fun(&path_expand_transform), itr->path() + (itr->path() == "/" ? "" : "/"))); } currentCache.clear(); From 4d6f6fe335b75f5c622e3759e5f0272b2ee09958 Mon Sep 17 00:00:00 2001 From: pyroscope Date: Sat, 1 Apr 2017 12:30:10 +0200 Subject: [PATCH 46/65] add '[ X of Y ]' to title bar --- src/display/window_download_list.cc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/display/window_download_list.cc b/src/display/window_download_list.cc index 749115555..7eaf38001 100644 --- a/src/display/window_download_list.cc +++ b/src/display/window_download_list.cc @@ -86,6 +86,15 @@ WindowDownloadList::redraw() { if (m_view->empty_visible() || m_canvas->width() < 5 || m_canvas->height() < 2) return; + // show "X of Y" + if (m_canvas->width() > 16 + 8 + m_view->name().length()) { + int item_idx = m_view->focus() - m_view->begin_visible(); + if (item_idx == int(m_view->size())) + m_canvas->print(m_canvas->width() - 16, 0, "[ none of %-5d]", m_view->size()); + else + m_canvas->print(m_canvas->width() - 16, 0, "[%5d of %-5d]", item_idx + 1, m_view->size()); + } + int layout_height; const std::string layout_name = rpc::call_command_string("ui.torrent_list.layout"); From 29d57e858a990624592b82778e540fecc0210661 Mon Sep 17 00:00:00 2001 From: chros Date: Tue, 6 Jun 2017 09:54:01 +0100 Subject: [PATCH 47/65] Make global throttle steps adjustable (Closes #17) --- src/command_ui.cc | 4 ++++ src/ui/download.cc | 25 +++++++++++++------------ src/ui/root.cc | 28 ++++++++++++++-------------- 3 files changed, 31 insertions(+), 26 deletions(-) diff --git a/src/command_ui.cc b/src/command_ui.cc index 69ee2f540..6a694691c 100644 --- a/src/command_ui.cc +++ b/src/command_ui.cc @@ -555,6 +555,10 @@ initialize_command_ui() { CMD2_ANY ("ui.current_view", std::bind(&cmd_ui_current_view)); CMD2_ANY_STRING("ui.current_view.set", std::bind(&cmd_ui_set_view, std::placeholders::_2)); + CMD2_VAR_VALUE ("ui.throttle.global.step.small", 5); + CMD2_VAR_VALUE ("ui.throttle.global.step.medium", 50); + CMD2_VAR_VALUE ("ui.throttle.global.step.large", 500); + // TODO: Add 'option_string' for rtorrent-specific options. CMD2_VAR_STRING("ui.torrent_list.layout", "full"); diff --git a/src/ui/download.cc b/src/ui/download.cc index 6058fe771..a82e2f774 100644 --- a/src/ui/download.cc +++ b/src/ui/download.cc @@ -54,6 +54,7 @@ #include "display/window_download_statusbar.h" #include "display/text_element_string.h" +#include "rpc/parse_commands.h" #include "control.h" #include "download.h" @@ -395,20 +396,20 @@ Download::bind_keys() { const char* keys = control->ui()->get_throttle_keys(); - m_bindings[keys[ 0]] = std::bind(&Download::adjust_up_throttle, this, 1); - m_bindings[keys[ 1]] = std::bind(&Download::adjust_up_throttle, this, -1); - m_bindings[keys[ 2]] = std::bind(&Download::adjust_down_throttle, this, 1); - m_bindings[keys[ 3]] = std::bind(&Download::adjust_down_throttle, this, -1); + m_bindings[keys[ 0]] = std::bind(&Download::adjust_up_throttle, this, (int) rpc::call_command_value("ui.throttle.global.step.small")); + m_bindings[keys[ 1]] = std::bind(&Download::adjust_up_throttle, this, (int) -rpc::call_command_value("ui.throttle.global.step.small")); + m_bindings[keys[ 2]] = std::bind(&Download::adjust_down_throttle, this, (int) rpc::call_command_value("ui.throttle.global.step.small")); + m_bindings[keys[ 3]] = std::bind(&Download::adjust_down_throttle, this, (int) -rpc::call_command_value("ui.throttle.global.step.small")); - m_bindings[keys[ 4]] = std::bind(&Download::adjust_up_throttle, this, 5); - m_bindings[keys[ 5]] = std::bind(&Download::adjust_up_throttle, this, -5); - m_bindings[keys[ 6]] = std::bind(&Download::adjust_down_throttle, this, 5); - m_bindings[keys[ 7]] = std::bind(&Download::adjust_down_throttle, this, -5); + m_bindings[keys[ 4]] = std::bind(&Download::adjust_up_throttle, this, (int) rpc::call_command_value("ui.throttle.global.step.medium")); + m_bindings[keys[ 5]] = std::bind(&Download::adjust_up_throttle, this, (int) -rpc::call_command_value("ui.throttle.global.step.medium")); + m_bindings[keys[ 6]] = std::bind(&Download::adjust_down_throttle, this, (int) rpc::call_command_value("ui.throttle.global.step.medium")); + m_bindings[keys[ 7]] = std::bind(&Download::adjust_down_throttle, this, (int) -rpc::call_command_value("ui.throttle.global.step.medium")); - m_bindings[keys[ 8]] = std::bind(&Download::adjust_up_throttle, this, 50); - m_bindings[keys[ 9]] = std::bind(&Download::adjust_up_throttle, this, -50); - m_bindings[keys[10]] = std::bind(&Download::adjust_down_throttle, this, 50); - m_bindings[keys[11]] = std::bind(&Download::adjust_down_throttle, this, -50); + m_bindings[keys[ 8]] = std::bind(&Download::adjust_up_throttle, this, (int) rpc::call_command_value("ui.throttle.global.step.large")); + m_bindings[keys[ 9]] = std::bind(&Download::adjust_up_throttle, this, (int) -rpc::call_command_value("ui.throttle.global.step.large")); + m_bindings[keys[10]] = std::bind(&Download::adjust_down_throttle, this, (int) rpc::call_command_value("ui.throttle.global.step.large")); + m_bindings[keys[11]] = std::bind(&Download::adjust_down_throttle, this, (int) -rpc::call_command_value("ui.throttle.global.step.large")); } } diff --git a/src/ui/root.cc b/src/ui/root.cc index e02fc938a..29e45d3f2 100644 --- a/src/ui/root.cc +++ b/src/ui/root.cc @@ -140,20 +140,20 @@ Root::setup_keys() { const char* keys = get_throttle_keys(); - m_bindings[keys[ 0]] = std::bind(&Root::adjust_up_throttle, this, 1); - m_bindings[keys[ 1]] = std::bind(&Root::adjust_up_throttle, this, -1); - m_bindings[keys[ 2]] = std::bind(&Root::adjust_down_throttle, this, 1); - m_bindings[keys[ 3]] = std::bind(&Root::adjust_down_throttle, this, -1); - - m_bindings[keys[ 4]] = std::bind(&Root::adjust_up_throttle, this, 5); - m_bindings[keys[ 5]] = std::bind(&Root::adjust_up_throttle, this, -5); - m_bindings[keys[ 6]] = std::bind(&Root::adjust_down_throttle, this, 5); - m_bindings[keys[ 7]] = std::bind(&Root::adjust_down_throttle, this, -5); - - m_bindings[keys[ 8]] = std::bind(&Root::adjust_up_throttle, this, 50); - m_bindings[keys[ 9]] = std::bind(&Root::adjust_up_throttle, this, -50); - m_bindings[keys[10]] = std::bind(&Root::adjust_down_throttle, this, 50); - m_bindings[keys[11]] = std::bind(&Root::adjust_down_throttle, this, -50); + m_bindings[keys[ 0]] = std::bind(&Root::adjust_up_throttle, this, (int) rpc::call_command_value("ui.throttle.global.step.small")); + m_bindings[keys[ 1]] = std::bind(&Root::adjust_up_throttle, this, (int) -rpc::call_command_value("ui.throttle.global.step.small")); + m_bindings[keys[ 2]] = std::bind(&Root::adjust_down_throttle, this, (int) rpc::call_command_value("ui.throttle.global.step.small")); + m_bindings[keys[ 3]] = std::bind(&Root::adjust_down_throttle, this, (int) -rpc::call_command_value("ui.throttle.global.step.small")); + + m_bindings[keys[ 4]] = std::bind(&Root::adjust_up_throttle, this, (int) rpc::call_command_value("ui.throttle.global.step.medium")); + m_bindings[keys[ 5]] = std::bind(&Root::adjust_up_throttle, this, (int) -rpc::call_command_value("ui.throttle.global.step.medium")); + m_bindings[keys[ 6]] = std::bind(&Root::adjust_down_throttle, this, (int) rpc::call_command_value("ui.throttle.global.step.medium")); + m_bindings[keys[ 7]] = std::bind(&Root::adjust_down_throttle, this, (int) -rpc::call_command_value("ui.throttle.global.step.medium")); + + m_bindings[keys[ 8]] = std::bind(&Root::adjust_up_throttle, this, (int) rpc::call_command_value("ui.throttle.global.step.large")); + m_bindings[keys[ 9]] = std::bind(&Root::adjust_up_throttle, this, (int) -rpc::call_command_value("ui.throttle.global.step.large")); + m_bindings[keys[10]] = std::bind(&Root::adjust_down_throttle, this, (int) rpc::call_command_value("ui.throttle.global.step.large")); + m_bindings[keys[11]] = std::bind(&Root::adjust_down_throttle, this, (int) -rpc::call_command_value("ui.throttle.global.step.large")); m_bindings['\x0C'] = std::bind(&display::Manager::force_redraw, m_control->display()); // ^L m_bindings['\x11'] = std::bind(&Control::receive_normal_shutdown, m_control); // ^Q From 943b576e1fdfbc9fc5b20868e98a7f980ae33000 Mon Sep 17 00:00:00 2001 From: chros Date: Sun, 30 Jul 2017 20:37:21 +0100 Subject: [PATCH 48/65] Fix compilation issue with gcc v6.x and empty CXXFLAGS (See #20) --- configure.ac | 1 + scripts/rak_compiler.m4 | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/configure.ac b/configure.ac index f06290380..c3e91fb68 100644 --- a/configure.ac +++ b/configure.ac @@ -8,6 +8,7 @@ AC_CONFIG_HEADERS(config.h) AC_PROG_CXX AC_PROG_LIBTOOL +RAK_CHECK_CXXFLAGS RAK_ENABLE_DEBUG RAK_ENABLE_EXTRA_DEBUG RAK_ENABLE_WERROR diff --git a/scripts/rak_compiler.m4 b/scripts/rak_compiler.m4 index 39bd19a7d..87871abfe 100644 --- a/scripts/rak_compiler.m4 +++ b/scripts/rak_compiler.m4 @@ -1,3 +1,16 @@ +AC_DEFUN([RAK_CHECK_CXXFLAGS], [ + + AC_MSG_CHECKING([for user-defined CXXFLAGS]) + + if test -n "$CXXFLAGS"; then + AC_MSG_RESULT([user-defined "$CXXFLAGS"]) + else + CXXFLAGS="-O2" + AC_MSG_RESULT([default "$CXXFLAGS"]) + fi +]) + + AC_DEFUN([RAK_ENABLE_DEBUG], [ AC_ARG_ENABLE(debug, AC_HELP_STRING([--enable-debug], [enable debug information [[default=yes]]]), From 1a4f6dab1ab5e0e29dc1a96be13a009455bfafb2 Mon Sep 17 00:00:00 2001 From: chros Date: Wed, 2 Aug 2017 12:51:03 +0100 Subject: [PATCH 49/65] Modfiy gcc v6.x fix for empty CXXFLAGS (See #20) --- configure.ac | 1 + scripts/rak_compiler.m4 | 21 +++++++++++++++++---- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index c3e91fb68..feb28e2b7 100644 --- a/configure.ac +++ b/configure.ac @@ -8,6 +8,7 @@ AC_CONFIG_HEADERS(config.h) AC_PROG_CXX AC_PROG_LIBTOOL +RAK_CHECK_CFLAGS RAK_CHECK_CXXFLAGS RAK_ENABLE_DEBUG RAK_ENABLE_EXTRA_DEBUG diff --git a/scripts/rak_compiler.m4 b/scripts/rak_compiler.m4 index 87871abfe..9a361bed2 100644 --- a/scripts/rak_compiler.m4 +++ b/scripts/rak_compiler.m4 @@ -1,12 +1,25 @@ +AC_DEFUN([RAK_CHECK_CFLAGS], [ + + AC_MSG_CHECKING([for user-defined CFLAGS]) + + if test "$CFLAGS" = ""; then + unset CFLAGS + AC_MSG_RESULT([undefined]) + else + AC_MSG_RESULT([user-defined "$CFLAGS"]) + fi +]) + + AC_DEFUN([RAK_CHECK_CXXFLAGS], [ AC_MSG_CHECKING([for user-defined CXXFLAGS]) - if test -n "$CXXFLAGS"; then - AC_MSG_RESULT([user-defined "$CXXFLAGS"]) + if test "$CXXFLAGS" = ""; then + unset CXXFLAGS + AC_MSG_RESULT([undefined]) else - CXXFLAGS="-O2" - AC_MSG_RESULT([default "$CXXFLAGS"]) + AC_MSG_RESULT([user-defined "$CXXFLAGS"]) fi ]) From 33f8fe804bffd20aba00e325ee1181b18ff30708 Mon Sep 17 00:00:00 2001 From: chros Date: Sun, 10 Dec 2017 18:54:55 +0000 Subject: [PATCH 50/65] IPv4 filter enhancement (Closes #21) --- src/command_ip.cc | 297 ++++++++++++++++++++++++++++------------ src/rpc/ip_table_list.h | 2 +- 2 files changed, 208 insertions(+), 91 deletions(-) diff --git a/src/command_ip.cc b/src/command_ip.cc index fec85081a..b13db0a1e 100644 --- a/src/command_ip.cc +++ b/src/command_ip.cc @@ -45,42 +45,14 @@ #include "globals.h" #include "command_helpers.h" -void -ipv4_filter_parse(const char* address, int value) { - uint32_t ip_values[4] = { 0, 0, 0, 0 }; - unsigned int block = rpc::ipv4_table::mask_bits; - - char ip_dot; - int values_read; - - if ((values_read = sscanf(address, "%u%1[.]%u%1[.]%u%1[.]%u/%u", - ip_values + 0, &ip_dot, - ip_values + 1, &ip_dot, - ip_values + 2, &ip_dot, - ip_values + 3, - &block)) < 2 || - - // Make sure the dot is included. - (values_read < 7 && values_read % 2) || - - ip_values[0] >= 256 || - ip_values[1] >= 256 || - ip_values[2] >= 256 || - ip_values[3] >= 256 || - - block > rpc::ipv4_table::mask_bits) - throw torrent::input_error("Invalid address format."); - - // E.g. '10.10.' will be '10.10.0.0/16'. - if (values_read < 7) - block = 8 * (values_read / 2); - - lt_log_print(torrent::LOG_CONNECTION_DEBUG, "Adding ip filter for %u.%u.%u.%u/%u.", - ip_values[0], ip_values[1], ip_values[2], ip_values[3], block); +#include +#include +#include +#include +#include +#include - torrent::PeerList::ipv4_filter()->insert((ip_values[0] << 24) + (ip_values[1] << 16) + (ip_values[2] << 8) + ip_values[3], - rpc::ipv4_table::mask_bits - block, value); -} +bool ipv4_range_parse(const char* address, uint32_t* address_start, uint32_t* address_end); torrent::Object apply_ip_tables_insert_table(const std::string& args) { @@ -98,7 +70,8 @@ apply_ip_tables_size_data(const std::string& args) { if (itr != ip_tables.end()) throw torrent::input_error("IP table does not exist."); - return itr->table.sizeof_data(); + uint32_t size = itr->table.sizeof_data(); + return size; } torrent::Object @@ -110,20 +83,21 @@ apply_ip_tables_get(const torrent::Object::list_type& args) { const std::string& name = (args_itr++)->as_string(); const std::string& address = (args_itr++)->as_string(); - - // Move to a helper function, add support for addresses. - uint32_t ip_values[4]; - - if (sscanf(address.c_str(), "%u.%u.%u.%u", - ip_values + 0, ip_values + 1, ip_values + 2, ip_values + 3) != 4) - throw torrent::input_error("Invalid address format."); + uint32_t address_start; + uint32_t address_end; rpc::ip_table_list::iterator table_itr = ip_tables.find(name); if (table_itr == ip_tables.end()) throw torrent::input_error("Could not find ip table."); - return table_itr->table.at((ip_values[0] << 24) + (ip_values[1] << 16) + (ip_values[2] << 8) + ip_values[3]); + if (!ipv4_range_parse(address.c_str(), &address_start, &address_end)) + throw torrent::input_error("Invalid address format."); + + if(!table_itr->table.defined(address_start, address_end)) + throw torrent::input_error("No value defined for specified IP(s)."); + + return table_itr->table.at(address_start, address_end); } torrent::Object @@ -136,15 +110,6 @@ apply_ip_tables_add_address(const torrent::Object::list_type& args) { const std::string& name = (args_itr++)->as_string(); const std::string& address = (args_itr++)->as_string(); const std::string& value_str = (args_itr++)->as_string(); - - // Move to a helper function, add support for addresses. - uint32_t ip_values[4]; - unsigned int block = rpc::ipv4_table::mask_bits; - - if (sscanf(address.c_str(), "%u.%u.%u.%u/%u", - ip_values + 0, ip_values + 1, ip_values + 2, ip_values + 3, &block) < 4 || - block > rpc::ipv4_table::mask_bits) - throw torrent::input_error("Invalid address format."); int value; @@ -158,8 +123,13 @@ apply_ip_tables_add_address(const torrent::Object::list_type& args) { if (table_itr == ip_tables.end()) throw torrent::input_error("Could not find ip table."); - table_itr->table.insert((ip_values[0] << 24) + (ip_values[1] << 16) + (ip_values[2] << 8) + ip_values[3], - rpc::ipv4_table::mask_bits - block, value); + uint32_t address_start; + uint32_t address_end; + + if (ipv4_range_parse(address.c_str(), &address_start, &address_end)) + table_itr->table.insert(address_start, address_end, value); + else + throw torrent::input_error("Invalid address format."); return torrent::Object(); } @@ -168,6 +138,158 @@ apply_ip_tables_add_address(const torrent::Object::list_type& args) { // IPv4 filter functions: // +/////////////////////////////////////////////////////////// +// IPV4_RANGE_PARSE parses string into an ip range +// +// should be compatible with lines in p2p files +// everything in address before colon is ignored +// +// ip range can be single ip in which case start=end +// ip range can be cidr notation a.b.c.d/e +// ip range can be explicit range like in p2p line a.b.c.d-w.x.y.z +// +// returns false if line does not contain valid ip or ip range +// address_start and address_end will contain start and end ip +// +// addresses parsed are returned in host byte order +// to get network byte order call htonl(address) +/////////////////////////////////////////////////////////// +bool +ipv4_range_parse(const char* address, uint32_t* address_start, uint32_t* address_end) { + // same length as buffer used to do reads so no worries about overflow + char address_copy[4096]; + bool valid = false; + char address_start_str[20]; + int address_start_index=0; + struct sockaddr_in sa_start; + *address_start=0; + *address_end=0; + + // get rid of everything after '#' comments + // copy everything up to '#' to address_copy and work from there + while(address[address_start_index] != '#' && address[address_start_index] != '\r' && + address[address_start_index] != '\n' && address[address_start_index] != '\0' && + address_start_index < 4096 ) { + + address_copy[address_start_index] = address[address_start_index]; + address_start_index++; + } + + address_copy[address_start_index] = '\0'; + address_start_index=0; + + // skip everything up to and including last ':' character and whitespace + const char* addr = strrchr(address_copy, ':'); + + addr = (addr == NULL) ? address_copy : addr + 1; + + while(addr[0] == ' ' || addr[0] == '\t') + addr++; + + while(((addr[0] >= '0' && addr[0] <= '9') || addr[0] == '.') && address_start_index < 19) { + address_start_str[address_start_index] = addr[0]; + address_start_index++; + addr++; + } + + address_start_str[address_start_index] = '\0'; + + if(strchr(addr, '-') != NULL) { + // explicit range + char address_end_str[20]; + int address_end_index=0; + struct sockaddr_in sa_end; + + while(addr[0] == '-' || addr[0] == ' ' || addr[0] == '\t') + addr++; + + while(((addr[0] >= '0' && addr[0] <= '9') || addr[0] == '.') && address_end_index < 19) { + address_end_str[address_end_index] = addr[0]; + address_end_index++; + addr++; + } + + address_end_str[address_end_index] = '\0'; + + if(inet_pton(AF_INET, address_start_str, &(sa_start.sin_addr)) != 0 && inet_pton(AF_INET, address_end_str, &(sa_end.sin_addr)) != 0) { + *address_start = ntohl(sa_start.sin_addr.s_addr); + *address_end = ntohl(sa_end.sin_addr.s_addr); + + if(*address_start <= *address_end) + valid=true; + } + } else if(strchr(addr, '/') != NULL) { + // cidr range + char mask_bits_str[20]; + int mask_bits_index=0; + uint32_t mask_bits; + + while(addr[0] == '/' || addr[0] == ' ' || addr[0] == '\t') + addr++; + + while( (addr[0] >= '0' && addr[0] <= '9') && mask_bits_index < 19) { + mask_bits_str[mask_bits_index] = addr[0]; + mask_bits_index++; + addr++; + } + + mask_bits_str[mask_bits_index] = '\0'; + + if(inet_pton(AF_INET, address_start_str, &(sa_start.sin_addr)) != 0 && sscanf(mask_bits_str, "%u", &mask_bits) != 0) { + if(mask_bits <=32) { + uint32_t ip=ntohl(sa_start.sin_addr.s_addr); + uint32_t mask=0; + uint32_t end_mask=0; + + mask = (~mask) << (32-mask_bits); + *address_start = ip & mask; + end_mask = (~end_mask) >> mask_bits; + *address_end = (ip & mask) | end_mask; + + valid=true; + } + } + } else { + // single ip + if(inet_pton(AF_INET, address_start_str, &(sa_start.sin_addr)) != 0) { + *address_start = ntohl(sa_start.sin_addr.s_addr); + *address_end = *address_start; + + valid=true; + } + } + + return valid; +} + +/////////////////////////////////////////////////////////// +// IPV4_FILTER_PARSE +// +// should now be compatible with lines in p2p files +// +// addresses in table MUST be in host byte order +// ntohl is called after parsing ip address(es) +/////////////////////////////////////////////////////////// +void +ipv4_filter_parse(const char* address, int value) { + uint32_t address_start; + uint32_t address_end; + + if (ipv4_range_parse(address, &address_start, &address_end) ) { + torrent::PeerList::ipv4_filter()->insert(address_start, address_end, value); + + char start_str[INET_ADDRSTRLEN]; + char end_str[INET_ADDRSTRLEN]; + uint32_t net_start = htonl(address_start); + uint32_t net_end = htonl(address_end); + + inet_ntop(AF_INET, &net_start, start_str, INET_ADDRSTRLEN); + inet_ntop(AF_INET, &net_end, end_str, INET_ADDRSTRLEN); + + lt_log_print(torrent::LOG_CONNECTION_DEBUG, "Adding ip filter for %s-%s.", start_str, end_str); + } +} + torrent::Object apply_ipv4_filter_size_data() { return torrent::PeerList::ipv4_filter()->sizeof_data(); @@ -175,14 +297,16 @@ apply_ipv4_filter_size_data() { torrent::Object apply_ipv4_filter_get(const std::string& args) { - // Move to a helper function, add support for addresses. - uint32_t ip_values[4]; + uint32_t address_start; + uint32_t address_end; - if (sscanf(args.c_str(), "%u.%u.%u.%u", - ip_values + 0, ip_values + 1, ip_values + 2, ip_values + 3) != 4) + if (!ipv4_range_parse(args.c_str(), &address_start, &address_end)) throw torrent::input_error("Invalid address format."); - return torrent::PeerList::ipv4_filter()->at((ip_values[0] << 24) + (ip_values[1] << 16) + (ip_values[2] << 8) + ip_values[3]); + if(!torrent::PeerList::ipv4_filter()->defined(address_start, address_end)) + throw torrent::input_error("No value defined for specified IP(s)."); + + return torrent::PeerList::ipv4_filter()->at(address_start, address_end); } torrent::Object @@ -240,41 +364,34 @@ apply_ipv4_filter_load(const torrent::Object::list_type& args) { return torrent::Object(); } -static void -append_table(torrent::ipv4_table::base_type* extent, torrent::Object::list_type& result) { - torrent::ipv4_table::table_type::iterator first = extent->table.begin(); - torrent::ipv4_table::table_type::iterator last = extent->table.end(); - - while (first != last) { - if (first->first != NULL) { - // Do something more here?... - append_table(first->first, result); - - } else if (first->second != 0) { - uint32_t position = extent->partition_pos(first); - - char buffer[256]; - snprintf(buffer, 256, "%u.%u.%u.%u/%u %s", - (position >> 24) & 0xff, - (position >> 16) & 0xff, - (position >> 8) & 0xff, - (position >> 0) & 0xff, - extent->mask_bits, - torrent::option_as_string(torrent::OPTION_IP_FILTER, first->second)); - - result.push_back((std::string)buffer); - } - - first++; - } -} - torrent::Object apply_ipv4_filter_dump() { torrent::Object raw_result = torrent::Object::create_list(); torrent::Object::list_type& result = raw_result.as_list(); - append_table(torrent::PeerList::ipv4_filter()->data(), result); + torrent::ipv4_table::range_map_type range_map = torrent::PeerList::ipv4_filter()->range_map; + torrent::ipv4_table::range_map_type::iterator iter = range_map.begin(); + + while(iter != range_map.end()) { + char buffer[64]; + uint32_t address_start = iter->first; + uint32_t address_end = (iter->second).first; + int value = (iter->second).second; + + char start_str[INET_ADDRSTRLEN]; + char end_str[INET_ADDRSTRLEN]; + uint32_t net_start = htonl(address_start); + uint32_t net_end = htonl(address_end); + + inet_ntop(AF_INET, &net_start, start_str, INET_ADDRSTRLEN); + inet_ntop(AF_INET, &net_end, end_str, INET_ADDRSTRLEN); + + snprintf(buffer, 64, "%s-%s %s", start_str, end_str, torrent::option_as_string(torrent::OPTION_IP_FILTER, value)); + + result.push_back((std::string)buffer); + + iter++; + } return raw_result; } diff --git a/src/rpc/ip_table_list.h b/src/rpc/ip_table_list.h index 8a4e16cd5..06a5408da 100644 --- a/src/rpc/ip_table_list.h +++ b/src/rpc/ip_table_list.h @@ -45,7 +45,7 @@ namespace rpc { -typedef torrent::extents ipv4_table; +typedef torrent::extents ipv4_table; struct ip_table_node { std::string name; From 2987ba808184b5d8531d24dde736cec36e33859f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?devil=20=E2=9D=82=20tux?= Date: Fri, 15 Dec 2017 10:45:31 +0100 Subject: [PATCH 51/65] Fix: Missing ranlib in autoconf On RHEL7 & possibly CentOS configuring using `autogen` does not append RANLIB nor is registered by default, this fixes definition of the library. --- configure.ac | 1 + 1 file changed, 1 insertion(+) diff --git a/configure.ac b/configure.ac index f06290380..949d9bb04 100644 --- a/configure.ac +++ b/configure.ac @@ -5,6 +5,7 @@ AC_DEFINE(API_VERSION, 9, api version) AM_INIT_AUTOMAKE AC_CONFIG_HEADERS(config.h) +AC_PROG_RANLIB AC_PROG_CXX AC_PROG_LIBTOOL From b82f3614c356aea83a58d6d3b3e392fa316754fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=98=83=20Stephen=20Shkardoon=20=E2=98=83?= Date: Sun, 14 Jan 2018 02:09:42 +1300 Subject: [PATCH 52/65] Include SCGI/XMLRPC example in rtorrent.rc Examples are for scgi_port, and scgi_local (with scheduling to change permissions on the file). --- doc/rtorrent.rc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/doc/rtorrent.rc b/doc/rtorrent.rc index 543831763..d0c17cf43 100644 --- a/doc/rtorrent.rc +++ b/doc/rtorrent.rc @@ -101,3 +101,12 @@ # Set downlad list layout style. ("full", "compact") # #ui.torrent_list.layout.set = "full" + +# SCGI Connectivity (for alternative rtorrent interfaces, XMLRPC) +# +# Use a IP socket with scgi_port, or a Unix socket with scgi_local. +# schedule can be used to set permissions on the unix socket. +# +#scgi_port = 127.0.0.1:5000 +#scgi_local = /home/user/rtorrent/rpc.socket +#schedule = scgi_permission,0,0,"execute.nothrow=chmod,\"g+w,o=\",/home/user/rtorrent/rpc.socket" From 3ea47d7acb69ba97030558279cbbdf2327e94885 Mon Sep 17 00:00:00 2001 From: chros Date: Wed, 24 Jan 2018 18:20:14 +0000 Subject: [PATCH 53/65] Fix for missing throttle arguments (See #23) --- src/command_throttle.cc | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/command_throttle.cc b/src/command_throttle.cc index bfe95eea9..fde828a55 100644 --- a/src/command_throttle.cc +++ b/src/command_throttle.cc @@ -96,12 +96,15 @@ torrent::Object apply_throttle(const torrent::Object::list_type& args, bool up) { torrent::Object::list_const_iterator argItr = args.begin(); + if (argItr == args.end()) + throw torrent::input_error("Missing throttle name."); + const std::string& name = argItr->as_string(); if (name.empty() || name == "NULL") - throw torrent::input_error("Invalid throttle name."); + throw torrent::input_error("Invalid throttle name '" + name + "'."); - if ((++argItr)->as_string().empty()) - return torrent::Object(); + if (++argItr == args.end() || argItr->as_string().empty()) + throw torrent::input_error("Missing throttle rate for '" + name + "'."); int64_t rate; rpc::parse_whole_value_nothrow(argItr->as_string().c_str(), &rate); From 6c11a1dbb065adc179e280dbf77b0b65eedc6b9c Mon Sep 17 00:00:00 2001 From: chros Date: Sat, 3 Mar 2018 09:08:28 +0000 Subject: [PATCH 54/65] Fix error message in as_vector method (See #14) --- src/command_ui.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/command_ui.cc b/src/command_ui.cc index d0646bd1f..5cd1e4af1 100644 --- a/src/command_ui.cc +++ b/src/command_ui.cc @@ -523,7 +523,7 @@ apply_elapsed_greater(const torrent::Object::list_type& args) { inline std::vector as_vector(const torrent::Object::list_type& args) { if (args.size() == 0) - throw torrent::input_error("Wrong argument count in as_list."); + throw torrent::input_error("Wrong argument count in as_vector."); std::vector result; @@ -537,7 +537,7 @@ as_vector(const torrent::Object::list_type& args) { std::vector subResult = as_vector(itr->as_list()); result.insert(result.end(), subResult.begin(), subResult.end()); } else { - throw torrent::input_error("Wrong type supplied to as_list."); + throw torrent::input_error("Wrong type supplied to as_vector."); } } From 6dc87e499ac4292d98c258b61dd140bb17de9c3e Mon Sep 17 00:00:00 2001 From: chros Date: Fri, 1 Jun 2018 11:51:42 +0100 Subject: [PATCH 55/65] Fix bugs in 'math.*' commands (See #14) --- src/command_ui.cc | 38 ++++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/src/command_ui.cc b/src/command_ui.cc index 5cd1e4af1..c98f94274 100644 --- a/src/command_ui.cc +++ b/src/command_ui.cc @@ -546,24 +546,30 @@ as_vector(const torrent::Object::list_type& args) { } int64_t -apply_math_basic(const std::function op, const torrent::Object::list_type& args) { - if (args.size() == 0) - throw torrent::input_error("Wrong argument count in apply_math_basic."); +apply_math_basic(const char* name, const std::function op, const torrent::Object::list_type& args) { + int64_t val = 0, rhs = 0; + bool divides = !strcmp(name, "math.div") || !strcmp(name, "math.mod"); - int64_t val = 0; + if (args.size() == 0) + throw torrent::input_error(std::string(name) + ": No arguments provided!"); for (torrent::Object::list_const_iterator itr = args.begin(), last = args.end(); itr != last; itr++) { if (itr->is_value()) { - val = itr == args.begin() ? itr->as_value() : op(val, itr->as_value()); + rhs = itr->as_value(); } else if (itr->is_string()) { - val = itr == args.begin() ? rpc::convert_to_value(itr->as_string()) : op(val, rpc::convert_to_value(itr->as_string())); + rhs = rpc::convert_to_value(itr->as_string()); } else if (itr->is_list()) { - val = itr == args.begin() ? apply_math_basic(op, itr->as_list()) : op(val, apply_math_basic(op, itr->as_list())); + rhs = apply_math_basic(name, op, itr->as_list()); } else { - throw torrent::input_error("Wrong type supplied to apply_math_basic."); + throw torrent::input_error(std::string(name) + ": Wrong argument type"); } + if (divides && !rhs && itr != args.begin()) + throw torrent::input_error(std::string(name) + ": Division by zero!"); + + val = itr == args.begin() ? rhs : op(val, rhs); + } return val; @@ -626,9 +632,9 @@ apply_arith_other(const char* op, const torrent::Object::list_type& args) { if (args.size() == 0) throw torrent::input_error("Wrong argument count in apply_arith_other."); - if (op == "average") { - return (int64_t)(apply_math_basic(std::plus(), args) / apply_arith_count(args)); - } else if (op == "median") { + if (strcmp(op, "average") == 0) { + return (int64_t)(apply_math_basic(op, std::plus(), args) / apply_arith_count(args)); + } else if (strcmp(op, "median") == 0) { std::vector result = as_vector(args); return (int64_t)rak::median(result.begin(), result.end()); } else { @@ -702,11 +708,11 @@ initialize_command_ui() { CMD2_ANY_VALUE("convert.xb", std::bind(&apply_to_xb, std::placeholders::_2)); CMD2_ANY_VALUE("convert.throttle", std::bind(&apply_to_throttle, std::placeholders::_2)); - CMD2_ANY_LIST("math.add", std::bind(&apply_math_basic, std::plus(), std::placeholders::_2)); - CMD2_ANY_LIST("math.sub", std::bind(&apply_math_basic, std::minus(), std::placeholders::_2)); - CMD2_ANY_LIST("math.mul", std::bind(&apply_math_basic, std::multiplies(), std::placeholders::_2)); - CMD2_ANY_LIST("math.div", std::bind(&apply_math_basic, std::divides(), std::placeholders::_2)); - CMD2_ANY_LIST("math.mod", std::bind(&apply_math_basic, std::modulus(), std::placeholders::_2)); + CMD2_ANY_LIST("math.add", std::bind(&apply_math_basic, "math.add", std::plus(), std::placeholders::_2)); + CMD2_ANY_LIST("math.sub", std::bind(&apply_math_basic, "math.sub", std::minus(), std::placeholders::_2)); + CMD2_ANY_LIST("math.mul", std::bind(&apply_math_basic, "math.mul", std::multiplies(), std::placeholders::_2)); + CMD2_ANY_LIST("math.div", std::bind(&apply_math_basic, "math.div", std::divides(), std::placeholders::_2)); + CMD2_ANY_LIST("math.mod", std::bind(&apply_math_basic, "math.mod", std::modulus(), std::placeholders::_2)); CMD2_ANY_LIST("math.min", std::bind(&apply_arith_basic, std::less(), std::placeholders::_2)); CMD2_ANY_LIST("math.max", std::bind(&apply_arith_basic, std::greater(), std::placeholders::_2)); CMD2_ANY_LIST("math.cnt", std::bind(&apply_arith_count, std::placeholders::_2)); From fd372b5e48439ad6d5cd1a36af6d5d13b989b61c Mon Sep 17 00:00:00 2001 From: rakshasa Date: Tue, 5 Jun 2018 16:22:01 +0900 Subject: [PATCH 56/65] Cleaned up download list bug fix.. --- src/ui/download_list.cc | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/ui/download_list.cc b/src/ui/download_list.cc index 08ed13bed..003f9cd01 100644 --- a/src/ui/download_list.cc +++ b/src/ui/download_list.cc @@ -126,15 +126,11 @@ DownloadList::set_current_view(const std::string& name) { void DownloadList::unfocus_download(core::Download* d) { - if (m_state == DISPLAY_DOWNLOAD) { - if (d == static_cast(m_uiArray[DISPLAY_DOWNLOAD])->download()) { - activate_display(DISPLAY_DOWNLOAD_LIST); - } - } + if (m_state == DISPLAY_DOWNLOAD && d == static_cast(m_uiArray[DISPLAY_DOWNLOAD])->download()) + activate_display(DISPLAY_DOWNLOAD_LIST); - if (*current_view()->focus() == d && current_view()->focus() < current_view()->end_visible()) { + if (*current_view()->focus() == d && current_view()->focus() < current_view()->end_visible()) current_view()->next_focus(); - } } void From dd2a4cc15192e712ee97b787967fa9fd390dbdea Mon Sep 17 00:00:00 2001 From: rakshasa Date: Tue, 5 Jun 2018 16:37:48 +0900 Subject: [PATCH 57/65] Fixed ncurses.h include bug fix by theirix. --- src/input/input_event.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/input/input_event.cc b/src/input/input_event.cc index 69dfef05d..72159d62f 100644 --- a/src/input/input_event.cc +++ b/src/input/input_event.cc @@ -38,8 +38,7 @@ #include "input_event.h" -//ncurses.h must be included last since sys/mman.h on Solaris munges ERR. -#include +#include "display/attributes.h" namespace input { From 327164f9d86aafcd2500a317d485374df32ea622 Mon Sep 17 00:00:00 2001 From: rakshasa Date: Thu, 7 Jun 2018 13:18:34 +0900 Subject: [PATCH 58/65] Bumped version to 0.6.7. --- configure.ac | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index a3701fb9d..cf9bc47f4 100644 --- a/configure.ac +++ b/configure.ac @@ -1,4 +1,4 @@ -AC_INIT(rtorrent, 0.9.6, sundell.software@gmail.com) +AC_INIT(rtorrent, 0.9.7, sundell.software@gmail.com) AC_DEFINE(API_VERSION, 9, api version) @@ -40,7 +40,7 @@ fi PKG_CHECK_MODULES([LIBCURL], [libcurl], , [LIBCURL_CHECK_CONFIG]) PKG_CHECK_MODULES([CPPUNIT], [cppunit],, [no_cppunit="yes"]) -PKG_CHECK_MODULES([DEPENDENCIES], [libtorrent >= 0.13.6]) +PKG_CHECK_MODULES([DEPENDENCIES], [libtorrent >= 0.13.7]) LIBS="$PTHREAD_LIBS $CURSES_LIB $CPPUNIT_LIBS $LIBCURL $LIBCURL_LIBS $DEPENDENCIES_LIBS $LIBS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS $CPPUNIT_CFLAGS $LIBCURL_CPPFLAGS $LIBCURL_CFLAGS $DEPENDENCIES_CFLAGS $CURSES_CFLAGS" From ca4c3bee8d144982c72020c0f9b91b0e434a34c7 Mon Sep 17 00:00:00 2001 From: pyroscope Date: Thu, 14 Jun 2018 20:32:28 +0200 Subject: [PATCH 59/65] add d.custom.if_z + d.custom.keys + d.custom.items --- src/command_download.cc | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/command_download.cc b/src/command_download.cc index 6d7b34581..a31d68570 100644 --- a/src/command_download.cc +++ b/src/command_download.cc @@ -274,6 +274,40 @@ retrieve_d_custom_throw(core::Download* download, const std::string& key) { } } +torrent::Object +retrieve_d_custom_if_z(core::Download* download, const torrent::Object::list_type& args) { + torrent::Object::list_const_iterator itr = args.begin(); + if (itr == args.end()) + throw torrent::bencode_error("d.custom.if_z: Missing key argument."); + const std::string& key = (itr++)->as_string(); + if (key.empty()) + throw torrent::bencode_error("d.custom.if_z: Empty key argument."); + if (itr == args.end()) + throw torrent::bencode_error("d.custom.if_z: Missing default argument."); + + try { + return download->bencode()->get_key("rtorrent").get_key("custom").get_key_string(key); + } catch (torrent::bencode_error& e) { + return itr->as_string(); + } +} + +torrent::Object +retrieve_d_custom_map(core::Download* download, bool keys_only, const torrent::Object::list_type& args) { + if (args.begin() != args.end()) + throw torrent::bencode_error("d.custom.keys/items takes no arguments."); + + torrent::Object result = keys_only ? torrent::Object::create_list() : torrent::Object::create_map(); + torrent::Object::map_type& entries = download->bencode()->get_key("rtorrent").get_key("custom").as_map(); + + for (torrent::Object::map_type::const_iterator itr = entries.begin(), last = entries.end(); itr != last; itr++) { + if (keys_only) result.as_list().push_back(itr->first); + else result.as_map()[itr->first] = itr->second; + } + + return result; +} + torrent::Object retrieve_d_bitfield(core::Download* download) { const torrent::Bitfield* bitField = download->download()->file_list()->bitfield(); @@ -710,6 +744,9 @@ initialize_command_download() { CMD2_DL_STRING("d.custom", std::bind(&retrieve_d_custom, std::placeholders::_1, std::placeholders::_2)); CMD2_DL_STRING("d.custom_throw", std::bind(&retrieve_d_custom_throw, std::placeholders::_1, std::placeholders::_2)); CMD2_DL_LIST ("d.custom.set", std::bind(&apply_d_custom, std::placeholders::_1, std::placeholders::_2)); + CMD2_DL_LIST ("d.custom.if_z", std::bind(&retrieve_d_custom_if_z, std::placeholders::_1, std::placeholders::_2)); + CMD2_DL_LIST ("d.custom.keys", std::bind(&retrieve_d_custom_map, std::placeholders::_1, true, std::placeholders::_2)); + CMD2_DL_LIST ("d.custom.items", std::bind(&retrieve_d_custom_map, std::placeholders::_1, false, std::placeholders::_2)); CMD2_DL_VAR_STRING_PUBLIC("d.custom1", "rtorrent", "custom1"); CMD2_DL_VAR_STRING_PUBLIC("d.custom2", "rtorrent", "custom2"); From f37fefcc5431a325ac9c37954ec7d8a06ff9a7c1 Mon Sep 17 00:00:00 2001 From: pyroscope Date: Fri, 15 Jun 2018 18:36:01 +0200 Subject: [PATCH 60/65] add 'event.view.hide/show' commands / events --- src/main.cc | 3 +++ src/ui/element_download_list.cc | 7 +++++++ 2 files changed, 10 insertions(+) diff --git a/src/main.cc b/src/main.cc index 369f8d6da..38bb1886d 100644 --- a/src/main.cc +++ b/src/main.cc @@ -249,6 +249,9 @@ main(int argc, char** argv) { rpc::parse_command_multiple (rpc::make_target(), + "method.insert = event.view.hide,multi|rlookup|static\n" + "method.insert = event.view.show,multi|rlookup|static\n" + "method.insert = event.download.inserted,multi|rlookup|static\n" "method.insert = event.download.inserted_new,multi|rlookup|static\n" "method.insert = event.download.inserted_session,multi|rlookup|static\n" diff --git a/src/ui/element_download_list.cc b/src/ui/element_download_list.cc index 3f34bb90b..90a769ab3 100644 --- a/src/ui/element_download_list.cc +++ b/src/ui/element_download_list.cc @@ -220,7 +220,14 @@ ElementDownloadList::receive_change_view(const std::string& name) { return; } + std::string old_name = view() ? view()->name() : ""; + if (!old_name.empty()) + rpc::commands.call_catch("event.view.hide", rpc::make_target(), name, + "View hide event action failed: "); set_view(*itr); + if (!old_name.empty()) + rpc::commands.call_catch("event.view.show", rpc::make_target(), old_name, + "View show event action failed: "); } void From 3d88ac2cc89ad203eb9ea75e4933d36bbda4d04d Mon Sep 17 00:00:00 2001 From: pyroscope Date: Fri, 15 Jun 2018 19:37:57 +0200 Subject: [PATCH 61/65] fix: properly close the XMLRPC log, resetting the handle after close --- src/thread_worker.cc | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/thread_worker.cc b/src/thread_worker.cc index d6fa2f610..939d70265 100644 --- a/src/thread_worker.cc +++ b/src/thread_worker.cc @@ -113,14 +113,15 @@ ThreadWorker::change_xmlrpc_log() { if (scgi() == NULL) return; - if (scgi()->log_fd() != -1) + if (scgi()->log_fd() != -1) { ::close(scgi()->log_fd()); - - if (m_xmlrpcLog.empty()) { + scgi()->set_log_fd(-1); control->core()->push_log("Closed XMLRPC log."); - return; } + if (m_xmlrpcLog.empty()) + return; + scgi()->set_log_fd(open(rak::path_expand(m_xmlrpcLog).c_str(), O_WRONLY | O_APPEND | O_CREAT, 0644)); if (scgi()->log_fd() == -1) { From 2ac65ad7e132c2183c5c46e02648908c0df908e3 Mon Sep 17 00:00:00 2001 From: pyroscope Date: Sat, 16 Jun 2018 06:54:39 +0200 Subject: [PATCH 62/65] add 'value' command / conversion op --- src/command_ui.cc | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/command_ui.cc b/src/command_ui.cc index c98f94274..573d5a9d5 100644 --- a/src/command_ui.cc +++ b/src/command_ui.cc @@ -148,6 +148,30 @@ apply_cat(rpc::target_type target, const torrent::Object& rawArgs) { return result; } +torrent::Object +apply_value(rpc::target_type target, const torrent::Object::list_type& args) { + if (args.size() < 1) + throw torrent::input_error("'value' takes at least a number argument!"); + if (args.size() > 2) + throw torrent::input_error("'value' takes at most two arguments!"); + + torrent::Object::value_type val = 0; + if (args.front().is_value()) { + val = args.front().as_value(); + } else { + int base = args.size() > 1 ? args.back().is_value() ? + args.back().as_value() : strtol(args.back().as_string().c_str(), NULL, 10) : 10; + char* endptr = 0; + + val = strtoll(args.front().as_string().c_str(), &endptr, base); + while (*endptr == ' ' || *endptr == '\n') ++endptr; + if (*endptr) + throw torrent::input_error("Junk at end of number: " + args.front().as_string()); + } + + return val; +} + // Move these boolean operators to a new file. inline bool @@ -684,6 +708,7 @@ initialize_command_ui() { // Move. CMD2_ANY("print", &apply_print); CMD2_ANY("cat", &apply_cat); + CMD2_ANY_LIST("value", &apply_value); CMD2_ANY("if", std::bind(&apply_if, std::placeholders::_1, std::placeholders::_2, 0)); CMD2_ANY("not", &apply_not); CMD2_ANY("false", &apply_false); From d9b39f5ac694c131401dcaff9996063fa01c011b Mon Sep 17 00:00:00 2001 From: pyroscope Date: Mon, 18 Jun 2018 19:41:53 +0200 Subject: [PATCH 63/65] d.custom.if_z: return default also for existing but empty value --- src/command_download.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/command_download.cc b/src/command_download.cc index a31d68570..70ec427aa 100644 --- a/src/command_download.cc +++ b/src/command_download.cc @@ -286,7 +286,8 @@ retrieve_d_custom_if_z(core::Download* download, const torrent::Object::list_typ throw torrent::bencode_error("d.custom.if_z: Missing default argument."); try { - return download->bencode()->get_key("rtorrent").get_key("custom").get_key_string(key); + const std::string& val = download->bencode()->get_key("rtorrent").get_key("custom").get_key_string(key); + return val.empty() ? itr->as_string() : val; } catch (torrent::bencode_error& e) { return itr->as_string(); } From f0207ce6548026853ec57ab26f2e57a872f223bb Mon Sep 17 00:00:00 2001 From: rakshasa Date: Sat, 23 Jun 2018 17:01:34 +0900 Subject: [PATCH 64/65] Added "try" command that catches input_errors and logs them on rpc_events. --- src/command_network.cc | 6 ++---- src/command_ui.cc | 13 +++++++++++++ 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/command_network.cc b/src/command_network.cc index 3594c3023..092287a5b 100644 --- a/src/command_network.cc +++ b/src/command_network.cc @@ -167,8 +167,7 @@ apply_scgi(const std::string& arg, int type) { sa.sa_inet()->clear(); saPtr = &sa; - lt_log_print(torrent::LOG_RPC_EVENTS, - "The SCGI socket has not been bound to any address and likely poses a security risk."); + lt_log_print(torrent::LOG_RPC_EVENTS, "SCGI socket is open to any address and is a security risk"); } else if (std::sscanf(arg.c_str(), "%1023[^:]:%i%c", address, &port, &dummy) == 2 || std::sscanf(arg.c_str(), "[%64[^]]]:%i%c", address, &port, &dummy) == 2) { // [xx::xx]:port format @@ -177,8 +176,7 @@ apply_scgi(const std::string& arg, int type) { saPtr = ai->address(); - lt_log_print(torrent::LOG_RPC_EVENTS, - "The SCGI socket is bound to a specific network device yet may still pose a security risk, consider using 'scgi_local'."); + lt_log_print(torrent::LOG_RPC_EVENTS, "SCGI socket is bound to an address and might be a security risk"); } else { throw torrent::input_error("Could not parse address."); diff --git a/src/command_ui.cc b/src/command_ui.cc index fa331565a..17658f7a2 100644 --- a/src/command_ui.cc +++ b/src/command_ui.cc @@ -42,6 +42,7 @@ #include #include #include +#include #include "core/manager.h" #include "core/view_manager.h" @@ -172,6 +173,17 @@ apply_value(rpc::target_type target, const torrent::Object::list_type& args) { return val; } +torrent::Object +apply_try(rpc::target_type target, const torrent::Object& args) { + try { + return rpc::call_object(args, target); + } catch (torrent::input_error& e) { + lt_log_print(torrent::LOG_RPC_EVENTS, "try command caught input_error: %s", e.what()); + } + + return torrent::Object(); +} + // Move these boolean operators to a new file. inline bool @@ -713,6 +725,7 @@ initialize_command_ui() { CMD2_ANY("print", &apply_print); CMD2_ANY("cat", &apply_cat); CMD2_ANY_LIST("value", &apply_value); + CMD2_ANY("try", &apply_try); CMD2_ANY("if", std::bind(&apply_if, std::placeholders::_1, std::placeholders::_2, 0)); CMD2_ANY("not", &apply_not); CMD2_ANY("false", &apply_false); From f84670dd6394729158569a7a5366a00a7d1dccb2 Mon Sep 17 00:00:00 2001 From: Stephen Shkardoon Date: Mon, 25 Jun 2018 20:14:43 +1200 Subject: [PATCH 65/65] Use AC_COMPILE instead of AC_RUN to check for execinfo.h This way enables cross compiling, since we don't need to run anything during the configure script. --- scripts/common.m4 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/common.m4 b/scripts/common.m4 index 9885b037f..b1b815b1f 100644 --- a/scripts/common.m4 +++ b/scripts/common.m4 @@ -153,7 +153,7 @@ dnl Need to fix this so that it uses the stuff defined by the system. AC_DEFUN([TORRENT_CHECK_EXECINFO], [ AC_MSG_CHECKING(for execinfo.h) - AC_RUN_IFELSE([AC_LANG_SOURCE([ + AC_COMPILE_IFELSE([AC_LANG_SOURCE([ #include int main() { backtrace((void**)0, 0); backtrace_symbols((char**)0, 0); return 0;} ])],