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