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
15 #include <sys/types.h>
16 #include <sys/socket.h>
17 #include <netinet/in.h>
18 #include <arpa/inet.h>
19 #include <asterisk/lock.h>
20 #include <asterisk/utils.h>
22 static char base64[64];
25 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
27 /* duh? ERANGE value copied from web... */
31 AST_MUTEX_DEFINE_STATIC(__mutex);
33 /* Recursive replacement for gethostbyname for BSD-based systems */
34 static int gethostbyname_r (const char *name, struct hostent *ret, char *buf,
35 size_t buflen, struct hostent **result,
40 ast_mutex_lock(&__mutex); /* begin critical area */
43 ph = gethostbyname(name);
44 *h_errnop = h_errno; /* copy h_errno to *h_herrnop */
51 int naddr=0, naliases=0;
52 /* determine if we have enough space in buf */
54 /* count how many addresses */
55 for (p = ph->h_addr_list; *p != 0; p++) {
56 nbytes += ph->h_length; /* addresses */
57 nbytes += sizeof(*p); /* pointers */
60 nbytes += sizeof(*p); /* one more for the terminating NULL */
62 /* count how many aliases, and total length of strings */
63 for (p = ph->h_aliases; *p != 0; p++) {
64 nbytes += (strlen(*p)+1); /* aliases */
65 nbytes += sizeof(*p); /* pointers */
68 nbytes += sizeof(*p); /* one more for the terminating NULL */
70 /* here nbytes is the number of bytes required in buffer */
71 /* as a terminator must be there, the minimum value is ph->h_length */
74 ast_mutex_unlock(&__mutex); /* end critical area */
75 return ERANGE; /* not enough space in buf!! */
78 /* There is enough space. Now we need to do a deep copy! */
79 /* Allocation in buffer:
80 from [0] to [(naddr-1) * sizeof(*p)]:
82 at [naddr * sizeof(*p)]:
84 from [(naddr+1) * sizeof(*p)] to [(naddr+naliases) * sizeof(*p)] :
86 at [(naddr+naliases+1) * sizeof(*p)]:
88 then naddr addresses (fixed length), and naliases aliases (asciiz).
91 *ret = *ph; /* copy whole structure (not its address!) */
94 q = (char **)buf; /* pointer to pointers area (type: char **) */
95 ret->h_addr_list = q; /* update pointer to address list */
96 pbuf = buf + ((naddr+naliases+2)*sizeof(*p)); /* skip that area */
97 for (p = ph->h_addr_list; *p != 0; p++) {
98 memcpy(pbuf, *p, ph->h_length); /* copy address bytes */
99 *q++ = pbuf; /* the pointer is the one inside buf... */
100 pbuf += ph->h_length; /* advance pbuf */
102 *q++ = NULL; /* address list terminator */
105 ret->h_aliases = q; /* update pointer to aliases list */
106 for (p = ph->h_aliases; *p != 0; p++) {
107 strcpy(pbuf, *p); /* copy alias strings */
108 *q++ = pbuf; /* the pointer is the one inside buf... */
109 pbuf += strlen(*p); /* advance pbuf */
110 *pbuf++ = 0; /* string terminator */
112 *q++ = NULL; /* terminator */
114 strcpy(pbuf, ph->h_name); /* copy alias strings */
116 pbuf += strlen(ph->h_name); /* advance pbuf */
117 *pbuf++ = 0; /* string terminator */
119 *result = ret; /* and let *result point to structure */
122 h_errno = hsave; /* restore h_errno */
123 ast_mutex_unlock(&__mutex); /* end critical area */
125 return (*result == NULL); /* return 0 on success, non-zero on error */
131 /* Recursive thread safe version of gethostbyname that replaces the
132 standard gethostbyname (which is not recursive)
134 struct hostent *ast_gethostbyname(const char *host, struct ast_hostent *hp)
139 struct hostent *result = NULL;
140 /* Although it is perfectly legitimate to lookup a pure integer, for
141 the sake of the sanity of people who like to name their peers as
142 integers, we break with tradition and refuse to look up a
152 res = gethostbyname_r(host, &hp->hp, hp->buf, sizeof(hp->buf), &result, &herrno);
154 if (res || !result || !hp->hp.h_addr_list || !hp->hp.h_addr_list[0])
160 /* This is a regression test for recursive mutexes.
161 test_for_thread_safety() will return 0 if recursive mutex locks are
162 working properly, and non-zero if they are not working properly. */
164 AST_MUTEX_DEFINE_STATIC(test_lock);
165 AST_MUTEX_DEFINE_STATIC(test_lock2);
166 static pthread_t test_thread;
167 static int lock_count = 0;
168 static int test_errors = 0;
170 static void *test_thread_body(void *data)
172 ast_mutex_lock(&test_lock);
174 if (lock_count != 10)
176 ast_mutex_lock(&test_lock);
178 if (lock_count != 20)
180 ast_mutex_lock(&test_lock2);
181 ast_mutex_unlock(&test_lock);
183 if (lock_count != 10)
185 ast_mutex_unlock(&test_lock);
187 ast_mutex_unlock(&test_lock2);
193 int test_for_thread_safety(void)
195 ast_mutex_lock(&test_lock2);
196 ast_mutex_lock(&test_lock);
198 ast_mutex_lock(&test_lock);
200 pthread_create(&test_thread, NULL, test_thread_body, NULL);
204 ast_mutex_unlock(&test_lock);
209 ast_mutex_unlock(&test_lock);
213 ast_mutex_unlock(&test_lock2);
217 pthread_join(test_thread, NULL);
218 return(test_errors); /* return 0 on success. */
221 int ast_base64decode(unsigned char *dst, char *src, int max)
224 unsigned int byte = 0;
225 unsigned int bits = 0;
228 unsigned char *odst = dst;
230 while(*src && (cnt < max)) {
231 /* Shift in 6 bits of input */
233 byte |= (b2a[(int)(*src)]) & 0x3f;
236 printf("Add: %c %s\n", *src, binary(b2a[(int)(*src)] & 0x3f, 6));
240 /* If we have at least 8 bits left over, take that character
244 *dst = (byte >> bits) & 0xff;
246 printf("Remove: %02x %s\n", *dst, binary(*dst, 8));
255 /* Dont worry about left over bits, they're extra anyway */
259 int ast_base64encode(char *dst, unsigned char *src, int srclen, int max)
262 unsigned int byte = 0;
270 /* Reserve one bit for end */
272 while((cntin < srclen) && (cnt < max)) {
275 printf("Add: %02x %s\n", *src, binary(*src, 8));
280 while((bits >= 6) && (cnt < max)) {
282 /* We want only the top */
283 index = (byte >> bits) & 0x3f;
284 *dst = base64[index];
286 printf("Remove: %c %s\n", *dst, binary(index, 6));
292 if (bits && (cnt < max)) {
293 /* Add one last character for the remaining bits,
294 padding the rest with 0 */
296 index = (byte) & 0x3f;
297 *(dst++) = base64[index];
304 static void base64_init(void)
307 memset(b2a, -1, sizeof(b2a));
308 /* Initialize base-64 Conversion table */
314 base64[x + 26] = 'a' + x;
315 b2a['a' + x] = x + 26;
318 base64[x + 52] = '0' + x;
319 b2a['0' + x] = x + 52;
328 if (b2a[(int)base64[x]] != x) {
329 fprintf(stderr, "!!! %d failed\n", x);
331 fprintf(stderr, "--- %d passed\n", x);
336 /* Recursive thread safe replacement of inet_ntoa */
337 const char *ast_inet_ntoa(char *buf, int bufsiz, struct in_addr ia)
339 return inet_ntop(AF_INET, &ia, buf, bufsiz);
342 int ast_utils_init(void)