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: 302554 $")
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, 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, (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, 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 doreserved)
00387 {
00388 char *reserved = ";/?:@&=+$,# ";
00389
00390 const char *ptr = string;
00391 char *out = outbuf;
00392
00393
00394 while (*ptr && out - outbuf < buflen - 1) {
00395 if ((*ptr < 32) || (doreserved && strchr(reserved, *ptr))) {
00396 if (out - outbuf >= buflen - 3) {
00397 break;
00398 }
00399
00400 out += sprintf(out, "%%%02x", (unsigned char) *ptr);
00401 } else {
00402 *out = *ptr;
00403 out++;
00404 }
00405 ptr++;
00406 }
00407
00408 if (buflen) {
00409 *out = '\0';
00410 }
00411
00412 return outbuf;
00413 }
00414
00415
00416 void ast_uri_decode(char *s)
00417 {
00418 char *o;
00419 unsigned int tmp;
00420
00421 for (o = s; *s; s++, o++) {
00422 if (*s == '%' && s[1] != '\0' && s[2] != '\0' && sscanf(s + 1, "%2x", &tmp) == 1) {
00423
00424 *o = tmp;
00425 s += 2;
00426 } else
00427 *o = *s;
00428 }
00429 *o = '\0';
00430 }
00431
00432
00433 const char *ast_inet_ntoa(struct in_addr ia)
00434 {
00435 char *buf;
00436
00437 if (!(buf = ast_threadstorage_get(&inet_ntoa_buf, INET_ADDRSTRLEN)))
00438 return "";
00439
00440 return inet_ntop(AF_INET, &ia, buf, INET_ADDRSTRLEN);
00441 }
00442
00443 #ifdef HAVE_DEV_URANDOM
00444 static int dev_urandom_fd;
00445 #endif
00446
00447 #ifndef __linux__
00448 #undef pthread_create
00449 #endif
00450
00451 #if !defined(LOW_MEMORY)
00452
00453 #ifdef DEBUG_THREADS
00454
00455
00456 #define AST_MAX_LOCKS 64
00457
00458
00459 #undef pthread_mutex_t
00460 #undef pthread_mutex_lock
00461 #undef pthread_mutex_unlock
00462 #undef pthread_mutex_init
00463 #undef pthread_mutex_destroy
00464
00465
00466
00467
00468
00469
00470 struct thr_lock_info {
00471
00472 pthread_t thread_id;
00473
00474 const char *thread_name;
00475
00476 struct {
00477 const char *file;
00478 int line_num;
00479 const char *func;
00480 const char *lock_name;
00481 void *lock_addr;
00482 int times_locked;
00483 enum ast_lock_type type;
00484
00485 int pending:2;
00486 #ifdef HAVE_BKTR
00487 struct ast_bt *backtrace;
00488 #endif
00489 } locks[AST_MAX_LOCKS];
00490
00491
00492
00493 unsigned int num_locks;
00494
00495
00496 pthread_mutex_t lock;
00497 AST_LIST_ENTRY(thr_lock_info) entry;
00498 };
00499
00500
00501
00502
00503 AST_MUTEX_DEFINE_STATIC(lock_infos_lock);
00504
00505
00506
00507 static AST_LIST_HEAD_NOLOCK_STATIC(lock_infos, thr_lock_info);
00508
00509
00510
00511
00512
00513
00514 static void lock_info_destroy(void *data)
00515 {
00516 struct thr_lock_info *lock_info = data;
00517 int i;
00518
00519 pthread_mutex_lock(&lock_infos_lock.mutex);
00520 AST_LIST_REMOVE(&lock_infos, lock_info, entry);
00521 pthread_mutex_unlock(&lock_infos_lock.mutex);
00522
00523
00524 for (i = 0; i < lock_info->num_locks; i++) {
00525 if (lock_info->locks[i].pending == -1) {
00526
00527
00528 break;
00529 }
00530
00531 ast_log(LOG_ERROR,
00532 "Thread '%s' still has a lock! - '%s' (%p) from '%s' in %s:%d!\n",
00533 lock_info->thread_name,
00534 lock_info->locks[i].lock_name,
00535 lock_info->locks[i].lock_addr,
00536 lock_info->locks[i].func,
00537 lock_info->locks[i].file,
00538 lock_info->locks[i].line_num
00539 );
00540 }
00541
00542 pthread_mutex_destroy(&lock_info->lock);
00543 if (lock_info->thread_name)
00544 free((void *) lock_info->thread_name);
00545 free(lock_info);
00546 }
00547
00548
00549
00550
00551 AST_THREADSTORAGE_CUSTOM(thread_lock_info, NULL, lock_info_destroy);
00552 #ifdef HAVE_BKTR
00553 void ast_store_lock_info(enum ast_lock_type type, const char *filename,
00554 int line_num, const char *func, const char *lock_name, void *lock_addr, struct ast_bt *bt)
00555 #else
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)
00558 #endif
00559 {
00560 struct thr_lock_info *lock_info;
00561 int i;
00562
00563 if (!(lock_info = ast_threadstorage_get(&thread_lock_info, sizeof(*lock_info))))
00564 return;
00565
00566 pthread_mutex_lock(&lock_info->lock);
00567
00568 for (i = 0; i < lock_info->num_locks; i++) {
00569 if (lock_info->locks[i].lock_addr == lock_addr) {
00570 lock_info->locks[i].times_locked++;
00571 #ifdef HAVE_BKTR
00572 lock_info->locks[i].backtrace = bt;
00573 #endif
00574 pthread_mutex_unlock(&lock_info->lock);
00575 return;
00576 }
00577 }
00578
00579 if (lock_info->num_locks == AST_MAX_LOCKS) {
00580
00581 fprintf(stderr, "XXX ERROR XXX A thread holds more locks than '%d'."
00582 " Increase AST_MAX_LOCKS!\n", AST_MAX_LOCKS);
00583 pthread_mutex_unlock(&lock_info->lock);
00584 return;
00585 }
00586
00587 if (i && lock_info->locks[i - 1].pending == -1) {
00588
00589
00590
00591 i--;
00592 lock_info->num_locks--;
00593 memset(&lock_info->locks[i], 0, sizeof(lock_info->locks[0]));
00594 }
00595
00596 lock_info->locks[i].file = filename;
00597 lock_info->locks[i].line_num = line_num;
00598 lock_info->locks[i].func = func;
00599 lock_info->locks[i].lock_name = lock_name;
00600 lock_info->locks[i].lock_addr = lock_addr;
00601 lock_info->locks[i].times_locked = 1;
00602 lock_info->locks[i].type = type;
00603 lock_info->locks[i].pending = 1;
00604 #ifdef HAVE_BKTR
00605 lock_info->locks[i].backtrace = bt;
00606 #endif
00607 lock_info->num_locks++;
00608
00609 pthread_mutex_unlock(&lock_info->lock);
00610 }
00611
00612 void ast_mark_lock_acquired(void *lock_addr)
00613 {
00614 struct thr_lock_info *lock_info;
00615
00616 if (!(lock_info = ast_threadstorage_get(&thread_lock_info, sizeof(*lock_info))))
00617 return;
00618
00619 pthread_mutex_lock(&lock_info->lock);
00620 if (lock_info->locks[lock_info->num_locks - 1].lock_addr == lock_addr) {
00621 lock_info->locks[lock_info->num_locks - 1].pending = 0;
00622 }
00623 pthread_mutex_unlock(&lock_info->lock);
00624 }
00625
00626 void ast_mark_lock_failed(void *lock_addr)
00627 {
00628 struct thr_lock_info *lock_info;
00629
00630 if (!(lock_info = ast_threadstorage_get(&thread_lock_info, sizeof(*lock_info))))
00631 return;
00632
00633 pthread_mutex_lock(&lock_info->lock);
00634 if (lock_info->locks[lock_info->num_locks - 1].lock_addr == lock_addr) {
00635 lock_info->locks[lock_info->num_locks - 1].pending = -1;
00636 lock_info->locks[lock_info->num_locks - 1].times_locked--;
00637 }
00638 pthread_mutex_unlock(&lock_info->lock);
00639 }
00640
00641 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)
00642 {
00643 struct thr_lock_info *lock_info;
00644 int i = 0;
00645
00646 if (!(lock_info = ast_threadstorage_get(&thread_lock_info, sizeof(*lock_info))))
00647 return -1;
00648
00649 pthread_mutex_lock(&lock_info->lock);
00650
00651 for (i = lock_info->num_locks - 1; i >= 0; i--) {
00652 if (lock_info->locks[i].lock_addr == lock_addr)
00653 break;
00654 }
00655
00656 if (i == -1) {
00657
00658 pthread_mutex_unlock(&lock_info->lock);
00659 return -1;
00660 }
00661
00662 ast_copy_string(filename, lock_info->locks[i].file, filename_size);
00663 *lineno = lock_info->locks[i].line_num;
00664 ast_copy_string(func, lock_info->locks[i].func, func_size);
00665 ast_copy_string(mutex_name, lock_info->locks[i].lock_name, mutex_name_size);
00666
00667 pthread_mutex_unlock(&lock_info->lock);
00668
00669 return 0;
00670 }
00671
00672 #ifdef HAVE_BKTR
00673 void ast_remove_lock_info(void *lock_addr, struct ast_bt *bt)
00674 #else
00675 void ast_remove_lock_info(void *lock_addr)
00676 #endif
00677 {
00678 struct thr_lock_info *lock_info;
00679 int i = 0;
00680
00681 if (!(lock_info = ast_threadstorage_get(&thread_lock_info, sizeof(*lock_info))))
00682 return;
00683
00684 pthread_mutex_lock(&lock_info->lock);
00685
00686 for (i = lock_info->num_locks - 1; i >= 0; i--) {
00687 if (lock_info->locks[i].lock_addr == lock_addr)
00688 break;
00689 }
00690
00691 if (i == -1) {
00692
00693 pthread_mutex_unlock(&lock_info->lock);
00694 return;
00695 }
00696
00697 if (lock_info->locks[i].times_locked > 1) {
00698 lock_info->locks[i].times_locked--;
00699 #ifdef HAVE_BKTR
00700 lock_info->locks[i].backtrace = bt;
00701 #endif
00702 pthread_mutex_unlock(&lock_info->lock);
00703 return;
00704 }
00705
00706 if (i < lock_info->num_locks - 1) {
00707
00708 memmove(&lock_info->locks[i], &lock_info->locks[i + 1],
00709 (lock_info->num_locks - (i + 1)) * sizeof(lock_info->locks[0]));
00710 }
00711
00712 lock_info->num_locks--;
00713
00714 pthread_mutex_unlock(&lock_info->lock);
00715 }
00716
00717 static const char *locktype2str(enum ast_lock_type type)
00718 {
00719 switch (type) {
00720 case AST_MUTEX:
00721 return "MUTEX";
00722 case AST_RDLOCK:
00723 return "RDLOCK";
00724 case AST_WRLOCK:
00725 return "WRLOCK";
00726 }
00727
00728 return "UNKNOWN";
00729 }
00730
00731 #ifdef HAVE_BKTR
00732 static void append_backtrace_information(struct ast_str **str, struct ast_bt *bt)
00733 {
00734 char **symbols;
00735
00736 if (!bt) {
00737 ast_str_append(str, 0, "\tNo backtrace to print\n");
00738 return;
00739 }
00740
00741 if ((symbols = ast_bt_get_symbols(bt->addresses, bt->num_frames))) {
00742 int frame_iterator;
00743
00744 for (frame_iterator = 0; frame_iterator < bt->num_frames; ++frame_iterator) {
00745 ast_str_append(str, 0, "\t%s\n", symbols[frame_iterator]);
00746 }
00747
00748 free(symbols);
00749 } else {
00750 ast_str_append(str, 0, "\tCouldn't retrieve backtrace symbols\n");
00751 }
00752 }
00753 #endif
00754
00755 static void append_lock_information(struct ast_str **str, struct thr_lock_info *lock_info, int i)
00756 {
00757 int j;
00758 ast_mutex_t *lock;
00759 struct ast_lock_track *lt;
00760
00761 ast_str_append(str, 0, "=== ---> %sLock #%d (%s): %s %d %s %s %p (%d)\n",
00762 lock_info->locks[i].pending > 0 ? "Waiting for " :
00763 lock_info->locks[i].pending < 0 ? "Tried and failed to get " : "", i,
00764 lock_info->locks[i].file,
00765 locktype2str(lock_info->locks[i].type),
00766 lock_info->locks[i].line_num,
00767 lock_info->locks[i].func, lock_info->locks[i].lock_name,
00768 lock_info->locks[i].lock_addr,
00769 lock_info->locks[i].times_locked);
00770 #ifdef HAVE_BKTR
00771 append_backtrace_information(str, lock_info->locks[i].backtrace);
00772 #endif
00773
00774 if (!lock_info->locks[i].pending || lock_info->locks[i].pending == -1)
00775 return;
00776
00777
00778 if (lock_info->locks[i].type != AST_MUTEX)
00779 return;
00780
00781 lock = lock_info->locks[i].lock_addr;
00782 lt = &lock->track;
00783 ast_reentrancy_lock(lt);
00784 for (j = 0; *str && j < lt->reentrancy; j++) {
00785 ast_str_append(str, 0, "=== --- ---> Locked Here: %s line %d (%s)\n",
00786 lt->file[j], lt->lineno[j], lt->func[j]);
00787 }
00788 ast_reentrancy_unlock(lt);
00789 }
00790
00791
00792
00793
00794
00795
00796
00797
00798
00799
00800
00801
00802
00803
00804
00805
00806
00807
00808
00809
00810
00811 void log_show_lock(void *this_lock_addr)
00812 {
00813 struct thr_lock_info *lock_info;
00814 struct ast_str *str;
00815
00816 if (!(str = ast_str_create(4096))) {
00817 ast_log(LOG_NOTICE,"Could not create str\n");
00818 return;
00819 }
00820
00821
00822 pthread_mutex_lock(&lock_infos_lock.mutex);
00823 AST_LIST_TRAVERSE(&lock_infos, lock_info, entry) {
00824 int i;
00825 pthread_mutex_lock(&lock_info->lock);
00826 for (i = 0; str && i < lock_info->num_locks; i++) {
00827
00828
00829 if (lock_info->locks[i].lock_addr == this_lock_addr) {
00830 append_lock_information(&str, lock_info, i);
00831 ast_log(LOG_NOTICE, "%s", ast_str_buffer(str));
00832 break;
00833 }
00834 }
00835 pthread_mutex_unlock(&lock_info->lock);
00836 }
00837 pthread_mutex_unlock(&lock_infos_lock.mutex);
00838 ast_free(str);
00839 }
00840
00841
00842 static char *handle_show_locks(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00843 {
00844 struct thr_lock_info *lock_info;
00845 struct ast_str *str;
00846
00847 if (!(str = ast_str_create(4096)))
00848 return CLI_FAILURE;
00849
00850 switch (cmd) {
00851 case CLI_INIT:
00852 e->command = "core show locks";
00853 e->usage =
00854 "Usage: core show locks\n"
00855 " This command is for lock debugging. It prints out which locks\n"
00856 "are owned by each active thread.\n";
00857 return NULL;
00858
00859 case CLI_GENERATE:
00860 return NULL;
00861 }
00862
00863 ast_str_append(&str, 0, "\n"
00864 "=======================================================================\n"
00865 "=== Currently Held Locks ==============================================\n"
00866 "=======================================================================\n"
00867 "===\n"
00868 "=== <pending> <lock#> (<file>): <lock type> <line num> <function> <lock name> <lock addr> (times locked)\n"
00869 "===\n");
00870
00871 if (!str)
00872 return CLI_FAILURE;
00873
00874 pthread_mutex_lock(&lock_infos_lock.mutex);
00875 AST_LIST_TRAVERSE(&lock_infos, lock_info, entry) {
00876 int i;
00877 if (lock_info->num_locks) {
00878 ast_str_append(&str, 0, "=== Thread ID: %ld (%s)\n", (long) lock_info->thread_id,
00879 lock_info->thread_name);
00880 pthread_mutex_lock(&lock_info->lock);
00881 for (i = 0; str && i < lock_info->num_locks; i++) {
00882 append_lock_information(&str, lock_info, i);
00883 }
00884 pthread_mutex_unlock(&lock_info->lock);
00885 if (!str)
00886 break;
00887 ast_str_append(&str, 0, "=== -------------------------------------------------------------------\n"
00888 "===\n");
00889 if (!str)
00890 break;
00891 }
00892 }
00893 pthread_mutex_unlock(&lock_infos_lock.mutex);
00894
00895 if (!str)
00896 return CLI_FAILURE;
00897
00898 ast_str_append(&str, 0, "=======================================================================\n"
00899 "\n");
00900
00901 if (!str)
00902 return CLI_FAILURE;
00903
00904 ast_cli(a->fd, "%s", ast_str_buffer(str));
00905
00906 ast_free(str);
00907
00908 return CLI_SUCCESS;
00909 }
00910
00911 static struct ast_cli_entry utils_cli[] = {
00912 AST_CLI_DEFINE(handle_show_locks, "Show which locks are held by which thread"),
00913 };
00914
00915 #endif
00916
00917
00918
00919
00920
00921
00922 struct thr_arg {
00923 void *(*start_routine)(void *);
00924 void *data;
00925 char *name;
00926 };
00927
00928
00929
00930
00931
00932
00933
00934
00935 static void *dummy_start(void *data)
00936 {
00937 void *ret;
00938 struct thr_arg a = *((struct thr_arg *) data);
00939 #ifdef DEBUG_THREADS
00940 struct thr_lock_info *lock_info;
00941 pthread_mutexattr_t mutex_attr;
00942 #endif
00943
00944
00945
00946
00947
00948
00949 ast_free(data);
00950 ast_register_thread(a.name);
00951 pthread_cleanup_push(ast_unregister_thread, (void *) pthread_self());
00952
00953 #ifdef DEBUG_THREADS
00954 if (!(lock_info = ast_threadstorage_get(&thread_lock_info, sizeof(*lock_info))))
00955 return NULL;
00956
00957 lock_info->thread_id = pthread_self();
00958 lock_info->thread_name = strdup(a.name);
00959
00960 pthread_mutexattr_init(&mutex_attr);
00961 pthread_mutexattr_settype(&mutex_attr, AST_MUTEX_KIND);
00962 pthread_mutex_init(&lock_info->lock, &mutex_attr);
00963 pthread_mutexattr_destroy(&mutex_attr);
00964
00965 pthread_mutex_lock(&lock_infos_lock.mutex);
00966 AST_LIST_INSERT_TAIL(&lock_infos, lock_info, entry);
00967 pthread_mutex_unlock(&lock_infos_lock.mutex);
00968 #endif
00969
00970 ret = a.start_routine(a.data);
00971
00972 pthread_cleanup_pop(1);
00973
00974 return ret;
00975 }
00976
00977 #endif
00978
00979 int ast_pthread_create_stack(pthread_t *thread, pthread_attr_t *attr, void *(*start_routine)(void *),
00980 void *data, size_t stacksize, const char *file, const char *caller,
00981 int line, const char *start_fn)
00982 {
00983 #if !defined(LOW_MEMORY)
00984 struct thr_arg *a;
00985 #endif
00986
00987 if (!attr) {
00988 attr = alloca(sizeof(*attr));
00989 pthread_attr_init(attr);
00990 }
00991
00992 #ifdef __linux__
00993
00994
00995
00996
00997
00998
00999
01000 if ((errno = pthread_attr_setinheritsched(attr, PTHREAD_INHERIT_SCHED)))
01001 ast_log(LOG_WARNING, "pthread_attr_setinheritsched: %s\n", strerror(errno));
01002 #endif
01003
01004 if (!stacksize)
01005 stacksize = AST_STACKSIZE;
01006
01007 if ((errno = pthread_attr_setstacksize(attr, stacksize ? stacksize : AST_STACKSIZE)))
01008 ast_log(LOG_WARNING, "pthread_attr_setstacksize: %s\n", strerror(errno));
01009
01010 #if !defined(LOW_MEMORY)
01011 if ((a = ast_malloc(sizeof(*a)))) {
01012 a->start_routine = start_routine;
01013 a->data = data;
01014 start_routine = dummy_start;
01015 if (asprintf(&a->name, "%-20s started at [%5d] %s %s()",
01016 start_fn, line, file, caller) < 0) {
01017 ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno));
01018 a->name = NULL;
01019 }
01020 data = a;
01021 }
01022 #endif
01023
01024 return pthread_create(thread, attr, start_routine, data);
01025 }
01026
01027
01028 int ast_pthread_create_detached_stack(pthread_t *thread, pthread_attr_t *attr, void *(*start_routine)(void *),
01029 void *data, size_t stacksize, const char *file, const char *caller,
01030 int line, const char *start_fn)
01031 {
01032 unsigned char attr_destroy = 0;
01033 int res;
01034
01035 if (!attr) {
01036 attr = alloca(sizeof(*attr));
01037 pthread_attr_init(attr);
01038 attr_destroy = 1;
01039 }
01040
01041 if ((errno = pthread_attr_setdetachstate(attr, PTHREAD_CREATE_DETACHED)))
01042 ast_log(LOG_WARNING, "pthread_attr_setdetachstate: %s\n", strerror(errno));
01043
01044 res = ast_pthread_create_stack(thread, attr, start_routine, data,
01045 stacksize, file, caller, line, start_fn);
01046
01047 if (attr_destroy)
01048 pthread_attr_destroy(attr);
01049
01050 return res;
01051 }
01052
01053 int ast_wait_for_input(int fd, int ms)
01054 {
01055 struct pollfd pfd[1];
01056 memset(pfd, 0, sizeof(pfd));
01057 pfd[0].fd = fd;
01058 pfd[0].events = POLLIN|POLLPRI;
01059 return ast_poll(pfd, 1, ms);
01060 }
01061
01062 static int ast_wait_for_output(int fd, int timeoutms)
01063 {
01064 struct pollfd pfd = {
01065 .fd = fd,
01066 .events = POLLOUT,
01067 };
01068 int res;
01069 struct timeval start = ast_tvnow();
01070 int elapsed = 0;
01071
01072
01073 while ((res = ast_poll(&pfd, 1, timeoutms - elapsed)) <= 0) {
01074 if (res == 0) {
01075
01076 #ifndef STANDALONE
01077 ast_debug(1, "Timed out trying to write\n");
01078 #endif
01079 return -1;
01080 } else if (res == -1) {
01081
01082
01083 if (errno == EINTR || errno == EAGAIN) {
01084 elapsed = ast_tvdiff_ms(ast_tvnow(), start);
01085 if (elapsed >= timeoutms) {
01086 return -1;
01087 }
01088
01089 continue;
01090 }
01091
01092
01093 ast_log(LOG_ERROR, "poll returned error: %s\n", strerror(errno));
01094
01095 return -1;
01096 }
01097 elapsed = ast_tvdiff_ms(ast_tvnow(), start);
01098 if (elapsed >= timeoutms) {
01099 return -1;
01100 }
01101 }
01102
01103 return 0;
01104 }
01105
01106
01107
01108
01109
01110
01111
01112
01113
01114
01115 int ast_carefulwrite(int fd, char *s, int len, int timeoutms)
01116 {
01117 struct timeval start = ast_tvnow();
01118 int res = 0;
01119 int elapsed = 0;
01120
01121 while (len) {
01122 if (ast_wait_for_output(fd, timeoutms - elapsed)) {
01123 return -1;
01124 }
01125
01126 res = write(fd, s, len);
01127
01128 if (res < 0 && errno != EAGAIN && errno != EINTR) {
01129
01130 ast_log(LOG_ERROR, "write() returned error: %s\n", strerror(errno));
01131 return -1;
01132 }
01133
01134 if (res < 0) {
01135
01136 res = 0;
01137 }
01138
01139
01140 len -= res;
01141 s += res;
01142 res = 0;
01143
01144 elapsed = ast_tvdiff_ms(ast_tvnow(), start);
01145 if (elapsed >= timeoutms) {
01146
01147
01148 res = len ? -1 : 0;
01149 break;
01150 }
01151 }
01152
01153 return res;
01154 }
01155
01156 int ast_careful_fwrite(FILE *f, int fd, const char *src, size_t len, int timeoutms)
01157 {
01158 struct timeval start = ast_tvnow();
01159 int n = 0;
01160 int elapsed = 0;
01161
01162 while (len) {
01163 if (ast_wait_for_output(fd, timeoutms - elapsed)) {
01164
01165 return -1;
01166 }
01167
01168
01169 clearerr(f);
01170
01171 n = fwrite(src, 1, len, f);
01172
01173 if (ferror(f) && errno != EINTR && errno != EAGAIN) {
01174
01175 if (!feof(f)) {
01176
01177 ast_log(LOG_ERROR, "fwrite() returned error: %s\n", strerror(errno));
01178 }
01179 n = -1;
01180 break;
01181 }
01182
01183
01184 len -= n;
01185 src += n;
01186
01187 elapsed = ast_tvdiff_ms(ast_tvnow(), start);
01188 if (elapsed >= timeoutms) {
01189
01190
01191 n = len ? -1 : 0;
01192 break;
01193 }
01194 }
01195
01196 while (fflush(f)) {
01197 if (errno == EAGAIN || errno == EINTR) {
01198 continue;
01199 }
01200 if (!feof(f)) {
01201
01202 ast_log(LOG_ERROR, "fflush() returned error: %s\n", strerror(errno));
01203 }
01204 n = -1;
01205 break;
01206 }
01207
01208 return n < 0 ? -1 : 0;
01209 }
01210
01211 char *ast_strip_quoted(char *s, const char *beg_quotes, const char *end_quotes)
01212 {
01213 char *e;
01214 char *q;
01215
01216 s = ast_strip(s);
01217 if ((q = strchr(beg_quotes, *s)) && *q != '\0') {
01218 e = s + strlen(s) - 1;
01219 if (*e == *(end_quotes + (q - beg_quotes))) {
01220 s++;
01221 *e = '\0';
01222 }
01223 }
01224
01225 return s;
01226 }
01227
01228 char *ast_unescape_semicolon(char *s)
01229 {
01230 char *e;
01231 char *work = s;
01232
01233 while ((e = strchr(work, ';'))) {
01234 if ((e > work) && (*(e-1) == '\\')) {
01235 memmove(e - 1, e, strlen(e) + 1);
01236 work = e;
01237 } else {
01238 work = e + 1;
01239 }
01240 }
01241
01242 return s;
01243 }
01244
01245
01246
01247 char *ast_unescape_c(char *src)
01248 {
01249 char c, *ret, *dst;
01250
01251 if (src == NULL)
01252 return NULL;
01253 for (ret = dst = src; (c = *src++); *dst++ = c ) {
01254 if (c != '\\')
01255 continue;
01256 switch ((c = *src++)) {
01257 case '\0':
01258 c = '\\';
01259 break;
01260 case 'b':
01261 c = '\b';
01262 break;
01263 case 'f':
01264 c = '\f';
01265 break;
01266 case 'n':
01267 c = '\n';
01268 break;
01269 case 'r':
01270 c = '\r';
01271 break;
01272 case 't':
01273 c = '\t';
01274 break;
01275 }
01276
01277 }
01278 *dst = '\0';
01279 return ret;
01280 }
01281
01282 int ast_build_string_va(char **buffer, size_t *space, const char *fmt, va_list ap)
01283 {
01284 int result;
01285
01286 if (!buffer || !*buffer || !space || !*space)
01287 return -1;
01288
01289 result = vsnprintf(*buffer, *space, fmt, ap);
01290
01291 if (result < 0)
01292 return -1;
01293 else if (result > *space)
01294 result = *space;
01295
01296 *buffer += result;
01297 *space -= result;
01298 return 0;
01299 }
01300
01301 int ast_build_string(char **buffer, size_t *space, const char *fmt, ...)
01302 {
01303 va_list ap;
01304 int result;
01305
01306 va_start(ap, fmt);
01307 result = ast_build_string_va(buffer, space, fmt, ap);
01308 va_end(ap);
01309
01310 return result;
01311 }
01312
01313 int ast_true(const char *s)
01314 {
01315 if (ast_strlen_zero(s))
01316 return 0;
01317
01318
01319 if (!strcasecmp(s, "yes") ||
01320 !strcasecmp(s, "true") ||
01321 !strcasecmp(s, "y") ||
01322 !strcasecmp(s, "t") ||
01323 !strcasecmp(s, "1") ||
01324 !strcasecmp(s, "on"))
01325 return -1;
01326
01327 return 0;
01328 }
01329
01330 int ast_false(const char *s)
01331 {
01332 if (ast_strlen_zero(s))
01333 return 0;
01334
01335
01336 if (!strcasecmp(s, "no") ||
01337 !strcasecmp(s, "false") ||
01338 !strcasecmp(s, "n") ||
01339 !strcasecmp(s, "f") ||
01340 !strcasecmp(s, "0") ||
01341 !strcasecmp(s, "off"))
01342 return -1;
01343
01344 return 0;
01345 }
01346
01347 #define ONE_MILLION 1000000
01348
01349
01350
01351
01352 static struct timeval tvfix(struct timeval a)
01353 {
01354 if (a.tv_usec >= ONE_MILLION) {
01355 ast_log(LOG_WARNING, "warning too large timestamp %ld.%ld\n",
01356 (long)a.tv_sec, (long int) a.tv_usec);
01357 a.tv_sec += a.tv_usec / ONE_MILLION;
01358 a.tv_usec %= ONE_MILLION;
01359 } else if (a.tv_usec < 0) {
01360 ast_log(LOG_WARNING, "warning negative timestamp %ld.%ld\n",
01361 (long)a.tv_sec, (long int) a.tv_usec);
01362 a.tv_usec = 0;
01363 }
01364 return a;
01365 }
01366
01367 struct timeval ast_tvadd(struct timeval a, struct timeval b)
01368 {
01369
01370 a = tvfix(a);
01371 b = tvfix(b);
01372 a.tv_sec += b.tv_sec;
01373 a.tv_usec += b.tv_usec;
01374 if (a.tv_usec >= ONE_MILLION) {
01375 a.tv_sec++;
01376 a.tv_usec -= ONE_MILLION;
01377 }
01378 return a;
01379 }
01380
01381 struct timeval ast_tvsub(struct timeval a, struct timeval b)
01382 {
01383
01384 a = tvfix(a);
01385 b = tvfix(b);
01386 a.tv_sec -= b.tv_sec;
01387 a.tv_usec -= b.tv_usec;
01388 if (a.tv_usec < 0) {
01389 a.tv_sec-- ;
01390 a.tv_usec += ONE_MILLION;
01391 }
01392 return a;
01393 }
01394 #undef ONE_MILLION
01395
01396
01397
01398
01399 #ifndef linux
01400 AST_MUTEX_DEFINE_STATIC(randomlock);
01401 #endif
01402
01403 long int ast_random(void)
01404 {
01405 long int res;
01406 #ifdef HAVE_DEV_URANDOM
01407 if (dev_urandom_fd >= 0) {
01408 int read_res = read(dev_urandom_fd, &res, sizeof(res));
01409 if (read_res > 0) {
01410 long int rm = RAND_MAX;
01411 res = res < 0 ? ~res : res;
01412 rm++;
01413 return res % rm;
01414 }
01415 }
01416 #endif
01417 #ifdef linux
01418 res = random();
01419 #else
01420 ast_mutex_lock(&randomlock);
01421 res = random();
01422 ast_mutex_unlock(&randomlock);
01423 #endif
01424 return res;
01425 }
01426
01427 char *ast_process_quotes_and_slashes(char *start, char find, char replace_with)
01428 {
01429 char *dataPut = start;
01430 int inEscape = 0;
01431 int inQuotes = 0;
01432
01433 for (; *start; start++) {
01434 if (inEscape) {
01435 *dataPut++ = *start;
01436 inEscape = 0;
01437 } else {
01438 if (*start == '\\') {
01439 inEscape = 1;
01440 } else if (*start == '\'') {
01441 inQuotes = 1 - inQuotes;
01442 } else {
01443
01444 *dataPut++ = inQuotes ? *start : ((*start == find) ? replace_with : *start);
01445 }
01446 }
01447 }
01448 if (start != dataPut)
01449 *dataPut = 0;
01450 return dataPut;
01451 }
01452
01453 void ast_join(char *s, size_t len, char * const w[])
01454 {
01455 int x, ofs = 0;
01456 const char *src;
01457
01458
01459 if (!s)
01460 return;
01461 for (x = 0; ofs < len && w[x]; x++) {
01462 if (x > 0)
01463 s[ofs++] = ' ';
01464 for (src = w[x]; *src && ofs < len; src++)
01465 s[ofs++] = *src;
01466 }
01467 if (ofs == len)
01468 ofs--;
01469 s[ofs] = '\0';
01470 }
01471
01472
01473
01474
01475
01476 const char __ast_string_field_empty[] = "";
01477
01478
01479
01480
01481
01482 static int add_string_pool(struct ast_string_field_mgr *mgr, struct ast_string_field_pool **pool_head,
01483 size_t size, const char *file, int lineno, const char *func)
01484 {
01485 struct ast_string_field_pool *pool;
01486
01487 #if defined(__AST_DEBUG_MALLOC)
01488 if (!(pool = __ast_calloc(1, sizeof(*pool) + size, file, lineno, func))) {
01489 return -1;
01490 }
01491 #else
01492 if (!(pool = ast_calloc(1, sizeof(*pool) + size))) {
01493 return -1;
01494 }
01495 #endif
01496
01497 pool->prev = *pool_head;
01498 *pool_head = pool;
01499 mgr->size = size;
01500 mgr->used = 0;
01501 mgr->last_alloc = NULL;
01502
01503 return 0;
01504 }
01505
01506
01507
01508
01509
01510
01511
01512
01513
01514
01515
01516 int __ast_string_field_init(struct ast_string_field_mgr *mgr, struct ast_string_field_pool **pool_head,
01517 int needed, const char *file, int lineno, const char *func)
01518 {
01519 const char **p = (const char **) pool_head + 1;
01520 struct ast_string_field_pool *cur = NULL;
01521 struct ast_string_field_pool *preserve = NULL;
01522
01523
01524 while ((struct ast_string_field_mgr *) p != mgr)
01525 *p++ = __ast_string_field_empty;
01526 mgr->last_alloc = NULL;
01527 #if defined(__AST_DEBUG_MALLOC)
01528 mgr->owner_file = file;
01529 mgr->owner_func = func;
01530 mgr->owner_line = lineno;
01531 #endif
01532 if (needed > 0) {
01533 *pool_head = NULL;
01534 return add_string_pool(mgr, pool_head, needed, file, lineno, func);
01535 }
01536 if (needed < 0) {
01537 if (*pool_head == NULL) {
01538 ast_log(LOG_WARNING, "trying to reset empty pool\n");
01539 return -1;
01540 }
01541 cur = *pool_head;
01542 } else {
01543 if (*pool_head == NULL) {
01544 ast_log(LOG_WARNING, "trying to reset empty pool\n");
01545 return -1;
01546 }
01547 mgr->used = 0;
01548 preserve = *pool_head;
01549 cur = preserve->prev;
01550 }
01551
01552 if (preserve) {
01553 preserve->prev = NULL;
01554 }
01555
01556 while (cur) {
01557 struct ast_string_field_pool *prev = cur->prev;
01558
01559 if (cur != preserve) {
01560 ast_free(cur);
01561 }
01562 cur = prev;
01563 }
01564
01565 *pool_head = preserve;
01566
01567 return 0;
01568 }
01569
01570 ast_string_field __ast_string_field_alloc_space(struct ast_string_field_mgr *mgr,
01571 struct ast_string_field_pool **pool_head, size_t needed)
01572 {
01573 char *result = NULL;
01574 size_t space = mgr->size - mgr->used;
01575
01576 if (__builtin_expect(needed > space, 0)) {
01577 size_t new_size = mgr->size * 2;
01578
01579 while (new_size < needed)
01580 new_size *= 2;
01581
01582 #if defined(__AST_DEBUG_MALLOC)
01583 if (add_string_pool(mgr, pool_head, new_size, mgr->owner_file, mgr->owner_line, mgr->owner_func))
01584 return NULL;
01585 #else
01586 if (add_string_pool(mgr, pool_head, new_size, __FILE__, __LINE__, __FUNCTION__))
01587 return NULL;
01588 #endif
01589 }
01590
01591 result = (*pool_head)->base + mgr->used;
01592 mgr->used += needed;
01593 mgr->last_alloc = result;
01594 return result;
01595 }
01596
01597 int __ast_string_field_ptr_grow(struct ast_string_field_mgr *mgr, size_t needed,
01598 const ast_string_field *ptr)
01599 {
01600 int grow = needed - (strlen(*ptr) + 1);
01601 size_t space = mgr->size - mgr->used;
01602
01603 if (grow <= 0) {
01604 return 0;
01605 }
01606
01607 if (*ptr != mgr->last_alloc) {
01608 return 1;
01609 }
01610
01611 if (space < grow) {
01612 return 1;
01613 }
01614
01615 mgr->used += grow;
01616
01617 return 0;
01618 }
01619
01620 void __ast_string_field_ptr_build_va(struct ast_string_field_mgr *mgr,
01621 struct ast_string_field_pool **pool_head,
01622 ast_string_field *ptr, const char *format, va_list ap1, va_list ap2)
01623 {
01624 size_t needed;
01625 size_t available;
01626 size_t space = mgr->size - mgr->used;
01627 char *target;
01628
01629
01630
01631
01632
01633 if ((*ptr)[0] != '\0') {
01634 target = (char *) *ptr;
01635 available = strlen(target) + 1;
01636 } else {
01637 target = (*pool_head)->base + mgr->used;
01638 available = space;
01639 }
01640
01641 needed = vsnprintf(target, available, format, ap1) + 1;
01642
01643 va_end(ap1);
01644
01645 if (needed > available) {
01646
01647
01648
01649
01650
01651 if (needed > space) {
01652 size_t new_size = mgr->size * 2;
01653
01654 while (new_size < needed)
01655 new_size *= 2;
01656
01657 #if defined(__AST_DEBUG_MALLOC)
01658 if (add_string_pool(mgr, pool_head, new_size, mgr->owner_file, mgr->owner_line, mgr->owner_func))
01659 return;
01660 #else
01661 if (add_string_pool(mgr, pool_head, new_size, NULL, 0, NULL))
01662 return;
01663 #endif
01664 }
01665
01666 target = (*pool_head)->base + mgr->used;
01667 vsprintf(target, format, ap2);
01668 }
01669
01670 if (*ptr != target) {
01671 mgr->last_alloc = *ptr = target;
01672 mgr->used += needed;
01673 }
01674 }
01675
01676 void __ast_string_field_ptr_build(struct ast_string_field_mgr *mgr,
01677 struct ast_string_field_pool **pool_head,
01678 ast_string_field *ptr, const char *format, ...)
01679 {
01680 va_list ap1, ap2;
01681
01682 va_start(ap1, format);
01683 va_start(ap2, format);
01684
01685 __ast_string_field_ptr_build_va(mgr, pool_head, ptr, format, ap1, ap2);
01686
01687 va_end(ap1);
01688 va_end(ap2);
01689 }
01690
01691
01692 AST_MUTEX_DEFINE_STATIC(fetchadd_m);
01693
01694 int ast_atomic_fetchadd_int_slow(volatile int *p, int v)
01695 {
01696 int ret;
01697 ast_mutex_lock(&fetchadd_m);
01698 ret = *p;
01699 *p += v;
01700 ast_mutex_unlock(&fetchadd_m);
01701 return ret;
01702 }
01703
01704
01705
01706
01707 int ast_get_timeval(const char *src, struct timeval *dst, struct timeval _default, int *consumed)
01708 {
01709 long double dtv = 0.0;
01710 int scanned;
01711
01712 if (dst == NULL)
01713 return -1;
01714
01715 *dst = _default;
01716
01717 if (ast_strlen_zero(src))
01718 return -1;
01719
01720
01721 if (sscanf(src, "%30Lf%n", &dtv, &scanned) > 0) {
01722 dst->tv_sec = dtv;
01723 dst->tv_usec = (dtv - dst->tv_sec) * 1000000.0;
01724 if (consumed)
01725 *consumed = scanned;
01726 return 0;
01727 } else
01728 return -1;
01729 }
01730
01731
01732
01733
01734 int ast_get_time_t(const char *src, time_t *dst, time_t _default, int *consumed)
01735 {
01736 long t;
01737 int scanned;
01738
01739 if (dst == NULL)
01740 return -1;
01741
01742 *dst = _default;
01743
01744 if (ast_strlen_zero(src))
01745 return -1;
01746
01747
01748 if (sscanf(src, "%30ld%n", &t, &scanned) == 1) {
01749 *dst = t;
01750 if (consumed)
01751 *consumed = scanned;
01752 return 0;
01753 } else
01754 return -1;
01755 }
01756
01757 void ast_enable_packet_fragmentation(int sock)
01758 {
01759 #if defined(HAVE_IP_MTU_DISCOVER)
01760 int val = IP_PMTUDISC_DONT;
01761
01762 if (setsockopt(sock, IPPROTO_IP, IP_MTU_DISCOVER, &val, sizeof(val)))
01763 ast_log(LOG_WARNING, "Unable to disable PMTU discovery. Large UDP packets may fail to be delivered when sent from this socket.\n");
01764 #endif
01765 }
01766
01767 int ast_mkdir(const char *path, int mode)
01768 {
01769 char *ptr;
01770 int len = strlen(path), count = 0, x, piececount = 0;
01771 char *tmp = ast_strdupa(path);
01772 char **pieces;
01773 char *fullpath = alloca(len + 1);
01774 int res = 0;
01775
01776 for (ptr = tmp; *ptr; ptr++) {
01777 if (*ptr == '/')
01778 count++;
01779 }
01780
01781
01782 pieces = alloca(count * sizeof(*pieces));
01783 for (ptr = tmp; *ptr; ptr++) {
01784 if (*ptr == '/') {
01785 *ptr = '\0';
01786 pieces[piececount++] = ptr + 1;
01787 }
01788 }
01789
01790 *fullpath = '\0';
01791 for (x = 0; x < piececount; x++) {
01792
01793 strcat(fullpath, "/");
01794 strcat(fullpath, pieces[x]);
01795 res = mkdir(fullpath, mode);
01796 if (res && errno != EEXIST)
01797 return errno;
01798 }
01799 return 0;
01800 }
01801
01802 int ast_utils_init(void)
01803 {
01804 #ifdef HAVE_DEV_URANDOM
01805 dev_urandom_fd = open("/dev/urandom", O_RDONLY);
01806 #endif
01807 base64_init();
01808 #ifdef DEBUG_THREADS
01809 #if !defined(LOW_MEMORY)
01810 ast_cli_register_multiple(utils_cli, ARRAY_LEN(utils_cli));
01811 #endif
01812 #endif
01813 return 0;
01814 }
01815
01816 #ifndef __AST_DEBUG_MALLOC
01817 int _ast_asprintf(char **ret, const char *file, int lineno, const char *func, const char *fmt, ...)
01818 {
01819 int res;
01820 va_list ap;
01821
01822 va_start(ap, fmt);
01823 if ((res = vasprintf(ret, fmt, ap)) == -1) {
01824 MALLOC_FAILURE_MSG;
01825 }
01826 va_end(ap);
01827
01828 return res;
01829 }
01830 #endif
01831
01832 char *ast_utils_which(const char *binary, char *fullpath, size_t fullpath_size)
01833 {
01834 const char *envPATH = getenv("PATH");
01835 char *tpath, *path;
01836 struct stat unused;
01837 if (!envPATH) {
01838 return NULL;
01839 }
01840 tpath = ast_strdupa(envPATH);
01841 while ((path = strsep(&tpath, ":"))) {
01842 snprintf(fullpath, fullpath_size, "%s/%s", path, binary);
01843 if (!stat(fullpath, &unused)) {
01844 return fullpath;
01845 }
01846 }
01847 return NULL;
01848 }
01849