bool udp_tracker_connection::on_announce_response(aux::array_view<char const> buf) { if (buf.size() < 20) return false; buf = buf.cut_first(8); restart_read_timeout(); tracker_response resp; resp.interval = aux::read_int32(buf); resp.min_interval = 60; resp.incomplete = aux::read_int32(buf); resp.complete = aux::read_int32(buf); int const num_peers = int(buf.size()) / 6; if ((buf.size() % 6) != 0) { fail(error_code(errors::invalid_tracker_response_length)); return false; } boost::shared_ptr<request_callback> cb = requester(); #ifndef TORRENT_DISABLE_LOGGING if (cb) { cb->debug_log("<== UDP_TRACKER_RESPONSE [ url: %s ]", tracker_req().url.c_str()); } #endif if (!cb) { close(); return true; } std::vector<peer_entry> peer_list; resp.peers4.reserve(num_peers); for (int i = 0; i < num_peers; ++i) { ipv4_peer_entry e; memcpy(&e.ip[0], buf.data(), 4); buf = buf.cut_first(4); e.port = aux::read_uint16(buf); resp.peers4.push_back(e); } std::list<address> ip_list; for (std::vector<tcp::endpoint>::const_iterator i = m_endpoints.begin() , end(m_endpoints.end()); i != end; ++i) { ip_list.push_back(i->address()); } cb->tracker_response(tracker_req(), m_target.address(), ip_list , resp); close(); return true; }
// allocate an uninitialized buffer of the specified size // and copy the initialization range into the start of the buffer buffer(std::size_t const size, aux::array_view<char const> initialize) : buffer(size) { TORRENT_ASSERT(initialize.size() <= size); if (initialize.size() > 0) { memcpy(m_begin, initialize.data(), std::min(initialize.size(), size)); } }
bool udp_tracker_connection::on_scrape_response(aux::array_view<char const> buf) { using namespace libtorrent::aux; restart_read_timeout(); int const action = aux::read_int32(buf); std::uint32_t const transaction = read_uint32(buf); if (transaction != m_transaction_id) { fail(error_code(errors::invalid_tracker_transaction_id)); return false; } if (action == action_error) { fail(error_code(errors::tracker_failure), -1 , std::string(buf.data(), buf.size()).c_str()); return true; } if (action != action_scrape) { fail(error_code(errors::invalid_tracker_action)); return true; } if (buf.size() < 12) { fail(error_code(errors::invalid_tracker_response_length)); return true; } int const complete = aux::read_int32(buf); int const downloaded = aux::read_int32(buf); int const incomplete = aux::read_int32(buf); boost::shared_ptr<request_callback> cb = requester(); if (!cb) { close(); return true; } cb->tracker_scrape_response(tracker_req() , complete, incomplete, downloaded, -1); close(); return true; }
bool udp_tracker_connection::on_connect_response(aux::array_view<char const> buf) { // ignore packets smaller than 16 bytes if (buf.size() < 16) return false; restart_read_timeout(); // skip header buf = buf.cut_first(8); // reset transaction update_transaction_id(); std::uint64_t const connection_id = read_int64(buf); std::lock_guard<std::mutex> l(m_cache_mutex); connection_cache_entry& cce = m_connection_cache[m_target.address()]; cce.connection_id = connection_id; cce.expires = aux::time_now() + seconds(m_man.settings().get_int(settings_pack::udp_tracker_token_expiry)); if (0 == (tracker_req().kind & tracker_request::scrape_request)) send_udp_announce(); else if (0 != (tracker_req().kind & tracker_request::scrape_request)) send_udp_scrape(); return true; }
bool udp_tracker_connection::on_receive(udp::endpoint const& ep , aux::array_view<char const> const buf) { #ifndef TORRENT_DISABLE_LOGGING boost::shared_ptr<request_callback> cb = requester(); #endif // ignore resposes before we've sent any requests if (m_state == action_error) { #ifndef TORRENT_DISABLE_LOGGING if (cb) cb->debug_log("<== UDP_TRACKER [ m_action == error ]"); #endif return false; } if (m_abort) { #ifndef TORRENT_DISABLE_LOGGING if (cb) cb->debug_log("<== UDP_TRACKER [ aborted]"); #endif return false; } // ignore packet not sent from the tracker // if m_target is inaddr_any, it suggests that we // sent the packet through a proxy only knowing // the hostname, in which case this packet might be for us if (!is_any(m_target.address()) && m_target != ep) { #ifndef TORRENT_DISABLE_LOGGING if (cb) cb->debug_log("<== UDP_TRACKER [ unexpected source IP: %s " "expected: %s ]" , print_endpoint(ep).c_str() , print_endpoint(m_target).c_str()); #endif return false; } #ifndef TORRENT_DISABLE_LOGGING if (cb) cb->debug_log("<== UDP_TRACKER_PACKET [ size: %d ]" , int(buf.size())); #endif // ignore packets smaller than 8 bytes if (buf.size() < 8) return false; aux::array_view<const char> ptr = buf; int const action = read_int32(ptr); std::uint32_t const transaction = read_uint32(ptr); #ifndef TORRENT_DISABLE_LOGGING if (cb) cb->debug_log("*** UDP_TRACKER_PACKET [ action: %d ]", action); #endif // ignore packets with incorrect transaction id if (m_transaction_id != transaction) { #ifndef TORRENT_DISABLE_LOGGING if (cb) cb->debug_log("*** UDP_TRACKER_PACKET [ tid: %x ]" , int(transaction)); #endif return false; } if (action == action_error) { fail(error_code(errors::tracker_failure), -1 , std::string(buf.data(), buf.size()).c_str()); return true; } // ignore packets that's not a response to our message if (action != m_state) { #ifndef TORRENT_DISABLE_LOGGING if (cb) cb->debug_log("*** UDP_TRACKER_PACKET [ unexpected action: %d " " expected: %d ]", action, m_state); #endif return false; } restart_read_timeout(); #ifndef TORRENT_DISABLE_LOGGING if (cb) cb->debug_log("*** UDP_TRACKER_RESPONSE [ tid: %x ]" , int(transaction)); #endif switch (m_state) { case action_connect: return on_connect_response(buf); case action_announce: return on_announce_response(buf); case action_scrape: return on_scrape_response(buf); default: break; } return false; }
bool utp_socket_manager::incoming_packet(udp::endpoint const& ep , aux::array_view<char const> p) { // UTP_LOGV("incoming packet size:%d\n", size); if (p.size() < int(sizeof(utp_header))) return false; utp_header const* ph = reinterpret_cast<utp_header const*>(p.data()); // UTP_LOGV("incoming packet version:%d\n", int(ph->get_version())); if (ph->get_version() != 1) return false; const time_point receive_time = clock_type::now(); // parse out connection ID and look for existing // connections. If found, forward to the utp_stream. std::uint16_t id = ph->connection_id; // first test to see if it's the same socket as last time // in most cases it is if (m_last_socket && utp_match(m_last_socket, ep, id)) { return utp_incoming_packet(m_last_socket, p, ep, receive_time); } std::pair<socket_map_t::iterator, socket_map_t::iterator> r = m_utp_sockets.equal_range(id); for (; r.first != r.second; ++r.first) { if (!utp_match(r.first->second, ep, id)) continue; bool ret = utp_incoming_packet(r.first->second, p, ep, receive_time); if (ret) m_last_socket = r.first->second; return ret; } // UTP_LOGV("incoming packet id:%d source:%s\n", id, print_endpoint(ep).c_str()); if (!m_sett.get_bool(settings_pack::enable_incoming_utp)) return false; // if not found, see if it's a SYN packet, if it is, // create a new utp_stream if (ph->get_type() == ST_SYN) { // possible SYN flood. Just ignore if (int(m_utp_sockets.size()) > m_sett.get_int(settings_pack::connections_limit) * 2) return false; // UTP_LOGV("not found, new connection id:%d\n", m_new_connection); boost::shared_ptr<socket_type> c(new (std::nothrow) socket_type(m_ios)); if (!c) return false; TORRENT_ASSERT(m_new_connection == -1); // create the new socket with this ID m_new_connection = id; instantiate_connection(m_ios, aux::proxy_settings(), *c , m_ssl_context, this, true, false); utp_stream* str = nullptr; #ifdef TORRENT_USE_OPENSSL if (is_ssl(*c)) str = &c->get<ssl_stream<utp_stream> >()->next_layer(); else #endif str = c->get<utp_stream>(); TORRENT_ASSERT(str); int link_mtu, utp_mtu; mtu_for_dest(ep.address(), link_mtu, utp_mtu); utp_init_mtu(str->get_impl(), link_mtu, utp_mtu); bool ret = utp_incoming_packet(str->get_impl(), p, ep, receive_time); if (!ret) return false; m_cb(c); // the connection most likely changed its connection ID here // we need to move it to the correct ID return true; } if (ph->get_type() == ST_RESET) return false; // #error send reset return false; }