2 This file is part of avahi.
4 avahi is free software; you can redistribute it and/or modify it
5 under the terms of the GNU Lesser General Public License as
6 published by the Free Software Foundation; either version 2.1 of the
7 License, or (at your option) any later version.
9 avahi is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
12 Public License for more details.
14 You should have received a copy of the GNU Lesser General Public
15 License along with avahi; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
28 #include <avahi-common/strlst.h>
29 #include <avahi-common/malloc.h>
30 #include <avahi-common/domain.h>
31 #include <avahi-common/simple-watch.h>
32 #include <avahi-common/error.h>
33 #include <avahi-common/llist.h>
35 #include <avahi-client/client.h>
36 #include <avahi-client/publish.h>
37 #include <avahi-client/lookup.h>
47 COMMAND_POLL_DONE = 'P',
48 COMMAND_POLL_FAILED = 'F'
59 typedef struct service_data service_data;
61 typedef struct oid_data {
64 sw_discovery discovery;
66 sw_result (*reply)(void);
67 service_data *service_data;
72 char *name, *regtype, *domain, *host;
74 AvahiIfIndex interface;
76 AVAHI_LLIST_FIELDS(service_data, services);
79 struct _sw_discovery {
81 AvahiSimplePoll *simple_poll;
84 oid_data oid_table[OID_MAX];
85 sw_discovery_oid oid_index;
87 int thread_fd, main_fd;
92 pthread_mutex_t mutex, salt_mutex;
94 AVAHI_LLIST_HEAD(service_data, services);
97 #define ASSERT_SUCCESS(r) { int __ret = (r); assert(__ret == 0); }
99 #define OID_GET_INDEX(data) ((sw_discovery_oid) (((data) - ((data)->discovery->oid_table))))
101 static sw_discovery discovery_ref(sw_discovery self);
102 static void discovery_unref(sw_discovery self);
104 static const char *add_trailing_dot(const char *s, char *buf, size_t buf_len) {
111 if (s[strlen(s)-1] == '.')
114 snprintf(buf, buf_len, "%s.", s);
118 static sw_result map_error(int error) {
123 case AVAHI_ERR_NO_MEMORY:
130 static int read_command(int fd) {
136 if ((r = read(fd, &command, 1)) != 1) {
137 fprintf(stderr, __FILE__": read() failed: %s\n", r < 0 ? strerror(errno) : "EOF");
144 static int write_command(int fd, char reply) {
147 if (write(fd, &reply, 1) != 1) {
148 fprintf(stderr, __FILE__": write() failed: %s\n", strerror(errno));
155 static int poll_func(struct pollfd *ufds, unsigned int nfds, int timeout, void *userdata) {
156 sw_discovery self = userdata;
161 ASSERT_SUCCESS(pthread_mutex_unlock(&self->mutex));
162 ret = poll(ufds, nfds, timeout);
163 ASSERT_SUCCESS(pthread_mutex_lock(&self->mutex));
168 static void * thread_func(void *data) {
169 sw_discovery self = data;
173 pthread_sigmask(SIG_BLOCK, &mask, NULL);
175 self->thread = pthread_self();
176 self->thread_running = 1;
181 if ((command = read_command(self->thread_fd)) < 0)
184 /* fprintf(stderr, "Command: %c\n", command); */
191 ASSERT_SUCCESS(pthread_mutex_lock(&self->mutex));
196 if ((ret = avahi_simple_poll_run(self->simple_poll)) < 0) {
201 fprintf(stderr, __FILE__": avahi_simple_poll_run() failed: %s\n", strerror(errno));
207 ASSERT_SUCCESS(pthread_mutex_unlock(&self->mutex));
209 if (write_command(self->thread_fd, ret < 0 ? COMMAND_POLL_FAILED : COMMAND_POLL_DONE) < 0)
224 static int oid_alloc(sw_discovery self, oid_type type) {
228 for (i = 0; i < OID_MAX; i++) {
230 while (self->oid_index >= OID_MAX)
231 self->oid_index -= OID_MAX;
233 if (self->oid_table[self->oid_index].type == OID_UNUSED) {
234 self->oid_table[self->oid_index].type = type;
235 self->oid_table[self->oid_index].discovery = self;
237 assert(OID_GET_INDEX(&self->oid_table[self->oid_index]) == self->oid_index);
239 return self->oid_index ++;
245 /* No free entry found */
247 return (sw_discovery_oid) -1;
250 static void oid_release(sw_discovery self, sw_discovery_oid oid) {
252 assert(oid < OID_MAX);
254 assert(self->oid_table[oid].type != OID_UNUSED);
256 self->oid_table[oid].type = OID_UNUSED;
257 self->oid_table[oid].discovery = NULL;
258 self->oid_table[oid].reply = NULL;
259 self->oid_table[oid].object = NULL;
260 self->oid_table[oid].extra = NULL;
261 self->oid_table[oid].service_data = NULL;
264 static oid_data* oid_get(sw_discovery self, sw_discovery_oid oid) {
270 if (self->oid_table[oid].type == OID_UNUSED)
273 return &self->oid_table[oid];
276 static service_data* service_data_new(sw_discovery self) {
281 if (!(sdata = avahi_new0(service_data, 1)))
284 AVAHI_LLIST_PREPEND(service_data, services, self->services, sdata);
290 static void service_data_free(sw_discovery self, service_data* sdata) {
294 AVAHI_LLIST_REMOVE(service_data, services, self->services, sdata);
296 avahi_free(sdata->name);
297 avahi_free(sdata->regtype);
298 avahi_free(sdata->domain);
299 avahi_free(sdata->host);
300 avahi_string_list_free(sdata->txt);
304 static void reg_client_callback(oid_data *data, AvahiClientState state);
306 static void client_callback(AvahiClient *s, AvahiClientState state, void* userdata) {
307 sw_discovery self = userdata;
308 sw_discovery_oid oid;
315 for (oid = 0; oid < OID_MAX; oid++) {
317 switch (self->oid_table[oid].type) {
319 case OID_ENTRY_GROUP:
320 reg_client_callback(&self->oid_table[oid], state);
323 case OID_DOMAIN_BROWSER:
324 case OID_SERVICE_BROWSER:
325 ((sw_discovery_browse_reply) self->oid_table[oid].reply)(self, oid, SW_DISCOVERY_BROWSE_INVALID, 0, NULL, NULL, NULL, self->oid_table[oid].extra);
328 case OID_SERVICE_RESOLVER:
334 discovery_unref(self);
337 sw_result sw_discovery_init(sw_discovery * self) {
338 int fd[2] = { -1, -1};
339 sw_result result = SW_E_UNKNOWN;
340 pthread_mutexattr_t mutex_attr;
349 if (socketpair(AF_UNIX, SOCK_STREAM, 0, fd) < 0)
352 if (!(*self = avahi_new(struct _sw_discovery, 1))) {
358 (*self)->thread_fd = fd[0];
359 (*self)->main_fd = fd[1];
361 (*self)->client = NULL;
362 (*self)->simple_poll = NULL;
364 memset((*self)->oid_table, 0, sizeof((*self)->oid_table));
365 (*self)->oid_index = 0;
367 (*self)->thread_running = 0;
369 AVAHI_LLIST_HEAD_INIT(service_info, (*self)->services);
371 ASSERT_SUCCESS(pthread_mutexattr_init(&mutex_attr));
372 pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_RECURSIVE);
373 ASSERT_SUCCESS(pthread_mutex_init(&(*self)->mutex, &mutex_attr));
374 ASSERT_SUCCESS(pthread_mutex_init(&(*self)->salt_mutex, &mutex_attr));
376 if (!((*self)->simple_poll = avahi_simple_poll_new()))
379 avahi_simple_poll_set_func((*self)->simple_poll, poll_func, *self);
381 if (!((*self)->client = avahi_client_new(avahi_simple_poll_get((*self)->simple_poll), 0, client_callback, *self, &error))) {
382 result = map_error(error);
386 /* Start simple poll */
387 if (avahi_simple_poll_prepare((*self)->simple_poll, -1) < 0)
390 /* Queue an initial POLL command for the thread */
391 if (write_command((*self)->main_fd, COMMAND_POLL) < 0)
394 if (pthread_create(&(*self)->thread, NULL, thread_func, *self) != 0)
397 (*self)->thread_running = 1;
404 sw_discovery_fina(*self);
409 static int stop_thread(sw_discovery self) {
412 if (!self->thread_running)
415 if (write_command(self->main_fd, COMMAND_QUIT) < 0)
418 avahi_simple_poll_wakeup(self->simple_poll);
420 ASSERT_SUCCESS(pthread_join(self->thread, NULL));
421 self->thread_running = 0;
425 static sw_discovery discovery_ref(sw_discovery self) {
427 assert(self->n_ref >= 1);
434 static void discovery_unref(sw_discovery self) {
436 assert(self->n_ref >= 1);
438 if (--self->n_ref > 0)
444 avahi_client_free(self->client);
446 if (self->simple_poll)
447 avahi_simple_poll_free(self->simple_poll);
449 if (self->thread_fd >= 0)
450 close(self->thread_fd);
452 if (self->main_fd >= 0)
453 close(self->main_fd);
455 ASSERT_SUCCESS(pthread_mutex_destroy(&self->mutex));
456 ASSERT_SUCCESS(pthread_mutex_destroy(&self->salt_mutex));
458 while (self->services)
459 service_data_free(self, self->services);
464 sw_result sw_discovery_fina(sw_discovery self) {
470 discovery_unref(self);
475 sw_result sw_discovery_run(sw_discovery self) {
480 return sw_salt_run((sw_salt) self);
483 sw_result sw_discovery_stop_run(sw_discovery self) {
488 return sw_salt_stop_run((sw_salt) self);
491 int sw_discovery_socket(sw_discovery self) {
496 return self->main_fd;
499 sw_result sw_discovery_read_socket(sw_discovery self) {
500 sw_result result = SW_E_UNKNOWN;
506 ASSERT_SUCCESS(pthread_mutex_lock(&self->mutex));
508 /* Cleanup notification socket */
509 if (read_command(self->main_fd) != COMMAND_POLL_DONE)
512 if (avahi_simple_poll_dispatch(self->simple_poll) < 0)
515 if (self->n_ref > 1) /* Perhaps we should die */
517 /* Dispatch events */
518 if (avahi_simple_poll_prepare(self->simple_poll, -1) < 0)
523 /* Request the poll */
524 if (write_command(self->main_fd, COMMAND_POLL) < 0)
531 ASSERT_SUCCESS(pthread_mutex_unlock(&self->mutex));
533 discovery_unref(self);
538 sw_result sw_discovery_salt(sw_discovery self, sw_salt *salt) {
544 *salt = (sw_salt) self;
549 sw_result sw_salt_step(sw_salt self, sw_uint32 * msec) {
556 if (!((sw_discovery) self)->thread_running)
559 memset(&p, 0, sizeof(p));
560 p.fd = ((sw_discovery) self)->main_fd;
563 if ((r = poll(&p, 1, msec ? (int) *msec : -1)) < 0) {
565 /* Don't treat EINTR as error */
579 if (p.revents != POLLIN)
582 if ((result = sw_discovery_read_socket((sw_discovery) self)) != SW_OKAY)
589 sw_result sw_salt_run(sw_salt self) {
597 if ((ret = sw_salt_step(self, NULL)) != SW_OKAY)
601 sw_result sw_salt_stop_run(sw_salt self) {
606 if (stop_thread((sw_discovery) self) < 0)
612 sw_result sw_salt_lock(sw_salt self) {
616 ASSERT_SUCCESS(pthread_mutex_lock(&((sw_discovery) self)->salt_mutex));
621 sw_result sw_salt_unlock(sw_salt self) {
626 ASSERT_SUCCESS(pthread_mutex_unlock(&((sw_discovery) self)->salt_mutex));
631 static void reg_report_status(oid_data *data, sw_discovery_publish_status status) {
632 sw_discovery_publish_reply reply;
636 reply = (sw_discovery_publish_reply) data->reply;
638 reply(data->discovery,
644 static int reg_create_service(oid_data *data) {
646 const char *real_type;
650 real_type = avahi_get_type_from_subtype(data->service_data->regtype);
652 if ((ret = avahi_entry_group_add_service_strlst(
654 data->service_data->interface,
657 data->service_data->name,
658 real_type ? real_type : data->service_data->regtype,
659 data->service_data->domain,
660 data->service_data->host,
661 data->service_data->port,
662 data->service_data->txt)) < 0)
666 /* Create a subtype entry */
668 if (avahi_entry_group_add_service_subtype(
670 data->service_data->interface,
673 data->service_data->name,
675 data->service_data->domain,
676 data->service_data->regtype) < 0)
681 if ((ret = avahi_entry_group_commit(data->object)) < 0)
687 static void reg_client_callback(oid_data *data, AvahiClientState state) {
690 /* We've not been setup completely */
695 case AVAHI_CLIENT_FAILURE:
696 reg_report_status(data, SW_DISCOVERY_PUBLISH_INVALID);
699 case AVAHI_CLIENT_S_RUNNING: {
702 /* Register the service */
703 if ((ret = reg_create_service(data)) < 0) {
704 reg_report_status(data, SW_DISCOVERY_PUBLISH_INVALID);
711 case AVAHI_CLIENT_S_COLLISION:
712 case AVAHI_CLIENT_S_REGISTERING:
714 /* Remove our entry */
715 avahi_entry_group_reset(data->object);
718 case AVAHI_CLIENT_CONNECTING:
725 static void reg_entry_group_callback(AvahiEntryGroup *g, AvahiEntryGroupState state, void *userdata) {
726 oid_data *data = userdata;
732 case AVAHI_ENTRY_GROUP_ESTABLISHED:
734 reg_report_status(data, SW_DISCOVERY_PUBLISH_STARTED);
737 case AVAHI_ENTRY_GROUP_COLLISION:
739 reg_report_status(data, SW_DISCOVERY_PUBLISH_NAME_COLLISION);
742 case AVAHI_ENTRY_GROUP_REGISTERING:
743 case AVAHI_ENTRY_GROUP_UNCOMMITED:
747 case AVAHI_ENTRY_GROUP_FAILURE:
748 reg_report_status(data, SW_DISCOVERY_PUBLISH_INVALID);
754 sw_result sw_discovery_publish(
756 sw_uint32 interface_index,
757 sw_const_string name,
758 sw_const_string type,
759 sw_const_string domain,
760 sw_const_string host,
762 sw_octets text_record,
763 sw_uint32 text_record_len,
764 sw_discovery_publish_reply reply,
766 sw_discovery_oid * oid) {
769 sw_result result = SW_E_UNKNOWN;
771 AvahiStringList *txt = NULL;
781 if (text_record && text_record_len > 0)
782 if (avahi_string_list_parse(text_record, text_record_len, &txt) < 0)
785 if ((*oid = oid_alloc(self, OID_ENTRY_GROUP)) == (sw_discovery_oid) -1) {
786 avahi_string_list_free(txt);
790 if (!(sdata = service_data_new(self))) {
791 avahi_string_list_free(txt);
792 oid_release(self, *oid);
796 data = oid_get(self, *oid);
798 data->reply = (sw_result (*)(void)) reply;
800 data->service_data = sdata;
802 sdata->interface = interface_index == 0 ? AVAHI_IF_UNSPEC : (AvahiIfIndex) interface_index;
803 sdata->name = avahi_strdup(name);
804 sdata->regtype = type ? avahi_normalize_name_strdup(type) : NULL;
805 sdata->domain = domain ? avahi_normalize_name_strdup(domain) : NULL;
806 sdata->host = host ? avahi_normalize_name_strdup(host) : NULL;
810 /* Some OOM checking would be cool here */
812 ASSERT_SUCCESS(pthread_mutex_lock(&self->mutex));
814 if (!(data->object = avahi_entry_group_new(self->client, reg_entry_group_callback, data))) {
815 result = map_error(avahi_client_errno(self->client));
819 if (avahi_client_get_state(self->client) == AVAHI_CLIENT_S_RUNNING) {
822 if ((error = reg_create_service(data)) < 0) {
823 result = map_error(error);
832 ASSERT_SUCCESS(pthread_mutex_unlock(&self->mutex));
834 if (result != SW_OKAY)
835 if (*oid != (sw_discovery_oid) -1)
836 sw_discovery_cancel(self, *oid);
841 static void domain_browser_callback(
842 AvahiDomainBrowser *b,
843 AvahiIfIndex interface,
844 AVAHI_GCC_UNUSED AvahiProtocol protocol,
845 AvahiBrowserEvent event,
847 AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
850 oid_data* data = userdata;
851 sw_discovery_browse_reply reply;
852 static char domain_fixed[AVAHI_DOMAIN_NAME_MAX];
857 reply = (sw_discovery_browse_reply) data->reply;
859 domain = add_trailing_dot(domain, domain_fixed, sizeof(domain_fixed));
862 case AVAHI_BROWSER_NEW:
863 reply(data->discovery, OID_GET_INDEX(data), SW_DISCOVERY_BROWSE_ADD_DOMAIN, interface, NULL, NULL, domain, data->extra);
866 case AVAHI_BROWSER_REMOVE:
867 reply(data->discovery, OID_GET_INDEX(data), SW_DISCOVERY_BROWSE_REMOVE_DOMAIN, interface, NULL, NULL, domain, data->extra);
870 case AVAHI_BROWSER_FAILURE:
871 reply(data->discovery, OID_GET_INDEX(data), SW_DISCOVERY_BROWSE_INVALID, interface, NULL, NULL, domain, data->extra);
874 case AVAHI_BROWSER_CACHE_EXHAUSTED:
875 case AVAHI_BROWSER_ALL_FOR_NOW:
880 sw_result sw_discovery_browse_domains(
882 sw_uint32 interface_index,
883 sw_discovery_browse_reply reply,
885 sw_discovery_oid * oid) {
888 AvahiIfIndex ifindex;
889 sw_result result = SW_E_UNKNOWN;
897 if ((*oid = oid_alloc(self, OID_DOMAIN_BROWSER)) == (sw_discovery_oid) -1)
900 data = oid_get(self, *oid);
902 data->reply = (sw_result (*)(void)) reply;
905 ifindex = interface_index == 0 ? AVAHI_IF_UNSPEC : (AvahiIfIndex) interface_index;
907 ASSERT_SUCCESS(pthread_mutex_lock(&self->mutex));
909 if (!(data->object = avahi_domain_browser_new(self->client, ifindex, AVAHI_PROTO_INET, NULL, AVAHI_DOMAIN_BROWSER_BROWSE, 0, domain_browser_callback, data))) {
910 result = map_error(avahi_client_errno(self->client));
918 ASSERT_SUCCESS(pthread_mutex_unlock(&self->mutex));
920 if (result != SW_OKAY)
921 if (*oid != (sw_discovery_oid) -1)
922 sw_discovery_cancel(self, *oid);
927 static void service_resolver_callback(
928 AvahiServiceResolver *r,
929 AvahiIfIndex interface,
930 AVAHI_GCC_UNUSED AvahiProtocol protocol,
931 AvahiResolverEvent event,
935 const char *host_name,
936 const AvahiAddress *a,
938 AvahiStringList *txt,
939 AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
942 oid_data* data = userdata;
943 sw_discovery_resolve_reply reply;
948 reply = (sw_discovery_resolve_reply) data->reply;
951 case AVAHI_RESOLVER_FOUND: {
953 char host_name_fixed[AVAHI_DOMAIN_NAME_MAX];
956 sw_ipv4_address addr;
958 sw_ipv4_address_init_from_saddr(&addr, a->data.ipv4.address);
960 host_name = add_trailing_dot(host_name, host_name_fixed, sizeof(host_name_fixed));
962 if ((p = avahi_new0(uint8_t, (l = avahi_string_list_serialize(txt, NULL, 0))+1)))
963 avahi_string_list_serialize(txt, p, l);
965 reply(data->discovery, OID_GET_INDEX(data), interface, name, type, domain, addr, port, p, l, data->extra);
971 case AVAHI_RESOLVER_FAILURE:
973 /* Apparently there is no way in HOWL to inform about failed resolvings ... */
975 avahi_warn("A service failed to resolve in the HOWL compatiblity layer of Avahi which is used by '%s'. "
976 "Since the HOWL API doesn't offer any means to inform the application about this, we have to ignore the failure. "
977 "Please fix your application to use the native API of Avahi!",
984 sw_result sw_discovery_resolve(
986 sw_uint32 interface_index,
987 sw_const_string name,
988 sw_const_string type,
989 sw_const_string domain,
990 sw_discovery_resolve_reply reply,
992 sw_discovery_oid * oid) {
995 AvahiIfIndex ifindex;
996 sw_result result = SW_E_UNKNOWN;
1006 if ((*oid = oid_alloc(self, OID_SERVICE_RESOLVER)) == (sw_discovery_oid) -1)
1007 return SW_E_UNKNOWN;
1009 data = oid_get(self, *oid);
1011 data->reply = (sw_result (*)(void)) reply;
1012 data->extra = extra;
1014 ifindex = interface_index == 0 ? AVAHI_IF_UNSPEC : (AvahiIfIndex) interface_index;
1016 ASSERT_SUCCESS(pthread_mutex_lock(&self->mutex));
1018 if (!(data->object = avahi_service_resolver_new(self->client, ifindex, AVAHI_PROTO_INET, name, type, domain, AVAHI_PROTO_INET, 0, service_resolver_callback, data))) {
1019 result = map_error(avahi_client_errno(self->client));
1027 ASSERT_SUCCESS(pthread_mutex_unlock(&self->mutex));
1029 if (result != SW_OKAY)
1030 if (*oid != (sw_discovery_oid) -1)
1031 sw_discovery_cancel(self, *oid);
1036 static void service_browser_callback(
1037 AvahiServiceBrowser *b,
1038 AvahiIfIndex interface,
1039 AVAHI_GCC_UNUSED AvahiProtocol protocol,
1040 AvahiBrowserEvent event,
1044 AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
1047 oid_data* data = userdata;
1048 char type_fixed[AVAHI_DOMAIN_NAME_MAX], domain_fixed[AVAHI_DOMAIN_NAME_MAX];
1049 sw_discovery_browse_reply reply;
1054 reply = (sw_discovery_browse_reply) data->reply;
1056 type = add_trailing_dot(type, type_fixed, sizeof(type_fixed));
1057 domain = add_trailing_dot(domain, domain_fixed, sizeof(domain_fixed));
1060 case AVAHI_BROWSER_NEW:
1061 reply(data->discovery, OID_GET_INDEX(data), SW_DISCOVERY_BROWSE_ADD_SERVICE, interface, name, type, domain, data->extra);
1064 case AVAHI_BROWSER_REMOVE:
1065 reply(data->discovery, OID_GET_INDEX(data), SW_DISCOVERY_BROWSE_REMOVE_SERVICE, interface, name, type, domain, data->extra);
1068 case AVAHI_BROWSER_FAILURE:
1069 reply(data->discovery, OID_GET_INDEX(data), SW_DISCOVERY_BROWSE_INVALID, interface, name, type, domain, data->extra);
1072 case AVAHI_BROWSER_CACHE_EXHAUSTED:
1073 case AVAHI_BROWSER_ALL_FOR_NOW:
1078 sw_result sw_discovery_browse(
1080 sw_uint32 interface_index,
1081 sw_const_string type,
1082 sw_const_string domain,
1083 sw_discovery_browse_reply reply,
1085 sw_discovery_oid * oid) {
1088 AvahiIfIndex ifindex;
1089 sw_result result = SW_E_UNKNOWN;
1098 if ((*oid = oid_alloc(self, OID_SERVICE_BROWSER)) == (sw_discovery_oid) -1)
1099 return SW_E_UNKNOWN;
1101 data = oid_get(self, *oid);
1103 data->reply = (sw_result (*)(void)) reply;
1104 data->extra = extra;
1106 ifindex = interface_index == 0 ? AVAHI_IF_UNSPEC : (AvahiIfIndex) interface_index;
1108 ASSERT_SUCCESS(pthread_mutex_lock(&self->mutex));
1110 if (!(data->object = avahi_service_browser_new(self->client, ifindex, AVAHI_PROTO_INET, type, domain, 0, service_browser_callback, data))) {
1111 result = map_error(avahi_client_errno(self->client));
1119 ASSERT_SUCCESS(pthread_mutex_unlock(&self->mutex));
1121 if (result != SW_OKAY)
1122 if (*oid != (sw_discovery_oid) -1)
1123 sw_discovery_cancel(self, *oid);
1128 sw_result sw_discovery_cancel(sw_discovery self, sw_discovery_oid oid) {
1134 if (!(data = oid_get(self, oid)))
1135 return SW_E_UNKNOWN;
1138 switch (data->type) {
1139 case OID_SERVICE_BROWSER:
1140 avahi_service_browser_free(data->object);
1143 case OID_SERVICE_RESOLVER:
1144 avahi_service_resolver_free(data->object);
1147 case OID_DOMAIN_BROWSER:
1148 avahi_domain_browser_free(data->object);
1151 case OID_ENTRY_GROUP:
1152 avahi_entry_group_free(data->object);
1160 if (data->service_data) {
1161 assert(data->type == OID_ENTRY_GROUP);
1162 service_data_free(self, data->service_data);
1165 oid_release(self, oid);
1170 sw_result sw_discovery_init_with_flags(
1171 sw_discovery * self,
1172 sw_discovery_init_flags flags) {
1178 if (flags != SW_DISCOVERY_USE_SHARED_SERVICE)
1179 return SW_E_NO_IMPL;
1181 return sw_discovery_init(self);