31#define _CRT_SECURE_NO_WARNINGS 1
42#define sleep(x) Sleep(x * 1000)
49#include <wx/datetime.h>
52#include "mDNS_query.h"
54extern bool g_bportable;
57std::vector<std::shared_ptr<ocpn_DNS_record_t>> g_DNS_cache;
58wxDateTime g_DNS_cache_time;
61static char addrbuffer[64];
62static char entrybuffer[256];
63static char namebuffer[256];
64static char sendbuffer[1024];
65static mdns_record_txt_t txtbuffer[128];
67static struct sockaddr_in service_address_ipv4;
68static struct sockaddr_in6 service_address_ipv6;
75ocpn_query_callback(
int sock,
const struct sockaddr* from,
size_t addrlen, mdns_entry_type_t entry,
76 uint16_t query_id, uint16_t rtype, uint16_t rclass, uint32_t ttl,
const void* data,
77 size_t size,
size_t name_offset,
size_t name_length,
size_t record_offset,
78 size_t record_length,
void* user_data) {
80 (void)
sizeof(query_id);
81 (void)
sizeof(name_length);
82 (void)
sizeof(user_data);
83 mdns_string_t fromaddrstr = ip_address_to_string(addrbuffer,
sizeof(addrbuffer), from, addrlen);
84 const char* entrytype = (entry == MDNS_ENTRYTYPE_ANSWER) ?
86 ((entry == MDNS_ENTRYTYPE_AUTHORITY) ?
"authority" :
"additional");
87 mdns_string_t entrystr =
88 mdns_string_extract(data, size, &name_offset, entrybuffer,
sizeof(entrybuffer));
89 bool is_ipv4 = from->sa_family == AF_INET;
91 if ((rtype == MDNS_RECORDTYPE_PTR) && is_ipv4) {
92 mdns_string_t namestr = mdns_record_parse_ptr(data, size, record_offset, record_length,
93 namebuffer,
sizeof(namebuffer));
94 printf(
"%.*s : %s %.*s PTR %.*s rclass 0x%x ttl %u length %d\n",
95 MDNS_STRING_FORMAT(fromaddrstr), entrytype, MDNS_STRING_FORMAT(entrystr),
96 MDNS_STRING_FORMAT(namestr), rclass, ttl, (
int)record_length);
98 std::string srv(namestr.str, namestr.length);
99 size_t rh = srv.find(
"opencpn-object");
101 std::string hostname = srv.substr(0, rh);
103 std::string from(fromaddrstr.str, fromaddrstr.length);
104 size_t r = from.find(
':');
105 std::string ip = from.substr(0, r);
108 auto func = [srv](
const std::shared_ptr<ocpn_DNS_record_t> record) {
109 return !record->service_instance.compare(srv);
111 auto found = std::find_if(g_DNS_cache.begin(), g_DNS_cache.end(), func);
113 std::shared_ptr<ocpn_DNS_record_t>entry;
115 if (found == g_DNS_cache.end()){
117 entry = std::make_shared<ocpn_DNS_record_t>();
118 g_DNS_cache.push_back(entry);
124 entry->service_instance = srv;
125 entry->hostname = hostname;
127 entry->port =
"8000";
129 std::string p (
"Portable");
130 std::size_t port = hostname.find(p);;
131 if (port != std::string::npos)
132 entry->port =
"8001";
138 else if (rtype == MDNS_RECORDTYPE_SRV) {
139 mdns_record_srv_t srv = mdns_record_parse_srv(data, size, record_offset, record_length,
140 namebuffer,
sizeof(namebuffer));
141 printf(
"%.*s : %s %.*s SRV %.*s priority %d weight %d port %d\n",
142 MDNS_STRING_FORMAT(fromaddrstr), entrytype, MDNS_STRING_FORMAT(entrystr),
143 MDNS_STRING_FORMAT(srv.name), srv.priority, srv.weight, srv.port);
144 }
else if (rtype == MDNS_RECORDTYPE_A) {
145 struct sockaddr_in addr;
146 mdns_record_parse_a(data, size, record_offset, record_length, &addr);
147 mdns_string_t addrstr =
148 ipv4_address_to_string(namebuffer,
sizeof(namebuffer), &addr,
sizeof(addr));
149 printf(
"%.*s : %s %.*s A %.*s\n", MDNS_STRING_FORMAT(fromaddrstr), entrytype,
150 MDNS_STRING_FORMAT(entrystr), MDNS_STRING_FORMAT(addrstr));
151 }
else if (rtype == MDNS_RECORDTYPE_AAAA) {
152 struct sockaddr_in6 addr;
153 mdns_record_parse_aaaa(data, size, record_offset, record_length, &addr);
154 mdns_string_t addrstr =
155 ipv6_address_to_string(namebuffer,
sizeof(namebuffer), &addr,
sizeof(addr));
156 printf(
"%.*s : %s %.*s AAAA %.*s\n", MDNS_STRING_FORMAT(fromaddrstr), entrytype,
157 MDNS_STRING_FORMAT(entrystr), MDNS_STRING_FORMAT(addrstr));
158 }
else if (rtype == MDNS_RECORDTYPE_TXT) {
159 size_t parsed = mdns_record_parse_txt(data, size, record_offset, record_length, txtbuffer,
160 sizeof(txtbuffer) /
sizeof(mdns_record_txt_t));
161 for (
size_t itxt = 0; itxt < parsed; ++itxt) {
162 if (txtbuffer[itxt].value.length) {
163 printf(
"%.*s : %s %.*s TXT %.*s = %.*s\n", MDNS_STRING_FORMAT(fromaddrstr),
164 entrytype, MDNS_STRING_FORMAT(entrystr),
165 MDNS_STRING_FORMAT(txtbuffer[itxt].key),
166 MDNS_STRING_FORMAT(txtbuffer[itxt].value));
168 printf(
"%.*s : %s %.*s TXT %.*s\n", MDNS_STRING_FORMAT(fromaddrstr), entrytype,
169 MDNS_STRING_FORMAT(entrystr), MDNS_STRING_FORMAT(txtbuffer[itxt].key));
173 printf(
"%.*s : %s %.*s type %u rclass 0x%x ttl %u length %d\n",
174 MDNS_STRING_FORMAT(fromaddrstr), entrytype, MDNS_STRING_FORMAT(entrystr), rtype,
175 rclass, ttl, (
int)record_length);
186send_mdns_query(mdns_query_t* query,
size_t count,
size_t timeout_secs) {
189 int num_sockets = open_client_sockets(sockets,
sizeof(sockets) /
sizeof(sockets[0]), 0);
190 if (num_sockets <= 0) {
191 printf(
"Failed to open any client sockets\n");
194 printf(
"Opened %d socket%s for mDNS query\n", num_sockets, num_sockets ?
"s" :
"");
196 size_t capacity = 2048;
197 void* buffer = malloc(capacity);
200 printf(
"Sending mDNS query");
201 for (
size_t iq = 0; iq < count; ++iq) {
202 const char* record_name =
"PTR";
203 if (query[iq].type == MDNS_RECORDTYPE_SRV)
205 else if (query[iq].type == MDNS_RECORDTYPE_A)
207 else if (query[iq].type == MDNS_RECORDTYPE_AAAA)
208 record_name =
"AAAA";
210 query[iq].type = MDNS_RECORDTYPE_PTR;
211 printf(
" : %s %s", query[iq].name, record_name);
214 for (
int isock = 0; isock < num_sockets; ++isock) {
216 mdns_multiquery_send(sockets[isock], query, count, buffer, capacity, 0);
217 if (query_id[isock] < 0)
218 printf(
"Failed to send mDNS query: %s\n", strerror(errno));
223 printf(
"Reading mDNS query replies\n");
226 struct timeval timeout;
227 timeout.tv_sec = timeout_secs;
233 for (
int isock = 0; isock < num_sockets; ++isock) {
234 if (sockets[isock] >= nfds)
235 nfds = sockets[isock] + 1;
236 FD_SET(sockets[isock], &readfs);
239 res = select(nfds, &readfs, 0, 0, &timeout);
241 for (
int isock = 0; isock < num_sockets; ++isock) {
242 if (FD_ISSET(sockets[isock], &readfs)) {
243 int rec = mdns_query_recv(sockets[isock], buffer, capacity, ocpn_query_callback,
244 user_data, query_id[isock]);
248 FD_SET(sockets[isock], &readfs);
253 printf(
"Read %d records\n", records);
257 for (
int isock = 0; isock < num_sockets; ++isock)
258 mdns_socket_close(sockets[isock]);
259 printf(
"Closed socket%s\n", num_sockets ?
"s" :
"");
269void FindAllOCPNServers(
size_t timeout_secs) {
270 s_query.name =
"opencpn-object-control-service";
271 s_query.type = MDNS_RECORDTYPE_PTR;
272 s_query.length = strlen(s_query.name);
274 std::thread{ send_mdns_query, &s_query, 1, timeout_secs}.detach();
278std::vector<std::string> get_local_ipv4_addresses() {
279 std::vector<std::string> ret_vec;
288 IP_ADAPTER_ADDRESSES* adapter_address = 0;
289 ULONG address_size = 8000;
291 unsigned int num_retries = 4;
293 adapter_address = (IP_ADAPTER_ADDRESSES*)malloc(address_size);
294 ret = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_ANYCAST, 0,
295 adapter_address, &address_size);
296 if (ret == ERROR_BUFFER_OVERFLOW) {
297 free(adapter_address);
303 }
while (num_retries-- > 0);
305 if (!adapter_address || (ret != NO_ERROR)) {
306 free(adapter_address);
307 printf(
"Failed to get network adapter addresses\n");
313 for (PIP_ADAPTER_ADDRESSES adapter = adapter_address; adapter; adapter = adapter->Next) {
314 if (adapter->TunnelType == TUNNEL_TYPE_TEREDO)
316 if (adapter->OperStatus != IfOperStatusUp)
319 for (IP_ADAPTER_UNICAST_ADDRESS* unicast = adapter->FirstUnicastAddress; unicast;
320 unicast = unicast->Next) {
321 if (unicast->Address.lpSockaddr->sa_family == AF_INET) {
322 struct sockaddr_in* saddr = (
struct sockaddr_in*)unicast->Address.lpSockaddr;
323 if ((saddr->sin_addr.S_un.S_un_b.s_b1 != 127) ||
324 (saddr->sin_addr.S_un.S_un_b.s_b2 != 0) ||
325 (saddr->sin_addr.S_un.S_un_b.s_b3 != 0) ||
326 (saddr->sin_addr.S_un.S_un_b.s_b4 != 1)) {
329 service_address_ipv4 = *saddr;
337 mdns_string_t addr = ipv4_address_to_string(buffer,
sizeof(buffer), saddr,
338 sizeof(
struct sockaddr_in));
339 std::string addr_string(addr.str, addr.length);
340 ret_vec.push_back(addr_string);
347 else if (unicast->Address.lpSockaddr->sa_family == AF_INET6) {
348 struct sockaddr_in6* saddr = (
struct sockaddr_in6*)unicast->Address.lpSockaddr;
350 if (saddr->sin6_scope_id)
352 static const unsigned char localhost[] = {0, 0, 0, 0, 0, 0, 0, 0,
353 0, 0, 0, 0, 0, 0, 0, 1};
354 static const unsigned char localhost_mapped[] = {0, 0, 0, 0, 0, 0, 0, 0,
355 0, 0, 0xff, 0xff, 0x7f, 0, 0, 1};
356 if ((unicast->DadState == NldsPreferred) &&
357 memcmp(saddr->sin6_addr.s6_addr, localhost, 16) &&
358 memcmp(saddr->sin6_addr.s6_addr, localhost_mapped, 16)) {
361 service_address_ipv6 = *saddr;
366 if (num_sockets < max_sockets) {
367 saddr->sin6_port = htons((
unsigned short)port);
368 int sock = mdns_socket_open_ipv6(saddr);
370 sockets[num_sockets++] = sock;
378 mdns_string_t addr = ipv6_address_to_string(buffer,
sizeof(buffer), saddr,
379 sizeof(
struct sockaddr_in6));
380 printf(
"Local IPv6 address: %.*s\n", MDNS_STRING_FORMAT(addr));
388 free(adapter_address);
392 struct ifaddrs* ifaddr = 0;
393 struct ifaddrs* ifa = 0;
395 if (getifaddrs(&ifaddr) < 0)
396 printf(
"Unable to get interface addresses\n");
400 for (ifa = ifaddr; ifa; ifa = ifa->ifa_next) {
403 if (!(ifa->ifa_flags & IFF_UP) || !(ifa->ifa_flags & IFF_MULTICAST))
405 if ((ifa->ifa_flags & IFF_LOOPBACK) || (ifa->ifa_flags & IFF_POINTOPOINT))
408 if (ifa->ifa_addr->sa_family == AF_INET) {
409 struct sockaddr_in* saddr = (
struct sockaddr_in*)ifa->ifa_addr;
410 if (saddr->sin_addr.s_addr != htonl(INADDR_LOOPBACK)) {
413 service_address_ipv4 = *saddr;
420 mdns_string_t addr = ipv4_address_to_string(buffer,
sizeof(buffer), saddr,
421 sizeof(
struct sockaddr_in));
422 std::string addr_string(addr.str, addr.length);
423 ret_vec.push_back(addr_string);
425 if (num_sockets < max_sockets) {
426 saddr->sin_port = htons(port);
427 int sock = mdns_socket_open_ipv4(saddr);
429 sockets[num_sockets++] = sock;
437 mdns_string_t addr = ipv4_address_to_string(buffer,
sizeof(buffer), saddr,
438 sizeof(
struct sockaddr_in));
439 printf(
"Local IPv4 address: %.*s\n", MDNS_STRING_FORMAT(addr));
445 else if (ifa->ifa_addr->sa_family == AF_INET6) {
446 struct sockaddr_in6* saddr = (
struct sockaddr_in6*)ifa->ifa_addr;
448 if (saddr->sin6_scope_id)
450 static const unsigned char localhost[] = {0, 0, 0, 0, 0, 0, 0, 0,
451 0, 0, 0, 0, 0, 0, 0, 1};
452 static const unsigned char localhost_mapped[] = {0, 0, 0, 0, 0, 0, 0, 0,
453 0, 0, 0xff, 0xff, 0x7f, 0, 0, 1};
454 if (memcmp(saddr->sin6_addr.s6_addr, localhost, 16) &&
455 memcmp(saddr->sin6_addr.s6_addr, localhost_mapped, 16)) {
458 service_address_ipv6 = *saddr;
463 if (num_sockets < max_sockets) {
464 saddr->sin6_port = htons(port);
465 int sock = mdns_socket_open_ipv6(saddr);
467 sockets[num_sockets++] = sock;
475 mdns_string_t addr = ipv6_address_to_string(buffer,
sizeof(buffer), saddr,
476 sizeof(
struct sockaddr_in6));
477 printf(
"Local IPv6 address: %.*s\n", MDNS_STRING_FORMAT(addr));