]> git.meshlink.io Git - catta/blob - avahi-common/util.c
* Change timeval arithmetic functions to use 64bit integers. This fixes some problems...
[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     guint l;
83     g_assert(s);
84
85     unescape_uneeded(s, tmp, sizeof(tmp));
86
87     if ((l = strlen(tmp)) == 0)
88         return g_strdup(".");
89
90     if (tmp[l-1] == '.')
91         return g_strdup(tmp);
92
93     return g_strdup_printf("%s.", tmp);
94 }
95
96 gint avahi_timeval_compare(const GTimeVal *a, const GTimeVal *b) {
97     g_assert(a);
98     g_assert(b);
99
100     if (a->tv_sec < b->tv_sec)
101         return -1;
102
103     if (a->tv_sec > b->tv_sec)
104         return 1;
105
106     if (a->tv_usec < b->tv_usec)
107         return -1;
108
109     if (a->tv_usec > b->tv_usec)
110         return 1;
111
112     return 0;
113 }
114
115 AvahiUsec avahi_timeval_diff(const GTimeVal *a, const GTimeVal *b) {
116     g_assert(a);
117     g_assert(b);
118
119     if (avahi_timeval_compare(a, b) < 0)
120         return - avahi_timeval_diff(b, a);
121
122     return ((AvahiUsec) a->tv_sec - b->tv_sec)*1000000 + a->tv_usec - b->tv_usec;
123 }
124
125 GTimeVal* avahi_timeval_add(GTimeVal *a, AvahiUsec usec) {
126     AvahiUsec u;
127     g_assert(a);
128
129     u = usec + a->tv_usec;
130
131     if (u < 0) {
132         a->tv_usec = (glong) (1000000 + (u % 1000000));
133         a->tv_sec += (glong) (-1 + (u / 1000000));
134     } else {
135         a->tv_usec = (glong) (u % 1000000);
136         a->tv_sec += (glong) (u / 1000000);
137     }
138
139     return a;
140 }
141
142 AvahiUsec avahi_age(const GTimeVal *a) {
143     GTimeVal now;
144     
145     g_assert(a);
146
147     g_get_current_time(&now);
148
149     return avahi_timeval_diff(&now, a);
150 }
151
152 GTimeVal *avahi_elapse_time(GTimeVal *tv, guint msec, guint jitter) {
153     g_assert(tv);
154
155     g_get_current_time(tv);
156
157     if (msec)
158         avahi_timeval_add(tv, (AvahiUsec) msec*1000);
159
160     if (jitter)
161         avahi_timeval_add(tv, (AvahiUsec) g_random_int_range(0, jitter) * 1000);
162         
163     return tv;
164 }
165
166 gint avahi_set_cloexec(gint fd) {
167     gint n;
168
169     g_assert(fd >= 0);
170     
171     if ((n = fcntl(fd, F_GETFD)) < 0)
172         return -1;
173
174     if (n & FD_CLOEXEC)
175         return 0;
176
177     return fcntl(fd, F_SETFD, n|FD_CLOEXEC);
178 }
179
180 gint avahi_set_nonblock(gint fd) {
181     gint n;
182
183     g_assert(fd >= 0);
184
185     if ((n = fcntl(fd, F_GETFL)) < 0)
186         return -1;
187
188     if (n & O_NONBLOCK)
189         return 0;
190
191     return fcntl(fd, F_SETFL, n|O_NONBLOCK);
192 }
193
194 gint avahi_wait_for_write(gint fd) {
195     fd_set fds;
196     gint r;
197     
198     FD_ZERO(&fds);
199     FD_SET(fd, &fds);
200     
201     if ((r = select(fd+1, NULL, &fds, NULL, NULL)) < 0) {
202         g_message("select() failed: %s", strerror(errno));
203
204         return -1;
205     }
206     
207     g_assert(r > 0);
208
209     return 0;
210 }
211
212 /* Read the first label from string *name, unescape "\" and write it to dest */
213 gchar *avahi_unescape_label(const gchar **name, gchar *dest, guint size) {
214     guint i = 0;
215     gchar *d;
216     
217     g_assert(dest);
218     g_assert(size > 0);
219     g_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     g_assert(i < size);
250
251     *d = 0;
252
253     return dest;
254 }
255
256 /* Escape "\" and ".", append \0 */
257 gchar *avahi_escape_label(const guint8* src, guint src_length, gchar **ret_name, guint *ret_size) {
258     gchar *r;
259
260     g_assert(src);
261     g_assert(ret_name);
262     g_assert(*ret_name);
263     g_assert(ret_size);
264     g_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 gboolean avahi_domain_equal(const gchar *a, const gchar *b) {
293     g_assert(a);
294     g_assert(b);
295
296     if (a == b)
297         return TRUE;
298     
299     for (;;) {
300         gchar 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 TRUE;
307         else if ((pa && !pb) || (!pa && pb))
308             return FALSE;
309
310         if (g_ascii_strcasecmp(pa, pb))
311             return FALSE;
312     }
313
314     return TRUE;
315 }
316
317 gint avahi_binary_domain_cmp(const gchar *a, const gchar *b) {
318     g_assert(a);
319     g_assert(b);
320
321     if (a == b)
322         return 0;
323
324     for (;;) {
325         gchar ca[65], cb[65], *pa, *pb;
326         gint 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(gconstpointer p, guint size) {
344     const guint8 *c = p;
345     g_assert(p);
346
347     printf("Dumping %u bytes from %p:\n", size, p);
348     
349     while (size > 0) {
350         guint 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 guint avahi_domain_hash(const gchar *s) {
378     guint hash = 0;
379     
380     for (;;) {
381         gchar c[65], *m;
382
383         if (!avahi_unescape_label(&s, c, sizeof(c)))
384             return hash;
385
386         if (!c[0])
387             continue;
388         
389         m = g_ascii_strdown(c, -1);
390         hash += g_str_hash(m);
391         g_free(m);
392     }
393 }
394
395 gchar *avahi_format_mac_address(const guint8* mac, guint size) {
396     gchar *r, *t;
397     guint i;
398     static const gchar hex[] = "0123456789abcdef";
399
400     t = r = g_new(gchar, size > 0 ? size*3 : 1);
401
402     if (size <= 0) {
403         *r = 0;
404         return r;
405     }
406     
407     for (i = 0; i < size; i++) {
408         *(t++) = hex[*mac >> 4];
409         *(t++) = hex[*mac & 0xF];
410         *(t++) = ':';
411
412         mac++;
413     }
414
415     *(--t) = 0;
416     return r;
417 }