]> git.meshlink.io Git - catta/blob - avahi-client/entrygroup.c
CVE-2009-0758: Reflector creates packet storm on legacy unicast traffic
[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_valid && group->state == state)
45         return;
46
47     group->state = state;
48     group->state_valid = 1;
49
50     if (group->callback)
51         group->callback(group, state, group->userdata);
52 }
53
54 static int retrieve_state(AvahiEntryGroup *group) {
55     DBusMessage *message = NULL, *reply = NULL;
56     DBusError error;
57     int r = AVAHI_OK;
58     int32_t state;
59     AvahiClient *client;
60     
61     dbus_error_init(&error);
62
63     assert(group);
64     client = group->client;
65     
66     if (!(message = dbus_message_new_method_call(AVAHI_DBUS_NAME, group->path, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "GetState"))) {
67         r = avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
68         goto fail;
69     }
70         
71     if (!(reply = dbus_connection_send_with_reply_and_block(client->bus, message, -1, &error)) ||
72         dbus_error_is_set (&error)) {
73         r = avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR);
74         goto fail;
75     }
76     
77     if (!dbus_message_get_args(reply, &error, DBUS_TYPE_INT32, &state, DBUS_TYPE_INVALID) ||
78         dbus_error_is_set (&error)) {
79         r = avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR);
80         goto fail;
81     }
82
83     dbus_message_unref(message);
84     dbus_message_unref(reply);
85
86     return state;
87     
88 fail:
89     if (dbus_error_is_set(&error)) {
90         r = avahi_client_set_dbus_error(client, &error);
91         dbus_error_free(&error);
92     }
93
94     if (message)
95         dbus_message_unref(message);
96
97     if (reply)
98         dbus_message_unref(reply);
99
100     return r;
101 }
102
103 AvahiEntryGroup* avahi_entry_group_new (AvahiClient *client, AvahiEntryGroupCallback callback, void *userdata) {
104     AvahiEntryGroup *group = NULL;
105     DBusMessage *message = NULL, *reply = NULL;
106     DBusError error;
107     char *path;
108     int state;
109
110     assert(client);
111
112     dbus_error_init (&error);
113
114     if (!avahi_client_is_connected(client)) {
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_valid = 0;
128     group->path = NULL;
129     AVAHI_LLIST_PREPEND(AvahiEntryGroup, groups, client->groups, group);
130     
131     if (!(message = dbus_message_new_method_call(
132               AVAHI_DBUS_NAME,
133               AVAHI_DBUS_PATH_SERVER,
134               AVAHI_DBUS_INTERFACE_SERVER,
135               "EntryGroupNew"))) {
136         avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
137         goto fail;
138     }
139
140     if (!(reply = dbus_connection_send_with_reply_and_block (client->bus, message, -1, &error)) ||
141         dbus_error_is_set (&error)) {
142         avahi_client_set_errno (client, AVAHI_ERR_DBUS_ERROR);
143         goto fail;
144     }
145
146     if (!dbus_message_get_args(reply, &error, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID) ||
147         dbus_error_is_set (&error)) {
148         avahi_client_set_errno (client, AVAHI_ERR_DBUS_ERROR);
149         goto fail;
150     }
151     
152     if (!(group->path = avahi_strdup (path))) {
153
154         /* FIXME: We don't remove the object on the server side */
155
156         avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
157         goto fail;
158     }
159
160     if ((state = retrieve_state(group)) < 0) {
161         avahi_client_set_errno(client, state);
162         goto fail;
163     }
164     
165     avahi_entry_group_set_state(group, (AvahiEntryGroupState) state);
166
167     dbus_message_unref(message);
168     dbus_message_unref(reply);
169
170     return group;
171
172 fail:
173     if (dbus_error_is_set(&error)) {
174         avahi_client_set_dbus_error(client, &error);
175         dbus_error_free(&error);
176     }
177
178     if (group)
179         avahi_entry_group_free(group);
180     
181     if (message)
182         dbus_message_unref(message);
183
184     if (reply)
185         dbus_message_unref(reply);
186     
187     return NULL;
188 }
189
190 static int entry_group_simple_method_call(AvahiEntryGroup *group, const char *method) {
191     DBusMessage *message = NULL, *reply = NULL;
192     DBusError error;
193     int r = AVAHI_OK;
194     AvahiClient *client;
195     
196     dbus_error_init(&error);
197
198     assert(group);
199     client = group->client;
200     
201     if (!(message = dbus_message_new_method_call(AVAHI_DBUS_NAME, group->path, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, method))) {
202         r = avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
203         goto fail;
204     }
205         
206     if (!(reply = dbus_connection_send_with_reply_and_block(client->bus, message, -1, &error)) ||
207         dbus_error_is_set (&error)) {
208         r = avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR);
209         goto fail;
210     }
211     
212     if (!dbus_message_get_args(reply, &error, DBUS_TYPE_INVALID) ||
213         dbus_error_is_set (&error)) {
214         r = avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR);
215         goto fail;
216     }
217
218     dbus_message_unref(message);
219     dbus_message_unref(reply);
220
221     return AVAHI_OK;
222     
223 fail:
224     if (dbus_error_is_set(&error)) {
225         r = avahi_client_set_dbus_error(client, &error);
226         dbus_error_free(&error);
227     }
228
229     if (message)
230         dbus_message_unref(message);
231
232     if (reply)
233         dbus_message_unref(reply);
234
235     return r;
236 }
237
238 int avahi_entry_group_free(AvahiEntryGroup *group) {
239     AvahiClient *client = group->client;
240     int r = AVAHI_OK;
241         
242     assert(group);
243     
244     if (group->path && avahi_client_is_connected(client))
245         r = entry_group_simple_method_call(group, "Free");
246     
247     AVAHI_LLIST_REMOVE(AvahiEntryGroup, groups, client->groups, group);
248
249     avahi_free(group->path);
250     avahi_free(group);
251
252     return r;
253 }
254
255 int avahi_entry_group_commit(AvahiEntryGroup *group) {
256     int ret;
257     assert(group);
258     
259     if (!group->path || !avahi_client_is_connected(group->client))
260         return avahi_client_set_errno(group->client, AVAHI_ERR_BAD_STATE);
261
262     if ((ret = entry_group_simple_method_call(group, "Commit")) < 0)
263         return ret;
264
265     group->state_valid = 0;
266     return ret;
267 }
268
269 int avahi_entry_group_reset(AvahiEntryGroup *group) {
270     int ret;
271     assert(group);
272     
273     if (!group->path || !avahi_client_is_connected(group->client))
274         return avahi_client_set_errno(group->client, AVAHI_ERR_BAD_STATE);
275
276     if ((ret = entry_group_simple_method_call(group, "Reset")) < 0)
277         return ret;
278     
279     group->state_valid = 0;
280     return ret;
281 }
282
283 int avahi_entry_group_get_state (AvahiEntryGroup *group) {
284     assert (group);
285
286     if (group->state_valid)
287         return group->state;
288     
289     return retrieve_state(group);
290 }
291
292 AvahiClient* avahi_entry_group_get_client (AvahiEntryGroup *group) {
293     assert(group);
294     
295     return group->client;
296 }
297
298 int avahi_entry_group_is_empty (AvahiEntryGroup *group) {
299     DBusMessage *message = NULL, *reply = NULL;
300     DBusError error;
301     int r = AVAHI_OK;
302     int b;
303     AvahiClient *client;
304     
305     assert(group);
306     client = group->client;
307
308     if (!group->path || !avahi_client_is_connected(group->client))
309         return avahi_client_set_errno(group->client, AVAHI_ERR_BAD_STATE);
310
311     dbus_error_init(&error);
312     
313     if (!(message = dbus_message_new_method_call(AVAHI_DBUS_NAME, group->path, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "IsEmpty"))) {
314         r = avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
315         goto fail;
316     }
317         
318     if (!(reply = dbus_connection_send_with_reply_and_block(client->bus, message, -1, &error)) ||
319         dbus_error_is_set (&error)) {
320         r = avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR);
321         goto fail;
322     }
323     
324     if (!dbus_message_get_args(reply, &error, DBUS_TYPE_BOOLEAN, &b, DBUS_TYPE_INVALID) ||
325         dbus_error_is_set (&error)) {
326         r = avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR);
327         goto fail;
328     }
329
330     dbus_message_unref(message);
331     dbus_message_unref(reply);
332
333     return !!b;
334     
335 fail:
336     if (dbus_error_is_set(&error)) {
337         r = avahi_client_set_dbus_error(client, &error);
338         dbus_error_free(&error);
339     }
340
341     if (message)
342         dbus_message_unref(message);
343
344     if (reply)
345         dbus_message_unref(reply);
346
347     return r;
348 }
349
350 static int append_rdata(DBusMessage *message, const void *rdata, size_t size) {
351     DBusMessageIter iter, sub;
352  
353     assert(message);
354  
355     dbus_message_iter_init_append(message, &iter);
356  
357     if (!(dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE_AS_STRING, &sub)) ||
358         !(dbus_message_iter_append_fixed_array(&sub, DBUS_TYPE_BYTE, &rdata, size)) ||
359         !(dbus_message_iter_close_container(&iter, &sub)))
360         return -1;
361     
362     return 0;
363 }
364
365 static int append_string_list(DBusMessage *message, AvahiStringList *txt) {
366     DBusMessageIter iter, sub;
367     int r = -1;
368     AvahiStringList *p;
369
370     assert(message);
371
372     dbus_message_iter_init_append(message, &iter);
373
374     /* Reverse the string list, so that we can pass it in-order to the server */
375     txt = avahi_string_list_reverse(txt);
376     
377     if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "ay", &sub))
378         goto fail;
379
380     /* Assemble the AvahiStringList into an Array of Array of Bytes to send over dbus */
381     for (p = txt; p != NULL; p = p->next) {
382         DBusMessageIter sub2;
383         const uint8_t *data = p->text;
384         
385         if (!(dbus_message_iter_open_container(&sub, DBUS_TYPE_ARRAY, "y", &sub2)) ||
386             !(dbus_message_iter_append_fixed_array(&sub2, DBUS_TYPE_BYTE, &data, p->size)) ||
387             !(dbus_message_iter_close_container(&sub, &sub2)))
388             goto fail;
389     }
390
391     if (!dbus_message_iter_close_container(&iter, &sub))
392         goto fail;
393
394     r = 0;
395
396 fail:
397
398     /* Reverse the string list to the original state */
399     txt = avahi_string_list_reverse(txt);
400
401     return r;
402 }
403
404 int avahi_entry_group_add_service_strlst(
405     AvahiEntryGroup *group,
406     AvahiIfIndex interface,
407     AvahiProtocol protocol,
408     AvahiPublishFlags flags,
409     const char *name,
410     const char *type,
411     const char *domain,
412     const char *host,
413     uint16_t port,
414     AvahiStringList *txt) {
415     
416     DBusMessage *message = NULL, *reply = NULL;
417     int r = AVAHI_OK;
418     DBusError error;
419     AvahiClient *client;
420     int32_t i_interface, i_protocol;
421     uint32_t u_flags;
422
423     assert(group);
424     assert(name);
425     assert(type);
426
427     client = group->client;
428
429     if (!group->path || !avahi_client_is_connected(group->client))
430         return avahi_client_set_errno(group->client, AVAHI_ERR_BAD_STATE);
431
432     if (!domain)
433         domain = "";
434
435     if (!host)
436         host = "";
437     
438     dbus_error_init(&error);
439     
440     if (!(message = dbus_message_new_method_call (AVAHI_DBUS_NAME, group->path, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "AddService"))) {
441         r = avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
442         goto fail;
443     }
444
445     i_interface = (int32_t) interface;
446     i_protocol = (int32_t) protocol;
447     u_flags = (uint32_t) flags;
448
449     if (!dbus_message_append_args(
450             message,
451             DBUS_TYPE_INT32, &i_interface,
452             DBUS_TYPE_INT32, &i_protocol,
453             DBUS_TYPE_UINT32, &u_flags,
454             DBUS_TYPE_STRING, &name,
455             DBUS_TYPE_STRING, &type,
456             DBUS_TYPE_STRING, &domain,
457             DBUS_TYPE_STRING, &host,
458             DBUS_TYPE_UINT16, &port,
459             DBUS_TYPE_INVALID) ||
460         append_string_list(message, txt) < 0) {
461         r = avahi_client_set_errno(group->client, AVAHI_ERR_NO_MEMORY);
462         goto fail;
463     }
464     
465     if (!(reply = dbus_connection_send_with_reply_and_block(client->bus, message, -1, &error)) ||
466         dbus_error_is_set (&error)) {
467         r = avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR);
468         goto fail;
469     }
470     
471     if (!dbus_message_get_args(reply, &error, DBUS_TYPE_INVALID) ||
472         dbus_error_is_set (&error)) {
473         r = avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR);
474         goto fail;
475     }
476
477     dbus_message_unref(message);
478     dbus_message_unref(reply);
479
480     return AVAHI_OK;
481
482 fail:
483     
484     if (dbus_error_is_set(&error)) {
485         r = avahi_client_set_dbus_error(client, &error);
486         dbus_error_free(&error);
487     }
488
489     if (message)
490         dbus_message_unref(message);
491
492     if (reply)
493         dbus_message_unref(reply);
494
495     return r;
496 }
497
498 int avahi_entry_group_add_service(
499     AvahiEntryGroup *group,
500     AvahiIfIndex interface,
501     AvahiProtocol protocol,
502     AvahiPublishFlags flags,
503     const char *name,
504     const char *type,
505     const char *domain,
506     const char *host,
507     uint16_t port,
508     ...) {
509     
510     va_list va;
511     int r;
512     AvahiStringList *txt;
513
514     assert(group);
515
516     va_start(va, port);
517     txt = avahi_string_list_new_va(va);
518     r = avahi_entry_group_add_service_strlst(group, interface, protocol, flags, name, type, domain, host, port, txt);
519     avahi_string_list_free(txt);
520     va_end(va);
521     return r;
522 }
523
524 int avahi_entry_group_add_service_subtype(
525     AvahiEntryGroup *group,
526     AvahiIfIndex interface,
527     AvahiProtocol protocol,
528     AvahiPublishFlags flags,
529     const char *name,
530     const char *type,
531     const char *domain,
532     const char *subtype) {
533
534     DBusMessage *message = NULL, *reply = NULL;
535     int r = AVAHI_OK;
536     DBusError error;
537     AvahiClient *client;
538     int32_t i_interface, i_protocol;
539     uint32_t u_flags;
540
541     assert(group);
542     assert(name);
543     assert(type);
544     assert(subtype);
545
546     client = group->client;
547
548     if (!group->path || !avahi_client_is_connected(group->client))
549         return avahi_client_set_errno(group->client, AVAHI_ERR_BAD_STATE);
550
551     if (!domain)
552         domain = "";
553
554     dbus_error_init(&error);
555     
556     if (!(message = dbus_message_new_method_call (AVAHI_DBUS_NAME, group->path, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "AddServiceSubtype"))) {
557         r = avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
558         goto fail;
559     }
560
561     i_interface = (int32_t) interface;
562     i_protocol = (int32_t) protocol;
563     u_flags = (uint32_t) flags;
564
565     if (!dbus_message_append_args(
566             message,
567             DBUS_TYPE_INT32, &i_interface,
568             DBUS_TYPE_INT32, &i_protocol,
569             DBUS_TYPE_UINT32, &u_flags,
570             DBUS_TYPE_STRING, &name,
571             DBUS_TYPE_STRING, &type,
572             DBUS_TYPE_STRING, &domain,
573             DBUS_TYPE_STRING, &subtype,
574             DBUS_TYPE_INVALID)) {
575         r = avahi_client_set_errno(group->client, AVAHI_ERR_NO_MEMORY);
576         goto fail;
577     }
578     
579     if (!(reply = dbus_connection_send_with_reply_and_block(client->bus, message, -1, &error)) ||
580         dbus_error_is_set (&error)) {
581         r = avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR);
582         goto fail;
583     }
584     
585     if (!dbus_message_get_args(reply, &error, DBUS_TYPE_INVALID) ||
586         dbus_error_is_set (&error)) {
587         r = avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR);
588         goto fail;
589     }
590
591     dbus_message_unref(message);
592     dbus_message_unref(reply);
593
594     return AVAHI_OK;
595
596 fail:
597     
598     if (dbus_error_is_set(&error)) {
599         r = avahi_client_set_dbus_error(client, &error);
600         dbus_error_free(&error);
601     }
602
603     if (message)
604         dbus_message_unref(message);
605
606     if (reply)
607         dbus_message_unref(reply);
608
609     return r;
610
611 }
612
613 int avahi_entry_group_update_service_txt(
614     AvahiEntryGroup *group,
615     AvahiIfIndex interface,
616     AvahiProtocol protocol,
617     AvahiPublishFlags flags,
618     const char *name,     
619     const char *type,     
620     const char *domain,   
621     ...) {
622
623     va_list va;
624     int r;
625     AvahiStringList *txt;
626
627     va_start(va, domain);
628     txt = avahi_string_list_new_va(va);
629     r = avahi_entry_group_update_service_txt_strlst(group, interface, protocol, flags, name, type, domain, txt);
630     avahi_string_list_free(txt);
631     va_end(va);
632     return r;
633 }
634
635 int avahi_entry_group_update_service_txt_strlst(
636     AvahiEntryGroup *group,
637     AvahiIfIndex interface,
638     AvahiProtocol protocol,
639     AvahiPublishFlags flags,
640     const char *name,     
641     const char *type,     
642     const char *domain,   
643     AvahiStringList *txt) {
644
645     DBusMessage *message = NULL, *reply = NULL;
646     int r = AVAHI_OK;
647     DBusError error;
648     AvahiClient *client;
649     int32_t i_interface, i_protocol;
650     uint32_t u_flags;
651
652     assert(group);
653     assert(name);
654     assert(type);
655
656     client = group->client;
657
658     if (!group->path || !avahi_client_is_connected(group->client))
659         return avahi_client_set_errno(group->client, AVAHI_ERR_BAD_STATE);
660
661     if (!domain)
662         domain = "";
663     
664     dbus_error_init(&error);
665     
666     if (!(message = dbus_message_new_method_call (AVAHI_DBUS_NAME, group->path, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "UpdateServiceTxt"))) {
667         r = avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
668         goto fail;
669     }
670
671     i_interface = (int32_t) interface;
672     i_protocol = (int32_t) protocol;
673     u_flags = (uint32_t) flags;
674
675     if (!dbus_message_append_args(
676             message,
677             DBUS_TYPE_INT32, &i_interface,
678             DBUS_TYPE_INT32, &i_protocol,
679             DBUS_TYPE_UINT32, &u_flags,
680             DBUS_TYPE_STRING, &name,
681             DBUS_TYPE_STRING, &type,
682             DBUS_TYPE_STRING, &domain,
683             DBUS_TYPE_INVALID) ||
684         append_string_list(message, txt) < 0) {
685         r = avahi_client_set_errno(group->client, AVAHI_ERR_NO_MEMORY);
686         goto fail;
687     }
688
689     if (!(reply = dbus_connection_send_with_reply_and_block(client->bus, message, -1, &error)) ||
690         dbus_error_is_set (&error)) {
691         r = avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR);
692         goto fail;
693     }
694     
695     if (!dbus_message_get_args(reply, &error, DBUS_TYPE_INVALID) ||
696         dbus_error_is_set (&error)) {
697         r = avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR);
698         goto fail;
699     }
700
701     dbus_message_unref(message);
702     dbus_message_unref(reply);
703
704     return AVAHI_OK;
705
706 fail:
707     
708     if (dbus_error_is_set(&error)) {
709         r = avahi_client_set_dbus_error(client, &error);
710         dbus_error_free(&error);
711     }
712
713     if (message)
714         dbus_message_unref(message);
715
716     if (reply)
717         dbus_message_unref(reply);
718
719     return r;
720 }
721
722 /** Add a host/address pair */
723 int avahi_entry_group_add_address(
724     AvahiEntryGroup *group,
725     AvahiIfIndex interface,
726     AvahiProtocol protocol,
727     AvahiPublishFlags flags,
728     const char *name,
729     const AvahiAddress *a) {
730
731     DBusMessage *message = NULL, *reply = NULL;
732     int r = AVAHI_OK;
733     DBusError error;
734     AvahiClient *client;
735     int32_t i_interface, i_protocol;
736     uint32_t u_flags;
737     char s_address[AVAHI_ADDRESS_STR_MAX];
738     char *p_address = s_address;
739
740     assert(name);
741
742     client = group->client;
743
744     if (!group->path || !avahi_client_is_connected(group->client))
745         return avahi_client_set_errno(group->client, AVAHI_ERR_BAD_STATE);
746
747     dbus_error_init(&error);
748     
749     if (!(message = dbus_message_new_method_call (AVAHI_DBUS_NAME, group->path, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "AddAddress"))) {
750         r = avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
751         goto fail;
752     }
753
754     i_interface = (int32_t) interface;
755     i_protocol = (int32_t) protocol;
756     u_flags = (uint32_t) flags;
757         
758     if (!avahi_address_snprint (s_address, sizeof (s_address), a))
759     {
760         r = avahi_client_set_errno(client, AVAHI_ERR_INVALID_ADDRESS);
761         goto fail;
762     }
763
764     if (!dbus_message_append_args(
765             message,
766             DBUS_TYPE_INT32, &i_interface,
767             DBUS_TYPE_INT32, &i_protocol,
768             DBUS_TYPE_UINT32, &u_flags,
769             DBUS_TYPE_STRING, &name,
770             DBUS_TYPE_STRING, &p_address,
771             DBUS_TYPE_INVALID)) {
772         r = avahi_client_set_errno(group->client, AVAHI_ERR_NO_MEMORY);
773         goto fail;
774     }
775     
776     if (!(reply = dbus_connection_send_with_reply_and_block(client->bus, message, -1, &error)) ||
777         dbus_error_is_set (&error)) {
778         r = avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR);
779         goto fail;
780     }
781     
782     if (!dbus_message_get_args(reply, &error, DBUS_TYPE_INVALID) ||
783         dbus_error_is_set (&error)) {
784         r = avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR);
785         goto fail;
786     }
787
788     dbus_message_unref(message);
789     dbus_message_unref(reply);
790
791     return AVAHI_OK;
792
793 fail:
794     
795     if (dbus_error_is_set(&error)) {
796         r = avahi_client_set_dbus_error(client, &error);
797         dbus_error_free(&error);
798     }
799
800     if (message)
801         dbus_message_unref(message);
802
803     if (reply)
804         dbus_message_unref(reply);
805
806     return r;
807 }
808
809 /** Add an arbitrary record */
810 int avahi_entry_group_add_record(
811     AvahiEntryGroup *group,
812     AvahiIfIndex interface,
813     AvahiProtocol protocol,
814     AvahiPublishFlags flags,
815     const char *name,
816     uint16_t clazz,
817     uint16_t type,
818     uint32_t ttl,
819     const void *rdata,
820     size_t size) {
821
822     DBusMessage *message = NULL, *reply = NULL;
823     int r = AVAHI_OK;
824     DBusError error;
825     AvahiClient *client;
826     int32_t i_interface, i_protocol;
827     uint32_t u_flags;
828
829     assert(name);
830
831     client = group->client;
832
833     if (!group->path || !avahi_client_is_connected(group->client))
834         return avahi_client_set_errno(group->client, AVAHI_ERR_BAD_STATE);
835
836     dbus_error_init(&error);
837     
838     if (!(message = dbus_message_new_method_call (AVAHI_DBUS_NAME, group->path, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "AddRecord"))) {
839         r = avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
840         goto fail;
841     }
842
843     i_interface = (int32_t) interface;
844     i_protocol = (int32_t) protocol;
845     u_flags = (uint32_t) flags;
846         
847     if (!dbus_message_append_args(
848             message,
849             DBUS_TYPE_INT32, &i_interface,
850             DBUS_TYPE_INT32, &i_protocol,
851             DBUS_TYPE_UINT32, &u_flags,
852             DBUS_TYPE_STRING, &name,
853             DBUS_TYPE_UINT16, &clazz,
854             DBUS_TYPE_UINT16, &type,
855             DBUS_TYPE_UINT32, &ttl,
856             DBUS_TYPE_INVALID) || append_rdata(message, rdata, size) < 0) {
857         r = avahi_client_set_errno(group->client, AVAHI_ERR_NO_MEMORY);
858         goto fail;
859     }
860     
861     if (!(reply = dbus_connection_send_with_reply_and_block(client->bus, message, -1, &error)) ||
862         dbus_error_is_set (&error)) {
863         r = avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR);
864         goto fail;
865     }
866     
867     if (!dbus_message_get_args(reply, &error, DBUS_TYPE_INVALID) ||
868         dbus_error_is_set (&error)) {
869         r = avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR);
870         goto fail;
871     }
872
873     dbus_message_unref(message);
874     dbus_message_unref(reply);
875
876     return AVAHI_OK;
877
878 fail:
879     
880     if (dbus_error_is_set(&error)) {
881         r = avahi_client_set_dbus_error(client, &error);
882         dbus_error_free(&error);
883     }
884
885     if (message)
886         dbus_message_unref(message);
887
888     if (reply)
889         dbus_message_unref(reply);
890
891     return r;
892 }