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