]> git.meshlink.io Git - catta/blob - avahi-common/util.c
improve documentation
[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 glong 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 ((glong) a->tv_sec - b->tv_sec)*1000000 + a->tv_usec - b->tv_usec;
123 }
124
125
126 gint avahi_set_cloexec(gint fd) {
127     gint n;
128
129     g_assert(fd >= 0);
130     
131     if ((n = fcntl(fd, F_GETFD)) < 0)
132         return -1;
133
134     if (n & FD_CLOEXEC)
135         return 0;
136
137     return fcntl(fd, F_SETFD, n|FD_CLOEXEC);
138 }
139
140 gint avahi_set_nonblock(gint fd) {
141     gint n;
142
143     g_assert(fd >= 0);
144
145     if ((n = fcntl(fd, F_GETFL)) < 0)
146         return -1;
147
148     if (n & O_NONBLOCK)
149         return 0;
150
151     return fcntl(fd, F_SETFL, n|O_NONBLOCK);
152 }
153
154 gint avahi_wait_for_write(gint fd) {
155     fd_set fds;
156     gint r;
157     
158     FD_ZERO(&fds);
159     FD_SET(fd, &fds);
160     
161     if ((r = select(fd+1, NULL, &fds, NULL, NULL)) < 0) {
162         g_message("select() failed: %s", strerror(errno));
163
164         return -1;
165     }
166     
167     g_assert(r > 0);
168
169     return 0;
170 }
171
172 GTimeVal *avahi_elapse_time(GTimeVal *tv, guint msec, guint jitter) {
173     g_assert(tv);
174
175     g_get_current_time(tv);
176
177     if (msec)
178         g_time_val_add(tv, msec*1000);
179
180     if (jitter)
181         g_time_val_add(tv, g_random_int_range(0, jitter) * 1000);
182         
183     return tv;
184 }
185
186 glong avahi_age(const GTimeVal *a) {
187     GTimeVal now;
188     
189     g_assert(a);
190
191     g_get_current_time(&now);
192
193     return avahi_timeval_diff(&now, a);
194 }
195
196 /* Read the first label from string *name, unescape "\" and write it to dest */
197 gchar *avahi_unescape_label(const gchar **name, gchar *dest, guint size) {
198     guint i = 0;
199     gchar *d;
200     
201     g_assert(dest);
202     g_assert(size > 0);
203     g_assert(name);
204
205     if (!**name)
206         return NULL;
207
208     d = dest;
209     
210     for (;;) {
211         if (i >= size)
212             return NULL;
213
214         if (**name == '.') {
215             (*name)++;
216             break;
217         }
218         
219         if (**name == 0)
220             break;
221         
222         if (**name == '\\') {
223             (*name) ++;
224             
225             if (**name == 0)
226                 break;
227         }
228         
229         *(d++) = *((*name) ++);
230         i++;
231     }
232
233     g_assert(i < size);
234
235     *d = 0;
236
237     return dest;
238 }
239
240 /* Escape "\" and ".", append \0 */
241 gchar *avahi_escape_label(const guint8* src, guint src_length, gchar **ret_name, guint *ret_size) {
242     gchar *r;
243
244     g_assert(src);
245     g_assert(ret_name);
246     g_assert(*ret_name);
247     g_assert(ret_size);
248     g_assert(*ret_size > 0);
249
250     r = *ret_name;
251
252     while (src_length > 0) {
253         if (*src == '.' || *src == '\\') {
254             if (*ret_size < 3)
255                 return NULL;
256             
257             *((*ret_name) ++) = '\\';
258             (*ret_size) --;
259         }
260
261         if (*ret_size < 2)
262             return NULL;
263         
264         *((*ret_name)++) = *src;
265         (*ret_size) --;
266
267         src_length --;
268         src++;
269     }
270
271     **ret_name = 0;
272
273     return r;
274 }
275
276 gboolean avahi_domain_equal(const gchar *a, const gchar *b) {
277     g_assert(a);
278     g_assert(b);
279
280     if (a == b)
281         return TRUE;
282     
283     for (;;) {
284         gchar ca[65], cb[65], *pa, *pb;
285
286         pa = avahi_unescape_label(&a, ca, sizeof(ca));
287         pb = avahi_unescape_label(&b, cb, sizeof(cb));
288
289         if (!pa && !pb)
290             return TRUE;
291         else if ((pa && !pb) || (!pa && pb))
292             return FALSE;
293
294         if (g_ascii_strcasecmp(pa, pb))
295             return FALSE;
296     }
297
298     return TRUE;
299 }
300
301 gint avahi_binary_domain_cmp(const gchar *a, const gchar *b) {
302     g_assert(a);
303     g_assert(b);
304
305     if (a == b)
306         return 0;
307
308     for (;;) {
309         gchar ca[65], cb[65], *pa, *pb;
310         gint r;
311
312         pa = avahi_unescape_label(&a, ca, sizeof(ca));
313         pb = avahi_unescape_label(&b, cb, sizeof(cb));
314
315         if (!pa && !pb)
316             return 0;
317         else if (pa && !pb)
318             return 1;
319         else if (!pa && pb)
320             return -1;
321         
322         if ((r = strcmp(pa, pb)))
323             return r;
324     }
325 }
326
327 void avahi_hexdump(gconstpointer p, guint size) {
328     const guint8 *c = p;
329     g_assert(p);
330
331     printf("Dumping %u bytes from %p:\n", size, p);
332     
333     while (size > 0) {
334         guint i;
335
336         for (i = 0; i < 16; i++) { 
337             if (i < size)
338                 printf("%02x ", c[i]);
339             else
340                 printf("   ");
341         }
342
343         for (i = 0; i < 16; i++) {
344             if (i < size)
345                 printf("%c", c[i] >= 32 && c[i] < 127 ? c[i] : '.');
346             else
347                 printf(" ");
348         }
349         
350         printf("\n");
351
352         c += 16;
353
354         if (size <= 16)
355             break;
356         
357         size -= 16;
358     }
359 }
360
361 guint avahi_domain_hash(const gchar *s) {
362     guint hash = 0;
363     
364     for (;;) {
365         gchar c[65], *m;
366
367         if (!avahi_unescape_label(&s, c, sizeof(c)))
368             return hash;
369
370         if (!c[0])
371             continue;
372         
373         m = g_ascii_strdown(c, -1);
374         hash += g_str_hash(m);
375         g_free(m);
376     }
377 }
378
379 gchar *avahi_format_mac_address(const guint8* mac, guint size) {
380     gchar *r, *t;
381     guint i;
382     static const gchar hex[] = "0123456789abcdef";
383
384     t = r = g_new(gchar, size > 0 ? size*3 : 1);
385
386     if (size <= 0) {
387         *r = 0;
388         return r;
389     }
390     
391     for (i = 0; i < size; i++) {
392         *(t++) = hex[*mac >> 4];
393         *(t++) = hex[*mac & 0xF];
394         *(t++) = ':';
395
396         mac++;
397     }
398
399     *(--t) = 0;
400     return r;
401 }