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