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
40 char *avahi_get_host_name(char *ret_s, size_t size) {
42 char t[HOST_NAME_MAX];
50 gethostname(t, sizeof(t));
53 return avahi_normalize_name(t, ret_s, size);
56 char *avahi_get_host_name_strdup(void) {
57 char t[AVAHI_DOMAIN_NAME_MAX];
59 if (!(avahi_get_host_name(t, sizeof(t))))
62 return avahi_strdup(t);
65 /* Read the first label from string *name, unescape "\" and write it to dest */
66 char *avahi_unescape_label(const char **name, char *dest, size_t size) {
89 /* Escaped character */
97 else if (**name == '\\' || **name == '.') {
98 /* Escaped backslash or dot */
99 *(d++) = *((*name) ++);
101 } else if (isdigit(**name)) {
104 /* Escaped literal ASCII character */
106 if (!isdigit(*(*name+1)) || !isdigit(*(*name+2)))
109 n = ((uint8_t) (**name - '0') * 100) + ((uint8_t) (*(*name+1) - '0') * 10) + ((uint8_t) (*(*name +2) - '0'));
111 if (n > 255 || n == 0)
123 /* Normal character */
125 *(d++) = *((*name) ++);
137 /* Escape "\" and ".", append \0 */
138 char *avahi_escape_label(const char* src, size_t src_length, char **ret_name, size_t *ret_size) {
145 assert(*ret_size > 0);
149 while (src_length > 0) {
150 if (*src == '.' || *src == '\\') {
152 /* Dot or backslash */
157 *((*ret_name) ++) = '\\';
158 *((*ret_name) ++) = *src;
164 (*src >= '0' && *src <= '9') ||
165 (*src >= 'a' && *src <= 'z') ||
166 (*src >= 'A' && *src <= 'Z')) {
168 /* Proper character */
173 *((*ret_name)++) = *src;
178 /* Everything else */
183 *((*ret_name) ++) = '\\';
184 *((*ret_name) ++) = '0' + (char) ((uint8_t) *src / 100);
185 *((*ret_name) ++) = '0' + (char) (((uint8_t) *src / 10) % 10);
186 *((*ret_name) ++) = '0' + (char) ((uint8_t) *src % 10);
200 char *avahi_normalize_name(const char *s, char *ret_s, size_t size) {
210 char label[AVAHI_LABEL_MAX];
212 if (!(avahi_unescape_label(&s, label, sizeof(label))))
215 if (strlen(label) > 0) {
227 avahi_escape_label(label, strlen(label), &r, &size);
237 char *avahi_normalize_name_strdup(const char *s) {
238 char t[AVAHI_DOMAIN_NAME_MAX];
241 if (!(avahi_normalize_name(s, t, sizeof(t))))
244 return avahi_strdup(t);
247 int avahi_domain_equal(const char *a, const char *b) {
255 char ca[AVAHI_LABEL_MAX], cb[AVAHI_LABEL_MAX], *r;
257 r = avahi_unescape_label(&a, ca, sizeof(ca));
259 r = avahi_unescape_label(&b, cb, sizeof(cb));
262 if (strcasecmp(ca, cb))
272 int avahi_binary_domain_cmp(const char *a, const char *b) {
280 char ca[AVAHI_LABEL_MAX], cb[AVAHI_LABEL_MAX], *p;
283 p = avahi_unescape_label(&a, ca, sizeof(ca));
285 p = avahi_unescape_label(&b, cb, sizeof(cb));
288 if ((r = strcmp(ca, cb)))
296 int avahi_is_valid_service_type_generic(const char *t) {
299 if (strlen(t) >= AVAHI_DOMAIN_NAME_MAX || !*t)
303 char label[AVAHI_LABEL_MAX];
305 if (!(avahi_unescape_label(&t, label, sizeof(label))))
308 if (strlen(label) <= 2 || label[0] != '_')
316 int avahi_is_valid_service_type_strict(const char *t) {
317 char label[AVAHI_LABEL_MAX];
320 if (strlen(t) >= AVAHI_DOMAIN_NAME_MAX || !*t)
323 /* Application name */
325 if (!(avahi_unescape_label(&t, label, sizeof(label))))
328 if (strlen(label) <= 2 || label[0] != '_')
334 /* _tcp or _udp boilerplate */
336 if (!(avahi_unescape_label(&t, label, sizeof(label))))
339 if (strcasecmp(label, "_tcp") && strcasecmp(label, "_udp"))
348 const char *avahi_get_type_from_subtype(const char *t) {
349 char label[AVAHI_LABEL_MAX];
353 if (strlen(t) >= AVAHI_DOMAIN_NAME_MAX || !*t)
358 if (!(avahi_unescape_label(&t, label, sizeof(label))))
361 if (strlen(label) <= 2 || label[0] != '_')
369 if (!(avahi_unescape_label(&t, label, sizeof(label))))
372 if (strcasecmp(label, "_sub"))
380 /* Application name */
382 if (!(avahi_unescape_label(&t, label, sizeof(label))))
385 if (strlen(label) <= 2 || label[0] != '_')
391 /* _tcp or _udp boilerplate */
393 if (!(avahi_unescape_label(&t, label, sizeof(label))))
396 if (strcasecmp(label, "_tcp") && strcasecmp(label, "_udp"))
405 int avahi_is_valid_service_subtype(const char *t) {
408 return !!avahi_get_type_from_subtype(t);
411 int avahi_is_valid_domain_name(const char *t) {
414 if (strlen(t) >= AVAHI_DOMAIN_NAME_MAX || !*t)
418 char label[AVAHI_LABEL_MAX];
420 if (!(avahi_unescape_label(&t, label, sizeof(label))))
423 if (strlen(label) < 1)
431 int avahi_is_valid_service_name(const char *t) {
434 if (strlen(t) >= AVAHI_LABEL_MAX || !*t)
440 int avahi_is_valid_host_name(const char *t) {
441 char label[AVAHI_LABEL_MAX];
444 if (strlen(t) >= AVAHI_DOMAIN_NAME_MAX || !*t)
447 if (!(avahi_unescape_label(&t, label, sizeof(label))))
450 if (strlen(label) < 1)
459 unsigned avahi_domain_hash(const char *s) {
463 char c[AVAHI_LABEL_MAX], *p, *r;
465 r = avahi_unescape_label(&s, c, sizeof(c));
469 hash = 31 * hash + tolower(*p);
475 int avahi_domain_ends_with(const char *domain, const char *suffix) {
480 char dummy[AVAHI_LABEL_MAX], *r;
485 if (avahi_domain_equal(domain, suffix))
488 r = avahi_unescape_label(&domain, dummy, sizeof(dummy));
493 int avahi_service_name_join(char *p, size_t size, const char *name, const char *type, const char *domain) {
494 char escaped_name[AVAHI_LABEL_MAX];
495 char normalized_type[AVAHI_DOMAIN_NAME_MAX];
496 char normalized_domain[AVAHI_DOMAIN_NAME_MAX];
500 /* Validity checks */
502 if ((name && !avahi_is_valid_service_name(name)))
503 return AVAHI_ERR_INVALID_SERVICE_NAME;
505 if (!avahi_is_valid_service_type_generic(type))
506 return AVAHI_ERR_INVALID_SERVICE_TYPE;
508 if (!avahi_is_valid_domain_name(domain))
509 return AVAHI_ERR_INVALID_DOMAIN_NAME;
514 size_t l = sizeof(escaped_name);
515 char *e = escaped_name, *r;
516 r = avahi_escape_label(name, strlen(name), &e, &l);
520 if (!(avahi_normalize_name(type, normalized_type, sizeof(normalized_type))))
521 return AVAHI_ERR_INVALID_SERVICE_TYPE;
523 if (!(avahi_normalize_name(domain, normalized_domain, sizeof(normalized_domain))))
524 return AVAHI_ERR_INVALID_DOMAIN_NAME;
528 snprintf(p, size, "%s%s%s.%s", name ? escaped_name : "", name ? "." : "", normalized_type, normalized_domain);
535 static size_t strlcpy(char *dest, const char *src, size_t n) {
540 strncpy(dest, src, n-1);
549 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) {
555 int type_empty = 1, domain_empty = 1;
559 assert(type_size > 0);
561 assert(domain_size > 0);
564 assert(name_size > 0);
575 if (!(avahi_unescape_label(&p, buf, sizeof(buf))))
580 strlcpy(name, buf, name_size);
590 return AVAHI_ERR_NO_MEMORY;
598 if (!(avahi_escape_label(buf, strlen(buf), &type, &type_size)))
599 return AVAHI_ERR_NO_MEMORY;
611 return AVAHI_ERR_NO_MEMORY;
618 if (!(avahi_escape_label(buf, strlen(buf), &domain, &domain_size)))
619 return AVAHI_ERR_NO_MEMORY;