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

Generated on Tue Aug 17 16:13:54 2004 for Asterisk by doxygen 1.3.8