Ejemplo n.º 1
0
	void i2p_connection::open(std::string const& s, int port
		, i2p_stream::handler_type const& handler)
	{
		// we already seem to have a session to this SAM router
		if (m_hostname == s
			&& m_port == port
			&& m_sam_socket
			&& (is_open() || m_state == sam_connecting)) return;

		m_hostname = s;
		m_port = port;

		if (m_hostname.empty()) return;

		m_state = sam_connecting;

		char tmp[20];
		std::generate(tmp, tmp + sizeof(tmp), &std::rand);
		m_session_id.resize(sizeof(tmp)*2);
		to_hex(tmp, 20, &m_session_id[0]);

		m_sam_socket.reset(new i2p_stream(m_io_service));
		m_sam_socket->set_proxy(m_hostname, m_port);
		m_sam_socket->set_command(i2p_stream::cmd_create_session);
		m_sam_socket->set_session_id(m_session_id.c_str());

#if defined TORRENT_ASIO_DEBUGGING
		add_outstanding_async("i2p_stream::on_sam_connect");
#endif
		m_sam_socket->async_connect(tcp::endpoint()
			, boost::bind(&i2p_connection::on_sam_connect, this, _1, handler, m_sam_socket));
	}
	void timeout_handler::set_timeout(int completion_timeout, int read_timeout)
	{
		m_completion_timeout = completion_timeout;
		m_read_timeout = read_timeout;
		m_start_time = m_read_time = time_now_hires();

		TORRENT_ASSERT(completion_timeout > 0 || read_timeout > 0);

		if (m_abort) return;

		int timeout = 0;
		if (m_read_timeout > 0) timeout = m_read_timeout;
		if (m_completion_timeout > 0)
		{
			timeout = timeout == 0
				? m_completion_timeout
				: (std::min)(m_completion_timeout, timeout);
		}

#if defined TORRENT_ASIO_DEBUGGING
		add_outstanding_async("timeout_handler::timeout_callback");
#endif
		error_code ec;
		m_timeout.expires_at(m_read_time + seconds(timeout), ec);
		m_timeout.async_wait(boost::bind(
			&timeout_handler::timeout_callback, self(), _1));
	}
Ejemplo n.º 3
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);
#if defined TORRENT_ASIO_DEBUGGING
		add_outstanding_async("i2p_stream::start_read_line");
#endif
		async_write(m_sock, boost::asio::buffer(cmd, size)
			, boost::bind(&i2p_stream::start_read_line, this, _1, h));
	}
Ejemplo n.º 4
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);
#if defined TORRENT_ASIO_DEBUGGING
		add_outstanding_async("i2p_stream::start_read_line");
#endif
		async_write(m_sock, boost::asio::buffer(cmd, size)
			, boost::bind(&i2p_stream::start_read_line, this, _1, h));
	}
Ejemplo n.º 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);
#if defined TORRENT_ASIO_DEBUGGING
		add_outstanding_async("i2p_stream::start_read_line");
#endif
		async_write(m_sock, boost::asio::buffer(cmd, size)
			, boost::bind(&i2p_stream::start_read_line, this, _1, h));
	}
Ejemplo n.º 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);
#if defined TORRENT_ASIO_DEBUGGING
		add_outstanding_async("i2p_stream::start_read_line");
#endif
		async_write(m_sock, asio::buffer(cmd, size)
			, boost::bind(&i2p_stream::start_read_line, this, _1, h));
	}
Ejemplo n.º 7
0
	void i2p_stream::start_read_line(error_code const& e, boost::shared_ptr<handler_type> h)
	{
		TORRENT_ASSERT(m_magic == 0x1337);
#if defined TORRENT_ASIO_DEBUGGING
		complete_async("i2p_stream::start_read_line");
#endif
		if (handle_error(e, h)) return;

#if defined TORRENT_ASIO_DEBUGGING
		add_outstanding_async("i2p_stream::read_line");
#endif
		m_buffer.resize(1);
		async_read(m_sock, boost::asio::buffer(m_buffer)
			, boost::bind(&i2p_stream::read_line, this, _1, h));
	}
Ejemplo n.º 8
0
	void resolver::async_resolve(std::string const& host, int flags
		, resolver_interface::callback_t const& h)
	{
		cache_t::iterator i = m_cache.find(host);
		if (i != m_cache.end())
		{
			// keep cache entries valid for m_timeout seconds
			if ((flags & resolver_interface::prefer_cache)
				|| i->second.last_seen + m_timeout >= aux::time_now())
			{
				error_code ec;
				m_ios.post(boost::bind(h, ec, i->second.addresses));
				return;
			}
		}

		// special handling for raw IP addresses. There's no need to get in line
		// behind actual lookups if we can just resolve it immediately.
		error_code ec;
		address ip = address::from_string(host.c_str(), ec);
		if (!ec)
		{
			std::vector<address> addresses;
			addresses.push_back(ip);
			m_ios.post(boost::bind(h, ec, addresses));
			return;
		}

		// the port is ignored
		tcp::resolver::query q(host, "80");

#if defined TORRENT_ASIO_DEBUGGING
		add_outstanding_async("resolver::on_lookup");
#endif
		if (flags & resolver_interface::abort_on_shutdown)
		{
			m_resolver.async_resolve(q, boost::bind(&resolver::on_lookup, this, _1, _2
				, h, host));
		}
		else
		{
			m_critical_resolver.async_resolve(q, boost::bind(&resolver::on_lookup, this, _1, _2
				, h, host));
		}
	}
Ejemplo n.º 9
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;
		}

#if defined TORRENT_ASIO_DEBUGGING
		add_outstanding_async("i2p_stream::connected");
#endif
		m_sock.async_connect(i->endpoint(), boost::bind(
			&i2p_stream::connected, this, _1, h));
	}
Ejemplo n.º 10
0
	void i2p_stream::connected(error_code const& e, boost::shared_ptr<handler_type> h)
	{
		TORRENT_ASSERT(m_magic == 0x1337);
#if defined TORRENT_ASIO_DEBUGGING
		complete_async("i2p_stream::connected");
#endif
		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";

#if defined TORRENT_ASIO_DEBUGGING
		add_outstanding_async("i2p_stream::start_read_line");
#endif
		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);
	}
Ejemplo n.º 11
0
void upnp::discover_device_impl(mutex::scoped_lock& l)
{
	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, l);
		disable(ec, l);
		return;
	}

#if defined TORRENT_ASIO_DEBUGGING
	add_outstanding_async("upnp::resend_request");
#endif
	++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", l);
}
	void timeout_handler::timeout_callback(error_code const& error)
	{
#if defined TORRENT_ASIO_DEBUGGING
		complete_async("timeout_handler::timeout_callback");
#endif
		if (m_abort) return;

		ptime now = time_now_hires();
		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);
		}
#if defined TORRENT_ASIO_DEBUGGING
		add_outstanding_async("timeout_handler::timeout_callback");
#endif
		error_code ec;
		m_timeout.expires_at(m_read_time + seconds(timeout), ec);
		m_timeout.async_wait(
			boost::bind(&timeout_handler::timeout_callback, self(), _1));
	}
	void async_connect(endpoint_type const& endpoint, Handler const& handler)
	{
		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));

#if defined TORRENT_ASIO_DEBUGGING
		add_outstanding_async("socks5_stream::name_lookup");
#endif
		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));
	}
Ejemplo n.º 14
0
void connection_queue::on_timeout(error_code const& e)
{
#if defined TORRENT_ASIO_DEBUGGING
    complete_async("connection_queue::on_timeout");
#endif
    mutex_t::scoped_lock l(m_mutex);
    --m_num_timers;

    INVARIANT_CHECK;
#ifdef TORRENT_DEBUG
    function_guard guard_(m_in_timeout_function);
#endif

    TORRENT_ASSERT(!e || e == error::operation_aborted);

    // if there was an error, it's most likely operation aborted,
    // we should just quit. However, in case there are still connections
    // in connecting state, and there are no other timer invocations
    // we need to stick around still.
    if (e && (m_num_connecting == 0 || m_num_timers > 0)) return;

    ptime next_expire = max_time();
    ptime now = time_now_hires() + milliseconds(100);
    std::list<entry> timed_out;
    for (std::list<entry>::iterator i = m_queue.begin();
            !m_queue.empty() && i != m_queue.end();)
    {
        if (i->connecting && i->expires < now)
        {
            std::list<entry>::iterator j = i;
            ++i;
            timed_out.splice(timed_out.end(), m_queue, j, i);
            --m_num_connecting;
            continue;
        }
        if (i->connecting && i->expires < next_expire)
            next_expire = i->expires;
        ++i;
    }

    // we don't want to call the timeout callback while we're locked
    // since that is a recepie for dead-locks
    l.unlock();

    for (std::list<entry>::iterator i = timed_out.begin()
                                        , end(timed_out.end()); i != end; ++i)
    {
        TORRENT_ASSERT(i->connecting);
        TORRENT_ASSERT(i->ticket != -1);
        TORRENT_TRY {
            i->on_timeout();
        } TORRENT_CATCH(std::exception&) {}
    }

    l.lock();

    if (next_expire < max_time())
    {
#if defined TORRENT_ASIO_DEBUGGING
        add_outstanding_async("connection_queue::on_timeout");
#endif
        error_code ec;
        m_timer.expires_at(next_expire, ec);
        m_timer.async_wait(boost::bind(&connection_queue::on_timeout, this, _1));
        ++m_num_timers;
    }
    try_connect(l);
}
Ejemplo n.º 15
0
void connection_queue::try_connect(connection_queue::mutex_t::scoped_lock& l)
{
    INVARIANT_CHECK;

#ifdef TORRENT_CONNECTION_LOGGING
    m_log << log_time() << " " << free_slots() << std::endl;
#endif
    // if this is enabled, UPnP connections will be blocked when shutting down
//		if (m_abort) return;

    if (m_num_connecting >= m_half_open_limit
            && m_half_open_limit > 0) return;

    if (m_queue.empty())
    {
        error_code ec;
        m_timer.cancel(ec);
        return;
    }

    // all entries are connecting, no need to look for new ones
    if (m_queue.size() == m_num_connecting)
        return;

    std::list<entry>::iterator i = std::find_if(m_queue.begin()
                                   , m_queue.end(), boost::bind(&entry::connecting, _1) == false);

    std::list<entry> to_connect;

    while (i != m_queue.end())
    {
        TORRENT_ASSERT(i->connecting == false);
        ptime expire = time_now_hires() + i->timeout;
        if (m_num_connecting == 0)
        {
#if defined TORRENT_ASIO_DEBUGGING
            add_outstanding_async("connection_queue::on_timeout");
#endif
            error_code ec;
            m_timer.expires_at(expire, ec);
            m_timer.async_wait(boost::bind(&connection_queue::on_timeout, this, _1));
            ++m_num_timers;
        }
        i->connecting = true;
        ++m_num_connecting;
        i->expires = expire;

        INVARIANT_CHECK;

        to_connect.push_back(*i);

#ifdef TORRENT_CONNECTION_LOGGING
        m_log << log_time() << " " << free_slots() << std::endl;
#endif

        if (m_num_connecting >= m_half_open_limit
                && m_half_open_limit > 0) break;
        if (m_num_connecting == m_queue.size()) break;
        i = std::find_if(i, m_queue.end(), boost::bind(&entry::connecting, _1) == false);
    }

    l.unlock();

    while (!to_connect.empty())
    {
        entry& ent = to_connect.front();
        TORRENT_TRY {
            ent.on_connect(ent.ticket);
        } TORRENT_CATCH(std::exception&) {}
        to_connect.pop_front();
    }

}
Ejemplo n.º 16
0
	void i2p_stream::read_line(error_code const& e, boost::shared_ptr<handler_type> h)
	{
		TORRENT_ASSERT(m_magic == 0x1337);
#if defined TORRENT_ASIO_DEBUGGING
		complete_async("i2p_stream::read_line");
#endif
		if (handle_error(e, h)) return;

		int read_pos = m_buffer.size();

		// look for \n which means end of the response
		if (m_buffer[read_pos - 1] != '\n')
		{
#if defined TORRENT_ASIO_DEBUGGING
			add_outstanding_async("i2p_stream::read_line");
#endif
			// 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);
#if defined TORRENT_ASIO_DEBUGGING
			add_outstanding_async("i2p_stream::read_line");
#endif
			async_read(m_sock, boost::asio::buffer(m_buffer)
				, boost::bind(&i2p_stream::read_line, this, _1, h));
			break;
		}

		return;
	}