]> git.saurik.com Git - apple/libinfo.git/blob - mdns.subproj/dnssd_clientlib.c
Libinfo-221.tar.gz
[apple/libinfo.git] / mdns.subproj / dnssd_clientlib.c
1 /*
2 * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22
23 Change History (most recent first):
24
25 $Log: dnssd_clientlib.c,v $
26 Revision 1.3 2004/09/16 23:45:23 majka
27 Integrated 3775315 and 3765280.
28
29 Revision 1.2.16.1 2004/09/02 19:43:41 ksekar
30 <rdar://problem/3775315>: Sync dns-sd client files between Libinfo and
31 mDNSResponder projects
32
33 Revision 1.7 2004/06/26 03:16:34 shersche
34 clean up warning messages on Win32 platform
35
36 Submitted by: herscher
37
38 Revision 1.6 2004/06/12 01:09:45 cheshire
39 To be callable from the broadest range of clients on Windows (e.g. Visual Basic, C#, etc.)
40 API routines have to be declared as "__stdcall", instead of the C default, "__cdecl"
41
42 Revision 1.5 2004/05/25 18:29:33 cheshire
43 Move DNSServiceConstructFullName() from dnssd_clientstub.c to dnssd_clientlib.c,
44 so that it's also accessible to dnssd_clientshim.c (single address space) clients.
45
46 Revision 1.4 2004/05/25 17:08:55 cheshire
47 Fix compiler warning (doesn't make sense for function return type to be const)
48
49 Revision 1.3 2004/05/21 21:41:35 cheshire
50 Add TXT record building and parsing APIs
51
52 Revision 1.2 2004/05/20 22:22:21 cheshire
53 Enable code that was bracketed by "#if 0"
54
55 Revision 1.1 2004/03/12 21:30:29 cheshire
56 Build a System-Context Shared Library from mDNSCore, for the benefit of developers
57 like Muse Research who want to be able to use mDNS/DNS-SD from GPL-licensed code.
58
59 */
60
61 #include <stdlib.h>
62 #include <string.h>
63
64 #include "dns_sd.h"
65
66 #if MDNS_BUILDINGSHAREDLIBRARY || MDNS_BUILDINGSTUBLIBRARY
67 #pragma export on
68 #endif
69
70 #if defined(_WIN32)
71 // disable warning "conversion from <data> to uint16_t"
72 #pragma warning(disable:4244)
73 #endif
74
75 /*********************************************************************************************
76 *
77 * Supporting Functions
78 *
79 *********************************************************************************************/
80
81 #define mdnsIsDigit(X) ((X) >= '0' && (X) <= '9')
82
83 static int DomainEndsInDot(const char *dom)
84 {
85 while (dom[0] && dom[1])
86 {
87 if (dom[0] == '\\') // advance past escaped byte sequence
88 {
89 if (mdnsIsDigit(dom[1]) && mdnsIsDigit(dom[2]) && mdnsIsDigit(dom[3]))
90 dom += 4; // If "\ddd" then skip four
91 else dom += 2; // else if "\x" then skip two
92 }
93 else dom++; // else goto next character
94 }
95 return (dom[0] == '.');
96 }
97
98 static uint8_t *InternalTXTRecordSearch
99 (
100 uint16_t txtLen,
101 const void *txtRecord,
102 const char *key,
103 unsigned long *keylen
104 )
105 {
106 uint8_t *p = (uint8_t*)txtRecord;
107 uint8_t *e = p + txtLen;
108 *keylen = (unsigned long) strlen(key);
109 while (p<e)
110 {
111 uint8_t *x = p;
112 p += 1 + p[0];
113 if (p <= e && *keylen <= x[0] && !strncmp(key, (char*)x+1, *keylen))
114 if (*keylen == x[0] || x[1+*keylen] == '=') return(x);
115 }
116 return(NULL);
117 }
118
119 /*********************************************************************************************
120 *
121 * General Utility Functions
122 *
123 *********************************************************************************************/
124
125 int DNSSD_API DNSServiceConstructFullName
126 (
127 char *fullName,
128 const char *service, /* may be NULL */
129 const char *regtype,
130 const char *domain
131 )
132 {
133 unsigned long len;
134 unsigned char c;
135 char *fn = fullName;
136 const char *s = service;
137 const char *r = regtype;
138 const char *d = domain;
139
140 if (service)
141 {
142 while(*s)
143 {
144 c = (unsigned char)*s++;
145 if (c == '.' || (c == '\\')) *fn++ = '\\'; // escape dot and backslash literals
146 else if (c <= ' ') // escape non-printable characters
147 {
148 *fn++ = '\\';
149 *fn++ = (char) ('0' + (c / 100));
150 *fn++ = (char) ('0' + (c / 10) % 10);
151 c = (unsigned char)('0' + (c % 10));
152 }
153 *fn++ = (char)c;
154 }
155 *fn++ = '.';
156 }
157
158 if (!regtype) return -1;
159 len = (unsigned long) strlen(regtype);
160 if (DomainEndsInDot(regtype)) len--;
161 if (len < 6) return -1; // regtype must be at least "x._udp" or "x._tcp"
162 if (strncmp((regtype + len - 4), "_tcp", 4) && strncmp((regtype + len - 4), "_udp", 4)) return -1;
163 while(*r) *fn++ = *r++;
164 if (!DomainEndsInDot(regtype)) *fn++ = '.';
165
166 if (!domain || !domain[0]) return -1;
167 while(*d) *fn++ = *d++;
168 if (!DomainEndsInDot(domain)) *fn++ = '.';
169 *fn = '\0';
170 return 0;
171 }
172
173 /*********************************************************************************************
174 *
175 * TXT Record Construction Functions
176 *
177 *********************************************************************************************/
178
179 typedef struct _TXTRecordRefRealType
180 {
181 uint8_t *buffer; // Pointer to data
182 uint16_t buflen; // Length of buffer
183 uint16_t datalen; // Length currently in use
184 uint16_t malloced; // Non-zero if buffer was allocated via malloc()
185 } TXTRecordRefRealType;
186
187 #define txtRec ((TXTRecordRefRealType*)txtRecord)
188
189 // The opaque storage defined in the public dns_sd.h header is 16 bytes;
190 // make sure we don't exceed that.
191 struct dnssd_clientlib_CompileTimeAssertionCheck
192 {
193 char assert0[(sizeof(TXTRecordRefRealType) <= 16) ? 1 : -1];
194 };
195
196 void TXTRecordCreate
197 (
198 TXTRecordRef *txtRecord,
199 uint16_t bufferLen,
200 void *buffer
201 )
202 {
203 txtRec->buffer = buffer;
204 txtRec->buflen = buffer ? bufferLen : (uint16_t)0;
205 txtRec->datalen = 0;
206 txtRec->malloced = 0;
207 }
208
209 void TXTRecordDeallocate(TXTRecordRef *txtRecord)
210 {
211 if (txtRec->malloced) free(txtRec->buffer);
212 }
213
214 DNSServiceErrorType TXTRecordSetValue
215 (
216 TXTRecordRef *txtRecord,
217 const char *key,
218 uint8_t valueSize,
219 const void *value
220 )
221 {
222 uint8_t *start, *p;
223 const char *k;
224 unsigned long keysize, keyvalsize;
225
226 for (k = key; *k; k++) if (*k < 0x20 || *k > 0x7E || *k == '=') return(kDNSServiceErr_Invalid);
227 keysize = (unsigned long)(k - key);
228 keyvalsize = 1 + keysize + (value ? (1 + valueSize) : 0);
229 if (keysize < 1 || keyvalsize > 255) return(kDNSServiceErr_Invalid);
230 (void)TXTRecordRemoveValue(txtRecord, key);
231 if (txtRec->datalen + keyvalsize > txtRec->buflen)
232 {
233 unsigned char *newbuf;
234 unsigned long newlen = txtRec->datalen + keyvalsize;
235 if (newlen > 0xFFFF) return(kDNSServiceErr_Invalid);
236 newbuf = malloc((size_t)newlen);
237 if (!newbuf) return(kDNSServiceErr_NoMemory);
238 memcpy(newbuf, txtRec->buffer, txtRec->datalen);
239 if (txtRec->malloced) free(txtRec->buffer);
240 txtRec->buffer = newbuf;
241 txtRec->buflen = (uint16_t)(newlen);
242 txtRec->malloced = 1;
243 }
244 start = txtRec->buffer + txtRec->datalen;
245 p = start + 1;
246 memcpy(p, key, keysize);
247 p += keysize;
248 if (value)
249 {
250 *p++ = '=';
251 memcpy(p, value, valueSize);
252 p += valueSize;
253 }
254 *start = (uint8_t)(p - start - 1);
255 txtRec->datalen += p - start;
256 return(kDNSServiceErr_NoError);
257 }
258
259 DNSServiceErrorType TXTRecordRemoveValue
260 (
261 TXTRecordRef *txtRecord,
262 const char *key
263 )
264 {
265 unsigned long keylen, itemlen, remainder;
266 uint8_t *item = InternalTXTRecordSearch(txtRec->datalen, txtRec->buffer, key, &keylen);
267 if (!item) return(kDNSServiceErr_NoSuchKey);
268 itemlen = (unsigned long)(1 + item[0]);
269 remainder = (unsigned long)((txtRec->buffer + txtRec->datalen) - (item + itemlen));
270 // Use memmove because memcpy behaviour is undefined for overlapping regions
271 memmove(item, item + itemlen, remainder);
272 txtRec->datalen -= itemlen;
273 return(kDNSServiceErr_NoError);
274 }
275
276 uint16_t TXTRecordGetLength (const TXTRecordRef *txtRecord) { return(txtRec->datalen); }
277 const void * TXTRecordGetBytesPtr(const TXTRecordRef *txtRecord) { return(txtRec->buffer); }
278
279 /*********************************************************************************************
280 *
281 * TXT Record Parsing Functions
282 *
283 *********************************************************************************************/
284
285 int TXTRecordContainsKey
286 (
287 uint16_t txtLen,
288 const void *txtRecord,
289 const char *key
290 )
291 {
292 unsigned long keylen;
293 return (InternalTXTRecordSearch(txtLen, txtRecord, key, &keylen) ? 1 : 0);
294 }
295
296 const void * TXTRecordGetValuePtr
297 (
298 uint16_t txtLen,
299 const void *txtRecord,
300 const char *key,
301 uint8_t *valueLen
302 )
303 {
304 unsigned long keylen;
305 uint8_t *item = InternalTXTRecordSearch(txtLen, txtRecord, key, &keylen);
306 if (!item || item[0] <= keylen) return(NULL); // If key not found, or found with no value, return NULL
307 *valueLen = (uint8_t)(item[0] - (keylen + 1));
308 return (item + 1 + keylen + 1);
309 }
310
311 uint16_t TXTRecordGetCount
312 (
313 uint16_t txtLen,
314 const void *txtRecord
315 )
316 {
317 uint16_t count = 0;
318 uint8_t *p = (uint8_t*)txtRecord;
319 uint8_t *e = p + txtLen;
320 while (p<e) { p += 1 + p[0]; count++; }
321 return((p>e) ? (uint16_t)0 : count);
322 }
323
324 DNSServiceErrorType TXTRecordGetItemAtIndex
325 (
326 uint16_t txtLen,
327 const void *txtRecord,
328 uint16_t index,
329 uint16_t keyBufLen,
330 char *key,
331 uint8_t *valueLen,
332 const void **value
333 )
334 {
335 uint16_t count = 0;
336 uint8_t *p = (uint8_t*)txtRecord;
337 uint8_t *e = p + txtLen;
338 while (p<e && count<index) { p += 1 + p[0]; count++; } // Find requested item
339 if (p<e && p + 1 + p[0] <= e) // If valid
340 {
341 uint8_t *x = p+1;
342 unsigned long len = 0;
343 e = p + 1 + p[0];
344 while (x+len<e && x[len] != '=') len++;
345 if (len >= keyBufLen) return(kDNSServiceErr_NoMemory);
346 memcpy(key, x, len);
347 key[len] = 0;
348 if (x+len<e) // If we found '='
349 {
350 *value = x + len + 1;
351 *valueLen = (uint8_t)(p[0] - (len + 1));
352 }
353 else
354 {
355 *value = NULL;
356 *valueLen = 0;
357 }
358 return(kDNSServiceErr_NoError);
359 }
360 return(kDNSServiceErr_Invalid);
361 }