40#if !defined (__linux__)
41void mdns_publish(
const char *name,
const char *service, uint16_t port) __attribute__ ((weak));
42void mdns_unpublish(
const char *name,
const char *service) __attribute__ ((weak));
44 struct addrinfo **addr) __attribute__ ((weak));
45void mdns_scan(
const char *service) __attribute__ ((weak));
52void mdns_publish(
const char *name,
const char *service, uint16_t port)
76#if defined(__FreeRTOS__)
77 string mdns_name(service);
78 mdns_name.append(
".local");
79 return ::getaddrinfo(
nullptr, mdns_name.c_str(), hints, addr);
81 DIE(
"Your OS does not support mDNS");
97void MDNS::publish(
const char *name,
const char *service, uint16_t port)
99#if defined (__linux__)
100 name = avahi_strdup(name);
104 group_ = avahi_entry_group_new(client_, entry_group_callback,
this);
107 fprintf(stderr,
"avahi_entry_group_new() failed: %s\n",
108 avahi_strerror(avahi_client_errno(client_)));
114 int result = avahi_entry_group_add_service(group_, AVAHI_IF_UNSPEC,
116 (AvahiPublishFlags)0, name,
123 fprintf(stderr,
"Error exporting mDNS name (%d) %s\n", result,
124 avahi_strerror(result));
139#if defined(__linux__)
140 DIE(
"unimplemented");
152#if defined (__linux__)
153 LookupUserdata lu(hints);
154 AvahiServiceBrowser *sb =
nullptr;
163 protocol = AVAHI_PROTO_INET;
166 protocol = AVAHI_PROTO_INET6;
169 protocol = AVAHI_PROTO_UNSPEC;
178 lu.sp = avahi_simple_poll_new();
185 lu.c = avahi_client_new(avahi_simple_poll_get(lu.sp),
186 (AvahiClientFlags)0, client_callback,
195 sb = avahi_service_browser_new(lu.c, AVAHI_IF_UNSPEC, protocol, service,
196 nullptr, (AvahiLookupFlags)0,
197 browse_callback, (
void*)&lu);
205 avahi_simple_poll_loop(lu.sp);
221 avahi_service_browser_free(sb);
226 avahi_client_free(lu.c);
231 avahi_simple_poll_free(lu.sp);
245#if defined (__linux__)
251#if defined (__linux__)
255void MDNS::resolve_callback(AvahiServiceResolver *r,
256 AvahiIfIndex interface, AvahiProtocol protocol,
257 AvahiResolverEvent event,
const char *name,
258 const char *type,
const char *domain,
259 const char *host_name,
260 const AvahiAddress *address, uint16_t port,
261 AvahiStringList *txt,
262 AvahiLookupResultFlags flags,
void* userdata)
265 LookupUserdata *lu =
static_cast<LookupUserdata*
>(userdata);
270 case AVAHI_RESOLVER_FAILURE:
272 fprintf(stderr,
"(Resolver) Failed to resolve service '%s' of type "
273 "'%s' in domain '%s': %s\n", name, type, domain,
274 avahi_strerror(avahi_client_errno(
275 avahi_service_resolver_get_client(r))));
278 case AVAHI_RESOLVER_FOUND:
286 memset(ai, 0,
sizeof(
struct addrinfo));
287 memset(sa, 0,
sizeof(
struct sockaddr));
297 ai->
ai_canonname = (
char*)malloc(strlen(host_name) + 1);
303 case AVAHI_PROTO_INET:
313 case AVAHI_PROTO_INET6:
315 struct sockaddr_in6 *sa_in = (
struct sockaddr_in6*)sa;
318 sa_in->sin6_flowinfo = 0;
320 sa_in->sin6_port =
htons(port);
321 memcpy(&(sa_in->sin6_addr.s6_addr),
322 address->data.ipv6.address,
323 sizeof(address->data.ipv6.address));
338 struct addrinfo *current = lu->addr;
346 char a[AVAHI_ADDRESS_STR_MAX], *t;
348 fprintf(stderr,
"Service '%s' of type '%s' in domain '%s':\n",
350 avahi_address_snprint(a,
sizeof(a), address);
351 t = txt ? &nil : avahi_string_list_to_string(txt);
361 host_name, port, a, t,
362 avahi_string_list_get_service_cookie(txt),
363 !!(flags & AVAHI_LOOKUP_RESULT_LOCAL),
364 !!(flags & AVAHI_LOOKUP_RESULT_OUR_OWN),
365 !!(flags & AVAHI_LOOKUP_RESULT_WIDE_AREA),
366 !!(flags & AVAHI_LOOKUP_RESULT_MULTICAST),
367 !!(flags & AVAHI_LOOKUP_RESULT_CACHED));
375 if (--lu->count == 0)
379 avahi_simple_poll_quit(lu->sp);
382 avahi_service_resolver_free(r);
388void MDNS::browse_callback(AvahiServiceBrowser *b, AvahiIfIndex interface,
389 AvahiProtocol protocol, AvahiBrowserEvent event,
390 const char *name,
const char *type,
392 AvahiLookupResultFlags flags,
void* userdata)
394 LookupUserdata *lu =
static_cast<LookupUserdata*
>(userdata);
395 AvahiClient *c = lu->c;
399 case AVAHI_BROWSER_FAILURE:
401 case AVAHI_BROWSER_NEW:
403 fprintf(stderr,
"(Browser) NEW: service '%s' of type '%s' "
404 "in domain '%s'\n", name, type, domain);
410 if (!avahi_service_resolver_new(c, interface, protocol, name, type,
411 domain, AVAHI_PROTO_UNSPEC,
413 resolve_callback, userdata))
416 fprintf(stderr,
"Failed to resolve service '%s': %s\n",
417 name, avahi_strerror(avahi_client_errno(c)));
425 case AVAHI_BROWSER_REMOVE:
427 case AVAHI_BROWSER_ALL_FOR_NOW:
428 case AVAHI_BROWSER_CACHE_EXHAUSTED:
430 fprintf(stderr,
"(Browser) %s\n",
431 event == AVAHI_BROWSER_CACHE_EXHAUSTED ?
"CACHE_EXHAUSTED" :
437 avahi_simple_poll_quit(lu->sp);
446void MDNS::entry_group_callback(AvahiEntryGroup *g, AvahiEntryGroupState state,
449 MDNS *mdns =
static_cast<MDNS *
>(userdata);
456void MDNS::client_callback(AvahiClient *c, AvahiClientState state,
463 case AVAHI_CLIENT_S_RUNNING:
464 printf(
"mDNS client running\n");
476 simplePoll_ = avahi_simple_poll_new();
479 client_ = avahi_client_new(avahi_simple_poll_get(simplePoll_),
480 (AvahiClientFlags)0, client_callback,
this,
486 fprintf(stderr,
"Error creating AvaHi client (%d) %s\nmDNS export will "
487 "not be functional.\n", error, avahi_strerror(error));
491 printf(
"mDNS client created\n");
495 avahi_simple_poll_loop(simplePoll_);
497 printf(
"mdns_thread exit\n");
501 avahi_entry_group_reset(group_);
502 avahi_entry_group_free(group_);
508 avahi_client_free(client_);
512 avahi_simple_poll_free(simplePoll_);
513 simplePoll_ =
nullptr;
523 avahi_simple_poll_quit(simplePoll_);
void mdns_publish(const char *name, const char *service, uint16_t port)
Publish an mDNS name.
void mdns_unpublish(const char *name, const char *service)
Unpublish an mDNS name.
void mdns_scan(const char *service)
Start continuous scan for mDNS service name.
int mdns_lookup(const char *service, struct addrinfo *hints, struct addrinfo **addr)
Lookup an mDNS name.
static void scan(const char *service)
Start continuous scan for mDNS service name.
static int lookup(const char *service, struct addrinfo *hints, struct addrinfo **addr)
Lookup an mDNS name.
void unpublish(const char *name, const char *service)
Constructor.
#define htons(x)
Converts a host endian short value to network endian.
#define IPPROTO_TCP
TCP Raw Socket.
#define HASSERT(x)
Checks that the value of expression x is true, else terminates the current process.
#define DIE(MSG)
Unconditionally terminates the current process with a message.
void mdns_publish(const char *name, const char *service, uint16_t port)
Publish an mDNS name.
void mdns_unpublish(const char *name, const char *service)
Unpublish an mDNS name.
#define EAI_MEMORY
Memory allocation failure.
#define SOCK_STREAM
TCP Socket.
#define AF_INET
IPv4 Socket (UDP, TCP, etc...)
#define AF_INET6
IPv6 Socket (UDP, TCP, etc...)
Structure to contain information about address of a service provider.
struct sockaddr * ai_addr
Socket address for socket.
char * ai_canonname
Canonical name for service location.
int ai_socktype
Socket type.
int ai_protocol
Protocol for socket.
socklen_t ai_addrlen
Length of socket address.
struct addrinfo * ai_next
Pointer to next in list.
int ai_family
Protocol family for socket.
Structure describing an Internet socket address.
uint16_t sin_family
protocol family (AF_INET)
uint16_t sin_port
port number
struct in_addr sin_addr
internet address