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