summaryrefslogtreecommitdiffstats
path: root/src/OSSupport/HostnameLookup.cpp
blob: 867472e8c50324a4cb9e7621d3e43adf4b575337 (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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136

// 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:

cHostnameLookup::cHostnameLookup(const AString & a_Hostname, cNetwork::cResolveNameCallbacksPtr a_Callbacks):
	m_Callbacks(a_Callbacks),
	m_Hostname(a_Hostname)
{
}





void cHostnameLookup::Lookup(const AString & a_Hostname, cNetwork::cResolveNameCallbacksPtr a_Callbacks)
{
	// Cannot use std::make_shared here, constructor is not accessible
	cHostnameLookupPtr Lookup{ new cHostnameLookup(a_Hostname, std::move(a_Callbacks)) };

	// Note the Lookup object is owned solely by this lambda which is destroyed after it runs
	cNetworkSingleton::Get().GetLookupThread().ScheduleLookup([=]()
	{
		// Start the lookup:
		addrinfo hints;
		memset(&hints, 0, sizeof(hints));
		hints.ai_protocol = IPPROTO_TCP;
		hints.ai_socktype = SOCK_STREAM;
		hints.ai_family = AF_UNSPEC;
		hints.ai_flags = AI_CANONNAME;

		addrinfo * Result;
		int ErrCode = getaddrinfo(Lookup->m_Hostname.c_str(), nullptr, &hints, &Result);

		Lookup->Callback(ErrCode, Result);
	});
}





void cHostnameLookup::Callback(int a_ErrCode, addrinfo * a_Addr)
{
	// If an error has occurred, notify the error callback:
	if (a_ErrCode != 0)
	{
		m_Callbacks->OnError(a_ErrCode, ErrorString(a_ErrCode));
		return;
	}

	// Call the success handler for each entry received:
	bool HasResolved = false;
	addrinfo * OrigAddr = a_Addr;
	for (;a_Addr != nullptr; a_Addr = a_Addr->ai_next)
	{
		char IP[128];
		switch (a_Addr->ai_family)
		{
			case AF_INET:  // IPv4
			{
				sockaddr_in * sin = reinterpret_cast<sockaddr_in *>(a_Addr->ai_addr);
				if (!m_Callbacks->OnNameResolvedV4(m_Hostname, sin))
				{
					// Callback indicated that the IP shouldn't be serialized to a string, just continue with the next address:
					HasResolved = true;
					continue;
				}
				evutil_inet_ntop(AF_INET, &(sin->sin_addr), IP, sizeof(IP));
				break;
			}
			case AF_INET6:  // IPv6
			{
				sockaddr_in6 * sin = reinterpret_cast<sockaddr_in6 *>(a_Addr->ai_addr);
				if (!m_Callbacks->OnNameResolvedV6(m_Hostname, sin))
				{
					// Callback indicated that the IP shouldn't be serialized to a string, just continue with the next address:
					HasResolved = true;
					continue;
				}
				evutil_inet_ntop(AF_INET6, &(sin->sin6_addr), IP, sizeof(IP));
				break;
			}
			default:
			{
				// Unknown address family, handle as if this entry wasn't received
				continue;  // for (a_Addr)
			}
		}
		m_Callbacks->OnNameResolved(m_Hostname, IP);
		HasResolved = true;
	}  // for (a_Addr)

	// If only unsupported families were reported, call the Error handler:
	if (!HasResolved)
	{
		m_Callbacks->OnError(EAI_NODATA, ErrorString(EAI_NODATA));
	}
	else
	{
		m_Callbacks->OnFinished();
	}
	freeaddrinfo(OrigAddr);
}





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

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