2 * Asterisk -- A telephony toolkit for Linux.
6 * Copyright (C) 2004 - 2005, Digium, Inc.
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>
28 #include <asterisk/md5.h>
30 static char base64[64];
33 char *ast_strip(char *buf)
36 /* Strip off trailing whitespace, returns, etc */
37 while (!ast_strlen_zero(buf) && (buf[strlen(buf)-1]<33))
38 buf[strlen(buf)-1] = '\0';
40 /* Strip off leading whitespace, returns, etc */
41 while (*start && (*start < 33))
46 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined( __NetBSD__ ) || defined(__APPLE__)
48 /* duh? ERANGE value copied from web... */
52 AST_MUTEX_DEFINE_STATIC(__mutex);
54 /* Recursive replacement for gethostbyname for BSD-based systems */
55 static int gethostbyname_r (const char *name, struct hostent *ret, char *buf,
56 size_t buflen, struct hostent **result,
61 ast_mutex_lock(&__mutex); /* begin critical area */
64 ph = gethostbyname(name);
65 *h_errnop = h_errno; /* copy h_errno to *h_herrnop */
72 int naddr=0, naliases=0;
73 /* determine if we have enough space in buf */
75 /* count how many addresses */
76 for (p = ph->h_addr_list; *p != 0; p++) {
77 nbytes += ph->h_length; /* addresses */
78 nbytes += sizeof(*p); /* pointers */
81 nbytes += sizeof(*p); /* one more for the terminating NULL */
83 /* count how many aliases, and total length of strings */
84 for (p = ph->h_aliases; *p != 0; p++) {
85 nbytes += (strlen(*p)+1); /* aliases */
86 nbytes += sizeof(*p); /* pointers */
89 nbytes += sizeof(*p); /* one more for the terminating NULL */
91 /* here nbytes is the number of bytes required in buffer */
92 /* as a terminator must be there, the minimum value is ph->h_length */
95 ast_mutex_unlock(&__mutex); /* end critical area */
96 return ERANGE; /* not enough space in buf!! */
99 /* There is enough space. Now we need to do a deep copy! */
100 /* Allocation in buffer:
101 from [0] to [(naddr-1) * sizeof(*p)]:
102 pointers to addresses
103 at [naddr * sizeof(*p)]:
105 from [(naddr+1) * sizeof(*p)] to [(naddr+naliases) * sizeof(*p)] :
107 at [(naddr+naliases+1) * sizeof(*p)]:
109 then naddr addresses (fixed length), and naliases aliases (asciiz).
112 *ret = *ph; /* copy whole structure (not its address!) */
115 q = (char **)buf; /* pointer to pointers area (type: char **) */
116 ret->h_addr_list = q; /* update pointer to address list */
117 pbuf = buf + ((naddr+naliases+2)*sizeof(*p)); /* skip that area */
118 for (p = ph->h_addr_list; *p != 0; p++) {
119 memcpy(pbuf, *p, ph->h_length); /* copy address bytes */
120 *q++ = pbuf; /* the pointer is the one inside buf... */
121 pbuf += ph->h_length; /* advance pbuf */
123 *q++ = NULL; /* address list terminator */
126 ret->h_aliases = q; /* update pointer to aliases list */
127 for (p = ph->h_aliases; *p != 0; p++) {
128 strcpy(pbuf, *p); /* copy alias strings */
129 *q++ = pbuf; /* the pointer is the one inside buf... */
130 pbuf += strlen(*p); /* advance pbuf */
131 *pbuf++ = 0; /* string terminator */
133 *q++ = NULL; /* terminator */
135 strcpy(pbuf, ph->h_name); /* copy alias strings */
137 pbuf += strlen(ph->h_name); /* advance pbuf */
138 *pbuf++ = 0; /* string terminator */
140 *result = ret; /* and let *result point to structure */
143 h_errno = hsave; /* restore h_errno */
144 ast_mutex_unlock(&__mutex); /* end critical area */
146 return (*result == NULL); /* return 0 on success, non-zero on error */
152 /* Recursive thread safe version of gethostbyname that replaces the
153 standard gethostbyname (which is not recursive)
155 struct hostent *ast_gethostbyname(const char *host, struct ast_hostent *hp)
160 struct hostent *result = NULL;
161 /* Although it is perfectly legitimate to lookup a pure integer, for
162 the sake of the sanity of people who like to name their peers as
163 integers, we break with tradition and refuse to look up a
174 result = gethostbyname_r(host, &hp->hp, hp->buf, sizeof(hp->buf), &herrno);
176 if (!result || !hp->hp.h_addr_list || !hp->hp.h_addr_list[0])
179 res = gethostbyname_r(host, &hp->hp, hp->buf, sizeof(hp->buf), &result, &herrno);
181 if (res || !result || !hp->hp.h_addr_list || !hp->hp.h_addr_list[0])
188 /* This is a regression test for recursive mutexes.
189 test_for_thread_safety() will return 0 if recursive mutex locks are
190 working properly, and non-zero if they are not working properly. */
192 AST_MUTEX_DEFINE_STATIC(test_lock);
193 AST_MUTEX_DEFINE_STATIC(test_lock2);
194 static pthread_t test_thread;
195 static int lock_count = 0;
196 static int test_errors = 0;
198 static void *test_thread_body(void *data)
200 ast_mutex_lock(&test_lock);
202 if (lock_count != 10)
204 ast_mutex_lock(&test_lock);
206 if (lock_count != 20)
208 ast_mutex_lock(&test_lock2);
209 ast_mutex_unlock(&test_lock);
211 if (lock_count != 10)
213 ast_mutex_unlock(&test_lock);
215 ast_mutex_unlock(&test_lock2);
221 int test_for_thread_safety(void)
223 ast_mutex_lock(&test_lock2);
224 ast_mutex_lock(&test_lock);
226 ast_mutex_lock(&test_lock);
228 ast_pthread_create(&test_thread, NULL, test_thread_body, NULL);
232 ast_mutex_unlock(&test_lock);
237 ast_mutex_unlock(&test_lock);
241 ast_mutex_unlock(&test_lock2);
245 pthread_join(test_thread, NULL);
246 return(test_errors); /* return 0 on success. */
249 /*--- ast_md5_hash: Produce 16 char MD5 hash of value. ---*/
250 void ast_md5_hash(char *output, char *input)
252 struct MD5Context md5;
253 unsigned char digest[16];
257 MD5Update(&md5, input, strlen(input));
258 MD5Final(digest, &md5);
261 ptr += sprintf(ptr, "%2.2x", digest[x]);
264 int ast_base64decode(unsigned char *dst, char *src, int max)
267 unsigned int byte = 0;
268 unsigned int bits = 0;
271 unsigned char *odst = dst;
273 while(*src && (cnt < max)) {
274 /* Shift in 6 bits of input */
276 byte |= (b2a[(int)(*src)]) & 0x3f;
279 printf("Add: %c %s\n", *src, binary(b2a[(int)(*src)] & 0x3f, 6));
283 /* If we have at least 8 bits left over, take that character
287 *dst = (byte >> bits) & 0xff;
289 printf("Remove: %02x %s\n", *dst, binary(*dst, 8));
298 /* Dont worry about left over bits, they're extra anyway */
302 int ast_base64encode(char *dst, unsigned char *src, int srclen, int max)
305 unsigned int byte = 0;
313 /* Reserve one bit for end */
315 while((cntin < srclen) && (cnt < max)) {
318 printf("Add: %02x %s\n", *src, binary(*src, 8));
323 while((bits >= 6) && (cnt < max)) {
325 /* We want only the top */
326 index = (byte >> bits) & 0x3f;
327 *dst = base64[index];
329 printf("Remove: %c %s\n", *dst, binary(index, 6));
335 if (bits && (cnt < max)) {
336 /* Add one last character for the remaining bits,
337 padding the rest with 0 */
339 index = (byte) & 0x3f;
340 *(dst++) = base64[index];
347 static void base64_init(void)
350 memset(b2a, -1, sizeof(b2a));
351 /* Initialize base-64 Conversion table */
357 base64[x + 26] = 'a' + x;
358 b2a['a' + x] = x + 26;
361 base64[x + 52] = '0' + x;
362 b2a['0' + x] = x + 52;
371 if (b2a[(int)base64[x]] != x) {
372 fprintf(stderr, "!!! %d failed\n", x);
374 fprintf(stderr, "--- %d passed\n", x);
379 /* Recursive thread safe replacement of inet_ntoa */
380 const char *ast_inet_ntoa(char *buf, int bufsiz, struct in_addr ia)
382 return inet_ntop(AF_INET, &ia, buf, bufsiz);
385 int ast_utils_init(void)
393 #undef pthread_create /* For ast_pthread_create function only */
394 int ast_pthread_create(pthread_t *thread, pthread_attr_t *attr, void *(*start_routine)(void *), void *data)
396 pthread_attr_t lattr;
398 pthread_attr_init(&lattr);
401 errno = pthread_attr_setstacksize(attr, AST_STACKSIZE);
403 ast_log(LOG_WARNING, "pthread_attr_setstacksize returned non-zero: %s\n", strerror(errno));
404 return pthread_create(thread, attr, start_routine, data); /* We're in ast_pthread_create, so it's okay */
408 /* Case-insensitive substring matching */
410 static char *upper(const char *orig, char *buf, int bufsize)
413 memset(buf, 0, bufsize);
414 for (i=0; i<bufsize - 1; i++) {
415 buf[i] = toupper(orig[i]);
416 if (orig[i] == '\0') {
423 char *ast_strcasestr(const char *haystack, const char *needle)
426 int u1len = strlen(haystack) + 1, u2len = strlen(needle) + 1;
433 /* Needle bigger than haystack */
436 offset = strstr(upper(haystack, u1, u1len), upper(needle, u2, u2len));
438 /* Return the offset into the original string */
439 return ((char *)((unsigned int)haystack + (unsigned int)(offset - u1)));
444 ast_log(LOG_ERROR, "Out of memory\n");