merged utp_socket and simultaneous connections fix from RC_0_16

This commit is contained in:
Arvid Norberg 2012-10-10 04:40:18 +00:00
parent 09d7a49ad7
commit 3555b01b85
5 changed files with 115 additions and 11 deletions

View File

@ -5,6 +5,8 @@
* fix uTP edge case where udp socket buffer fills up
* fix nagle implementation in uTP
* consistently disconnect the same peer when two peers simultaneously connect
* fix local endpoint queries for uTP connections
* small optimization to local peer discovery to ignore our own broadcasts
* try harder to bind the udp socket (uTP, DHT, UDP-trackers, LSD) to the same port as TCP
* relax file timestamp requirements for accepting resume data

View File

@ -65,7 +65,8 @@ namespace libtorrent
void tick(ptime now);
tcp::endpoint local_endpoint(error_code& ec) const;
tcp::endpoint local_endpoint(address const& remote, error_code& ec) const;
int local_port(error_code& ec) const;
// flags for send_packet
enum { dont_fragment = 1 };

View File

@ -871,20 +871,66 @@ namespace libtorrent
i->connection->disconnect(ec2);
TORRENT_ASSERT(i->connection == 0);
}
else if (!i->connection->is_connecting() || c.is_outgoing())
else if (i->connection->is_outgoing() == c.is_outgoing())
{
// if the other end connected to us both times, just drop
// the second one. Or if we made both connections.
c.disconnect(errors::duplicate_peer_id);
return false;
}
else
{
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING
m_torrent->debug_log("duplicate connection. existing connection"
" is connecting and this connection is incoming. closing existing "
"connection in favour of this one");
// at this point, we need to disconnect either
// i->connection or c. In order for both this client
// and the client on the other end to decide to
// disconnect the same one, we need a consistent rule to
// select which one.
bool outgoing1 = c.is_outgoing();
// for this, we compare our endpoints (IP and port)
// and whoever has the lower IP,port should be the
// one keeping its outgoing connection. Since outgoing
// ports are selected at random by the OS, we need
// to be careful to only look at the target end of a
// connection for the endpoint.
tcp::endpoint our_ep = outgoing1 ? other_socket->local_endpoint(ec1) : this_socket->local_endpoint(ec1);
tcp::endpoint other_ep = outgoing1 ? this_socket->remote_endpoint(ec1) : other_socket->remote_endpoint(ec1);
if (our_ep < other_ep)
{
#ifdef TORRENT_VERBOSE_LOGGING
c.peer_log("*** DUPLICATE PEER RESOLUTION [ \"%s\" < \"%s\" ]"
, print_endpoint(our_ep).c_str(), print_endpoint(other_ep).c_str());
i->connection->peer_log("*** DUPLICATE PEER RESOLUTION [ \"%s\" < \"%s\" ]"
, print_endpoint(our_ep).c_str(), print_endpoint(other_ep).c_str());
#endif
i->connection->disconnect(errors::duplicate_peer_id);
TORRENT_ASSERT(i->connection == 0);
// we should keep our outgoing connection
if (!outgoing1)
{
c.disconnect(errors::duplicate_peer_id);
return false;
}
i->connection->disconnect(errors::duplicate_peer_id);
}
else
{
#ifdef TORRENT_VERBOSE_LOGGING
c.peer_log("*** DUPLICATE PEER RESOLUTION [ \"%s\" >= \"%s\" ]"
, print_endpoint(our_ep).c_str(), print_endpoint(other_ep).c_str());
i->connection->peer_log("*** DUPLICATE PEER RESOLUTION [ \"%s\" >= \"%s\" ]"
, print_endpoint(our_ep).c_str(), print_endpoint(other_ep).c_str());
#endif
// they should keep their outgoing connection
if (outgoing1)
{
c.disconnect(errors::duplicate_peer_id);
return false;
}
i->connection->disconnect(errors::duplicate_peer_id);
}
}
}

View File

@ -194,9 +194,55 @@ namespace libtorrent
#endif
}
tcp::endpoint utp_socket_manager::local_endpoint(error_code& ec) const
int utp_socket_manager::local_port(error_code& ec) const
{
return m_sock.local_endpoint(ec);
return m_sock.local_endpoint(ec).port();
}
tcp::endpoint utp_socket_manager::local_endpoint(address const& remote, error_code& ec) const
{
tcp::endpoint socket_ep = m_sock.local_endpoint(ec);
// first enumerate the routes in the routing table
std::vector<ip_route> routes = enum_routes(m_sock.get_io_service(), ec);
if (ec) return socket_ep;
if (routes.empty()) return socket_ep;
// then find the best match
ip_route* best = &routes[0];
for (std::vector<ip_route>::iterator i = routes.begin()
, end(routes.end()); i != end; ++i)
{
if (is_any(i->destination) && i->destination.is_v4() == remote.is_v4())
{
best = &*i;
continue;
}
if (match_addr_mask(remote, i->destination, i->netmask))
{
best = &*i;
continue;
}
}
// best now tells us which interface we would send over
// for this target. Now figure out what the local address
// is for that interface
std::vector<ip_interface> net = enum_net_interfaces(m_sock.get_io_service(), ec);
if (ec) return socket_ep;
for (std::vector<ip_interface>::iterator i = net.begin()
, end(net.end()); i != end; ++i)
{
if (i->interface_address.is_v4() != remote.is_v4())
continue;
if (strcmp(best->name, i->name) == 0)
return tcp::endpoint(i->interface_address, socket_ep.port());
}
return socket_ep;
}
bool utp_socket_manager::incoming_packet(error_code const& ec, udp::endpoint const& ep

View File

@ -398,6 +398,9 @@ struct utp_socket_impl
// the address of the remote endpoint
address m_remote_address;
// the local address
address m_local_address;
// the send and receive buffers
// maps packet sequence numbers
packet_buffer m_inbuf;
@ -789,7 +792,7 @@ utp_stream::endpoint_type utp_stream::local_endpoint(error_code& ec) const
ec = asio::error::not_connected;
return endpoint_type();
}
return m_impl->m_sm->local_endpoint(ec);
return tcp::endpoint(m_impl->m_local_address, m_impl->m_sm->local_port(ec));
}
utp_stream::~utp_stream()
@ -1063,6 +1066,9 @@ void utp_stream::do_connect(tcp::endpoint const& ep, utp_stream::connect_handler
m_impl->m_port = ep.port();
m_impl->m_connect_handler = handler;
error_code ec;
m_impl->m_local_address = m_impl->m_sm->local_endpoint(m_impl->m_remote_address, ec).address();
if (m_impl->test_socket_state()) return;
m_impl->send_syn();
}
@ -2710,6 +2716,9 @@ bool utp_socket_impl::incoming_packet(boost::uint8_t const* buf, int size
m_remote_address = ep.address();
m_port = ep.port();
error_code ec;
m_local_address = m_sm->local_endpoint(m_remote_address, ec).address();
m_ack_nr = ph->seq_nr;
m_seq_nr = random();
m_acked_seq_nr = (m_seq_nr - 1) & ACK_MASK;