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