]>
Commit | Line | Data |
---|---|---|
f6eddb84 JL |
1 | /* |
2 | * Embedded Avahi client. This file is part of Shairport. | |
3 | * Copyright (c) James Laird 2013 | |
4d6f5b48 | 4 | * Additions for metadata and for detecting IPv6 Copyright (c) Mike Brady 2015--2019 |
f6eddb84 JL |
5 | * All rights reserved. |
6 | * | |
7 | * Permission is hereby granted, free of charge, to any person | |
8 | * obtaining a copy of this software and associated documentation | |
9 | * files (the "Software"), to deal in the Software without | |
10 | * restriction, including without limitation the rights to use, | |
11 | * copy, modify, merge, publish, distribute, sublicense, and/or | |
12 | * sell copies of the Software, and to permit persons to whom the | |
13 | * Software is furnished to do so, subject to the following conditions: | |
14 | * | |
15 | * The above copyright notice and this permission notice shall be | |
16 | * included in all copies or substantial portions of the Software. | |
17 | * | |
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |
19 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES | |
20 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | |
21 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT | |
22 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | |
23 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
24 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | |
25 | * OTHER DEALINGS IN THE SOFTWARE. | |
26 | */ | |
27 | ||
139c18bf | 28 | #include <pthread.h> |
d343a851 | 29 | #include <stdlib.h> |
f0195c5d | 30 | |
fe3b70b4 MB |
31 | #include "config.h" |
32 | ||
ca8ae1fa MB |
33 | #include "common.h" |
34 | #include "mdns.h" | |
3cb86f40 | 35 | #include "rtsp.h" |
69642bb7 | 36 | #ifdef CONFIG_DACP_CLIENT |
fe3b70b4 | 37 | #include "dacp.h" |
e0ecdac9 | 38 | #endif |
064bd293 | 39 | #include <string.h> |
ca8ae1fa | 40 | |
f6eddb84 JL |
41 | #include <avahi-client/client.h> |
42 | #include <avahi-client/publish.h> | |
f6eddb84 | 43 | #include <avahi-common/error.h> |
064bd293 MB |
44 | #include <avahi-common/malloc.h> |
45 | #include <avahi-common/thread-watch.h> | |
f6eddb84 | 46 | |
f864adf3 | 47 | #include <avahi-client/lookup.h> |
dace5b05 | 48 | #include <avahi-common/alternative.h> |
f6eddb84 | 49 | |
23d86d0a MB |
50 | void threaded_poll_unlock(void *arg) { avahi_threaded_poll_unlock((AvahiThreadedPoll *)arg); } |
51 | ||
fd880056 MB |
52 | #define pthread_avahi_threaded_poll_lock_and_push(mu) \ |
53 | avahi_threaded_poll_lock(mu); \ | |
23d86d0a MB |
54 | pthread_cleanup_push(threaded_poll_unlock, (void *)mu) |
55 | ||
de180967 MB |
56 | #define check_avahi_response(debugLevelArg, veryUnLikelyArgumentName) \ |
57 | { \ | |
58 | int rc = veryUnLikelyArgumentName; \ | |
59 | if (rc) \ | |
60 | debug(debugLevelArg, "avahi call response %d at __FILE__, __LINE__)", rc); \ | |
61 | } | |
62 | ||
139c18bf | 63 | typedef struct { |
d343a851 | 64 | AvahiServiceBrowser *service_browser; |
32c7a535 | 65 | char *dacp_id; |
139c18bf MB |
66 | } dacp_browser_struct; |
67 | ||
72079ada MB |
68 | dacp_browser_struct private_dbs; |
69 | ||
3a02b79a | 70 | AvahiStringList *text_record_string_list = NULL; |
e1034e11 | 71 | AvahiStringList *ap2_text_record_string_list = NULL; |
3a02b79a | 72 | |
d343a851 | 73 | // static AvahiServiceBrowser *sb = NULL; |
f6eddb84 | 74 | static AvahiClient *client = NULL; |
139c18bf | 75 | // static AvahiClient *service_client = NULL; |
f6eddb84 JL |
76 | static AvahiEntryGroup *group = NULL; |
77 | static AvahiThreadedPoll *tpoll = NULL; | |
139c18bf | 78 | // static AvahiThreadedPoll *service_poll = NULL; |
f6eddb84 | 79 | |
139c18bf | 80 | static char *service_name = NULL; |
e1034e11 MB |
81 | char *ap2_service_name = NULL; |
82 | ||
38969090 | 83 | static int port = 0; |
f6eddb84 | 84 | |
d343a851 MB |
85 | static void resolve_callback(AvahiServiceResolver *r, AVAHI_GCC_UNUSED AvahiIfIndex interface, |
86 | AVAHI_GCC_UNUSED AvahiProtocol protocol, AvahiResolverEvent event, | |
87 | const char *name, const char *type, const char *domain, | |
8991f342 MB |
88 | __attribute__((unused)) const char *host_name, |
89 | __attribute__((unused)) const AvahiAddress *address, uint16_t port, | |
90 | __attribute__((unused)) AvahiStringList *txt, | |
91 | __attribute__((unused)) AvahiLookupResultFlags flags, void *userdata) { | |
4d6f5b48 | 92 | // debug(1,"resolve_callback, event %d.", event); |
d343a851 | 93 | assert(r); |
1637a79d | 94 | |
32c7a535 | 95 | dacp_browser_struct *dbs = (dacp_browser_struct *)userdata; |
d343a851 MB |
96 | |
97 | /* Called whenever a service has been resolved successfully or timed out */ | |
98 | switch (event) { | |
c2e3fa5a MB |
99 | case AVAHI_RESOLVER_FAILURE: |
100 | debug(2, "(Resolver) Failed to resolve service '%s' of type '%s' in domain '%s': %s.", name, | |
101 | type, domain, avahi_strerror(avahi_client_errno(avahi_service_resolver_get_client(r)))); | |
102 | break; | |
103 | case AVAHI_RESOLVER_FOUND: { | |
104 | // char a[AVAHI_ADDRESS_STR_MAX], *t; | |
4d6f5b48 | 105 | debug(3, "resolve_callback: Service '%s' of type '%s' in domain '%s':", name, type, domain); |
72079ada MB |
106 | if (dbs->dacp_id) { |
107 | char *dacpid = strstr(name, "iTunes_Ctrl_"); | |
108 | if (dacpid) { | |
109 | dacpid += strlen("iTunes_Ctrl_"); | |
eef6bbf9 | 110 | while (*dacpid == '0') |
df7d6df0 | 111 | dacpid++; // skip any leading zeroes |
72079ada | 112 | if (strcmp(dacpid, dbs->dacp_id) == 0) { |
4090b2d8 | 113 | debug(3, "resolve_callback: client dacp_id \"%s\" dacp port: %u.", dbs->dacp_id, port); |
69642bb7 | 114 | #ifdef CONFIG_DACP_CLIENT |
72079ada | 115 | dacp_monitor_port_update_callback(dacpid, port); |
c2e3fa5a MB |
116 | #endif |
117 | #ifdef CONFIG_METADATA | |
72079ada MB |
118 | char portstring[20]; |
119 | memset(portstring, 0, sizeof(portstring)); | |
120 | snprintf(portstring, sizeof(portstring), "%u", port); | |
7258a45b | 121 | send_ssnc_metadata('dapo', portstring, strlen(portstring), 0); |
c2e3fa5a | 122 | #endif |
72079ada MB |
123 | } |
124 | } else { | |
125 | debug(1, "Resolve callback: Can't see a DACP string in a DACP Record!"); | |
d343a851 | 126 | } |
f864adf3 | 127 | } |
d343a851 | 128 | } |
c2e3fa5a | 129 | } |
7e0f6acb | 130 | // debug(1,"service resolver freed by resolve_callback"); |
4d6f5b48 | 131 | avahi_service_resolver_free(r); |
f864adf3 | 132 | } |
4d6f5b48 | 133 | |
d343a851 MB |
134 | static void browse_callback(AvahiServiceBrowser *b, AvahiIfIndex interface, AvahiProtocol protocol, |
135 | AvahiBrowserEvent event, const char *name, const char *type, | |
136 | const char *domain, AVAHI_GCC_UNUSED AvahiLookupResultFlags flags, | |
137 | void *userdata) { | |
4d6f5b48 | 138 | // debug(1,"browse_callback, event %d.", event); |
d343a851 MB |
139 | assert(b); |
140 | /* Called whenever a new services becomes available on the LAN or is removed from the LAN */ | |
141 | switch (event) { | |
142 | case AVAHI_BROWSER_FAILURE: | |
143 | warn("avahi: browser failure.", | |
144 | avahi_strerror(avahi_client_errno(avahi_service_browser_get_client(b)))); | |
145 | avahi_threaded_poll_quit(tpoll); | |
146 | break; | |
147 | case AVAHI_BROWSER_NEW: | |
4d6f5b48 MB |
148 | // debug(1, "browse_callback: avahi_service_resolver_new for service '%s' of type '%s' in domain |
149 | // '%s'.", name, type, domain); | |
d343a851 MB |
150 | /* We ignore the returned resolver object. In the callback |
151 | function we free it. If the server is terminated before | |
152 | the callback function is called the server will free | |
153 | the resolver for us. */ | |
4d6f5b48 | 154 | if (!(avahi_service_resolver_new(client, interface, protocol, name, type, domain, |
d343a851 MB |
155 | AVAHI_PROTO_UNSPEC, 0, resolve_callback, userdata))) |
156 | debug(1, "Failed to resolve service '%s': %s.", name, | |
4d6f5b48 | 157 | avahi_strerror(avahi_client_errno(client))); |
d343a851 MB |
158 | break; |
159 | case AVAHI_BROWSER_REMOVE: | |
4d6f5b48 | 160 | debug(2, "(Browser) REMOVE: service '%s' of type '%s' in domain '%s'.", name, type, domain); |
69642bb7 | 161 | #ifdef CONFIG_DACP_CLIENT |
cf70c123 | 162 | dacp_browser_struct *dbs = (dacp_browser_struct *)userdata; |
d343a851 MB |
163 | char *dacpid = strstr(name, "iTunes_Ctrl_"); |
164 | if (dacpid) { | |
165 | dacpid += strlen("iTunes_Ctrl_"); | |
282871ea | 166 | while (*dacpid == '0') |
df7d6df0 | 167 | dacpid++; // skip any leading zeroes |
72079ada | 168 | if ((dbs->dacp_id) && (strcmp(dacpid, dbs->dacp_id) == 0)) |
32c7a535 | 169 | dacp_monitor_port_update_callback(dbs->dacp_id, 0); // say the port is withdrawn |
d343a851 MB |
170 | } else { |
171 | debug(1, "Browse callback: Can't see a DACP string in a DACP Record!"); | |
139c18bf | 172 | } |
32c7a535 | 173 | #endif |
d343a851 MB |
174 | break; |
175 | case AVAHI_BROWSER_ALL_FOR_NOW: | |
176 | case AVAHI_BROWSER_CACHE_EXHAUSTED: | |
177 | // debug(1, "(Browser) %s.", event == AVAHI_BROWSER_CACHE_EXHAUSTED ? "CACHE_EXHAUSTED" : | |
178 | // "ALL_FOR_NOW"); | |
179 | break; | |
180 | } | |
181 | } | |
139c18bf | 182 | |
064bd293 | 183 | static void register_service(AvahiClient *c); |
49093398 | 184 | |
87a0475c | 185 | static void egroup_callback(AvahiEntryGroup *g, AvahiEntryGroupState state, |
f6eddb84 | 186 | AVAHI_GCC_UNUSED void *userdata) { |
4d6f5b48 | 187 | // debug(1,"egroup_callback, state %d.", state); |
064bd293 | 188 | switch (state) { |
c2e3fa5a MB |
189 | case AVAHI_ENTRY_GROUP_ESTABLISHED: |
190 | /* The entry group has been established successfully */ | |
4d6f5b48 | 191 | debug(2, "avahi: service '%s' successfully added.", service_name); |
c2e3fa5a | 192 | break; |
064bd293 | 193 | |
c2e3fa5a MB |
194 | case AVAHI_ENTRY_GROUP_COLLISION: { |
195 | char *n; | |
064bd293 | 196 | |
c2e3fa5a MB |
197 | /* A service name collision with a remote service |
198 | * happened. Let's pick a new name */ | |
e1034e11 | 199 | debug(1, "avahi name collision -- look for another"); |
c2e3fa5a MB |
200 | n = avahi_alternative_service_name(service_name); |
201 | if (service_name) | |
202 | avahi_free(service_name); | |
203 | else | |
204 | debug(1, "avahi attempt to free a NULL service name"); | |
205 | service_name = n; | |
064bd293 | 206 | |
c2e3fa5a | 207 | debug(2, "avahi: service name collision, renaming service to '%s'", service_name); |
064bd293 | 208 | |
04e3f891 | 209 | /* And try to recreate the services */ |
c2e3fa5a MB |
210 | register_service(avahi_entry_group_get_client(g)); |
211 | break; | |
212 | } | |
064bd293 | 213 | |
c2e3fa5a MB |
214 | case AVAHI_ENTRY_GROUP_FAILURE: |
215 | debug(1, "avahi: entry group failure: %s", | |
216 | avahi_strerror(avahi_client_errno(avahi_entry_group_get_client(g)))); | |
217 | break; | |
064bd293 | 218 | |
c2e3fa5a MB |
219 | case AVAHI_ENTRY_GROUP_UNCOMMITED: |
220 | debug(2, "avahi: service '%s' group is not yet committed.", service_name); | |
221 | break; | |
222 | ||
223 | case AVAHI_ENTRY_GROUP_REGISTERING: | |
224 | debug(2, "avahi: service '%s' group is registering.", service_name); | |
225 | break; | |
226 | ||
227 | default: | |
228 | debug(1, "avahi: unhandled egroup state: %d", state); | |
229 | break; | |
064bd293 | 230 | } |
f6eddb84 JL |
231 | } |
232 | ||
04e3f891 MB |
233 | static int deregister_service(AVAHI_GCC_UNUSED AvahiClient *c) { |
234 | int response = 0; | |
235 | if (group != NULL) { | |
236 | response = avahi_entry_group_free(group); | |
237 | group = NULL; | |
238 | } | |
239 | return response; | |
240 | } | |
241 | ||
f6eddb84 | 242 | static void register_service(AvahiClient *c) { |
87a0475c MB |
243 | if (!group) |
244 | group = avahi_entry_group_new(c, egroup_callback, NULL); | |
245 | if (!group) | |
4d6f5b48 | 246 | debug(1, "avahi: avahi_entry_group_new failed"); |
7b3694d9 | 247 | else { |
4d6f5b48 | 248 | // debug(2, "register_service -- go ahead and register."); |
7b3694d9 MB |
249 | if (!avahi_entry_group_is_empty(group)) |
250 | return; | |
251 | ||
3a02b79a MB |
252 | int ret = 0; |
253 | ||
2cab35cd | 254 | AvahiIfIndex selected_interface; |
cf29625d | 255 | if (config.interface != NULL) |
2cab35cd MB |
256 | selected_interface = config.interface_index; |
257 | else | |
258 | selected_interface = AVAHI_IF_UNSPEC; | |
e1034e11 | 259 | if (ap2_text_record_string_list) { |
a382ac66 | 260 | ret = avahi_entry_group_add_service_strlst(group, selected_interface, AVAHI_PROTO_UNSPEC, 0, |
a109b587 MB |
261 | ap2_service_name, config.regtype2, NULL, NULL, |
262 | port, ap2_text_record_string_list); | |
a382ac66 MB |
263 | if (ret == AVAHI_ERR_COLLISION) { |
264 | die("Error: AirPlay 2 name \"%s\" is already in use.", ap2_service_name); | |
265 | } | |
e1034e11 MB |
266 | } |
267 | if ((ret == 0) && (text_record_string_list)) { | |
3a02b79a MB |
268 | ret = avahi_entry_group_add_service_strlst(group, selected_interface, AVAHI_PROTO_UNSPEC, 0, |
269 | service_name, config.regtype, NULL, NULL, port, | |
270 | text_record_string_list); | |
a382ac66 MB |
271 | if (ret == AVAHI_ERR_COLLISION) { |
272 | die("Error: AirPlay 1 name \"%s\" is already in use.", service_name); | |
273 | } | |
e1034e11 | 274 | } |
a109b587 MB |
275 | if (ret == 0) { |
276 | ret = avahi_entry_group_commit(group); | |
277 | debug(2, "avahi: avahi_entry_group_commit %d", ret); | |
278 | if (ret < 0) | |
279 | debug(1, "avahi: avahi_entry_group_commit failed"); | |
280 | } else if (ret < 0) { | |
281 | debug(1, "avahi: avahi_entry_group_add_service failed"); | |
282 | } else { | |
283 | debug(1, "avahi: unexpected positive return"); | |
284 | } | |
87a0475c | 285 | } |
f6eddb84 JL |
286 | } |
287 | ||
87a0475c MB |
288 | static void client_callback(AvahiClient *c, AvahiClientState state, |
289 | AVAHI_GCC_UNUSED void *userdata) { | |
4d6f5b48 | 290 | // debug(1,"client_callback, state %d.", state); |
9e61da91 JK |
291 | int err; |
292 | ||
87a0475c | 293 | switch (state) { |
064bd293 MB |
294 | case AVAHI_CLIENT_S_REGISTERING: |
295 | if (group) | |
de180967 | 296 | check_avahi_response(1, avahi_entry_group_reset(group)); |
064bd293 MB |
297 | break; |
298 | ||
299 | case AVAHI_CLIENT_S_RUNNING: | |
300 | register_service(c); | |
301 | break; | |
302 | ||
303 | case AVAHI_CLIENT_FAILURE: | |
9e61da91 | 304 | err = avahi_client_errno(c); |
9e61da91 | 305 | if (err == AVAHI_ERR_DISCONNECTED) { |
04e3f891 MB |
306 | debug(1, "avahi client disconnected -- reconnection attempted."); |
307 | if (c) { | |
308 | // it seems that the avahi_threaded_poll thread is still running and locked here | |
309 | deregister_service(c); // delete the group | |
310 | dacp_browser_struct *dbs = &private_dbs; | |
311 | if (dbs->service_browser) { | |
312 | int rc = avahi_service_browser_free(dbs->service_browser); // delete the service browser | |
313 | if (rc != 0) | |
314 | debug(1, | |
315 | "Error %d freeing the Avahi service browser after the Avahi client has been " | |
316 | "disconnected.", | |
317 | rc); | |
318 | dbs->service_browser = NULL; | |
319 | } | |
320 | avahi_client_free(c); // delete the client | |
321 | } | |
cf29625d MB |
322 | if (!(client = avahi_client_new(avahi_threaded_poll_get(tpoll), AVAHI_CLIENT_NO_FAIL, |
323 | client_callback, userdata, &err))) { | |
04e3f891 | 324 | warn("avahi: failed to create a replacement client object: %s", avahi_strerror(err)); |
9e61da91 JK |
325 | avahi_threaded_poll_quit(tpoll); |
326 | } | |
327 | } else { | |
328 | warn("avahi: client failure: %s", avahi_strerror(err)); | |
329 | avahi_threaded_poll_quit(tpoll); | |
330 | } | |
064bd293 MB |
331 | break; |
332 | ||
333 | case AVAHI_CLIENT_S_COLLISION: | |
139c18bf | 334 | debug(2, "avahi: state is AVAHI_CLIENT_S_COLLISION...needs a rename: %s", service_name); |
064bd293 MB |
335 | break; |
336 | ||
337 | case AVAHI_CLIENT_CONNECTING: | |
338 | debug(2, "avahi: received AVAHI_CLIENT_CONNECTING"); | |
339 | break; | |
340 | ||
341 | default: | |
342 | debug(1, "avahi: unexpected and unhandled avahi client state: %d", state); | |
343 | break; | |
87a0475c | 344 | } |
f6eddb84 JL |
345 | } |
346 | ||
4090b2d8 | 347 | static int avahi_update(char **txt_records, char **secondary_txt_records) { |
2e4156d3 MB |
348 | // debug(1, "avahi_update."); |
349 | ||
4090b2d8 MB |
350 | /* |
351 | service_name = strdup(ap1name); | |
352 | if (ap2name != NULL) | |
353 | ap2_service_name = strdup(ap2name); | |
354 | port = srvport; | |
355 | */ | |
2e4156d3 MB |
356 | int err = 0; |
357 | AvahiIfIndex selected_interface; | |
4090b2d8 MB |
358 | if (config.interface != NULL) |
359 | selected_interface = config.interface_index; | |
360 | else | |
361 | selected_interface = AVAHI_IF_UNSPEC; | |
23d86d0a | 362 | pthread_avahi_threaded_poll_lock_and_push(tpoll); |
fd880056 MB |
363 | // avahi_threaded_poll_lock(tpoll); |
364 | // pthread_cleanup_push(threaded_poll_unlock, (void *)tpoll) | |
2e4156d3 MB |
365 | |
366 | if (txt_records != NULL) { | |
367 | if (text_record_string_list) | |
368 | avahi_string_list_free(text_record_string_list); | |
4090b2d8 MB |
369 | text_record_string_list = avahi_string_list_new_from_array((const char **)txt_records, -1); |
370 | err = avahi_entry_group_update_service_txt_strlst(group, selected_interface, AVAHI_PROTO_UNSPEC, | |
371 | 0, service_name, config.regtype, NULL, | |
372 | text_record_string_list); | |
2e4156d3 | 373 | if (err != 0) |
4090b2d8 | 374 | debug(1, "avahi_update error updating primary txt records."); |
2e4156d3 MB |
375 | } |
376 | ||
377 | if (secondary_txt_records != NULL) { | |
378 | if (ap2_text_record_string_list) | |
379 | avahi_string_list_free(ap2_text_record_string_list); | |
380 | ap2_text_record_string_list = | |
4090b2d8 MB |
381 | avahi_string_list_new_from_array((const char **)secondary_txt_records, -1); |
382 | err = avahi_entry_group_update_service_txt_strlst(group, selected_interface, AVAHI_PROTO_UNSPEC, | |
383 | 0, ap2_service_name, config.regtype2, NULL, | |
384 | ap2_text_record_string_list); | |
2e4156d3 | 385 | if (err != 0) |
4090b2d8 | 386 | debug(1, "avahi_update error updating secondary txt records."); |
2e4156d3 | 387 | } |
7fde77c4 | 388 | |
23d86d0a | 389 | pthread_cleanup_pop(1); // unlock the avahi_threaded_poll_lock |
2e4156d3 MB |
390 | return 0; |
391 | } | |
392 | ||
a109b587 MB |
393 | static int avahi_register(char *ap1name, char *ap2name, int srvport, char **txt_records, |
394 | char **secondary_txt_records) { | |
4d6f5b48 | 395 | // debug(1, "avahi_register."); |
e1034e11 MB |
396 | service_name = strdup(ap1name); |
397 | if (ap2name != NULL) | |
398 | ap2_service_name = strdup(ap2name); | |
3a02b79a MB |
399 | |
400 | text_record_string_list = avahi_string_list_new_from_array((const char **)txt_records, -1); | |
401 | ||
e1034e11 | 402 | if (secondary_txt_records != NULL) |
a109b587 MB |
403 | ap2_text_record_string_list = |
404 | avahi_string_list_new_from_array((const char **)secondary_txt_records, -1); | |
e1034e11 | 405 | |
87a0475c MB |
406 | port = srvport; |
407 | ||
408 | int err; | |
409 | if (!(tpoll = avahi_threaded_poll_new())) { | |
410 | warn("couldn't create avahi threaded tpoll!"); | |
411 | return -1; | |
412 | } | |
cf29625d MB |
413 | if (!(client = avahi_client_new(avahi_threaded_poll_get(tpoll), AVAHI_CLIENT_NO_FAIL, |
414 | client_callback, NULL, &err))) { | |
87a0475c MB |
415 | warn("couldn't create avahi client: %s!", avahi_strerror(err)); |
416 | return -1; | |
417 | } | |
f864adf3 | 418 | |
87a0475c MB |
419 | if (avahi_threaded_poll_start(tpoll) < 0) { |
420 | warn("couldn't start avahi tpoll thread"); | |
421 | return -1; | |
422 | } | |
423 | ||
424 | return 0; | |
f6eddb84 JL |
425 | } |
426 | ||
38969090 | 427 | static void avahi_unregister(void) { |
3a02b79a | 428 | debug(2, "avahi_unregister."); |
d805ce91 | 429 | if (tpoll) { |
4e1f74db | 430 | debug(2, "avahi: stop the threaded poll."); |
5f750ba9 | 431 | avahi_threaded_poll_stop(tpoll); |
de180967 | 432 | |
d805ce91 | 433 | if (client) { |
4e1f74db | 434 | debug(2, "avahi: free the client."); |
d805ce91 MB |
435 | avahi_client_free(client); |
436 | client = NULL; | |
de180967 MB |
437 | } else { |
438 | debug(1, "avahi attempting to unregister a NULL client"); | |
439 | } | |
4e1f74db | 440 | debug(2, "avahi: free the threaded poll."); |
d805ce91 MB |
441 | avahi_threaded_poll_free(tpoll); |
442 | tpoll = NULL; | |
f1d45034 MB |
443 | } else { |
444 | debug(1, "No avahi threaded poll."); | |
d805ce91 | 445 | } |
87a0475c | 446 | |
f1d45034 | 447 | if (service_name) { |
4e1f74db | 448 | debug(2, "avahi: free the service name."); |
139c18bf | 449 | free(service_name); |
e1034e11 | 450 | service_name = NULL; |
f1d45034 | 451 | } else |
de180967 | 452 | debug(1, "avahi attempt to free NULL service name"); |
3a02b79a | 453 | |
e1034e11 MB |
454 | if (ap2_service_name) { |
455 | debug(2, "avahi: free the ap2 service_name."); | |
456 | free(ap2_service_name); | |
457 | ap2_service_name = NULL; | |
458 | } | |
459 | ||
3a02b79a MB |
460 | if (text_record_string_list) { |
461 | debug(2, "avahi free text_record_string_list"); | |
462 | avahi_string_list_free(text_record_string_list); | |
e1034e11 MB |
463 | text_record_string_list = NULL; |
464 | } else | |
465 | debug(1, "avahi attempt to free NULL text_record_string_list"); | |
466 | ||
e1034e11 MB |
467 | if (ap2_text_record_string_list) { |
468 | debug(2, "avahi free ap_2text_record_string_list"); | |
469 | avahi_string_list_free(ap2_text_record_string_list); | |
470 | ap2_text_record_string_list = NULL; | |
471 | } | |
139c18bf MB |
472 | } |
473 | ||
72079ada | 474 | void avahi_dacp_monitor_start(void) { |
4d6f5b48 | 475 | // debug(1, "avahi_dacp_monitor_start."); |
72079ada | 476 | memset((void *)&private_dbs, 0, sizeof(dacp_browser_struct)); |
4090b2d8 | 477 | debug(2, "avahi_dacp_monitor_start Avahi DACP monitor successfully started"); |
72079ada | 478 | return; |
139c18bf MB |
479 | } |
480 | ||
72079ada | 481 | void avahi_dacp_monitor_set_id(const char *dacp_id) { |
4d6f5b48 | 482 | // debug(1, "avahi_dacp_monitor_set_id: Search for DACP ID \"%s\".", t); |
72079ada MB |
483 | dacp_browser_struct *dbs = &private_dbs; |
484 | ||
4090b2d8 MB |
485 | if (((dbs->dacp_id) && (dacp_id) && (strcmp(dbs->dacp_id, dacp_id) == 0)) || |
486 | ((dbs->dacp_id == NULL) && (dacp_id == NULL))) { | |
487 | debug(3, "no change..."); | |
488 | } else { | |
489 | if (dbs->dacp_id) | |
490 | free(dbs->dacp_id); | |
491 | if (dacp_id == NULL) | |
492 | dbs->dacp_id = NULL; | |
493 | else { | |
494 | char *t = strdup(dacp_id); | |
495 | if (t) { | |
496 | dbs->dacp_id = t; | |
23d86d0a MB |
497 | pthread_avahi_threaded_poll_lock_and_push(tpoll); |
498 | // avahi_threaded_poll_lock(tpoll); | |
4090b2d8 MB |
499 | if (dbs->service_browser) |
500 | avahi_service_browser_free(dbs->service_browser); | |
501 | ||
502 | if (!(dbs->service_browser = | |
503 | avahi_service_browser_new(client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, | |
504 | "_dacp._tcp", NULL, 0, browse_callback, (void *)dbs))) { | |
505 | warn("failed to create avahi service browser: %s\n", | |
506 | avahi_strerror(avahi_client_errno(client))); | |
507 | } | |
23d86d0a MB |
508 | pthread_cleanup_pop(1); // unlock the avahi_threaded_poll_lock |
509 | // avahi_threaded_poll_unlock(tpoll); | |
4090b2d8 MB |
510 | debug(2, "dacp_monitor for \"%s\"", dacp_id); |
511 | } else { | |
512 | warn("avahi_dacp_set_id: can not allocate a dacp_id string in dacp_browser_struct."); | |
72079ada | 513 | } |
7e0f6acb | 514 | } |
72079ada MB |
515 | } |
516 | } | |
517 | ||
518 | void avahi_dacp_monitor_stop() { | |
4d6f5b48 | 519 | // debug(1, "avahi_dacp_monitor_stop"); |
72079ada MB |
520 | dacp_browser_struct *dbs = &private_dbs; |
521 | // stop and dispose of everything | |
23d86d0a MB |
522 | pthread_avahi_threaded_poll_lock_and_push(tpoll); |
523 | // avahi_threaded_poll_lock(tpoll); | |
4d6f5b48 MB |
524 | if (dbs->service_browser) { |
525 | avahi_service_browser_free(dbs->service_browser); | |
526 | dbs->service_browser = NULL; | |
3cb86f40 | 527 | } |
23d86d0a MB |
528 | pthread_cleanup_pop(1); // unlock the avahi_threaded_poll_lock |
529 | // avahi_threaded_poll_unlock(tpoll); | |
72079ada | 530 | free(dbs->dacp_id); |
4e1f74db | 531 | debug(2, "avahi_dacp_monitor_stop Avahi DACP monitor successfully stopped"); |
f6eddb84 JL |
532 | } |
533 | ||
d343a851 MB |
534 | mdns_backend mdns_avahi = {.name = "avahi", |
535 | .mdns_register = avahi_register, | |
2e4156d3 | 536 | .mdns_update = avahi_update, |
d343a851 | 537 | .mdns_unregister = avahi_unregister, |
72079ada MB |
538 | .mdns_dacp_monitor_start = avahi_dacp_monitor_start, |
539 | .mdns_dacp_monitor_set_id = avahi_dacp_monitor_set_id, | |
540 | .mdns_dacp_monitor_stop = avahi_dacp_monitor_stop}; |