2 * Asterisk -- A telephony toolkit for Linux.
6 * Copyright (C) 2004, Digium
8 * This program is free software, distributed under the terms of
9 * the GNU General Public License
12 #ifdef Linux /* For strcasestr */
19 #include <sys/types.h>
20 #include <sys/socket.h>
21 #include <netinet/in.h>
22 #include <arpa/inet.h>
23 #include <asterisk/lock.h>
24 #include <asterisk/utils.h>
25 #include <asterisk/logger.h>
28 static char base64[64];
31 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
33 /* duh? ERANGE value copied from web... */
37 AST_MUTEX_DEFINE_STATIC(__mutex);
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,
46 ast_mutex_lock(&__mutex); /* begin critical area */
49 ph = gethostbyname(name);
50 *h_errnop = h_errno; /* copy h_errno to *h_herrnop */
57 int naddr=0, naliases=0;
58 /* determine if we have enough space in buf */
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 */
66 nbytes += sizeof(*p); /* one more for the terminating NULL */
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 */
74 nbytes += sizeof(*p); /* one more for the terminating NULL */
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 */
80 ast_mutex_unlock(&__mutex); /* end critical area */
81 return ERANGE; /* not enough space in buf!! */
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)]:
88 at [naddr * sizeof(*p)]:
90 from [(naddr+1) * sizeof(*p)] to [(naddr+naliases) * sizeof(*p)] :
92 at [(naddr+naliases+1) * sizeof(*p)]:
94 then naddr addresses (fixed length), and naliases aliases (asciiz).
97 *ret = *ph; /* copy whole structure (not its address!) */
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 */
108 *q++ = NULL; /* address list terminator */
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 */
118 *q++ = NULL; /* terminator */
120 strcpy(pbuf, ph->h_name); /* copy alias strings */
122 pbuf += strlen(ph->h_name); /* advance pbuf */
123 *pbuf++ = 0; /* string terminator */
125 *result = ret; /* and let *result point to structure */
128 h_errno = hsave; /* restore h_errno */
129 ast_mutex_unlock(&__mutex); /* end critical area */
131 return (*result == NULL); /* return 0 on success, non-zero on error */
137 /* Recursive thread safe version of gethostbyname that replaces the
138 standard gethostbyname (which is not recursive)
140 struct hostent *ast_gethostbyname(const char *host, struct ast_hostent *hp)
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
158 res = gethostbyname_r(host, &hp->hp, hp->buf, sizeof(hp->buf), &result, &herrno);
160 if (res || !result || !hp->hp.h_addr_list || !hp->hp.h_addr_list[0])
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. */
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;
176 static void *test_thread_body(void *data)
178 ast_mutex_lock(&test_lock);
180 if (lock_count != 10)
182 ast_mutex_lock(&test_lock);
184 if (lock_count != 20)
186 ast_mutex_lock(&test_lock2);
187 ast_mutex_unlock(&test_lock);
189 if (lock_count != 10)
191 ast_mutex_unlock(&test_lock);
193 ast_mutex_unlock(&test_lock2);
199 int test_for_thread_safety(void)
201 ast_mutex_lock(&test_lock2);
202 ast_mutex_lock(&test_lock);
204 ast_mutex_lock(&test_lock);
206 ast_pthread_create(&test_thread, NULL, test_thread_body, NULL);
210 ast_mutex_unlock(&test_lock);
215 ast_mutex_unlock(&test_lock);
219 ast_mutex_unlock(&test_lock2);
223 pthread_join(test_thread, NULL);
224 return(test_errors); /* return 0 on success. */
227 int ast_base64decode(unsigned char *dst, char *src, int max)
230 unsigned int byte = 0;
231 unsigned int bits = 0;
234 unsigned char *odst = dst;
236 while(*src && (cnt < max)) {
237 /* Shift in 6 bits of input */
239 byte |= (b2a[(int)(*src)]) & 0x3f;
242 printf("Add: %c %s\n", *src, binary(b2a[(int)(*src)] & 0x3f, 6));
246 /* If we have at least 8 bits left over, take that character
250 *dst = (byte >> bits) & 0xff;
252 printf("Remove: %02x %s\n", *dst, binary(*dst, 8));
261 /* Dont worry about left over bits, they're extra anyway */
265 int ast_base64encode(char *dst, unsigned char *src, int srclen, int max)
268 unsigned int byte = 0;
276 /* Reserve one bit for end */
278 while((cntin < srclen) && (cnt < max)) {
281 printf("Add: %02x %s\n", *src, binary(*src, 8));
286 while((bits >= 6) && (cnt < max)) {
288 /* We want only the top */
289 index = (byte >> bits) & 0x3f;
290 *dst = base64[index];
292 printf("Remove: %c %s\n", *dst, binary(index, 6));
298 if (bits && (cnt < max)) {
299 /* Add one last character for the remaining bits,
300 padding the rest with 0 */
302 index = (byte) & 0x3f;
303 *(dst++) = base64[index];
310 static void base64_init(void)
313 memset(b2a, -1, sizeof(b2a));
314 /* Initialize base-64 Conversion table */
320 base64[x + 26] = 'a' + x;
321 b2a['a' + x] = x + 26;
324 base64[x + 52] = '0' + x;
325 b2a['0' + x] = x + 52;
334 if (b2a[(int)base64[x]] != x) {
335 fprintf(stderr, "!!! %d failed\n", x);
337 fprintf(stderr, "--- %d passed\n", x);
342 /* Recursive thread safe replacement of inet_ntoa */
343 const char *ast_inet_ntoa(char *buf, int bufsiz, struct in_addr ia)
345 return inet_ntop(AF_INET, &ia, buf, bufsiz);
348 int ast_utils_init(void)
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)
359 pthread_attr_t lattr;
361 pthread_attr_init(&lattr);
364 errno = pthread_attr_setstacksize(attr, PTHREAD_ATTR_STACKSIZE);
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 */
371 static char *upper(const char *orig, char *buf, int bufsize)
374 memset(buf, 0, bufsize);
375 for (i=0; i<bufsize - 1; i++) {
376 buf[i] = toupper(orig[i]);
377 if (orig[i] == '\0') {
384 /* Case-insensitive substring matching */
386 char *ast_strcasestr(const char *haystack, const char *needle)
389 int u1len = strlen(haystack), u2len = strlen(needle);
396 /* Needle bigger than haystack */
399 offset = strstr(upper(haystack, u1, u1len), upper(needle, u2, u2len));
401 /* Return the offset into the original string */
402 return ((char *)((unsigned int)haystack + (unsigned int)(offset - u1)));
407 ast_log(LOG_ERROR, "Out of memory\n");