4 This file is part of avahi.
6 avahi is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as
8 published by the Free Software Foundation; either version 2.1 of the
9 License, or (at your option) any later version.
11 avahi is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
14 Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with avahi; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
30 #include <dbus/dbus.h>
32 #include <avahi-client/client.h>
33 #include <avahi-common/dbus.h>
34 #include <avahi-common/llist.h>
35 #include <avahi-common/error.h>
36 #include <avahi-common/malloc.h>
37 #include <avahi-common/domain.h>
41 #include "xdg-config.h"
43 static void parse_environment(AvahiDomainBrowser *b) {
44 char buf[AVAHI_DOMAIN_NAME_MAX*3], *e, *t, *p;
48 if (!(e = getenv("AVAHI_BROWSE_DOMAINS")))
51 snprintf(buf, sizeof(buf), "%s", e);
53 for (t = strtok_r(buf, ":", &p); t; t = strtok_r(NULL, ":", &p)) {
54 char domain[AVAHI_DOMAIN_NAME_MAX];
55 if (avahi_normalize_name(t, domain, sizeof(domain)))
56 b->static_browse_domains = avahi_string_list_add(b->static_browse_domains, domain);
60 static void parse_domain_file(AvahiDomainBrowser *b) {
62 char buf[AVAHI_DOMAIN_NAME_MAX];
66 if (!(f = avahi_xdg_config_open("avahi/browse-domains")))
70 while (fgets(buf, sizeof(buf)-1, f)) {
71 char domain[AVAHI_DOMAIN_NAME_MAX];
72 buf[strcspn(buf, "\n\r")] = 0;
74 if (avahi_normalize_name(buf, domain, sizeof(domain)))
75 b->static_browse_domains = avahi_string_list_add(b->static_browse_domains, domain);
79 static void domain_browser_ref(AvahiDomainBrowser *db) {
85 static void defer_timeout_callback(AvahiTimeout *t, void *userdata) {
86 AvahiDomainBrowser *db = userdata;
90 db->client->poll_api->timeout_free(db->defer_timeout);
91 db->defer_timeout = NULL;
93 domain_browser_ref(db);
95 for (l = db->static_browse_domains; l; l = l->next) {
100 db->callback(db, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, AVAHI_BROWSER_NEW, (char*) l->text, AVAHI_LOOKUP_RESULT_STATIC, db->userdata);
103 avahi_domain_browser_free(db);
106 AvahiDomainBrowser* avahi_domain_browser_new(
108 AvahiIfIndex interface,
109 AvahiProtocol protocol,
111 AvahiDomainBrowserType btype,
112 AvahiLookupFlags flags,
113 AvahiDomainBrowserCallback callback,
116 AvahiDomainBrowser *db = NULL;
117 DBusMessage *message = NULL, *reply = NULL;
120 int32_t i_interface, i_protocol, bt;
126 dbus_error_init (&error);
128 if (!avahi_client_is_connected(client)) {
129 avahi_client_set_errno(client, AVAHI_ERR_BAD_STATE);
136 if (!(db = avahi_new (AvahiDomainBrowser, 1))) {
137 avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
143 db->callback = callback;
144 db->userdata = userdata;
146 db->interface = interface;
147 db->protocol = protocol;
148 db->static_browse_domains = NULL;
149 db->defer_timeout = NULL;
151 AVAHI_LLIST_PREPEND(AvahiDomainBrowser, domain_browsers, client->domain_browsers, db);
153 if (!(client->flags & AVAHI_CLIENT_IGNORE_USER_CONFIG)) {
154 parse_environment(db);
155 parse_domain_file(db);
158 db->static_browse_domains = avahi_string_list_reverse(db->static_browse_domains);
160 if (!(message = dbus_message_new_method_call (AVAHI_DBUS_NAME, AVAHI_DBUS_PATH_SERVER, AVAHI_DBUS_INTERFACE_SERVER, "DomainBrowserNew"))) {
161 avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
165 i_interface = (int32_t) interface;
166 i_protocol = (int32_t) protocol;
167 u_flags = (uint32_t) flags;
170 if (!(dbus_message_append_args(
172 DBUS_TYPE_INT32, &i_interface,
173 DBUS_TYPE_INT32, &i_protocol,
174 DBUS_TYPE_STRING, &domain,
175 DBUS_TYPE_INT32, &bt,
176 DBUS_TYPE_UINT32, &flags,
177 DBUS_TYPE_INVALID))) {
178 avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
182 if (!(reply = dbus_connection_send_with_reply_and_block (client->bus, message, -1, &error)) ||
183 dbus_error_is_set(&error)) {
184 avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR);
188 if (!dbus_message_get_args (reply, &error, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID) ||
189 dbus_error_is_set(&error) ||
191 avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR);
195 if (!(db->path = avahi_strdup(path))) {
197 /* FIXME: We don't remove the object on the server side */
199 avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
203 if (db->static_browse_domains) {
204 struct timeval tv = { 0, 0 };
206 if (!(db->defer_timeout = client->poll_api->timeout_new(client->poll_api, &tv, defer_timeout_callback, db))) {
207 avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
212 dbus_message_unref(message);
213 dbus_message_unref(reply);
219 if (dbus_error_is_set(&error)) {
220 avahi_client_set_dbus_error(client, &error);
221 dbus_error_free(&error);
225 avahi_domain_browser_free(db);
228 dbus_message_unref(message);
231 dbus_message_unref(reply);
236 AvahiClient* avahi_domain_browser_get_client (AvahiDomainBrowser *b) {
241 int avahi_domain_browser_free (AvahiDomainBrowser *b) {
253 if (b->path && avahi_client_is_connected(b->client))
254 r = avahi_client_simple_method_call(client, b->path, AVAHI_DBUS_INTERFACE_DOMAIN_BROWSER, "Free");
256 AVAHI_LLIST_REMOVE(AvahiDomainBrowser, domain_browsers, client->domain_browsers, b);
258 if (b->defer_timeout)
259 b->client->poll_api->timeout_free(b->defer_timeout);
261 avahi_string_list_free(b->static_browse_domains);
268 DBusHandlerResult avahi_domain_browser_event (AvahiClient *client, AvahiBrowserEvent event, DBusMessage *message) {
269 AvahiDomainBrowser *db = NULL;
273 int32_t interface, protocol;
280 dbus_error_init (&error);
282 if (!(path = dbus_message_get_path(message)))
285 for (db = client->domain_browsers; db; db = db->domain_browsers_next)
286 if (strcmp (db->path, path) == 0)
292 interface = db->interface;
293 protocol = db->protocol;
296 case AVAHI_BROWSER_NEW:
297 case AVAHI_BROWSER_REMOVE:
299 if (!dbus_message_get_args(
301 DBUS_TYPE_INT32, &interface,
302 DBUS_TYPE_INT32, &protocol,
303 DBUS_TYPE_STRING, &domain,
304 DBUS_TYPE_UINT32, &flags,
305 DBUS_TYPE_INVALID) ||
306 dbus_error_is_set (&error)) {
307 fprintf(stderr, "Failed to parse browser event.\n");
313 case AVAHI_BROWSER_CACHE_EXHAUSTED:
314 case AVAHI_BROWSER_ALL_FOR_NOW:
317 case AVAHI_BROWSER_FAILURE: {
320 if (!dbus_message_get_args(
322 DBUS_TYPE_STRING, &etxt,
323 DBUS_TYPE_INVALID) ||
324 dbus_error_is_set (&error)) {
325 fprintf(stderr, "Failed to parse browser event.\n");
329 avahi_client_set_errno(db->client, avahi_error_dbus_to_number(etxt));
335 for (l = db->static_browse_domains; l; l = l->next)
336 if (avahi_domain_equal((char*) l->text, domain)) {
337 /* We had this entry already in the static entries */
338 return DBUS_HANDLER_RESULT_HANDLED;
341 db->callback(db, (AvahiIfIndex) interface, (AvahiProtocol) protocol, event, domain, (AvahiLookupResultFlags) flags, db->userdata);
343 return DBUS_HANDLER_RESULT_HANDLED;
346 dbus_error_free (&error);
347 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
350 /* AvahiServiceTypeBrowser */
351 AvahiServiceTypeBrowser* avahi_service_type_browser_new(
353 AvahiIfIndex interface,
354 AvahiProtocol protocol,
356 AvahiLookupFlags flags,
357 AvahiServiceTypeBrowserCallback callback,
360 AvahiServiceTypeBrowser *b = NULL;
361 DBusMessage *message = NULL, *reply = NULL;
364 int32_t i_interface, i_protocol;
370 dbus_error_init(&error);
372 if (!avahi_client_is_connected(client)) {
373 avahi_client_set_errno(client, AVAHI_ERR_BAD_STATE);
380 if (!(b = avahi_new(AvahiServiceTypeBrowser, 1))) {
381 avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
386 b->callback = callback;
387 b->userdata = userdata;
390 b->interface = interface;
391 b->protocol = protocol;
393 AVAHI_LLIST_PREPEND(AvahiServiceTypeBrowser, service_type_browsers, client->service_type_browsers, b);
396 if (!(b->domain = avahi_strdup(domain))) {
397 avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
401 if (!(message = dbus_message_new_method_call (AVAHI_DBUS_NAME, AVAHI_DBUS_PATH_SERVER, AVAHI_DBUS_INTERFACE_SERVER, "ServiceTypeBrowserNew"))) {
402 avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
406 i_interface = (int32_t) interface;
407 i_protocol = (int32_t) protocol;
408 u_flags = (uint32_t) flags;
410 if (!dbus_message_append_args(
412 DBUS_TYPE_INT32, &i_interface,
413 DBUS_TYPE_INT32, &i_protocol,
414 DBUS_TYPE_STRING, &domain,
415 DBUS_TYPE_UINT32, &u_flags,
416 DBUS_TYPE_INVALID)) {
417 avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
421 if (!(reply = dbus_connection_send_with_reply_and_block (client->bus, message, -1, &error)) ||
422 dbus_error_is_set(&error)) {
423 avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR);
427 if (!dbus_message_get_args (reply, &error, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID) ||
428 dbus_error_is_set(&error) ||
430 avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR);
434 if (!(b->path = avahi_strdup(path))) {
436 /* FIXME: We don't remove the object on the server side */
438 avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
442 dbus_message_unref(message);
443 dbus_message_unref(reply);
449 if (dbus_error_is_set(&error)) {
450 avahi_client_set_dbus_error(client, &error);
451 dbus_error_free(&error);
455 avahi_service_type_browser_free(b);
458 dbus_message_unref(message);
461 dbus_message_unref(reply);
466 AvahiClient* avahi_service_type_browser_get_client (AvahiServiceTypeBrowser *b) {
471 int avahi_service_type_browser_free (AvahiServiceTypeBrowser *b) {
478 if (b->path && avahi_client_is_connected(b->client))
479 r = avahi_client_simple_method_call(client, b->path, AVAHI_DBUS_INTERFACE_SERVICE_TYPE_BROWSER, "Free");
481 AVAHI_LLIST_REMOVE(AvahiServiceTypeBrowser, service_type_browsers, b->client->service_type_browsers, b);
484 avahi_free(b->domain);
489 DBusHandlerResult avahi_service_type_browser_event (AvahiClient *client, AvahiBrowserEvent event, DBusMessage *message) {
490 AvahiServiceTypeBrowser *b = NULL;
493 char *domain, *type = NULL;
494 int32_t interface, protocol;
500 dbus_error_init (&error);
502 if (!(path = dbus_message_get_path(message)))
505 for (b = client->service_type_browsers; b; b = b->service_type_browsers_next)
506 if (strcmp (b->path, path) == 0)
513 interface = b->interface;
514 protocol = b->protocol;
517 case AVAHI_BROWSER_NEW:
518 case AVAHI_BROWSER_REMOVE:
519 if (!dbus_message_get_args(
521 DBUS_TYPE_INT32, &interface,
522 DBUS_TYPE_INT32, &protocol,
523 DBUS_TYPE_STRING, &type,
524 DBUS_TYPE_STRING, &domain,
525 DBUS_TYPE_UINT32, &flags,
526 DBUS_TYPE_INVALID) ||
527 dbus_error_is_set(&error)) {
528 fprintf(stderr, "Failed to parse browser event.\n");
533 case AVAHI_BROWSER_CACHE_EXHAUSTED:
534 case AVAHI_BROWSER_ALL_FOR_NOW:
537 case AVAHI_BROWSER_FAILURE: {
540 if (!dbus_message_get_args(
542 DBUS_TYPE_STRING, &etxt,
543 DBUS_TYPE_INVALID) ||
544 dbus_error_is_set (&error)) {
545 fprintf(stderr, "Failed to parse browser event.\n");
549 avahi_client_set_errno(b->client, avahi_error_dbus_to_number(etxt));
554 b->callback(b, (AvahiIfIndex) interface, (AvahiProtocol) protocol, event, type, domain, (AvahiLookupResultFlags) flags, b->userdata);
556 return DBUS_HANDLER_RESULT_HANDLED;
559 dbus_error_free (&error);
560 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
563 /* AvahiServiceBrowser */
565 AvahiServiceBrowser* avahi_service_browser_new(
567 AvahiIfIndex interface,
568 AvahiProtocol protocol,
571 AvahiLookupFlags flags,
572 AvahiServiceBrowserCallback callback,
575 AvahiServiceBrowser *b = NULL;
576 DBusMessage *message = NULL, *reply = NULL;
579 int32_t i_protocol, i_interface;
586 dbus_error_init(&error);
588 if (!avahi_client_is_connected(client)) {
589 avahi_client_set_errno(client, AVAHI_ERR_BAD_STATE);
596 if (!(b = avahi_new(AvahiServiceBrowser, 1))) {
597 avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
602 b->callback = callback;
603 b->userdata = userdata;
605 b->type = b->domain = NULL;
606 b->interface = interface;
607 b->protocol = protocol;
609 AVAHI_LLIST_PREPEND(AvahiServiceBrowser, service_browsers, client->service_browsers, b);
611 if (!(b->type = avahi_strdup(type))) {
612 avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
616 if (domain && domain[0])
617 if (!(b->domain = avahi_strdup(domain))) {
618 avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
622 if (!(message = dbus_message_new_method_call (AVAHI_DBUS_NAME, AVAHI_DBUS_PATH_SERVER, AVAHI_DBUS_INTERFACE_SERVER, "ServiceBrowserNew"))) {
623 avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
627 i_interface = (int32_t) interface;
628 i_protocol = (int32_t) protocol;
629 u_flags = (uint32_t) flags;
631 if (!dbus_message_append_args(
633 DBUS_TYPE_INT32, &i_interface,
634 DBUS_TYPE_INT32, &i_protocol,
635 DBUS_TYPE_STRING, &type,
636 DBUS_TYPE_STRING, &domain,
637 DBUS_TYPE_UINT32, &u_flags,
638 DBUS_TYPE_INVALID)) {
639 avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
643 if (!(reply = dbus_connection_send_with_reply_and_block (client->bus, message, -1, &error)) ||
644 dbus_error_is_set(&error)) {
645 avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR);
649 if (!dbus_message_get_args (reply, &error, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID) ||
650 dbus_error_is_set(&error) ||
652 avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR);
656 if (!(b->path = avahi_strdup(path))) {
658 /* FIXME: We don't remove the object on the server side */
660 avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
664 dbus_message_unref(message);
665 dbus_message_unref(reply);
670 if (dbus_error_is_set(&error)) {
671 avahi_client_set_dbus_error(client, &error);
672 dbus_error_free(&error);
676 avahi_service_browser_free(b);
679 dbus_message_unref(message);
682 dbus_message_unref(reply);
687 AvahiClient* avahi_service_browser_get_client (AvahiServiceBrowser *b) {
692 int avahi_service_browser_free (AvahiServiceBrowser *b) {
699 if (b->path && avahi_client_is_connected(b->client))
700 r = avahi_client_simple_method_call(client, b->path, AVAHI_DBUS_INTERFACE_SERVICE_BROWSER, "Free");
702 AVAHI_LLIST_REMOVE(AvahiServiceBrowser, service_browsers, b->client->service_browsers, b);
706 avahi_free(b->domain);
711 DBusHandlerResult avahi_service_browser_event(AvahiClient *client, AvahiBrowserEvent event, DBusMessage *message) {
712 AvahiServiceBrowser *b = NULL;
715 char *name = NULL, *type, *domain;
716 int32_t interface, protocol;
719 dbus_error_init (&error);
721 if (!(path = dbus_message_get_path(message)))
724 for (b = client->service_browsers; b; b = b->service_browsers_next)
725 if (strcmp (b->path, path) == 0)
733 interface = b->interface;
734 protocol = b->protocol;
737 case AVAHI_BROWSER_NEW:
738 case AVAHI_BROWSER_REMOVE:
740 if (!dbus_message_get_args (
742 DBUS_TYPE_INT32, &interface,
743 DBUS_TYPE_INT32, &protocol,
744 DBUS_TYPE_STRING, &name,
745 DBUS_TYPE_STRING, &type,
746 DBUS_TYPE_STRING, &domain,
747 DBUS_TYPE_UINT32, &flags,
748 DBUS_TYPE_INVALID) ||
749 dbus_error_is_set(&error)) {
750 fprintf(stderr, "Failed to parse browser event.\n");
755 case AVAHI_BROWSER_CACHE_EXHAUSTED:
756 case AVAHI_BROWSER_ALL_FOR_NOW:
759 case AVAHI_BROWSER_FAILURE: {
762 if (!dbus_message_get_args(
764 DBUS_TYPE_STRING, &etxt,
765 DBUS_TYPE_INVALID) ||
766 dbus_error_is_set (&error)) {
767 fprintf(stderr, "Failed to parse browser event.\n");
771 avahi_client_set_errno(b->client, avahi_error_dbus_to_number(etxt));
776 b->callback(b, (AvahiIfIndex) interface, (AvahiProtocol) protocol, event, name, type, domain, (AvahiLookupResultFlags) flags, b->userdata);
778 return DBUS_HANDLER_RESULT_HANDLED;
781 dbus_error_free (&error);
782 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;