]> git.meshlink.io Git - catta/blob - avahi-common/util.c
a41475a3b7242d11ef9eb7fa67423fd01cad8bad
[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
35 #include "util.h"
36
37 gchar *avahi_get_host_name(void) {
38 #ifdef HOST_NAME_MAX
39     char t[HOST_NAME_MAX];
40 #else
41     char t[256];
42 #endif
43     gethostname(t, sizeof(t));
44     t[sizeof(t)-1] = 0;
45     return avahi_normalize_name(t);
46 }
47
48 static gchar *unescape_uneeded(const gchar *src, gchar *ret_dest, size_t size) {
49     gboolean escaped = FALSE;
50     
51     g_assert(src);
52     g_assert(ret_dest);
53     g_assert(size > 0);
54     
55     for (; *src; src++) {
56
57         if (!escaped && *src == '\\')
58             escaped = TRUE;
59         else if (escaped && (*src == '.' || *src == '\\')) {
60
61             if ((size -= 2) <= 1) break;
62             
63             *(ret_dest++) = '\\';
64             *(ret_dest++) = *src;
65             escaped = FALSE;
66         } else {
67             if (--size <= 1) break;
68
69             *(ret_dest++) = *src;
70             escaped = FALSE;
71         }
72
73     }
74
75     *ret_dest = 0;
76     
77     return ret_dest;
78 }
79
80 gchar *avahi_normalize_name(const gchar *s) {
81     gchar tmp[256];
82     gchar *n, *t;
83     guint l;
84     g_assert(s);
85
86     unescape_uneeded(s, tmp, sizeof(tmp));
87
88     n = g_utf8_normalize(tmp, -1, G_NORMALIZE_DEFAULT);
89
90     if ((l = strlen(n)) == 0) {
91         g_free(n);
92         return g_strdup(".");
93     }
94
95     if (n[l-1] == '.')
96         return n;
97
98     t = g_strdup_printf("%s.", n);
99     g_free(n);
100     return t;
101 }
102
103 gint avahi_timeval_compare(const GTimeVal *a, const GTimeVal *b) {
104     g_assert(a);
105     g_assert(b);
106
107     if (a->tv_sec < b->tv_sec)
108         return -1;
109
110     if (a->tv_sec > b->tv_sec)
111         return 1;
112
113     if (a->tv_usec < b->tv_usec)
114         return -1;
115
116     if (a->tv_usec > b->tv_usec)
117         return 1;
118
119     return 0;
120 }
121
122 glong avahi_timeval_diff(const GTimeVal *a, const GTimeVal *b) {
123     g_assert(a);
124     g_assert(b);
125
126     if (avahi_timeval_compare(a, b) < 0)
127         return avahi_timeval_diff(b, a);
128
129     return ((glong) a->tv_sec - b->tv_sec)*1000000 + a->tv_usec - b->tv_usec;
130 }
131
132
133 gint avahi_set_cloexec(gint fd) {
134     gint n;
135
136     g_assert(fd >= 0);
137     
138     if ((n = fcntl(fd, F_GETFD)) < 0)
139         return -1;
140
141     if (n & FD_CLOEXEC)
142         return 0;
143
144     return fcntl(fd, F_SETFD, n|FD_CLOEXEC);
145 }
146
147 gint avahi_set_nonblock(gint fd) {
148     gint n;
149
150     g_assert(fd >= 0);
151
152     if ((n = fcntl(fd, F_GETFL)) < 0)
153         return -1;
154
155     if (n & O_NONBLOCK)
156         return 0;
157
158     return fcntl(fd, F_SETFL, n|O_NONBLOCK);
159 }
160
161 gint avahi_wait_for_write(gint fd) {
162     fd_set fds;
163     gint r;
164     
165     FD_ZERO(&fds);
166     FD_SET(fd, &fds);
167     
168     if ((r = select(fd+1, NULL, &fds, NULL, NULL)) < 0) {
169         g_message("select() failed: %s", strerror(errno));
170
171         return -1;
172     }
173     
174     g_assert(r > 0);
175
176     return 0;
177 }
178
179 GTimeVal *avahi_elapse_time(GTimeVal *tv, guint msec, guint jitter) {
180     g_assert(tv);
181
182     g_get_current_time(tv);
183
184     if (msec)
185         g_time_val_add(tv, msec*1000);
186
187     if (jitter)
188         g_time_val_add(tv, g_random_int_range(0, jitter) * 1000);
189         
190     return tv;
191 }
192
193 glong avahi_age(const GTimeVal *a) {
194     GTimeVal now;
195     
196     g_assert(a);
197
198     g_get_current_time(&now);
199
200     return avahi_timeval_diff(&now, a);
201 }
202
203 /* Read the first label from string *name, unescape "\" and write it to dest */
204 gchar *avahi_unescape_label(const gchar **name, gchar *dest, guint size) {
205     guint i = 0;
206     gchar *d;
207     
208     g_assert(dest);
209     g_assert(size > 0);
210     g_assert(name);
211
212     if (!**name)
213         return NULL;
214
215     d = dest;
216     
217     for (;;) {
218         if (i >= size)
219             return NULL;
220
221         if (**name == '.') {
222             (*name)++;
223             break;
224         }
225         
226         if (**name == 0)
227             break;
228         
229         if (**name == '\\') {
230             (*name) ++;
231             
232             if (**name == 0)
233                 break;
234         }
235         
236         *(d++) = *((*name) ++);
237         i++;
238     }
239
240     g_assert(i < size);
241
242     *d = 0;
243
244     return dest;
245 }
246
247 /* Escape "\" and ".", append \0 */
248 gchar *avahi_escape_label(const guint8* src, guint src_length, gchar **ret_name, guint *ret_size) {
249     gchar *r;
250
251     g_assert(src);
252     g_assert(ret_name);
253     g_assert(*ret_name);
254     g_assert(ret_size);
255     g_assert(*ret_size > 0);
256
257     r = *ret_name;
258
259     while (src_length > 0) {
260         if (*src == '.' || *src == '\\') {
261             if (*ret_size < 3)
262                 return NULL;
263             
264             *((*ret_name) ++) = '\\';
265             (*ret_size) --;
266         }
267
268         if (*ret_size < 2)
269             return NULL;
270         
271         *((*ret_name)++) = *src;
272         (*ret_size) --;
273
274         src_length --;
275         src++;
276     }
277
278     **ret_name = 0;
279
280     return r;
281 }
282
283 static gint utf8_strcasecmp(const gchar *a, const gchar *b) {
284     gchar *ta, *tb;
285     gint r;
286     
287     g_assert(a);
288     g_assert(b);
289
290     ta = g_utf8_casefold(a, -1);
291     tb = g_utf8_casefold(b, -1);
292     r = g_utf8_collate(ta, tb);
293     g_free(ta);
294     g_free(tb);
295
296     return r;
297 }
298
299 gboolean avahi_domain_equal(const gchar *a, const gchar *b) {
300     g_assert(a);
301     g_assert(b);
302
303     if (a == b)
304         return TRUE;
305     
306     for (;;) {
307         gchar ca[65], cb[65], *pa, *pb;
308
309         pa = avahi_unescape_label(&a, ca, sizeof(ca));
310         pb = avahi_unescape_label(&b, cb, sizeof(cb));
311
312         if (!pa && !pb)
313             return TRUE;
314         else if ((pa && !pb) || (!pa && pb))
315             return FALSE;
316
317         if (utf8_strcasecmp(pa, pb))
318             return FALSE;
319     }
320
321     return TRUE;
322 }
323
324 gint avahi_binary_domain_cmp(const gchar *a, const gchar *b) {
325     g_assert(a);
326     g_assert(b);
327
328     if (a == b)
329         return 0;
330
331     for (;;) {
332         gchar ca[65], cb[65], *pa, *pb;
333         gint r;
334
335         pa = avahi_unescape_label(&a, ca, sizeof(ca));
336         pb = avahi_unescape_label(&b, cb, sizeof(cb));
337
338         if (!pa && !pb)
339             return 0;
340         else if (pa && !pb)
341             return 1;
342         else if (!pa && pb)
343             return -1;
344         
345         if ((r = strcmp(pa, pb)))
346             return r;
347     }
348 }
349
350 void avahi_hexdump(gconstpointer p, guint size) {
351     const guint8 *c = p;
352     g_assert(p);
353
354     printf("Dumping %u bytes from %p:\n", size, p);
355     
356     while (size > 0) {
357         guint i;
358
359         for (i = 0; i < 16; i++) { 
360             if (i < size)
361                 printf("%02x ", c[i]);
362             else
363                 printf("   ");
364         }
365
366         for (i = 0; i < 16; i++) {
367             if (i < size)
368                 printf("%c", c[i] >= 32 && c[i] < 127 ? c[i] : '.');
369             else
370                 printf(" ");
371         }
372         
373         printf("\n");
374
375         c += 16;
376
377         if (size <= 16)
378             break;
379         
380         size -= 16;
381     }
382 }
383
384 guint avahi_domain_hash(const gchar *s) {
385     guint hash = 0;
386     
387     for (;;) {
388         gchar c[65], *n, *m;
389
390         if (!avahi_unescape_label(&s, c, sizeof(c)))
391             return hash;
392
393         if (!c[0])
394             continue;
395         
396         n = g_utf8_normalize(c, -1, G_NORMALIZE_DEFAULT);
397         m = g_utf8_strdown(n, -1);
398
399         hash += g_str_hash(m);
400
401         g_free(m);
402         g_free(n);
403     }
404 }
405
406 gchar *avahi_format_mac_address(const guint8* mac, guint size) {
407     gchar *r, *t;
408     guint i;
409     static const gchar hex[] = "0123456789abcdef";
410
411     t = r = g_new(gchar, size > 0 ? size*3 : 1);
412
413     if (size <= 0) {
414         *r = 0;
415         return r;
416     }
417     
418     for (i = 0; i < size; i++) {
419         *(t++) = hex[*mac >> 4];
420         *(t++) = hex[*mac & 0xF];
421         *(t++) = ':';
422
423         mac++;
424     }
425
426     *(--t) = 0;
427     return r;
428 }