147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt/* -*- Mode: C; tab-width: 4 -*- 247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * 347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * Copyright (c) 2004, Apple Computer, Inc. All rights reserved. 447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * 547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * Redistribution and use in source and binary forms, with or without 647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * modification, are permitted provided that the following conditions are met: 747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * 847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * 1. Redistributions of source code must retain the above copyright notice, 947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * this list of conditions and the following disclaimer. 1047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * 2. Redistributions in binary form must reproduce the above copyright notice, 1147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * this list of conditions and the following disclaimer in the documentation 1247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * and/or other materials provided with the distribution. 1347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of its 1447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * contributors may be used to endorse or promote products derived from this 1547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * software without specific prior written permission. 1647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * 1747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 1847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 1947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 2047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 2147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 2247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 2347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 2447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 2647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt */ 2847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 2947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#include <stdlib.h> 3047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#include <string.h> 3147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 3247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#include "dns_sd.h" 3347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 3447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if MDNS_BUILDINGSHAREDLIBRARY || MDNS_BUILDINGSTUBLIBRARY 3547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#pragma export on 3647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif 3747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 3847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if defined(_WIN32) 3947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// disable warning "conversion from <data> to uint16_t" 4047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#pragma warning(disable:4244) 4147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define strncasecmp _strnicmp 4247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define strcasecmp _stricmp 4347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif 4447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 4547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt/********************************************************************************************* 4647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * 4747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * Supporting Functions 4847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * 4947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *********************************************************************************************/ 5047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 5147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define mDNSIsDigit(X) ((X) >= '0' && (X) <= '9') 5247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 5347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// DomainEndsInDot returns 1 if name ends with a dot, 0 otherwise 5447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// (DNSServiceConstructFullName depends this returning 1 for true, rather than any non-zero value meaning true) 5547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 5647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltstatic int DomainEndsInDot(const char *dom) 5747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 5847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (dom[0] && dom[1]) 5947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 6047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (dom[0] == '\\') // advance past escaped byte sequence 6147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 6247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (mDNSIsDigit(dom[1]) && mDNSIsDigit(dom[2]) && mDNSIsDigit(dom[3])) 6347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt dom += 4; // If "\ddd" then skip four 6447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else dom += 2; // else if "\x" then skip two 6547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 6647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else dom++; // else goto next character 6747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 6847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return (dom[0] == '.'); 6947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 7047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 7147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltstatic uint8_t *InternalTXTRecordSearch 7247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ( 7347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt uint16_t txtLen, 7447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const void *txtRecord, 7547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const char *key, 7647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt unsigned long *keylen 7747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ) 7847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 7947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt uint8_t *p = (uint8_t*)txtRecord; 8047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt uint8_t *e = p + txtLen; 8147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *keylen = (unsigned long) strlen(key); 8247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (p<e) 8347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 8447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt uint8_t *x = p; 8547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt p += 1 + p[0]; 8647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (p <= e && *keylen <= x[0] && !strncasecmp(key, (char*)x+1, *keylen)) 8747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (*keylen == x[0] || x[1+*keylen] == '=') return(x); 8847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 8947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(NULL); 9047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 9147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 9247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt/********************************************************************************************* 9347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * 9447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * General Utility Functions 9547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * 9647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *********************************************************************************************/ 9747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 9847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Note: Need to make sure we don't write more than kDNSServiceMaxDomainName (1009) bytes to fullName 9947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// In earlier builds this constant was defined to be 1005, so to avoid buffer overruns on clients 10047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// compiled with that constant we'll actually limit the output to 1005 bytes. 10147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 10247e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltDNSServiceErrorType DNSSD_API DNSServiceConstructFullName 10347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ( 10447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt char *const fullName, 10547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const char *const service, // May be NULL 10647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const char *const regtype, 10747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const char *const domain 10847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ) 10947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 11047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const size_t len = !regtype ? 0 : strlen(regtype) - DomainEndsInDot(regtype); 11147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt char *fn = fullName; 11247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt char *const lim = fullName + 1005; 11347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const char *s = service; 11447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const char *r = regtype; 11547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const char *d = domain; 11647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 11747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // regtype must be at least "x._udp" or "x._tcp" 11847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (len < 6 || !domain || !domain[0]) return kDNSServiceErr_BadParam; 11947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (strncasecmp((regtype + len - 4), "_tcp", 4) && strncasecmp((regtype + len - 4), "_udp", 4)) return kDNSServiceErr_BadParam; 12047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 12147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (service && *service) 12247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 12347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (*s) 12447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 12547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt unsigned char c = *s++; // Needs to be unsigned, or values like 0xFF will be interpreted as < 32 12647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (c <= ' ') // Escape non-printable characters 12747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 12847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (fn+4 >= lim) goto fail; 12947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *fn++ = '\\'; 13047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *fn++ = '0' + (c / 100); 13147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *fn++ = '0' + (c / 10) % 10; 13247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt c = '0' + (c ) % 10; 13347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 13447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (c == '.' || (c == '\\')) // Escape dot and backslash literals 13547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 13647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (fn+2 >= lim) goto fail; 13747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *fn++ = '\\'; 13847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 13947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 14047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (fn+1 >= lim) goto fail; 14147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *fn++ = (char)c; 14247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 14347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *fn++ = '.'; 14447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 14547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 14647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (*r) if (fn+1 >= lim) goto fail; else *fn++ = *r++; 14747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!DomainEndsInDot(regtype)) { if (fn+1 >= lim) goto fail; else *fn++ = '.'; } 14847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 14947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (*d) if (fn+1 >= lim) goto fail; else *fn++ = *d++; 15047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!DomainEndsInDot(domain)) { if (fn+1 >= lim) goto fail; else *fn++ = '.'; } 15147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 15247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *fn = '\0'; 15347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return kDNSServiceErr_NoError; 15447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 15547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltfail: 15647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *fn = '\0'; 15747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return kDNSServiceErr_BadParam; 15847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 15947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 16047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt/********************************************************************************************* 16147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * 16247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * TXT Record Construction Functions 16347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * 16447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *********************************************************************************************/ 16547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 16647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalttypedef struct _TXTRecordRefRealType 16747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 16847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt uint8_t *buffer; // Pointer to data 16947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt uint16_t buflen; // Length of buffer 17047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt uint16_t datalen; // Length currently in use 17147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt uint16_t malloced; // Non-zero if buffer was allocated via malloc() 17247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } TXTRecordRefRealType; 17347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 17447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define txtRec ((TXTRecordRefRealType*)txtRecord) 17547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 17647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// The opaque storage defined in the public dns_sd.h header is 16 bytes; 17747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// make sure we don't exceed that. 17847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltstruct CompileTimeAssertionCheck_dnssd_clientlib 17947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 18047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt char assert0[(sizeof(TXTRecordRefRealType) <= 16) ? 1 : -1]; 18147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt }; 18247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 18347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltvoid DNSSD_API TXTRecordCreate 18447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ( 18547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt TXTRecordRef *txtRecord, 18647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt uint16_t bufferLen, 18747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt void *buffer 18847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ) 18947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 19047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt txtRec->buffer = buffer; 19147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt txtRec->buflen = buffer ? bufferLen : (uint16_t)0; 19247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt txtRec->datalen = 0; 19347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt txtRec->malloced = 0; 19447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 19547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 19647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltvoid DNSSD_API TXTRecordDeallocate(TXTRecordRef *txtRecord) 19747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 19847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (txtRec->malloced) free(txtRec->buffer); 19947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 20047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 20147e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltDNSServiceErrorType DNSSD_API TXTRecordSetValue 20247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ( 20347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt TXTRecordRef *txtRecord, 20447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const char *key, 20547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt uint8_t valueSize, 20647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const void *value 20747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ) 20847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 20947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt uint8_t *start, *p; 21047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const char *k; 21147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt unsigned long keysize, keyvalsize; 21247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 21347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (k = key; *k; k++) if (*k < 0x20 || *k > 0x7E || *k == '=') return(kDNSServiceErr_Invalid); 21447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt keysize = (unsigned long)(k - key); 21547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt keyvalsize = 1 + keysize + (value ? (1 + valueSize) : 0); 21647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (keysize < 1 || keyvalsize > 255) return(kDNSServiceErr_Invalid); 21747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt (void)TXTRecordRemoveValue(txtRecord, key); 21847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (txtRec->datalen + keyvalsize > txtRec->buflen) 21947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 22047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt unsigned char *newbuf; 22147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt unsigned long newlen = txtRec->datalen + keyvalsize; 22247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (newlen > 0xFFFF) return(kDNSServiceErr_Invalid); 22347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt newbuf = malloc((size_t)newlen); 22447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!newbuf) return(kDNSServiceErr_NoMemory); 22547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt memcpy(newbuf, txtRec->buffer, txtRec->datalen); 22647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (txtRec->malloced) free(txtRec->buffer); 22747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt txtRec->buffer = newbuf; 22847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt txtRec->buflen = (uint16_t)(newlen); 22947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt txtRec->malloced = 1; 23047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 23147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt start = txtRec->buffer + txtRec->datalen; 23247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt p = start + 1; 23347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt memcpy(p, key, keysize); 23447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt p += keysize; 23547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (value) 23647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 23747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *p++ = '='; 23847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt memcpy(p, value, valueSize); 23947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt p += valueSize; 24047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 24147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *start = (uint8_t)(p - start - 1); 24247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt txtRec->datalen += p - start; 24347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(kDNSServiceErr_NoError); 24447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 24547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 24647e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltDNSServiceErrorType DNSSD_API TXTRecordRemoveValue 24747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ( 24847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt TXTRecordRef *txtRecord, 24947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const char *key 25047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ) 25147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 25247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt unsigned long keylen, itemlen, remainder; 25347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt uint8_t *item = InternalTXTRecordSearch(txtRec->datalen, txtRec->buffer, key, &keylen); 25447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!item) return(kDNSServiceErr_NoSuchKey); 25547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt itemlen = (unsigned long)(1 + item[0]); 25647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt remainder = (unsigned long)((txtRec->buffer + txtRec->datalen) - (item + itemlen)); 25747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Use memmove because memcpy behaviour is undefined for overlapping regions 25847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt memmove(item, item + itemlen, remainder); 25947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt txtRec->datalen -= itemlen; 26047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(kDNSServiceErr_NoError); 26147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 26247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 26347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltuint16_t DNSSD_API TXTRecordGetLength (const TXTRecordRef *txtRecord) { return(txtRec->datalen); } 26447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltconst void * DNSSD_API TXTRecordGetBytesPtr(const TXTRecordRef *txtRecord) { return(txtRec->buffer); } 26547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 26647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt/********************************************************************************************* 26747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * 26847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * TXT Record Parsing Functions 26947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * 27047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *********************************************************************************************/ 27147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 27247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltint DNSSD_API TXTRecordContainsKey 27347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ( 27447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt uint16_t txtLen, 27547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const void *txtRecord, 27647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const char *key 27747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ) 27847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 27947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt unsigned long keylen; 28047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return (InternalTXTRecordSearch(txtLen, txtRecord, key, &keylen) ? 1 : 0); 28147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 28247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 28347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltconst void * DNSSD_API TXTRecordGetValuePtr 28447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ( 28547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt uint16_t txtLen, 28647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const void *txtRecord, 28747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const char *key, 28847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt uint8_t *valueLen 28947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ) 29047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 29147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt unsigned long keylen; 29247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt uint8_t *item = InternalTXTRecordSearch(txtLen, txtRecord, key, &keylen); 29347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!item || item[0] <= keylen) return(NULL); // If key not found, or found with no value, return NULL 29447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *valueLen = (uint8_t)(item[0] - (keylen + 1)); 29547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return (item + 1 + keylen + 1); 29647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 29747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 29847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltuint16_t DNSSD_API TXTRecordGetCount 29947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ( 30047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt uint16_t txtLen, 30147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const void *txtRecord 30247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ) 30347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 30447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt uint16_t count = 0; 30547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt uint8_t *p = (uint8_t*)txtRecord; 30647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt uint8_t *e = p + txtLen; 30747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (p<e) { p += 1 + p[0]; count++; } 30847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return((p>e) ? (uint16_t)0 : count); 30947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 31047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 31147e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltDNSServiceErrorType DNSSD_API TXTRecordGetItemAtIndex 31247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ( 31347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt uint16_t txtLen, 31447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const void *txtRecord, 31547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt uint16_t itemIndex, 31647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt uint16_t keyBufLen, 31747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt char *key, 31847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt uint8_t *valueLen, 31947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const void **value 32047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ) 32147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 32247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt uint16_t count = 0; 32347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt uint8_t *p = (uint8_t*)txtRecord; 32447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt uint8_t *e = p + txtLen; 32547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (p<e && count<itemIndex) { p += 1 + p[0]; count++; } // Find requested item 32647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (p<e && p + 1 + p[0] <= e) // If valid 32747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 32847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt uint8_t *x = p+1; 32947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt unsigned long len = 0; 33047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt e = p + 1 + p[0]; 33147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (x+len<e && x[len] != '=') len++; 33247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (len >= keyBufLen) return(kDNSServiceErr_NoMemory); 33347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt memcpy(key, x, len); 33447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt key[len] = 0; 33547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (x+len<e) // If we found '=' 33647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 33747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *value = x + len + 1; 33847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *valueLen = (uint8_t)(p[0] - (len + 1)); 33947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 34047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 34147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 34247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *value = NULL; 34347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *valueLen = 0; 34447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 34547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(kDNSServiceErr_NoError); 34647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 34747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(kDNSServiceErr_Invalid); 34847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 34947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 35047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt/********************************************************************************************* 35147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * 35247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * SCCS-compatible version string 35347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * 35447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *********************************************************************************************/ 35547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 35647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// For convenience when using the "strings" command, this is the last thing in the file 35747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 35847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Note: The C preprocessor stringify operator ('#') makes a string from its argument, without macro expansion 35947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// e.g. If "version" is #define'd to be "4", then STRINGIFY_AWE(version) will return the string "version", not "4" 36047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// To expand "version" to its value before making the string, use STRINGIFY(version) instead 36147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s) #s 36247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define STRINGIFY(s) STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s) 36347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 36447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// NOT static -- otherwise the compiler may optimize it out 36547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// The "@(#) " pattern is a special prefix the "what" command looks for 36647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltconst char VersionString_SCCS_libdnssd[] = "@(#) libdns_sd " STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")"; 367