Home | History | Annotate | Download | only in avahi-common
      1 /***
      2   This file is part of avahi.
      3 
      4   avahi is free software; you can redistribute it and/or modify it
      5   under the terms of the GNU Lesser General Public License as
      6   published by the Free Software Foundation; either version 2.1 of the
      7   License, or (at your option) any later version.
      8 
      9   avahi is distributed in the hope that it will be useful, but WITHOUT
     10   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
     11   or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
     12   Public License for more details.
     13 
     14   You should have received a copy of the GNU Lesser General Public
     15   License along with avahi; if not, write to the Free Software
     16   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
     17   USA.
     18 ***/
     19 
     20 #ifdef HAVE_CONFIG_H
     21 #include <config.h>
     22 #endif
     23 
     24 #include <string.h>
     25 #include <stdarg.h>
     26 #include <assert.h>
     27 #include <stdio.h>
     28 #include <stdlib.h>
     29 
     30 #include "strlst.h"
     31 #include "avahi-malloc.h"
     32 #include "defs.h"
     33 
     34 AvahiStringList*avahi_string_list_add_anonymous(AvahiStringList *l, size_t size) {
     35     AvahiStringList *n;
     36 
     37     if (!(n = avahi_malloc(sizeof(AvahiStringList) + size)))
     38         return NULL;
     39 
     40     n->next = l;
     41     n->size = size;
     42 
     43     /* NUL terminate strings, just to make sure */
     44     n->text[size] = 0;
     45 
     46     return n;
     47 }
     48 
     49 AvahiStringList *avahi_string_list_add_arbitrary(AvahiStringList *l, const uint8_t*text, size_t size) {
     50     AvahiStringList *n;
     51 
     52     assert(size == 0 || text);
     53 
     54     if (!(n = avahi_string_list_add_anonymous(l, size)))
     55         return NULL;
     56 
     57     if (size > 0)
     58         memcpy(n->text, text, size);
     59 
     60     return n;
     61 }
     62 
     63 AvahiStringList *avahi_string_list_add(AvahiStringList *l, const char *text) {
     64     assert(text);
     65 
     66     return avahi_string_list_add_arbitrary(l, (const uint8_t*) text, strlen(text));
     67 }
     68 
     69 int avahi_string_list_parse(const void* data, size_t size, AvahiStringList **ret) {
     70     const uint8_t *c;
     71     AvahiStringList *r = NULL;
     72 
     73     assert(data);
     74     assert(ret);
     75 
     76     c = data;
     77     while (size > 0) {
     78         size_t k;
     79 
     80         k = *(c++);
     81         size--;
     82 
     83         if (k > size)
     84             goto fail; /* Overflow */
     85 
     86         if (k > 0) { /* Ignore empty strings */
     87             AvahiStringList *n;
     88 
     89             if (!(n = avahi_string_list_add_arbitrary(r, c, k)))
     90                 goto fail; /* OOM */
     91 
     92             r = n;
     93         }
     94 
     95         c += k;
     96         size -= k;
     97     }
     98 
     99     *ret = r;
    100 
    101     return 0;
    102 
    103 fail:
    104     avahi_string_list_free(r);
    105     return -1;
    106 }
    107 
    108 void avahi_string_list_free(AvahiStringList *l) {
    109     AvahiStringList *n;
    110 
    111     while (l) {
    112         n = l->next;
    113         avahi_free(l);
    114         l = n;
    115     }
    116 }
    117 
    118 AvahiStringList* avahi_string_list_reverse(AvahiStringList *l) {
    119     AvahiStringList *r = NULL, *n;
    120 
    121     while (l) {
    122         n = l->next;
    123         l->next = r;
    124         r = l;
    125         l = n;
    126     }
    127 
    128     return r;
    129 }
    130 
    131 char* avahi_string_list_to_string(AvahiStringList *l) {
    132     AvahiStringList *n;
    133     size_t s = 0;
    134     char *t, *e;
    135 
    136     for (n = l; n; n = n->next) {
    137         if (n != l)
    138             s ++;
    139 
    140         s += n->size+2;
    141     }
    142 
    143     if (!(t = e = avahi_new(char, s+1)))
    144         return NULL;
    145 
    146     l = avahi_string_list_reverse(l);
    147 
    148     for (n = l; n; n = n->next) {
    149         if (n != l)
    150             *(e++) = ' ';
    151 
    152         *(e++) = '"';
    153         strncpy(e, (char*) n->text, n->size);
    154         e[n->size] = 0;
    155         e = strchr(e, 0);
    156         *(e++) = '"';
    157 
    158         assert(e);
    159     }
    160 
    161     l = avahi_string_list_reverse(l);
    162 
    163     *e = 0;
    164 
    165     return t;
    166 }
    167 
    168 size_t avahi_string_list_serialize(AvahiStringList *l, void *data, size_t size) {
    169     size_t used = 0;
    170 
    171     if (data) {
    172         AvahiStringList *n;
    173         uint8_t *c;
    174 
    175         l = avahi_string_list_reverse(l);
    176         c = data;
    177 
    178         for (n = l; size > 1 && n; n = n->next) {
    179             size_t k;
    180 
    181             if ((k = n->size) == 0)
    182                 /* Skip empty strings */
    183                 continue;
    184 
    185             if (k > 255)
    186                 /* Truncate strings at 255 characters */
    187                 k = 255;
    188 
    189             if (k > size-1)
    190                 /* Make sure this string fits in */
    191                 k = size-1;
    192 
    193             *(c++) = (uint8_t) k;
    194             memcpy(c, n->text, k);
    195             c += k;
    196 
    197             used += 1 + k;
    198             size -= 1 + k;
    199         }
    200 
    201         l = avahi_string_list_reverse(l);
    202 
    203         if (used == 0 && size > 0) {
    204 
    205             /* Empty lists are treated specially. To comply with
    206              * section 6.1 of the DNS-SD spec, we return a single
    207              * empty string (i.e. a NUL byte)*/
    208 
    209             *(uint8_t*) data = 0;
    210             used = 1;
    211         }
    212 
    213     } else {
    214         AvahiStringList *n;
    215 
    216         for (n = l; n; n = n->next) {
    217             size_t k;
    218 
    219             if ((k = n->size) == 0)
    220                 continue;
    221 
    222             if (k > 255)
    223                 k = 255;
    224 
    225             used += 1+k;
    226         }
    227 
    228         if (used == 0)
    229             used = 1;
    230     }
    231 
    232     return used;
    233 }
    234 
    235 int avahi_string_list_equal(const AvahiStringList *a, const AvahiStringList *b) {
    236 
    237     for (;;) {
    238         if (!a && !b)
    239             return 1;
    240 
    241         if (!a || !b)
    242             return 0;
    243 
    244         if (a->size != b->size)
    245             return 0;
    246 
    247         if (a->size != 0 && memcmp(a->text, b->text, a->size) != 0)
    248             return 0;
    249 
    250         a = a->next;
    251         b = b->next;
    252     }
    253 }
    254 
    255 AvahiStringList *avahi_string_list_add_many(AvahiStringList *r, ...) {
    256     va_list va;
    257 
    258     va_start(va, r);
    259     r = avahi_string_list_add_many_va(r, va);
    260     va_end(va);
    261 
    262     return r;
    263 }
    264 
    265 AvahiStringList *avahi_string_list_add_many_va(AvahiStringList *r, va_list va) {
    266     const char *txt;
    267 
    268     while ((txt = va_arg(va, const char*)))
    269         r = avahi_string_list_add(r, txt);
    270 
    271     return r;
    272 }
    273 
    274 AvahiStringList *avahi_string_list_new(const char *txt, ...) {
    275     va_list va;
    276     AvahiStringList *r = NULL;
    277 
    278     if (txt) {
    279         r = avahi_string_list_add(r, txt);
    280 
    281         va_start(va, txt);
    282         r = avahi_string_list_add_many_va(r, va);
    283         va_end(va);
    284     }
    285 
    286     return r;
    287 }
    288 
    289 AvahiStringList *avahi_string_list_new_va(va_list va) {
    290     return avahi_string_list_add_many_va(NULL, va);
    291 }
    292 
    293 AvahiStringList *avahi_string_list_copy(const AvahiStringList *l) {
    294     AvahiStringList *r = NULL;
    295 
    296     for (; l; l = l->next)
    297         if (!(r = avahi_string_list_add_arbitrary(r, l->text, l->size))) {
    298             avahi_string_list_free(r);
    299             return NULL;
    300         }
    301 
    302     return avahi_string_list_reverse(r);
    303 }
    304 
    305 AvahiStringList *avahi_string_list_new_from_array(const char *array[], int length) {
    306     AvahiStringList *r = NULL;
    307     int i;
    308 
    309     assert(array);
    310 
    311     for (i = 0; length >= 0 ? i < length : !!array[i]; i++)
    312         r = avahi_string_list_add(r, array[i]);
    313 
    314     return r;
    315 }
    316 
    317 unsigned avahi_string_list_length(const AvahiStringList *l) {
    318     unsigned n = 0;
    319 
    320     for (; l; l = l->next)
    321         n++;
    322 
    323     return n;
    324 }
    325 
    326 AvahiStringList *avahi_string_list_add_vprintf(AvahiStringList *l, const char *format, va_list va) {
    327     size_t len = 80;
    328     AvahiStringList *r;
    329 
    330     assert(format);
    331 
    332     if (!(r = avahi_malloc(sizeof(AvahiStringList) + len)))
    333         return NULL;
    334 
    335     for (;;) {
    336         int n;
    337         AvahiStringList *nr;
    338         va_list va2;
    339 
    340         va_copy(va2, va);
    341         n = vsnprintf((char*) r->text, len, format, va2);
    342         va_end(va2);
    343 
    344         if (n >= 0 && n < (int) len)
    345             break;
    346 
    347         if (n >= 0)
    348             len = n+1;
    349         else
    350             len *= 2;
    351 
    352         if (!(nr = avahi_realloc(r, sizeof(AvahiStringList) + len))) {
    353             avahi_free(r);
    354             return NULL;
    355         }
    356 
    357         r = nr;
    358     }
    359 
    360     r->next = l;
    361     r->size = strlen((char*) r->text);
    362 
    363     return r;
    364 }
    365 
    366 AvahiStringList *avahi_string_list_add_printf(AvahiStringList *l, const char *format, ...) {
    367     va_list va;
    368 
    369     assert(format);
    370 
    371     va_start(va, format);
    372     l  = avahi_string_list_add_vprintf(l, format, va);
    373     va_end(va);
    374 
    375     return l;
    376 }
    377 
    378 AvahiStringList *avahi_string_list_find(AvahiStringList *l, const char *key) {
    379     size_t n;
    380 
    381     assert(key);
    382     n = strlen(key);
    383 
    384     for (; l; l = l->next) {
    385         if (strcasecmp((char*) l->text, key) == 0)
    386             return l;
    387 
    388         if (strncasecmp((char*) l->text, key, n) == 0 && l->text[n] == '=')
    389             return l;
    390     }
    391 
    392     return NULL;
    393 }
    394 
    395 AvahiStringList *avahi_string_list_add_pair(AvahiStringList *l, const char *key, const char *value) {
    396     assert(key);
    397 
    398     if (value)
    399         return avahi_string_list_add_printf(l, "%s=%s", key, value);
    400     else
    401         return avahi_string_list_add(l, key);
    402 }
    403 
    404 AvahiStringList *avahi_string_list_add_pair_arbitrary(AvahiStringList *l, const char *key, const uint8_t *value, size_t size) {
    405     size_t n;
    406     assert(key);
    407 
    408     if (!value)
    409         return avahi_string_list_add(l, key);
    410 
    411     n = strlen(key);
    412 
    413     if (!(l = avahi_string_list_add_anonymous(l, n + 1 + size)))
    414         return NULL;
    415 
    416     memcpy(l->text, key, n);
    417     l->text[n] = '=';
    418     memcpy(l->text + n + 1, value, size);
    419 
    420     return l;
    421 }
    422 
    423 int avahi_string_list_get_pair(AvahiStringList *l, char **key, char **value, size_t *size) {
    424     char *e;
    425 
    426     assert(l);
    427 
    428     if (!(e = memchr(l->text, '=', l->size))) {
    429 
    430         if (key)
    431             if (!(*key = avahi_strdup((char*) l->text)))
    432                 return -1;
    433 
    434         if (value)
    435             *value = NULL;
    436 
    437         if (size)
    438             *size = 0;
    439 
    440     } else {
    441         size_t n;
    442 
    443         if (key)
    444             if (!(*key = avahi_strndup((char*) l->text, e - (char *) l->text)))
    445                 return -1;
    446 
    447         e++; /* Advance after '=' */
    448 
    449         n = l->size - (e - (char*) l->text);
    450 
    451         if (value) {
    452 
    453             if (!(*value = avahi_memdup(e, n+1))) {
    454                 if (key)
    455                     avahi_free(*key);
    456                 return -1;
    457             }
    458 
    459             (*value)[n] = 0;
    460         }
    461 
    462         if (size)
    463             *size = n;
    464     }
    465 
    466     return 0;
    467 }
    468 
    469 AvahiStringList *avahi_string_list_get_next(AvahiStringList *l) {
    470     assert(l);
    471     return l->next;
    472 }
    473 
    474 uint8_t *avahi_string_list_get_text(AvahiStringList *l) {
    475     assert(l);
    476     return l->text;
    477 }
    478 
    479 size_t avahi_string_list_get_size(AvahiStringList *l) {
    480     assert(l);
    481     return l->size;
    482 }
    483 
    484 uint32_t avahi_string_list_get_service_cookie(AvahiStringList *l) {
    485     AvahiStringList *f;
    486     char *value = NULL, *end = NULL;
    487     uint32_t ret;
    488 
    489     if (!(f = avahi_string_list_find(l, AVAHI_SERVICE_COOKIE)))
    490         return AVAHI_SERVICE_COOKIE_INVALID;
    491 
    492     if (avahi_string_list_get_pair(f, NULL, &value, NULL) < 0 || !value)
    493         return AVAHI_SERVICE_COOKIE_INVALID;
    494 
    495     ret = (uint32_t) strtoll(value, &end, 0);
    496 
    497     if (*value && end && *end != 0) {
    498         avahi_free(value);
    499         return AVAHI_SERVICE_COOKIE_INVALID;
    500     }
    501 
    502     avahi_free(value);
    503 
    504     return ret;
    505 }
    506