From c26e445b409215cd2fa380c8ba8e6c8f6115aec5 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 4 Oct 2005 19:22:29 +0000 Subject: final rename git-svn-id: file:///home/lennart/svn/public/avahi/trunk@698 941a03a8-eaeb-0310-b9a0-b1bbd8fe43fe --- avahi-compat-libdns_sd/txt.c | 491 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 491 insertions(+) create mode 100644 avahi-compat-libdns_sd/txt.c (limited to 'avahi-compat-libdns_sd/txt.c') diff --git a/avahi-compat-libdns_sd/txt.c b/avahi-compat-libdns_sd/txt.c new file mode 100644 index 0000000..c85837a --- /dev/null +++ b/avahi-compat-libdns_sd/txt.c @@ -0,0 +1,491 @@ +/* $Id$ */ + +/*** + This file is part of avahi. + + avahi is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + avahi is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General + Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with avahi; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include + +#include "dns_sd.h" +#include "warn.h" + +typedef struct TXTRecordInternal { + uint8_t *buffer, *malloc_buffer; + size_t size, max_size; +} TXTRecordInternal; + +#define INTERNAL_PTR(txtref) (* (TXTRecordInternal**) (txtref)) +#define INTERNAL_PTR_CONST(txtref) (* (const TXTRecordInternal* const *) (txtref)) + +void DNSSD_API TXTRecordCreate( + TXTRecordRef *txtref, + uint16_t length, + void *buffer) { + + TXTRecordInternal *t; + + AVAHI_WARN_LINKAGE; + + assert(txtref); + + /* Apple's API design is flawed in so many ways, including the + * fact that it isn't compatible with 64 bit processors. To work + * around this we need some magic here which involves allocating + * our own memory. Please, Apple, do your homework next time + * before designing an API! */ + + if ((t = avahi_new(TXTRecordInternal, 1))) { + t->buffer = buffer; + t->max_size = length; + t->size = 0; + t->malloc_buffer = NULL; + } + + /* If we were unable to allocate memory, we store a NULL pointer + * and return a NoMemory error later, is somewhat unclean, but + * should work. */ + INTERNAL_PTR(txtref) = t; +} + +void DNSSD_API TXTRecordDeallocate(TXTRecordRef *txtref) { + TXTRecordInternal *t; + + AVAHI_WARN_LINKAGE; + + assert(txtref); + t = INTERNAL_PTR(txtref); + if (!t) + return; + + avahi_free(t->malloc_buffer); + avahi_free(t); + + /* Just in case ... */ + INTERNAL_PTR(txtref) = NULL; +} + +static int make_sure_fits_in(TXTRecordInternal *t, size_t size) { + uint8_t *n; + size_t nsize; + + assert(t); + + if (t->size + size <= t->max_size) + return 0; + + nsize = t->size + size + 100; + + if (nsize > 0xFFFF) + return -1; + + if (!(n = avahi_realloc(t->malloc_buffer, nsize))) + return -1; + + if (!t->malloc_buffer && t->size) + memcpy(n, t->buffer, t->size); + + t->buffer = t->malloc_buffer = n; + t->max_size = nsize; + + return 0; +} + +static int remove_key(TXTRecordInternal *t, const char *key) { + size_t i; + uint8_t *p; + size_t key_len; + int found = 0; + + key_len = strlen(key); + assert(key_len <= 0xFF); + + p = t->buffer; + i = 0; + + while (i < t->size) { + + /* Does the item fit in? */ + assert(*p <= t->size - i - 1); + + /* Key longer than buffer */ + if (key_len > t->size - i - 1) + break; + + if (key_len <= *p && + strncmp(key, (char*) p+1, key_len) == 0 && + (key_len == *p || p[1+key_len] == '=')) { + + uint8_t s; + + /* Key matches, so let's remove it */ + + s = *p; + memmove(p, p + 1 + *p, t->size - i - *p -1); + t->size -= s + 1; + + found = 1; + } else { + /* Skip to next */ + + i += *p +1; + p += *p +1; + } + } + + return found; +} + +DNSServiceErrorType DNSSD_API TXTRecordSetValue( + TXTRecordRef *txtref, + const char *key, + uint8_t length, + const void *value) { + + TXTRecordInternal *t; + uint8_t *p; + size_t l, n; + + AVAHI_WARN_LINKAGE; + + assert(key); + assert(txtref); + + l = strlen(key); + + if (*key == 0 || strchr(key, '=') || l > 0xFF) /* Empty or invalid key */ + return kDNSServiceErr_Invalid; + + if (!(t = INTERNAL_PTR(txtref))) + return kDNSServiceErr_NoMemory; + + n = l + (value ? length + 1 : 0); + + if (n > 0xFF) + return kDNSServiceErr_Invalid; + + if (make_sure_fits_in(t, 1 + n) < 0) + return kDNSServiceErr_NoMemory; + + remove_key(t, key); + + p = t->buffer + t->size; + + *(p++) = (uint8_t) n; + t->size ++; + + memcpy(p, key, l); + p += l; + t->size += l; + + if (value) { + *(p++) = '='; + memcpy(p, value, length); + t->size += length + 1; + } + + assert(t->size <= t->max_size); + + return kDNSServiceErr_NoError; +} + +DNSServiceErrorType DNSSD_API TXTRecordRemoveValue(TXTRecordRef *txtref, const char *key) { + TXTRecordInternal *t; + int found; + + AVAHI_WARN_LINKAGE; + + assert(key); + assert(txtref); + + if (*key == 0 || strchr(key, '=') || strlen(key) > 0xFF) /* Empty or invalid key */ + return kDNSServiceErr_Invalid; + + if (!(t = INTERNAL_PTR(txtref))) + return kDNSServiceErr_NoError; + + found = remove_key(t, key); + + return found ? kDNSServiceErr_NoError : kDNSServiceErr_NoSuchKey; +} + +uint16_t DNSSD_API TXTRecordGetLength(const TXTRecordRef *txtref) { + const TXTRecordInternal *t; + + AVAHI_WARN_LINKAGE; + + assert(txtref); + + if (!(t = INTERNAL_PTR_CONST(txtref))) + return 0; + + assert(t->size <= 0xFFFF); + return (uint16_t) t->size; +} + +const void * DNSSD_API TXTRecordGetBytesPtr(const TXTRecordRef *txtref) { + const TXTRecordInternal *t; + + AVAHI_WARN_LINKAGE; + + assert(txtref); + + if (!(t = INTERNAL_PTR_CONST(txtref)) || !t->buffer) + return ""; + + return t->buffer; +} + +static const uint8_t *find_key(const uint8_t *buffer, size_t size, const char *key) { + size_t i; + const uint8_t *p; + size_t key_len; + + key_len = strlen(key); + + assert(key_len <= 0xFF); + + p = buffer; + i = 0; + + while (i < size) { + + /* Does the item fit in? */ + if (*p > size - i - 1) + return NULL; + + /* Key longer than buffer */ + if (key_len > size - i - 1) + return NULL; + + if (key_len <= *p && + strncmp(key, (const char*) p+1, key_len) == 0 && + (key_len == *p || p[1+key_len] == '=')) { + + /* Key matches, so let's return it */ + + return p; + } + + /* Skip to next */ + i += *p +1; + p += *p +1; + } + + return NULL; +} + +int DNSSD_API TXTRecordContainsKey ( + uint16_t size, + const void *buffer, + const char *key) { + + AVAHI_WARN_LINKAGE; + + assert(key); + + if (!size) + return 0; + + assert(buffer); + + if (!(find_key(buffer, size, key))) + return 0; + + return 1; +} + +const void * DNSSD_API TXTRecordGetValuePtr( + uint16_t size, + const void *buffer, + const char *key, + uint8_t *value_len) { + + const uint8_t *p; + size_t n, l; + + AVAHI_WARN_LINKAGE; + + assert(key); + + if (!size) + goto fail; + + if (*key == 0 || strchr(key, '=') || strlen(key) > 0xFF) /* Empty or invalid key */ + return NULL; + + assert(buffer); + + if (!(p = find_key(buffer, size, key))) + goto fail; + + n = *p; + l = strlen(key); + + assert(n >= l); + p += 1 + l; + n -= l; + + if (n <= 0) + goto fail; + + assert(*p == '='); + p++; + n--; + + if (value_len) + *value_len = n; + + return p; + +fail: + if (value_len) + *value_len = 0; + + return NULL; +} + + +uint16_t DNSSD_API TXTRecordGetCount( + uint16_t size, + const void *buffer) { + + const uint8_t *p; + unsigned n = 0; + size_t i; + + AVAHI_WARN_LINKAGE; + + if (!size) + return 0; + + assert(buffer); + + p = buffer; + i = 0; + + while (i < size) { + + /* Does the item fit in? */ + if (*p > size - i - 1) + break; + + n++; + + /* Skip to next */ + i += *p +1; + p += *p +1; + } + + assert(n <= 0xFFFF); + + return (uint16_t) n; +} + +DNSServiceErrorType DNSSD_API TXTRecordGetItemAtIndex( + uint16_t size, + const void *buffer, + uint16_t idx, + uint16_t key_len, + char *key, + uint8_t *value_len, + const void **value) { + + const uint8_t *p; + size_t i; + unsigned n = 0; + DNSServiceErrorType ret = kDNSServiceErr_Invalid; + + AVAHI_WARN_LINKAGE; + + if (!size) + goto fail; + + assert(buffer); + + p = buffer; + i = 0; + + while (i < size) { + + /* Does the item fit in? */ + if (*p > size - i - 1) + goto fail; + + if (n >= idx) { + size_t l; + const uint8_t *d; + + d = memchr(p+1, '=', *p); + + /* Length of key */ + l = d ? d - p - 1 : *p; + + if (key_len < l+1) { + ret = kDNSServiceErr_NoMemory; + goto fail; + } + + strncpy(key, (const char*) p + 1, l); + key[l] = 0; + + if (d) { + if (value_len) + *value_len = *p - l - 1; + + if (value) + *value = d + 1; + } else { + + if (value_len) + *value_len = 0; + + if (value) + *value = NULL; + } + + return kDNSServiceErr_NoError; + } + + n++; + + /* Skip to next */ + i += *p +1; + p += *p +1; + } + + +fail: + + if (value) + *value = NULL; + + if (value_len) + *value_len = 0; + + return ret; + +} -- cgit