From 92f4947bbe3f9459a1a9297595d493f9a2f655da Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Tue, 5 Feb 2008 06:32:10 +0000 Subject: [PATCH] full proxy support for udp-trackers, and more reliable udp tracker code --- .../libtorrent/http_tracker_connection.hpp | 4 - include/libtorrent/udp_socket.hpp | 5 +- include/libtorrent/udp_tracker_connection.hpp | 24 +- src/http_tracker_connection.cpp | 4 - src/kademlia/dht_tracker.cpp | 2 +- src/tracker_manager.cpp | 37 +- src/udp_socket.cpp | 34 +- src/udp_tracker_connection.cpp | 472 +++++++----------- 8 files changed, 240 insertions(+), 342 deletions(-) diff --git a/include/libtorrent/http_tracker_connection.hpp b/include/libtorrent/http_tracker_connection.hpp index 13a205d33..fb0999d97 100755 --- a/include/libtorrent/http_tracker_connection.hpp +++ b/include/libtorrent/http_tracker_connection.hpp @@ -69,10 +69,6 @@ namespace libtorrent , connection_queue& cc , tracker_manager& man , tracker_request const& req - , std::string const& protocol - , std::string const& hostname - , unsigned short port - , std::string request , address bind_infc , boost::weak_ptr c , session_settings const& stn diff --git a/include/libtorrent/udp_socket.hpp b/include/libtorrent/udp_socket.hpp index 2fd3143d1..33952b722 100644 --- a/include/libtorrent/udp_socket.hpp +++ b/include/libtorrent/udp_socket.hpp @@ -53,7 +53,8 @@ namespace libtorrent bool is_open() const { return m_ipv4_sock.is_open() || m_ipv6_sock.is_open(); } asio::io_service& get_io_service() { return m_ipv4_sock.get_io_service(); } - void send(udp::endpoint const& ep, char const* p, int len); + void send(udp::endpoint const& ep, char const* p, int len, asio::error_code& ec); + void bind(udp::endpoint const& ep, asio::error_code& ec); void bind(int port); void close(); int local_port() const { return m_bind_port; } @@ -78,7 +79,7 @@ namespace libtorrent void connect1(asio::error_code const& e); void connect2(asio::error_code const& e); - void wrap(udp::endpoint const& ep, char const* p, int len); + void wrap(udp::endpoint const& ep, char const* p, int len, asio::error_code& ec); void unwrap(char const* buf, int size); udp::socket m_ipv4_sock; diff --git a/include/libtorrent/udp_tracker_connection.hpp b/include/libtorrent/udp_tracker_connection.hpp index b3d6abef1..3a2c75b32 100755 --- a/include/libtorrent/udp_tracker_connection.hpp +++ b/include/libtorrent/udp_tracker_connection.hpp @@ -49,7 +49,7 @@ POSSIBILITY OF SUCH DAMAGE. #pragma warning(pop) #endif -#include "libtorrent/socket.hpp" +#include "libtorrent/udp_socket.hpp" #include "libtorrent/entry.hpp" #include "libtorrent/session_settings.hpp" #include "libtorrent/peer_id.hpp" @@ -66,13 +66,13 @@ namespace libtorrent udp_tracker_connection( io_service& ios + , connection_queue& cc , tracker_manager& man , tracker_request const& req - , std::string const& hostname - , unsigned short port , address bind_infc , boost::weak_ptr c - , session_settings const& stn); + , session_settings const& stn + , proxy_settings const& ps); void close(); @@ -92,29 +92,29 @@ namespace libtorrent void name_lookup(asio::error_code const& error, udp::resolver::iterator i); void timeout(asio::error_code const& error); + void on_receive(udp::endpoint const& ep, char const* buf, int size); + void on_connect_response(char const* buf, int size); + void on_announce_response(char const* buf, int size); + void on_scrape_response(char const* buf, int size); + void send_udp_connect(); - void connect_response(asio::error_code const& error, std::size_t bytes_transferred); - void send_udp_announce(); - void announce_response(asio::error_code const& error, std::size_t bytes_transferred); - void send_udp_scrape(); - void scrape_response(asio::error_code const& error, std::size_t bytes_transferred); virtual void on_timeout(); tracker_manager& m_man; udp::resolver m_name_lookup; - datagram_socket m_socket; + udp_socket m_socket; udp::endpoint m_target; - udp::endpoint m_sender; int m_transaction_id; boost::int64_t m_connection_id; session_settings const& m_settings; int m_attempts; - std::vector m_buffer; + + action_t m_state; }; } diff --git a/src/http_tracker_connection.cpp b/src/http_tracker_connection.cpp index 3213a8131..5f05e7d89 100755 --- a/src/http_tracker_connection.cpp +++ b/src/http_tracker_connection.cpp @@ -71,10 +71,6 @@ namespace libtorrent , connection_queue& cc , tracker_manager& man , tracker_request const& req - , std::string const& protocol - , std::string const& hostname - , unsigned short port - , std::string request , address bind_infc , boost::weak_ptr c , session_settings const& stn diff --git a/src/kademlia/dht_tracker.cpp b/src/kademlia/dht_tracker.cpp index b9d5d1cc1..d18fc1e7c 100644 --- a/src/kademlia/dht_tracker.cpp +++ b/src/kademlia/dht_tracker.cpp @@ -949,7 +949,7 @@ namespace libtorrent { namespace dht m_send_buf.clear(); bencode(std::back_inserter(m_send_buf), e); asio::error_code ec; - m_sock.send(m.addr, &m_send_buf[0], (int)m_send_buf.size()); + m_sock.send(m.addr, &m_send_buf[0], (int)m_send_buf.size(), ec); #ifdef TORRENT_DHT_VERBOSE_LOGGING m_total_out_bytes += m_send_buf.size(); diff --git a/src/tracker_manager.cpp b/src/tracker_manager.cpp index e72c55eb0..3a2b137da 100755 --- a/src/tracker_manager.cpp +++ b/src/tracker_manager.cpp @@ -274,15 +274,7 @@ exit: if (m_abort && req.event != tracker_request::stopped) return; - std::string protocol; - std::string hostname; - int port; - std::string request_string; - - using boost::tuples::ignore; - // TODO: should auth be used here? - boost::tie(protocol, ignore, hostname, port, request_string) - = parse_url_components(req.url); + std::string protocol = req.url.substr(0, req.url.find(':')); boost::intrusive_ptr con; @@ -293,37 +285,20 @@ exit: #endif { con = new http_tracker_connection( - ios - , cc - , *this - , req - , protocol - , hostname - , port - , request_string - , bind_infc - , c - , m_settings - , m_proxy - , auth); + ios, cc, *this, req, bind_infc, c + , m_settings, m_proxy, auth); } else if (protocol == "udp") { con = new udp_tracker_connection( - ios - , *this - , req - , hostname - , port - , bind_infc - , c - , m_settings); + ios, cc, *this, req, bind_infc + , c, m_settings, m_proxy); } else { if (boost::shared_ptr r = c.lock()) r->tracker_request_error(req, -1, "unknown protocol in tracker url: " - + protocol); + + req.url); return; } diff --git a/src/udp_socket.cpp b/src/udp_socket.cpp index f398455d9..d31513166 100644 --- a/src/udp_socket.cpp +++ b/src/udp_socket.cpp @@ -22,16 +22,15 @@ udp_socket::udp_socket(asio::io_service& ios, udp_socket::callback_t const& c { } -void udp_socket::send(udp::endpoint const& ep, char const* p, int len) +void udp_socket::send(udp::endpoint const& ep, char const* p, int len, asio::error_code& ec) { if (m_tunnel_packets) { // send udp packets through SOCKS5 server - wrap(ep, p, len); + wrap(ep, p, len, ec); return; } - asio::error_code ec; if (ep.address().is_v4() && m_ipv4_sock.is_open()) m_ipv4_sock.send_to(asio::buffer(p, len), ep, 0, ec); else @@ -79,7 +78,7 @@ void udp_socket::on_read(udp::socket* s, asio::error_code const& e, std::size_t } } -void udp_socket::wrap(udp::endpoint const& ep, char const* p, int len) +void udp_socket::wrap(udp::endpoint const& ep, char const* p, int len, asio::error_code& ec) { using namespace libtorrent::detail; @@ -96,7 +95,6 @@ void udp_socket::wrap(udp::endpoint const& ep, char const* p, int len) iovec[0] = asio::const_buffer(header, h - header); iovec[1] = asio::const_buffer(p, len); - asio::error_code ec; if (m_proxy_addr.address().is_v4() && m_ipv4_sock.is_open()) m_ipv4_sock.send_to(iovec, m_proxy_addr, 0, ec); else @@ -155,6 +153,32 @@ void udp_socket::close() } } +void udp_socket::bind(udp::endpoint const& ep, asio::error_code& ec) +{ + if (m_ipv4_sock.is_open()) m_ipv4_sock.close(ec); + if (m_ipv6_sock.is_open()) m_ipv6_sock.close(ec); + + if (ep.address().is_v4()) + { + m_ipv4_sock.open(udp::v4(), ec); + if (ec) return; + m_ipv4_sock.bind(ep, ec); + if (ec) return; + m_ipv4_sock.async_receive_from(asio::buffer(m_v4_buf, sizeof(m_v4_buf)) + , m_v4_ep, boost::bind(&udp_socket::on_read, this, &m_ipv4_sock, _1, _2)); + } + else + { + m_ipv6_sock.set_option(v6only(true), ec); + if (ec) return; + m_ipv6_sock.bind(ep, ec); + if (ec) return; + m_ipv6_sock.async_receive_from(asio::buffer(m_v6_buf, sizeof(m_v6_buf)) + , m_v6_ep, boost::bind(&udp_socket::on_read, this, &m_ipv6_sock, _1, _2)); + } + m_bind_port = ep.port(); +} + void udp_socket::bind(int port) { asio::error_code ec; diff --git a/src/udp_tracker_connection.cpp b/src/udp_tracker_connection.cpp index 9338d3e44..214b57d4f 100755 --- a/src/udp_tracker_connection.cpp +++ b/src/udp_tracker_connection.cpp @@ -62,8 +62,7 @@ namespace udp_connection_retries = 4, udp_announce_retries = 15, udp_connect_timeout = 15, - udp_announce_timeout = 10, - udp_buffer_size = 2048 + udp_announce_timeout = 10 }; } @@ -75,22 +74,31 @@ namespace libtorrent udp_tracker_connection::udp_tracker_connection( io_service& ios + , connection_queue& cc , tracker_manager& man , tracker_request const& req - , std::string const& hostname - , unsigned short port , address bind_infc , boost::weak_ptr c - , session_settings const& stn) + , session_settings const& stn + , proxy_settings const& proxy) : tracker_connection(man, req, ios, bind_infc, c) , m_man(man) , m_name_lookup(ios) - , m_socket(ios) + , m_socket(ios, boost::bind(&udp_tracker_connection::on_receive, this, _1, _2, _3), cc) , m_transaction_id(0) , m_connection_id(0) , m_settings(stn) , m_attempts(0) + , m_state(action_error) { + m_socket.set_proxy_settings(proxy); + + std::string hostname; + int port; + + using boost::tuples::ignore; + boost::tie(ignore, ignore, hostname, port, ignore) = parse_url_components(req.url); + udp::resolver::query q(hostname, boost::lexical_cast(port)); m_name_lookup.async_resolve(q , boost::bind( @@ -149,24 +157,12 @@ namespace libtorrent if (cb) cb->m_tracker_address = tcp::endpoint(target_address.address(), target_address.port()); m_target = target_address; asio::error_code ec; - m_socket.open(target_address.protocol(), ec); - if (ec) - { - fail(-1, ec.message().c_str()); - return; - } m_socket.bind(udp::endpoint(bind_interface(), 0), ec); if (ec) { fail(-1, ec.message().c_str()); return; } - m_socket.connect(target_address, ec); - if (ec) - { - fail(-1, ec.message().c_str()); - return; - } send_udp_connect(); } @@ -176,8 +172,7 @@ namespace libtorrent boost::shared_ptr cb = requester(); if (cb) cb->debug_log("*** UDP_TRACKER [ timed out ]"); #endif - asio::error_code ec; - m_socket.close(ec); + m_socket.close(); m_name_lookup.cancel(); fail_timeout(); } @@ -185,11 +180,104 @@ namespace libtorrent void udp_tracker_connection::close() { asio::error_code ec; - m_socket.close(ec); + m_socket.close(); m_name_lookup.cancel(); tracker_connection::close(); } + void udp_tracker_connection::on_receive(udp::endpoint const& ep, char const* buf, int size) + { + // ignore resposes before we've sent any requests + if (m_state == action_error) return; + + if (!m_socket.is_open()) return; // the operation was aborted + + // ignore packet not sent from the tracker + if (m_target != ep) return; + +#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) + boost::shared_ptr cb = requester(); + if (cb) + { + std::stringstream msg; + msg << "<== UDP_TRACKER_PACKET [ size: " << size << " ]"; + cb->debug_log(msg.str()); + } +#endif + + // ignore packets smaller than 8 bytes + if (size < 8) return; + + restart_read_timeout(); + + const char* ptr = buf; + int action = detail::read_int32(ptr); + int transaction = detail::read_int32(ptr); + +#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) + if (cb) + { + std::stringstream msg; + msg << "*** UDP_TRACKER_PACKET [ acton: " << action << " ]"; + cb->debug_log(msg.str()); + } +#endif + + // ignore packets with incorrect transaction id + if (m_transaction_id != transaction) return; + + if (action == action_error) + { + fail(-1, std::string(ptr, size - 8).c_str()); + return; + } + + // ignore packets that's not a response to our message + if (action != m_state) return; + +#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) + if (cb) + { + std::stringstream msg; + msg << "*** UDP_TRACKER_RESPONSE [ cid: " << m_connection_id << " ]"; + cb->debug_log(msg.str()); + } +#endif + + switch (m_state) + { + case action_connect: + on_connect_response(buf, size); + break; + case action_announce: + on_announce_response(buf, size); + break; + case action_scrape: + on_scrape_response(buf, size); + break; + default: break; + } + } + + void udp_tracker_connection::on_connect_response(char const* buf, int size) + { + // ignore packets smaller than 16 bytes + if (size < 16) return; + + restart_read_timeout(); + buf += 8; // skip header + + // reset transaction + m_transaction_id = 0; + m_attempts = 0; + m_connection_id = detail::read_int64(buf); + + if (tracker_req().kind == tracker_request::announce_request) + send_udp_announce(); + else if (tracker_req().kind == tracker_request::scrape_request) + send_udp_scrape(); + } + void udp_tracker_connection::send_udp_connect() { #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) @@ -202,179 +290,27 @@ namespace libtorrent #endif if (!m_socket.is_open()) return; // the operation was aborted - char send_buf[16]; - char* ptr = send_buf; + char buf[16]; + char* ptr = buf; if (m_transaction_id == 0) m_transaction_id = rand() ^ (rand() << 16); - // connection_id detail::write_uint32(0x417, ptr); - detail::write_uint32(0x27101980, ptr); - // action (connect) - detail::write_int32(action_connect, ptr); - // transaction_id - detail::write_int32(m_transaction_id, ptr); + detail::write_uint32(0x27101980, ptr); // connection_id + detail::write_int32(action_connect, ptr); // action (connect) + detail::write_int32(m_transaction_id, ptr); // transaction_id + TORRENT_ASSERT(ptr - buf == sizeof(buf)); asio::error_code ec; - m_socket.send(asio::buffer((void*)send_buf, 16), 0, ec); + m_socket.send(m_target, buf, 16, ec); + m_state = action_connect; ++m_attempts; if (ec) { fail(-1, ec.message().c_str()); return; } - m_buffer.resize(udp_buffer_size); - m_socket.async_receive_from(asio::buffer(m_buffer), m_sender - , boost::bind(&udp_tracker_connection::connect_response, self(), _1, _2)); - } - - void udp_tracker_connection::connect_response(asio::error_code const& error - , std::size_t bytes_transferred) - { - if (error == asio::error::operation_aborted) return; - if (!m_socket.is_open()) return; // the operation was aborted - if (error) - { - fail(-1, error.message().c_str()); - return; - } - - if (m_target != m_sender) - { - // this packet was not received from the tracker - m_socket.async_receive_from(asio::buffer(m_buffer), m_sender - , boost::bind(&udp_tracker_connection::connect_response, self(), _1, _2)); - return; - } - - if (bytes_transferred >= udp_buffer_size) - { - fail(-1, "udp response too big"); - return; - } - - if (bytes_transferred < 8) - { - fail(-1, "got a message with size < 8"); - return; - } - - restart_read_timeout(); - - const char* ptr = &m_buffer[0]; - int action = detail::read_int32(ptr); - int transaction = detail::read_int32(ptr); - - if (action == action_error) - { - fail(-1, std::string(ptr, bytes_transferred - 8).c_str()); - return; - } - - if (action != action_connect) - { - fail(-1, "invalid action in connect reply"); - return; - } - - if (m_transaction_id != transaction) - { - fail(-1, "incorrect transaction id"); - return; - } - - if (bytes_transferred < 16) - { - fail(-1, "udp_tracker_connection: " - "got a message with size < 16"); - return; - } - // reset transaction - m_transaction_id = 0; - m_attempts = 0; - m_connection_id = detail::read_int64(ptr); - -#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) - boost::shared_ptr cb = requester(); - if (cb) - { - std::stringstream msg; - msg << "<== UDP_TRACKER_CONNECT_RESPONSE [ cid: " << m_connection_id << " ]"; - cb->debug_log(msg.str()); - } -#endif - - if (tracker_req().kind == tracker_request::announce_request) - send_udp_announce(); - else if (tracker_req().kind == tracker_request::scrape_request) - send_udp_scrape(); - } - - void udp_tracker_connection::send_udp_announce() - { - if (m_transaction_id == 0) - m_transaction_id = rand() ^ (rand() << 16); - - if (!m_socket.is_open()) return; // the operation was aborted - - std::vector buf; - std::back_insert_iterator > out(buf); - - tracker_request const& req = tracker_req(); - - // connection_id - detail::write_int64(m_connection_id, out); - // action (announce) - detail::write_int32(action_announce, out); - // transaction_id - detail::write_int32(m_transaction_id, out); - // info_hash - std::copy(req.info_hash.begin(), req.info_hash.end(), out); - // peer_id - std::copy(req.pid.begin(), req.pid.end(), out); - // downloaded - detail::write_int64(req.downloaded, out); - // left - detail::write_int64(req.left, out); - // uploaded - detail::write_int64(req.uploaded, out); - // event - detail::write_int32(req.event, out); - // ip address - if (m_settings.announce_ip != address() && m_settings.announce_ip.is_v4()) - detail::write_uint32(m_settings.announce_ip.to_v4().to_ulong(), out); - else - detail::write_int32(0, out); - // key - detail::write_int32(req.key, out); - // num_want - detail::write_int32(req.num_want, out); - // port - detail::write_uint16(req.listen_port, out); - // extensions - detail::write_uint16(0, out); - -#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) - boost::shared_ptr cb = requester(); - if (cb) - { - cb->debug_log("==> UDP_TRACKER_ANNOUNCE [" - + lexical_cast(req.info_hash) + "]"); - } -#endif - - asio::error_code ec; - m_socket.send(asio::buffer(buf), 0, ec); - ++m_attempts; - if (ec) - { - fail(-1, ec.message().c_str()); - return; - } - - m_socket.async_receive_from(asio::buffer(m_buffer), m_sender - , bind(&udp_tracker_connection::announce_response, self(), _1, _2)); } void udp_tracker_connection::send_udp_scrape() @@ -384,96 +320,39 @@ namespace libtorrent if (!m_socket.is_open()) return; // the operation was aborted - std::vector buf; - std::back_insert_iterator > out(buf); + char buf[8 + 4 + 4 + 20]; + char* out = buf; - // connection_id - detail::write_int64(m_connection_id, out); - // action (scrape) - detail::write_int32(action_scrape, out); - // transaction_id - detail::write_int32(m_transaction_id, out); + detail::write_int64(m_connection_id, out); // connection_id + detail::write_int32(action_scrape, out); // action (scrape) + detail::write_int32(m_transaction_id, out); // transaction_id // info_hash std::copy(tracker_req().info_hash.begin(), tracker_req().info_hash.end(), out); asio::error_code ec; - m_socket.send(asio::buffer(&buf[0], buf.size()), 0, ec); + m_socket.send(m_target, buf, sizeof(buf), ec); + m_state = action_scrape; ++m_attempts; if (ec) { fail(-1, ec.message().c_str()); return; } - - m_socket.async_receive_from(asio::buffer(m_buffer), m_sender - , bind(&udp_tracker_connection::scrape_response, self(), _1, _2)); } - void udp_tracker_connection::announce_response(asio::error_code const& error - , std::size_t bytes_transferred) + void udp_tracker_connection::on_announce_response(char const* buf, int size) { - if (error == asio::error::operation_aborted) return; - if (!m_socket.is_open()) return; // the operation was aborted - if (error) - { - fail(-1, error.message().c_str()); - return; - } - - if (m_target != m_sender) - { - // this packet was not received from the tracker - m_socket.async_receive_from(asio::buffer(m_buffer), m_sender - , bind(&udp_tracker_connection::connect_response, self(), _1, _2)); - return; - } - - if (bytes_transferred >= udp_buffer_size) - { - fail(-1, "udp response too big"); - return; - } - - if (bytes_transferred < 8) - { - fail(-1, "got a message with size < 8"); - return; - } + if (size < 20) return; restart_read_timeout(); - char* buf = &m_buffer[0]; - int action = detail::read_int32(buf); - int transaction = detail::read_int32(buf); - - if (transaction != m_transaction_id) - { - fail(-1, "incorrect transaction id"); - return; - } - - if (action == action_error) - { - fail(-1, std::string(buf, bytes_transferred - 8).c_str()); - return; - } - - if (action != action_announce) - { - fail(-1, "invalid action in announce response"); - return; - } - - if (bytes_transferred < 20) - { - fail(-1, "got a message with size < 20"); - return; - } + buf += 8; // skip header + restart_read_timeout(); int interval = detail::read_int32(buf); int incomplete = detail::read_int32(buf); int complete = detail::read_int32(buf); - int num_peers = (bytes_transferred - 20) / 6; - if ((bytes_transferred - 20) % 6 != 0) + int num_peers = (size - 20) / 6; + if ((size - 20) % 6 != 0) { fail(-1, "invalid udp tracker response length"); return; @@ -496,6 +375,7 @@ namespace libtorrent std::vector peer_list; for (int i = 0; i < num_peers; ++i) { + // TODO: don't use a string here peer_entry e; std::stringstream s; s << (int)detail::read_uint8(buf) << "."; @@ -515,39 +395,11 @@ namespace libtorrent close(); } - void udp_tracker_connection::scrape_response(asio::error_code const& error - , std::size_t bytes_transferred) + void udp_tracker_connection::on_scrape_response(char const* buf, int size) { - if (error == asio::error::operation_aborted) return; - if (!m_socket.is_open()) return; // the operation was aborted - if (error) - { - fail(-1, error.message().c_str()); - return; - } - - if (m_target != m_sender) - { - // this packet was not received from the tracker - m_socket.async_receive_from(asio::buffer(m_buffer), m_sender - , bind(&udp_tracker_connection::connect_response, self(), _1, _2)); - return; - } - - if (bytes_transferred >= udp_buffer_size) - { - fail(-1, "udp response too big"); - return; - } - - if (bytes_transferred < 8) - { - fail(-1, "got a message with size < 8"); - return; - } + buf += 8; // skip header restart_read_timeout(); - char* buf = &m_buffer[0]; int action = detail::read_int32(buf); int transaction = detail::read_int32(buf); @@ -559,7 +411,7 @@ namespace libtorrent if (action == action_error) { - fail(-1, std::string(buf, bytes_transferred - 8).c_str()); + fail(-1, std::string(buf, size - 8).c_str()); return; } @@ -569,7 +421,7 @@ namespace libtorrent return; } - if (bytes_transferred < 20) + if (size < 20) { fail(-1, "got a message with size < 20"); return; @@ -592,5 +444,59 @@ namespace libtorrent m_man.remove_request(this); close(); } + + void udp_tracker_connection::send_udp_announce() + { + if (m_transaction_id == 0) + m_transaction_id = rand() ^ (rand() << 16); + + if (!m_socket.is_open()) return; // the operation was aborted + + char buf[8 + 4 + 4 + 20 + 20 + 8 + 8 + 8 + 4 + 4 + 4 + 4 + 2 + 2]; + char* out = buf; + + tracker_request const& req = tracker_req(); + + detail::write_int64(m_connection_id, out); // connection_id + detail::write_int32(action_announce, out); // action (announce) + detail::write_int32(m_transaction_id, out); // transaction_id + std::copy(req.info_hash.begin(), req.info_hash.end(), out); // info_hash + std::copy(req.pid.begin(), req.pid.end(), out); // peer_id + detail::write_int64(req.downloaded, out); // downloaded + detail::write_int64(req.left, out); // left + detail::write_int64(req.uploaded, out); // uploaded + detail::write_int32(req.event, out); // event + // ip address + if (m_settings.announce_ip != address() && m_settings.announce_ip.is_v4()) + detail::write_uint32(m_settings.announce_ip.to_v4().to_ulong(), out); + else + detail::write_int32(0, out); + detail::write_int32(req.key, out); // key + detail::write_int32(req.num_want, out); // num_want + detail::write_uint16(req.listen_port, out); // port + detail::write_uint16(0, out); // extensions + + TORRENT_ASSERT(out - buf == sizeof(buf)); + +#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) + boost::shared_ptr cb = requester(); + if (cb) + { + cb->debug_log("==> UDP_TRACKER_ANNOUNCE [" + + lexical_cast(req.info_hash) + "]"); + } +#endif + + asio::error_code ec; + m_socket.send(m_target, buf, sizeof(buf), ec); + m_state = action_announce; + ++m_attempts; + if (ec) + { + fail(-1, ec.message().c_str()); + return; + } + } + }