diff --git a/libtorrent/rak/socket_address.h b/libtorrent/rak/socket_address.h index b4600637..961c53b2 100644 --- a/libtorrent/rak/socket_address.h +++ b/libtorrent/rak/socket_address.h @@ -127,9 +127,6 @@ class socket_address { static socket_address* cast_from(sockaddr* sa) { return reinterpret_cast(sa); } static const socket_address* cast_from(const sockaddr* sa) { return reinterpret_cast(sa); } - - static socket_address_inet* cast_from_in(sockaddr_in* sa) { return reinterpret_cast(sa); } - static const socket_address_inet* cast_from_in(const sockaddr_in* sa) { return reinterpret_cast(sa); } // The different families will be sorted according to the // sa_family_t's numeric value. @@ -164,9 +161,7 @@ class socket_address_inet { uint16_t port_n() const { return m_sockaddr.sin_port; } void set_port(uint16_t p) { m_sockaddr.sin_port = htons(p); } void set_port_n(uint16_t p) { m_sockaddr.sin_port = p; } - - uint32_t length() const { return sizeof(sockaddr_in); } - + // Should address() return the uint32_t? in_addr address() const { return m_sockaddr.sin_addr; } uint32_t address_h() const { return ntohl(m_sockaddr.sin_addr.s_addr); } diff --git a/libtorrent/src/net/socket_datagram.cc b/libtorrent/src/net/socket_datagram.cc index 7d8d3166..e7c5e1a5 100644 --- a/libtorrent/src/net/socket_datagram.cc +++ b/libtorrent/src/net/socket_datagram.cc @@ -86,38 +86,4 @@ SocketDatagram::write_datagram(const void* buffer, unsigned int length, rak::soc return r; } -int -SocketDatagram::read_datagram_inet(void* buffer, unsigned int length, rak::socket_address_inet* sa) { - if (length == 0) - throw internal_error("Tried to receive buffer length 0"); - - int r; - socklen_t fromlen; - - if (sa != NULL) { - fromlen = sizeof(rak::socket_address); - r = ::recvfrom(m_fileDesc, buffer, length, 0, sa->c_sockaddr(), &fromlen); - } else { - r = ::recv(m_fileDesc, buffer, length, 0); - } - - return r; -} - -int -SocketDatagram::write_datagram_inet(const void* buffer, unsigned int length, rak::socket_address_inet* sa) { - if (length == 0) - throw internal_error("Tried to send buffer length 0"); - - int r; - - if (sa != NULL) { - r = ::sendto(m_fileDesc, buffer, length, 0, sa->c_sockaddr(), sa->length()); - } else { - r = ::send(m_fileDesc, buffer, length, 0); - } - - return r; -} - } diff --git a/libtorrent/src/net/socket_datagram.h b/libtorrent/src/net/socket_datagram.h index de477f75..47649f55 100644 --- a/libtorrent/src/net/socket_datagram.h +++ b/libtorrent/src/net/socket_datagram.h @@ -48,9 +48,6 @@ class SocketDatagram : public SocketBase { // used. int read_datagram(void* buffer, unsigned int length, rak::socket_address* sa = NULL); int write_datagram(const void* buffer, unsigned int length, rak::socket_address* sa = NULL); - - int read_datagram_inet(void* buffer, unsigned int length, rak::socket_address_inet* sa = NULL); - int write_datagram_inet(const void* buffer, unsigned int length, rak::socket_address_inet* sa = NULL); }; } diff --git a/libtorrent/src/torrent/connection_manager.cc b/libtorrent/src/torrent/connection_manager.cc index ebf6dd53..f1a5778a 100644 --- a/libtorrent/src/torrent/connection_manager.cc +++ b/libtorrent/src/torrent/connection_manager.cc @@ -61,7 +61,7 @@ class UdnsAsyncResolver : public AsyncResolver { public: UdnsAsyncResolver(ConnectionManager *cm) : AsyncResolver(cm) {} - void *enqueue(const char *name, int family, async_resolver_callback *cbck) { + void *enqueue(const char *name, int family, resolver_callback *cbck) { return m_udnsevent.enqueue_resolve(name, family, cbck); } @@ -83,12 +83,12 @@ class StubAsyncResolver : public AsyncResolver { struct mock_resolve { std::string hostname; int family; - async_resolver_callback *callback; + resolver_callback *callback; }; StubAsyncResolver(ConnectionManager *cm): AsyncResolver(cm), m_connection_manager(cm) {} - void *enqueue(const char *name, int family, async_resolver_callback *cbck) { + void *enqueue(const char *name, int family, resolver_callback *cbck) { mock_resolve *mr = new mock_resolve {name, family, cbck}; m_mock_resolve_queue.emplace_back(mr); return mr; diff --git a/libtorrent/src/torrent/connection_manager.h b/libtorrent/src/torrent/connection_manager.h index 8b1ff507..bed441ca 100644 --- a/libtorrent/src/torrent/connection_manager.h +++ b/libtorrent/src/torrent/connection_manager.h @@ -57,8 +57,7 @@ typedef std::pair ThrottlePair; // The sockaddr argument in the result call is NULL if the resolve failed, // and the int holds the error code. -typedef std::function resolver_callback; -typedef std::function async_resolver_callback; +typedef std::function resolver_callback; // Encapsulates whether we do genuine async resolution or fall back to sync. // In a build with USE_UDNS, these do genuine asynchronous DNS resolution. @@ -71,7 +70,7 @@ class LIBTORRENT_EXPORT AsyncResolver { // this queues a DNS resolve but doesn't send it. it doesn't execute any callbacks // and returns control immediately. the return value is an opaque identifier that // can be used to cancel the query (as long as the callback hasn't been executed yet): - virtual void* enqueue(const char *name, int family, async_resolver_callback *cbck) = 0; + virtual void* enqueue(const char *name, int family, resolver_callback *cbck) = 0; // this sends any queued resolves. it can execute arbitrary callbacks // before returning control: virtual void flush() = 0; @@ -179,7 +178,7 @@ class LIBTORRENT_EXPORT ConnectionManager { void set_listen_port(port_type p) { m_listen_port = p; } void set_listen_backlog(int v); - void* enqueue_async_resolve(const char *name, int family, async_resolver_callback *cbck); + void* enqueue_async_resolve(const char *name, int family, resolver_callback *cbck); void flush_async_resolves(); void cancel_async_resolve(void *query); diff --git a/libtorrent/src/tracker/tracker_udp.cc b/libtorrent/src/tracker/tracker_udp.cc index 2a0b2411..e50b51bd 100644 --- a/libtorrent/src/tracker/tracker_udp.cc +++ b/libtorrent/src/tracker/tracker_udp.cc @@ -107,13 +107,13 @@ TrackerUdp::send_state(int state) { } void -TrackerUdp::start_announce(const sockaddr_in* sa, int err) { +TrackerUdp::start_announce(const sockaddr* sa, int err) { m_resolver_query = NULL; if (sa == NULL) return receive_failed("could not resolve hostname"); - m_connectAddress = *rak::socket_address::cast_from_in(sa); + m_connectAddress = *rak::socket_address::cast_from(sa); m_connectAddress.set_port(m_port); LT_LOG_TRACKER(DEBUG, "address found (address:%s)", m_connectAddress.address_str().c_str()); @@ -209,8 +209,9 @@ TrackerUdp::receive_timeout() { void TrackerUdp::event_read() { - rak::socket_address_inet sa; - int s = read_datagram_inet(m_readBuffer->begin(), m_readBuffer->reserved(), &sa); + rak::socket_address sa; + + int s = read_datagram(m_readBuffer->begin(), m_readBuffer->reserved(), &sa); if (s < 0) return; @@ -261,7 +262,7 @@ TrackerUdp::event_write() { if (m_writeBuffer->size_end() == 0) throw internal_error("TrackerUdp::write() called but the write buffer is empty."); - int __UNUSED s = write_datagram_inet(m_writeBuffer->begin(), m_writeBuffer->size_end(), &m_connectAddress); + int __UNUSED s = write_datagram(m_writeBuffer->begin(), m_writeBuffer->size_end(), &m_connectAddress); manager->poll()->remove_write(this); } diff --git a/libtorrent/src/tracker/tracker_udp.h b/libtorrent/src/tracker/tracker_udp.h index ad2e260b..d0be6376 100644 --- a/libtorrent/src/tracker/tracker_udp.h +++ b/libtorrent/src/tracker/tracker_udp.h @@ -82,7 +82,7 @@ class TrackerUdp : public SocketDatagram, public Tracker { void receive_failed(const std::string& msg); void receive_timeout(); - void start_announce(const sockaddr_in* sa, int err); + void start_announce(const sockaddr* sa, int err); void prepare_connect_input(); void prepare_announce_input(); @@ -93,13 +93,13 @@ class TrackerUdp : public SocketDatagram, public Tracker { bool parse_udp_url(const std::string& url, hostname_type& hostname, int& port) const; - rak::socket_address_inet m_connectAddress; + rak::socket_address m_connectAddress; int m_port; std::string m_hostname; int m_sendState; - async_resolver_callback m_resolver_callback; + resolver_callback m_resolver_callback; void* m_resolver_query; uint32_t m_action; diff --git a/libtorrent/src/utils/udnsevent.cc b/libtorrent/src/utils/udnsevent.cc index 0d7242af..e603d76c 100644 --- a/libtorrent/src/utils/udnsevent.cc +++ b/libtorrent/src/utils/udnsevent.cc @@ -57,11 +57,37 @@ void a4_callback_wrapper(struct ::dns_ctx *ctx, ::dns_rr_a4 *result, void *data) if (query->a6_query != NULL) { ::dns_cancel(ctx, query->a6_query); } - if (*query->callback) { (*query->callback)(static_cast(&sa), 0); } + if (*query->callback) { (*query->callback)(reinterpret_cast(&sa), 0); } delete query; } } +void a6_callback_wrapper(struct ::dns_ctx *ctx, ::dns_rr_a6 *result, void *data) { + struct sockaddr_in6 sa; + udns_query *query = static_cast(data); + // udns will free the a6_query after this callback exits + query->a6_query = NULL; + + if (result == NULL || result->dnsa6_nrr == 0) { + if (query->a4_query == NULL) { + // nothing more to do: call the callback with a failure status + (*(query->callback))(NULL, udnserror_to_gaierror(::dns_status(ctx))); + delete query; + } + // else: return and wait to see if we get an a6 response + } else { + sa.sin6_family = AF_INET6; + sa.sin6_port = 0; + sa.sin6_addr = result->dnsa6_addr[0]; + if (query->a4_query != NULL) { + ::dns_cancel(ctx, query->a4_query); + } + (*query->callback)(reinterpret_cast(&sa), 0); + delete query; + } +} + + UdnsEvent::UdnsEvent() { // reinitialize the default context, no-op // TODO don't do this here --- do it once in the manager, or in rtorrent @@ -95,7 +121,7 @@ void UdnsEvent::event_write() { void UdnsEvent::event_error() { } -struct udns_query *UdnsEvent::enqueue_resolve(const char *name, int family, async_resolver_callback *callback) { +struct udns_query *UdnsEvent::enqueue_resolve(const char *name, int family, resolver_callback *callback) { struct udns_query *query = new udns_query { NULL, NULL, callback, 0 }; if (family == AF_INET || family == AF_UNSPEC) { @@ -117,6 +143,21 @@ struct udns_query *UdnsEvent::enqueue_resolve(const char *name, int family, asyn } } + if (family == AF_INET6) { + query->a6_query = ::dns_submit_a6(m_ctx, name, 0, a6_callback_wrapper, query); + if (query->a6_query == NULL) { + // it should be impossible for dns_submit_a6 to fail if dns_submit_a4 + // succeeded, but just in case, make it a hard failure: + if (::dns_status(m_ctx) == DNS_E_BADQUERY && query->a4_query == NULL) { + query->error = EAI_NONAME; + m_malformed_queries.push_back(query); + return query; + } else { + throw new internal_error("dns_submit_a6 failed"); + } + } + } + return query; } diff --git a/libtorrent/src/utils/udnsevent.h b/libtorrent/src/utils/udnsevent.h index 42d5dce0..f214814e 100644 --- a/libtorrent/src/utils/udnsevent.h +++ b/libtorrent/src/utils/udnsevent.h @@ -18,7 +18,7 @@ namespace torrent { struct udns_query { ::dns_query *a4_query; ::dns_query *a6_query; - async_resolver_callback *callback; + resolver_callback *callback; int error; }; @@ -37,7 +37,7 @@ class UdnsEvent : public Event { // wraps udns's dns_submit_a[46] functions. they and it return control immediately, // without either sending outgoing UDP packets or executing callbacks: - udns_query* enqueue_resolve(const char *name, int family, async_resolver_callback *callback); + udns_query* enqueue_resolve(const char *name, int family, resolver_callback *callback); // wraps the dns_timeouts function. it sends packets and can execute arbitrary // callbacks: void flush_resolves();