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;
	}
Ejemplo n.º 2
0
	// 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_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;
	}
	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;
	}
Ejemplo n.º 6
0
	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;
	}