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 */
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/logger.h>
29 static char base64[64];
32 char *ast_strip(char *buf)
35 /* Strip off trailing whitespace, returns, etc */
36 while (!ast_strlen_zero(buf) && (buf[strlen(buf)-1]<33))
37 buf[strlen(buf)-1] = '\0';
39 /* Strip off leading whitespace, returns, etc */
40 while (*start && (*start < 33))
45 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined( __NetBSD__ ) || defined(__APPLE__)
47 /* duh? ERANGE value copied from web... */
51 AST_MUTEX_DEFINE_STATIC(__mutex);
53 /* Recursive replacement for gethostbyname for BSD-based systems */
54 static int gethostbyname_r (const char *name, struct hostent *ret, char *buf,
55 size_t buflen, struct hostent **result,
60 ast_mutex_lock(&__mutex); /* begin critical area */
63 ph = gethostbyname(name);
64 *h_errnop = h_errno; /* copy h_errno to *h_herrnop */
71 int naddr=0, naliases=0;
72 /* determine if we have enough space in buf */
74 /* count how many addresses */
75 for (p = ph->h_addr_list; *p != 0; p++) {
76 nbytes += ph->h_length; /* addresses */
77 nbytes += sizeof(*p); /* pointers */
80 nbytes += sizeof(*p); /* one more for the terminating NULL */
82 /* count how many aliases, and total length of strings */
83 for (p = ph->h_aliases; *p != 0; p++) {
84 nbytes += (strlen(*p)+1); /* aliases */
85 nbytes += sizeof(*p); /* pointers */
88 nbytes += sizeof(*p); /* one more for the terminating NULL */
90 /* here nbytes is the number of bytes required in buffer */
91 /* as a terminator must be there, the minimum value is ph->h_length */
94 ast_mutex_unlock(&__mutex); /* end critical area */
95 return ERANGE; /* not enough space in buf!! */
98 /* There is enough space. Now we need to do a deep copy! */
99 /* Allocation in buffer:
100 from [0] to [(naddr-1) * sizeof(*p)]:
101 pointers to addresses
102 at [naddr * sizeof(*p)]:
104 from [(naddr+1) * sizeof(*p)] to [(naddr+naliases) * sizeof(*p)] :
106 at [(naddr+naliases+1) * sizeof(*p)]:
108 then naddr addresses (fixed length), and naliases aliases (asciiz).
111 *ret = *ph; /* copy whole structure (not its address!) */
114 q = (char **)buf; /* pointer to pointers area (type: char **) */
115 ret->h_addr_list = q; /* update pointer to address list */
116 pbuf = buf + ((naddr+naliases+2)*sizeof(*p)); /* skip that area */
117 for (p = ph->h_addr_list; *p != 0; p++) {
118 memcpy(pbuf, *p, ph->h_length); /* copy address bytes */
119 *q++ = pbuf; /* the pointer is the one inside buf... */
120 pbuf += ph->h_length; /* advance pbuf */
122 *q++ = NULL; /* address list terminator */
125 ret->h_aliases = q; /* update pointer to aliases list */
126 for (p = ph->h_aliases; *p != 0; p++) {
127 strcpy(pbuf, *p); /* copy alias strings */
128 *q++ = pbuf; /* the pointer is the one inside buf... */
129 pbuf += strlen(*p); /* advance pbuf */
130 *pbuf++ = 0; /* string terminator */
132 *q++ = NULL; /* terminator */
134 strcpy(pbuf, ph->h_name); /* copy alias strings */
136 pbuf += strlen(ph->h_name); /* advance pbuf */
137 *pbuf++ = 0; /* string terminator */
139 *result = ret; /* and let *result point to structure */
142 h_errno = hsave; /* restore h_errno */
143 ast_mutex_unlock(&__mutex); /* end critical area */
145 return (*result == NULL); /* return 0 on success, non-zero on error */
151 /* Recursive thread safe version of gethostbyname that replaces the
152 standard gethostbyname (which is not recursive)
154 struct hostent *ast_gethostbyname(const char *host, struct ast_hostent *hp)
159 struct hostent *result = NULL;
160 /* Although it is perfectly legitimate to lookup a pure integer, for
161 the sake of the sanity of people who like to name their peers as
162 integers, we break with tradition and refuse to look up a
173 result = gethostbyname_r(host, &hp->hp, hp->buf, sizeof(hp->buf), &herrno);
175 if (!result || !hp->hp.h_addr_list || !hp->hp.h_addr_list[0])
178 res = gethostbyname_r(host, &hp->hp, hp->buf, sizeof(hp->buf), &result, &herrno);
180 if (res || !result || !hp->hp.h_addr_list || !hp->hp.h_addr_list[0])
187 /* This is a regression test for recursive mutexes.
188 test_for_thread_safety() will return 0 if recursive mutex locks are
189 working properly, and non-zero if they are not working properly. */
191 AST_MUTEX_DEFINE_STATIC(test_lock);
192 AST_MUTEX_DEFINE_STATIC(test_lock2);
193 static pthread_t test_thread;
194 static int lock_count = 0;
195 static int test_errors = 0;
197 static void *test_thread_body(void *data)
199 ast_mutex_lock(&test_lock);
201 if (lock_count != 10)
203 ast_mutex_lock(&test_lock);
205 if (lock_count != 20)
207 ast_mutex_lock(&test_lock2);
208 ast_mutex_unlock(&test_lock);
210 if (lock_count != 10)
212 ast_mutex_unlock(&test_lock);
214 ast_mutex_unlock(&test_lock2);
220 int test_for_thread_safety(void)
222 ast_mutex_lock(&test_lock2);
223 ast_mutex_lock(&test_lock);
225 ast_mutex_lock(&test_lock);
227 ast_pthread_create(&test_thread, NULL, test_thread_body, NULL);
231 ast_mutex_unlock(&test_lock);
236 ast_mutex_unlock(&test_lock);
240 ast_mutex_unlock(&test_lock2);
244 pthread_join(test_thread, NULL);
245 return(test_errors); /* return 0 on success. */
248 int ast_base64decode(unsigned char *dst, char *src, int max)
251 unsigned int byte = 0;
252 unsigned int bits = 0;
255 unsigned char *odst = dst;
257 while(*src && (cnt < max)) {
258 /* Shift in 6 bits of input */
260 byte |= (b2a[(int)(*src)]) & 0x3f;
263 printf("Add: %c %s\n", *src, binary(b2a[(int)(*src)] & 0x3f, 6));
267 /* If we have at least 8 bits left over, take that character
271 *dst = (byte >> bits) & 0xff;
273 printf("Remove: %02x %s\n", *dst, binary(*dst, 8));
282 /* Dont worry about left over bits, they're extra anyway */
286 int ast_base64encode(char *dst, unsigned char *src, int srclen, int max)
289 unsigned int byte = 0;
297 /* Reserve one bit for end */
299 while((cntin < srclen) && (cnt < max)) {
302 printf("Add: %02x %s\n", *src, binary(*src, 8));
307 while((bits >= 6) && (cnt < max)) {
309 /* We want only the top */
310 index = (byte >> bits) & 0x3f;
311 *dst = base64[index];
313 printf("Remove: %c %s\n", *dst, binary(index, 6));
319 if (bits && (cnt < max)) {
320 /* Add one last character for the remaining bits,
321 padding the rest with 0 */
323 index = (byte) & 0x3f;
324 *(dst++) = base64[index];
331 static void base64_init(void)
334 memset(b2a, -1, sizeof(b2a));
335 /* Initialize base-64 Conversion table */
341 base64[x + 26] = 'a' + x;
342 b2a['a' + x] = x + 26;
345 base64[x + 52] = '0' + x;
346 b2a['0' + x] = x + 52;
355 if (b2a[(int)base64[x]] != x) {
356 fprintf(stderr, "!!! %d failed\n", x);
358 fprintf(stderr, "--- %d passed\n", x);
363 /* Recursive thread safe replacement of inet_ntoa */
364 const char *ast_inet_ntoa(char *buf, int bufsiz, struct in_addr ia)
366 return inet_ntop(AF_INET, &ia, buf, bufsiz);
369 int ast_utils_init(void)
377 #undef pthread_create /* For ast_pthread_create function only */
378 int ast_pthread_create(pthread_t *thread, pthread_attr_t *attr, void *(*start_routine)(void *), void *data)
380 pthread_attr_t lattr;
382 pthread_attr_init(&lattr);
385 errno = pthread_attr_setstacksize(attr, PTHREAD_ATTR_STACKSIZE);
387 ast_log(LOG_WARNING, "pthread_attr_setstacksize returned non-zero: %s\n", strerror(errno));
388 return pthread_create(thread, attr, start_routine, data); /* We're in ast_pthread_create, so it's okay */
392 /* Case-insensitive substring matching */
394 static char *upper(const char *orig, char *buf, int bufsize)
397 memset(buf, 0, bufsize);
398 for (i=0; i<bufsize - 1; i++) {
399 buf[i] = toupper(orig[i]);
400 if (orig[i] == '\0') {
407 char *ast_strcasestr(const char *haystack, const char *needle)
410 int u1len = strlen(haystack) + 1, u2len = strlen(needle) + 1;
417 /* Needle bigger than haystack */
420 offset = strstr(upper(haystack, u1, u1len), upper(needle, u2, u2len));
422 /* Return the offset into the original string */
423 return ((char *)((unsigned int)haystack + (unsigned int)(offset - u1)));
428 ast_log(LOG_ERROR, "Out of memory\n");