29#if defined(_WIN32) && !defined(_CRT_SECURE_NO_WARNINGS)
30#define _CRT_SECURE_NO_WARNINGS 1
41#define sleep(x) Sleep(x * 1000)
48#include <wx/datetime.h>
52#include "androidUTIL.h"
61std::vector<ocpn_DNS_record_t> g_sk_servers;
63static char addrbuffer[64];
64static char entrybuffer[256];
65static char namebuffer[256];
66static char sendbuffer[1024];
67static mdns_record_txt_t txtbuffer[128];
69static struct sockaddr_in service_address_ipv4;
70static struct sockaddr_in6 service_address_ipv6;
75static void log_printf(
const char* fmt, ...) {
76 if (getenv(
"OCPN_MDNS_DEBUG") ||
77 wxLog::GetActiveTarget()->GetLogLevel() >= wxLOG_Debug) {
85static int ocpn_query_callback(
int sock,
const struct sockaddr* from,
86 size_t addrlen, mdns_entry_type_t entry,
87 uint16_t query_id, uint16_t rtype,
88 uint16_t rclass, uint32_t ttl,
const void* data,
89 size_t size,
size_t name_offset,
90 size_t name_length,
size_t record_offset,
91 size_t record_length,
void* user_data) {
93 (void)
sizeof(query_id);
94 (void)
sizeof(name_length);
95 (void)
sizeof(user_data);
96 mdns_string_t fromaddrstr =
97 ip_address_to_string(addrbuffer,
sizeof(addrbuffer), from, addrlen);
98 const char* entrytype =
99 (entry == MDNS_ENTRYTYPE_ANSWER)
101 : ((entry == MDNS_ENTRYTYPE_AUTHORITY) ?
"authority" :
"additional");
102 mdns_string_t entrystr = mdns_string_extract(
103 data, size, &name_offset, entrybuffer,
sizeof(entrybuffer));
105 from->sa_family == AF_INET;
107 if ((rtype == MDNS_RECORDTYPE_PTR) && is_ipv4) {
108 mdns_string_t namestr =
109 mdns_record_parse_ptr(data, size, record_offset, record_length,
110 namebuffer,
sizeof(namebuffer));
111 log_printf(
"%.*s : %s %.*s PTR %.*s rclass 0x%x ttl %u length %d\n",
112 MDNS_STRING_FORMAT(fromaddrstr), entrytype,
113 MDNS_STRING_FORMAT(entrystr), MDNS_STRING_FORMAT(namestr),
114 rclass, ttl, (
int)record_length);
116 std::string srv(namestr.str, namestr.length);
117 size_t rh = srv.find(
"opencpn-object");
119 std::string hostname = srv.substr(0, rh);
121 std::string from(fromaddrstr.str, fromaddrstr.length);
122 size_t r = from.find(
':');
123 std::string ip = from.substr(0, r);
127 hostname.find(
"Portable") == std::string::npos ?
"8000" :
"8001";
128 MdnsCache::GetInstance().
Add(srv, hostname, ip, port);
134static int sk_query_callback(
int sock,
const struct sockaddr* from,
135 size_t addrlen, mdns_entry_type_t entry,
136 uint16_t query_id, uint16_t rtype, uint16_t rclass,
137 uint32_t ttl,
const void* data,
size_t size,
138 size_t name_offset,
size_t name_length,
139 size_t record_offset,
size_t record_length,
142 (void)
sizeof(query_id);
143 (void)
sizeof(name_length);
144 (void)
sizeof(user_data);
145 mdns_string_t fromaddrstr =
146 ip_address_to_string(addrbuffer,
sizeof(addrbuffer), from, addrlen);
147 const char* entrytype =
148 (entry == MDNS_ENTRYTYPE_ANSWER)
150 : ((entry == MDNS_ENTRYTYPE_AUTHORITY) ?
"authority" :
"additional");
151 mdns_string_t entrystr = mdns_string_extract(
152 data, size, &name_offset, entrybuffer,
sizeof(entrybuffer));
154 from->sa_family == AF_INET;
156 if ((rtype == MDNS_RECORDTYPE_PTR) && is_ipv4) {
157 mdns_string_t namestr =
158 mdns_record_parse_ptr(data, size, record_offset, record_length,
159 namebuffer,
sizeof(namebuffer));
160 std::string srv(namestr.str, namestr.length);
161 size_t rh = srv.find(
"_signalk-ws");
165 std::string hostname = srv.substr(0, rh);
167 hostname.erase(remove_if(hostname.begin(), hostname.end(),
168 [](
char c) { return (c < 0); }),
171 for (
const auto& sks : g_sk_servers) {
172 if (sks.hostname == hostname) {
179 sk_server.service_instance = srv;
180 sk_server.hostname = hostname;
181 g_sk_servers.push_back(sk_server);
183 }
else if ((rtype == MDNS_RECORDTYPE_SRV) && is_ipv4) {
184 mdns_record_srv_t srv =
185 mdns_record_parse_srv(data, size, record_offset, record_length,
186 namebuffer,
sizeof(namebuffer));
187 g_sk_servers.back().port = std::to_string(srv.port);
188 }
else if ((rtype == MDNS_RECORDTYPE_A) && is_ipv4) {
190 mdns_record_parse_a(data, size, record_offset, record_length, &addr);
191 mdns_string_t addrstr = ipv4_address_to_string(
192 namebuffer,
sizeof(namebuffer), &addr,
sizeof(addr));
193 g_sk_servers.back().ip = addrstr.str;
201int send_mdns_query(mdns_query_t* query,
size_t count,
size_t timeout_secs,
202 mdns_record_callback_fn callback_function) {
206 open_client_sockets(sockets,
sizeof(sockets) /
sizeof(sockets[0]), 0);
207 if (num_sockets <= 0) {
208 log_printf(
"Failed to open any client sockets\n");
211 log_printf(
"Opened %d socket%s for mDNS query\n", num_sockets,
212 num_sockets ?
"s" :
"");
214 size_t capacity = 2048;
215 void* buffer = malloc(capacity);
218 log_printf(
"Sending mDNS query");
219 for (
size_t iq = 0; iq < count; ++iq) {
220 const char* record_name =
"PTR";
221 if (query[iq].type == MDNS_RECORDTYPE_SRV)
223 else if (query[iq].type == MDNS_RECORDTYPE_A)
225 else if (query[iq].type == MDNS_RECORDTYPE_AAAA)
226 record_name =
"AAAA";
228 query[iq].type = MDNS_RECORDTYPE_PTR;
229 log_printf(
" : %s %s", query[iq].name, record_name);
232 for (
int isock = 0; isock < num_sockets; ++isock) {
234 mdns_multiquery_send(sockets[isock], query, count, buffer, capacity, 0);
235 if (query_id[isock] < 0)
236 log_printf(
"Failed to send mDNS query: %s\n", strerror(errno));
242 log_printf(
"Reading mDNS query replies\n");
245 struct timeval timeout;
246 timeout.tv_sec = timeout_secs;
252 for (
int isock = 0; isock < num_sockets; ++isock) {
253 if (sockets[isock] >= nfds) nfds = sockets[isock] + 1;
254 FD_SET(sockets[isock], &readfs);
257 res = select(nfds, &readfs, 0, 0, &timeout);
259 for (
int isock = 0; isock < num_sockets; ++isock) {
260 if (FD_ISSET(sockets[isock], &readfs)) {
262 mdns_query_recv(sockets[isock], buffer, capacity,
263 callback_function, user_data, query_id[isock]);
264 if (rec > 0) records += rec;
266 FD_SET(sockets[isock], &readfs);
271 log_printf(
"Read %d records\n", records);
275 for (
int isock = 0; isock < num_sockets; ++isock)
276 mdns_socket_close(sockets[isock]);
277 log_printf(
"Closed socket%s\n", num_sockets ?
"s" :
"");
286void FindAllOCPNServers(
size_t timeout_secs) {
287 s_query.name =
"opencpn-object-control-service";
288 s_query.type = MDNS_RECORDTYPE_PTR;
289 s_query.length = strlen(s_query.name);
291 std::thread{send_mdns_query, &s_query, 1, timeout_secs, ocpn_query_callback}
296void FindAllSignalKServers(
size_t timeout_secs) {
297 g_sk_servers.clear();
298 s_query.name =
"_signalk-ws._tcp.local.";
299 s_query.type = MDNS_RECORDTYPE_PTR;
300 s_query.length = strlen(s_query.name);
302 std::thread{send_mdns_query, &s_query, 1, timeout_secs, sk_query_callback}
306std::vector<std::string> get_local_ipv4_addresses() {
307 std::vector<std::string> ret_vec;
310 wxString ipa = androidGetIpV4Address();
311 ret_vec.push_back(ipa.ToStdString());
320 IP_ADAPTER_ADDRESSES* adapter_address = 0;
321 ULONG address_size = 8000;
323 unsigned int num_retries = 4;
325 adapter_address = (IP_ADAPTER_ADDRESSES*)malloc(address_size);
326 ret = GetAdaptersAddresses(AF_UNSPEC,
327 GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_ANYCAST,
328 0, adapter_address, &address_size);
329 if (ret == ERROR_BUFFER_OVERFLOW) {
330 free(adapter_address);
336 }
while (num_retries-- > 0);
338 if (!adapter_address || (ret != NO_ERROR)) {
339 free(adapter_address);
340 log_printf(
"Failed to get network adapter addresses\n");
346 for (PIP_ADAPTER_ADDRESSES adapter = adapter_address; adapter;
347 adapter = adapter->Next) {
348 if (adapter->TunnelType == TUNNEL_TYPE_TEREDO)
continue;
349 if (adapter->OperStatus != IfOperStatusUp)
continue;
351 for (IP_ADAPTER_UNICAST_ADDRESS* unicast = adapter->FirstUnicastAddress;
352 unicast; unicast = unicast->Next) {
353 if (unicast->Address.lpSockaddr->sa_family == AF_INET) {
354 struct sockaddr_in* saddr =
355 (
struct sockaddr_in*)unicast->Address.lpSockaddr;
356 if ((saddr->sin_addr.S_un.S_un_b.s_b1 != 127) ||
357 (saddr->sin_addr.S_un.S_un_b.s_b2 != 0) ||
358 (saddr->sin_addr.S_un.S_un_b.s_b3 != 0) ||
359 (saddr->sin_addr.S_un.S_un_b.s_b4 != 1)) {
362 service_address_ipv4 = *saddr;
369 mdns_string_t addr = ipv4_address_to_string(
370 buffer,
sizeof(buffer), saddr,
sizeof(
struct sockaddr_in));
371 std::string addr_string(addr.str, addr.length);
372 ret_vec.push_back(addr_string);
377 free(adapter_address);
381#if !defined(_WIN32) && !defined(__ANDROID__)
383 struct ifaddrs* ifaddr = 0;
384 struct ifaddrs* ifa = 0;
386 if (getifaddrs(&ifaddr) < 0)
387 log_printf(
"Unable to get interface addresses\n");
391 for (ifa = ifaddr; ifa; ifa = ifa->ifa_next) {
392 if (!ifa->ifa_addr)
continue;
393 if (!(ifa->ifa_flags & IFF_UP) || !(ifa->ifa_flags & IFF_MULTICAST))
395 if ((ifa->ifa_flags & IFF_LOOPBACK) || (ifa->ifa_flags & IFF_POINTOPOINT))
398 if (ifa->ifa_addr->sa_family == AF_INET) {
399 struct sockaddr_in* saddr = (
struct sockaddr_in*)ifa->ifa_addr;
400 if (saddr->sin_addr.s_addr != htonl(INADDR_LOOPBACK)) {
403 service_address_ipv4 = *saddr;
410 mdns_string_t addr = ipv4_address_to_string(
411 buffer,
sizeof(buffer), saddr,
sizeof(
struct sockaddr_in));
412 std::string addr_string(addr.str, addr.length);
413 ret_vec.push_back(addr_string);
bool Add(const Entry &entry)
Add new entry to the cache.
Global variables reflecting command line options and arguments.