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