31 #define _CRT_SECURE_NO_WARNINGS 1
42 #define sleep(x) Sleep(x * 1000)
49 #include <wx/datetime.h>
53 #include "androidUTIL.h"
57 #include "mdns_util.h"
58 #include "model/mdns_cache.h"
59 #include "model/mDNS_query.h"
62 std::vector<ocpn_DNS_record_t> g_sk_servers;
64 static char addrbuffer[64];
65 static char entrybuffer[256];
66 static char namebuffer[256];
67 static char sendbuffer[1024];
68 static mdns_record_txt_t txtbuffer[128];
70 static struct sockaddr_in service_address_ipv4;
71 static struct sockaddr_in6 service_address_ipv6;
76 static void log_printf(
const char* fmt, ...) {
77 if (getenv(
"OCPN_MDNS_DEBUG") ||
78 wxLog::GetActiveTarget()->GetLogLevel() >= wxLOG_Debug) {
86 static int ocpn_query_callback(
int sock,
const struct sockaddr* from,
87 size_t addrlen, mdns_entry_type_t entry,
88 uint16_t query_id, uint16_t rtype,
89 uint16_t rclass, uint32_t ttl,
const void* data,
90 size_t size,
size_t name_offset,
91 size_t name_length,
size_t record_offset,
92 size_t record_length,
void* user_data) {
94 (void)
sizeof(query_id);
95 (void)
sizeof(name_length);
96 (void)
sizeof(user_data);
97 mdns_string_t fromaddrstr =
98 ip_address_to_string(addrbuffer,
sizeof(addrbuffer), from, addrlen);
99 const char* entrytype =
100 (entry == MDNS_ENTRYTYPE_ANSWER)
102 : ((entry == MDNS_ENTRYTYPE_AUTHORITY) ?
"authority" :
"additional");
103 mdns_string_t entrystr = mdns_string_extract(
104 data, size, &name_offset, entrybuffer,
sizeof(entrybuffer));
106 from->sa_family == AF_INET;
108 if ((rtype == MDNS_RECORDTYPE_PTR) && is_ipv4) {
109 mdns_string_t namestr =
110 mdns_record_parse_ptr(data, size, record_offset, record_length,
111 namebuffer,
sizeof(namebuffer));
112 log_printf(
"%.*s : %s %.*s PTR %.*s rclass 0x%x ttl %u length %d\n",
113 MDNS_STRING_FORMAT(fromaddrstr), entrytype,
114 MDNS_STRING_FORMAT(entrystr), MDNS_STRING_FORMAT(namestr),
115 rclass, ttl, (
int)record_length);
117 std::string srv(namestr.str, namestr.length);
118 size_t rh = srv.find(
"opencpn-object");
120 std::string hostname = srv.substr(0, rh);
122 std::string from(fromaddrstr.str, fromaddrstr.length);
123 size_t r = from.find(
':');
124 std::string ip = from.substr(0, r);
128 hostname.find(
"Portable") == std::string::npos ?
"8000" :
"8001";
129 MdnsCache::GetInstance().
Add(srv, hostname, ip, port);
135 static int sk_query_callback(
int sock,
const struct sockaddr* from,
136 size_t addrlen, mdns_entry_type_t entry,
137 uint16_t query_id, uint16_t rtype, uint16_t rclass,
138 uint32_t ttl,
const void* data,
size_t size,
139 size_t name_offset,
size_t name_length,
140 size_t record_offset,
size_t record_length,
143 (void)
sizeof(query_id);
144 (void)
sizeof(name_length);
145 (void)
sizeof(user_data);
146 mdns_string_t fromaddrstr =
147 ip_address_to_string(addrbuffer,
sizeof(addrbuffer), from, addrlen);
148 const char* entrytype =
149 (entry == MDNS_ENTRYTYPE_ANSWER)
151 : ((entry == MDNS_ENTRYTYPE_AUTHORITY) ?
"authority" :
"additional");
152 mdns_string_t entrystr = mdns_string_extract(
153 data, size, &name_offset, entrybuffer,
sizeof(entrybuffer));
155 from->sa_family == AF_INET;
157 if ((rtype == MDNS_RECORDTYPE_PTR) && is_ipv4) {
158 mdns_string_t namestr =
159 mdns_record_parse_ptr(data, size, record_offset, record_length,
160 namebuffer,
sizeof(namebuffer));
161 std::string srv(namestr.str, namestr.length);
162 size_t rh = srv.find(
"_signalk-ws");
166 std::string hostname = srv.substr(0, rh);
168 hostname.erase(remove_if(hostname.begin(), hostname.end(),
169 [](
char c) { return !(c >= 0 && c < 128); }),
172 for (
const auto& sks : g_sk_servers) {
173 if (sks.hostname == hostname) {
180 sk_server.service_instance = srv;
181 sk_server.hostname = hostname;
182 g_sk_servers.push_back(sk_server);
184 }
else if ((rtype == MDNS_RECORDTYPE_SRV) && is_ipv4) {
185 mdns_record_srv_t srv =
186 mdns_record_parse_srv(data, size, record_offset, record_length,
187 namebuffer,
sizeof(namebuffer));
188 g_sk_servers.back().port = std::to_string(srv.port);
189 }
else if ((rtype == MDNS_RECORDTYPE_A) && is_ipv4) {
191 mdns_record_parse_a(data, size, record_offset, record_length, &addr);
192 mdns_string_t addrstr = ipv4_address_to_string(
193 namebuffer,
sizeof(namebuffer), &addr,
sizeof(addr));
194 g_sk_servers.back().ip = addrstr.str;
202 int send_mdns_query(mdns_query_t* query,
size_t count,
size_t timeout_secs,
203 mdns_record_callback_fn callback_function) {
207 open_client_sockets(sockets,
sizeof(sockets) /
sizeof(sockets[0]), 0);
208 if (num_sockets <= 0) {
209 log_printf(
"Failed to open any client sockets\n");
212 log_printf(
"Opened %d socket%s for mDNS query\n", num_sockets,
213 num_sockets ?
"s" :
"");
215 size_t capacity = 2048;
216 void* buffer = malloc(capacity);
219 log_printf(
"Sending mDNS query");
220 for (
size_t iq = 0; iq < count; ++iq) {
221 const char* record_name =
"PTR";
222 if (query[iq].type == MDNS_RECORDTYPE_SRV)
224 else if (query[iq].type == MDNS_RECORDTYPE_A)
226 else if (query[iq].type == MDNS_RECORDTYPE_AAAA)
227 record_name =
"AAAA";
229 query[iq].type = MDNS_RECORDTYPE_PTR;
230 log_printf(
" : %s %s", query[iq].name, record_name);
233 for (
int isock = 0; isock < num_sockets; ++isock) {
235 mdns_multiquery_send(sockets[isock], query, count, buffer, capacity, 0);
236 if (query_id[isock] < 0)
237 log_printf(
"Failed to send mDNS query: %s\n", strerror(errno));
243 log_printf(
"Reading mDNS query replies\n");
246 struct timeval timeout;
247 timeout.tv_sec = timeout_secs;
253 for (
int isock = 0; isock < num_sockets; ++isock) {
254 if (sockets[isock] >= nfds) nfds = sockets[isock] + 1;
255 FD_SET(sockets[isock], &readfs);
258 res = select(nfds, &readfs, 0, 0, &timeout);
260 for (
int isock = 0; isock < num_sockets; ++isock) {
261 if (FD_ISSET(sockets[isock], &readfs)) {
263 mdns_query_recv(sockets[isock], buffer, capacity,
264 callback_function, user_data, query_id[isock]);
265 if (rec > 0) records += rec;
267 FD_SET(sockets[isock], &readfs);
272 log_printf(
"Read %d records\n", records);
276 for (
int isock = 0; isock < num_sockets; ++isock)
277 mdns_socket_close(sockets[isock]);
278 log_printf(
"Closed socket%s\n", num_sockets ?
"s" :
"");
285 mdns_query_t s_query;
287 void FindAllOCPNServers(
size_t timeout_secs) {
288 s_query.name =
"opencpn-object-control-service";
289 s_query.type = MDNS_RECORDTYPE_PTR;
290 s_query.length = strlen(s_query.name);
292 std::thread{send_mdns_query, &s_query, 1, timeout_secs, ocpn_query_callback}
297 void FindAllSignalKServers(
size_t timeout_secs) {
298 g_sk_servers.clear();
299 s_query.name =
"_signalk-ws._tcp.local.";
300 s_query.type = MDNS_RECORDTYPE_PTR;
301 s_query.length = strlen(s_query.name);
303 std::thread{send_mdns_query, &s_query, 1, timeout_secs, sk_query_callback}
307 std::vector<std::string> get_local_ipv4_addresses() {
308 std::vector<std::string> ret_vec;
311 wxString ipa = androidGetIpV4Address();
312 ret_vec.push_back(ipa.ToStdString());
321 IP_ADAPTER_ADDRESSES* adapter_address = 0;
322 ULONG address_size = 8000;
324 unsigned int num_retries = 4;
326 adapter_address = (IP_ADAPTER_ADDRESSES*)malloc(address_size);
327 ret = GetAdaptersAddresses(AF_UNSPEC,
328 GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_ANYCAST,
329 0, adapter_address, &address_size);
330 if (ret == ERROR_BUFFER_OVERFLOW) {
331 free(adapter_address);
337 }
while (num_retries-- > 0);
339 if (!adapter_address || (ret != NO_ERROR)) {
340 free(adapter_address);
341 log_printf(
"Failed to get network adapter addresses\n");
347 for (PIP_ADAPTER_ADDRESSES adapter = adapter_address; adapter;
348 adapter = adapter->Next) {
349 if (adapter->TunnelType == TUNNEL_TYPE_TEREDO)
continue;
350 if (adapter->OperStatus != IfOperStatusUp)
continue;
352 for (IP_ADAPTER_UNICAST_ADDRESS* unicast = adapter->FirstUnicastAddress;
353 unicast; unicast = unicast->Next) {
354 if (unicast->Address.lpSockaddr->sa_family == AF_INET) {
355 struct sockaddr_in* saddr =
356 (
struct sockaddr_in*)unicast->Address.lpSockaddr;
357 if ((saddr->sin_addr.S_un.S_un_b.s_b1 != 127) ||
358 (saddr->sin_addr.S_un.S_un_b.s_b2 != 0) ||
359 (saddr->sin_addr.S_un.S_un_b.s_b3 != 0) ||
360 (saddr->sin_addr.S_un.S_un_b.s_b4 != 1)) {
363 service_address_ipv4 = *saddr;
370 mdns_string_t addr = ipv4_address_to_string(
371 buffer,
sizeof(buffer), saddr,
sizeof(
struct sockaddr_in));
372 std::string addr_string(addr.str, addr.length);
373 ret_vec.push_back(addr_string);
379 else if (unicast->Address.lpSockaddr->sa_family == AF_INET6) {
380 struct sockaddr_in6* saddr = (
struct sockaddr_in6*)unicast->Address.lpSockaddr;
382 if (saddr->sin6_scope_id)
384 static const unsigned char localhost[] = {0, 0, 0, 0, 0, 0, 0, 0,
385 0, 0, 0, 0, 0, 0, 0, 1};
386 static const unsigned char localhost_mapped[] = {0, 0, 0, 0, 0, 0, 0, 0,
387 0, 0, 0xff, 0xff, 0x7f, 0, 0, 1};
388 if ((unicast->DadState == NldsPreferred) &&
389 memcmp(saddr->sin6_addr.s6_addr, localhost, 16) &&
390 memcmp(saddr->sin6_addr.s6_addr, localhost_mapped, 16)) {
393 service_address_ipv6 = *saddr;
398 if (num_sockets < max_sockets) {
399 saddr->sin6_port = htons((
unsigned short)port);
400 int sock = mdns_socket_open_ipv6(saddr);
402 sockets[num_sockets++] = sock;
410 mdns_string_t addr = ipv6_address_to_string(buffer,
sizeof(buffer), saddr,
411 sizeof(
struct sockaddr_in6));
412 log_printf(
"Local IPv6 address: %.*s\n", MDNS_STRING_FORMAT(addr));
420 free(adapter_address);
424 #if !defined(_WIN32) && !defined(__ANDROID__)
426 struct ifaddrs* ifaddr = 0;
427 struct ifaddrs* ifa = 0;
429 if (getifaddrs(&ifaddr) < 0)
430 log_printf(
"Unable to get interface addresses\n");
434 for (ifa = ifaddr; ifa; ifa = ifa->ifa_next) {
435 if (!ifa->ifa_addr)
continue;
436 if (!(ifa->ifa_flags & IFF_UP) || !(ifa->ifa_flags & IFF_MULTICAST))
438 if ((ifa->ifa_flags & IFF_LOOPBACK) || (ifa->ifa_flags & IFF_POINTOPOINT))
441 if (ifa->ifa_addr->sa_family == AF_INET) {
442 struct sockaddr_in* saddr = (
struct sockaddr_in*)ifa->ifa_addr;
443 if (saddr->sin_addr.s_addr != htonl(INADDR_LOOPBACK)) {
446 service_address_ipv4 = *saddr;
453 mdns_string_t addr = ipv4_address_to_string(
454 buffer,
sizeof(buffer), saddr,
sizeof(
struct sockaddr_in));
455 std::string addr_string(addr.str, addr.length);
456 ret_vec.push_back(addr_string);
458 if (num_sockets < max_sockets) {
459 saddr->sin_port = htons(port);
460 int sock = mdns_socket_open_ipv4(saddr);
462 sockets[num_sockets++] = sock;
470 mdns_string_t addr = ipv4_address_to_string(buffer,
sizeof(buffer), saddr,
471 sizeof(
struct sockaddr_in));
472 log_printf(
"Local IPv4 address: %.*s\n", MDNS_STRING_FORMAT(addr));
478 else if (ifa->ifa_addr->sa_family == AF_INET6) {
479 struct sockaddr_in6* saddr = (
struct sockaddr_in6*)ifa->ifa_addr;
481 if (saddr->sin6_scope_id)
483 static const unsigned char localhost[] = {0, 0, 0, 0, 0, 0, 0, 0,
484 0, 0, 0, 0, 0, 0, 0, 1};
485 static const unsigned char localhost_mapped[] = {0, 0, 0, 0, 0, 0, 0, 0,
486 0, 0, 0xff, 0xff, 0x7f, 0, 0, 1};
487 if (memcmp(saddr->sin6_addr.s6_addr, localhost, 16) &&
488 memcmp(saddr->sin6_addr.s6_addr, localhost_mapped, 16)) {
491 service_address_ipv6 = *saddr;
496 if (num_sockets < max_sockets) {
497 saddr->sin6_port = htons(port);
498 int sock = mdns_socket_open_ipv6(saddr);
500 sockets[num_sockets++] = sock;
508 mdns_string_t addr = ipv6_address_to_string(buffer,
sizeof(buffer), saddr,
509 sizeof(
struct sockaddr_in6));
510 log_printf(
"Local IPv6 address: %.*s\n", MDNS_STRING_FORMAT(addr));
bool Add(const Entry &entry)
Add new entry to the cache.
Global variables reflecting command line options and arguments.