55d9154064f0f44ab588d322378e3c377b4164bc
[asterisk/asterisk.git] / utils.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * Utility functions
5  *
6  * Copyright (C) 2004, Digium
7  *
8  * This program is free software, distributed under the terms of
9  * the GNU General Public License
10  */
11
12 #ifdef Linux    /* For strcasestr */
13 #define __USE_GNU
14 #endif
15 #include <ctype.h>
16 #include <string.h>
17 #include <unistd.h>
18 #include <stdlib.h>
19 #include <errno.h>
20 #include <stdio.h>
21 #include <sys/types.h>
22 #include <sys/socket.h>
23 #include <netinet/in.h>
24 #include <arpa/inet.h>
25 #include <asterisk/lock.h>
26 #include <asterisk/utils.h>
27 #include <asterisk/logger.h>
28
29 static char base64[64];
30 static char b2a[256];
31
32 char *ast_strip(char *buf)
33 {
34         char *start;
35         /* Strip off trailing whitespace, returns, etc */
36         while (!ast_strlen_zero(buf) && (buf[strlen(buf)-1]<33))
37                 buf[strlen(buf)-1] = '\0';
38         start = buf;
39         /* Strip off leading whitespace, returns, etc */
40         while (*start && (*start < 33))
41                 *start++ = '\0';
42         return start;
43 }
44
45 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined( __NetBSD__ ) || defined(__APPLE__)
46
47 /* duh? ERANGE value copied from web... */
48 #define ERANGE 34
49 #undef gethostbyname
50
51 AST_MUTEX_DEFINE_STATIC(__mutex);
52
53 /* Recursive replacement for gethostbyname for BSD-based systems */
54 static int gethostbyname_r (const char *name, struct hostent *ret, char *buf,
55                                 size_t buflen, struct hostent **result, 
56                                 int *h_errnop) 
57 {
58         int hsave;
59         struct hostent *ph;
60         ast_mutex_lock(&__mutex); /* begin critical area */
61         hsave = h_errno;
62
63         ph = gethostbyname(name);
64         *h_errnop = h_errno; /* copy h_errno to *h_herrnop */
65         if (ph == NULL) {
66                 *result = NULL;
67         } else {
68                 char **p, **q;
69                 char *pbuf;
70                 int nbytes=0;
71                 int naddr=0, naliases=0;
72                 /* determine if we have enough space in buf */
73
74                 /* count how many addresses */
75                 for (p = ph->h_addr_list; *p != 0; p++) {
76                         nbytes += ph->h_length; /* addresses */
77                         nbytes += sizeof(*p); /* pointers */
78                         naddr++;
79                 }
80                 nbytes += sizeof(*p); /* one more for the terminating NULL */
81
82                 /* count how many aliases, and total length of strings */
83                 for (p = ph->h_aliases; *p != 0; p++) {
84                         nbytes += (strlen(*p)+1); /* aliases */
85                         nbytes += sizeof(*p);  /* pointers */
86                         naliases++;
87                 }
88                 nbytes += sizeof(*p); /* one more for the terminating NULL */
89
90                 /* here nbytes is the number of bytes required in buffer */
91                 /* as a terminator must be there, the minimum value is ph->h_length */
92                 if(nbytes > buflen) {
93                         *result = NULL;
94                         ast_mutex_unlock(&__mutex); /* end critical area */
95                         return ERANGE; /* not enough space in buf!! */
96                 }
97
98                 /* There is enough space. Now we need to do a deep copy! */
99                 /* Allocation in buffer:
100                         from [0] to [(naddr-1) * sizeof(*p)]:
101                         pointers to addresses
102                         at [naddr * sizeof(*p)]:
103                         NULL
104                         from [(naddr+1) * sizeof(*p)] to [(naddr+naliases) * sizeof(*p)] :
105                         pointers to aliases
106                         at [(naddr+naliases+1) * sizeof(*p)]:
107                         NULL
108                         then naddr addresses (fixed length), and naliases aliases (asciiz).
109                 */
110
111                 *ret = *ph;   /* copy whole structure (not its address!) */
112
113                 /* copy addresses */
114                 q = (char **)buf; /* pointer to pointers area (type: char **) */
115                 ret->h_addr_list = q; /* update pointer to address list */
116                 pbuf = buf + ((naddr+naliases+2)*sizeof(*p)); /* skip that area */
117                 for (p = ph->h_addr_list; *p != 0; p++) {
118                         memcpy(pbuf, *p, ph->h_length); /* copy address bytes */
119                         *q++ = pbuf; /* the pointer is the one inside buf... */
120                         pbuf += ph->h_length; /* advance pbuf */
121                 }
122                 *q++ = NULL; /* address list terminator */
123
124                 /* copy aliases */
125                 ret->h_aliases = q; /* update pointer to aliases list */
126                 for (p = ph->h_aliases; *p != 0; p++) {
127                         strcpy(pbuf, *p); /* copy alias strings */
128                         *q++ = pbuf; /* the pointer is the one inside buf... */
129                         pbuf += strlen(*p); /* advance pbuf */
130                         *pbuf++ = 0; /* string terminator */
131                 }
132                 *q++ = NULL; /* terminator */
133
134                 strcpy(pbuf, ph->h_name); /* copy alias strings */
135                 ret->h_name = pbuf;
136                 pbuf += strlen(ph->h_name); /* advance pbuf */
137                 *pbuf++ = 0; /* string terminator */
138
139                 *result = ret;  /* and let *result point to structure */
140
141         }
142         h_errno = hsave;  /* restore h_errno */
143         ast_mutex_unlock(&__mutex); /* end critical area */
144
145         return (*result == NULL); /* return 0 on success, non-zero on error */
146 }
147
148
149 #endif
150
151 /* Recursive thread safe version of gethostbyname that replaces the 
152    standard gethostbyname (which is not recursive)
153 */
154 struct hostent *ast_gethostbyname(const char *host, struct ast_hostent *hp)
155 {
156         int res;
157         int herrno;
158         const char *s;
159         struct hostent *result = NULL;
160         /* Although it is perfectly legitimate to lookup a pure integer, for
161            the sake of the sanity of people who like to name their peers as
162            integers, we break with tradition and refuse to look up a
163            pure integer */
164         s = host;
165         while(s && *s) {
166                 if (!isdigit(*s))
167                         break;
168                 s++;
169         }
170         if (!s || !*s)
171                 return NULL;
172 #ifdef SOLARIS
173         result = gethostbyname_r(host, &hp->hp, hp->buf, sizeof(hp->buf), &herrno);
174
175         if (!result || !hp->hp.h_addr_list || !hp->hp.h_addr_list[0])
176                 return NULL;
177 #else
178         res = gethostbyname_r(host, &hp->hp, hp->buf, sizeof(hp->buf), &result, &herrno);
179
180         if (res || !result || !hp->hp.h_addr_list || !hp->hp.h_addr_list[0])
181                 return NULL;
182 #endif
183         return &hp->hp;
184 }
185
186
187 /* This is a regression test for recursive mutexes.
188    test_for_thread_safety() will return 0 if recursive mutex locks are
189    working properly, and non-zero if they are not working properly. */
190
191 AST_MUTEX_DEFINE_STATIC(test_lock);
192 AST_MUTEX_DEFINE_STATIC(test_lock2);
193 static pthread_t test_thread; 
194 static int lock_count = 0;
195 static int test_errors = 0;
196
197 static void *test_thread_body(void *data) 
198
199         ast_mutex_lock(&test_lock);
200         lock_count += 10;
201         if (lock_count != 10) 
202                 test_errors++;
203         ast_mutex_lock(&test_lock);
204         lock_count += 10;
205         if (lock_count != 20) 
206                 test_errors++;
207         ast_mutex_lock(&test_lock2);
208         ast_mutex_unlock(&test_lock);
209         lock_count -= 10;
210         if (lock_count != 10) 
211                 test_errors++;
212         ast_mutex_unlock(&test_lock);
213         lock_count -= 10;
214         ast_mutex_unlock(&test_lock2);
215         if (lock_count != 0) 
216                 test_errors++;
217         return NULL;
218
219
220 int test_for_thread_safety(void)
221
222         ast_mutex_lock(&test_lock2);
223         ast_mutex_lock(&test_lock);
224         lock_count += 1;
225         ast_mutex_lock(&test_lock);
226         lock_count += 1;
227         ast_pthread_create(&test_thread, NULL, test_thread_body, NULL); 
228         usleep(100);
229         if (lock_count != 2) 
230                 test_errors++;
231         ast_mutex_unlock(&test_lock);
232         lock_count -= 1;
233         usleep(100); 
234         if (lock_count != 1) 
235                 test_errors++;
236         ast_mutex_unlock(&test_lock);
237         lock_count -= 1;
238         if (lock_count != 0) 
239                 test_errors++;
240         ast_mutex_unlock(&test_lock2);
241         usleep(100);
242         if (lock_count != 0) 
243                 test_errors++;
244         pthread_join(test_thread, NULL);
245         return(test_errors);          /* return 0 on success. */
246 }
247
248 int ast_base64decode(unsigned char *dst, char *src, int max)
249 {
250         int cnt = 0;
251         unsigned int byte = 0;
252         unsigned int bits = 0;
253         int incnt = 0;
254 #if 0
255         unsigned char *odst = dst;
256 #endif
257         while(*src && (cnt < max)) {
258                 /* Shift in 6 bits of input */
259                 byte <<= 6;
260                 byte |= (b2a[(int)(*src)]) & 0x3f;
261                 bits += 6;
262 #if 0
263                 printf("Add: %c %s\n", *src, binary(b2a[(int)(*src)] & 0x3f, 6));
264 #endif
265                 src++;
266                 incnt++;
267                 /* If we have at least 8 bits left over, take that character 
268                    off the top */
269                 if (bits >= 8)  {
270                         bits -= 8;
271                         *dst = (byte >> bits) & 0xff;
272 #if 0
273                         printf("Remove: %02x %s\n", *dst, binary(*dst, 8));
274 #endif
275                         dst++;
276                         cnt++;
277                 }
278         }
279 #if 0
280         dump(odst, cnt);
281 #endif
282         /* Dont worry about left over bits, they're extra anyway */
283         return cnt;
284 }
285
286 int ast_base64encode(char *dst, unsigned char *src, int srclen, int max)
287 {
288         int cnt = 0;
289         unsigned int byte = 0;
290         int bits = 0;
291         int index;
292         int cntin = 0;
293 #if 0
294         char *odst = dst;
295         dump(src, srclen);
296 #endif
297         /* Reserve one bit for end */
298         max--;
299         while((cntin < srclen) && (cnt < max)) {
300                 byte <<= 8;
301 #if 0
302                 printf("Add: %02x %s\n", *src, binary(*src, 8));
303 #endif
304                 byte |= *(src++);
305                 bits += 8;
306                 cntin++;
307                 while((bits >= 6) && (cnt < max)) {
308                         bits -= 6;
309                         /* We want only the top */
310                         index = (byte >> bits) & 0x3f;
311                         *dst = base64[index];
312 #if 0
313                         printf("Remove: %c %s\n", *dst, binary(index, 6));
314 #endif
315                         dst++;
316                         cnt++;
317                 }
318         }
319         if (bits && (cnt < max)) {
320                 /* Add one last character for the remaining bits, 
321                    padding the rest with 0 */
322                 byte <<= (6 - bits);
323                 index = (byte) & 0x3f;
324                 *(dst++) = base64[index];
325                 cnt++;
326         }
327         *dst = '\0';
328         return cnt;
329 }
330
331 static void base64_init(void)
332 {
333         int x;
334         memset(b2a, -1, sizeof(b2a));
335         /* Initialize base-64 Conversion table */
336         for (x=0;x<26;x++) {
337                 /* A-Z */
338                 base64[x] = 'A' + x;
339                 b2a['A' + x] = x;
340                 /* a-z */
341                 base64[x + 26] = 'a' + x;
342                 b2a['a' + x] = x + 26;
343                 /* 0-9 */
344                 if (x < 10) {
345                         base64[x + 52] = '0' + x;
346                         b2a['0' + x] = x + 52;
347                 }
348         }
349         base64[62] = '+';
350         base64[63] = '/';
351         b2a[(int)'+'] = 62;
352         b2a[(int)'/'] = 63;
353 #if 0
354         for (x=0;x<64;x++) {
355                 if (b2a[(int)base64[x]] != x) {
356                         fprintf(stderr, "!!! %d failed\n", x);
357                 } else
358                         fprintf(stderr, "--- %d passed\n", x);
359         }
360 #endif
361 }
362
363 /* Recursive thread safe replacement of inet_ntoa */
364 const char *ast_inet_ntoa(char *buf, int bufsiz, struct in_addr ia)
365 {
366         return inet_ntop(AF_INET, &ia, buf, bufsiz);
367 }
368
369 int ast_utils_init(void)
370 {
371         base64_init();
372         return 0;
373 }
374
375
376 #ifndef __linux__
377 #undef pthread_create /* For ast_pthread_create function only */
378 int ast_pthread_create(pthread_t *thread, pthread_attr_t *attr, void *(*start_routine)(void *), void *data)
379 {
380         pthread_attr_t lattr;
381         if (!attr) {
382                 pthread_attr_init(&lattr);
383                 attr = &lattr;
384         }
385         errno = pthread_attr_setstacksize(attr, PTHREAD_ATTR_STACKSIZE);
386         if (errno)
387                 ast_log(LOG_WARNING, "pthread_attr_setstacksize returned non-zero: %s\n", strerror(errno));
388         return pthread_create(thread, attr, start_routine, data); /* We're in ast_pthread_create, so it's okay */
389 }
390 #endif /* ! LINUX */
391
392 /* Case-insensitive substring matching */
393 #ifndef LINUX
394 static char *upper(const char *orig, char *buf, int bufsize)
395 {
396         int i;
397         memset(buf, 0, bufsize);
398         for (i=0; i<bufsize - 1; i++) {
399                 buf[i] = toupper(orig[i]);
400                 if (orig[i] == '\0') {
401                         break;
402                 }
403         }
404         return buf;
405 }
406
407 char *ast_strcasestr(const char *haystack, const char *needle)
408 {
409         char *u1, *u2;
410         int u1len = strlen(haystack) + 1, u2len = strlen(needle) + 1;
411
412         u1 = alloca(u1len);
413         u2 = alloca(u2len);
414         if (u1 && u2) {
415                 char *offset;
416                 if (u2len > u1len) {
417                         /* Needle bigger than haystack */
418                         return NULL;
419                 }
420                 offset = strstr(upper(haystack, u1, u1len), upper(needle, u2, u2len));
421                 if (offset) {
422                         /* Return the offset into the original string */
423                         return ((char *)((unsigned int)haystack + (unsigned int)(offset - u1)));
424                 } else {
425                         return NULL;
426                 }
427         } else {
428                 ast_log(LOG_ERROR, "Out of memory\n");
429                 return NULL;
430         }
431 }
432 #endif
433
434
435 /*--- ast_print_group: Print call group and pickup group ---*/
436 char *ast_print_group(char *buf, int buflen, unsigned int group) 
437 {
438         unsigned int i;
439         int first=1;
440         char num[3];
441
442         buf[0] = '\0';
443         
444         if (!group)     /* Return empty string if no group */
445                 return(buf);
446
447         for (i=0; i<=31; i++) { /* Max group is 31 */
448                 if (group & (1 << i)) {
449                         if (!first) {
450                                 strncat(buf, ", ", buflen);
451                         } else {
452                                 first=0;
453                         }
454                         snprintf(num, sizeof(num), "%u", i);
455                         strncat(buf, num, buflen);
456                 }
457         }
458         return(buf);
459 }