]> git.meshlink.io Git - catta/blob - avahi-common/util.c
* drop glib from avahi-common
[catta] / avahi-common / util.c
1 /* $Id$ */
2
3 /***
4   This file is part of avahi.
5  
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.
10  
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.
15  
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.
20 ***/
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
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>
35
36 #include "util.h"
37 #include "malloc.h"
38
39 char *avahi_get_host_name(void) {
40 #ifdef HOST_NAME_MAX
41     char t[HOST_NAME_MAX];
42 #else
43     char t[256];
44 #endif
45     gethostname(t, sizeof(t));
46     t[sizeof(t)-1] = 0;
47     return avahi_normalize_name(t);
48 }
49
50 static char *unescape_uneeded(const char *src, char *ret_dest, size_t size) {
51     int escaped = 0;
52     
53     assert(src);
54     assert(ret_dest);
55     assert(size > 0);
56     
57     for (; *src; src++) {
58
59         if (!escaped && *src == '\\')
60             escaped = 1;
61         else if (escaped && (*src == '.' || *src == '\\')) {
62
63             if ((size -= 2) <= 1) break;
64             
65             *(ret_dest++) = '\\';
66             *(ret_dest++) = *src;
67             escaped = 0;
68         } else {
69             if (--size <= 1) break;
70
71             *(ret_dest++) = *src;
72             escaped = 0;
73         }
74
75     }
76
77     *ret_dest = 0;
78     
79     return ret_dest;
80 }
81
82 char *avahi_normalize_name(const char *s) {
83     char tmp[256];
84     size_t l;
85     
86     assert(s);
87
88     unescape_uneeded(s, tmp, sizeof(tmp));
89
90     l = strlen(tmp);
91
92     while (l > 0 && tmp[l-1] == '.')
93         tmp[--l] = 0;
94
95     return avahi_strdup(tmp);
96 }
97
98 int avahi_timeval_compare(const struct timeval *a, const struct timeval *b) {
99     assert(a);
100     assert(b);
101
102     if (a->tv_sec < b->tv_sec)
103         return -1;
104
105     if (a->tv_sec > b->tv_sec)
106         return 1;
107
108     if (a->tv_usec < b->tv_usec)
109         return -1;
110
111     if (a->tv_usec > b->tv_usec)
112         return 1;
113
114     return 0;
115 }
116
117 AvahiUsec avahi_timeval_diff(const struct timeval *a, const struct timeval *b) {
118     assert(a);
119     assert(b);
120
121     if (avahi_timeval_compare(a, b) < 0)
122         return - avahi_timeval_diff(b, a);
123
124     return ((AvahiUsec) a->tv_sec - b->tv_sec)*1000000 + a->tv_usec - b->tv_usec;
125 }
126
127 struct timeval* avahi_timeval_add(struct timeval *a, AvahiUsec usec) {
128     AvahiUsec u;
129     assert(a);
130
131     u = usec + a->tv_usec;
132
133     if (u < 0) {
134         a->tv_usec = (long) (1000000 + (u % 1000000));
135         a->tv_sec += (long) (-1 + (u / 1000000));
136     } else {
137         a->tv_usec = (long) (u % 1000000);
138         a->tv_sec += (long) (u / 1000000);
139     }
140
141     return a;
142 }
143
144 AvahiUsec avahi_age(const struct timeval *a) {
145     struct timeval now;
146     
147     assert(a);
148
149     gettimeofday(&now, NULL);
150
151     return avahi_timeval_diff(&now, a);
152 }
153
154
155 struct timeval *avahi_elapse_time(struct timeval *tv, unsigned msec, unsigned jitter) {
156     assert(tv);
157
158     gettimeofday(tv, NULL);
159
160     if (msec)
161         avahi_timeval_add(tv, (AvahiUsec) msec*1000);
162
163     if (jitter)
164         avahi_timeval_add(tv, (AvahiUsec) (jitter*1000.0*rand()/(RAND_MAX+1.0)));
165         
166     return tv;
167 }
168
169 int avahi_set_cloexec(int fd) {
170     int n;
171
172     assert(fd >= 0);
173     
174     if ((n = fcntl(fd, F_GETFD)) < 0)
175         return -1;
176
177     if (n & FD_CLOEXEC)
178         return 0;
179
180     return fcntl(fd, F_SETFD, n|FD_CLOEXEC);
181 }
182
183 int avahi_set_nonblock(int fd) {
184     int n;
185     
186     assert(fd >= 0);
187
188     if ((n = fcntl(fd, F_GETFL)) < 0)
189         return -1;
190
191     if (n & O_NONBLOCK)
192         return 0;
193
194     return fcntl(fd, F_SETFL, n|O_NONBLOCK);
195 }
196
197 int avahi_wait_for_write(int fd) {
198     fd_set fds;
199     int r;
200     
201     FD_ZERO(&fds);
202     FD_SET(fd, &fds);
203     
204     if ((r = select(fd+1, NULL, &fds, NULL, NULL)) < 0)
205         return -1;
206     
207     assert(r > 0);
208
209     return 0;
210 }
211
212 /* Read the first label from string *name, unescape "\" and write it to dest */
213 char *avahi_unescape_label(const char **name, char *dest, size_t size) {
214     unsigned i = 0;
215     char *d;
216     
217     assert(dest);
218     assert(size > 0);
219     assert(name);
220
221     if (!**name)
222         return NULL;
223
224     d = dest;
225     
226     for (;;) {
227         if (i >= size)
228             return NULL;
229
230         if (**name == '.') {
231             (*name)++;
232             break;
233         }
234         
235         if (**name == 0)
236             break;
237         
238         if (**name == '\\') {
239             (*name) ++;
240             
241             if (**name == 0)
242                 break;
243         }
244         
245         *(d++) = *((*name) ++);
246         i++;
247     }
248
249     assert(i < size);
250
251     *d = 0;
252
253     return dest;
254 }
255
256 /* Escape "\" and ".", append \0 */
257 char *avahi_escape_label(const uint8_t* src, size_t src_length, char **ret_name, size_t *ret_size) {
258     char *r;
259
260     assert(src);
261     assert(ret_name);
262     assert(*ret_name);
263     assert(ret_size);
264     assert(*ret_size > 0);
265
266     r = *ret_name;
267
268     while (src_length > 0) {
269         if (*src == '.' || *src == '\\') {
270             if (*ret_size < 3)
271                 return NULL;
272             
273             *((*ret_name) ++) = '\\';
274             (*ret_size) --;
275         }
276
277         if (*ret_size < 2)
278             return NULL;
279         
280         *((*ret_name)++) = *src;
281         (*ret_size) --;
282
283         src_length --;
284         src++;
285     }
286
287     **ret_name = 0;
288
289     return r;
290 }
291
292 int avahi_domain_equal(const char *a, const char *b) {
293     assert(a);
294     assert(b);
295
296     if (a == b)
297         return 1;
298     
299     for (;;) {
300         char ca[65], cb[65], *pa, *pb;
301
302         pa = avahi_unescape_label(&a, ca, sizeof(ca));
303         pb = avahi_unescape_label(&b, cb, sizeof(cb));
304
305         if (!pa && !pb)
306             return 1;
307         else if ((pa && !pb) || (!pa && pb))
308             return 0;
309
310         if (strcasecmp(pa, pb))
311             return 0;
312     }
313
314     return 1;
315 }
316
317 int avahi_binary_domain_cmp(const char *a, const char *b) {
318     assert(a);
319     assert(b);
320
321     if (a == b)
322         return 0;
323
324     for (;;) {
325         char ca[65], cb[65], *pa, *pb;
326         int r;
327
328         pa = avahi_unescape_label(&a, ca, sizeof(ca));
329         pb = avahi_unescape_label(&b, cb, sizeof(cb));
330
331         if (!pa && !pb)
332             return 0;
333         else if (pa && !pb)
334             return 1;
335         else if (!pa && pb)
336             return -1;
337         
338         if ((r = strcmp(pa, pb)))
339             return r;
340     }
341 }
342
343 void avahi_hexdump(const void* p, size_t size) {
344     const uint8_t *c = p;
345     assert(p);
346
347     printf("Dumping %u bytes from %p:\n", size, p);
348     
349     while (size > 0) {
350         unsigned i;
351
352         for (i = 0; i < 16; i++) { 
353             if (i < size)
354                 printf("%02x ", c[i]);
355             else
356                 printf("   ");
357         }
358
359         for (i = 0; i < 16; i++) {
360             if (i < size)
361                 printf("%c", c[i] >= 32 && c[i] < 127 ? c[i] : '.');
362             else
363                 printf(" ");
364         }
365         
366         printf("\n");
367
368         c += 16;
369
370         if (size <= 16)
371             break;
372         
373         size -= 16;
374     }
375 }
376
377 unsigned avahi_strhash(const char *p) {
378     unsigned hash = 0;
379
380     for (; *p; p++)
381         hash = 31 * hash + *p;
382
383     return hash;
384 }
385
386 unsigned avahi_domain_hash(const char *s) {
387     unsigned hash = 0;
388     
389     for (;;) {
390         char c[65];
391
392         if (!avahi_unescape_label(&s, c, sizeof(c)))
393             return hash;
394
395         if (!c[0])
396             continue;
397         
398         hash += avahi_strhash(avahi_strdown(c));
399     }
400 }
401
402 char *avahi_format_mac_address(const uint8_t* mac, size_t size) {
403     char *r, *t;
404     unsigned i;
405     static const char hex[] = "0123456789abcdef";
406
407     t = r = avahi_new(char, size > 0 ? size*3 : 1);
408
409     if (size <= 0) {
410         *r = 0;
411         return r;
412     }
413     
414     for (i = 0; i < size; i++) {
415         *(t++) = hex[*mac >> 4];
416         *(t++) = hex[*mac & 0xF];
417         *(t++) = ':';
418
419         mac++;
420     }
421
422     *(--t) = 0;
423     return r;
424 }
425
426 int avahi_valid_service_type(const char *t) {
427     const char *p;
428     assert(t);
429
430     if (strlen(t) < 5)
431         return 0;
432     
433     if (*t != '_')
434         return 0;
435
436     if (!(p = strchr(t, '.')))
437         return 0;
438
439     if (p - t > 63 || p - t < 2)
440         return 0;
441
442     if (*(++p) != '_')
443         return 0;
444
445     if (strchr(p, '.'))
446         return 0;
447
448     if (strlen(p) > 63 || strlen(p) < 2)
449         return 0;
450     
451     return 1;
452 }
453
454 int avahi_valid_domain_name(const char *t) {
455     const char *p, *dp;
456     int dot = 0;
457         
458     assert(t);
459
460     if (*t == 0)
461         return 0;
462
463     /* Domains may not start with a dot */
464     if (*t == '.')
465         return 0;
466
467     dp = t; 
468
469     for (p = t; *p; p++) {
470
471         if (*p == '.') {
472             if (dot) /* Two subsequent dots */
473                 return 0;
474
475             if (p - dp > 63)
476                 return 0;
477
478             dot = 1;
479             dp = p + 1;
480         } else
481             dot = 0;
482
483     }
484
485     if (p - dp > 63)
486         return 0;
487
488     /* A trailing dot IS allowed */
489     
490     return 1;
491 }
492
493 int avahi_valid_service_name(const char *t) {
494     assert(t);
495
496     if (*t == 0)
497         return 0;
498
499     if (strlen(t) > 63)
500         return 0;
501
502     return 1;
503 }
504
505 int avahi_valid_host_name(const char *t) {
506     assert(t);
507
508     if (*t == 0)
509         return 0;
510
511     if (strlen(t) > 63)
512         return 0;
513
514     if (strchr(t, '.'))
515         return 0;
516
517     return 1;
518 }
519
520 char *avahi_strdown(char *s) {
521     char *c;
522     
523     assert(s);
524
525     for (c = s; *c; c++)
526         *c = (char) tolower(*c);
527
528     return s;
529 }
530
531 char *avahi_strup(char *s) {
532     char *c;
533     assert(s);
534
535     for (c = s; *c; c++)
536         *c = (char) toupper(*c);
537
538     return s;
539 }
540