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