summaryrefslogtreecommitdiffstats
path: root/src/OSSupport/HostnameLookup.cpp
blob: ee9610f639be9a8f79d1ec942b9d6f873453e028 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117

// HostnameLookup.cpp

// Implements the cHostnameLookup class representing an in-progress hostname-to-IP lookup

#include "Globals.h"
#include "HostnameLookup.h"
#include "NetworkSingleton.h"
#include "GetAddressInfoError.h"





////////////////////////////////////////////////////////////////////////////////
// cHostnameLookup:

void cHostnameLookup::Lookup(
	const AString & a_Hostname, cNetwork::cResolveNameCallbacksPtr a_Callbacks)
{
	// Note the Lookup object is owned solely by this lambda which is destroyed
	// after it runs
	cNetworkSingleton::Get().GetLookupThread().async_resolve(
		a_Hostname, "",
		[Callbacks = std::move(a_Callbacks)](const auto & a_Error, const auto & a_Results)
		{
			// If an error has occurred, notify the error callback:
			if (a_Error)
			{
				Callbacks->OnError(a_Error.value(), a_Error.message());
				return;
			}

			Callback(*Callbacks.get(), a_Results);
		}
	);
}





void cHostnameLookup::Callback(cNetwork::cResolveNameCallbacks & a_Callbacks, const asio::ip::tcp::resolver::results_type & a_Addr)
{
	// Call the success handler for each entry received:
	bool HasResolved = false;

	for (const auto & Addr : a_Addr)
	{
		const auto & Endpoint = Addr.endpoint();
		const auto & Address = Endpoint.address();
		const auto & Hostname = Addr.host_name();

		if (Address.is_v4())
		{
			const auto sin =
				reinterpret_cast<const sockaddr_in *>(Endpoint.data());
			if (!a_Callbacks.OnNameResolvedV4(Hostname, sin))
			{
				// Callback indicated that the IP shouldn't be serialized to
				// a string, just continue with the next address:
				HasResolved = true;
				continue;
			}
		}
		else if (Address.is_v6())
		{
			const auto sin =
				reinterpret_cast<const sockaddr_in6 *>(Endpoint.data());
			if (!a_Callbacks.OnNameResolvedV6(Hostname, sin))
			{
				// Callback indicated that the IP shouldn't be serialized to
				// a string, just continue with the next address:
				HasResolved = true;
				continue;
			}
		}
		else
		{
			// Unknown address family, handle as if this entry wasn't
			// received
			continue;  // for (a_Addr)
		}
		a_Callbacks.OnNameResolved(Hostname, Address.to_string());
		HasResolved = true;
	}  // for (a_Addr)

	// If only unsupported families were reported, call the Error handler:
	if (!HasResolved)
	{
		a_Callbacks.OnError(EAI_NONAME, ErrorString(EAI_NONAME));
	}
	else
	{
		a_Callbacks.OnFinished();
	}
}





////////////////////////////////////////////////////////////////////////////////
// cNetwork API:

bool cNetwork::HostnameToIP(
	const AString & a_Hostname,
	cNetwork::cResolveNameCallbacksPtr a_Callbacks
)
{
	cHostnameLookup::Lookup(a_Hostname, std::move(a_Callbacks));
	return true;
}