void async_connect(endpoint_type const& endpoint, Handler const& handler)
	{
		// make sure we don't try to connect to INADDR_ANY. binding is fine,
		// and using a hostname is fine on SOCKS version 5.
		TORRENT_ASSERT(m_command == socks5_bind
			|| endpoint.address() != address()
			|| (!m_dst_name.empty() && m_version == 5));

		m_remote_endpoint = endpoint;

		// the connect is split up in the following steps:
		// 1. resolve name of proxy server
		// 2. connect to proxy server
		// 3. if version == 5:
		//   3.1 send SOCKS5 authentication method message
		//   3.2 read SOCKS5 authentication response
		//   3.3 send username+password
		// 4. send SOCKS command message

		// to avoid unnecessary copying of the handler,
		// store it in a shaed_ptr
		boost::shared_ptr<handler_type> h(new handler_type(handler));

		ADD_OUTSTANDING_ASYNC("socks5_stream::name_lookup");
		tcp::resolver::query q(m_hostname, to_string(m_port).elems);
		m_resolver.async_resolve(q, boost::bind(
			&socks5_stream::name_lookup, this, _1, _2, h));
	}
Beispiel #2
0
	void i2p_stream::send_name_lookup(boost::shared_ptr<handler_type> h)
	{
		TORRENT_ASSERT(m_magic == 0x1337);
		m_state = read_name_lookup_response;
		char cmd[1024];
		int size = snprintf(cmd, sizeof(cmd), "NAMING LOOKUP NAME=%s\n", m_name_lookup.c_str());
//		fprintf(stderr, ">>> %s", cmd);
		ADD_OUTSTANDING_ASYNC("i2p_stream::start_read_line");
		async_write(m_sock, boost::asio::buffer(cmd, size)
			, boost::bind(&i2p_stream::start_read_line, this, _1, h));
	}
Beispiel #3
0
	void i2p_stream::send_accept(boost::shared_ptr<handler_type> h)
	{
		TORRENT_ASSERT(m_magic == 0x1337);
		m_state = read_accept_response;
		char cmd[400];
		int size = snprintf(cmd, sizeof(cmd), "STREAM ACCEPT ID=%s\n", m_id);
//		fprintf(stderr, ">>> %s", cmd);
		ADD_OUTSTANDING_ASYNC("i2p_stream::start_read_line");
		async_write(m_sock, boost::asio::buffer(cmd, size)
			, boost::bind(&i2p_stream::start_read_line, this, _1, h));
	}
Beispiel #4
0
	void i2p_stream::start_read_line(error_code const& e, boost::shared_ptr<handler_type> h)
	{
		TORRENT_ASSERT(m_magic == 0x1337);
		COMPLETE_ASYNC("i2p_stream::start_read_line");
		if (handle_error(e, h)) return;

		ADD_OUTSTANDING_ASYNC("i2p_stream::read_line");
		m_buffer.resize(1);
		async_read(m_sock, boost::asio::buffer(m_buffer)
			, boost::bind(&i2p_stream::read_line, this, _1, h));
	}
Beispiel #5
0
	void i2p_stream::send_session_create(boost::shared_ptr<handler_type> h)
	{
		TORRENT_ASSERT(m_magic == 0x1337);
		m_state = read_session_create_response;
		char cmd[400];
		int size = snprintf(cmd, sizeof(cmd), "SESSION CREATE STYLE=STREAM ID=%s DESTINATION=TRANSIENT\n"
			, m_id);
//		fprintf(stderr, ">>> %s", cmd);
		ADD_OUTSTANDING_ASYNC("i2p_stream::start_read_line");
		async_write(m_sock, boost::asio::buffer(cmd, size)
			, boost::bind(&i2p_stream::start_read_line, this, _1, h));
	}
Beispiel #6
0
	void i2p_stream::send_connect(boost::shared_ptr<handler_type> h)
	{
		TORRENT_ASSERT(m_magic == 0x1337);
		m_state = read_connect_response;
		char cmd[1024];
		int size = snprintf(cmd, sizeof(cmd), "STREAM CONNECT ID=%s DESTINATION=%s\n"
			, m_id, m_dest.c_str());
//		fprintf(stderr, ">>> %s", cmd);
		ADD_OUTSTANDING_ASYNC("i2p_stream::start_read_line");
		async_write(m_sock, boost::asio::buffer(cmd, size)
			, boost::bind(&i2p_stream::start_read_line, this, _1, h));
	}
Beispiel #7
0
	void i2p_stream::connected(error_code const& e, boost::shared_ptr<handler_type> h)
	{
		TORRENT_ASSERT(m_magic == 0x1337);
		COMPLETE_ASYNC("i2p_stream::connected");
		if (handle_error(e, h)) return;

		// send hello command
		m_state = read_hello_response;
		static const char cmd[] = "HELLO VERSION MIN=3.0 MAX=3.0\n";

		ADD_OUTSTANDING_ASYNC("i2p_stream::start_read_line");
		async_write(m_sock, boost::asio::buffer(cmd, sizeof(cmd) - 1)
			, boost::bind(&i2p_stream::start_read_line, this, _1, h));
//		fprintf(stderr, ">>> %s", cmd);
	}
Beispiel #8
0
	void i2p_stream::do_connect(error_code const& e, tcp::resolver::iterator i
		, boost::shared_ptr<handler_type> h)
	{
		TORRENT_ASSERT(m_magic == 0x1337);
		if (e || i == tcp::resolver::iterator())
		{
			(*h)(e);
			error_code ec;
			close(ec);
			return;
		}

		ADD_OUTSTANDING_ASYNC("i2p_stream::connected");
		m_sock.async_connect(i->endpoint(), boost::bind(
			&i2p_stream::connected, this, _1, h));
	}
Beispiel #9
0
	void timeout_handler::timeout_callback(error_code const& error)
	{
		COMPLETE_ASYNC("timeout_handler::timeout_callback");
#if TORRENT_USE_ASSERTS
		TORRENT_ASSERT(m_outstanding_timer_wait > 0);
		--m_outstanding_timer_wait;
#endif
		if (m_abort) return;

		time_point now = clock_type::now();
		time_duration receive_timeout = now - m_read_time;
		time_duration completion_timeout = now - m_start_time;

		if ((m_read_timeout
				&& m_read_timeout <= total_seconds(receive_timeout))
			|| (m_completion_timeout
				&& m_completion_timeout <= total_seconds(completion_timeout))
			|| error)
		{
			on_timeout(error);
			return;
		}

		int timeout = 0;
		if (m_read_timeout > 0) timeout = m_read_timeout;
		if (m_completion_timeout > 0)
		{
			timeout = timeout == 0
				? int(m_completion_timeout - total_seconds(m_read_time - m_start_time))
				: (std::min)(int(m_completion_timeout - total_seconds(m_read_time - m_start_time)), timeout);
		}
		ADD_OUTSTANDING_ASYNC("timeout_handler::timeout_callback");
		error_code ec;
		m_timeout.expires_at(m_read_time + seconds(timeout), ec);
		m_timeout.async_wait(
			std::bind(&timeout_handler::timeout_callback, shared_from_this(), _1));
#if TORRENT_USE_ASSERTS
		++m_outstanding_timer_wait;
#endif
	}
Beispiel #10
0
void upnp::discover_device_impl()
{
	TORRENT_ASSERT(is_single_thread());
	const char msearch[] =
		"M-SEARCH * HTTP/1.1\r\n"
		"HOST: 239.255.255.250:1900\r\n"
		"ST:upnp:rootdevice\r\n"
		"MAN:\"ssdp:discover\"\r\n"
		"MX:3\r\n"
		"\r\n\r\n";

	error_code ec;
#ifdef TORRENT_DEBUG_UPNP
	// simulate packet loss
	if (m_retry_count & 1)
#endif
	m_socket.send(msearch, sizeof(msearch) - 1, ec);

	if (ec)
	{
		char msg[500];
		snprintf(msg, sizeof(msg), "broadcast failed: %s. Aborting."
			, convert_from_native(ec.message()).c_str());
		log(msg);
		disable(ec);
		return;
	}

	ADD_OUTSTANDING_ASYNC("upnp::resend_request");
	++m_retry_count;
	m_broadcast_timer.expires_from_now(seconds(2 * m_retry_count), ec);
	m_broadcast_timer.async_wait(boost::bind(&upnp::resend_request
		, self(), _1));

	log("broadcasting search for rootdevice");
}
Beispiel #11
0
	void i2p_stream::read_line(error_code const& e, boost::shared_ptr<handler_type> h)
	{
		TORRENT_ASSERT(m_magic == 0x1337);
		COMPLETE_ASYNC("i2p_stream::read_line");
		if (handle_error(e, h)) return;

		int read_pos = int(m_buffer.size());

		// look for \n which means end of the response
		if (m_buffer[read_pos - 1] != '\n')
		{
			ADD_OUTSTANDING_ASYNC("i2p_stream::read_line");
			// read another byte from the socket
			m_buffer.resize(read_pos + 1);
			async_read(m_sock, boost::asio::buffer(&m_buffer[read_pos], 1)
				, boost::bind(&i2p_stream::read_line, this, _1, h));
			return;
		}
		m_buffer[read_pos - 1] = 0;

		if (m_command == cmd_incoming)
		{
			// this is the line containing the destination
			// of the incoming connection in an accept call
			m_dest = &m_buffer[0];
			(*h)(e);
			std::vector<char>().swap(m_buffer);
			return;
		}

		error_code invalid_response(i2p_error::parse_failed
			, get_i2p_category());

		// null-terminate the string and parse it
		m_buffer.push_back(0);
		char* ptr = &m_buffer[0];
		char* next = ptr;

		char const* expect1 = 0;
		char const* expect2 = 0;

		switch (m_state)
		{
			case read_hello_response:
				expect1 = "HELLO";
				expect2 = "REPLY";
				break;
			case read_connect_response:
			case read_accept_response:
				expect1 = "STREAM";
				expect2 = "STATUS";
				break;
			case read_session_create_response:
				expect1 = "SESSION";
				expect2 = "STATUS";
				break;
			case read_name_lookup_response:
				expect1 = "NAMING";
				expect2 = "REPLY";
				break;
		}

//		fprintf(stderr, "<<< %s\n", &m_buffer[0]);
		ptr = string_tokenize(next, ' ', &next);
		if (ptr == 0 || expect1 == 0 || strcmp(expect1, ptr)) { handle_error(invalid_response, h); return; }
		ptr = string_tokenize(next, ' ', &next);
		if (ptr == 0 || expect2 == 0 || strcmp(expect2, ptr)) { handle_error(invalid_response, h); return; }

		int result = 0;
//		char const* message = 0;
//		float version = 3.0f;

		for(;;)
		{
			char* name = string_tokenize(next, '=', &next);
			if (name == 0) break;
//			fprintf(stderr, "name=\"%s\"\n", name);
			char* ptr2 = string_tokenize(next, ' ', &next);
			if (ptr2 == 0) { handle_error(invalid_response, h); return; }
//			fprintf(stderr, "value=\"%s\"\n", ptr2);

			if (strcmp("RESULT", name) == 0)
			{
				if (strcmp("OK", ptr2) == 0)
					result = i2p_error::no_error;
				else if (strcmp("CANT_REACH_PEER", ptr2) == 0)
					result = i2p_error::cant_reach_peer;
				else if (strcmp("I2P_ERROR", ptr2) == 0)
					result = i2p_error::i2p_error;
				else if (strcmp("INVALID_KEY", ptr2) == 0)
					result = i2p_error::invalid_key;
				else if (strcmp("INVALID_ID", ptr2) == 0)
					result = i2p_error::invalid_id;
				else if (strcmp("TIMEOUT", ptr2) == 0)
					result = i2p_error::timeout;
				else if (strcmp("KEY_NOT_FOUND", ptr2) == 0)
					result = i2p_error::key_not_found;
				else if (strcmp("DUPLICATED_ID", ptr2) == 0)
					result = i2p_error::duplicated_id;
				else
					result = i2p_error::num_errors; // unknown error
			}
			else if (strcmp("MESSAGE", name) == 0)
			{
//				message = ptr2;
			}
			else if (strcmp("VERSION", name) == 0)
			{
//				version = float(atof(ptr2));
			}
			else if (strcmp("VALUE", name) == 0)
			{
				m_name_lookup = ptr2;
			}
			else if (strcmp("DESTINATION", name) == 0)
			{
				m_dest = ptr2;
			}
		}

		error_code ec(result, get_i2p_category());
		switch (result)
		{
			case i2p_error::no_error:
			case i2p_error::invalid_key:
				break;
			default:
			{
				handle_error (ec, h);
				return;
			}
		}

		switch (m_state)
		{
		case read_hello_response:
			switch (m_command)
			{
				case cmd_create_session:
					send_session_create(h);
					break;
				case cmd_accept:
					send_accept(h);
					break;
				case cmd_connect:
					send_connect(h);
					break;
				default:
					(*h)(e);
					std::vector<char>().swap(m_buffer);
			}
			break;
		case read_connect_response:
		case read_session_create_response:
		case read_name_lookup_response:
			(*h)(ec);
			std::vector<char>().swap(m_buffer);
			break;
		case read_accept_response:
			// the SAM bridge is waiting for an incoming
			// connection.
			// wait for one more line containing
			// the destination of the remote peer
			m_command = cmd_incoming;
			m_buffer.resize(1);
			ADD_OUTSTANDING_ASYNC("i2p_stream::read_line");
			async_read(m_sock, boost::asio::buffer(m_buffer)
				, boost::bind(&i2p_stream::read_line, this, _1, h));
			break;
		}

		return;
	}