diff --git a/docs/manual.rst b/docs/manual.rst index 1bb806118..6027ae2ff 100644 --- a/docs/manual.rst +++ b/docs/manual.rst @@ -3856,6 +3856,7 @@ session_settings int default_peer_upload_rate; int default_peer_download_rate; + bool broadcast_lsd; }; ``user_agent`` this is the client identification to the tracker. @@ -4467,6 +4468,11 @@ set on new peer connections (not existing ones). The peer rate limits can be changed individually later using `set_peer_upload_limit() set_peer_download_limit()`_. +if ``broadcast_lsd`` is set to true, the local peer discovery +(or Local Service Discovery) will not only use IP multicast, but also +broadcast its messages. This can be useful when running on networks +that don't support multicast. It's off by default since it's inefficient. + pe_settings =========== diff --git a/include/libtorrent/broadcast_socket.hpp b/include/libtorrent/broadcast_socket.hpp index e13669d1f..040e4d2b6 100644 --- a/include/libtorrent/broadcast_socket.hpp +++ b/include/libtorrent/broadcast_socket.hpp @@ -72,26 +72,37 @@ namespace libtorrent void send(char const* buffer, int size, error_code& ec); void close(); int num_send_sockets() const { return m_unicast_sockets.size(); } + void enable_ip_broadcast(bool e); private: struct socket_entry { - socket_entry(boost::shared_ptr const& s): socket(s) {} + socket_entry(boost::shared_ptr const& s) + : socket(s) {} + socket_entry(boost::shared_ptr const& s + , address_v4 const& mask): socket(s), netmask(mask) {} boost::shared_ptr socket; char buffer[1024]; udp::endpoint remote; + address_v4 netmask; void close() { if (!socket) return; error_code ec; socket->close(ec); } + address_v4 broadcast_address() const + { + error_code ec; + return address_v4::broadcast(socket->local_endpoint(ec).address().to_v4(), netmask); + } }; void on_receive(socket_entry* s, error_code const& ec , std::size_t bytes_transferred); - void open_unicast_socket(io_service& ios, address const& addr); + void open_unicast_socket(io_service& ios, address const& addr + , address_v4 const& mask); void open_multicast_socket(io_service& ios, address const& addr , bool loopback, error_code& ec); @@ -106,6 +117,11 @@ namespace libtorrent std::list m_unicast_sockets; udp::endpoint m_multicast_endpoint; receive_handler_t m_on_receive; + + // if set, use IP broadcast as well as IP multicast + // this is off by default because it's expensive in + // terms of bandwidth usage + bool m_ip_broadcast; }; } diff --git a/include/libtorrent/lsd.hpp b/include/libtorrent/lsd.hpp index 037bab675..72c4fcca4 100644 --- a/include/libtorrent/lsd.hpp +++ b/include/libtorrent/lsd.hpp @@ -64,6 +64,8 @@ public: void announce(sha1_hash const& ih, int listen_port); void close(); + void use_broadcast(bool b); + private: void resend_announce(error_code const& e, std::string msg); diff --git a/include/libtorrent/session_settings.hpp b/include/libtorrent/session_settings.hpp index 43cc70c28..6b0483b33 100644 --- a/include/libtorrent/session_settings.hpp +++ b/include/libtorrent/session_settings.hpp @@ -207,6 +207,7 @@ namespace libtorrent , strict_end_game_mode(true) , default_peer_upload_rate(0) , default_peer_download_rate(0) + , broadcast_lsd(false) {} // this is the user agent that will be sent to the tracker @@ -791,6 +792,12 @@ namespace libtorrent // each peer will have these limits set on it int default_peer_upload_rate; int default_peer_download_rate; + + // if this is true, the broadcast socket will not only use IP multicast + // but also send the messages on the broadcast address. This is false by + // default in order to avoid flooding networks for no good reason. If + // a network is known not to support multicast, this can be enabled + bool broadcast_lsd; }; #ifndef TORRENT_DISABLE_DHT diff --git a/src/broadcast_socket.cpp b/src/broadcast_socket.cpp index c7696f57c..e075a81ef 100644 --- a/src/broadcast_socket.cpp +++ b/src/broadcast_socket.cpp @@ -187,6 +187,7 @@ namespace libtorrent , bool loopback) : m_multicast_endpoint(multicast_endpoint) , m_on_receive(handler) + , m_ip_broadcast(false) { TORRENT_ASSERT(is_multicast(m_multicast_endpoint.address())); @@ -218,7 +219,22 @@ namespace libtorrent // , print_address(multicast_endpoint.address()).c_str() // , ec.message().c_str()); #endif - open_unicast_socket(ios, i->interface_address); + open_unicast_socket(ios, i->interface_address + , i->netmask.is_v4() ? i->netmask.to_v4() : address_v4()); + } + } + + void broadcast_socket::enable_ip_broadcast(bool e) + { + if (e == m_ip_broadcast) return; + m_ip_broadcast = e; + + asio::socket_base::broadcast option(m_ip_broadcast); + for (std::list::iterator i = m_unicast_sockets.begin() + , end(m_unicast_sockets.end()); i != end; ++i) + { + if (i->socket) continue; + i->socket->set_option(option); } } @@ -246,7 +262,8 @@ namespace libtorrent , se.remote, bind(&broadcast_socket::on_receive, this, &se, _1, _2)); } - void broadcast_socket::open_unicast_socket(io_service& ios, address const& addr) + void broadcast_socket::open_unicast_socket(io_service& ios, address const& addr + , address_v4 const& mask) { using namespace asio::ip::multicast; error_code ec; @@ -255,7 +272,7 @@ namespace libtorrent if (ec) return; s->bind(udp::endpoint(addr, 0), ec); if (ec) return; - m_unicast_sockets.push_back(socket_entry(s)); + m_unicast_sockets.push_back(socket_entry(s, mask)); socket_entry& se = m_unicast_sockets.back(); s->async_receive_from(asio::buffer(se.buffer, sizeof(se.buffer)) , se.remote, bind(&broadcast_socket::on_receive, this, &se, _1, _2)); @@ -289,6 +306,9 @@ namespace libtorrent if (!i->socket) continue; error_code e; i->socket->send_to(asio::buffer(buffer, size), m_multicast_endpoint, 0, e); + if (m_ip_broadcast && i->socket->local_endpoint(e).address().is_v4()) + i->socket->send_to(asio::buffer(buffer, size) + , udp::endpoint(i->broadcast_address(), m_multicast_endpoint.port()), 0, e); #ifndef NDEBUG // extern std::string print_address(address const& addr); // extern std::string print_endpoint(udp::endpoint const& ep); diff --git a/src/lsd.cpp b/src/lsd.cpp index 8949fd0e1..edae36293 100644 --- a/src/lsd.cpp +++ b/src/lsd.cpp @@ -213,3 +213,8 @@ void lsd::close() m_callback.clear(); } +void lsd::use_broadcast(bool b) +{ + m_socket.enable_ip_broadcast(b); +} + diff --git a/src/session_impl.cpp b/src/session_impl.cpp index 45f37ca7e..9d72513fc 100644 --- a/src/session_impl.cpp +++ b/src/session_impl.cpp @@ -806,6 +806,12 @@ namespace aux { } } #endif + + if (m_settings.connection_speed < 0) m_settings.connection_speed = 200; + + if (m_settings.broadcast_lsd && m_lsd) + m_lsd->use_broadcast(true); + update_disk_thread_settings(); } @@ -1164,6 +1170,8 @@ namespace aux { m_auto_manage_time_scaler = 2; m_settings = s; if (m_settings.connection_speed < 0) m_settings.connection_speed = 200; + if (m_settings.broadcast_lsd && m_lsd) + m_lsd->use_broadcast(true); if (update_disk_io_thread) update_disk_thread_settings(); @@ -3630,6 +3638,8 @@ namespace aux { m_lsd = new lsd(m_io_service , m_listen_interface.address() , bind(&session_impl::on_lsd_peer, this, _1, _2)); + if (m_settings.broadcast_lsd) + m_lsd->use_broadcast(true); } void session_impl::start_natpmp(natpmp* n)