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