00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "asterisk.h"
00027
00028 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 304950 $")
00029
00030 #include <ctype.h>
00031 #include <sys/stat.h>
00032 #include <sys/stat.h>
00033
00034 #ifdef HAVE_DEV_URANDOM
00035 #include <fcntl.h>
00036 #endif
00037
00038 #include "asterisk/network.h"
00039
00040 #define AST_API_MODULE
00041 #include "asterisk/lock.h"
00042 #include "asterisk/io.h"
00043 #include "asterisk/md5.h"
00044 #include "asterisk/sha1.h"
00045 #include "asterisk/cli.h"
00046 #include "asterisk/linkedlists.h"
00047
00048 #define AST_API_MODULE
00049 #include "asterisk/strings.h"
00050
00051 #define AST_API_MODULE
00052 #include "asterisk/time.h"
00053
00054 #define AST_API_MODULE
00055 #include "asterisk/stringfields.h"
00056
00057 #define AST_API_MODULE
00058 #include "asterisk/utils.h"
00059
00060 #define AST_API_MODULE
00061 #include "asterisk/threadstorage.h"
00062
00063 #define AST_API_MODULE
00064 #include "asterisk/config.h"
00065
00066 static char base64[64];
00067 static char b2a[256];
00068
00069 AST_THREADSTORAGE(inet_ntoa_buf);
00070
00071 #if !defined(HAVE_GETHOSTBYNAME_R_5) && !defined(HAVE_GETHOSTBYNAME_R_6)
00072
00073 #define ERANGE 34
00074 #undef gethostbyname
00075
00076 AST_MUTEX_DEFINE_STATIC(__mutex);
00077
00078
00079
00080
00081
00082
00083 static int gethostbyname_r (const char *name, struct hostent *ret, char *buf,
00084 size_t buflen, struct hostent **result,
00085 int *h_errnop)
00086 {
00087 int hsave;
00088 struct hostent *ph;
00089 ast_mutex_lock(&__mutex);
00090 hsave = h_errno;
00091
00092 ph = gethostbyname(name);
00093 *h_errnop = h_errno;
00094 if (ph == NULL) {
00095 *result = NULL;
00096 } else {
00097 char **p, **q;
00098 char *pbuf;
00099 int nbytes = 0;
00100 int naddr = 0, naliases = 0;
00101
00102
00103
00104 for (p = ph->h_addr_list; *p != 0; p++) {
00105 nbytes += ph->h_length;
00106 nbytes += sizeof(*p);
00107 naddr++;
00108 }
00109 nbytes += sizeof(*p);
00110
00111
00112 for (p = ph->h_aliases; *p != 0; p++) {
00113 nbytes += (strlen(*p)+1);
00114 nbytes += sizeof(*p);
00115 naliases++;
00116 }
00117 nbytes += sizeof(*p);
00118
00119
00120
00121 if (nbytes > buflen) {
00122 *result = NULL;
00123 ast_mutex_unlock(&__mutex);
00124 return ERANGE;
00125 }
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140 *ret = *ph;
00141
00142
00143 q = (char **)buf;
00144 ret->h_addr_list = q;
00145 pbuf = buf + ((naddr + naliases + 2) * sizeof(*p));
00146 for (p = ph->h_addr_list; *p != 0; p++) {
00147 memcpy(pbuf, *p, ph->h_length);
00148 *q++ = pbuf;
00149 pbuf += ph->h_length;
00150 }
00151 *q++ = NULL;
00152
00153
00154 ret->h_aliases = q;
00155 for (p = ph->h_aliases; *p != 0; p++) {
00156 strcpy(pbuf, *p);
00157 *q++ = pbuf;
00158 pbuf += strlen(*p);
00159 *pbuf++ = 0;
00160 }
00161 *q++ = NULL;
00162
00163 strcpy(pbuf, ph->h_name);
00164 ret->h_name = pbuf;
00165 pbuf += strlen(ph->h_name);
00166 *pbuf++ = 0;
00167
00168 *result = ret;
00169
00170 }
00171 h_errno = hsave;
00172 ast_mutex_unlock(&__mutex);
00173
00174 return (*result == NULL);
00175 }
00176
00177
00178 #endif
00179
00180
00181
00182
00183 struct hostent *ast_gethostbyname(const char *host, struct ast_hostent *hp)
00184 {
00185 int res;
00186 int herrno;
00187 int dots = 0;
00188 const char *s;
00189 struct hostent *result = NULL;
00190
00191
00192
00193
00194 s = host;
00195 res = 0;
00196 while (s && *s) {
00197 if (*s == '.')
00198 dots++;
00199 else if (!isdigit(*s))
00200 break;
00201 s++;
00202 }
00203 if (!s || !*s) {
00204
00205 if (dots != 3)
00206 return NULL;
00207 memset(hp, 0, sizeof(struct ast_hostent));
00208 hp->hp.h_addrtype = AF_INET;
00209 hp->hp.h_addr_list = (void *) hp->buf;
00210 hp->hp.h_addr = hp->buf + sizeof(void *);
00211
00212 hp->hp.h_length = 4;
00213 if (inet_pton(AF_INET, host, hp->hp.h_addr) > 0)
00214 return &hp->hp;
00215 return NULL;
00216
00217 }
00218 #ifdef HAVE_GETHOSTBYNAME_R_5
00219 result = gethostbyname_r(host, &hp->hp, hp->buf, sizeof(hp->buf), &herrno);
00220
00221 if (!result || !hp->hp.h_addr_list || !hp->hp.h_addr_list[0])
00222 return NULL;
00223 #else
00224 res = gethostbyname_r(host, &hp->hp, hp->buf, sizeof(hp->buf), &result, &herrno);
00225
00226 if (res || !result || !hp->hp.h_addr_list || !hp->hp.h_addr_list[0])
00227 return NULL;
00228 #endif
00229 return &hp->hp;
00230 }
00231
00232
00233 void ast_md5_hash(char *output, const char *input)
00234 {
00235 struct MD5Context md5;
00236 unsigned char digest[16];
00237 char *ptr;
00238 int x;
00239
00240 MD5Init(&md5);
00241 MD5Update(&md5, (const unsigned char *) input, strlen(input));
00242 MD5Final(digest, &md5);
00243 ptr = output;
00244 for (x = 0; x < 16; x++)
00245 ptr += sprintf(ptr, "%2.2x", digest[x]);
00246 }
00247
00248
00249 void ast_sha1_hash(char *output, const char *input)
00250 {
00251 struct SHA1Context sha;
00252 char *ptr;
00253 int x;
00254 uint8_t Message_Digest[20];
00255
00256 SHA1Reset(&sha);
00257
00258 SHA1Input(&sha, (const unsigned char *) input, strlen(input));
00259
00260 SHA1Result(&sha, Message_Digest);
00261 ptr = output;
00262 for (x = 0; x < 20; x++)
00263 ptr += sprintf(ptr, "%2.2x", Message_Digest[x]);
00264 }
00265
00266
00267 int ast_base64decode(unsigned char *dst, const char *src, int max)
00268 {
00269 int cnt = 0;
00270 unsigned int byte = 0;
00271 unsigned int bits = 0;
00272 int incnt = 0;
00273 while(*src && *src != '=' && (cnt < max)) {
00274
00275 byte <<= 6;
00276 byte |= (b2a[(int)(*src)]) & 0x3f;
00277 bits += 6;
00278 src++;
00279 incnt++;
00280
00281
00282 if (bits >= 8) {
00283 bits -= 8;
00284 *dst = (byte >> bits) & 0xff;
00285 dst++;
00286 cnt++;
00287 }
00288 }
00289
00290 return cnt;
00291 }
00292
00293
00294 int ast_base64encode_full(char *dst, const unsigned char *src, int srclen, int max, int linebreaks)
00295 {
00296 int cnt = 0;
00297 int col = 0;
00298 unsigned int byte = 0;
00299 int bits = 0;
00300 int cntin = 0;
00301
00302 max--;
00303 while ((cntin < srclen) && (cnt < max)) {
00304 byte <<= 8;
00305 byte |= *(src++);
00306 bits += 8;
00307 cntin++;
00308 if ((bits == 24) && (cnt + 4 <= max)) {
00309 *dst++ = base64[(byte >> 18) & 0x3f];
00310 *dst++ = base64[(byte >> 12) & 0x3f];
00311 *dst++ = base64[(byte >> 6) & 0x3f];
00312 *dst++ = base64[byte & 0x3f];
00313 cnt += 4;
00314 col += 4;
00315 bits = 0;
00316 byte = 0;
00317 }
00318 if (linebreaks && (cnt < max) && (col == 64)) {
00319 *dst++ = '\n';
00320 cnt++;
00321 col = 0;
00322 }
00323 }
00324 if (bits && (cnt + 4 <= max)) {
00325
00326
00327 byte <<= 24 - bits;
00328 *dst++ = base64[(byte >> 18) & 0x3f];
00329 *dst++ = base64[(byte >> 12) & 0x3f];
00330 if (bits == 16)
00331 *dst++ = base64[(byte >> 6) & 0x3f];
00332 else
00333 *dst++ = '=';
00334 *dst++ = '=';
00335 cnt += 4;
00336 }
00337 if (linebreaks && (cnt < max)) {
00338 *dst++ = '\n';
00339 cnt++;
00340 }
00341 *dst = '\0';
00342 return cnt;
00343 }
00344
00345 int ast_base64encode(char *dst, const unsigned char *src, int srclen, int max)
00346 {
00347 return ast_base64encode_full(dst, src, srclen, max, 0);
00348 }
00349
00350 static void base64_init(void)
00351 {
00352 int x;
00353 memset(b2a, -1, sizeof(b2a));
00354
00355 for (x = 0; x < 26; x++) {
00356
00357 base64[x] = 'A' + x;
00358 b2a['A' + x] = x;
00359
00360 base64[x + 26] = 'a' + x;
00361 b2a['a' + x] = x + 26;
00362
00363 if (x < 10) {
00364 base64[x + 52] = '0' + x;
00365 b2a['0' + x] = x + 52;
00366 }
00367 }
00368 base64[62] = '+';
00369 base64[63] = '/';
00370 b2a[(int)'+'] = 62;
00371 b2a[(int)'/'] = 63;
00372 }
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386 char *ast_uri_encode(const char *string, char *outbuf, int buflen, int do_special_char)
00387 {
00388 const char *ptr = string;
00389 char *out = outbuf;
00390 const char *mark = "-_.!~*'()";
00391
00392 while (*ptr && out - outbuf < buflen - 1) {
00393 if ((const signed char) *ptr < 32 || *ptr == 0x7f || *ptr == '%' ||
00394 (do_special_char &&
00395 !(*ptr >= '0' && *ptr <= '9') &&
00396 !(*ptr >= 'A' && *ptr <= 'Z') &&
00397 !(*ptr >= 'a' && *ptr <= 'z') &&
00398 !strchr(mark, *ptr))) {
00399 if (out - outbuf >= buflen - 3) {
00400 break;
00401 }
00402
00403 out += sprintf(out, "%%%02X", (unsigned char) *ptr);
00404 } else {
00405 *out = *ptr;
00406 out++;
00407 }
00408 ptr++;
00409 }
00410
00411 if (buflen) {
00412 *out = '\0';
00413 }
00414
00415 return outbuf;
00416 }
00417
00418
00419 void ast_uri_decode(char *s)
00420 {
00421 char *o;
00422 unsigned int tmp;
00423
00424 for (o = s; *s; s++, o++) {
00425 if (*s == '%' && s[1] != '\0' && s[2] != '\0' && sscanf(s + 1, "%2x", &tmp) == 1) {
00426
00427 *o = tmp;
00428 s += 2;
00429 } else
00430 *o = *s;
00431 }
00432 *o = '\0';
00433 }
00434
00435
00436 const char *ast_inet_ntoa(struct in_addr ia)
00437 {
00438 char *buf;
00439
00440 if (!(buf = ast_threadstorage_get(&inet_ntoa_buf, INET_ADDRSTRLEN)))
00441 return "";
00442
00443 return inet_ntop(AF_INET, &ia, buf, INET_ADDRSTRLEN);
00444 }
00445
00446 #ifdef HAVE_DEV_URANDOM
00447 static int dev_urandom_fd;
00448 #endif
00449
00450 #ifndef __linux__
00451 #undef pthread_create
00452 #endif
00453
00454 #if !defined(LOW_MEMORY)
00455
00456 #ifdef DEBUG_THREADS
00457
00458
00459 #define AST_MAX_LOCKS 64
00460
00461
00462 #undef pthread_mutex_t
00463 #undef pthread_mutex_lock
00464 #undef pthread_mutex_unlock
00465 #undef pthread_mutex_init
00466 #undef pthread_mutex_destroy
00467
00468
00469
00470
00471
00472
00473 struct thr_lock_info {
00474
00475 pthread_t thread_id;
00476
00477 const char *thread_name;
00478
00479 struct {
00480 const char *file;
00481 int line_num;
00482 const char *func;
00483 const char *lock_name;
00484 void *lock_addr;
00485 int times_locked;
00486 enum ast_lock_type type;
00487
00488 int pending:2;
00489 #ifdef HAVE_BKTR
00490 struct ast_bt *backtrace;
00491 #endif
00492 } locks[AST_MAX_LOCKS];
00493
00494
00495
00496 unsigned int num_locks;
00497
00498
00499 pthread_mutex_t lock;
00500 AST_LIST_ENTRY(thr_lock_info) entry;
00501 };
00502
00503
00504
00505
00506 AST_MUTEX_DEFINE_STATIC(lock_infos_lock);
00507
00508
00509
00510 static AST_LIST_HEAD_NOLOCK_STATIC(lock_infos, thr_lock_info);
00511
00512
00513
00514
00515
00516
00517 static void lock_info_destroy(void *data)
00518 {
00519 struct thr_lock_info *lock_info = data;
00520 int i;
00521
00522 pthread_mutex_lock(&lock_infos_lock.mutex);
00523 AST_LIST_REMOVE(&lock_infos, lock_info, entry);
00524 pthread_mutex_unlock(&lock_infos_lock.mutex);
00525
00526
00527 for (i = 0; i < lock_info->num_locks; i++) {
00528 if (lock_info->locks[i].pending == -1) {
00529
00530
00531 break;
00532 }
00533
00534 ast_log(LOG_ERROR,
00535 "Thread '%s' still has a lock! - '%s' (%p) from '%s' in %s:%d!\n",
00536 lock_info->thread_name,
00537 lock_info->locks[i].lock_name,
00538 lock_info->locks[i].lock_addr,
00539 lock_info->locks[i].func,
00540 lock_info->locks[i].file,
00541 lock_info->locks[i].line_num
00542 );
00543 }
00544
00545 pthread_mutex_destroy(&lock_info->lock);
00546 if (lock_info->thread_name)
00547 free((void *) lock_info->thread_name);
00548 free(lock_info);
00549 }
00550
00551
00552
00553
00554 AST_THREADSTORAGE_CUSTOM(thread_lock_info, NULL, lock_info_destroy);
00555 #ifdef HAVE_BKTR
00556 void ast_store_lock_info(enum ast_lock_type type, const char *filename,
00557 int line_num, const char *func, const char *lock_name, void *lock_addr, struct ast_bt *bt)
00558 #else
00559 void ast_store_lock_info(enum ast_lock_type type, const char *filename,
00560 int line_num, const char *func, const char *lock_name, void *lock_addr)
00561 #endif
00562 {
00563 struct thr_lock_info *lock_info;
00564 int i;
00565
00566 if (!(lock_info = ast_threadstorage_get(&thread_lock_info, sizeof(*lock_info))))
00567 return;
00568
00569 pthread_mutex_lock(&lock_info->lock);
00570
00571 for (i = 0; i < lock_info->num_locks; i++) {
00572 if (lock_info->locks[i].lock_addr == lock_addr) {
00573 lock_info->locks[i].times_locked++;
00574 #ifdef HAVE_BKTR
00575 lock_info->locks[i].backtrace = bt;
00576 #endif
00577 pthread_mutex_unlock(&lock_info->lock);
00578 return;
00579 }
00580 }
00581
00582 if (lock_info->num_locks == AST_MAX_LOCKS) {
00583
00584 fprintf(stderr, "XXX ERROR XXX A thread holds more locks than '%d'."
00585 " Increase AST_MAX_LOCKS!\n", AST_MAX_LOCKS);
00586 pthread_mutex_unlock(&lock_info->lock);
00587 return;
00588 }
00589
00590 if (i && lock_info->locks[i - 1].pending == -1) {
00591
00592
00593
00594 i--;
00595 lock_info->num_locks--;
00596 memset(&lock_info->locks[i], 0, sizeof(lock_info->locks[0]));
00597 }
00598
00599 lock_info->locks[i].file = filename;
00600 lock_info->locks[i].line_num = line_num;
00601 lock_info->locks[i].func = func;
00602 lock_info->locks[i].lock_name = lock_name;
00603 lock_info->locks[i].lock_addr = lock_addr;
00604 lock_info->locks[i].times_locked = 1;
00605 lock_info->locks[i].type = type;
00606 lock_info->locks[i].pending = 1;
00607 #ifdef HAVE_BKTR
00608 lock_info->locks[i].backtrace = bt;
00609 #endif
00610 lock_info->num_locks++;
00611
00612 pthread_mutex_unlock(&lock_info->lock);
00613 }
00614
00615 void ast_mark_lock_acquired(void *lock_addr)
00616 {
00617 struct thr_lock_info *lock_info;
00618
00619 if (!(lock_info = ast_threadstorage_get(&thread_lock_info, sizeof(*lock_info))))
00620 return;
00621
00622 pthread_mutex_lock(&lock_info->lock);
00623 if (lock_info->locks[lock_info->num_locks - 1].lock_addr == lock_addr) {
00624 lock_info->locks[lock_info->num_locks - 1].pending = 0;
00625 }
00626 pthread_mutex_unlock(&lock_info->lock);
00627 }
00628
00629 void ast_mark_lock_failed(void *lock_addr)
00630 {
00631 struct thr_lock_info *lock_info;
00632
00633 if (!(lock_info = ast_threadstorage_get(&thread_lock_info, sizeof(*lock_info))))
00634 return;
00635
00636 pthread_mutex_lock(&lock_info->lock);
00637 if (lock_info->locks[lock_info->num_locks - 1].lock_addr == lock_addr) {
00638 lock_info->locks[lock_info->num_locks - 1].pending = -1;
00639 lock_info->locks[lock_info->num_locks - 1].times_locked--;
00640 }
00641 pthread_mutex_unlock(&lock_info->lock);
00642 }
00643
00644 int ast_find_lock_info(void *lock_addr, char *filename, size_t filename_size, int *lineno, char *func, size_t func_size, char *mutex_name, size_t mutex_name_size)
00645 {
00646 struct thr_lock_info *lock_info;
00647 int i = 0;
00648
00649 if (!(lock_info = ast_threadstorage_get(&thread_lock_info, sizeof(*lock_info))))
00650 return -1;
00651
00652 pthread_mutex_lock(&lock_info->lock);
00653
00654 for (i = lock_info->num_locks - 1; i >= 0; i--) {
00655 if (lock_info->locks[i].lock_addr == lock_addr)
00656 break;
00657 }
00658
00659 if (i == -1) {
00660
00661 pthread_mutex_unlock(&lock_info->lock);
00662 return -1;
00663 }
00664
00665 ast_copy_string(filename, lock_info->locks[i].file, filename_size);
00666 *lineno = lock_info->locks[i].line_num;
00667 ast_copy_string(func, lock_info->locks[i].func, func_size);
00668 ast_copy_string(mutex_name, lock_info->locks[i].lock_name, mutex_name_size);
00669
00670 pthread_mutex_unlock(&lock_info->lock);
00671
00672 return 0;
00673 }
00674
00675 #ifdef HAVE_BKTR
00676 void ast_remove_lock_info(void *lock_addr, struct ast_bt *bt)
00677 #else
00678 void ast_remove_lock_info(void *lock_addr)
00679 #endif
00680 {
00681 struct thr_lock_info *lock_info;
00682 int i = 0;
00683
00684 if (!(lock_info = ast_threadstorage_get(&thread_lock_info, sizeof(*lock_info))))
00685 return;
00686
00687 pthread_mutex_lock(&lock_info->lock);
00688
00689 for (i = lock_info->num_locks - 1; i >= 0; i--) {
00690 if (lock_info->locks[i].lock_addr == lock_addr)
00691 break;
00692 }
00693
00694 if (i == -1) {
00695
00696 pthread_mutex_unlock(&lock_info->lock);
00697 return;
00698 }
00699
00700 if (lock_info->locks[i].times_locked > 1) {
00701 lock_info->locks[i].times_locked--;
00702 #ifdef HAVE_BKTR
00703 lock_info->locks[i].backtrace = bt;
00704 #endif
00705 pthread_mutex_unlock(&lock_info->lock);
00706 return;
00707 }
00708
00709 if (i < lock_info->num_locks - 1) {
00710
00711 memmove(&lock_info->locks[i], &lock_info->locks[i + 1],
00712 (lock_info->num_locks - (i + 1)) * sizeof(lock_info->locks[0]));
00713 }
00714
00715 lock_info->num_locks--;
00716
00717 pthread_mutex_unlock(&lock_info->lock);
00718 }
00719
00720 static const char *locktype2str(enum ast_lock_type type)
00721 {
00722 switch (type) {
00723 case AST_MUTEX:
00724 return "MUTEX";
00725 case AST_RDLOCK:
00726 return "RDLOCK";
00727 case AST_WRLOCK:
00728 return "WRLOCK";
00729 }
00730
00731 return "UNKNOWN";
00732 }
00733
00734 #ifdef HAVE_BKTR
00735 static void append_backtrace_information(struct ast_str **str, struct ast_bt *bt)
00736 {
00737 char **symbols;
00738
00739 if (!bt) {
00740 ast_str_append(str, 0, "\tNo backtrace to print\n");
00741 return;
00742 }
00743
00744 if ((symbols = ast_bt_get_symbols(bt->addresses, bt->num_frames))) {
00745 int frame_iterator;
00746
00747 for (frame_iterator = 0; frame_iterator < bt->num_frames; ++frame_iterator) {
00748 ast_str_append(str, 0, "\t%s\n", symbols[frame_iterator]);
00749 }
00750
00751 free(symbols);
00752 } else {
00753 ast_str_append(str, 0, "\tCouldn't retrieve backtrace symbols\n");
00754 }
00755 }
00756 #endif
00757
00758 static void append_lock_information(struct ast_str **str, struct thr_lock_info *lock_info, int i)
00759 {
00760 int j;
00761 ast_mutex_t *lock;
00762 struct ast_lock_track *lt;
00763
00764 ast_str_append(str, 0, "=== ---> %sLock #%d (%s): %s %d %s %s %p (%d)\n",
00765 lock_info->locks[i].pending > 0 ? "Waiting for " :
00766 lock_info->locks[i].pending < 0 ? "Tried and failed to get " : "", i,
00767 lock_info->locks[i].file,
00768 locktype2str(lock_info->locks[i].type),
00769 lock_info->locks[i].line_num,
00770 lock_info->locks[i].func, lock_info->locks[i].lock_name,
00771 lock_info->locks[i].lock_addr,
00772 lock_info->locks[i].times_locked);
00773 #ifdef HAVE_BKTR
00774 append_backtrace_information(str, lock_info->locks[i].backtrace);
00775 #endif
00776
00777 if (!lock_info->locks[i].pending || lock_info->locks[i].pending == -1)
00778 return;
00779
00780
00781 if (lock_info->locks[i].type != AST_MUTEX)
00782 return;
00783
00784 lock = lock_info->locks[i].lock_addr;
00785 lt = lock->track;
00786 ast_reentrancy_lock(lt);
00787 for (j = 0; *str && j < lt->reentrancy; j++) {
00788 ast_str_append(str, 0, "=== --- ---> Locked Here: %s line %d (%s)\n",
00789 lt->file[j], lt->lineno[j], lt->func[j]);
00790 }
00791 ast_reentrancy_unlock(lt);
00792 }
00793
00794
00795
00796
00797
00798
00799
00800
00801
00802
00803
00804
00805
00806
00807
00808
00809
00810
00811
00812
00813
00814 void log_show_lock(void *this_lock_addr)
00815 {
00816 struct thr_lock_info *lock_info;
00817 struct ast_str *str;
00818
00819 if (!(str = ast_str_create(4096))) {
00820 ast_log(LOG_NOTICE,"Could not create str\n");
00821 return;
00822 }
00823
00824
00825 pthread_mutex_lock(&lock_infos_lock.mutex);
00826 AST_LIST_TRAVERSE(&lock_infos, lock_info, entry) {
00827 int i;
00828 pthread_mutex_lock(&lock_info->lock);
00829 for (i = 0; str && i < lock_info->num_locks; i++) {
00830
00831
00832 if (lock_info->locks[i].lock_addr == this_lock_addr) {
00833 append_lock_information(&str, lock_info, i);
00834 ast_log(LOG_NOTICE, "%s", ast_str_buffer(str));
00835 break;
00836 }
00837 }
00838 pthread_mutex_unlock(&lock_info->lock);
00839 }
00840 pthread_mutex_unlock(&lock_infos_lock.mutex);
00841 ast_free(str);
00842 }
00843
00844
00845 static char *handle_show_locks(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00846 {
00847 struct thr_lock_info *lock_info;
00848 struct ast_str *str;
00849
00850 if (!(str = ast_str_create(4096)))
00851 return CLI_FAILURE;
00852
00853 switch (cmd) {
00854 case CLI_INIT:
00855 e->command = "core show locks";
00856 e->usage =
00857 "Usage: core show locks\n"
00858 " This command is for lock debugging. It prints out which locks\n"
00859 "are owned by each active thread.\n";
00860 return NULL;
00861
00862 case CLI_GENERATE:
00863 return NULL;
00864 }
00865
00866 ast_str_append(&str, 0, "\n"
00867 "=======================================================================\n"
00868 "=== Currently Held Locks ==============================================\n"
00869 "=======================================================================\n"
00870 "===\n"
00871 "=== <pending> <lock#> (<file>): <lock type> <line num> <function> <lock name> <lock addr> (times locked)\n"
00872 "===\n");
00873
00874 if (!str)
00875 return CLI_FAILURE;
00876
00877 pthread_mutex_lock(&lock_infos_lock.mutex);
00878 AST_LIST_TRAVERSE(&lock_infos, lock_info, entry) {
00879 int i;
00880 if (lock_info->num_locks) {
00881 ast_str_append(&str, 0, "=== Thread ID: %ld (%s)\n", (long) lock_info->thread_id,
00882 lock_info->thread_name);
00883 pthread_mutex_lock(&lock_info->lock);
00884 for (i = 0; str && i < lock_info->num_locks; i++) {
00885 append_lock_information(&str, lock_info, i);
00886 }
00887 pthread_mutex_unlock(&lock_info->lock);
00888 if (!str)
00889 break;
00890 ast_str_append(&str, 0, "=== -------------------------------------------------------------------\n"
00891 "===\n");
00892 if (!str)
00893 break;
00894 }
00895 }
00896 pthread_mutex_unlock(&lock_infos_lock.mutex);
00897
00898 if (!str)
00899 return CLI_FAILURE;
00900
00901 ast_str_append(&str, 0, "=======================================================================\n"
00902 "\n");
00903
00904 if (!str)
00905 return CLI_FAILURE;
00906
00907 ast_cli(a->fd, "%s", ast_str_buffer(str));
00908
00909 ast_free(str);
00910
00911 return CLI_SUCCESS;
00912 }
00913
00914 static struct ast_cli_entry utils_cli[] = {
00915 AST_CLI_DEFINE(handle_show_locks, "Show which locks are held by which thread"),
00916 };
00917
00918 #endif
00919
00920
00921
00922
00923
00924
00925 struct thr_arg {
00926 void *(*start_routine)(void *);
00927 void *data;
00928 char *name;
00929 };
00930
00931
00932
00933
00934
00935
00936
00937
00938 static void *dummy_start(void *data)
00939 {
00940 void *ret;
00941 struct thr_arg a = *((struct thr_arg *) data);
00942 #ifdef DEBUG_THREADS
00943 struct thr_lock_info *lock_info;
00944 pthread_mutexattr_t mutex_attr;
00945 #endif
00946
00947
00948
00949
00950
00951
00952 ast_free(data);
00953 ast_register_thread(a.name);
00954 pthread_cleanup_push(ast_unregister_thread, (void *) pthread_self());
00955
00956 #ifdef DEBUG_THREADS
00957 if (!(lock_info = ast_threadstorage_get(&thread_lock_info, sizeof(*lock_info))))
00958 return NULL;
00959
00960 lock_info->thread_id = pthread_self();
00961 lock_info->thread_name = strdup(a.name);
00962
00963 pthread_mutexattr_init(&mutex_attr);
00964 pthread_mutexattr_settype(&mutex_attr, AST_MUTEX_KIND);
00965 pthread_mutex_init(&lock_info->lock, &mutex_attr);
00966 pthread_mutexattr_destroy(&mutex_attr);
00967
00968 pthread_mutex_lock(&lock_infos_lock.mutex);
00969 AST_LIST_INSERT_TAIL(&lock_infos, lock_info, entry);
00970 pthread_mutex_unlock(&lock_infos_lock.mutex);
00971 #endif
00972
00973 ret = a.start_routine(a.data);
00974
00975 pthread_cleanup_pop(1);
00976
00977 return ret;
00978 }
00979
00980 #endif
00981
00982 int ast_pthread_create_stack(pthread_t *thread, pthread_attr_t *attr, void *(*start_routine)(void *),
00983 void *data, size_t stacksize, const char *file, const char *caller,
00984 int line, const char *start_fn)
00985 {
00986 #if !defined(LOW_MEMORY)
00987 struct thr_arg *a;
00988 #endif
00989
00990 if (!attr) {
00991 attr = alloca(sizeof(*attr));
00992 pthread_attr_init(attr);
00993 }
00994
00995 #ifdef __linux__
00996
00997
00998
00999
01000
01001
01002
01003 if ((errno = pthread_attr_setinheritsched(attr, PTHREAD_INHERIT_SCHED)))
01004 ast_log(LOG_WARNING, "pthread_attr_setinheritsched: %s\n", strerror(errno));
01005 #endif
01006
01007 if (!stacksize)
01008 stacksize = AST_STACKSIZE;
01009
01010 if ((errno = pthread_attr_setstacksize(attr, stacksize ? stacksize : AST_STACKSIZE)))
01011 ast_log(LOG_WARNING, "pthread_attr_setstacksize: %s\n", strerror(errno));
01012
01013 #if !defined(LOW_MEMORY)
01014 if ((a = ast_malloc(sizeof(*a)))) {
01015 a->start_routine = start_routine;
01016 a->data = data;
01017 start_routine = dummy_start;
01018 if (asprintf(&a->name, "%-20s started at [%5d] %s %s()",
01019 start_fn, line, file, caller) < 0) {
01020 ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno));
01021 a->name = NULL;
01022 }
01023 data = a;
01024 }
01025 #endif
01026
01027 return pthread_create(thread, attr, start_routine, data);
01028 }
01029
01030
01031 int ast_pthread_create_detached_stack(pthread_t *thread, pthread_attr_t *attr, void *(*start_routine)(void *),
01032 void *data, size_t stacksize, const char *file, const char *caller,
01033 int line, const char *start_fn)
01034 {
01035 unsigned char attr_destroy = 0;
01036 int res;
01037
01038 if (!attr) {
01039 attr = alloca(sizeof(*attr));
01040 pthread_attr_init(attr);
01041 attr_destroy = 1;
01042 }
01043
01044 if ((errno = pthread_attr_setdetachstate(attr, PTHREAD_CREATE_DETACHED)))
01045 ast_log(LOG_WARNING, "pthread_attr_setdetachstate: %s\n", strerror(errno));
01046
01047 res = ast_pthread_create_stack(thread, attr, start_routine, data,
01048 stacksize, file, caller, line, start_fn);
01049
01050 if (attr_destroy)
01051 pthread_attr_destroy(attr);
01052
01053 return res;
01054 }
01055
01056 int ast_wait_for_input(int fd, int ms)
01057 {
01058 struct pollfd pfd[1];
01059 memset(pfd, 0, sizeof(pfd));
01060 pfd[0].fd = fd;
01061 pfd[0].events = POLLIN|POLLPRI;
01062 return ast_poll(pfd, 1, ms);
01063 }
01064
01065 static int ast_wait_for_output(int fd, int timeoutms)
01066 {
01067 struct pollfd pfd = {
01068 .fd = fd,
01069 .events = POLLOUT,
01070 };
01071 int res;
01072 struct timeval start = ast_tvnow();
01073 int elapsed = 0;
01074
01075
01076 while ((res = ast_poll(&pfd, 1, timeoutms - elapsed)) <= 0) {
01077 if (res == 0) {
01078
01079 #ifndef STANDALONE
01080 ast_debug(1, "Timed out trying to write\n");
01081 #endif
01082 return -1;
01083 } else if (res == -1) {
01084
01085
01086 if (errno == EINTR || errno == EAGAIN) {
01087 elapsed = ast_tvdiff_ms(ast_tvnow(), start);
01088 if (elapsed >= timeoutms) {
01089 return -1;
01090 }
01091
01092 continue;
01093 }
01094
01095
01096 ast_log(LOG_ERROR, "poll returned error: %s\n", strerror(errno));
01097
01098 return -1;
01099 }
01100 elapsed = ast_tvdiff_ms(ast_tvnow(), start);
01101 if (elapsed >= timeoutms) {
01102 return -1;
01103 }
01104 }
01105
01106 return 0;
01107 }
01108
01109
01110
01111
01112
01113
01114
01115
01116
01117
01118 int ast_carefulwrite(int fd, char *s, int len, int timeoutms)
01119 {
01120 struct timeval start = ast_tvnow();
01121 int res = 0;
01122 int elapsed = 0;
01123
01124 while (len) {
01125 if (ast_wait_for_output(fd, timeoutms - elapsed)) {
01126 return -1;
01127 }
01128
01129 res = write(fd, s, len);
01130
01131 if (res < 0 && errno != EAGAIN && errno != EINTR) {
01132
01133 ast_log(LOG_ERROR, "write() returned error: %s\n", strerror(errno));
01134 return -1;
01135 }
01136
01137 if (res < 0) {
01138
01139 res = 0;
01140 }
01141
01142
01143 len -= res;
01144 s += res;
01145 res = 0;
01146
01147 elapsed = ast_tvdiff_ms(ast_tvnow(), start);
01148 if (elapsed >= timeoutms) {
01149
01150
01151 res = len ? -1 : 0;
01152 break;
01153 }
01154 }
01155
01156 return res;
01157 }
01158
01159 int ast_careful_fwrite(FILE *f, int fd, const char *src, size_t len, int timeoutms)
01160 {
01161 struct timeval start = ast_tvnow();
01162 int n = 0;
01163 int elapsed = 0;
01164
01165 while (len) {
01166 if (ast_wait_for_output(fd, timeoutms - elapsed)) {
01167
01168 return -1;
01169 }
01170
01171
01172 clearerr(f);
01173
01174 n = fwrite(src, 1, len, f);
01175
01176 if (ferror(f) && errno != EINTR && errno != EAGAIN) {
01177
01178 if (!feof(f)) {
01179
01180 ast_log(LOG_ERROR, "fwrite() returned error: %s\n", strerror(errno));
01181 }
01182 n = -1;
01183 break;
01184 }
01185
01186
01187 len -= n;
01188 src += n;
01189
01190 elapsed = ast_tvdiff_ms(ast_tvnow(), start);
01191 if (elapsed >= timeoutms) {
01192
01193
01194 n = len ? -1 : 0;
01195 break;
01196 }
01197 }
01198
01199 while (fflush(f)) {
01200 if (errno == EAGAIN || errno == EINTR) {
01201 continue;
01202 }
01203 if (!feof(f)) {
01204
01205 ast_log(LOG_ERROR, "fflush() returned error: %s\n", strerror(errno));
01206 }
01207 n = -1;
01208 break;
01209 }
01210
01211 return n < 0 ? -1 : 0;
01212 }
01213
01214 char *ast_strip_quoted(char *s, const char *beg_quotes, const char *end_quotes)
01215 {
01216 char *e;
01217 char *q;
01218
01219 s = ast_strip(s);
01220 if ((q = strchr(beg_quotes, *s)) && *q != '\0') {
01221 e = s + strlen(s) - 1;
01222 if (*e == *(end_quotes + (q - beg_quotes))) {
01223 s++;
01224 *e = '\0';
01225 }
01226 }
01227
01228 return s;
01229 }
01230
01231 char *ast_unescape_semicolon(char *s)
01232 {
01233 char *e;
01234 char *work = s;
01235
01236 while ((e = strchr(work, ';'))) {
01237 if ((e > work) && (*(e-1) == '\\')) {
01238 memmove(e - 1, e, strlen(e) + 1);
01239 work = e;
01240 } else {
01241 work = e + 1;
01242 }
01243 }
01244
01245 return s;
01246 }
01247
01248
01249
01250 char *ast_unescape_c(char *src)
01251 {
01252 char c, *ret, *dst;
01253
01254 if (src == NULL)
01255 return NULL;
01256 for (ret = dst = src; (c = *src++); *dst++ = c ) {
01257 if (c != '\\')
01258 continue;
01259 switch ((c = *src++)) {
01260 case '\0':
01261 c = '\\';
01262 break;
01263 case 'b':
01264 c = '\b';
01265 break;
01266 case 'f':
01267 c = '\f';
01268 break;
01269 case 'n':
01270 c = '\n';
01271 break;
01272 case 'r':
01273 c = '\r';
01274 break;
01275 case 't':
01276 c = '\t';
01277 break;
01278 }
01279
01280 }
01281 *dst = '\0';
01282 return ret;
01283 }
01284
01285 int ast_build_string_va(char **buffer, size_t *space, const char *fmt, va_list ap)
01286 {
01287 int result;
01288
01289 if (!buffer || !*buffer || !space || !*space)
01290 return -1;
01291
01292 result = vsnprintf(*buffer, *space, fmt, ap);
01293
01294 if (result < 0)
01295 return -1;
01296 else if (result > *space)
01297 result = *space;
01298
01299 *buffer += result;
01300 *space -= result;
01301 return 0;
01302 }
01303
01304 int ast_build_string(char **buffer, size_t *space, const char *fmt, ...)
01305 {
01306 va_list ap;
01307 int result;
01308
01309 va_start(ap, fmt);
01310 result = ast_build_string_va(buffer, space, fmt, ap);
01311 va_end(ap);
01312
01313 return result;
01314 }
01315
01316 int ast_true(const char *s)
01317 {
01318 if (ast_strlen_zero(s))
01319 return 0;
01320
01321
01322 if (!strcasecmp(s, "yes") ||
01323 !strcasecmp(s, "true") ||
01324 !strcasecmp(s, "y") ||
01325 !strcasecmp(s, "t") ||
01326 !strcasecmp(s, "1") ||
01327 !strcasecmp(s, "on"))
01328 return -1;
01329
01330 return 0;
01331 }
01332
01333 int ast_false(const char *s)
01334 {
01335 if (ast_strlen_zero(s))
01336 return 0;
01337
01338
01339 if (!strcasecmp(s, "no") ||
01340 !strcasecmp(s, "false") ||
01341 !strcasecmp(s, "n") ||
01342 !strcasecmp(s, "f") ||
01343 !strcasecmp(s, "0") ||
01344 !strcasecmp(s, "off"))
01345 return -1;
01346
01347 return 0;
01348 }
01349
01350 #define ONE_MILLION 1000000
01351
01352
01353
01354
01355 static struct timeval tvfix(struct timeval a)
01356 {
01357 if (a.tv_usec >= ONE_MILLION) {
01358 ast_log(LOG_WARNING, "warning too large timestamp %ld.%ld\n",
01359 (long)a.tv_sec, (long int) a.tv_usec);
01360 a.tv_sec += a.tv_usec / ONE_MILLION;
01361 a.tv_usec %= ONE_MILLION;
01362 } else if (a.tv_usec < 0) {
01363 ast_log(LOG_WARNING, "warning negative timestamp %ld.%ld\n",
01364 (long)a.tv_sec, (long int) a.tv_usec);
01365 a.tv_usec = 0;
01366 }
01367 return a;
01368 }
01369
01370 struct timeval ast_tvadd(struct timeval a, struct timeval b)
01371 {
01372
01373 a = tvfix(a);
01374 b = tvfix(b);
01375 a.tv_sec += b.tv_sec;
01376 a.tv_usec += b.tv_usec;
01377 if (a.tv_usec >= ONE_MILLION) {
01378 a.tv_sec++;
01379 a.tv_usec -= ONE_MILLION;
01380 }
01381 return a;
01382 }
01383
01384 struct timeval ast_tvsub(struct timeval a, struct timeval b)
01385 {
01386
01387 a = tvfix(a);
01388 b = tvfix(b);
01389 a.tv_sec -= b.tv_sec;
01390 a.tv_usec -= b.tv_usec;
01391 if (a.tv_usec < 0) {
01392 a.tv_sec-- ;
01393 a.tv_usec += ONE_MILLION;
01394 }
01395 return a;
01396 }
01397 #undef ONE_MILLION
01398
01399
01400
01401
01402 #ifndef linux
01403 AST_MUTEX_DEFINE_STATIC(randomlock);
01404 #endif
01405
01406 long int ast_random(void)
01407 {
01408 long int res;
01409 #ifdef HAVE_DEV_URANDOM
01410 if (dev_urandom_fd >= 0) {
01411 int read_res = read(dev_urandom_fd, &res, sizeof(res));
01412 if (read_res > 0) {
01413 long int rm = RAND_MAX;
01414 res = res < 0 ? ~res : res;
01415 rm++;
01416 return res % rm;
01417 }
01418 }
01419 #endif
01420 #ifdef linux
01421 res = random();
01422 #else
01423 ast_mutex_lock(&randomlock);
01424 res = random();
01425 ast_mutex_unlock(&randomlock);
01426 #endif
01427 return res;
01428 }
01429
01430 char *ast_process_quotes_and_slashes(char *start, char find, char replace_with)
01431 {
01432 char *dataPut = start;
01433 int inEscape = 0;
01434 int inQuotes = 0;
01435
01436 for (; *start; start++) {
01437 if (inEscape) {
01438 *dataPut++ = *start;
01439 inEscape = 0;
01440 } else {
01441 if (*start == '\\') {
01442 inEscape = 1;
01443 } else if (*start == '\'') {
01444 inQuotes = 1 - inQuotes;
01445 } else {
01446
01447 *dataPut++ = inQuotes ? *start : ((*start == find) ? replace_with : *start);
01448 }
01449 }
01450 }
01451 if (start != dataPut)
01452 *dataPut = 0;
01453 return dataPut;
01454 }
01455
01456 void ast_join(char *s, size_t len, const char * const w[])
01457 {
01458 int x, ofs = 0;
01459 const char *src;
01460
01461
01462 if (!s)
01463 return;
01464 for (x = 0; ofs < len && w[x]; x++) {
01465 if (x > 0)
01466 s[ofs++] = ' ';
01467 for (src = w[x]; *src && ofs < len; src++)
01468 s[ofs++] = *src;
01469 }
01470 if (ofs == len)
01471 ofs--;
01472 s[ofs] = '\0';
01473 }
01474
01475
01476
01477
01478
01479
01480
01481
01482
01483
01484
01485
01486 static const struct {
01487 ast_string_field_allocation allocation;
01488 char string[1];
01489 } __ast_string_field_empty_buffer;
01490
01491 ast_string_field __ast_string_field_empty = __ast_string_field_empty_buffer.string;
01492
01493 #define ALLOCATOR_OVERHEAD 48
01494
01495 static size_t optimal_alloc_size(size_t size)
01496 {
01497 unsigned int count;
01498
01499 size += ALLOCATOR_OVERHEAD;
01500
01501 for (count = 1; size; size >>= 1, count++);
01502
01503 return (1 << count) - ALLOCATOR_OVERHEAD;
01504 }
01505
01506
01507
01508
01509
01510 static int add_string_pool(struct ast_string_field_mgr *mgr, struct ast_string_field_pool **pool_head,
01511 size_t size, const char *file, int lineno, const char *func)
01512 {
01513 struct ast_string_field_pool *pool;
01514 size_t alloc_size = optimal_alloc_size(sizeof(*pool) + size);
01515
01516 #if defined(__AST_DEBUG_MALLOC)
01517 if (!(pool = __ast_calloc(1, alloc_size, file, lineno, func))) {
01518 return -1;
01519 }
01520 #else
01521 if (!(pool = ast_calloc(1, alloc_size))) {
01522 return -1;
01523 }
01524 #endif
01525
01526 pool->prev = *pool_head;
01527 pool->size = alloc_size - sizeof(*pool);
01528 *pool_head = pool;
01529 mgr->last_alloc = NULL;
01530
01531 return 0;
01532 }
01533
01534
01535
01536
01537
01538
01539
01540
01541
01542
01543
01544
01545
01546 int __ast_string_field_init(struct ast_string_field_mgr *mgr, struct ast_string_field_pool **pool_head,
01547 int needed, const char *file, int lineno, const char *func)
01548 {
01549 const char **p = (const char **) pool_head + 1;
01550 struct ast_string_field_pool *cur = NULL;
01551 struct ast_string_field_pool *preserve = NULL;
01552
01553
01554 while ((struct ast_string_field_mgr *) p != mgr) {
01555 *p++ = __ast_string_field_empty;
01556 }
01557
01558 mgr->last_alloc = NULL;
01559 #if defined(__AST_DEBUG_MALLOC)
01560 mgr->owner_file = file;
01561 mgr->owner_func = func;
01562 mgr->owner_line = lineno;
01563 #endif
01564 if (needed > 0) {
01565 *pool_head = NULL;
01566 mgr->embedded_pool = NULL;
01567 return add_string_pool(mgr, pool_head, needed, file, lineno, func);
01568 }
01569
01570
01571
01572
01573
01574
01575
01576 if ((needed < 0) && mgr->embedded_pool) {
01577 needed = 0;
01578 }
01579
01580 if (needed < 0) {
01581 cur = *pool_head;
01582 } else if (mgr->embedded_pool) {
01583 preserve = mgr->embedded_pool;
01584 cur = *pool_head;
01585 } else {
01586 if (*pool_head == NULL) {
01587 ast_log(LOG_WARNING, "trying to reset empty pool\n");
01588 return -1;
01589 }
01590 preserve = *pool_head;
01591 cur = preserve->prev;
01592 }
01593
01594 if (preserve) {
01595 preserve->prev = NULL;
01596 preserve->used = preserve->active = 0;
01597 }
01598
01599 while (cur) {
01600 struct ast_string_field_pool *prev = cur->prev;
01601
01602 if (cur != preserve) {
01603 ast_free(cur);
01604 }
01605 cur = prev;
01606 }
01607
01608 *pool_head = preserve;
01609
01610 return 0;
01611 }
01612
01613 ast_string_field __ast_string_field_alloc_space(struct ast_string_field_mgr *mgr,
01614 struct ast_string_field_pool **pool_head, size_t needed)
01615 {
01616 char *result = NULL;
01617 size_t space = (*pool_head)->size - (*pool_head)->used;
01618 size_t to_alloc = needed + sizeof(ast_string_field_allocation);
01619
01620
01621 if (__builtin_expect(to_alloc + 1 > space, 0)) {
01622 size_t new_size = (*pool_head)->size;
01623
01624 while (new_size < to_alloc) {
01625 new_size *= 2;
01626 }
01627
01628 #if defined(__AST_DEBUG_MALLOC)
01629 if (add_string_pool(mgr, pool_head, new_size, mgr->owner_file, mgr->owner_line, mgr->owner_func))
01630 return NULL;
01631 #else
01632 if (add_string_pool(mgr, pool_head, new_size, __FILE__, __LINE__, __FUNCTION__))
01633 return NULL;
01634 #endif
01635 }
01636
01637 result = (*pool_head)->base + (*pool_head)->used;
01638 #ifdef __sparc__
01639
01640 if ((long) result % sizeof(ast_string_field_allocation)) {
01641 result++;
01642 (*pool_head)->used++;
01643 }
01644 #endif
01645 (*pool_head)->used += to_alloc;
01646 (*pool_head)->active += needed;
01647 result += sizeof(ast_string_field_allocation);
01648 AST_STRING_FIELD_ALLOCATION(result) = needed;
01649 mgr->last_alloc = result;
01650
01651 return result;
01652 }
01653
01654 int __ast_string_field_ptr_grow(struct ast_string_field_mgr *mgr,
01655 struct ast_string_field_pool **pool_head, size_t needed,
01656 const ast_string_field *ptr)
01657 {
01658 ssize_t grow = needed - AST_STRING_FIELD_ALLOCATION(*ptr);
01659 size_t space = (*pool_head)->size - (*pool_head)->used;
01660
01661 if (*ptr != mgr->last_alloc) {
01662 return 1;
01663 }
01664
01665 if (space < grow) {
01666 return 1;
01667 }
01668
01669 (*pool_head)->used += grow;
01670 (*pool_head)->active += grow;
01671 AST_STRING_FIELD_ALLOCATION(*ptr) += grow;
01672
01673 return 0;
01674 }
01675
01676 void __ast_string_field_release_active(struct ast_string_field_pool *pool_head,
01677 const ast_string_field ptr)
01678 {
01679 struct ast_string_field_pool *pool, *prev;
01680
01681 if (ptr == __ast_string_field_empty) {
01682 return;
01683 }
01684
01685 for (pool = pool_head, prev = NULL; pool; prev = pool, pool = pool->prev) {
01686 if ((ptr >= pool->base) && (ptr <= (pool->base + pool->size))) {
01687 pool->active -= AST_STRING_FIELD_ALLOCATION(ptr);
01688 if ((pool->active == 0) && prev) {
01689 prev->prev = pool->prev;
01690 ast_free(pool);
01691 }
01692 break;
01693 }
01694 }
01695 }
01696
01697 void __ast_string_field_ptr_build_va(struct ast_string_field_mgr *mgr,
01698 struct ast_string_field_pool **pool_head,
01699 ast_string_field *ptr, const char *format, va_list ap1, va_list ap2)
01700 {
01701 size_t needed;
01702 size_t available;
01703 size_t space = (*pool_head)->size - (*pool_head)->used;
01704 ssize_t grow;
01705 char *target;
01706
01707
01708
01709
01710
01711 if (*ptr != __ast_string_field_empty) {
01712 target = (char *) *ptr;
01713 available = AST_STRING_FIELD_ALLOCATION(*ptr);
01714 if (*ptr == mgr->last_alloc) {
01715 available += space;
01716 }
01717 } else {
01718 target = (*pool_head)->base + (*pool_head)->used + sizeof(ast_string_field_allocation);
01719 #ifdef __sparc__
01720 if ((long) target % sizeof(ast_string_field_allocation)) {
01721 target++;
01722 space--;
01723 }
01724 #endif
01725 available = space - sizeof(ast_string_field_allocation);
01726 }
01727
01728 needed = vsnprintf(target, available, format, ap1) + 1;
01729
01730 va_end(ap1);
01731
01732 if (needed > available) {
01733
01734
01735
01736
01737 if (!(target = (char *) __ast_string_field_alloc_space(mgr, pool_head, needed))) {
01738 return;
01739 }
01740 vsprintf(target, format, ap2);
01741 __ast_string_field_release_active(*pool_head, *ptr);
01742 *ptr = target;
01743 } else if (*ptr != target) {
01744
01745
01746
01747 __ast_string_field_release_active(*pool_head, *ptr);
01748 mgr->last_alloc = *ptr = target;
01749 AST_STRING_FIELD_ALLOCATION(target) = needed;
01750 (*pool_head)->used += needed + sizeof(ast_string_field_allocation);
01751 (*pool_head)->active += needed;
01752 } else if ((grow = (needed - AST_STRING_FIELD_ALLOCATION(*ptr))) > 0) {
01753
01754
01755
01756 (*pool_head)->used += grow;
01757 (*pool_head)->active += grow;
01758 AST_STRING_FIELD_ALLOCATION(*ptr) += grow;
01759 }
01760 }
01761
01762 void __ast_string_field_ptr_build(struct ast_string_field_mgr *mgr,
01763 struct ast_string_field_pool **pool_head,
01764 ast_string_field *ptr, const char *format, ...)
01765 {
01766 va_list ap1, ap2;
01767
01768 va_start(ap1, format);
01769 va_start(ap2, format);
01770
01771 __ast_string_field_ptr_build_va(mgr, pool_head, ptr, format, ap1, ap2);
01772
01773 va_end(ap1);
01774 va_end(ap2);
01775 }
01776
01777 void *__ast_calloc_with_stringfields(unsigned int num_structs, size_t struct_size, size_t field_mgr_offset,
01778 size_t field_mgr_pool_offset, size_t pool_size, const char *file,
01779 int lineno, const char *func)
01780 {
01781 struct ast_string_field_mgr *mgr;
01782 struct ast_string_field_pool *pool;
01783 struct ast_string_field_pool **pool_head;
01784 size_t pool_size_needed = sizeof(*pool) + pool_size;
01785 size_t size_to_alloc = optimal_alloc_size(struct_size + pool_size_needed);
01786 void *allocation;
01787 unsigned int x;
01788
01789 #if defined(__AST_DEBUG_MALLOC)
01790 if (!(allocation = __ast_calloc(num_structs, size_to_alloc, file, lineno, func))) {
01791 return NULL;
01792 }
01793 #else
01794 if (!(allocation = ast_calloc(num_structs, size_to_alloc))) {
01795 return NULL;
01796 }
01797 #endif
01798
01799 for (x = 0; x < num_structs; x++) {
01800 void *base = allocation + (size_to_alloc * x);
01801 const char **p;
01802
01803 mgr = base + field_mgr_offset;
01804 pool_head = base + field_mgr_pool_offset;
01805 pool = base + struct_size;
01806
01807 p = (const char **) pool_head + 1;
01808 while ((struct ast_string_field_mgr *) p != mgr) {
01809 *p++ = __ast_string_field_empty;
01810 }
01811
01812 mgr->embedded_pool = pool;
01813 *pool_head = pool;
01814 pool->size = size_to_alloc - struct_size - sizeof(*pool);
01815 #if defined(__AST_DEBUG_MALLOC)
01816 mgr->owner_file = file;
01817 mgr->owner_func = func;
01818 mgr->owner_line = lineno;
01819 #endif
01820 }
01821
01822 return allocation;
01823 }
01824
01825
01826
01827 AST_MUTEX_DEFINE_STATIC(fetchadd_m);
01828
01829 int ast_atomic_fetchadd_int_slow(volatile int *p, int v)
01830 {
01831 int ret;
01832 ast_mutex_lock(&fetchadd_m);
01833 ret = *p;
01834 *p += v;
01835 ast_mutex_unlock(&fetchadd_m);
01836 return ret;
01837 }
01838
01839
01840
01841
01842 int ast_get_timeval(const char *src, struct timeval *dst, struct timeval _default, int *consumed)
01843 {
01844 long double dtv = 0.0;
01845 int scanned;
01846
01847 if (dst == NULL)
01848 return -1;
01849
01850 *dst = _default;
01851
01852 if (ast_strlen_zero(src))
01853 return -1;
01854
01855
01856 if (sscanf(src, "%30Lf%n", &dtv, &scanned) > 0) {
01857 dst->tv_sec = dtv;
01858 dst->tv_usec = (dtv - dst->tv_sec) * 1000000.0;
01859 if (consumed)
01860 *consumed = scanned;
01861 return 0;
01862 } else
01863 return -1;
01864 }
01865
01866
01867
01868
01869 int ast_get_time_t(const char *src, time_t *dst, time_t _default, int *consumed)
01870 {
01871 long t;
01872 int scanned;
01873
01874 if (dst == NULL)
01875 return -1;
01876
01877 *dst = _default;
01878
01879 if (ast_strlen_zero(src))
01880 return -1;
01881
01882
01883 if (sscanf(src, "%30ld%n", &t, &scanned) == 1) {
01884 *dst = t;
01885 if (consumed)
01886 *consumed = scanned;
01887 return 0;
01888 } else
01889 return -1;
01890 }
01891
01892 void ast_enable_packet_fragmentation(int sock)
01893 {
01894 #if defined(HAVE_IP_MTU_DISCOVER)
01895 int val = IP_PMTUDISC_DONT;
01896
01897 if (setsockopt(sock, IPPROTO_IP, IP_MTU_DISCOVER, &val, sizeof(val)))
01898 ast_log(LOG_WARNING, "Unable to disable PMTU discovery. Large UDP packets may fail to be delivered when sent from this socket.\n");
01899 #endif
01900 }
01901
01902 int ast_mkdir(const char *path, int mode)
01903 {
01904 char *ptr;
01905 int len = strlen(path), count = 0, x, piececount = 0;
01906 char *tmp = ast_strdupa(path);
01907 char **pieces;
01908 char *fullpath = alloca(len + 1);
01909 int res = 0;
01910
01911 for (ptr = tmp; *ptr; ptr++) {
01912 if (*ptr == '/')
01913 count++;
01914 }
01915
01916
01917 pieces = alloca(count * sizeof(*pieces));
01918 for (ptr = tmp; *ptr; ptr++) {
01919 if (*ptr == '/') {
01920 *ptr = '\0';
01921 pieces[piececount++] = ptr + 1;
01922 }
01923 }
01924
01925 *fullpath = '\0';
01926 for (x = 0; x < piececount; x++) {
01927
01928 strcat(fullpath, "/");
01929 strcat(fullpath, pieces[x]);
01930 res = mkdir(fullpath, mode);
01931 if (res && errno != EEXIST)
01932 return errno;
01933 }
01934 return 0;
01935 }
01936
01937 int ast_utils_init(void)
01938 {
01939 #ifdef HAVE_DEV_URANDOM
01940 dev_urandom_fd = open("/dev/urandom", O_RDONLY);
01941 #endif
01942 base64_init();
01943 #ifdef DEBUG_THREADS
01944 #if !defined(LOW_MEMORY)
01945 ast_cli_register_multiple(utils_cli, ARRAY_LEN(utils_cli));
01946 #endif
01947 #endif
01948 return 0;
01949 }
01950
01951
01952
01953
01954
01955
01956
01957
01958
01959 int ast_parse_digest(const char *digest, struct ast_http_digest *d, int request, int pedantic) {
01960 int i;
01961 char *c, key[512], val[512], tmp[512];
01962 struct ast_str *str = ast_str_create(16);
01963
01964 if (ast_strlen_zero(digest) || !d || !str) {
01965 ast_free(str);
01966 return -1;
01967 }
01968
01969 ast_str_set(&str, 0, "%s", digest);
01970
01971 c = ast_skip_blanks(ast_str_buffer(str));
01972
01973 if (strncasecmp(tmp, "Digest ", strlen("Digest "))) {
01974 ast_log(LOG_WARNING, "Missing Digest.\n");
01975 ast_free(str);
01976 return -1;
01977 }
01978 c += strlen("Digest ");
01979
01980
01981 while (*c && *(c = ast_skip_blanks(c))) {
01982
01983 i = 0;
01984 while (*c && *c != '=' && *c != ',' && !isspace(*c)) {
01985 key[i++] = *c++;
01986 }
01987 key[i] = '\0';
01988 c = ast_skip_blanks(c);
01989 if (*c == '=') {
01990 c = ast_skip_blanks(++c);
01991 i = 0;
01992 if (*c == '\"') {
01993
01994 c++;
01995 while (*c && *c != '\"') {
01996 if (*c == '\\' && c[1] != '\0') {
01997 c++;
01998 }
01999 val[i++] = *c++;
02000 }
02001 } else {
02002
02003 while (*c && *c != ',' && !isspace(*c)) {
02004 val[i++] = *c++;
02005 }
02006 }
02007 val[i] = '\0';
02008 }
02009
02010 while (*c && *c != ',') {
02011 c++;
02012 }
02013 if (*c) {
02014 c++;
02015 }
02016
02017 if (!strcasecmp(key, "username")) {
02018 ast_string_field_set(d, username, val);
02019 } else if (!strcasecmp(key, "realm")) {
02020 ast_string_field_set(d, realm, val);
02021 } else if (!strcasecmp(key, "nonce")) {
02022 ast_string_field_set(d, nonce, val);
02023 } else if (!strcasecmp(key, "uri")) {
02024 ast_string_field_set(d, uri, val);
02025 } else if (!strcasecmp(key, "domain")) {
02026 ast_string_field_set(d, domain, val);
02027 } else if (!strcasecmp(key, "response")) {
02028 ast_string_field_set(d, response, val);
02029 } else if (!strcasecmp(key, "algorithm")) {
02030 if (strcasecmp(val, "MD5")) {
02031 ast_log(LOG_WARNING, "Digest algorithm: \"%s\" not supported.\n", val);
02032 return -1;
02033 }
02034 } else if (!strcasecmp(key, "cnonce")) {
02035 ast_string_field_set(d, cnonce, val);
02036 } else if (!strcasecmp(key, "opaque")) {
02037 ast_string_field_set(d, opaque, val);
02038 } else if (!strcasecmp(key, "qop") && !strcasecmp(val, "auth")) {
02039 d->qop = 1;
02040 } else if (!strcasecmp(key, "nc")) {
02041 unsigned long u;
02042 if (sscanf(val, "%30lx", &u) != 1) {
02043 ast_log(LOG_WARNING, "Incorrect Digest nc value: \"%s\".\n", val);
02044 return -1;
02045 }
02046 ast_string_field_set(d, nc, val);
02047 }
02048 }
02049 ast_free(str);
02050
02051
02052 if (ast_strlen_zero(d->realm) || ast_strlen_zero(d->nonce)) {
02053
02054 return -1;
02055 }
02056
02057 if (!request) {
02058
02059 if (ast_strlen_zero(d->username) || ast_strlen_zero(d->uri) || ast_strlen_zero(d->response)) {
02060 return -1;
02061 }
02062
02063 if (pedantic && d->qop && (ast_strlen_zero(d->cnonce) || ast_strlen_zero(d->nc))) {
02064 return -1;
02065 }
02066 }
02067
02068 return 0;
02069 }
02070
02071 #ifndef __AST_DEBUG_MALLOC
02072 int _ast_asprintf(char **ret, const char *file, int lineno, const char *func, const char *fmt, ...)
02073 {
02074 int res;
02075 va_list ap;
02076
02077 va_start(ap, fmt);
02078 if ((res = vasprintf(ret, fmt, ap)) == -1) {
02079 MALLOC_FAILURE_MSG;
02080 }
02081 va_end(ap);
02082
02083 return res;
02084 }
02085 #endif
02086
02087 char *ast_utils_which(const char *binary, char *fullpath, size_t fullpath_size)
02088 {
02089 const char *envPATH = getenv("PATH");
02090 char *tpath, *path;
02091 struct stat unused;
02092 if (!envPATH) {
02093 return NULL;
02094 }
02095 tpath = ast_strdupa(envPATH);
02096 while ((path = strsep(&tpath, ":"))) {
02097 snprintf(fullpath, fullpath_size, "%s/%s", path, binary);
02098 if (!stat(fullpath, &unused)) {
02099 return fullpath;
02100 }
02101 }
02102 return NULL;
02103 }
02104