• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-WNDR4500v2-V1.0.0.60_1.0.38/ap/gpl/timemachine/avahi-0.6.25/avahi-compat-libdns_sd/
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 <sys/types.h>
28#include <assert.h>
29#include <string.h>
30
31#include <avahi-common/malloc.h>
32
33#include "dns_sd.h"
34#include "warn.h"
35
36typedef struct TXTRecordInternal {
37    uint8_t *buffer, *malloc_buffer;
38    size_t size, max_size;
39} TXTRecordInternal;
40
41#define INTERNAL_PTR(txtref) (* (TXTRecordInternal**) (txtref))
42#define INTERNAL_PTR_CONST(txtref) (* (const TXTRecordInternal* const *) (txtref))
43
44void DNSSD_API TXTRecordCreate(
45    TXTRecordRef *txtref,
46    uint16_t length,
47    void *buffer) {
48
49    TXTRecordInternal *t;
50
51    AVAHI_WARN_LINKAGE;
52
53    assert(txtref);
54
55    /* Apple's API design is flawed in so many ways, including the
56     * fact that it isn't compatible with 64 bit processors. To work
57     * around this we need some magic here which involves allocating
58     * our own memory. Please, Apple, do your homework next time
59     * before designing an API! */
60
61    if ((t = avahi_new(TXTRecordInternal, 1))) {
62        t->buffer = buffer;
63        t->max_size = buffer ? length : (size_t)0;
64        t->size = 0;
65        t->malloc_buffer = NULL;
66    }
67
68    /* If we were unable to allocate memory, we store a NULL pointer
69     * and return a NoMemory error later, is somewhat unclean, but
70     * should work. */
71    INTERNAL_PTR(txtref) = t;
72}
73
74void DNSSD_API TXTRecordDeallocate(TXTRecordRef *txtref) {
75    TXTRecordInternal *t;
76
77    AVAHI_WARN_LINKAGE;
78
79    assert(txtref);
80    t = INTERNAL_PTR(txtref);
81    if (!t)
82        return;
83
84    avahi_free(t->malloc_buffer);
85    avahi_free(t);
86
87    /* Just in case ... */
88    INTERNAL_PTR(txtref) = NULL;
89}
90
91static int make_sure_fits_in(TXTRecordInternal *t, size_t size) {
92    uint8_t *n;
93    size_t nsize;
94
95    assert(t);
96
97    if (t->size + size <= t->max_size)
98        return 0;
99
100    nsize = t->size + size + 100;
101
102    if (nsize > 0xFFFF)
103        return -1;
104
105    if (!(n = avahi_realloc(t->malloc_buffer, nsize)))
106        return -1;
107
108    if (!t->malloc_buffer && t->size)
109        memcpy(n, t->buffer, t->size);
110
111    t->buffer = t->malloc_buffer = n;
112    t->max_size = nsize;
113
114    return 0;
115}
116
117static int remove_key(TXTRecordInternal *t, const char *key) {
118    size_t i;
119    uint8_t *p;
120    size_t key_len;
121    int found = 0;
122
123    key_len = strlen(key);
124    assert(key_len <= 0xFF);
125
126    p = t->buffer;
127    i = 0;
128
129    while (i < t->size) {
130
131        /* Does the item fit in? */
132        assert(*p <= t->size - i - 1);
133
134        /* Key longer than buffer */
135        if (key_len > t->size - i - 1)
136            break;
137
138        if (key_len <= *p &&
139            strncmp(key, (char*) p+1, key_len) == 0 &&
140            (key_len == *p || p[1+key_len] == '=')) {
141
142            uint8_t s;
143
144            /* Key matches, so let's remove it */
145
146            s = *p;
147            memmove(p, p + 1 + *p, t->size - i - *p -1);
148            t->size -= s + 1;
149
150            found = 1;
151        } else {
152            /* Skip to next */
153
154            i += *p +1;
155            p += *p +1;
156        }
157    }
158
159    return found;
160}
161
162DNSServiceErrorType DNSSD_API TXTRecordSetValue(
163    TXTRecordRef *txtref,
164    const char *key,
165    uint8_t length,
166    const void *value) {
167
168    TXTRecordInternal *t;
169    uint8_t *p;
170    size_t l, n;
171
172    AVAHI_WARN_LINKAGE;
173
174    assert(key);
175    assert(txtref);
176
177    l = strlen(key);
178
179    if (*key == 0 || strchr(key, '=') || l > 0xFF) /* Empty or invalid key */
180        return kDNSServiceErr_Invalid;
181
182    if (!(t = INTERNAL_PTR(txtref)))
183        return kDNSServiceErr_NoMemory;
184
185    n = l + (value ? length + 1 : 0);
186
187    if (n > 0xFF)
188        return kDNSServiceErr_Invalid;
189
190    if (make_sure_fits_in(t, 1 + n) < 0)
191        return kDNSServiceErr_NoMemory;
192
193    remove_key(t, key);
194
195    p = t->buffer + t->size;
196
197    *(p++) = (uint8_t) n;
198    t->size ++;
199
200    memcpy(p, key, l);
201    p += l;
202    t->size += l;
203
204    if (value) {
205        *(p++) = '=';
206        memcpy(p, value, length);
207        t->size += length + 1;
208    }
209
210    assert(t->size <= t->max_size);
211
212    return kDNSServiceErr_NoError;
213}
214
215DNSServiceErrorType DNSSD_API TXTRecordRemoveValue(TXTRecordRef *txtref, const char *key) {
216    TXTRecordInternal *t;
217    int found;
218
219    AVAHI_WARN_LINKAGE;
220
221    assert(key);
222    assert(txtref);
223
224    if (*key == 0 || strchr(key, '=') || strlen(key) > 0xFF) /* Empty or invalid key */
225        return kDNSServiceErr_Invalid;
226
227    if (!(t = INTERNAL_PTR(txtref)))
228        return kDNSServiceErr_NoError;
229
230    found = remove_key(t, key);
231
232    return found ? kDNSServiceErr_NoError : kDNSServiceErr_NoSuchKey;
233}
234
235uint16_t DNSSD_API TXTRecordGetLength(const TXTRecordRef *txtref) {
236    const TXTRecordInternal *t;
237
238    AVAHI_WARN_LINKAGE;
239
240    assert(txtref);
241
242    if (!(t = INTERNAL_PTR_CONST(txtref)))
243        return 0;
244
245    assert(t->size <= 0xFFFF);
246    return (uint16_t) t->size;
247}
248
249const void * DNSSD_API TXTRecordGetBytesPtr(const TXTRecordRef *txtref) {
250    const TXTRecordInternal *t;
251
252    AVAHI_WARN_LINKAGE;
253
254    assert(txtref);
255
256    if (!(t = INTERNAL_PTR_CONST(txtref)) || !t->buffer)
257        return "";
258
259    return t->buffer;
260}
261
262static const uint8_t *find_key(const uint8_t *buffer, size_t size, const char *key) {
263    size_t i;
264    const uint8_t *p;
265    size_t key_len;
266
267    key_len = strlen(key);
268
269    assert(key_len <= 0xFF);
270
271    p = buffer;
272    i = 0;
273
274    while (i < size) {
275
276        /* Does the item fit in? */
277        if (*p > size - i - 1)
278            return NULL;
279
280        /* Key longer than buffer */
281        if (key_len > size - i - 1)
282            return NULL;
283
284        if (key_len <= *p &&
285            strncmp(key, (const char*) p+1, key_len) == 0 &&
286            (key_len == *p || p[1+key_len] == '=')) {
287
288            /* Key matches, so let's return it */
289
290            return p;
291        }
292
293        /* Skip to next */
294        i += *p +1;
295        p += *p +1;
296    }
297
298    return NULL;
299}
300
301int DNSSD_API TXTRecordContainsKey (
302    uint16_t size,
303    const void *buffer,
304    const char *key) {
305
306    AVAHI_WARN_LINKAGE;
307
308    assert(key);
309
310    if (!size)
311        return 0;
312
313    assert(buffer);
314
315    if (!(find_key(buffer, size, key)))
316        return 0;
317
318    return 1;
319}
320
321const void * DNSSD_API TXTRecordGetValuePtr(
322    uint16_t size,
323    const void *buffer,
324    const char *key,
325    uint8_t *value_len) {
326
327    const uint8_t *p;
328    size_t n, l;
329
330    AVAHI_WARN_LINKAGE;
331
332    assert(key);
333
334    if (!size)
335        goto fail;
336
337    if (*key == 0 || strchr(key, '=') || strlen(key) > 0xFF) /* Empty or invalid key */
338        return NULL;
339
340    assert(buffer);
341
342    if (!(p = find_key(buffer, size, key)))
343        goto fail;
344
345    n = *p;
346    l = strlen(key);
347
348    assert(n >= l);
349    p += 1 + l;
350    n -= l;
351
352    if (n <= 0)
353        goto fail;
354
355    assert(*p == '=');
356    p++;
357    n--;
358
359    if (value_len)
360        *value_len = n;
361
362    return p;
363
364fail:
365    if (value_len)
366        *value_len = 0;
367
368    return NULL;
369}
370
371
372uint16_t DNSSD_API TXTRecordGetCount(
373    uint16_t size,
374    const void *buffer) {
375
376    const uint8_t *p;
377    unsigned n = 0;
378    size_t i;
379
380    AVAHI_WARN_LINKAGE;
381
382    if (!size)
383        return 0;
384
385    assert(buffer);
386
387    p = buffer;
388    i = 0;
389
390    while (i < size) {
391
392        /* Does the item fit in? */
393        if (*p > size - i - 1)
394            break;
395
396        n++;
397
398        /* Skip to next */
399        i += *p +1;
400        p += *p +1;
401    }
402
403    assert(n <= 0xFFFF);
404
405    return (uint16_t) n;
406}
407
408DNSServiceErrorType DNSSD_API TXTRecordGetItemAtIndex(
409    uint16_t size,
410    const void *buffer,
411    uint16_t idx,
412    uint16_t key_len,
413    char *key,
414    uint8_t *value_len,
415    const void **value) {
416
417    const uint8_t *p;
418    size_t i;
419    unsigned n = 0;
420    DNSServiceErrorType ret = kDNSServiceErr_Invalid;
421
422    AVAHI_WARN_LINKAGE;
423
424    if (!size)
425        goto fail;
426
427    assert(buffer);
428
429    p = buffer;
430    i = 0;
431
432    while (i < size) {
433
434        /* Does the item fit in? */
435        if (*p > size - i - 1)
436            goto fail;
437
438        if (n >= idx) {
439            size_t l;
440            const uint8_t *d;
441
442            d = memchr(p+1, '=', *p);
443
444            /* Length of key */
445            l = d ? d - p - 1 : *p;
446
447            if (key_len < l+1) {
448                ret = kDNSServiceErr_NoMemory;
449                goto fail;
450            }
451
452            strncpy(key, (const char*) p + 1, l);
453            key[l] = 0;
454
455            if (d) {
456                if (value_len)
457                    *value_len = *p - l - 1;
458
459                if (value)
460                    *value = d + 1;
461            } else {
462
463                if (value_len)
464                    *value_len  = 0;
465
466                if (value)
467                    *value = NULL;
468            }
469
470            return kDNSServiceErr_NoError;
471        }
472
473        n++;
474
475        /* Skip to next */
476        i += *p +1;
477        p += *p +1;
478    }
479
480
481fail:
482
483    if (value)
484        *value = NULL;
485
486    if (value_len)
487        *value_len = 0;
488
489    return ret;
490
491}
492