Skip to content

Commit 6761a8e

Browse files
committed
Never use the resolver to "resolve" something that is already an IP address.
The resolver in boost::asio is by default a single-threaded pseudo-async thing, so while it is blocked by a lengthy lookup, no further lookups can proceed. If we use the resolver even if we have a perfectly good IP address to start with, we can get blocked by DNS resolution even if we don't need resolving at all...
1 parent 8fd8b27 commit 6761a8e

File tree

9 files changed

+57
-20
lines changed

9 files changed

+57
-20
lines changed

faucet/IpLookup.cpp

+4-6
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,15 @@
77
using namespace boost::asio::ip;
88
std::shared_ptr<IpLookup> IpLookup::lookup(const char *lookup) {
99
std::shared_ptr<IpLookup> ipLookup (new IpLookup());
10-
tcp::resolver::query query(lookup, "", tcp::resolver::query::address_configured);
11-
ipLookup->resolver_.async_resolve(query, boost::bind(&IpLookup::handleResolve,
10+
fct_async_resolve<tcp>(lookup, 0, ipLookup->resolver_, boost::bind(&IpLookup::handleResolve,
1211
ipLookup, boost::asio::placeholders::error, boost::asio::placeholders::iterator));
1312
return ipLookup;
1413
}
1514

16-
std::shared_ptr<IpLookup> IpLookup::lookup(const char *lookup, const tcp::resolver::protocol_type &protocol) {
15+
std::shared_ptr<IpLookup> IpLookup::lookup(const char *lookup, fct_lookup_protocol protocol) {
1716
std::shared_ptr<IpLookup> ipLookup (new IpLookup());
18-
tcp::resolver::query query(protocol, lookup, "", tcp::resolver::query::address_configured);
19-
ipLookup->resolver_.async_resolve(query, boost::bind(&IpLookup::handleResolve,
20-
ipLookup, boost::asio::placeholders::error, boost::asio::placeholders::iterator));
17+
fct_async_resolve<tcp>(lookup, 0, ipLookup->resolver_, boost::bind(&IpLookup::handleResolve,
18+
ipLookup, boost::asio::placeholders::error, boost::asio::placeholders::iterator), protocol);
2119
return ipLookup;
2220
}
2321

faucet/IpLookup.hpp

+3-1
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,13 @@
88
#include <string>
99
#include <memory>
1010

11+
#include <faucet/resolve.hpp>
12+
1113
class IpLookup: public Handled,
1214
boost::noncopyable {
1315
public:
1416
static std::shared_ptr<IpLookup> lookup(const char *lookup);
15-
static std::shared_ptr<IpLookup> lookup(const char *lookup, const boost::asio::ip::tcp::resolver::protocol_type &protocol);
17+
static std::shared_ptr<IpLookup> lookup(const char *lookup, fct_lookup_protocol protocol);
1618

1719
bool ready();
1820
bool hasNext();

faucet/resolve.hpp

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
#pragma once
2+
3+
#include <faucet/Asio.hpp>
4+
#include <string>
5+
#include <functional>
6+
#include <boost/lexical_cast.hpp>
7+
8+
enum class fct_lookup_protocol {V4, V6, ANY};
9+
10+
template <typename InternetProtocol>
11+
void fct_async_resolve(std::string host, uint16_t port, typename InternetProtocol::resolver &resolver, std::function<void(const boost::system::error_code&, typename InternetProtocol::resolver::iterator)> handleResolve) {
12+
fct_async_resolve<InternetProtocol>(host, port, resolver, handleResolve, fct_lookup_protocol::ANY);
13+
}
14+
15+
/**
16+
* Wrapper around resolver::async_resolve which will first attempt to interpret the hostname as a literal IP address.
17+
* If it can be parsed this way, the handler function will be called synchronously.
18+
*/
19+
template <typename InternetProtocol>
20+
void fct_async_resolve(std::string host, uint16_t port, typename InternetProtocol::resolver &resolver, std::function<void(const boost::system::error_code&, typename InternetProtocol::resolver::iterator)> handleResolve, fct_lookup_protocol protocol) {
21+
boost::system::error_code ec;
22+
typename InternetProtocol::endpoint endpoint(boost::asio::ip::address::from_string(host, ec), port);
23+
24+
if(!ec) {
25+
if((protocol == fct_lookup_protocol::V4 && endpoint.address().is_v4()) || (protocol == fct_lookup_protocol::V6 && endpoint.address().is_v6()) || protocol == fct_lookup_protocol::ANY) {
26+
handleResolve(ec, InternetProtocol::resolver::iterator::create(endpoint, "", ""));
27+
} else {
28+
handleResolve(ec, typename InternetProtocol::resolver::iterator());
29+
}
30+
} else {
31+
std::string portStr(boost::lexical_cast<std::string>(port));
32+
typename InternetProtocol::resolver::query::flags flags(InternetProtocol::resolver::query::numeric_service | InternetProtocol::resolver::query::address_configured);
33+
typename InternetProtocol::resolver::query query([&](){
34+
if(protocol == fct_lookup_protocol::ANY) {
35+
return typename InternetProtocol::resolver::query(host, portStr, flags);
36+
} else {
37+
return typename InternetProtocol::resolver::query((protocol == fct_lookup_protocol::V4) ? InternetProtocol::v4() : InternetProtocol::v6(), host, portStr, flags);
38+
}
39+
}());
40+
41+
resolver.async_resolve(query, handleResolve);
42+
}
43+
}

faucet/socketApi.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -799,12 +799,12 @@ DLLEXPORT double ip_lookup_create(const char *host) {
799799

800800
DLLEXPORT double ipv4_lookup_create(const char *host) {
801801
MutexLock lock(*apiMutex);
802-
return handles.allocate(IpLookup::lookup(host, boost::asio::ip::tcp::v4()));
802+
return handles.allocate(IpLookup::lookup(host, fct_lookup_protocol::V4));
803803
}
804804

805805
DLLEXPORT double ipv6_lookup_create(const char *host) {
806806
MutexLock lock(*apiMutex);
807-
return handles.allocate(IpLookup::lookup(host, boost::asio::ip::tcp::v6()));
807+
return handles.allocate(IpLookup::lookup(host, fct_lookup_protocol::V6));
808808
}
809809

810810
DLLEXPORT double ip_lookup_ready(double lookupHandle) {

faucet/tcp/connectionStates/TcpConnecting.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
#include <boost/bind.hpp>
77
#include <boost/thread/locks.hpp>
88

9+
#include <faucet/resolve.hpp>
10+
911
using namespace boost::asio::ip;
1012

1113
TcpConnecting::TcpConnecting(TcpSocket &socket) :
@@ -16,9 +18,7 @@ TcpConnecting::TcpConnecting(TcpSocket &socket) :
1618
}
1719

1820
void TcpConnecting::enter(const char *host, uint16_t port) {
19-
tcp::resolver::query query(host, boost::lexical_cast<std::string>(port),
20-
tcp::resolver::query::numeric_service | tcp::resolver::query::address_configured);
21-
resolver.async_resolve(query, boost::bind(&TcpConnecting::handleResolve,
21+
fct_async_resolve<tcp>(host, port, resolver, boost::bind(&TcpConnecting::handleResolve,
2222
this, socket->shared_from_this(), boost::asio::placeholders::error,
2323
boost::asio::placeholders::iterator));
2424
}

faucet/udp/UdpSocket.cpp

+2-8
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include "UdpSocket.hpp"
22

33
#include "broadcastAddrs.hpp"
4+
#include <faucet/resolve.hpp>
45

56
#include <boost/lexical_cast.hpp>
67
#include <boost/make_shared.hpp>
@@ -242,15 +243,8 @@ void UdpSocket::asyncSend() {
242243
sendqueue_.pop();
243244
asyncSendInProgress_ = true;
244245

245-
boost::system::error_code ec;
246-
udp::endpoint endpoint(address::from_string(item.remoteHost, ec), item.remotePort);
247-
if(!ec) {
248-
handleResolve(ec, udp::resolver::iterator::create(endpoint, "", ""), item.buffer);
249-
} else {
250-
udp::resolver::query query(item.remoteHost, boost::lexical_cast<std::string>(item.remotePort), udp::resolver::query::numeric_service | udp::resolver::query::address_configured);
251-
resolver_.async_resolve(query, boost::bind(&UdpSocket::handleResolve, shared_from_this(),
246+
fct_async_resolve<udp>(item.remoteHost, item.remotePort, resolver_, boost::bind(&UdpSocket::handleResolve, shared_from_this(),
252247
boost::asio::placeholders::error, boost::asio::placeholders::iterator, item.buffer));
253-
}
254248
}
255249

256250
udp::socket *UdpSocket::getAppropriateSocket(const udp::endpoint &endpoint) {

faucetnet.ged

0 Bytes
Binary file not shown.

fct_faucetnet.ged

0 Bytes
Binary file not shown.

help.pdf

-167 KB
Binary file not shown.

0 commit comments

Comments
 (0)