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