]> git.meshlink.io Git - catta/blob - avahi-core/dns.c
Merge portability patch from Philipp Zabel
[catta] / avahi-core / dns.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 <netinet/in.h>
27
28 #include <stdlib.h>
29 #include <string.h>
30 #include <stdio.h>
31 #include <assert.h>
32
33 #include <avahi-common/domain.h>
34 #include <avahi-common/malloc.h>
35
36 #include "dns.h"
37 #include "log.h"
38
39 AvahiDnsPacket* avahi_dns_packet_new(unsigned mtu) {
40     AvahiDnsPacket *p;
41     size_t max_size;
42
43     if (mtu <= 0)
44         max_size = AVAHI_DNS_PACKET_MAX_SIZE;
45     else if (mtu >= AVAHI_DNS_PACKET_EXTRA_SIZE)
46         max_size = mtu - AVAHI_DNS_PACKET_EXTRA_SIZE;
47     else
48         max_size = 0;
49
50     if (max_size < AVAHI_DNS_PACKET_HEADER_SIZE)
51         max_size = AVAHI_DNS_PACKET_HEADER_SIZE;
52     
53     if (!(p = avahi_malloc(sizeof(AvahiDnsPacket) + max_size)))
54         return p;
55     
56     p->size = p->rindex = AVAHI_DNS_PACKET_HEADER_SIZE;
57     p->max_size = max_size;
58     p->name_table = NULL;
59
60     memset(AVAHI_DNS_PACKET_DATA(p), 0, p->size);
61     return p;
62 }
63
64 AvahiDnsPacket* avahi_dns_packet_new_query(unsigned mtu) {
65     AvahiDnsPacket *p;
66
67     if (!(p = avahi_dns_packet_new(mtu)))
68         return NULL;
69     
70     avahi_dns_packet_set_field(p, AVAHI_DNS_FIELD_FLAGS, AVAHI_DNS_FLAGS(0, 0, 0, 0, 0, 0, 0, 0, 0, 0));
71     return p;
72 }
73
74 AvahiDnsPacket* avahi_dns_packet_new_response(unsigned mtu, int aa) {
75     AvahiDnsPacket *p;
76
77     if (!(p = avahi_dns_packet_new(mtu)))
78         return NULL;
79     
80     avahi_dns_packet_set_field(p, AVAHI_DNS_FIELD_FLAGS, AVAHI_DNS_FLAGS(1, 0, aa, 0, 0, 0, 0, 0, 0, 0));
81     return p;
82 }
83
84 AvahiDnsPacket* avahi_dns_packet_new_reply(AvahiDnsPacket* p, unsigned mtu, int copy_queries, int aa) {
85     AvahiDnsPacket *r;
86     assert(p);
87
88     if (!(r = avahi_dns_packet_new_response(mtu, aa)))
89         return NULL;
90
91     if (copy_queries) {
92         unsigned saved_rindex;
93         uint32_t n;
94
95         saved_rindex = p->rindex;
96         p->rindex = AVAHI_DNS_PACKET_HEADER_SIZE;
97         
98         for (n = avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_QDCOUNT); n > 0; n--) {
99             AvahiKey *k;
100             int unicast_response;
101
102             if ((k = avahi_dns_packet_consume_key(p, &unicast_response))) {
103                 avahi_dns_packet_append_key(r, k, unicast_response);
104                 avahi_key_unref(k);
105             }
106         }
107
108         p->rindex = saved_rindex;
109
110         avahi_dns_packet_set_field(r, AVAHI_DNS_FIELD_QDCOUNT, avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_QDCOUNT));
111     }
112
113     avahi_dns_packet_set_field(r, AVAHI_DNS_FIELD_ID, avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_ID));
114
115     avahi_dns_packet_set_field(r, AVAHI_DNS_FIELD_FLAGS,
116                                (avahi_dns_packet_get_field(r, AVAHI_DNS_FIELD_FLAGS) & ~AVAHI_DNS_FLAG_OPCODE) |
117                                (avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_FLAGS) & AVAHI_DNS_FLAG_OPCODE));
118
119     return r;
120
121
122
123 void avahi_dns_packet_free(AvahiDnsPacket *p) {
124     assert(p);
125
126     if (p->name_table)
127         avahi_hashmap_free(p->name_table);
128     
129     avahi_free(p);
130 }
131
132 void avahi_dns_packet_set_field(AvahiDnsPacket *p, unsigned idx, uint16_t v) {
133     assert(p);
134     assert(idx < AVAHI_DNS_PACKET_HEADER_SIZE);
135     
136     ((uint16_t*) AVAHI_DNS_PACKET_DATA(p))[idx] = htons(v);
137 }
138
139 uint16_t avahi_dns_packet_get_field(AvahiDnsPacket *p, unsigned idx) {
140     assert(p);
141     assert(idx < AVAHI_DNS_PACKET_HEADER_SIZE);
142
143     return ntohs(((uint16_t*) AVAHI_DNS_PACKET_DATA(p))[idx]);
144 }
145
146 void avahi_dns_packet_inc_field(AvahiDnsPacket *p, unsigned idx) {
147     assert(p);
148     assert(idx < AVAHI_DNS_PACKET_HEADER_SIZE);
149
150     avahi_dns_packet_set_field(p, idx, avahi_dns_packet_get_field(p, idx) + 1);
151 }   
152
153 uint8_t* avahi_dns_packet_append_name(AvahiDnsPacket *p, const char *name) {
154     uint8_t *d, *saved_ptr = NULL;
155     size_t saved_size;
156     
157     assert(p);
158     assert(name);
159
160     saved_size = p->size;
161     saved_ptr = avahi_dns_packet_extend(p, 0);
162     
163     while (*name) {
164         uint8_t* prev;
165         const char *pname;
166         char label[64], *u;
167         
168         /* Check whether we can compress this name. */
169
170         if (p->name_table && (prev = avahi_hashmap_lookup(p->name_table, name))) {
171             unsigned idx;
172             
173             assert(prev >= AVAHI_DNS_PACKET_DATA(p));
174             idx = (unsigned) (prev - AVAHI_DNS_PACKET_DATA(p));
175
176             assert(idx < p->size);
177
178             if (idx < 0x4000) {
179                 uint8_t *t;
180                 if (!(t = (uint8_t*) avahi_dns_packet_extend(p, sizeof(uint16_t))))
181                     return NULL;
182
183                 t[0] = (uint8_t) ((0xC000 | idx) >> 8);
184                 t[1] = (uint8_t) idx;
185                 return saved_ptr;
186             }
187         }
188
189         pname = name;
190         
191         if (!(avahi_unescape_label(&name, label, sizeof(label))))
192             goto fail;
193
194         if (!(d = avahi_dns_packet_append_string(p, label)))
195             goto fail;
196
197         if (!p->name_table)
198             /* This works only for normalized domain names */
199             p->name_table = avahi_hashmap_new(avahi_string_hash, avahi_string_equal, avahi_free, NULL);
200
201         if (!(u = avahi_strdup(pname)))
202             avahi_log_error("avahi_strdup() failed.");
203         else
204             avahi_hashmap_insert(p->name_table, u, d);
205     }
206
207     if (!(d = avahi_dns_packet_extend(p, 1)))
208         goto fail;
209     
210     *d = 0;
211
212     return saved_ptr;
213
214 fail:
215     p->size = saved_size;
216     return NULL;
217 }
218
219 uint8_t* avahi_dns_packet_append_uint16(AvahiDnsPacket *p, uint16_t v) {
220     uint8_t *d;
221     assert(p);
222     
223     if (!(d = avahi_dns_packet_extend(p, sizeof(uint16_t))))
224         return NULL;
225     
226     d[0] = (uint8_t) (v >> 8);
227     d[1] = (uint8_t) v;
228     return d;
229 }
230
231 uint8_t *avahi_dns_packet_append_uint32(AvahiDnsPacket *p, uint32_t v) {
232     uint8_t *d;
233     assert(p);
234
235     if (!(d = avahi_dns_packet_extend(p, sizeof(uint32_t))))
236         return NULL;
237     
238     d[0] = (uint8_t) (v >> 24);
239     d[1] = (uint8_t) (v >> 16);
240     d[2] = (uint8_t) (v >> 8);
241     d[3] = (uint8_t) v;
242
243     return d;
244 }
245
246 uint8_t *avahi_dns_packet_append_bytes(AvahiDnsPacket  *p, const void *b, size_t l) {
247     uint8_t* d;
248
249     assert(p);
250     assert(b);
251     assert(l);
252
253     if (!(d = avahi_dns_packet_extend(p, l)))
254         return NULL;
255
256     memcpy(d, b, l);
257     return d;
258 }
259
260 uint8_t* avahi_dns_packet_append_string(AvahiDnsPacket *p, const char *s) {
261     uint8_t* d;
262     size_t k;
263     
264     assert(p);
265     assert(s);
266
267     if ((k = strlen(s)) >= 255)
268         k = 255;
269     
270     if (!(d = avahi_dns_packet_extend(p, k+1)))
271         return NULL;
272
273     *d = (uint8_t) k;
274     memcpy(d+1, s, k);
275
276     return d;
277 }
278
279 uint8_t *avahi_dns_packet_extend(AvahiDnsPacket *p, size_t l) {
280     uint8_t *d;
281     
282     assert(p);
283
284     if (p->size+l > p->max_size)
285         return NULL;
286     
287     d = AVAHI_DNS_PACKET_DATA(p) + p->size;
288     p->size += l;
289     
290     return d;
291 }
292
293 int avahi_dns_packet_check_valid(AvahiDnsPacket *p) {
294     uint16_t flags;
295     assert(p);
296
297     if (p->size < AVAHI_DNS_PACKET_HEADER_SIZE)
298         return -1;
299
300     flags = avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_FLAGS);
301     
302     if (flags & AVAHI_DNS_FLAG_OPCODE)
303         return -1;
304
305     return 0;
306 }
307
308 int avahi_dns_packet_check_valid_multicast(AvahiDnsPacket *p) {
309     uint16_t flags;
310     assert(p);
311
312     if (avahi_dns_packet_check_valid(p) < 0)
313         return -1;
314     
315     flags = avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_FLAGS);
316     
317     if (flags & AVAHI_DNS_FLAG_RCODE)
318         return -1;
319
320     return 0;
321 }
322
323
324 int avahi_dns_packet_is_query(AvahiDnsPacket *p) {
325     assert(p);
326     
327     return !(avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_FLAGS) & AVAHI_DNS_FLAG_QR);
328 }
329
330 static int consume_labels(AvahiDnsPacket *p, unsigned idx, char *ret_name, size_t l) {
331     int ret = 0;
332     int compressed = 0;
333     int first_label = 1;
334     assert(p && ret_name && l);
335     
336     for (;;) {
337         uint8_t n;
338
339         if (idx+1 > p->size)
340             return -1;
341
342         n = AVAHI_DNS_PACKET_DATA(p)[idx];
343
344         if (!n) {
345             idx++;
346             if (!compressed)
347                 ret++;
348
349             if (l < 1)
350                 return -1;
351             *ret_name = 0;
352             
353             return ret;
354             
355         } else if (n <= 63) {
356             /* Uncompressed label */
357             idx++;
358             if (!compressed)
359                 ret++;
360         
361             if (idx + n > p->size)
362                 return -1;
363
364             if ((size_t) n + 1 > l)
365                 return -1;
366
367             if (!first_label) {
368                 *(ret_name++) = '.';
369                 l--;
370             } else
371                 first_label = 0;
372
373             if (!(avahi_escape_label((char*) AVAHI_DNS_PACKET_DATA(p) + idx, n, &ret_name, &l)))
374                 return -1;
375
376             idx += n;
377             
378             if (!compressed)
379                 ret += n;
380         } else if ((n & 0xC0) == 0xC0) {
381             /* Compressed label */
382
383             if (idx+2 > p->size)
384                 return -1;
385
386             idx = ((unsigned) (AVAHI_DNS_PACKET_DATA(p)[idx] & ~0xC0)) << 8 | AVAHI_DNS_PACKET_DATA(p)[idx+1];
387
388             if (!compressed)
389                 ret += 2;
390             
391             compressed = 1;
392         } else
393             return -1;
394     }
395 }
396
397 int avahi_dns_packet_consume_name(AvahiDnsPacket *p, char *ret_name, size_t l) {
398     int r;
399     
400     if ((r = consume_labels(p, p->rindex, ret_name, l)) < 0)
401         return -1;
402
403     p->rindex += r;
404     return 0;
405 }
406
407 int avahi_dns_packet_consume_uint16(AvahiDnsPacket *p, uint16_t *ret_v) {
408     uint8_t *d;
409
410     assert(p);
411     assert(ret_v);
412
413     if (p->rindex + sizeof(uint16_t) > p->size)
414         return -1;
415
416     d = (uint8_t*) (AVAHI_DNS_PACKET_DATA(p) + p->rindex);
417     *ret_v = (d[0] << 8) | d[1];
418     p->rindex += sizeof(uint16_t);
419
420     return 0;
421 }
422
423 int avahi_dns_packet_consume_uint32(AvahiDnsPacket *p, uint32_t *ret_v) {
424     uint8_t* d;
425
426     assert(p);
427     assert(ret_v);
428
429     if (p->rindex + sizeof(uint32_t) > p->size)
430         return -1;
431
432     d = (uint8_t*) (AVAHI_DNS_PACKET_DATA(p) + p->rindex);
433     *ret_v = (d[0] << 24) | (d[1] << 16) | (d[2] << 8) | d[3];
434     p->rindex += sizeof(uint32_t);
435     
436     return 0;
437 }
438
439 int avahi_dns_packet_consume_bytes(AvahiDnsPacket *p, void * ret_data, size_t l) {
440     assert(p);
441     assert(ret_data);
442     assert(l > 0);
443     
444     if (p->rindex + l > p->size)
445         return -1;
446
447     memcpy(ret_data, AVAHI_DNS_PACKET_DATA(p) + p->rindex, l);
448     p->rindex += l;
449
450     return 0;
451 }
452
453 int avahi_dns_packet_consume_string(AvahiDnsPacket *p, char *ret_string, size_t l) {
454     size_t k;
455     
456     assert(p);
457     assert(ret_string);
458     assert(l > 0);
459
460     if (p->rindex >= p->size)
461         return -1;
462
463     k = AVAHI_DNS_PACKET_DATA(p)[p->rindex];
464
465     if (p->rindex+1+k > p->size)
466         return -1;
467
468     if (l > k+1)
469         l = k+1;
470
471     memcpy(ret_string, AVAHI_DNS_PACKET_DATA(p)+p->rindex+1, l-1);
472     ret_string[l-1] = 0;
473     
474     p->rindex += 1+k;
475
476     return 0;
477 }
478
479 const void* avahi_dns_packet_get_rptr(AvahiDnsPacket *p) {
480     assert(p);
481     
482     if (p->rindex > p->size)
483         return NULL;
484
485     return AVAHI_DNS_PACKET_DATA(p) + p->rindex;
486 }
487
488 int avahi_dns_packet_skip(AvahiDnsPacket *p, size_t length) {
489     assert(p);
490
491     if (p->rindex + length > p->size)
492         return -1;
493
494     p->rindex += length;
495     return 0;
496 }
497
498 AvahiRecord* avahi_dns_packet_consume_record(AvahiDnsPacket *p, int *ret_cache_flush) {
499     char name[257], buf[257];
500     uint16_t type, class;
501     uint32_t ttl;
502     uint16_t rdlength;
503     AvahiRecord *r = NULL;
504     const void* start;
505
506     assert(p);
507
508 /*     avahi_log_debug("consume_record()"); */
509
510     if (avahi_dns_packet_consume_name(p, name, sizeof(name)) < 0 ||
511         avahi_dns_packet_consume_uint16(p, &type) < 0 ||
512         avahi_dns_packet_consume_uint16(p, &class) < 0 ||
513         avahi_dns_packet_consume_uint32(p, &ttl) < 0 ||
514         avahi_dns_packet_consume_uint16(p, &rdlength) < 0 ||
515         p->rindex + rdlength > p->size)
516         goto fail;
517
518 /*     avahi_log_debug("name = %s, rdlength = %u", name, rdlength); */
519
520     if (ret_cache_flush)
521         *ret_cache_flush = !!(class & AVAHI_DNS_CACHE_FLUSH);
522     class &= ~AVAHI_DNS_CACHE_FLUSH;
523     
524     start = avahi_dns_packet_get_rptr(p);
525     
526     if (!(r = avahi_record_new_full(name, class, type, ttl)))
527         return NULL;
528     
529     switch (type) {
530         case AVAHI_DNS_TYPE_PTR:
531         case AVAHI_DNS_TYPE_CNAME:
532         case AVAHI_DNS_TYPE_NS:
533
534 /*             avahi_log_debug("ptr"); */
535             
536             if (avahi_dns_packet_consume_name(p, buf, sizeof(buf)) < 0)
537                 goto fail;
538
539             r->data.ptr.name = avahi_strdup(buf);
540             break;
541
542             
543         case AVAHI_DNS_TYPE_SRV:
544
545 /*             avahi_log_debug("srv"); */
546             
547             if (avahi_dns_packet_consume_uint16(p, &r->data.srv.priority) < 0 ||
548                 avahi_dns_packet_consume_uint16(p, &r->data.srv.weight) < 0 ||
549                 avahi_dns_packet_consume_uint16(p, &r->data.srv.port) < 0 ||
550                 avahi_dns_packet_consume_name(p, buf, sizeof(buf)) < 0)
551                 goto fail;
552             
553             r->data.srv.name = avahi_strdup(buf);
554             break;
555
556         case AVAHI_DNS_TYPE_HINFO:
557             
558 /*             avahi_log_debug("hinfo"); */
559
560             if (avahi_dns_packet_consume_string(p, buf, sizeof(buf)) < 0)
561                 goto fail;
562
563             r->data.hinfo.cpu = avahi_strdup(buf);
564
565             if (avahi_dns_packet_consume_string(p, buf, sizeof(buf)) < 0)
566                 goto fail;
567
568             r->data.hinfo.os = avahi_strdup(buf);
569             break;
570
571         case AVAHI_DNS_TYPE_TXT:
572
573 /*             avahi_log_debug("txt"); */
574
575             if (rdlength > 0) {
576                 r->data.txt.string_list = avahi_string_list_parse(avahi_dns_packet_get_rptr(p), rdlength);
577                 
578                 if (avahi_dns_packet_skip(p, rdlength) < 0)
579                     goto fail;
580             } else
581                 r->data.txt.string_list = NULL;
582             
583             break;
584
585         case AVAHI_DNS_TYPE_A:
586
587 /*             avahi_log_debug("A"); */
588
589             if (avahi_dns_packet_consume_bytes(p, &r->data.a.address, sizeof(AvahiIPv4Address)) < 0)
590                 goto fail;
591             
592             break;
593
594         case AVAHI_DNS_TYPE_AAAA:
595
596 /*             avahi_log_debug("aaaa"); */
597             
598             if (avahi_dns_packet_consume_bytes(p, &r->data.aaaa.address, sizeof(AvahiIPv6Address)) < 0)
599                 goto fail;
600             
601             break;
602             
603         default:
604
605 /*             avahi_log_debug("generic"); */
606             
607             if (rdlength > 0) {
608
609                 r->data.generic.data = avahi_memdup(avahi_dns_packet_get_rptr(p), rdlength);
610                 
611                 if (avahi_dns_packet_skip(p, rdlength) < 0)
612                     goto fail;
613             }
614
615             break;
616     }
617
618 /*     avahi_log_debug("%i == %u ?", (uint8_t*) avahi_dns_packet_get_rptr(p) - (uint8_t*) start, rdlength); */
619     
620     /* Check if we read enough data */
621     if ((const uint8_t*) avahi_dns_packet_get_rptr(p) - (const uint8_t*) start != rdlength)
622         goto fail;
623
624     return r;
625
626 fail:
627     if (r)
628         avahi_record_unref(r);
629
630     return NULL;
631 }
632
633 AvahiKey* avahi_dns_packet_consume_key(AvahiDnsPacket *p, int *ret_unicast_response) {
634     char name[256];
635     uint16_t type, class;
636
637     assert(p);
638
639     if (avahi_dns_packet_consume_name(p, name, sizeof(name)) < 0 ||
640         avahi_dns_packet_consume_uint16(p, &type) < 0 ||
641         avahi_dns_packet_consume_uint16(p, &class) < 0)
642         return NULL;
643
644     if (ret_unicast_response)
645         *ret_unicast_response = !!(class & AVAHI_DNS_UNICAST_RESPONSE);
646
647     class &= ~AVAHI_DNS_UNICAST_RESPONSE;
648     
649     return avahi_key_new(name, class, type);
650 }
651
652 uint8_t* avahi_dns_packet_append_key(AvahiDnsPacket *p, AvahiKey *k, int unicast_response) {
653     uint8_t *t;
654     size_t size;
655     
656     assert(p);
657     assert(k);
658
659     size = p->size;
660     
661     if (!(t = avahi_dns_packet_append_name(p, k->name)) ||
662         !avahi_dns_packet_append_uint16(p, k->type) ||
663         !avahi_dns_packet_append_uint16(p, k->clazz | (unicast_response ? AVAHI_DNS_UNICAST_RESPONSE : 0))) {
664         p->size = size;
665         return NULL;
666     }
667
668     return t;
669 }
670
671 uint8_t* avahi_dns_packet_append_record(AvahiDnsPacket *p, AvahiRecord *r, int cache_flush, unsigned max_ttl) {
672     uint8_t *t, *l, *start;
673     size_t size;
674
675     assert(p);
676     assert(r);
677
678     size = p->size;
679
680     if (!(t = avahi_dns_packet_append_name(p, r->key->name)) ||
681         !avahi_dns_packet_append_uint16(p, r->key->type) ||
682         !avahi_dns_packet_append_uint16(p, cache_flush ? (r->key->clazz | AVAHI_DNS_CACHE_FLUSH) : (r->key->clazz &~ AVAHI_DNS_CACHE_FLUSH)) ||
683         !avahi_dns_packet_append_uint32(p, (max_ttl && r->ttl > max_ttl) ? max_ttl : r->ttl) ||
684         !(l = avahi_dns_packet_append_uint16(p, 0)))
685         goto fail;
686
687     start = avahi_dns_packet_extend(p, 0);
688
689     switch (r->key->type) {
690         
691         case AVAHI_DNS_TYPE_PTR:
692         case AVAHI_DNS_TYPE_CNAME:
693         case AVAHI_DNS_TYPE_NS:
694             
695             if (!(avahi_dns_packet_append_name(p, r->data.ptr.name)))
696                 goto fail;
697             
698             break;
699
700         case AVAHI_DNS_TYPE_SRV:
701
702             if (!avahi_dns_packet_append_uint16(p, r->data.srv.priority) ||
703                 !avahi_dns_packet_append_uint16(p, r->data.srv.weight) ||
704                 !avahi_dns_packet_append_uint16(p, r->data.srv.port) ||
705                 !avahi_dns_packet_append_name(p, r->data.srv.name))
706                 goto fail;
707
708             break;
709
710         case AVAHI_DNS_TYPE_HINFO:
711             if (!avahi_dns_packet_append_string(p, r->data.hinfo.cpu) ||
712                 !avahi_dns_packet_append_string(p, r->data.hinfo.os))
713                 goto fail;
714
715             break;
716
717         case AVAHI_DNS_TYPE_TXT: {
718
719             uint8_t *data;
720             size_t n;
721
722             n = avahi_string_list_serialize(r->data.txt.string_list, NULL, 0);
723
724 /*             avahi_log_debug("appending string: %u %p", n, r->data.txt.string_list); */
725
726             if (!(data = avahi_dns_packet_extend(p, n)))
727                 goto fail;
728
729             avahi_string_list_serialize(r->data.txt.string_list, data, n);
730             break;
731         }
732
733
734         case AVAHI_DNS_TYPE_A:
735
736             if (!avahi_dns_packet_append_bytes(p, &r->data.a.address, sizeof(r->data.a.address)))
737                 goto fail;
738             
739             break;
740
741         case AVAHI_DNS_TYPE_AAAA:
742             
743             if (!avahi_dns_packet_append_bytes(p, &r->data.aaaa.address, sizeof(r->data.aaaa.address)))
744                 goto fail;
745             
746             break;
747             
748         default:
749
750             if (r->data.generic.size &&
751                 avahi_dns_packet_append_bytes(p, r->data.generic.data, r->data.generic.size))
752                 goto fail;
753
754             break;
755     }
756
757
758
759     
760     size = avahi_dns_packet_extend(p, 0) - start;
761     assert(size <= 0xFFFF);
762
763 /*     avahi_log_debug("appended %u", size); */
764
765     l[0] = (uint8_t) ((uint16_t) size >> 8);
766     l[1] = (uint8_t) ((uint16_t) size);
767     
768     return t;
769
770
771 fail:
772     p->size = size;
773     return NULL;
774 }
775
776 int avahi_dns_packet_is_empty(AvahiDnsPacket *p) {
777     assert(p);
778
779     return p->size <= AVAHI_DNS_PACKET_HEADER_SIZE;
780 }
781
782 size_t avahi_dns_packet_space(AvahiDnsPacket *p) {
783     assert(p);
784
785     assert(p->size <= p->max_size);
786     
787     return p->max_size - p->size;
788 }