Lines Matching defs:*
0 /* $Id$ */
4 This file is part of avahi.
6 avahi is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as
8 published by the Free Software Foundation; either version 2.1 of the
9 License, or (at your option) any later version.
11 avahi is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
14 Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with avahi; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19 USA.
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
26 #include <string.h>
27 #include <unistd.h>
28 #include <fcntl.h>
29 #include <errno.h>
30 #include <limits.h>
31 #include <stdio.h>
32 #include <ctype.h>
33 #include <stdlib.h>
34 #include <assert.h>
36 #include "domain.h"
37 #include "malloc.h"
38 #include "error.h"
39 #include "address.h"
40 #include "utf8.h"
42 /* Read the first label from string *name, unescape "\" and write it to dest */
43 char *avahi_unescape_label(const char **name, char *dest, size_t size) {
44 unsigned i = 0;
45 char *d;
47 assert(dest);
48 assert(size > 0);
49 assert(name);
51 d = dest;
53 for (;;) {
54 if (i >= size)
55 return NULL;
57 if (**name == '.') {
58 (*name)++;
59 break;
62 if (**name == 0)
63 break;
65 if (**name == '\\') {
66 /* Escaped character */
68 (*name) ++;
70 if (**name == 0)
71 /* Ending NUL */
72 return NULL;
74 else if (**name == '\\' || **name == '.') {
75 /* Escaped backslash or dot */
76 *(d++) = *((*name) ++);
77 i++;
78 } else if (isdigit(**name)) {
79 int n;
81 /* Escaped literal ASCII character */
83 if (!isdigit(*(*name+1)) || !isdigit(*(*name+2)))
84 return NULL;
86 n = ((uint8_t) (**name - '0') * 100) + ((uint8_t) (*(*name+1) - '0') * 10) + ((uint8_t) (*(*name +2) - '0'));
88 if (n > 255 || n == 0)
89 return NULL;
91 *(d++) = (char) n;
92 i++;
94 (*name) += 3;
95 } else
96 return NULL;
98 } else {
100 /* Normal character */
102 *(d++) = *((*name) ++);
103 i++;
107 assert(i < size);
109 *d = 0;
111 if (!avahi_utf8_valid(dest))
112 return NULL;
114 return dest;
117 /* Escape "\" and ".", append \0 */
118 char *avahi_escape_label(const char* src, size_t src_length, char **ret_name, size_t *ret_size) {
119 char *r;
121 assert(src);
122 assert(ret_name);
123 assert(*ret_name);
124 assert(ret_size);
125 assert(*ret_size > 0);
127 r = *ret_name;
129 while (src_length > 0) {
130 if (*src == '.' || *src == '\\') {
132 /* Dot or backslash */
134 if (*ret_size < 3)
135 return NULL;
137 *((*ret_name) ++) = '\\';
138 *((*ret_name) ++) = *src;
139 (*ret_size) -= 2;
141 } else if (
142 *src == '_' ||
143 *src == '-' ||
144 (*src >= '0' && *src <= '9') ||
145 (*src >= 'a' && *src <= 'z') ||
146 (*src >= 'A' && *src <= 'Z')) {
148 /* Proper character */
150 if (*ret_size < 2)
151 return NULL;
153 *((*ret_name)++) = *src;
154 (*ret_size) --;
156 } else {
158 /* Everything else */
160 if (*ret_size < 5)
161 return NULL;
163 *((*ret_name) ++) = '\\';
164 *((*ret_name) ++) = '0' + (char) ((uint8_t) *src / 100);
165 *((*ret_name) ++) = '0' + (char) (((uint8_t) *src / 10) % 10);
166 *((*ret_name) ++) = '0' + (char) ((uint8_t) *src % 10);
168 (*ret_size) -= 4;
171 src_length --;
172 src++;
175 **ret_name = 0;
177 return r;
180 char *avahi_normalize_name(const char *s, char *ret_s, size_t size) {
181 int empty = 1;
182 char *r;
184 assert(s);
185 assert(ret_s);
186 assert(size > 0);
188 r = ret_s;
189 *ret_s = 0;
191 while (*s) {
192 char label[AVAHI_LABEL_MAX];
194 if (!(avahi_unescape_label(&s, label, sizeof(label))))
195 return NULL;
197 if (label[0] == 0) {
199 if (*s == 0 && empty)
200 return ret_s;
202 return NULL;
205 if (!empty) {
206 if (size < 1)
207 return NULL;
209 *(r++) = '.';
210 size--;
212 } else
213 empty = 0;
215 avahi_escape_label(label, strlen(label), &r, &size);
218 return ret_s;
221 char *avahi_normalize_name_strdup(const char *s) {
222 char t[AVAHI_DOMAIN_NAME_MAX];
223 assert(s);
225 if (!(avahi_normalize_name(s, t, sizeof(t))))
226 return NULL;
228 return avahi_strdup(t);
231 int avahi_domain_equal(const char *a, const char *b) {
232 assert(a);
233 assert(b);
235 if (a == b)
236 return 1;
238 for (;;) {
239 char ca[AVAHI_LABEL_MAX], cb[AVAHI_LABEL_MAX], *r;
241 r = avahi_unescape_label(&a, ca, sizeof(ca));
242 assert(r);
243 r = avahi_unescape_label(&b, cb, sizeof(cb));
244 assert(r);
246 if (strcasecmp(ca, cb))
247 return 0;
249 if (!*a && !*b)
250 return 1;
253 return 1;
256 int avahi_is_valid_service_type_generic(const char *t) {
257 assert(t);
259 if (strlen(t) >= AVAHI_DOMAIN_NAME_MAX || !*t)
260 return 0;
262 do {
263 char label[AVAHI_LABEL_MAX];
265 if (!(avahi_unescape_label(&t, label, sizeof(label))))
266 return 0;
268 if (strlen(label) <= 2 || label[0] != '_')
269 return 0;
271 } while (*t);
273 return 1;
276 int avahi_is_valid_service_type_strict(const char *t) {
277 char label[AVAHI_LABEL_MAX];
278 assert(t);
280 if (strlen(t) >= AVAHI_DOMAIN_NAME_MAX || !*t)
281 return 0;
283 /* Application name */
285 if (!(avahi_unescape_label(&t, label, sizeof(label))))
286 return 0;
288 if (strlen(label) <= 2 || label[0] != '_')
289 return 0;
291 if (!*t)
292 return 0;
294 /* _tcp or _udp boilerplate */
296 if (!(avahi_unescape_label(&t, label, sizeof(label))))
297 return 0;
299 if (strcasecmp(label, "_tcp") && strcasecmp(label, "_udp"))
300 return 0;
302 if (*t)
303 return 0;
305 return 1;
308 const char *avahi_get_type_from_subtype(const char *t) {
309 char label[AVAHI_LABEL_MAX];
310 const char *ret;
311 assert(t);
313 if (strlen(t) >= AVAHI_DOMAIN_NAME_MAX || !*t)
314 return NULL;
316 /* Subtype name */
318 if (!(avahi_unescape_label(&t, label, sizeof(label))))
319 return NULL;
321 if (strlen(label) <= 2 || label[0] != '_')
322 return NULL;
324 if (!*t)
325 return NULL;
327 /* String "_sub" */
329 if (!(avahi_unescape_label(&t, label, sizeof(label))))
330 return NULL;
332 if (strcasecmp(label, "_sub"))
333 return NULL;
335 if (!*t)
336 return NULL;
338 ret = t;
340 /* Application name */
342 if (!(avahi_unescape_label(&t, label, sizeof(label))))
343 return NULL;
345 if (strlen(label) <= 2 || label[0] != '_')
346 return NULL;
348 if (!*t)
349 return NULL;
351 /* _tcp or _udp boilerplate */
353 if (!(avahi_unescape_label(&t, label, sizeof(label))))
354 return NULL;
356 if (strcasecmp(label, "_tcp") && strcasecmp(label, "_udp"))
357 return NULL;
359 if (*t)
360 return NULL;
362 return ret;
365 int avahi_is_valid_service_subtype(const char *t) {
366 assert(t);
368 return !!avahi_get_type_from_subtype(t);
371 int avahi_is_valid_domain_name(const char *t) {
372 int is_first = 1;
373 assert(t);
375 if (strlen(t) >= AVAHI_DOMAIN_NAME_MAX)
376 return 0;
378 do {
379 char label[AVAHI_LABEL_MAX];
381 if (!(avahi_unescape_label(&t, label, sizeof(label))))
382 return 0;
384 /* Explicitly allow the root domain name */
385 if (is_first && label[0] == 0 && *t == 0)
386 return 1;
388 is_first = 0;
390 if (label[0] == 0)
391 return 0;
393 } while (*t);
395 return 1;
398 int avahi_is_valid_service_name(const char *t) {
399 assert(t);
401 if (strlen(t) >= AVAHI_LABEL_MAX || !*t)
402 return 0;
404 return 1;
407 int avahi_is_valid_host_name(const char *t) {
408 char label[AVAHI_LABEL_MAX];
409 assert(t);
411 if (strlen(t) >= AVAHI_DOMAIN_NAME_MAX || !*t)
412 return 0;
414 if (!(avahi_unescape_label(&t, label, sizeof(label))))
415 return 0;
417 if (strlen(label) < 1)
418 return 0;
420 if (*t)
421 return 0;
423 return 1;
426 unsigned avahi_domain_hash(const char *s) {
427 unsigned hash = 0;
429 while (*s) {
430 char c[AVAHI_LABEL_MAX], *p, *r;
432 r = avahi_unescape_label(&s, c, sizeof(c));
433 assert(r);
435 for (p = c; *p; p++)
436 hash = 31 * hash + tolower(*p);
439 return hash;
442 int avahi_service_name_join(char *p, size_t size, const char *name, const char *type, const char *domain) {
443 char escaped_name[AVAHI_LABEL_MAX*4];
444 char normalized_type[AVAHI_DOMAIN_NAME_MAX];
445 char normalized_domain[AVAHI_DOMAIN_NAME_MAX];
447 assert(p);
449 /* Validity checks */
451 if ((name && !avahi_is_valid_service_name(name)))
452 return AVAHI_ERR_INVALID_SERVICE_NAME;
454 if (!avahi_is_valid_service_type_generic(type))
455 return AVAHI_ERR_INVALID_SERVICE_TYPE;
457 if (!avahi_is_valid_domain_name(domain))
458 return AVAHI_ERR_INVALID_DOMAIN_NAME;
460 /* Preparation */
462 if (name) {
463 size_t l = sizeof(escaped_name);
464 char *e = escaped_name, *r;
465 r = avahi_escape_label(name, strlen(name), &e, &l);
466 assert(r);
469 if (!(avahi_normalize_name(type, normalized_type, sizeof(normalized_type))))
470 return AVAHI_ERR_INVALID_SERVICE_TYPE;
472 if (!(avahi_normalize_name(domain, normalized_domain, sizeof(normalized_domain))))
473 return AVAHI_ERR_INVALID_DOMAIN_NAME;
475 /* Concatenation */
477 snprintf(p, size, "%s%s%s.%s", name ? escaped_name : "", name ? "." : "", normalized_type, normalized_domain);
479 return AVAHI_OK;
482 #ifndef HAVE_STRLCPY
484 static size_t strlcpy(char *dest, const char *src, size_t n) {
485 assert(dest);
486 assert(src);
488 if (n > 0) {
489 strncpy(dest, src, n-1);
490 dest[n-1] = 0;
493 return strlen(src);
496 #endif
498 int avahi_service_name_split(const char *p, char *name, size_t name_size, char *type, size_t type_size, char *domain, size_t domain_size) {
499 enum {
500 NAME,
501 TYPE,
502 DOMAIN
503 } state;
504 int type_empty = 1, domain_empty = 1;
506 assert(p);
507 assert(type);
508 assert(type_size > 0);
509 assert(domain);
510 assert(domain_size > 0);
512 if (name) {
513 assert(name_size > 0);
514 *name = 0;
515 state = NAME;
516 } else
517 state = TYPE;
519 *type = *domain = 0;
521 while (*p) {
522 char buf[64];
524 if (!(avahi_unescape_label(&p, buf, sizeof(buf))))
525 return -1;
527 switch (state) {
528 case NAME:
529 strlcpy(name, buf, name_size);
530 state = TYPE;
531 break;
533 case TYPE:
535 if (buf[0] == '_') {
537 if (!type_empty) {
538 if (!type_size)
539 return AVAHI_ERR_NO_MEMORY;
541 *(type++) = '.';
542 type_size --;
544 } else
545 type_empty = 0;
547 if (!(avahi_escape_label(buf, strlen(buf), &type, &type_size)))
548 return AVAHI_ERR_NO_MEMORY;
550 break;
553 state = DOMAIN;
554 /* fall through */
556 case DOMAIN:
558 if (!domain_empty) {
559 if (!domain_size)
560 return AVAHI_ERR_NO_MEMORY;
562 *(domain++) = '.';
563 domain_size --;
564 } else
565 domain_empty = 0;
567 if (!(avahi_escape_label(buf, strlen(buf), &domain, &domain_size)))
568 return AVAHI_ERR_NO_MEMORY;
570 break;
574 return 0;
577 int avahi_is_valid_fqdn(const char *t) {
578 char label[AVAHI_LABEL_MAX];
579 char normalized[AVAHI_DOMAIN_NAME_MAX];
580 const char *k = t;
581 AvahiAddress a;
582 assert(t);
584 if (strlen(t) >= AVAHI_DOMAIN_NAME_MAX)
585 return 0;
587 if (!avahi_is_valid_domain_name(t))
588 return 0;
590 /* Check if there are at least two labels*/
591 if (!(avahi_unescape_label(&k, label, sizeof(label))))
592 return 0;
594 if (label[0] == 0 || !k)
595 return 0;
597 if (!(avahi_unescape_label(&k, label, sizeof(label))))
598 return 0;
600 if (label[0] == 0 || !k)
601 return 0;
603 /* Make sure that the name is not an IP address */
604 if (!(avahi_normalize_name(t, normalized, sizeof(normalized))))
605 return 0;
607 if (avahi_address_parse(normalized, AVAHI_PROTO_UNSPEC, &a))
608 return 0;
610 return 1;