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)); }
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)); }
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)); }
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)); }
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)); }
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)); }
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); }
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)); }
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 }
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"); }
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; }