]> git.meshlink.io Git - catta/blob - avahi-client/entrygroup.c
* many improvements to avahi-client (especially error handling)
[catta] / avahi-client / entrygroup.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 void avahi_entry_group_set_state(AvahiEntryGroup *group, AvahiEntryGroupState state) {
42     assert(group);
43
44     if (group->state == state)
45         return;
46
47     group->state = state;
48
49     if (group->callback)
50         group->callback(group, state, group->userdata);
51 }
52
53 static int retrieve_state(AvahiEntryGroup *group) {
54     DBusMessage *message, *reply;
55     DBusError error;
56     int r = AVAHI_OK;
57     int32_t state;
58     AvahiClient *client;
59     
60     dbus_error_init(&error);
61
62     assert(group);
63     client = group->client;
64     
65     if (!(message = dbus_message_new_method_call(AVAHI_DBUS_NAME, group->path, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "GetState"))) {
66         r = avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
67         goto fail;
68     }
69         
70     if (!(reply = dbus_connection_send_with_reply_and_block(client->bus, message, -1, &error)) ||
71         dbus_error_is_set (&error)) {
72         r = avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR);
73         goto fail;
74     }
75     
76     if (!dbus_message_get_args(reply, &error, DBUS_TYPE_INT32, &state, DBUS_TYPE_INVALID) ||
77         dbus_error_is_set (&error)) {
78         r = avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR);
79         goto fail;
80     }
81
82     dbus_message_unref(message);
83     dbus_message_unref(reply);
84
85     avahi_entry_group_set_state(group, (AvahiEntryGroupState) state);
86     
87     return AVAHI_OK;
88     
89 fail:
90     if (dbus_error_is_set(&error)) {
91         r = avahi_client_set_dbus_error(client, &error);
92         dbus_error_free(&error);
93     }
94
95     if (message)
96         dbus_message_unref(message);
97
98     if (reply)
99         dbus_message_unref(reply);
100
101     return r;
102 }
103
104 AvahiEntryGroup* avahi_entry_group_new (AvahiClient *client, AvahiEntryGroupCallback callback, void *userdata) {
105     AvahiEntryGroup *group = NULL;
106     DBusMessage *message = NULL, *reply = NULL;
107     DBusError error;
108     char *path;
109
110     assert(client);
111
112     dbus_error_init (&error);
113
114     if (client->state == AVAHI_CLIENT_DISCONNECTED) {
115         avahi_client_set_errno(client, AVAHI_ERR_BAD_STATE);
116         goto fail;
117     }
118
119     if (!(group = avahi_new(AvahiEntryGroup, 1))) {
120         avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
121         goto fail;
122     }
123     
124     group->client = client;
125     group->callback = callback;
126     group->userdata = userdata;
127     group->state = AVAHI_ENTRY_GROUP_UNCOMMITED;
128     AVAHI_LLIST_PREPEND(AvahiEntryGroup, groups, client->groups, group);
129     
130     if (!(message = dbus_message_new_method_call(
131               AVAHI_DBUS_NAME,
132               AVAHI_DBUS_PATH_SERVER,
133               AVAHI_DBUS_INTERFACE_SERVER,
134               "EntryGroupNew"))) {
135         avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
136         goto fail;
137     }
138
139     if (!(reply = dbus_connection_send_with_reply_and_block (client->bus, message, -1, &error)) ||
140         dbus_error_is_set (&error)) {
141         avahi_client_set_errno (client, AVAHI_ERR_DBUS_ERROR);
142         goto fail;
143     }
144
145     if (!dbus_message_get_args(reply, &error, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID) ||
146         dbus_error_is_set (&error)) {
147         avahi_client_set_errno (client, AVAHI_ERR_DBUS_ERROR);
148         goto fail;
149     }
150     
151     if (!(group->path = avahi_strdup (path))) {
152
153         /* FIXME: We don't remove the object on the server side */
154
155         avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
156         goto fail;
157     }
158
159
160     if (retrieve_state(group) < 0)
161         goto fail;
162
163     dbus_message_unref(message);
164     dbus_message_unref(reply);
165
166     return group;
167
168 fail:
169     if (dbus_error_is_set(&error)) {
170         avahi_client_set_dbus_error(client, &error);
171         dbus_error_free(&error);
172     }
173
174     if (group)
175         avahi_entry_group_free(group);
176     
177     if (message)
178         dbus_message_unref(message);
179
180     if (reply)
181         dbus_message_unref(reply);
182     
183     return NULL;
184 }
185
186 static int entry_group_simple_method_call(AvahiEntryGroup *group, const char *method) {
187     DBusMessage *message, *reply;
188     DBusError error;
189     int r = AVAHI_OK;
190     AvahiClient *client;
191     
192     dbus_error_init(&error);
193
194     assert(group);
195     client = group->client;
196     
197     if (!(message = dbus_message_new_method_call(AVAHI_DBUS_NAME, group->path, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, method))) {
198         r = avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
199         goto fail;
200     }
201         
202     if (!(reply = dbus_connection_send_with_reply_and_block(client->bus, message, -1, &error)) ||
203         dbus_error_is_set (&error)) {
204         r = avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR);
205         goto fail;
206     }
207     
208     if (!dbus_message_get_args(reply, &error, DBUS_TYPE_INVALID) ||
209         dbus_error_is_set (&error)) {
210         r = avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR);
211         goto fail;
212     }
213
214     dbus_message_unref(message);
215     dbus_message_unref(reply);
216
217     return AVAHI_OK;
218     
219 fail:
220     if (dbus_error_is_set(&error)) {
221         r = avahi_client_set_dbus_error(client, &error);
222         dbus_error_free(&error);
223     }
224
225     if (message)
226         dbus_message_unref(message);
227
228     if (reply)
229         dbus_message_unref(reply);
230
231     return r;
232 }
233
234 int avahi_entry_group_free(AvahiEntryGroup *group) {
235     AvahiClient *client = group->client;
236     int r = AVAHI_OK;
237         
238     assert(group);
239     
240     if (group->path && client->state != AVAHI_CLIENT_DISCONNECTED)
241         r = entry_group_simple_method_call(group, "Free");
242     
243     AVAHI_LLIST_REMOVE(AvahiEntryGroup, groups, client->groups, group);
244
245     avahi_free(group->path);
246     avahi_free(group);
247
248     return r;
249 }
250
251 int avahi_entry_group_commit(AvahiEntryGroup *group) {
252     assert(group);
253     
254     if (!group->path || group->client->state == AVAHI_CLIENT_DISCONNECTED)
255         return avahi_client_set_errno(group->client, AVAHI_ERR_BAD_STATE);
256
257     return entry_group_simple_method_call(group, "Commit");
258 }
259
260 int avahi_entry_group_reset(AvahiEntryGroup *group) {
261     assert(group);
262     
263     if (!group->path || group->client->state == AVAHI_CLIENT_DISCONNECTED)
264         return avahi_client_set_errno(group->client, AVAHI_ERR_BAD_STATE);
265
266     return entry_group_simple_method_call(group, "Reset");
267 }
268
269 int avahi_entry_group_get_state (AvahiEntryGroup *group) {
270     assert (group);
271
272     return group->state;
273 }
274
275 AvahiClient* avahi_entry_group_get_client (AvahiEntryGroup *group) {
276     assert(group);
277     
278     return group->client;
279 }
280
281 int avahi_entry_group_is_empty (AvahiEntryGroup *group) {
282     DBusMessage *message, *reply;
283     DBusError error;
284     int r = AVAHI_OK;
285     int b;
286     AvahiClient *client;
287     
288     assert(group);
289     client = group->client;
290
291     dbus_error_init(&error);
292     
293     if (!(message = dbus_message_new_method_call(AVAHI_DBUS_NAME, group->path, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "IsEmpty"))) {
294         r = avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
295         goto fail;
296     }
297         
298     if (!(reply = dbus_connection_send_with_reply_and_block(client->bus, message, -1, &error)) ||
299         dbus_error_is_set (&error)) {
300         r = avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR);
301         goto fail;
302     }
303     
304     if (!dbus_message_get_args(reply, &error, DBUS_TYPE_BOOLEAN, &b, DBUS_TYPE_INVALID) ||
305         dbus_error_is_set (&error)) {
306         r = avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR);
307         goto fail;
308     }
309
310     dbus_message_unref(message);
311     dbus_message_unref(reply);
312
313     return !!b;
314     
315 fail:
316     if (dbus_error_is_set(&error)) {
317         r = avahi_client_set_dbus_error(client, &error);
318         dbus_error_free(&error);
319     }
320
321     if (message)
322         dbus_message_unref(message);
323
324     if (reply)
325         dbus_message_unref(reply);
326
327     return r;
328 }
329
330 int avahi_entry_group_add_service_strlst(
331     AvahiEntryGroup *group,
332     AvahiIfIndex interface,
333     AvahiProtocol protocol,
334     const char *name,
335     const char *type,
336     const char *domain,
337     const char *host,
338     uint16_t port,
339     AvahiStringList *txt) {
340     
341     DBusMessage *message = NULL, *reply = NULL;
342     DBusMessageIter iter, sub;
343     AvahiStringList *p;
344     int reverse = 0, r = AVAHI_OK;
345     DBusError error;
346     AvahiClient *client;
347
348     assert(group);
349     assert(name);
350     assert(type);
351
352     client = group->client;
353
354     dbus_error_init(&error);
355     
356     if (!(message = dbus_message_new_method_call (AVAHI_DBUS_NAME, group->path, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "AddService"))) {
357         r = avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
358         goto fail;
359     }
360
361     if (!dbus_message_append_args(
362             message,
363             DBUS_TYPE_INT32, &interface,
364             DBUS_TYPE_INT32, &protocol,
365             DBUS_TYPE_STRING, &name,
366             DBUS_TYPE_STRING, &type,
367             DBUS_TYPE_STRING, &domain,
368             DBUS_TYPE_STRING, &host,
369             DBUS_TYPE_UINT16, &port,
370             DBUS_TYPE_INVALID)) {
371         r = avahi_client_set_errno(group->client, AVAHI_ERR_NO_MEMORY);
372         goto fail;
373     }
374     
375     dbus_message_iter_init_append(message, &iter);
376
377     /* Reverse the string list, so that we can pass it in-order to the server */
378     txt = avahi_string_list_reverse(txt);
379     reverse = 1;
380     
381     if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "ay", &sub)) {
382         r = avahi_client_set_errno(group->client, AVAHI_ERR_NO_MEMORY);
383         goto fail;
384     }
385
386     /* Assemble the AvahiStringList into an Array of Array of Bytes to send over dbus */
387     for (p = txt; p != NULL; p = p->next) {
388         DBusMessageIter sub2;
389         const uint8_t *data = p->text;
390         
391         if (!(dbus_message_iter_open_container(&sub, DBUS_TYPE_ARRAY, "y", &sub2)) ||
392             !(dbus_message_iter_append_fixed_array(&sub2, DBUS_TYPE_BYTE, &data, p->size)) ||
393             !(dbus_message_iter_close_container(&sub, &sub2))) {
394             r = avahi_client_set_errno(group->client, AVAHI_ERR_NO_MEMORY);
395             goto fail;
396         }
397     }
398
399     if (!dbus_message_iter_close_container(&iter, &sub))  {
400         r = avahi_client_set_errno(group->client, AVAHI_ERR_NO_MEMORY);
401         goto fail;
402     }
403
404     /* Reverse the string list to the original state */
405     txt = avahi_string_list_reverse(txt);
406     reverse = 0;
407     
408     if (!(reply = dbus_connection_send_with_reply_and_block(client->bus, message, -1, &error)) ||
409         dbus_error_is_set (&error)) {
410         r = avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR);
411         goto fail;
412     }
413     
414     if (!dbus_message_get_args(reply, &error, DBUS_TYPE_INVALID) ||
415         dbus_error_is_set (&error)) {
416         r = avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR);
417         goto fail;
418     }
419
420     dbus_message_unref(message);
421     dbus_message_unref(reply);
422
423     return AVAHI_OK;
424
425 fail:
426     if (reverse)
427         txt = avahi_string_list_reverse(txt);
428     
429     if (dbus_error_is_set(&error)) {
430         r = avahi_client_set_dbus_error(client, &error);
431         dbus_error_free(&error);
432     }
433
434     if (message)
435         dbus_message_unref(message);
436
437     if (reply)
438         dbus_message_unref(reply);
439
440     return r;
441 }
442
443 int avahi_entry_group_add_service(
444     AvahiEntryGroup *group,
445     AvahiIfIndex interface,
446     AvahiProtocol protocol,
447     const char *name,
448     const char *type,
449     const char *domain,
450     const char *host,
451     uint16_t port,
452     ...) {
453     
454     va_list va;
455     int r;
456
457     assert(group);
458
459     va_start(va, port);
460     r = avahi_entry_group_add_service_va(group, interface, protocol, name, type, domain, host, port, va);
461     va_end(va);
462     return r;
463 }
464
465 int avahi_entry_group_add_service_va(
466     AvahiEntryGroup *group,
467     AvahiIfIndex interface,
468     AvahiProtocol protocol,
469     const char *name,
470     const char *type,
471     const char *domain,
472     const char *host,
473     uint16_t port,
474     va_list va) {
475
476     int r;
477     AvahiStringList *txt;
478
479     assert(group);
480
481     txt = avahi_string_list_new_va(va);
482     r = avahi_entry_group_add_service_strlst(group, interface, protocol, name, type, domain, host, port, txt);
483     avahi_string_list_free(txt);
484
485     return r;
486 }
487
488 const char* avahi_entry_group_get_dbus_path(AvahiEntryGroup *group) {
489     assert(group);
490
491     return group->path;
492 }