]> git.meshlink.io Git - catta/blob - avahi-client/browser.c
bdbd8c5c58da6b79731bde7a5372426f4aa99216
[catta] / avahi-client / browser.c
1 /* $Id$ */
2
3 /***
4   This file is part of avahi.
5  
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.
10  
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.
15  
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
19   USA.
20 ***/
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <string.h>
29
30 #include <dbus/dbus.h>
31
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
38 #include "client.h"
39 #include "internal.h"
40
41 AvahiDomainBrowser* avahi_domain_browser_new(
42     AvahiClient *client,
43     AvahiIfIndex interface,
44     AvahiProtocol protocol,
45     const char *domain,
46     AvahiDomainBrowserType btype,
47     AvahiLookupFlags flags,
48     AvahiDomainBrowserCallback callback,
49     void *userdata) {
50     
51     AvahiDomainBrowser *db = NULL;
52     DBusMessage *message = NULL, *reply = NULL;
53     DBusError error;
54     char *path;
55     int32_t i_interface, i_protocol, bt;
56     uint32_t u_flags;
57
58     assert(client);
59     assert(callback);
60
61     dbus_error_init (&error);
62
63     if (client->state == AVAHI_CLIENT_DISCONNECTED) {
64         avahi_client_set_errno(client, AVAHI_ERR_BAD_STATE);
65         goto fail;
66     }
67
68     if (!domain)
69         domain = "";
70
71     if (!(db = avahi_new (AvahiDomainBrowser, 1))) {
72         avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
73         goto fail;
74     }
75
76     db->client = client;
77     db->callback = callback;
78     db->userdata = userdata;
79     db->path = NULL;
80
81     AVAHI_LLIST_PREPEND(AvahiDomainBrowser, domain_browsers, client->domain_browsers, db);
82
83     if (!(message = dbus_message_new_method_call (AVAHI_DBUS_NAME, AVAHI_DBUS_PATH_SERVER, AVAHI_DBUS_INTERFACE_SERVER, "DomainBrowserNew"))) {
84         avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
85         goto fail;
86     }
87
88     i_interface = (int32_t) interface;
89     i_protocol = (int32_t) protocol;
90     u_flags = (uint32_t) flags;
91     bt = btype;
92
93     if (!(dbus_message_append_args(
94               message,
95               DBUS_TYPE_INT32, &i_interface,
96               DBUS_TYPE_INT32, &i_protocol,
97               DBUS_TYPE_STRING, &domain,
98               DBUS_TYPE_INT32, &bt,
99               DBUS_TYPE_UINT32, &flags,
100               DBUS_TYPE_INVALID))) {
101         avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
102         goto fail;
103     }
104
105     if (!(reply = dbus_connection_send_with_reply_and_block (client->bus, message, -1, &error)) ||
106         dbus_error_is_set(&error)) {
107         avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR);
108         goto fail;
109     }
110
111     if (!dbus_message_get_args (reply, &error, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID) ||
112         dbus_error_is_set(&error) ||
113         !path) {
114         avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR);
115         goto fail;
116     }
117
118     if (!(db->path = avahi_strdup(path))) {
119
120         /* FIXME: We don't remove the object on the server side */
121
122         avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
123         goto fail;
124     }
125
126     dbus_message_unref(message);
127     dbus_message_unref(reply);
128     
129     return db;
130
131 fail:
132
133     if (dbus_error_is_set(&error)) {
134         avahi_client_set_dbus_error(client, &error);
135         dbus_error_free(&error);
136     }
137
138     if (db)
139         avahi_domain_browser_free(db);
140     
141     if (message)
142         dbus_message_unref(message);
143
144     if (reply)
145         dbus_message_unref(reply);
146
147     return NULL;
148 }
149
150 AvahiClient* avahi_domain_browser_get_client (AvahiDomainBrowser *b)
151 {
152     assert(b);
153     return b->client;
154 }
155
156 int avahi_domain_browser_free (AvahiDomainBrowser *b) {
157     AvahiClient *client;
158     int r = AVAHI_OK;
159
160     assert(b);
161     client = b->client;
162
163     if (b->path && client->state != AVAHI_CLIENT_DISCONNECTED)
164         r = avahi_client_simple_method_call(client, b->path, AVAHI_DBUS_INTERFACE_DOMAIN_BROWSER, "Free");
165
166     AVAHI_LLIST_REMOVE(AvahiDomainBrowser, domain_browsers, client->domain_browsers, b);
167
168     avahi_free(b->path);
169     avahi_free(b);
170
171     return r;
172 }
173
174 DBusHandlerResult avahi_domain_browser_event (AvahiClient *client, AvahiBrowserEvent event, DBusMessage *message) {
175     AvahiDomainBrowser *db = NULL;
176     DBusError error;
177     const char *path;
178     char *domain = NULL;
179     int32_t interface = AVAHI_IF_UNSPEC, protocol = AVAHI_PROTO_UNSPEC;
180     uint32_t flags = 0;
181
182     assert(client);
183     assert(message);
184     
185     dbus_error_init (&error);
186
187     if (!(path = dbus_message_get_path(message)))
188         goto fail;
189
190     for (db = client->domain_browsers; db; db = db->domain_browsers_next)
191         if (strcmp (db->path, path) == 0)
192             break;
193
194     if (!db)
195         goto fail;
196
197     switch (event) {
198         case AVAHI_BROWSER_NEW:
199         case AVAHI_BROWSER_REMOVE:
200             
201             if (!dbus_message_get_args(
202                     message, &error,
203                     DBUS_TYPE_INT32, &interface,
204                     DBUS_TYPE_INT32, &protocol,
205                     DBUS_TYPE_STRING, &domain,
206                     DBUS_TYPE_UINT32, &flags,
207                     DBUS_TYPE_INVALID) ||
208                 dbus_error_is_set (&error)) {
209                 fprintf(stderr, "Failed to parse browser event.\n");
210                 goto fail;
211             }
212
213             break;
214             
215         case AVAHI_BROWSER_CACHE_EXHAUSTED:
216         case AVAHI_BROWSER_ALL_FOR_NOW:
217             break;
218
219         case AVAHI_BROWSER_FAILURE: {
220             char *etxt;
221             
222             if (!dbus_message_get_args(
223                     message, &error,
224                     DBUS_TYPE_STRING, &etxt,
225                     DBUS_TYPE_INVALID) ||
226                 dbus_error_is_set (&error)) {
227                 fprintf(stderr, "Failed to parse browser event.\n");
228                 goto fail;
229             }
230             
231             avahi_client_set_errno(db->client, avahi_error_dbus_to_number(etxt));
232             break;
233         }
234     }
235
236     db->callback(db, (AvahiIfIndex) interface, (AvahiProtocol) protocol, event, domain, (AvahiLookupResultFlags) flags, db->userdata);
237
238     return DBUS_HANDLER_RESULT_HANDLED;
239
240 fail:
241     dbus_error_free (&error);
242     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
243 }
244
245 /* AvahiServiceTypeBrowser */
246 AvahiServiceTypeBrowser* avahi_service_type_browser_new(
247     AvahiClient *client,
248     AvahiIfIndex interface,
249     AvahiProtocol protocol,
250     const char *domain,
251     AvahiLookupFlags flags, 
252     AvahiServiceTypeBrowserCallback callback,
253     void *userdata) {
254         
255     AvahiServiceTypeBrowser *b = NULL;
256     DBusMessage *message = NULL, *reply = NULL;
257     DBusError error;
258     char *path;
259     int32_t i_interface, i_protocol;
260     uint32_t u_flags;
261
262     assert(client);
263     assert(callback);
264
265     dbus_error_init(&error);
266
267     if (client->state == AVAHI_CLIENT_DISCONNECTED) {
268         avahi_client_set_errno(client, AVAHI_ERR_BAD_STATE);
269         goto fail;
270     }
271
272     if (!domain)
273         domain = "";
274
275     if (!(b = avahi_new(AvahiServiceTypeBrowser, 1))) {
276         avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
277         goto fail;
278     }
279
280     b->client = client;
281     b->callback = callback;
282     b->userdata = userdata;
283     b->path = NULL;
284
285     AVAHI_LLIST_PREPEND(AvahiServiceTypeBrowser, service_type_browsers, client->service_type_browsers, b);
286
287     if (!(message = dbus_message_new_method_call (AVAHI_DBUS_NAME, AVAHI_DBUS_PATH_SERVER, AVAHI_DBUS_INTERFACE_SERVER, "ServiceTypeBrowserNew"))) {
288         avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
289         goto fail;
290     }
291     
292     i_interface = (int32_t) interface;
293     i_protocol = (int32_t) protocol;
294     u_flags = (uint32_t) flags;
295
296     if (!dbus_message_append_args(
297             message,
298             DBUS_TYPE_INT32, &i_interface,
299             DBUS_TYPE_INT32, &i_protocol,
300             DBUS_TYPE_STRING, &domain,
301             DBUS_TYPE_UINT32, &u_flags,
302             DBUS_TYPE_INVALID)) {
303         avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
304         goto fail;
305     }
306
307     if (!(reply = dbus_connection_send_with_reply_and_block (client->bus, message, -1, &error)) ||
308         dbus_error_is_set(&error)) {
309         avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR);
310         goto fail;
311     }
312
313     if (!dbus_message_get_args (reply, &error, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID) ||
314         dbus_error_is_set(&error) ||
315         !path) {
316         avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR);
317         goto fail;
318     }
319
320     if (!(b->path = avahi_strdup(path))) {
321
322         /* FIXME: We don't remove the object on the server side */
323
324         avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
325         goto fail;
326     }
327
328     dbus_message_unref(message);
329     dbus_message_unref(reply);
330
331     return b;
332
333 fail:
334     
335     if (dbus_error_is_set(&error)) {
336         avahi_client_set_dbus_error(client, &error);
337         dbus_error_free(&error);
338     }
339
340     if (b)
341         avahi_service_type_browser_free(b);
342     
343     if (message)
344         dbus_message_unref(message);
345
346     if (reply)
347         dbus_message_unref(reply);
348
349     return NULL;
350 }
351
352 AvahiClient* avahi_service_type_browser_get_client (AvahiServiceTypeBrowser *b)
353 {
354     assert(b);
355     return b->client;
356 }
357
358 int avahi_service_type_browser_free (AvahiServiceTypeBrowser *b) {
359     AvahiClient *client;
360     int r = AVAHI_OK;
361
362     assert(b);
363     client = b->client;
364
365     if (b->path && client->state != AVAHI_CLIENT_DISCONNECTED)
366         r = avahi_client_simple_method_call(client, b->path, AVAHI_DBUS_INTERFACE_SERVICE_TYPE_BROWSER, "Free");
367
368     AVAHI_LLIST_REMOVE(AvahiServiceTypeBrowser, service_type_browsers, b->client->service_type_browsers, b);
369
370     avahi_free(b->path);
371     avahi_free(b);
372     return r;
373 }
374
375 DBusHandlerResult avahi_service_type_browser_event (AvahiClient *client, AvahiBrowserEvent event, DBusMessage *message) {
376     AvahiServiceTypeBrowser *b = NULL;
377     DBusError error;
378     const char *path;
379     char *domain = NULL, *type = NULL;
380     int32_t interface = AVAHI_IF_UNSPEC, protocol = AVAHI_PROTO_UNSPEC;
381     uint32_t flags = 0;
382
383     assert(client);
384     assert(message);
385     
386     dbus_error_init (&error);
387
388     if (!(path = dbus_message_get_path(message)))
389         goto fail;
390
391     for (b = client->service_type_browsers; b; b = b->service_type_browsers_next)
392         if (strcmp (b->path, path) == 0)
393             break;
394
395     if (!b)
396         goto fail;
397     switch (event) {
398         case AVAHI_BROWSER_NEW:
399         case AVAHI_BROWSER_REMOVE:
400             if (!dbus_message_get_args(
401                     message, &error,
402                     DBUS_TYPE_INT32, &interface,
403                     DBUS_TYPE_INT32, &protocol,
404                     DBUS_TYPE_STRING, &type,
405                     DBUS_TYPE_STRING, &domain,
406                     DBUS_TYPE_UINT32, &flags,
407                     DBUS_TYPE_INVALID) ||
408                 dbus_error_is_set(&error)) {
409                 fprintf(stderr, "Failed to parse browser event.\n");
410                 goto fail;
411             }
412             break;
413             
414         case AVAHI_BROWSER_CACHE_EXHAUSTED:
415         case AVAHI_BROWSER_ALL_FOR_NOW:
416             break;
417
418         case AVAHI_BROWSER_FAILURE: {
419             char *etxt;
420             
421             if (!dbus_message_get_args(
422                     message, &error,
423                     DBUS_TYPE_STRING, &etxt,
424                     DBUS_TYPE_INVALID) ||
425                 dbus_error_is_set (&error)) {
426                 fprintf(stderr, "Failed to parse browser event.\n");
427                 goto fail;
428             }
429             
430             avahi_client_set_errno(b->client, avahi_error_dbus_to_number(etxt));
431             break;
432         }
433     }
434
435     b->callback(b, (AvahiIfIndex) interface, (AvahiProtocol) protocol, event, type, domain, (AvahiLookupResultFlags) flags, b->userdata);
436
437     return DBUS_HANDLER_RESULT_HANDLED;
438
439 fail:
440     dbus_error_free (&error);
441     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
442 }
443
444 /* AvahiServiceBrowser */
445
446 AvahiServiceBrowser* avahi_service_browser_new(
447     AvahiClient *client,
448     AvahiIfIndex interface,
449     AvahiProtocol protocol,
450     const char *type,
451     const char *domain,
452     AvahiLookupFlags flags, 
453     AvahiServiceBrowserCallback callback,
454     void *userdata) {
455     
456     AvahiServiceBrowser *b = NULL;
457     DBusMessage *message = NULL, *reply = NULL;
458     DBusError error;
459     char *path;
460     int32_t i_protocol, i_interface;
461     uint32_t u_flags;
462
463     assert(client);
464     assert(type);
465     assert(callback);
466
467     dbus_error_init(&error);
468
469     if (client->state == AVAHI_CLIENT_DISCONNECTED) {
470         avahi_client_set_errno(client, AVAHI_ERR_BAD_STATE);
471         goto fail;
472     }
473
474     if (!domain)
475         domain = "";
476
477     if (!(b = avahi_new(AvahiServiceBrowser, 1))) {
478         avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
479         goto fail;
480     }
481     
482     b->client = client;
483     b->callback = callback;
484     b->userdata = userdata;
485     b->path = NULL;
486
487     AVAHI_LLIST_PREPEND(AvahiServiceBrowser, service_browsers, client->service_browsers, b);
488
489     if (!(message = dbus_message_new_method_call (AVAHI_DBUS_NAME, AVAHI_DBUS_PATH_SERVER, AVAHI_DBUS_INTERFACE_SERVER, "ServiceBrowserNew"))) {
490         avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
491         goto fail;
492     }
493
494     i_interface = (int32_t) interface;
495     i_protocol = (int32_t) protocol;
496     u_flags = (uint32_t) flags;
497
498     if (!dbus_message_append_args(
499             message,
500             DBUS_TYPE_INT32, &i_interface,
501             DBUS_TYPE_INT32, &i_protocol,
502             DBUS_TYPE_STRING, &type,
503             DBUS_TYPE_STRING, &domain,
504             DBUS_TYPE_UINT32, &u_flags,
505             DBUS_TYPE_INVALID)) {
506         avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
507         goto fail;
508     }
509
510     if (!(reply = dbus_connection_send_with_reply_and_block (client->bus, message, -1, &error)) ||
511         dbus_error_is_set(&error)) {
512         avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR);
513         goto fail;
514     }
515
516     if (!dbus_message_get_args (reply, &error, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID) ||
517         dbus_error_is_set(&error) ||
518         !path) {
519         avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR);
520         goto fail;
521     }
522
523     if (!(b->path = avahi_strdup(path))) {
524
525         /* FIXME: We don't remove the object on the server side */
526
527         avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
528         goto fail;
529     }
530
531     dbus_message_unref(message);
532     dbus_message_unref(reply);
533     
534     return b;
535
536 fail:
537     if (dbus_error_is_set(&error)) {
538         avahi_client_set_dbus_error(client, &error);
539         dbus_error_free(&error);
540     }
541
542     if (b)
543         avahi_service_browser_free(b);
544     
545     if (message)
546         dbus_message_unref(message);
547
548     if (reply)
549         dbus_message_unref(reply);
550
551     return NULL;
552 }
553
554 AvahiClient* avahi_service_browser_get_client (AvahiServiceBrowser *b)
555 {
556     assert(b);
557     return b->client;
558 }
559
560 int avahi_service_browser_free (AvahiServiceBrowser *b) {
561     AvahiClient *client;
562     int r = AVAHI_OK;
563
564     assert(b);
565     client = b->client;
566
567     if (b->path && client->state != AVAHI_CLIENT_DISCONNECTED)
568         r = avahi_client_simple_method_call(client, b->path, AVAHI_DBUS_INTERFACE_SERVICE_BROWSER, "Free");
569
570     AVAHI_LLIST_REMOVE(AvahiServiceBrowser, service_browsers, b->client->service_browsers, b);
571
572     avahi_free(b->path);
573     avahi_free(b);
574     return r;
575 }
576
577
578 DBusHandlerResult avahi_service_browser_event(AvahiClient *client, AvahiBrowserEvent event, DBusMessage *message) {
579     AvahiServiceBrowser *b = NULL;
580     DBusError error;
581     const char *path;
582     char *name = NULL, *type = NULL, *domain = NULL;
583     int32_t interface = AVAHI_IF_UNSPEC, protocol = AVAHI_PROTO_UNSPEC;
584     uint32_t flags = 0;
585
586     dbus_error_init (&error);
587
588     if (!(path = dbus_message_get_path(message)))
589         goto fail;
590
591     for (b = client->service_browsers; b; b = b->service_browsers_next)
592         if (strcmp (b->path, path) == 0)
593             break;
594
595     if (!b)
596         goto fail;
597
598     switch (event) {
599         case AVAHI_BROWSER_NEW:
600         case AVAHI_BROWSER_REMOVE:
601             
602             if (!dbus_message_get_args (
603                     message, &error,
604                     DBUS_TYPE_INT32, &interface,
605                     DBUS_TYPE_INT32, &protocol,
606                     DBUS_TYPE_STRING, &name,
607                     DBUS_TYPE_STRING, &type,
608                     DBUS_TYPE_STRING, &domain,
609                     DBUS_TYPE_UINT32, &flags,
610                     DBUS_TYPE_INVALID) ||
611                 dbus_error_is_set(&error)) {
612                 fprintf(stderr, "Failed to parse browser event.\n");
613                 goto fail;
614             }
615             break;
616
617         case AVAHI_BROWSER_CACHE_EXHAUSTED:
618         case AVAHI_BROWSER_ALL_FOR_NOW:
619             break;
620
621         case AVAHI_BROWSER_FAILURE: {
622             char *etxt;
623             
624             if (!dbus_message_get_args(
625                     message, &error,
626                     DBUS_TYPE_STRING, &etxt,
627                     DBUS_TYPE_INVALID) ||
628                 dbus_error_is_set (&error)) {
629                 fprintf(stderr, "Failed to parse browser event.\n");
630                 goto fail;
631             }
632             
633             avahi_client_set_errno(b->client, avahi_error_dbus_to_number(etxt));
634             break;
635         }
636     }
637
638     b->callback(b, (AvahiIfIndex) interface, (AvahiProtocol) protocol, event, name, type, domain, (AvahiLookupResultFlags) flags, b->userdata);
639
640     return DBUS_HANDLER_RESULT_HANDLED;
641
642 fail:
643     dbus_error_free (&error);
644     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
645 }
646
647