#include <stdarg.h>
#include <assert.h>
#include <stdio.h>
+#include <stdlib.h>
#include "strlst.h"
#include "malloc.h"
+#include "defs.h"
AvahiStringList*avahi_string_list_add_anonymous(AvahiStringList *l, size_t size) {
AvahiStringList *n;
AvahiStringList *avahi_string_list_add_arbitrary(AvahiStringList *l, const uint8_t*text, size_t size) {
AvahiStringList *n;
- assert(text);
+ assert(size == 0 || text);
if (!(n = avahi_string_list_add_anonymous(l, size)))
return NULL;
return avahi_string_list_add_arbitrary(l, (const uint8_t*) text, strlen(text));
}
-AvahiStringList *avahi_string_list_parse(const void* data, size_t size) {
- AvahiStringList *r = NULL;
+int avahi_string_list_parse(const void* data, size_t size, AvahiStringList **ret) {
const uint8_t *c;
+ AvahiStringList *r = NULL;
assert(data);
+ assert(ret);
c = data;
- for (;;) {
+ while (size > 0) {
size_t k;
- if (size < 1)
- break;
-
k = *(c++);
- r = avahi_string_list_add_arbitrary(r, c, k);
- c += k;
+ size--;
+
+ if (k > size)
+ goto fail; /* Overflow */
- size -= 1 + k;
+ if (k > 0) { /* Ignore empty strings */
+ AvahiStringList *n;
+
+ if (!(n = avahi_string_list_add_arbitrary(r, c, k)))
+ goto fail; /* OOM */
+
+ r = n;
+ }
+
+ c += k;
+ size -= k;
}
- return r;
+ *ret = r;
+
+ return 0;
+
+fail:
+ avahi_string_list_free(r);
+ return -1;
}
void avahi_string_list_free(AvahiStringList *l) {
size_t used = 0;
if (data) {
- uint8_t *c;
AvahiStringList *n;
-
- assert(data);
-
+ uint8_t *c;
+
l = avahi_string_list_reverse(l);
c = data;
- for (n = l; n; n = n->next) {
+ for (n = l; size > 1 && n; n = n->next) {
size_t k;
- if (size < 1)
- break;
+
+ if ((k = n->size) == 0)
+ /* Skip empty strings */
+ continue;
- k = n->size;
if (k > 255)
+ /* Truncate strings at 255 characters */
k = 255;
if (k > size-1)
+ /* Make sure this string fits in */
k = size-1;
-
- *(c++) = k;
+
+ *(c++) = (uint8_t) k;
memcpy(c, n->text, k);
c += k;
- used += 1+ k;
+ used += 1 + k;
+ size -= 1 + k;
}
l = avahi_string_list_reverse(l);
+
+ if (used == 0 && size > 0) {
+
+ /* Empty lists are treated specially. To comply with
+ * section 6.1 of the DNS-SD spec, we return a single
+ * empty string (i.e. a NUL byte)*/
+
+ *(uint8_t*) data = 0;
+ used = 1;
+ }
+
} else {
AvahiStringList *n;
for (n = l; n; n = n->next) {
size_t k;
-
- k = n->size;
+
+ if ((k = n->size) == 0)
+ continue;
+
if (k > 255)
k = 255;
used += 1+k;
}
+
+ if (used == 0)
+ used = 1;
}
return used;
AvahiStringList *r = NULL;
for (; l; l = l->next)
- r = avahi_string_list_add_arbitrary(r, l->text, l->size);
+ if (!(r = avahi_string_list_add_arbitrary(r, l->text, l->size))) {
+ avahi_string_list_free(r);
+ return NULL;
+ }
return avahi_string_list_reverse(r);
}
for (;;) {
int n;
AvahiStringList *nr;
+ va_list va2;
- n = vsnprintf((char*) r->text, len+1, format, va);
+ va_copy(va2, va);
+ n = vsnprintf((char*) r->text, len, format, va2);
+ va_end(va2);
if (n >= 0 && n < (int) len)
break;
r = nr;
}
-
r->next = l;
r->size = strlen((char*) r->text);
return l;
}
-
int avahi_string_list_get_pair(AvahiStringList *l, char **key, char **value, size_t *size) {
char *e;
assert(l);
- assert(key);
if (!(e = memchr(l->text, '=', l->size))) {
-
- if (!(*key = avahi_strdup((char*) l->text)))
- return -1;
+
+ if (key)
+ if (!(*key = avahi_strdup((char*) l->text)))
+ return -1;
if (value)
*value = NULL;
} else {
size_t n;
- if (!(*key = avahi_strndup((char*) l->text, e - (char *) l->text)))
- return -1;
+ if (key)
+ if (!(*key = avahi_strndup((char*) l->text, e - (char *) l->text)))
+ return -1;
e++; /* Advance after '=' */
if (value) {
if (!(*value = avahi_memdup(e, n+1))) {
- avahi_free(*key);
+ if (key)
+ avahi_free(*key);
return -1;
}
return 0;
}
+
+AvahiStringList *avahi_string_list_get_next(AvahiStringList *l) {
+ assert(l);
+ return l->next;
+}
+
+uint8_t *avahi_string_list_get_text(AvahiStringList *l) {
+ assert(l);
+ return l->text;
+}
+
+size_t avahi_string_list_get_size(AvahiStringList *l) {
+ assert(l);
+ return l->size;
+}
+
+uint32_t avahi_string_list_get_service_cookie(AvahiStringList *l) {
+ AvahiStringList *f;
+ char *value = NULL, *end = NULL;
+ uint32_t ret;
+
+ if (!(f = avahi_string_list_find(l, AVAHI_SERVICE_COOKIE)))
+ return AVAHI_SERVICE_COOKIE_INVALID;
+
+ if (avahi_string_list_get_pair(f, NULL, &value, NULL) < 0 || !value)
+ return AVAHI_SERVICE_COOKIE_INVALID;
+
+ ret = (uint32_t) strtoll(value, &end, 0);
+
+ if (*value && end && *end != 0) {
+ avahi_free(value);
+ return AVAHI_SERVICE_COOKIE_INVALID;
+ }
+
+ avahi_free(value);
+
+ return ret;
+}