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