diff --git a/ChangeLog b/ChangeLog index f20a5dd7d..3e6ef4cd6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,4 @@ + * fixed bug caused when binding outgoing connections to a non-local interface. * add_torrent() will now throw if called while the session object is being closed. * added the ability to limit the number of simultaneous half-open diff --git a/examples/client_test.cpp b/examples/client_test.cpp index 5d287ffe9..1e3d180d8 100755 --- a/examples/client_test.cpp +++ b/examples/client_test.cpp @@ -420,6 +420,7 @@ int main(int ac, char* av[]) std::string ip_filter_file; std::string allocation_mode; std::string in_monitor_dir; + std::string bind_to_interface; int poll_interval; namespace po = boost::program_options; @@ -461,6 +462,9 @@ int main(int ac, char* av[]) "in seconds) between two refreshes of the directory listing") ("half-open-limit,a", po::value(&half_open_limit)->default_value(-1) , "Sets the maximum number of simultaneous half-open tcp connections") + ("bind,b", po::value(&bind_to_interface)->default_value("") + , "Sets the local interface to bind outbound and the listen " + "socket to") ; po::positional_options_description p; @@ -519,7 +523,8 @@ int main(int ac, char* av[]) ses.set_max_half_open_connections(half_open_limit); ses.set_download_rate_limit(download_limit); ses.set_upload_rate_limit(upload_limit); - ses.listen_on(std::make_pair(listen_port, listen_port + 10)); + ses.listen_on(std::make_pair(listen_port, listen_port + 10) + , bind_to_interface.c_str()); ses.set_http_settings(settings); if (log_level == "debug") ses.set_severity_level(alert::debug); diff --git a/include/libtorrent/session.hpp b/include/libtorrent/session.hpp index 7af375f96..8676e18e1 100755 --- a/include/libtorrent/session.hpp +++ b/include/libtorrent/session.hpp @@ -201,6 +201,15 @@ namespace libtorrent // is reached. void process_connection_queue(); + void connection_failed(boost::shared_ptr const& s + , address const& a, char const* message); + + // this is where all active sockets are stored. + // the selector can sleep while there's no activity on + // them + selector m_selector; + + // this maps sockets to their peer_connection // object. It is the complete list of all connected // peers. @@ -243,11 +252,6 @@ namespace libtorrent // interface to listen on address m_listen_interface; - // this is where all active sockets are stored. - // the selector can sleep while there's no activity on - // them - selector m_selector; - boost::shared_ptr m_listen_socket; // the entries in this array maps the diff --git a/src/peer_connection.cpp b/src/peer_connection.cpp index cabc29b58..98072c29a 100755 --- a/src/peer_connection.cpp +++ b/src/peer_connection.cpp @@ -1180,6 +1180,7 @@ namespace libtorrent const char* ptr = &m_recv_buffer[1]; int listen_port = detail::read_uint16(ptr); + (void)listen_port; #ifdef TORRENT_VERBOSE_LOGGING using namespace boost::posix_time; diff --git a/src/policy.cpp b/src/policy.cpp index f4771ef38..383ddbe83 100755 --- a/src/policy.cpp +++ b/src/policy.cpp @@ -1169,6 +1169,7 @@ namespace libtorrent bool policy::connect_peer(peer *p) { + INVARIANT_CHECK; try { assert(!p->connection); diff --git a/src/session.cpp b/src/session.cpp index 583700acf..e9dd16276 100755 --- a/src/session.cpp +++ b/src/session.cpp @@ -560,6 +560,69 @@ namespace libtorrent { namespace detail } } + void session_impl::connection_failed(boost::shared_ptr const& s + , address const& a, char const* message) + { + connection_map::iterator p = m_connections.find(s); + + // the connection may have been disconnected in the receive or send phase + if (p != m_connections.end()) + { + if (m_alerts.should_post(alert::debug)) + { + m_alerts.post_alert( + peer_error_alert( + a + , p->second->id() + , message)); + } + +#if defined(TORRENT_VERBOSE_LOGGING) + (*p->second->m_logger) << "*** CONNECTION EXCEPTION\n"; +#endif + p->second->set_failed(); + m_connections.erase(p); + } + else if (s == m_listen_socket) + { + if (m_alerts.should_post(alert::fatal)) + { + std::string msg = "cannot listen on the given interface '" + m_listen_interface.as_string() + "'"; + m_alerts.post_alert(listen_failed_alert(msg)); + } +#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) + std::string msg = "cannot listen on the given interface '" + m_listen_interface.as_string() + "'"; + (*m_logger) << msg << "\n"; +#endif + assert(m_listen_socket.unique()); + m_listen_socket.reset(); + } + else + { + // the error was not in one of the connected + // conenctions. Look among the half-open ones. + p = m_half_open.find(s); + if (p != m_half_open.end()) + { + if (m_alerts.should_post(alert::debug)) + { + m_alerts.post_alert( + peer_error_alert( + a + , p->second->id() + , message)); + } +#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) + (*m_logger) << "FAILED: " << a.as_string() << "\n"; +#endif + p->second->set_failed(); + m_half_open.erase(p); + process_connection_queue(); + } + } + } + + void session_impl::operator()() { eh_initializer(); @@ -834,63 +897,7 @@ namespace libtorrent { namespace detail for (std::vector >::iterator i = error_clients.begin(); i != error_clients.end(); ++i) { - connection_map::iterator p = m_connections.find(*i); - - // the connection may have been disconnected in the receive or send phase - if (p != m_connections.end()) - { - if (m_alerts.should_post(alert::debug)) - { - m_alerts.post_alert( - peer_error_alert( - p->first->sender() - , p->second->id() - , "connection closed")); - } - -#if defined(TORRENT_VERBOSE_LOGGING) - (*p->second->m_logger) << "*** CONNECTION EXCEPTION\n"; -#endif - p->second->set_failed(); - m_connections.erase(p); - } - else if (*i == m_listen_socket) - { - if (m_alerts.should_post(alert::fatal)) - { - std::string msg = "cannot listen on the given interface '" + m_listen_interface.as_string() + "'"; - m_alerts.post_alert(listen_failed_alert(msg)); - } -#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) - std::string msg = "cannot listen on the given interface '" + m_listen_interface.as_string() + "'"; - (*m_logger) << msg << "\n"; -#endif - assert(m_listen_socket.unique()); - m_listen_socket.reset(); - } - else - { - // the error was not in one of the connected - // conenctions. Look among the half-open ones. - p = m_half_open.find(*i); - if (p != m_half_open.end()) - { - if (m_alerts.should_post(alert::debug)) - { - m_alerts.post_alert( - peer_error_alert( - p->first->sender() - , p->second->id() - , "connection attempt failed")); - } -#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) - (*m_logger) << "FAILED: " << (*i)->sender().as_string() << "\n"; -#endif - p->second->set_failed(); - m_half_open.erase(p); - process_connection_queue(); - } - } + connection_failed(*i, (*i)->sender(), "connection exception"); } #ifndef NDEBUG diff --git a/src/torrent.cpp b/src/torrent.cpp index 896b4b45f..c70dca163 100755 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -864,7 +864,7 @@ namespace libtorrent assert(p != 0); peer_iterator i = m_connections.find(p->remote()); - assert(i != m_connections.end()); + if (i == m_connections.end()) return; if (ready_for_connections()) { @@ -920,16 +920,27 @@ namespace libtorrent m_policy->check_invariant(); #endif - // add the newly connected peer to this torrent's peer list - m_connections.insert( - std::make_pair(a, boost::get_pointer(c))); + try + { + // add the newly connected peer to this torrent's peer list + m_connections.insert( + std::make_pair(a, boost::get_pointer(c))); #ifndef NDEBUG - m_policy->check_invariant(); + m_policy->check_invariant(); #endif - m_ses.m_selector.monitor_errors(s); - m_ses.process_connection_queue(); + m_ses.m_selector.monitor_errors(s); + m_ses.process_connection_queue(); + } + catch (std::exception& e) + { + // TODO: post an error alert! + std::map::iterator i = m_connections.find(a); + if (i != m_connections.end()) m_connections.erase(i); + m_ses.connection_failed(s, a, e.what()); + throw; + } return *c; }