void connection::handle_write(const error_code& e, reply *rep) { //如果连接已经断开 则放弃写回 if(stopped())return; string mess_r = "Client[" + address_ + ":" + port_ + "] request file " + request_.uri; //记录 请求信息 log->record(mess_r); if (!e) { // Initiate graceful connection closure. //error_code ignored_ec; //socket_.shutdown(asio::ip::tcp::socket::shutdown_both, ignored_ec); string mess_s; if(rep->status == reply::ok){ mess_s = "Successfully send file " + request_.uri + " with " + boost::lexical_cast<std::string>(rep->content.size())+ " bytes to clien[" +\ address_ + ":" + port_ + "]"; }else{ mess_s = "Failed to send file " + request_.uri + " to client[" + address_ + ":" + port_ + "] due to " + rep->to_string(rep->status); } log->record(mess_s); connection::start_read(); }else{ string mess_f = "Failed to send file " + request_.uri + " to client[" + address_ + ":" + port_ + "] due to error " + e.message() ; log->record(mess_f); } //connection::start_read(); // No new asynchronous operations are started. This means that all shared_ptr // references to the connection object will disappear and the object will be // destroyed automatically after this handler returns. The connection class's // destructor closes the socket. }
void natpmp::on_reply(error_code const& e , std::size_t bytes_transferred) { mutex::scoped_lock l(m_mutex); #if defined TORRENT_ASIO_DEBUGGING complete_async("natpmp::on_reply"); #endif using namespace libtorrent::detail; if (e) { char msg[200]; snprintf(msg, sizeof(msg), "error on receiving reply: %s" , convert_from_native(e.message()).c_str()); log(msg, l); return; } #if defined TORRENT_ASIO_DEBUGGING add_outstanding_async("natpmp::on_reply"); #endif // make a copy of the response packet buffer // to avoid overwriting it in the next receive call char msg_buf[16]; memcpy(msg_buf, m_response_buffer, bytes_transferred); m_socket.async_receive_from(asio::buffer(&m_response_buffer, 16) , m_remote, boost::bind(&natpmp::on_reply, self(), _1, _2)); // simulate packet loss /* if ((random() % 2) == 0) { log(" simulating drop", l); return; } */ if (m_remote != m_nat_endpoint) { char msg[200]; snprintf(msg, sizeof(msg), "received packet from wrong IP: %s" , print_endpoint(m_remote).c_str()); log(msg, l); return; } error_code ec; m_send_timer.cancel(ec); if (bytes_transferred < 12) { char msg[200]; snprintf(msg, sizeof(msg), "received packet of invalid size: %d", int(bytes_transferred)); log(msg, l); return; } char* in = msg_buf; int version = read_uint8(in); int cmd = read_uint8(in); int result = read_uint16(in); int time = read_uint32(in); if (cmd == 128) { // public IP request response m_external_ip = read_v4_address(in); char msg[200]; snprintf(msg, sizeof(msg), "<== public IP address [ %s ]", print_address(m_external_ip).c_str()); log(msg, l); return; } if (bytes_transferred < 16) { char msg[200]; snprintf(msg, sizeof(msg), "received packet of invalid size: %d", int(bytes_transferred)); log(msg, l); return; } int private_port = read_uint16(in); int public_port = read_uint16(in); int lifetime = read_uint32(in); (void)time; // to remove warning int protocol = (cmd - 128 == 1)?udp:tcp; char msg[200]; int num_chars = snprintf(msg, sizeof(msg), "<== port map [" " protocol: %s local: %u external: %u ttl: %u ]" , (cmd - 128 == 1 ? "udp" : "tcp") , private_port, public_port, lifetime); if (version != 0) { snprintf(msg + num_chars, sizeof(msg) - num_chars, "unexpected version: %u" , version); log(msg, l); } mapping_t* m = 0; int index = -1; for (std::vector<mapping_t>::iterator i = m_mappings.begin() , end(m_mappings.end()); i != end; ++i) { if (private_port != i->local_port) continue; if (protocol != i->protocol) continue; if (!i->map_sent) continue; if (!i->outstanding_request) continue; m = &*i; index = i - m_mappings.begin(); break; } if (m == 0) { snprintf(msg + num_chars, sizeof(msg) - num_chars, " not found in map table"); log(msg, l); return; } m->outstanding_request = false; log(msg, l); if (public_port == 0 || lifetime == 0) { // this means the mapping was // successfully closed m->protocol = none; } else { m->expires = aux::time_now() + seconds(int(lifetime * 0.7f)); m->external_port = public_port; } if (result != 0) { int errors[] = { errors::unsupported_protocol_version, errors::natpmp_not_authorized, errors::network_failure, errors::no_resources, errors::unsupported_opcode, }; int ev = errors::no_error; if (result >= 1 && result <= 5) ev = errors[result - 1]; m->expires = aux::time_now() + hours(2); l.unlock(); m_callback(index, address(), 0, error_code(ev, get_libtorrent_category())); l.lock(); } else if (m->action == mapping_t::action_add) { l.unlock(); m_callback(index, m_external_ip, m->external_port, error_code(errors::no_error, get_libtorrent_category())); l.lock(); } if (m_abort) return; m_currently_mapping = -1; m->action = mapping_t::action_none; m_send_timer.cancel(ec); update_expiration_timer(l); try_next_mapping(index, l); }
void on_disconnected(error_code const& ec) { LogInfo("Client " << " disconnected with error: " << ec.message() ); }
void natpmp::on_reply(error_code const& e , std::size_t bytes_transferred) { TORRENT_ASSERT(is_single_thread()); COMPLETE_ASYNC("natpmp::on_reply"); using namespace libtorrent::detail; if (e) { #ifndef TORRENT_DISABLE_LOGGING log("error on receiving reply: %s" , convert_from_native(e.message()).c_str()); #endif return; } ADD_OUTSTANDING_ASYNC("natpmp::on_reply"); // make a copy of the response packet buffer // to avoid overwriting it in the next receive call char msg_buf[sizeof(m_response_buffer)]; memcpy(msg_buf, m_response_buffer, bytes_transferred); m_socket.async_receive_from(boost::asio::buffer(&m_response_buffer[0] , sizeof(m_response_buffer)) , m_remote, std::bind(&natpmp::on_reply, self(), _1, _2)); if (m_remote != m_nat_endpoint) { #ifndef TORRENT_DISABLE_LOGGING log("received packet from wrong IP: %s" , print_endpoint(m_remote).c_str()); #endif return; } error_code ec; m_send_timer.cancel(ec); if (bytes_transferred < 12) { #ifndef TORRENT_DISABLE_LOGGING log("received packet of invalid size: %d", int(bytes_transferred)); #endif return; } char* in = msg_buf; int version = read_uint8(in); int cmd = read_uint8(in); int result = read_uint16(in); int time = read_uint32(in); TORRENT_UNUSED(version); TORRENT_UNUSED(time); if (cmd == 128) { // public IP request response m_external_ip = read_v4_address(in); #ifndef TORRENT_DISABLE_LOGGING log("<== public IP address [ %s ]", print_address(m_external_ip).c_str()); #endif return; } if (bytes_transferred != 16) { #ifndef TORRENT_DISABLE_LOGGING log("received packet of invalid size: %d", int(bytes_transferred)); #endif return; } int const private_port = read_uint16(in); int const public_port = read_uint16(in); int const lifetime = read_uint32(in); int const protocol = (cmd - 128 == 1)?udp:tcp; #ifndef TORRENT_DISABLE_LOGGING char msg[200]; int num_chars = std::snprintf(msg, sizeof(msg), "<== port map [" " protocol: %s local: %u external: %u ttl: %u ]" , (cmd - 128 == 1 ? "udp" : "tcp") , private_port, public_port, lifetime); if (version != 0) { std::snprintf(msg + num_chars, sizeof(msg) - num_chars, "unexpected version: %u" , version); log("%s", msg); } #endif mapping_t* m = nullptr; int index = -1; for (std::vector<mapping_t>::iterator i = m_mappings.begin() , end(m_mappings.end()); i != end; ++i) { if (private_port != i->local_port) continue; if (protocol != i->protocol) continue; if (!i->map_sent) continue; if (!i->outstanding_request) continue; m = &*i; index = i - m_mappings.begin(); break; } if (m == nullptr) { #ifndef TORRENT_DISABLE_LOGGING snprintf(msg + num_chars, sizeof(msg) - num_chars, " not found in map table"); log("%s", msg); #endif return; } m->outstanding_request = false; #ifndef TORRENT_DISABLE_LOGGING log("%s", msg); #endif if (public_port == 0 || lifetime == 0) { // this means the mapping was // successfully closed m->protocol = none; } else { m->expires = aux::time_now() + seconds(int(lifetime * 0.7f)); m->external_port = public_port; } if (result != 0) { int errors[] = { errors::unsupported_protocol_version, errors::natpmp_not_authorized, errors::network_failure, errors::no_resources, errors::unsupported_opcode, }; int ev = errors::no_error; if (result >= 1 && result <= 5) ev = errors[result - 1]; m->expires = aux::time_now() + hours(2); int const proto = m->protocol; m_callback(index, address(), 0, proto , error_code(ev, get_libtorrent_category())); } else if (m->action == mapping_t::action_add) { int const proto = m->protocol; m_callback(index, m_external_ip, m->external_port, proto , error_code(errors::no_error, get_libtorrent_category())); } if (m_abort) return; m_currently_mapping = -1; m->action = mapping_t::action_none; m_send_timer.cancel(ec); update_expiration_timer(); try_next_mapping(index); }
void udp_tracker_connection::name_lookup(error_code const& error , udp::resolver::iterator i) { if (error == asio::error::operation_aborted) return; if (error || i == udp::resolver::iterator()) { fail(-1, error.message().c_str()); return; } boost::shared_ptr<request_callback> cb = requester(); #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING if (cb) cb->debug_log("*** UDP_TRACKER [ name lookup successful ]"); #endif restart_read_timeout(); // look for an address that has the same kind as the one // we're listening on. To make sure the tracker get our // correct listening address. std::transform(i, udp::resolver::iterator(), std::back_inserter(m_endpoints) , boost::bind(&udp::resolver::iterator::value_type::endpoint, _1)); // remove endpoints that are filtered by the IP filter for (std::list<udp::endpoint>::iterator i = m_endpoints.begin(); i != m_endpoints.end();) { if (m_ses.m_ip_filter.access(i->address()) == ip_filter::blocked) i = m_endpoints.erase(i); else ++i; } if (m_endpoints.empty()) { fail(-1, "blocked by IP filter"); return; } std::list<udp::endpoint>::iterator iter = m_endpoints.begin(); m_target = *iter; if (bind_interface() != address_v4::any()) { // find first endpoint that matches our bind interface type for (; iter != m_endpoints.end() && iter->address().is_v4() != bind_interface().is_v4(); ++iter); if (iter == m_endpoints.end()) { TORRENT_ASSERT(m_target.address().is_v4() != bind_interface().is_v4()); if (cb) { char const* tracker_address_type = m_target.address().is_v4() ? "IPv4" : "IPv6"; char const* bind_address_type = bind_interface().is_v4() ? "IPv4" : "IPv6"; char msg[200]; snprintf(msg, sizeof(msg) , "the tracker only resolves to an %s address, and you're " "listening on an %s socket. This may prevent you from receiving " "incoming connections." , tracker_address_type, bind_address_type); cb->tracker_warning(tracker_req(), msg); } } else { m_target = *iter; } } if (cb) cb->m_tracker_address = tcp::endpoint(m_target.address(), m_target.port()); if (bind_interface() != address_v4::any()) { error_code ec; m_socket.bind(udp::endpoint(bind_interface(), 0), ec); if (ec) { fail(-1, ec.message().c_str()); return; } } send_udp_connect(); }
void udp_tracker_connection::on_receive(error_code const& e , udp::endpoint const& ep, char const* buf, int size) { // ignore resposes before we've sent any requests if (m_state == action_error) return; if (!m_socket.is_open()) return; // the operation was aborted // ignore packet not sent from the tracker if (m_target != ep) return; received_bytes(size + 28); // assuming UDP/IP header if (e) fail(-1, e.message().c_str()); #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING boost::shared_ptr<request_callback> cb = requester(); if (cb) { char msg[200]; snprintf(msg, 200, "<== UDP_TRACKER_PACKET [ size: %d ]", size); cb->debug_log(msg); } #endif // ignore packets smaller than 8 bytes if (size < 8) return; restart_read_timeout(); const char* ptr = buf; int action = detail::read_int32(ptr); int transaction = detail::read_int32(ptr); #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING if (cb) { char msg[200]; snprintf(msg, 200, "*** UDP_TRACKER_PACKET [ action: %d ]", action); cb->debug_log(msg); } #endif // ignore packets with incorrect transaction id if (m_transaction_id != transaction) return; if (action == action_error) { fail(-1, std::string(ptr, size - 8).c_str()); return; } // ignore packets that's not a response to our message if (action != m_state) return; #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING if (cb) { char msg[200]; snprintf(msg, 200, "*** UDP_TRACKER_RESPONSE [ cid: %x%x ]" , int(m_connection_id >> 32), int(m_connection_id & 0xffffffff)); cb->debug_log(msg); } #endif switch (m_state) { case action_connect: on_connect_response(buf, size); break; case action_announce: on_announce_response(buf, size); break; case action_scrape: on_scrape_response(buf, size); break; default: break; } }
static bool error(error_code ec) { if (!ec) return false; errs() << "LLVMSymbolizer: error reading file: " << ec.message() << ".\n"; return true; }
void TAsyncCommonSocketChannel::handleResolve(const error_code& err, tcp::resolver::iterator epItr, const ReturnCallback& cb) { if (err) { cb(::boost::make_shared<TTransportException>("TAsyncCommonSocketChannel error in handling resolve: " + err.message())); } else { //attempt a connection on the first endpoint resolved connectToResolvedEndpoint(epItr, cb); } }
void http_seed_connection::on_receive(error_code const& error , std::size_t bytes_transferred) { INVARIANT_CHECK; if (error) { m_statistics.received_bytes(0, bytes_transferred); #ifdef TORRENT_VERBOSE_LOGGING peer_log("*** http_seed_connection error: %s", error.message().c_str()); #endif return; } boost::shared_ptr<torrent> t = associated_torrent().lock(); TORRENT_ASSERT(t); for (;;) { buffer::const_interval recv_buffer = receive_buffer(); if (bytes_transferred == 0) break; TORRENT_ASSERT(recv_buffer.left() > 0); TORRENT_ASSERT(!m_requests.empty()); if (m_requests.empty()) { m_statistics.received_bytes(0, bytes_transferred); disconnect(errors::http_error, 2); return; } peer_request front_request = m_requests.front(); bool header_finished = m_parser.header_finished(); if (!header_finished) { bool parse_error = false; int protocol = 0; int payload = 0; boost::tie(payload, protocol) = m_parser.incoming(recv_buffer, parse_error); m_statistics.received_bytes(0, protocol); bytes_transferred -= protocol; #if defined TORRENT_DEBUG || TORRENT_RELEASE_ASSERTS if (payload > front_request.length) payload = front_request.length; #endif if (parse_error) { m_statistics.received_bytes(0, bytes_transferred); disconnect(errors::http_parse_error, 2); return; } TORRENT_ASSERT(recv_buffer.left() == 0 || *recv_buffer.begin == 'H'); TORRENT_ASSERT(recv_buffer.left() <= packet_size()); // this means the entire status line hasn't been received yet if (m_parser.status_code() == -1) { TORRENT_ASSERT(payload == 0); TORRENT_ASSERT(bytes_transferred == 0); break; } // if the status code is not one of the accepted ones, abort if (!is_ok_status(m_parser.status_code())) { int retry_time = atoi(m_parser.header("retry-after").c_str()); if (retry_time <= 0) retry_time = 5 * 60; // temporarily unavailable, retry later t->retry_web_seed(this, retry_time); std::string error_msg = to_string(m_parser.status_code()).elems + (" " + m_parser.message()); if (m_ses.m_alerts.should_post<url_seed_alert>()) { m_ses.m_alerts.post_alert(url_seed_alert(t->get_handle(), url() , error_msg)); } m_statistics.received_bytes(0, bytes_transferred); disconnect(error_code(m_parser.status_code(), get_http_category()), 1); return; } if (!m_parser.header_finished()) { TORRENT_ASSERT(payload == 0); TORRENT_ASSERT(bytes_transferred == 0); break; } } // we just completed reading the header if (!header_finished) { if (is_redirect(m_parser.status_code())) { // this means we got a redirection request // look for the location header std::string location = m_parser.header("location"); m_statistics.received_bytes(0, bytes_transferred); if (location.empty()) { // we should not try this server again. t->remove_web_seed(this); disconnect(errors::missing_location, 2); return; } // add the redirected url and remove the current one t->add_web_seed(location, web_seed_entry::http_seed); t->remove_web_seed(this); disconnect(errors::redirecting, 2); return; } std::string const& server_version = m_parser.header("server"); if (!server_version.empty()) { m_server_string = "URL seed @ "; m_server_string += m_host; m_server_string += " ("; m_server_string += server_version; m_server_string += ")"; } m_response_left = atol(m_parser.header("content-length").c_str()); if (m_response_left == -1) { m_statistics.received_bytes(0, bytes_transferred); // we should not try this server again. t->remove_web_seed(this); disconnect(errors::no_content_length, 2); return; } if (m_response_left != front_request.length) { m_statistics.received_bytes(0, bytes_transferred); // we should not try this server again. t->remove_web_seed(this); disconnect(errors::invalid_range, 2); return; } m_body_start = m_parser.body_start(); } recv_buffer.begin += m_body_start; // ========================= // === CHUNKED ENCODING === // ========================= while (m_parser.chunked_encoding() && m_chunk_pos >= 0 && m_chunk_pos < recv_buffer.left()) { int header_size = 0; size_type chunk_size = 0; buffer::const_interval chunk_start = recv_buffer; chunk_start.begin += m_chunk_pos; TORRENT_ASSERT(chunk_start.begin[0] == '\r' || is_hex(chunk_start.begin, 1)); bool ret = m_parser.parse_chunk_header(chunk_start, &chunk_size, &header_size); if (!ret) { TORRENT_ASSERT(bytes_transferred >= size_t(chunk_start.left() - m_partial_chunk_header)); bytes_transferred -= chunk_start.left() - m_partial_chunk_header; m_statistics.received_bytes(0, chunk_start.left() - m_partial_chunk_header); m_partial_chunk_header = chunk_start.left(); if (bytes_transferred == 0) return; break; } else { #ifdef TORRENT_VERBOSE_LOGGING peer_log("*** parsed chunk: %d header_size: %d", chunk_size, header_size); #endif TORRENT_ASSERT(bytes_transferred >= size_t(header_size - m_partial_chunk_header)); bytes_transferred -= header_size - m_partial_chunk_header; m_statistics.received_bytes(0, header_size - m_partial_chunk_header); m_partial_chunk_header = 0; TORRENT_ASSERT(chunk_size != 0 || chunk_start.left() <= header_size || chunk_start.begin[header_size] == 'H'); // cut out the chunk header from the receive buffer TORRENT_ASSERT(m_chunk_pos + m_body_start < INT_MAX); cut_receive_buffer(header_size, t->block_size() + 1024, int(m_chunk_pos + m_body_start)); recv_buffer = receive_buffer(); recv_buffer.begin += m_body_start; m_chunk_pos += chunk_size; if (chunk_size == 0) { TORRENT_ASSERT(receive_buffer().left() < m_chunk_pos + m_body_start + 1 || receive_buffer()[int(m_chunk_pos + m_body_start)] == 'H' || (m_parser.chunked_encoding() && receive_buffer()[int(m_chunk_pos + m_body_start)] == '\r')); m_chunk_pos = -1; } } } int payload = bytes_transferred; if (payload > m_response_left) payload = int(m_response_left); if (payload > front_request.length) payload = front_request.length; m_statistics.received_bytes(payload, 0); incoming_piece_fragment(payload); m_response_left -= payload; if (m_parser.status_code() == 503) { if (!m_parser.finished()) return; int retry_time = atol(std::string(recv_buffer.begin, recv_buffer.end).c_str()); if (retry_time <= 0) retry_time = 60; #ifdef TORRENT_VERBOSE_LOGGING peer_log("*** retrying in %d seconds", retry_time); #endif m_statistics.received_bytes(0, bytes_transferred); // temporarily unavailable, retry later t->retry_web_seed(this, retry_time); disconnect(error_code(m_parser.status_code(), get_http_category()), 1); return; } // we only received the header, no data if (recv_buffer.left() == 0) break; if (recv_buffer.left() < front_request.length) break; // if the response is chunked, we need to receive the last // terminating chunk and the tail headers before we can proceed if (m_parser.chunked_encoding() && m_chunk_pos >= 0) break; m_requests.pop_front(); incoming_piece(front_request, recv_buffer.begin); if (associated_torrent().expired()) return; int size_to_cut = m_body_start + front_request.length; TORRENT_ASSERT(receive_buffer().left() < size_to_cut + 1 || receive_buffer()[size_to_cut] == 'H' || (m_parser.chunked_encoding() && receive_buffer()[size_to_cut] == '\r')); cut_receive_buffer(size_to_cut, t->block_size() + 1024); if (m_response_left == 0) m_chunk_pos = 0; else m_chunk_pos -= front_request.length; bytes_transferred -= payload; m_body_start = 0; if (m_response_left > 0) continue; TORRENT_ASSERT(m_response_left == 0); m_parser.reset(); } }
void on_udp_receive(error_code const& ec, size_t bytes_transferred, udp::endpoint* from, char* buffer, int size) { if (ec) { fprintf(stderr, "%s: UDP tracker, read failed: %s\n", time_now_string(), ec.message().c_str()); return; } if (bytes_transferred < 16) { fprintf(stderr, "%s: UDP message too short (from: %s)\n", time_now_string(), print_endpoint(*from).c_str()); return; } fprintf(stderr, "%s: UDP message %d bytes\n", time_now_string(), int(bytes_transferred)); char* ptr = buffer; detail::read_uint64(ptr); boost::uint32_t action = detail::read_uint32(ptr); boost::uint32_t transaction_id = detail::read_uint32(ptr); error_code e; switch (action) { case 0: // connect fprintf(stderr, "%s: UDP connect from %s\n", time_now_string() , print_endpoint(*from).c_str()); ptr = buffer; detail::write_uint32(0, ptr); // action = connect detail::write_uint32(transaction_id, ptr); // transaction_id detail::write_uint64(10, ptr); // connection_id m_socket.send_to(asio::buffer(buffer, 16), *from, 0, e); if (e) fprintf(stderr, "%s: UDP send_to failed. ERROR: %s\n" , time_now_string(), e.message().c_str()); else fprintf(stderr, "%s: UDP sent response to: %s\n" , time_now_string(), print_endpoint(*from).c_str()); break; case 1: // announce ++m_udp_announces; fprintf(stderr, "%s: UDP announce [%d]\n", time_now_string() , int(m_udp_announces)); ptr = buffer; detail::write_uint32(1, ptr); // action = announce detail::write_uint32(transaction_id, ptr); // transaction_id detail::write_uint32(1800, ptr); // interval detail::write_uint32(1, ptr); // incomplete detail::write_uint32(1, ptr); // complete // 0 peers m_socket.send_to(asio::buffer(buffer, 20), *from, 0, e); if (e) fprintf(stderr, "%s: UDP send_to failed. ERROR: %s\n" , time_now_string(), e.message().c_str()); else fprintf(stderr, "%s: UDP sent response to: %s\n" , time_now_string(), print_endpoint(*from).c_str()); break; case 2: // ignore scrapes fprintf(stderr, "%s: UDP scrape (ignored)\n", time_now_string()); break; default: fprintf(stderr, "%s: UDP unknown message: %d\n", time_now_string() , action); break; } m_socket.async_receive_from( asio::buffer(buffer, size), *from, 0 , boost::bind(&udp_tracker::on_udp_receive, this, _1, _2, from, buffer, size)); }
void Client::printErrorCode(const error_code &ec, const std::string& method) { warnlog << "[" << method << "] Error Code: " << ec.value() << ", message: " << ec.message(); }
void handle_sent(const error_code& ec, std::size_t) { // here response has been sent if (ec) { std::cout << "Error sending response to " << remote_endpoint_ << ": " << ec.message() << "\n"; } }
// throws exception when the client should be disconnected void web_peer_connection::on_receive(error_code const& error , std::size_t bytes_transferred) { INVARIANT_CHECK; if (error) { #ifdef TORRENT_VERBOSE_LOGGING (*m_logger) << "*** web_peer_connection error: " << error.message() << "\n"; #endif return; } boost::shared_ptr<torrent> t = associated_torrent().lock(); TORRENT_ASSERT(t); incoming_piece_fragment(); for (;;) { buffer::const_interval recv_buffer = receive_buffer(); int payload; int protocol; bool header_finished = m_parser.header_finished(); if (!header_finished) { boost::tie(payload, protocol) = m_parser.incoming(recv_buffer); m_statistics.received_bytes(0, protocol); bytes_transferred -= protocol; TORRENT_ASSERT(recv_buffer.left() == 0 || *recv_buffer.begin == 'H'); TORRENT_ASSERT(recv_buffer.left() <= packet_size()); // this means the entire status line hasn't been received yet if (m_parser.status_code() == -1) { TORRENT_ASSERT(payload == 0); TORRENT_ASSERT(bytes_transferred == 0); break; } // if the status code is not one of the accepted ones, abort if (m_parser.status_code() != 206 // partial content && m_parser.status_code() != 200 // OK && !(m_parser.status_code() >= 300 // redirect && m_parser.status_code() < 400)) { if (m_parser.status_code() == 503) { // temporarily unavailable, retry later t->retry_url_seed(m_url); } t->remove_url_seed(m_url); std::string error_msg = boost::lexical_cast<std::string>(m_parser.status_code()) + " " + m_parser.message(); if (m_ses.m_alerts.should_post(alert::warning)) { session_impl::mutex_t::scoped_lock l(m_ses.m_mutex); m_ses.m_alerts.post_alert(url_seed_alert(t->get_handle(), url() , error_msg)); } throw std::runtime_error(error_msg); } if (!m_parser.header_finished()) { TORRENT_ASSERT(payload == 0); TORRENT_ASSERT(bytes_transferred == 0); break; } m_body_start = m_parser.body_start(); m_received_body = 0; } // we just completed reading the header if (!header_finished) { if (m_parser.status_code() >= 300 && m_parser.status_code() < 400) { // this means we got a redirection request // look for the location header std::string location = m_parser.header("location"); if (location.empty()) { // we should not try this server again. t->remove_url_seed(m_url); throw std::runtime_error("got HTTP redirection status without location header"); } bool single_file_request = false; if (!m_path.empty() && m_path[m_path.size() - 1] != '/') single_file_request = true; // add the redirected url and remove the current one if (!single_file_request) { TORRENT_ASSERT(!m_file_requests.empty()); int file_index = m_file_requests.front(); torrent_info const& info = t->torrent_file(); std::string path = info.file_at(file_index).path.string(); path = escape_path(path.c_str(), path.length()); size_t i = location.rfind(path); if (i == std::string::npos) { t->remove_url_seed(m_url); throw std::runtime_error("got invalid HTTP redirection location (\"" + location + "\") " "expected it to end with: " + path); } location.resize(i); } t->add_url_seed(location); t->remove_url_seed(m_url); throw std::runtime_error("redirecting to " + location); } std::string const& server_version = m_parser.header("server"); if (!server_version.empty()) { m_server_string = "URL seed @ "; m_server_string += m_host; m_server_string += " ("; m_server_string += server_version; m_server_string += ")"; } m_body_start = m_parser.body_start(); m_received_body = 0; m_range_pos = 0; } recv_buffer.begin += m_body_start; // we only received the header, no data if (recv_buffer.left() == 0) break; size_type range_start; size_type range_end; if (m_parser.status_code() == 206) { std::stringstream range_str(m_parser.header("content-range")); char dummy; std::string bytes; range_str >> bytes >> range_start >> dummy >> range_end; if (!range_str) { // we should not try this server again. t->remove_url_seed(m_url); throw std::runtime_error("invalid range in HTTP response: " + range_str.str()); } // the http range is inclusive range_end++; } else {
void lsd::announce_impl(sha1_hash const& ih, int listen_port, bool broadcast , int retry_count) { #if TORRENT_USE_IPV6 if (m_disabled && m_disabled6) return; #else if (m_disabled) return; #endif char ih_hex[41]; to_hex((char const*)&ih[0], 20, ih_hex); char msg[200]; #ifndef TORRENT_DISABLE_LOGGING debug_log("==> LSD: ih: %s port: %u\n", ih_hex, listen_port); #endif error_code ec; if (!m_disabled) { int msg_len = render_lsd_packet(msg, sizeof(msg), listen_port, ih_hex , m_cookie, "239.192.152.143"); m_socket.send(msg, msg_len, ec, broadcast ? broadcast_socket::broadcast : 0); if (ec) { m_disabled = true; #ifndef TORRENT_DISABLE_LOGGING debug_log("*** LSD: failed to send message: (%d) %s", ec.value() , ec.message().c_str()); #endif } } #if TORRENT_USE_IPV6 if (!m_disabled6) { int msg_len = render_lsd_packet(msg, sizeof(msg), listen_port, ih_hex , m_cookie, "[ff15::efc0:988f]"); m_socket6.send(msg, msg_len, ec, broadcast ? broadcast_socket::broadcast : 0); if (ec) { m_disabled6 = true; #ifndef TORRENT_DISABLE_LOGGING debug_log("*** LSD: failed to send message6: (%d) %s", ec.value() , ec.message().c_str()); #endif } } #endif ++retry_count; if (retry_count >= 3) return; #if TORRENT_USE_IPV6 if (m_disabled && m_disabled6) return; #else if (m_disabled) return; #endif #if defined TORRENT_ASIO_DEBUGGING add_outstanding_async("lsd::resend_announce"); #endif m_broadcast_timer.expires_from_now(seconds(2 * retry_count), ec); m_broadcast_timer.async_wait(boost::bind(&lsd::resend_announce, self(), _1 , ih, listen_port, retry_count)); }
static inline void print_error(char const * title, error_code const & ec) { LOG_ERROR(title << ": " << ec.message()); }