8d976fee208459d98862f7214cd61e946e316fa2
[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 <asterisk/lock.h>
16 #include <asterisk/utils.h>
17
18 static char base64[64];
19 static char b2a[256];
20
21 #if defined(__FreeBSD__) || defined(__OpenBSD__)
22
23 /* duh? ERANGE value copied from web... */
24 #define ERANGE 34
25 #undef gethostbyname
26
27 AST_MUTEX_DEFINE_STATIC(__mutex);
28
29 static int gethostbyname_r (const char *name, struct hostent *ret, char *buf,
30                                 size_t buflen, struct hostent **result, 
31                                 int *h_errnop) 
32 {
33         int hsave;
34         struct hostent *ph;
35         ast_mutex_lock(&__mutex); /* begin critical area */
36         hsave = h_errno;
37
38         ph = gethostbyname(name);
39         *h_errnop = h_errno; /* copy h_errno to *h_herrnop */
40         if (ph == NULL) {
41                 *result = NULL;
42         } else {
43                 char **p, **q;
44                 char *pbuf;
45                 int nbytes=0;
46                 int naddr=0, naliases=0;
47                 /* determine if we have enough space in buf */
48
49                 /* count how many addresses */
50                 for (p = ph->h_addr_list; *p != 0; p++) {
51                         nbytes += ph->h_length; /* addresses */
52                         nbytes += sizeof(*p); /* pointers */
53                         naddr++;
54                 }
55                 nbytes += sizeof(*p); /* one more for the terminating NULL */
56
57                 /* count how many aliases, and total length of strings */
58                 for (p = ph->h_aliases; *p != 0; p++) {
59                         nbytes += (strlen(*p)+1); /* aliases */
60                         nbytes += sizeof(*p);  /* pointers */
61                         naliases++;
62                 }
63                 nbytes += sizeof(*p); /* one more for the terminating NULL */
64
65                 /* here nbytes is the number of bytes required in buffer */
66                 /* as a terminator must be there, the minimum value is ph->h_length */
67                 if(nbytes > buflen) {
68                         *result = NULL;
69                         ast_mutex_unlock(&__mutex); /* end critical area */
70                         return ERANGE; /* not enough space in buf!! */
71                 }
72
73                 /* There is enough space. Now we need to do a deep copy! */
74                 /* Allocation in buffer:
75                         from [0] to [(naddr-1) * sizeof(*p)]:
76                         pointers to addresses
77                         at [naddr * sizeof(*p)]:
78                         NULL
79                         from [(naddr+1) * sizeof(*p)] to [(naddr+naliases) * sizeof(*p)] :
80                         pointers to aliases
81                         at [(naddr+naliases+1) * sizeof(*p)]:
82                         NULL
83                         then naddr addresses (fixed length), and naliases aliases (asciiz).
84                 */
85
86                 *ret = *ph;   /* copy whole structure (not its address!) */
87
88                 /* copy addresses */
89                 q = (char **)buf; /* pointer to pointers area (type: char **) */
90                 ret->h_addr_list = q; /* update pointer to address list */
91                 pbuf = buf + ((naddr+naliases+2)*sizeof(*p)); /* skip that area */
92                 for (p = ph->h_addr_list; *p != 0; p++) {
93                         memcpy(pbuf, *p, ph->h_length); /* copy address bytes */
94                         *q++ = pbuf; /* the pointer is the one inside buf... */
95                         pbuf += ph->h_length; /* advance pbuf */
96                 }
97                 *q++ = NULL; /* address list terminator */
98
99                 /* copy aliases */
100                 ret->h_aliases = q; /* update pointer to aliases list */
101                 for (p = ph->h_aliases; *p != 0; p++) {
102                         strcpy(pbuf, *p); /* copy alias strings */
103                         *q++ = pbuf; /* the pointer is the one inside buf... */
104                         pbuf += strlen(*p); /* advance pbuf */
105                         *pbuf++ = 0; /* string terminator */
106                 }
107                 *q++ = NULL; /* terminator */
108
109                 strcpy(pbuf, ph->h_name); /* copy alias strings */
110                 ret->h_name = pbuf;
111                 pbuf += strlen(ph->h_name); /* advance pbuf */
112                 *pbuf++ = 0; /* string terminator */
113
114                 *result = ret;  /* and let *result point to structure */
115
116         }
117         h_errno = hsave;  /* restore h_errno */
118         ast_mutex_unlock(&__mutex); /* end critical area */
119
120         return (*result == NULL); /* return 0 on success, non-zero on error */
121 }
122
123
124 #endif
125
126 struct hostent *ast_gethostbyname(const char *host, struct ast_hostent *hp)
127 {
128         int res;
129         int herrno;
130         const char *s;
131         struct hostent *result = NULL;
132         /* Although it is perfectly legitimate to lookup a pure integer, for
133            the sake of the sanity of people who like to name their peers as
134            integers, we break with tradition and refuse to look up a
135            pure integer */
136         s = host;
137         while(s && *s) {
138                 if (!isdigit(*s))
139                         break;
140                 s++;
141         }
142         if (!s || !*s)
143                 return NULL;
144         res = gethostbyname_r(host, &hp->hp, hp->buf, sizeof(hp->buf), &result, &herrno);
145
146         if (res || !result || !hp->hp.h_addr_list || !hp->hp.h_addr_list[0])
147                 return NULL;
148         return &hp->hp;
149 }
150
151
152 /* This is a regression test for recursive mutexes.
153    test_for_thread_safety() will return 0 if recursive mutex locks are
154    working properly, and non-zero if they are not working properly. */
155
156 AST_MUTEX_DEFINE_STATIC(test_lock);
157 AST_MUTEX_DEFINE_STATIC(test_lock2);
158 static pthread_t test_thread; 
159 static int lock_count = 0;
160 static int test_errors = 0;
161
162 static void *test_thread_body(void *data) 
163
164         ast_mutex_lock(&test_lock);
165         lock_count += 10;
166         if (lock_count != 10) 
167                 test_errors++;
168         ast_mutex_lock(&test_lock);
169         lock_count += 10;
170         if (lock_count != 20) 
171                 test_errors++;
172         ast_mutex_lock(&test_lock2);
173         ast_mutex_unlock(&test_lock);
174         lock_count -= 10;
175         if (lock_count != 10) 
176                 test_errors++;
177         ast_mutex_unlock(&test_lock);
178         lock_count -= 10;
179         ast_mutex_unlock(&test_lock2);
180         if (lock_count != 0) 
181                 test_errors++;
182         return NULL;
183
184
185 int test_for_thread_safety(void)
186
187         ast_mutex_lock(&test_lock2);
188         ast_mutex_lock(&test_lock);
189         lock_count += 1;
190         ast_mutex_lock(&test_lock);
191         lock_count += 1;
192         pthread_create(&test_thread, NULL, test_thread_body, NULL); 
193         pthread_yield();
194         usleep(100);
195         if (lock_count != 2) 
196                 test_errors++;
197         ast_mutex_unlock(&test_lock);
198         lock_count -= 1;
199         pthread_yield(); 
200         usleep(100); 
201         if (lock_count != 1) 
202                 test_errors++;
203         ast_mutex_unlock(&test_lock);
204         lock_count -= 1;
205         if (lock_count != 0) 
206                 test_errors++;
207         ast_mutex_unlock(&test_lock2);
208         pthread_yield();
209         usleep(100);
210         if (lock_count != 0) 
211                 test_errors++;
212         pthread_join(test_thread, NULL);
213         return(test_errors);          /* return 0 on success. */
214 }
215
216 int ast_base64decode(unsigned char *dst, char *src, int max)
217 {
218         int cnt = 0;
219         unsigned int byte = 0;
220         unsigned int bits = 0;
221         int incnt = 0;
222 #if 0
223         unsigned char *odst = dst;
224 #endif
225         while(*src && (cnt < max)) {
226                 /* Shift in 6 bits of input */
227                 byte <<= 6;
228                 byte |= (b2a[(int)(*src)]) & 0x3f;
229                 bits += 6;
230 #if 0
231                 printf("Add: %c %s\n", *src, binary(b2a[(int)(*src)] & 0x3f, 6));
232 #endif
233                 src++;
234                 incnt++;
235                 /* If we have at least 8 bits left over, take that character 
236                    off the top */
237                 if (bits >= 8)  {
238                         bits -= 8;
239                         *dst = (byte >> bits) & 0xff;
240 #if 0
241                         printf("Remove: %02x %s\n", *dst, binary(*dst, 8));
242 #endif
243                         dst++;
244                         cnt++;
245                 }
246         }
247 #if 0
248         dump(odst, cnt);
249 #endif
250         /* Dont worry about left over bits, they're extra anyway */
251         return cnt;
252 }
253
254 int ast_base64encode(char *dst, unsigned char *src, int srclen, int max)
255 {
256         int cnt = 0;
257         unsigned int byte = 0;
258         int bits = 0;
259         int index;
260         int cntin = 0;
261 #if 0
262         char *odst = dst;
263         dump(src, srclen);
264 #endif
265         /* Reserve one bit for end */
266         max--;
267         while((cntin < srclen) && (cnt < max)) {
268                 byte <<= 8;
269 #if 0
270                 printf("Add: %02x %s\n", *src, binary(*src, 8));
271 #endif
272                 byte |= *(src++);
273                 bits += 8;
274                 cntin++;
275                 while((bits >= 6) && (cnt < max)) {
276                         bits -= 6;
277                         /* We want only the top */
278                         index = (byte >> bits) & 0x3f;
279                         *dst = base64[index];
280 #if 0
281                         printf("Remove: %c %s\n", *dst, binary(index, 6));
282 #endif
283                         dst++;
284                         cnt++;
285                 }
286         }
287         if (bits && (cnt < max)) {
288                 /* Add one last character for the remaining bits, 
289                    padding the rest with 0 */
290                 byte <<= (6 - bits);
291                 index = (byte) & 0x3f;
292                 *(dst++) = base64[index];
293                 cnt++;
294         }
295         *dst = '\0';
296         return cnt;
297 }
298
299 static void base64_init(void)
300 {
301         int x;
302         memset(b2a, -1, sizeof(b2a));
303         /* Initialize base-64 Conversion table */
304         for (x=0;x<26;x++) {
305                 /* A-Z */
306                 base64[x] = 'A' + x;
307                 b2a['A' + x] = x;
308                 /* a-z */
309                 base64[x + 26] = 'a' + x;
310                 b2a['a' + x] = x + 26;
311                 /* 0-9 */
312                 if (x < 10) {
313                         base64[x + 52] = '0' + x;
314                         b2a['0' + x] = x + 52;
315                 }
316         }
317         base64[62] = '+';
318         base64[63] = '/';
319         b2a[(int)'+'] = 62;
320         b2a[(int)'/'] = 63;
321 #if 0
322         for (x=0;x<64;x++) {
323                 if (b2a[(int)base64[x]] != x) {
324                         fprintf(stderr, "!!! %d failed\n", x);
325                 } else
326                         fprintf(stderr, "--- %d passed\n", x);
327         }
328 #endif
329 }
330
331
332 int ast_utils_init(void)
333 {
334         base64_init();
335         return 0;
336 }