Main Page | Alphabetical List | Data Structures | File List | Data Fields | Globals

utils.c

Go to the documentation of this file.
00001 /* 00002 * Asterisk -- A telephony toolkit for Linux. 00003 * 00004 * Utility functions 00005 * 00006 * Copyright (C) 2004, Digium 00007 * 00008 * This program is free software, distributed under the terms of 00009 * the GNU General Public License 00010 */ 00011 00012 #ifdef Linux /* For strcasestr */ 00013 #define __USE_GNU 00014 #endif 00015 #include <ctype.h> 00016 #include <string.h> 00017 #include <unistd.h> 00018 #include <stdlib.h> 00019 #include <errno.h> 00020 #include <sys/types.h> 00021 #include <sys/socket.h> 00022 #include <netinet/in.h> 00023 #include <arpa/inet.h> 00024 #include <asterisk/lock.h> 00025 #include <asterisk/utils.h> 00026 #include <asterisk/logger.h> 00027 00028 static char base64[64]; 00029 static char b2a[256]; 00030 00031 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined( __NetBSD__ ) || defined(__APPLE__) 00032 00033 /* duh? ERANGE value copied from web... */ 00034 #define ERANGE 34 00035 #undef gethostbyname 00036 00037 AST_MUTEX_DEFINE_STATIC(__mutex); 00038 00039 /* Recursive replacement for gethostbyname for BSD-based systems */ 00040 static int gethostbyname_r (const char *name, struct hostent *ret, char *buf, 00041 size_t buflen, struct hostent **result, 00042 int *h_errnop) 00043 { 00044 int hsave; 00045 struct hostent *ph; 00046 ast_mutex_lock(&__mutex); /* begin critical area */ 00047 hsave = h_errno; 00048 00049 ph = gethostbyname(name); 00050 *h_errnop = h_errno; /* copy h_errno to *h_herrnop */ 00051 if (ph == NULL) { 00052 *result = NULL; 00053 } else { 00054 char **p, **q; 00055 char *pbuf; 00056 int nbytes=0; 00057 int naddr=0, naliases=0; 00058 /* determine if we have enough space in buf */ 00059 00060 /* count how many addresses */ 00061 for (p = ph->h_addr_list; *p != 0; p++) { 00062 nbytes += ph->h_length; /* addresses */ 00063 nbytes += sizeof(*p); /* pointers */ 00064 naddr++; 00065 } 00066 nbytes += sizeof(*p); /* one more for the terminating NULL */ 00067 00068 /* count how many aliases, and total length of strings */ 00069 for (p = ph->h_aliases; *p != 0; p++) { 00070 nbytes += (strlen(*p)+1); /* aliases */ 00071 nbytes += sizeof(*p); /* pointers */ 00072 naliases++; 00073 } 00074 nbytes += sizeof(*p); /* one more for the terminating NULL */ 00075 00076 /* here nbytes is the number of bytes required in buffer */ 00077 /* as a terminator must be there, the minimum value is ph->h_length */ 00078 if(nbytes > buflen) { 00079 *result = NULL; 00080 ast_mutex_unlock(&__mutex); /* end critical area */ 00081 return ERANGE; /* not enough space in buf!! */ 00082 } 00083 00084 /* There is enough space. Now we need to do a deep copy! */ 00085 /* Allocation in buffer: 00086 from [0] to [(naddr-1) * sizeof(*p)]: 00087 pointers to addresses 00088 at [naddr * sizeof(*p)]: 00089 NULL 00090 from [(naddr+1) * sizeof(*p)] to [(naddr+naliases) * sizeof(*p)] : 00091 pointers to aliases 00092 at [(naddr+naliases+1) * sizeof(*p)]: 00093 NULL 00094 then naddr addresses (fixed length), and naliases aliases (asciiz). 00095 */ 00096 00097 *ret = *ph; /* copy whole structure (not its address!) */ 00098 00099 /* copy addresses */ 00100 q = (char **)buf; /* pointer to pointers area (type: char **) */ 00101 ret->h_addr_list = q; /* update pointer to address list */ 00102 pbuf = buf + ((naddr+naliases+2)*sizeof(*p)); /* skip that area */ 00103 for (p = ph->h_addr_list; *p != 0; p++) { 00104 memcpy(pbuf, *p, ph->h_length); /* copy address bytes */ 00105 *q++ = pbuf; /* the pointer is the one inside buf... */ 00106 pbuf += ph->h_length; /* advance pbuf */ 00107 } 00108 *q++ = NULL; /* address list terminator */ 00109 00110 /* copy aliases */ 00111 ret->h_aliases = q; /* update pointer to aliases list */ 00112 for (p = ph->h_aliases; *p != 0; p++) { 00113 strcpy(pbuf, *p); /* copy alias strings */ 00114 *q++ = pbuf; /* the pointer is the one inside buf... */ 00115 pbuf += strlen(*p); /* advance pbuf */ 00116 *pbuf++ = 0; /* string terminator */ 00117 } 00118 *q++ = NULL; /* terminator */ 00119 00120 strcpy(pbuf, ph->h_name); /* copy alias strings */ 00121 ret->h_name = pbuf; 00122 pbuf += strlen(ph->h_name); /* advance pbuf */ 00123 *pbuf++ = 0; /* string terminator */ 00124 00125 *result = ret; /* and let *result point to structure */ 00126 00127 } 00128 h_errno = hsave; /* restore h_errno */ 00129 ast_mutex_unlock(&__mutex); /* end critical area */ 00130 00131 return (*result == NULL); /* return 0 on success, non-zero on error */ 00132 } 00133 00134 00135 #endif 00136 00137 /* Recursive thread safe version of gethostbyname that replaces the 00138 standard gethostbyname (which is not recursive) 00139 */ 00140 struct hostent *ast_gethostbyname(const char *host, struct ast_hostent *hp) 00141 { 00142 int res; 00143 int herrno; 00144 const char *s; 00145 struct hostent *result = NULL; 00146 /* Although it is perfectly legitimate to lookup a pure integer, for 00147 the sake of the sanity of people who like to name their peers as 00148 integers, we break with tradition and refuse to look up a 00149 pure integer */ 00150 s = host; 00151 while(s && *s) { 00152 if (!isdigit(*s)) 00153 break; 00154 s++; 00155 } 00156 if (!s || !*s) 00157 return NULL; 00158 res = gethostbyname_r(host, &hp->hp, hp->buf, sizeof(hp->buf), &result, &herrno); 00159 00160 if (res || !result || !hp->hp.h_addr_list || !hp->hp.h_addr_list[0]) 00161 return NULL; 00162 return &hp->hp; 00163 } 00164 00165 00166 /* This is a regression test for recursive mutexes. 00167 test_for_thread_safety() will return 0 if recursive mutex locks are 00168 working properly, and non-zero if they are not working properly. */ 00169 00170 AST_MUTEX_DEFINE_STATIC(test_lock); 00171 AST_MUTEX_DEFINE_STATIC(test_lock2); 00172 static pthread_t test_thread; 00173 static int lock_count = 0; 00174 static int test_errors = 0; 00175 00176 static void *test_thread_body(void *data) 00177 { 00178 ast_mutex_lock(&test_lock); 00179 lock_count += 10; 00180 if (lock_count != 10) 00181 test_errors++; 00182 ast_mutex_lock(&test_lock); 00183 lock_count += 10; 00184 if (lock_count != 20) 00185 test_errors++; 00186 ast_mutex_lock(&test_lock2); 00187 ast_mutex_unlock(&test_lock); 00188 lock_count -= 10; 00189 if (lock_count != 10) 00190 test_errors++; 00191 ast_mutex_unlock(&test_lock); 00192 lock_count -= 10; 00193 ast_mutex_unlock(&test_lock2); 00194 if (lock_count != 0) 00195 test_errors++; 00196 return NULL; 00197 } 00198 00199 int test_for_thread_safety(void) 00200 { 00201 ast_mutex_lock(&test_lock2); 00202 ast_mutex_lock(&test_lock); 00203 lock_count += 1; 00204 ast_mutex_lock(&test_lock); 00205 lock_count += 1; 00206 ast_pthread_create(&test_thread, NULL, test_thread_body, NULL); 00207 usleep(100); 00208 if (lock_count != 2) 00209 test_errors++; 00210 ast_mutex_unlock(&test_lock); 00211 lock_count -= 1; 00212 usleep(100); 00213 if (lock_count != 1) 00214 test_errors++; 00215 ast_mutex_unlock(&test_lock); 00216 lock_count -= 1; 00217 if (lock_count != 0) 00218 test_errors++; 00219 ast_mutex_unlock(&test_lock2); 00220 usleep(100); 00221 if (lock_count != 0) 00222 test_errors++; 00223 pthread_join(test_thread, NULL); 00224 return(test_errors); /* return 0 on success. */ 00225 } 00226 00227 int ast_base64decode(unsigned char *dst, char *src, int max) 00228 { 00229 int cnt = 0; 00230 unsigned int byte = 0; 00231 unsigned int bits = 0; 00232 int incnt = 0; 00233 #if 0 00234 unsigned char *odst = dst; 00235 #endif 00236 while(*src && (cnt < max)) { 00237 /* Shift in 6 bits of input */ 00238 byte <<= 6; 00239 byte |= (b2a[(int)(*src)]) & 0x3f; 00240 bits += 6; 00241 #if 0 00242 printf("Add: %c %s\n", *src, binary(b2a[(int)(*src)] & 0x3f, 6)); 00243 #endif 00244 src++; 00245 incnt++; 00246 /* If we have at least 8 bits left over, take that character 00247 off the top */ 00248 if (bits >= 8) { 00249 bits -= 8; 00250 *dst = (byte >> bits) & 0xff; 00251 #if 0 00252 printf("Remove: %02x %s\n", *dst, binary(*dst, 8)); 00253 #endif 00254 dst++; 00255 cnt++; 00256 } 00257 } 00258 #if 0 00259 dump(odst, cnt); 00260 #endif 00261 /* Dont worry about left over bits, they're extra anyway */ 00262 return cnt; 00263 } 00264 00265 int ast_base64encode(char *dst, unsigned char *src, int srclen, int max) 00266 { 00267 int cnt = 0; 00268 unsigned int byte = 0; 00269 int bits = 0; 00270 int index; 00271 int cntin = 0; 00272 #if 0 00273 char *odst = dst; 00274 dump(src, srclen); 00275 #endif 00276 /* Reserve one bit for end */ 00277 max--; 00278 while((cntin < srclen) && (cnt < max)) { 00279 byte <<= 8; 00280 #if 0 00281 printf("Add: %02x %s\n", *src, binary(*src, 8)); 00282 #endif 00283 byte |= *(src++); 00284 bits += 8; 00285 cntin++; 00286 while((bits >= 6) && (cnt < max)) { 00287 bits -= 6; 00288 /* We want only the top */ 00289 index = (byte >> bits) & 0x3f; 00290 *dst = base64[index]; 00291 #if 0 00292 printf("Remove: %c %s\n", *dst, binary(index, 6)); 00293 #endif 00294 dst++; 00295 cnt++; 00296 } 00297 } 00298 if (bits && (cnt < max)) { 00299 /* Add one last character for the remaining bits, 00300 padding the rest with 0 */ 00301 byte <<= (6 - bits); 00302 index = (byte) & 0x3f; 00303 *(dst++) = base64[index]; 00304 cnt++; 00305 } 00306 *dst = '\0'; 00307 return cnt; 00308 } 00309 00310 static void base64_init(void) 00311 { 00312 int x; 00313 memset(b2a, -1, sizeof(b2a)); 00314 /* Initialize base-64 Conversion table */ 00315 for (x=0;x<26;x++) { 00316 /* A-Z */ 00317 base64[x] = 'A' + x; 00318 b2a['A' + x] = x; 00319 /* a-z */ 00320 base64[x + 26] = 'a' + x; 00321 b2a['a' + x] = x + 26; 00322 /* 0-9 */ 00323 if (x < 10) { 00324 base64[x + 52] = '0' + x; 00325 b2a['0' + x] = x + 52; 00326 } 00327 } 00328 base64[62] = '+'; 00329 base64[63] = '/'; 00330 b2a[(int)'+'] = 62; 00331 b2a[(int)'/'] = 63; 00332 #if 0 00333 for (x=0;x<64;x++) { 00334 if (b2a[(int)base64[x]] != x) { 00335 fprintf(stderr, "!!! %d failed\n", x); 00336 } else 00337 fprintf(stderr, "--- %d passed\n", x); 00338 } 00339 #endif 00340 } 00341 00342 /* Recursive thread safe replacement of inet_ntoa */ 00343 const char *ast_inet_ntoa(char *buf, int bufsiz, struct in_addr ia) 00344 { 00345 return inet_ntop(AF_INET, &ia, buf, bufsiz); 00346 } 00347 00348 int ast_utils_init(void) 00349 { 00350 base64_init(); 00351 return 0; 00352 } 00353 00354 00355 #ifndef LINUX 00356 #undef pthread_create /* For ast_pthread_create function only */ 00357 int ast_pthread_create(pthread_t *thread, pthread_attr_t *attr, void *(*start_routine)(void *), void *data) 00358 { 00359 pthread_attr_t lattr; 00360 if (!attr) { 00361 pthread_attr_init(&lattr); 00362 attr = &lattr; 00363 } 00364 errno = pthread_attr_setstacksize(attr, PTHREAD_ATTR_STACKSIZE); 00365 if (errno) 00366 ast_log(LOG_WARNING, "pthread_attr_setstacksize returned non-zero: %s\n", strerror(errno)); 00367 return pthread_create(thread, attr, start_routine, data); /* We're in ast_pthread_create, so it's okay */ 00368 } 00369 #endif /* ! LINUX */ 00370 00371 static char *upper(const char *orig, char *buf, int bufsize) 00372 { 00373 int i; 00374 memset(buf, 0, bufsize); 00375 for (i=0; i<bufsize - 1; i++) { 00376 buf[i] = toupper(orig[i]); 00377 if (orig[i] == '\0') { 00378 break; 00379 } 00380 } 00381 return buf; 00382 } 00383 00384 /* Case-insensitive substring matching */ 00385 #ifndef LINUX 00386 char *ast_strcasestr(const char *haystack, const char *needle) 00387 { 00388 char *u1, *u2; 00389 int u1len = strlen(haystack), u2len = strlen(needle); 00390 00391 u1 = alloca(u1len); 00392 u2 = alloca(u2len); 00393 if (u1 && u2) { 00394 char *offset; 00395 if (u2len > u1len) { 00396 /* Needle bigger than haystack */ 00397 return NULL; 00398 } 00399 offset = strstr(upper(haystack, u1, u1len), upper(needle, u2, u2len)); 00400 if (offset) { 00401 /* Return the offset into the original string */ 00402 return ((char *)((unsigned int)haystack + (unsigned int)(offset - u1))); 00403 } else { 00404 return NULL; 00405 } 00406 } else { 00407 ast_log(LOG_ERROR, "Out of memory\n"); 00408 return NULL; 00409 } 00410 } 00411 #endif 00412

Generated on Fri Sep 24 21:03:48 2004 for Asterisk by doxygen 1.3.8