First pass at properly handling account codes in forwarding
[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 #include <ctype.h>
13 #include <string.h>
14 #include <unistd.h>
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>
21
22 static char base64[64];
23 static char b2a[256];
24
25 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
26
27 /* duh? ERANGE value copied from web... */
28 #define ERANGE 34
29 #undef gethostbyname
30
31 AST_MUTEX_DEFINE_STATIC(__mutex);
32
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, 
36                                 int *h_errnop) 
37 {
38         int hsave;
39         struct hostent *ph;
40         ast_mutex_lock(&__mutex); /* begin critical area */
41         hsave = h_errno;
42
43         ph = gethostbyname(name);
44         *h_errnop = h_errno; /* copy h_errno to *h_herrnop */
45         if (ph == NULL) {
46                 *result = NULL;
47         } else {
48                 char **p, **q;
49                 char *pbuf;
50                 int nbytes=0;
51                 int naddr=0, naliases=0;
52                 /* determine if we have enough space in buf */
53
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 */
58                         naddr++;
59                 }
60                 nbytes += sizeof(*p); /* one more for the terminating NULL */
61
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 */
66                         naliases++;
67                 }
68                 nbytes += sizeof(*p); /* one more for the terminating NULL */
69
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 */
72                 if(nbytes > buflen) {
73                         *result = NULL;
74                         ast_mutex_unlock(&__mutex); /* end critical area */
75                         return ERANGE; /* not enough space in buf!! */
76                 }
77
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)]:
81                         pointers to addresses
82                         at [naddr * sizeof(*p)]:
83                         NULL
84                         from [(naddr+1) * sizeof(*p)] to [(naddr+naliases) * sizeof(*p)] :
85                         pointers to aliases
86                         at [(naddr+naliases+1) * sizeof(*p)]:
87                         NULL
88                         then naddr addresses (fixed length), and naliases aliases (asciiz).
89                 */
90
91                 *ret = *ph;   /* copy whole structure (not its address!) */
92
93                 /* copy addresses */
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 */
101                 }
102                 *q++ = NULL; /* address list terminator */
103
104                 /* copy aliases */
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 */
111                 }
112                 *q++ = NULL; /* terminator */
113
114                 strcpy(pbuf, ph->h_name); /* copy alias strings */
115                 ret->h_name = pbuf;
116                 pbuf += strlen(ph->h_name); /* advance pbuf */
117                 *pbuf++ = 0; /* string terminator */
118
119                 *result = ret;  /* and let *result point to structure */
120
121         }
122         h_errno = hsave;  /* restore h_errno */
123         ast_mutex_unlock(&__mutex); /* end critical area */
124
125         return (*result == NULL); /* return 0 on success, non-zero on error */
126 }
127
128
129 #endif
130
131 /* Recursive thread safe version of gethostbyname that replaces the 
132    standard gethostbyname (which is not recursive)
133 */
134 struct hostent *ast_gethostbyname(const char *host, struct ast_hostent *hp)
135 {
136         int res;
137         int herrno;
138         const char *s;
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
143            pure integer */
144         s = host;
145         while(s && *s) {
146                 if (!isdigit(*s))
147                         break;
148                 s++;
149         }
150         if (!s || !*s)
151                 return NULL;
152         res = gethostbyname_r(host, &hp->hp, hp->buf, sizeof(hp->buf), &result, &herrno);
153
154         if (res || !result || !hp->hp.h_addr_list || !hp->hp.h_addr_list[0])
155                 return NULL;
156         return &hp->hp;
157 }
158
159
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. */
163
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;
169
170 static void *test_thread_body(void *data) 
171
172         ast_mutex_lock(&test_lock);
173         lock_count += 10;
174         if (lock_count != 10) 
175                 test_errors++;
176         ast_mutex_lock(&test_lock);
177         lock_count += 10;
178         if (lock_count != 20) 
179                 test_errors++;
180         ast_mutex_lock(&test_lock2);
181         ast_mutex_unlock(&test_lock);
182         lock_count -= 10;
183         if (lock_count != 10) 
184                 test_errors++;
185         ast_mutex_unlock(&test_lock);
186         lock_count -= 10;
187         ast_mutex_unlock(&test_lock2);
188         if (lock_count != 0) 
189                 test_errors++;
190         return NULL;
191
192
193 int test_for_thread_safety(void)
194
195         ast_mutex_lock(&test_lock2);
196         ast_mutex_lock(&test_lock);
197         lock_count += 1;
198         ast_mutex_lock(&test_lock);
199         lock_count += 1;
200         pthread_create(&test_thread, NULL, test_thread_body, NULL); 
201         usleep(100);
202         if (lock_count != 2) 
203                 test_errors++;
204         ast_mutex_unlock(&test_lock);
205         lock_count -= 1;
206         usleep(100); 
207         if (lock_count != 1) 
208                 test_errors++;
209         ast_mutex_unlock(&test_lock);
210         lock_count -= 1;
211         if (lock_count != 0) 
212                 test_errors++;
213         ast_mutex_unlock(&test_lock2);
214         usleep(100);
215         if (lock_count != 0) 
216                 test_errors++;
217         pthread_join(test_thread, NULL);
218         return(test_errors);          /* return 0 on success. */
219 }
220
221 int ast_base64decode(unsigned char *dst, char *src, int max)
222 {
223         int cnt = 0;
224         unsigned int byte = 0;
225         unsigned int bits = 0;
226         int incnt = 0;
227 #if 0
228         unsigned char *odst = dst;
229 #endif
230         while(*src && (cnt < max)) {
231                 /* Shift in 6 bits of input */
232                 byte <<= 6;
233                 byte |= (b2a[(int)(*src)]) & 0x3f;
234                 bits += 6;
235 #if 0
236                 printf("Add: %c %s\n", *src, binary(b2a[(int)(*src)] & 0x3f, 6));
237 #endif
238                 src++;
239                 incnt++;
240                 /* If we have at least 8 bits left over, take that character 
241                    off the top */
242                 if (bits >= 8)  {
243                         bits -= 8;
244                         *dst = (byte >> bits) & 0xff;
245 #if 0
246                         printf("Remove: %02x %s\n", *dst, binary(*dst, 8));
247 #endif
248                         dst++;
249                         cnt++;
250                 }
251         }
252 #if 0
253         dump(odst, cnt);
254 #endif
255         /* Dont worry about left over bits, they're extra anyway */
256         return cnt;
257 }
258
259 int ast_base64encode(char *dst, unsigned char *src, int srclen, int max)
260 {
261         int cnt = 0;
262         unsigned int byte = 0;
263         int bits = 0;
264         int index;
265         int cntin = 0;
266 #if 0
267         char *odst = dst;
268         dump(src, srclen);
269 #endif
270         /* Reserve one bit for end */
271         max--;
272         while((cntin < srclen) && (cnt < max)) {
273                 byte <<= 8;
274 #if 0
275                 printf("Add: %02x %s\n", *src, binary(*src, 8));
276 #endif
277                 byte |= *(src++);
278                 bits += 8;
279                 cntin++;
280                 while((bits >= 6) && (cnt < max)) {
281                         bits -= 6;
282                         /* We want only the top */
283                         index = (byte >> bits) & 0x3f;
284                         *dst = base64[index];
285 #if 0
286                         printf("Remove: %c %s\n", *dst, binary(index, 6));
287 #endif
288                         dst++;
289                         cnt++;
290                 }
291         }
292         if (bits && (cnt < max)) {
293                 /* Add one last character for the remaining bits, 
294                    padding the rest with 0 */
295                 byte <<= (6 - bits);
296                 index = (byte) & 0x3f;
297                 *(dst++) = base64[index];
298                 cnt++;
299         }
300         *dst = '\0';
301         return cnt;
302 }
303
304 static void base64_init(void)
305 {
306         int x;
307         memset(b2a, -1, sizeof(b2a));
308         /* Initialize base-64 Conversion table */
309         for (x=0;x<26;x++) {
310                 /* A-Z */
311                 base64[x] = 'A' + x;
312                 b2a['A' + x] = x;
313                 /* a-z */
314                 base64[x + 26] = 'a' + x;
315                 b2a['a' + x] = x + 26;
316                 /* 0-9 */
317                 if (x < 10) {
318                         base64[x + 52] = '0' + x;
319                         b2a['0' + x] = x + 52;
320                 }
321         }
322         base64[62] = '+';
323         base64[63] = '/';
324         b2a[(int)'+'] = 62;
325         b2a[(int)'/'] = 63;
326 #if 0
327         for (x=0;x<64;x++) {
328                 if (b2a[(int)base64[x]] != x) {
329                         fprintf(stderr, "!!! %d failed\n", x);
330                 } else
331                         fprintf(stderr, "--- %d passed\n", x);
332         }
333 #endif
334 }
335
336 /* Recursive thread safe replacement of inet_ntoa */
337 const char *ast_inet_ntoa(char *buf, int bufsiz, struct in_addr ia)
338 {
339         return inet_ntop(AF_INET, &ia, buf, bufsiz);
340 }
341
342 int ast_utils_init(void)
343 {
344         base64_init();
345         return 0;
346 }