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