Sat Aug 6 00:39:32 2011

Asterisk developer's documentation


utils.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 1999 - 2006, Digium, Inc.
00005  *
00006  * See http://www.asterisk.org for more information about
00007  * the Asterisk project. Please do not directly contact
00008  * any of the maintainers of this project for assistance;
00009  * the project provides a web site, mailing lists and IRC
00010  * channels for your use.
00011  *
00012  * This program is free software, distributed under the terms of
00013  * the GNU General Public License Version 2. See the LICENSE file
00014  * at the top of the source tree.
00015  */
00016 
00017 /*! \file
00018  *
00019  * \brief Utility functions
00020  *
00021  * \note These are important for portability and security,
00022  * so please use them in favour of other routines.
00023  * Please consult the CODING GUIDELINES for more information.
00024  */
00025 
00026 #include "asterisk.h"
00027 
00028 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 310779 $")
00029 
00030 #include <ctype.h>
00031 #include <string.h>
00032 #include <unistd.h>
00033 #include <stdlib.h>
00034 #include <errno.h>
00035 #include <stdarg.h>
00036 #include <stdio.h>
00037 #include <sys/types.h>
00038 #include <sys/socket.h>
00039 #include <netinet/in.h>
00040 #include <arpa/inet.h>
00041 #include <sys/stat.h>
00042 
00043 #define AST_API_MODULE     /* ensure that inlinable API functions will be built in lock.h if required */
00044 #include "asterisk/lock.h"
00045 #include "asterisk/io.h"
00046 #include "asterisk/logger.h"
00047 #include "asterisk/md5.h"
00048 #include "asterisk/sha1.h"
00049 #include "asterisk/options.h"
00050 #include "asterisk/cli.h"
00051 #include "asterisk/linkedlists.h"
00052 
00053 #define AST_API_MODULE     /* ensure that inlinable API functions will be built in this module if required */
00054 #include "asterisk/strings.h"
00055 
00056 #define AST_API_MODULE     /* ensure that inlinable API functions will be built in this module if required */
00057 #include "asterisk/time.h"
00058 
00059 #define AST_API_MODULE     /* ensure that inlinable API functions will be built in this module if required */
00060 #include "asterisk/stringfields.h"
00061 
00062 #define AST_API_MODULE     /* ensure that inlinable API functions will be built in this module if required */
00063 #include "asterisk/utils.h"
00064 
00065 #define AST_API_MODULE
00066 #include "asterisk/threadstorage.h"
00067 
00068 static char base64[64];
00069 static char b2a[256];
00070 
00071 AST_THREADSTORAGE(inet_ntoa_buf, inet_ntoa_buf_init);
00072 
00073 #if !defined(HAVE_GETHOSTBYNAME_R_5) && !defined(HAVE_GETHOSTBYNAME_R_6)
00074 
00075 #define ERANGE 34 /*!< duh? ERANGE value copied from web... */
00076 #undef gethostbyname
00077 
00078 AST_MUTEX_DEFINE_STATIC(__mutex);
00079 
00080 /*! \brief Reentrant replacement for gethostbyname for BSD-based systems.
00081 \note This
00082 routine is derived from code originally written and placed in the public 
00083 domain by Enzo Michelangeli <em@em.no-ip.com> */
00084 
00085 static int gethostbyname_r (const char *name, struct hostent *ret, char *buf,
00086             size_t buflen, struct hostent **result, 
00087             int *h_errnop) 
00088 {
00089    int hsave;
00090    struct hostent *ph;
00091    ast_mutex_lock(&__mutex); /* begin critical area */
00092    hsave = h_errno;
00093 
00094    ph = gethostbyname(name);
00095    *h_errnop = h_errno; /* copy h_errno to *h_herrnop */
00096    if (ph == NULL) {
00097       *result = NULL;
00098    } else {
00099       char **p, **q;
00100       char *pbuf;
00101       int nbytes=0;
00102       int naddr=0, naliases=0;
00103       /* determine if we have enough space in buf */
00104 
00105       /* count how many addresses */
00106       for (p = ph->h_addr_list; *p != 0; p++) {
00107          nbytes += ph->h_length; /* addresses */
00108          nbytes += sizeof(*p); /* pointers */
00109          naddr++;
00110       }
00111       nbytes += sizeof(*p); /* one more for the terminating NULL */
00112 
00113       /* count how many aliases, and total length of strings */
00114       for (p = ph->h_aliases; *p != 0; p++) {
00115          nbytes += (strlen(*p)+1); /* aliases */
00116          nbytes += sizeof(*p);  /* pointers */
00117          naliases++;
00118       }
00119       nbytes += sizeof(*p); /* one more for the terminating NULL */
00120 
00121       /* here nbytes is the number of bytes required in buffer */
00122       /* as a terminator must be there, the minimum value is ph->h_length */
00123       if (nbytes > buflen) {
00124          *result = NULL;
00125          ast_mutex_unlock(&__mutex); /* end critical area */
00126          return ERANGE; /* not enough space in buf!! */
00127       }
00128 
00129       /* There is enough space. Now we need to do a deep copy! */
00130       /* Allocation in buffer:
00131          from [0] to [(naddr-1) * sizeof(*p)]:
00132          pointers to addresses
00133          at [naddr * sizeof(*p)]:
00134          NULL
00135          from [(naddr+1) * sizeof(*p)] to [(naddr+naliases) * sizeof(*p)] :
00136          pointers to aliases
00137          at [(naddr+naliases+1) * sizeof(*p)]:
00138          NULL
00139          then naddr addresses (fixed length), and naliases aliases (asciiz).
00140       */
00141 
00142       *ret = *ph;   /* copy whole structure (not its address!) */
00143 
00144       /* copy addresses */
00145       q = (char **)buf; /* pointer to pointers area (type: char **) */
00146       ret->h_addr_list = q; /* update pointer to address list */
00147       pbuf = buf + ((naddr + naliases + 2) * sizeof(*p)); /* skip that area */
00148       for (p = ph->h_addr_list; *p != 0; p++) {
00149          memcpy(pbuf, *p, ph->h_length); /* copy address bytes */
00150          *q++ = pbuf; /* the pointer is the one inside buf... */
00151          pbuf += ph->h_length; /* advance pbuf */
00152       }
00153       *q++ = NULL; /* address list terminator */
00154 
00155       /* copy aliases */
00156       ret->h_aliases = q; /* update pointer to aliases list */
00157       for (p = ph->h_aliases; *p != 0; p++) {
00158          strcpy(pbuf, *p); /* copy alias strings */
00159          *q++ = pbuf; /* the pointer is the one inside buf... */
00160          pbuf += strlen(*p); /* advance pbuf */
00161          *pbuf++ = 0; /* string terminator */
00162       }
00163       *q++ = NULL; /* terminator */
00164 
00165       strcpy(pbuf, ph->h_name); /* copy alias strings */
00166       ret->h_name = pbuf;
00167       pbuf += strlen(ph->h_name); /* advance pbuf */
00168       *pbuf++ = 0; /* string terminator */
00169 
00170       *result = ret;  /* and let *result point to structure */
00171 
00172    }
00173    h_errno = hsave;  /* restore h_errno */
00174    ast_mutex_unlock(&__mutex); /* end critical area */
00175 
00176    return (*result == NULL); /* return 0 on success, non-zero on error */
00177 }
00178 
00179 
00180 #endif
00181 
00182 /*! \brief Re-entrant (thread safe) version of gethostbyname that replaces the 
00183    standard gethostbyname (which is not thread safe)
00184 */
00185 struct hostent *ast_gethostbyname(const char *host, struct ast_hostent *hp)
00186 {
00187    int res;
00188    int herrno;
00189    int dots=0;
00190    const char *s;
00191    struct hostent *result = NULL;
00192    /* Although it is perfectly legitimate to lookup a pure integer, for
00193       the sake of the sanity of people who like to name their peers as
00194       integers, we break with tradition and refuse to look up a
00195       pure integer */
00196    s = host;
00197    res = 0;
00198    while(s && *s) {
00199       if (*s == '.')
00200          dots++;
00201       else if (!isdigit(*s))
00202          break;
00203       s++;
00204    }
00205    if (!s || !*s) {
00206       /* Forge a reply for IP's to avoid octal IP's being interpreted as octal */
00207       if (dots != 3)
00208          return NULL;
00209       memset(hp, 0, sizeof(struct ast_hostent));
00210       hp->hp.h_addrtype = AF_INET;
00211       hp->hp.h_addr_list = (void *) hp->buf;
00212       hp->hp.h_addr = hp->buf + sizeof(void *);
00213       if (inet_pton(AF_INET, host, hp->hp.h_addr) > 0)
00214          return &hp->hp;
00215       return NULL;
00216       
00217    }
00218 #ifdef HAVE_GETHOSTBYNAME_R_5
00219    result = gethostbyname_r(host, &hp->hp, hp->buf, sizeof(hp->buf), &herrno);
00220 
00221    if (!result || !hp->hp.h_addr_list || !hp->hp.h_addr_list[0])
00222       return NULL;
00223 #else
00224    res = gethostbyname_r(host, &hp->hp, hp->buf, sizeof(hp->buf), &result, &herrno);
00225 
00226    if (res || !result || !hp->hp.h_addr_list || !hp->hp.h_addr_list[0])
00227       return NULL;
00228 #endif
00229    return &hp->hp;
00230 }
00231 
00232 /*! \brief Produce 32 char MD5 hash of value. */
00233 void ast_md5_hash(char *output, char *input)
00234 {
00235    struct MD5Context md5;
00236    unsigned char digest[16];
00237    char *ptr;
00238    int x;
00239 
00240    MD5Init(&md5);
00241    MD5Update(&md5, (unsigned char *)input, strlen(input));
00242    MD5Final(digest, &md5);
00243    ptr = output;
00244    for (x = 0; x < 16; x++)
00245       ptr += sprintf(ptr, "%2.2x", digest[x]);
00246 }
00247 
00248 /*! \brief Produce 40 char SHA1 hash of value. */
00249 void ast_sha1_hash(char *output, char *input)
00250 {
00251    struct SHA1Context sha;
00252    char *ptr;
00253    int x;
00254    uint8_t Message_Digest[20];
00255 
00256    SHA1Reset(&sha);
00257    
00258    SHA1Input(&sha, (const unsigned char *) input, strlen(input));
00259 
00260    SHA1Result(&sha, Message_Digest);
00261    ptr = output;
00262    for (x = 0; x < 20; x++)
00263       ptr += sprintf(ptr, "%2.2x", Message_Digest[x]);
00264 }
00265 
00266 /*! \brief decode BASE64 encoded text */
00267 int ast_base64decode(unsigned char *dst, const char *src, int max)
00268 {
00269    int cnt = 0;
00270    unsigned int byte = 0;
00271    unsigned int bits = 0;
00272    int incnt = 0;
00273    while(*src && *src != '=' && (cnt < max)) {
00274       /* Shift in 6 bits of input */
00275       byte <<= 6;
00276       byte |= (b2a[(int)(*src)]) & 0x3f;
00277       bits += 6;
00278       src++;
00279       incnt++;
00280       /* If we have at least 8 bits left over, take that character 
00281          off the top */
00282       if (bits >= 8)  {
00283          bits -= 8;
00284          *dst = (byte >> bits) & 0xff;
00285          dst++;
00286          cnt++;
00287       }
00288    }
00289    /* Dont worry about left over bits, they're extra anyway */
00290    return cnt;
00291 }
00292 
00293 /*! \brief encode text to BASE64 coding */
00294 int ast_base64encode_full(char *dst, const unsigned char *src, int srclen, int max, int linebreaks)
00295 {
00296    int cnt = 0;
00297    int col = 0;
00298    unsigned int byte = 0;
00299    int bits = 0;
00300    int cntin = 0;
00301    /* Reserve space for null byte at end of string */
00302    max--;
00303    while ((cntin < srclen) && (cnt < max)) {
00304       byte <<= 8;
00305       byte |= *(src++);
00306       bits += 8;
00307       cntin++;
00308       if ((bits == 24) && (cnt + 4 <= max)) {
00309          *dst++ = base64[(byte >> 18) & 0x3f];
00310          *dst++ = base64[(byte >> 12) & 0x3f];
00311          *dst++ = base64[(byte >> 6) & 0x3f];
00312          *dst++ = base64[byte & 0x3f];
00313          cnt += 4;
00314          col += 4;
00315          bits = 0;
00316          byte = 0;
00317       }
00318       if (linebreaks && (cnt < max) && (col == 64)) {
00319          *dst++ = '\n';
00320          cnt++;
00321          col = 0;
00322       }
00323    }
00324    if (bits && (cnt + 4 <= max)) {
00325       /* Add one last character for the remaining bits, 
00326          padding the rest with 0 */
00327       byte <<= 24 - bits;
00328       *dst++ = base64[(byte >> 18) & 0x3f];
00329       *dst++ = base64[(byte >> 12) & 0x3f];
00330       if (bits == 16)
00331          *dst++ = base64[(byte >> 6) & 0x3f];
00332       else
00333          *dst++ = '=';
00334       *dst++ = '=';
00335       cnt += 4;
00336    }
00337    if (linebreaks && (cnt < max)) {
00338       *dst++ = '\n';
00339       cnt++;
00340    }
00341    *dst = '\0';
00342    return cnt;
00343 }
00344 
00345 int ast_base64encode(char *dst, const unsigned char *src, int srclen, int max)
00346 {
00347    return ast_base64encode_full(dst, src, srclen, max, 0);
00348 }
00349 
00350 static void base64_init(void)
00351 {
00352    int x;
00353    memset(b2a, -1, sizeof(b2a));
00354    /* Initialize base-64 Conversion table */
00355    for (x = 0; x < 26; x++) {
00356       /* A-Z */
00357       base64[x] = 'A' + x;
00358       b2a['A' + x] = x;
00359       /* a-z */
00360       base64[x + 26] = 'a' + x;
00361       b2a['a' + x] = x + 26;
00362       /* 0-9 */
00363       if (x < 10) {
00364          base64[x + 52] = '0' + x;
00365          b2a['0' + x] = x + 52;
00366       }
00367    }
00368    base64[62] = '+';
00369    base64[63] = '/';
00370    b2a[(int)'+'] = 62;
00371    b2a[(int)'/'] = 63;
00372 }
00373 
00374 /*! \brief  ast_uri_encode: Turn text string to URI-encoded %XX version
00375 \note    At this point, we're converting from ISO-8859-x (8-bit), not UTF8
00376    as in the SIP protocol spec 
00377    If doreserved == 1 we will convert reserved characters also.
00378    RFC 2396, section 2.4
00379    outbuf needs to have more memory allocated than the instring
00380    to have room for the expansion. Every char that is converted
00381    is replaced by three ASCII characters.
00382 
00383    Note: The doreserved option is needed for replaces header in
00384    SIP transfers.
00385 */
00386 char *ast_uri_encode(const char *string, char *outbuf, int buflen, int doreserved) 
00387 {
00388    char *reserved = ";/?:@&=+$,# "; /* Reserved chars */
00389 
00390    const char *ptr  = string; /* Start with the string */
00391    char *out = outbuf;
00392 
00393    /* If there's no characters to convert, just go through and copy the string */
00394    while (*ptr && out - outbuf < buflen - 1) {
00395       if ((*ptr < 32) || (doreserved && strchr(reserved, *ptr))) {
00396          if (out - outbuf >= buflen - 3) {
00397             break;
00398          }
00399 
00400          out += sprintf(out, "%%%02x", (unsigned char) *ptr);
00401       } else {
00402          *out = *ptr;   /* copy the character */
00403          out++;
00404       }
00405       ptr++;
00406    }
00407 
00408    if (buflen) {
00409       *out = '\0';
00410    }
00411 
00412    return outbuf;
00413 }
00414 
00415 /*! \brief  ast_uri_decode: Decode SIP URI, URN, URL (overwrite the string)  */
00416 void ast_uri_decode(char *s) 
00417 {
00418    char *o;
00419    unsigned int tmp;
00420 
00421    for (o = s; *s; s++, o++) {
00422       if (*s == '%' && strlen(s) > 2 && sscanf(s + 1, "%2x", &tmp) == 1) {
00423          /* have '%', two chars and correct parsing */
00424          *o = tmp;
00425          s += 2;  /* Will be incremented once more when we break out */
00426       } else /* all other cases, just copy */
00427          *o = *s;
00428    }
00429    *o = '\0';
00430 }
00431 
00432 /*! \brief  ast_inet_ntoa: Recursive thread safe replacement of inet_ntoa */
00433 const char *ast_inet_ntoa(struct in_addr ia)
00434 {
00435    char *buf;
00436 
00437    if (!(buf = ast_threadstorage_get(&inet_ntoa_buf, INET_ADDRSTRLEN)))
00438       return "";
00439 
00440    return inet_ntop(AF_INET, &ia, buf, INET_ADDRSTRLEN);
00441 }
00442 
00443 #ifndef __linux__
00444 #undef pthread_create /* For ast_pthread_create function only */
00445 #endif /* !__linux__ */
00446 
00447 #if !defined(LOW_MEMORY)
00448 
00449 #ifdef DEBUG_THREADS
00450 
00451 /*! \brief A reasonable maximum number of locks a thread would be holding ... */
00452 #define AST_MAX_LOCKS 64
00453 
00454 /* Allow direct use of pthread_mutex_t and friends */
00455 #undef pthread_mutex_t
00456 #undef pthread_mutex_lock
00457 #undef pthread_mutex_unlock
00458 #undef pthread_mutex_init
00459 #undef pthread_mutex_destroy
00460 
00461 /*! 
00462  * \brief Keep track of which locks a thread holds 
00463  *
00464  * There is an instance of this struct for every active thread
00465  */
00466 struct thr_lock_info {
00467    /*! The thread's ID */
00468    pthread_t thread_id;
00469    /*! The thread name which includes where the thread was started */
00470    const char *thread_name;
00471    /*! This is the actual container of info for what locks this thread holds */
00472    struct {
00473       const char *file;
00474       int line_num;
00475       const char *func;
00476       const char *lock_name;
00477       void *lock_addr;
00478       int times_locked;
00479       enum ast_lock_type type;
00480       /*! This thread is waiting on this lock */
00481       int pending:2;
00482    } locks[AST_MAX_LOCKS];
00483    /*! This is the number of locks currently held by this thread.
00484     *  The index (num_locks - 1) has the info on the last one in the
00485     *  locks member */
00486    unsigned int num_locks;
00487    /*! Protects the contents of the locks member 
00488     * Intentionally not ast_mutex_t */
00489    pthread_mutex_t lock;
00490    AST_LIST_ENTRY(thr_lock_info) entry;
00491 };
00492 
00493 /*! 
00494  * \brief Locked when accessing the lock_infos list 
00495  */
00496 AST_MUTEX_DEFINE_STATIC(lock_infos_lock);
00497 /*!
00498  * \brief A list of each thread's lock info 
00499  */
00500 static AST_LIST_HEAD_NOLOCK_STATIC(lock_infos, thr_lock_info);
00501 
00502 /*!
00503  * \brief Destroy a thread's lock info
00504  *
00505  * This gets called automatically when the thread stops
00506  */
00507 static void lock_info_destroy(void *data)
00508 {
00509    struct thr_lock_info *lock_info = data;
00510    int i;
00511 
00512    pthread_mutex_lock(&lock_infos_lock.mutex);
00513    AST_LIST_REMOVE(&lock_infos, lock_info, entry);
00514    pthread_mutex_unlock(&lock_infos_lock.mutex);
00515 
00516 
00517    for (i = 0; i < lock_info->num_locks; i++) {
00518       if (lock_info->locks[i].pending == -1) {
00519          /* This just means that the last lock this thread went for was by
00520           * using trylock, and it failed.  This is fine. */
00521          break;
00522       }
00523 
00524       ast_log(LOG_ERROR, 
00525          "Thread '%s' still has a lock! - '%s' (%p) from '%s' in %s:%d!\n", 
00526          lock_info->thread_name,
00527          lock_info->locks[i].lock_name,
00528          lock_info->locks[i].lock_addr,
00529          lock_info->locks[i].func,
00530          lock_info->locks[i].file,
00531          lock_info->locks[i].line_num
00532       );
00533    }
00534 
00535    pthread_mutex_destroy(&lock_info->lock);
00536    free((void *) lock_info->thread_name);
00537    free(lock_info);
00538 }
00539 
00540 /*!
00541  * \brief The thread storage key for per-thread lock info
00542  */
00543 AST_THREADSTORAGE_CUSTOM(thread_lock_info, thread_lock_info_init, lock_info_destroy);
00544 
00545 void ast_store_lock_info(enum ast_lock_type type, const char *filename,
00546    int line_num, const char *func, const char *lock_name, void *lock_addr)
00547 {
00548    struct thr_lock_info *lock_info;
00549    int i;
00550 
00551    if (!(lock_info = ast_threadstorage_get(&thread_lock_info, sizeof(*lock_info))))
00552       return;
00553 
00554    pthread_mutex_lock(&lock_info->lock);
00555 
00556    for (i = 0; i < lock_info->num_locks; i++) {
00557       if (lock_info->locks[i].lock_addr == lock_addr) {
00558          lock_info->locks[i].times_locked++;
00559          pthread_mutex_unlock(&lock_info->lock);
00560          return;
00561       }
00562    }
00563 
00564    if (lock_info->num_locks == AST_MAX_LOCKS) {
00565       /* Can't use ast_log here, because it will cause infinite recursion */
00566       fprintf(stderr, "XXX ERROR XXX A thread holds more locks than '%d'."
00567          "  Increase AST_MAX_LOCKS!\n", AST_MAX_LOCKS);
00568       pthread_mutex_unlock(&lock_info->lock);
00569       return;
00570    }
00571 
00572    if (i && lock_info->locks[i - 1].pending == -1) {
00573       /* The last lock on the list was one that this thread tried to lock but
00574        * failed at doing so.  It has now moved on to something else, so remove
00575        * the old lock from the list. */
00576       i--;
00577       lock_info->num_locks--;
00578       memset(&lock_info->locks[i], 0, sizeof(lock_info->locks[0]));
00579    }
00580 
00581    lock_info->locks[i].file = filename;
00582    lock_info->locks[i].line_num = line_num;
00583    lock_info->locks[i].func = func;
00584    lock_info->locks[i].lock_name = lock_name;
00585    lock_info->locks[i].lock_addr = lock_addr;
00586    lock_info->locks[i].times_locked = 1;
00587    lock_info->locks[i].type = type;
00588    lock_info->locks[i].pending = 1;
00589    lock_info->num_locks++;
00590 
00591    pthread_mutex_unlock(&lock_info->lock);
00592 }
00593 
00594 void ast_mark_lock_acquired(void *lock_addr)
00595 {
00596    struct thr_lock_info *lock_info;
00597 
00598    if (!(lock_info = ast_threadstorage_get(&thread_lock_info, sizeof(*lock_info))))
00599       return;
00600 
00601    pthread_mutex_lock(&lock_info->lock);
00602    if (lock_info->locks[lock_info->num_locks - 1].lock_addr == lock_addr) {
00603       lock_info->locks[lock_info->num_locks - 1].pending = 0;
00604    }
00605    pthread_mutex_unlock(&lock_info->lock);
00606 }
00607 
00608 void ast_mark_lock_failed(void *lock_addr)
00609 {
00610    struct thr_lock_info *lock_info;
00611 
00612    if (!(lock_info = ast_threadstorage_get(&thread_lock_info, sizeof(*lock_info))))
00613       return;
00614 
00615    pthread_mutex_lock(&lock_info->lock);
00616    if (lock_info->locks[lock_info->num_locks - 1].lock_addr == lock_addr) {
00617       lock_info->locks[lock_info->num_locks - 1].pending = -1;
00618       lock_info->locks[lock_info->num_locks - 1].times_locked--;
00619    }
00620    pthread_mutex_unlock(&lock_info->lock);
00621 }
00622 
00623 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)
00624 {
00625    struct thr_lock_info *lock_info;
00626    int i = 0;
00627 
00628    if (!(lock_info = ast_threadstorage_get(&thread_lock_info, sizeof(*lock_info))))
00629       return -1;
00630 
00631    pthread_mutex_lock(&lock_info->lock);
00632 
00633    for (i = lock_info->num_locks - 1; i >= 0; i--) {
00634       if (lock_info->locks[i].lock_addr == lock_addr)
00635          break;
00636    }
00637 
00638    if (i == -1) {
00639       /* Lock not found :( */
00640       pthread_mutex_unlock(&lock_info->lock);
00641       return -1;
00642    }
00643 
00644    ast_copy_string(filename, lock_info->locks[i].file, filename_size);
00645    *lineno = lock_info->locks[i].line_num;
00646    ast_copy_string(func, lock_info->locks[i].func, func_size);
00647    ast_copy_string(mutex_name, lock_info->locks[i].lock_name, mutex_name_size);
00648 
00649    pthread_mutex_unlock(&lock_info->lock);
00650 
00651    return 0;
00652 }
00653 
00654 void ast_remove_lock_info(void *lock_addr)
00655 {
00656    struct thr_lock_info *lock_info;
00657    int i = 0;
00658 
00659    if (!(lock_info = ast_threadstorage_get(&thread_lock_info, sizeof(*lock_info))))
00660       return;
00661 
00662    pthread_mutex_lock(&lock_info->lock);
00663 
00664    for (i = lock_info->num_locks - 1; i >= 0; i--) {
00665       if (lock_info->locks[i].lock_addr == lock_addr)
00666          break;
00667    }
00668 
00669    if (i == -1) {
00670       /* Lock not found :( */
00671       pthread_mutex_unlock(&lock_info->lock);
00672       return;
00673    }
00674 
00675    if (lock_info->locks[i].times_locked > 1) {
00676       lock_info->locks[i].times_locked--;
00677       pthread_mutex_unlock(&lock_info->lock);
00678       return;
00679    }
00680 
00681    if (i < lock_info->num_locks - 1) {
00682       /* Not the last one ... *should* be rare! */
00683       memmove(&lock_info->locks[i], &lock_info->locks[i + 1], 
00684          (lock_info->num_locks - (i + 1)) * sizeof(lock_info->locks[0]));
00685    }
00686 
00687    lock_info->num_locks--;
00688 
00689    pthread_mutex_unlock(&lock_info->lock);
00690 }
00691 
00692 static const char *locktype2str(enum ast_lock_type type)
00693 {
00694    switch (type) {
00695    case AST_MUTEX:
00696       return "MUTEX";
00697    case AST_RDLOCK:
00698       return "RDLOCK";
00699    case AST_WRLOCK:
00700       return "WRLOCK";
00701    }
00702 
00703    return "UNKNOWN";
00704 }
00705 
00706 static int handle_show_locks(int fd, int argc, char *argv[])
00707 {
00708    struct thr_lock_info *lock_info;
00709    struct ast_dynamic_str *str;
00710 
00711    if (!(str = ast_dynamic_str_create(4096)))
00712       return RESULT_FAILURE;
00713 
00714    ast_dynamic_str_append(&str, 0, "\n" 
00715                "=======================================================================\n"
00716                "=== Currently Held Locks ==============================================\n"
00717                "=======================================================================\n"
00718                "===\n"
00719             "=== <file> <line num> <function> <lock name> <lock addr> (times locked)\n"
00720             "===\n");
00721 
00722    if (!str)
00723       return RESULT_FAILURE;
00724 
00725    pthread_mutex_lock(&lock_infos_lock.mutex);
00726    AST_LIST_TRAVERSE(&lock_infos, lock_info, entry) {
00727       int i;
00728       if (lock_info->num_locks) {
00729          ast_dynamic_str_append(&str, 0, "=== Thread ID: 0x%lx (%s)\n", (long) lock_info->thread_id,
00730             lock_info->thread_name);
00731          pthread_mutex_lock(&lock_info->lock);
00732          for (i = 0; str && i < lock_info->num_locks; i++) {
00733             int j;
00734             ast_mutex_t *lock;
00735 
00736             ast_dynamic_str_append(&str, 0, "=== ---> %sLock #%d (%s): %s %d %s %s %p (%d)\n", 
00737                lock_info->locks[i].pending > 0 ? "Waiting for " : 
00738                   lock_info->locks[i].pending < 0 ? "Tried and failed to get " : "", i,
00739                lock_info->locks[i].file, 
00740                locktype2str(lock_info->locks[i].type),
00741                lock_info->locks[i].line_num,
00742                lock_info->locks[i].func, lock_info->locks[i].lock_name,
00743                lock_info->locks[i].lock_addr, 
00744                lock_info->locks[i].times_locked);
00745 
00746             if (!lock_info->locks[i].pending || lock_info->locks[i].pending == -1)
00747                continue;
00748 
00749             /* We only have further details for mutexes right now */
00750             if (lock_info->locks[i].type != AST_MUTEX)
00751                continue;
00752 
00753             lock = lock_info->locks[i].lock_addr;
00754 
00755             ast_reentrancy_lock(lock);
00756             for (j = 0; str && j < lock->reentrancy; j++) {
00757                ast_dynamic_str_append(&str, 0, "=== --- ---> Locked Here: %s line %d (%s)\n",
00758                   lock->file[j], lock->lineno[j], lock->func[j]);
00759             }
00760             ast_reentrancy_unlock(lock);  
00761          }
00762          pthread_mutex_unlock(&lock_info->lock);
00763          if (!str)
00764             break;
00765          ast_dynamic_str_append(&str, 0, "=== -------------------------------------------------------------------\n"
00766                      "===\n");
00767          if (!str)
00768             break;
00769       }
00770    }
00771    pthread_mutex_unlock(&lock_infos_lock.mutex);
00772 
00773    if (!str)
00774       return RESULT_FAILURE;
00775 
00776    ast_dynamic_str_append(&str, 0, "=======================================================================\n"
00777                "\n");
00778 
00779    if (!str)
00780       return RESULT_FAILURE;
00781 
00782    ast_cli(fd, "%s", str->str);
00783 
00784    free(str);
00785 
00786    return RESULT_SUCCESS;
00787 }
00788 
00789 static char show_locks_help[] =
00790 "Usage: core show locks\n"
00791 "       This command is for lock debugging.  It prints out which locks\n"
00792 "are owned by each active thread.\n";
00793 
00794 static struct ast_cli_entry utils_cli[] = {
00795    { { "core", "show", "locks", NULL }, handle_show_locks,
00796      "Show which locks are locked by which thread", show_locks_help },
00797 };
00798 
00799 #endif /* DEBUG_THREADS */
00800 
00801 
00802 
00803 /*
00804  * support for 'show threads'. The start routine is wrapped by
00805  * dummy_start(), so that ast_register_thread() and
00806  * ast_unregister_thread() know the thread identifier.
00807  */
00808 struct thr_arg {
00809    void *(*start_routine)(void *);
00810    void *data;
00811    char *name;
00812 };
00813 
00814 /*
00815  * on OS/X, pthread_cleanup_push() and pthread_cleanup_pop()
00816  * are odd macros which start and end a block, so they _must_ be
00817  * used in pairs (the latter with a '1' argument to call the
00818  * handler on exit.
00819  * On BSD we don't need this, but we keep it for compatibility.
00820  */
00821 static void *dummy_start(void *data)
00822 {
00823    void *ret;
00824    struct thr_arg a = *((struct thr_arg *) data);  /* make a local copy */
00825 #ifdef DEBUG_THREADS
00826    struct thr_lock_info *lock_info;
00827    pthread_mutexattr_t mutex_attr;
00828 #endif
00829 
00830    /* note that even though data->name is a pointer to allocated memory,
00831       we are not freeing it here because ast_register_thread is going to
00832       keep a copy of the pointer and then ast_unregister_thread will
00833       free the memory
00834    */
00835    free(data);
00836    ast_register_thread(a.name);
00837    pthread_cleanup_push(ast_unregister_thread, (void *) pthread_self());
00838 
00839 #ifdef DEBUG_THREADS
00840    if (!(lock_info = ast_threadstorage_get(&thread_lock_info, sizeof(*lock_info))))
00841       return NULL;
00842 
00843    lock_info->thread_id = pthread_self();
00844    lock_info->thread_name = strdup(a.name);
00845 
00846    pthread_mutexattr_init(&mutex_attr);
00847    pthread_mutexattr_settype(&mutex_attr, AST_MUTEX_KIND);
00848    pthread_mutex_init(&lock_info->lock, &mutex_attr);
00849    pthread_mutexattr_destroy(&mutex_attr);
00850 
00851    pthread_mutex_lock(&lock_infos_lock.mutex); /* Intentionally not the wrapper */
00852    AST_LIST_INSERT_TAIL(&lock_infos, lock_info, entry);
00853    pthread_mutex_unlock(&lock_infos_lock.mutex); /* Intentionally not the wrapper */
00854 #endif /* DEBUG_THREADS */
00855 
00856    ret = a.start_routine(a.data);
00857 
00858    pthread_cleanup_pop(1);
00859 
00860    return ret;
00861 }
00862 
00863 #endif /* !LOW_MEMORY */
00864 
00865 int ast_pthread_create_stack(pthread_t *thread, pthread_attr_t *attr, void *(*start_routine)(void *),
00866               void *data, size_t stacksize, const char *file, const char *caller,
00867               int line, const char *start_fn)
00868 {
00869 #if !defined(LOW_MEMORY)
00870    struct thr_arg *a;
00871 #endif
00872 
00873    if (!attr) {
00874       attr = alloca(sizeof(*attr));
00875       pthread_attr_init(attr);
00876    }
00877 
00878 #ifdef __linux__
00879    /* On Linux, pthread_attr_init() defaults to PTHREAD_EXPLICIT_SCHED,
00880       which is kind of useless. Change this here to
00881       PTHREAD_INHERIT_SCHED; that way the -p option to set realtime
00882       priority will propagate down to new threads by default.
00883       This does mean that callers cannot set a different priority using
00884       PTHREAD_EXPLICIT_SCHED in the attr argument; instead they must set
00885       the priority afterwards with pthread_setschedparam(). */
00886    if ((errno = pthread_attr_setinheritsched(attr, PTHREAD_INHERIT_SCHED)))
00887       ast_log(LOG_WARNING, "pthread_attr_setinheritsched: %s\n", strerror(errno));
00888 #endif
00889 
00890    if (!stacksize)
00891       stacksize = AST_STACKSIZE;
00892 
00893    if ((errno = pthread_attr_setstacksize(attr, stacksize ? stacksize : AST_STACKSIZE)))
00894       ast_log(LOG_WARNING, "pthread_attr_setstacksize: %s\n", strerror(errno));
00895 
00896 #if !defined(LOW_MEMORY)
00897    if ((a = ast_malloc(sizeof(*a)))) {
00898       a->start_routine = start_routine;
00899       a->data = data;
00900       start_routine = dummy_start;
00901       if (asprintf(&a->name, "%-20s started at [%5d] %s %s()",
00902               start_fn, line, file, caller) < 0) {
00903          ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno));
00904          a->name = NULL;
00905       }
00906       data = a;
00907    }
00908 #endif /* !LOW_MEMORY */
00909 
00910    return pthread_create(thread, attr, start_routine, data); /* We're in ast_pthread_create, so it's okay */
00911 }
00912 
00913 int ast_wait_for_input(int fd, int ms)
00914 {
00915    struct pollfd pfd[1];
00916    memset(pfd, 0, sizeof(pfd));
00917    pfd[0].fd = fd;
00918    pfd[0].events = POLLIN|POLLPRI;
00919    return ast_poll(pfd, 1, ms);
00920 }
00921 
00922 int ast_carefulwrite(int fd, char *s, int len, int timeoutms) 
00923 {
00924    struct timeval start = ast_tvnow();
00925    int res = 0;
00926    int elapsed = 0;
00927 
00928    while (len) {
00929       struct pollfd pfd = {
00930          .fd = fd,
00931          .events = POLLOUT,
00932       };
00933 
00934       /* poll() until the fd is writable without blocking */
00935       while ((res = ast_poll(&pfd, 1, timeoutms - elapsed)) <= 0) {
00936          if (res == 0) {
00937             /* timed out. */
00938             if (option_debug) {
00939                ast_log(LOG_DEBUG, "Timed out trying to write\n");
00940             }
00941             return -1;
00942          } else if (res == -1) {
00943             /* poll() returned an error, check to see if it was fatal */
00944 
00945             if (errno == EINTR || errno == EAGAIN) {
00946                elapsed = ast_tvdiff_ms(ast_tvnow(), start);
00947                if (elapsed > timeoutms) {
00948                   /* We've taken too long to write 
00949                    * This is only an error condition if we haven't finished writing. */
00950                   res = len ? -1 : 0;
00951                   break;
00952                }
00953                /* This was an acceptable error, go back into poll() */
00954                continue;
00955             }
00956 
00957             /* Fatal error, bail. */
00958             ast_log(LOG_ERROR, "poll returned error: %s\n", strerror(errno));
00959 
00960             return -1;
00961          }
00962       }
00963 
00964       res = write(fd, s, len);
00965 
00966       if (res < 0 && errno != EAGAIN && errno != EINTR) {
00967          /* fatal error from write() */
00968          ast_log(LOG_ERROR, "write() returned error: %s\n", strerror(errno));
00969          return -1;
00970       }
00971 
00972       if (res < 0) {
00973          /* It was an acceptable error */
00974          res = 0;
00975       }
00976 
00977       /* Update how much data we have left to write */
00978       len -= res;
00979       s += res;
00980       res = 0;
00981 
00982       elapsed = ast_tvdiff_ms(ast_tvnow(), start);
00983       if (elapsed > timeoutms) {
00984          /* We've taken too long to write 
00985           * This is only an error condition if we haven't finished writing. */
00986          res = len ? -1 : 0;
00987          break;
00988       }
00989    }
00990 
00991    return res;
00992 }
00993 
00994 char *ast_strip_quoted(char *s, const char *beg_quotes, const char *end_quotes)
00995 {
00996    char *e;
00997    char *q;
00998 
00999    s = ast_strip(s);
01000    if ((q = strchr(beg_quotes, *s)) && *q != '\0') {
01001       e = s + strlen(s) - 1;
01002       if (*e == *(end_quotes + (q - beg_quotes))) {
01003          s++;
01004          *e = '\0';
01005       }
01006    }
01007 
01008    return s;
01009 }
01010 
01011 char *ast_unescape_semicolon(char *s)
01012 {
01013    char *e;
01014    char *work = s;
01015 
01016    while ((e = strchr(work, ';'))) {
01017       if ((e > work) && (*(e-1) == '\\')) {
01018          memmove(e - 1, e, strlen(e) + 1);
01019          work = e;
01020       } else {
01021          work = e + 1;
01022       }
01023    }
01024 
01025    return s;
01026 }
01027 
01028 int ast_build_string_va(char **buffer, size_t *space, const char *fmt, va_list ap)
01029 {
01030    int result;
01031 
01032    if (!buffer || !*buffer || !space || !*space)
01033       return -1;
01034 
01035    result = vsnprintf(*buffer, *space, fmt, ap);
01036 
01037    if (result < 0)
01038       return -1;
01039    else if (result > *space)
01040       result = *space;
01041 
01042    *buffer += result;
01043    *space -= result;
01044    return 0;
01045 }
01046 
01047 int ast_build_string(char **buffer, size_t *space, const char *fmt, ...)
01048 {
01049    va_list ap;
01050    int result;
01051 
01052    va_start(ap, fmt);
01053    result = ast_build_string_va(buffer, space, fmt, ap);
01054    va_end(ap);
01055 
01056    return result;
01057 }
01058 
01059 int ast_true(const char *s)
01060 {
01061    if (ast_strlen_zero(s))
01062       return 0;
01063 
01064    /* Determine if this is a true value */
01065    if (!strcasecmp(s, "yes") ||
01066        !strcasecmp(s, "true") ||
01067        !strcasecmp(s, "y") ||
01068        !strcasecmp(s, "t") ||
01069        !strcasecmp(s, "1") ||
01070        !strcasecmp(s, "on"))
01071       return -1;
01072 
01073    return 0;
01074 }
01075 
01076 int ast_false(const char *s)
01077 {
01078    if (ast_strlen_zero(s))
01079       return 0;
01080 
01081    /* Determine if this is a false value */
01082    if (!strcasecmp(s, "no") ||
01083        !strcasecmp(s, "false") ||
01084        !strcasecmp(s, "n") ||
01085        !strcasecmp(s, "f") ||
01086        !strcasecmp(s, "0") ||
01087        !strcasecmp(s, "off"))
01088       return -1;
01089 
01090    return 0;
01091 }
01092 
01093 #define ONE_MILLION  1000000
01094 /*
01095  * put timeval in a valid range. usec is 0..999999
01096  * negative values are not allowed and truncated.
01097  */
01098 static struct timeval tvfix(struct timeval a)
01099 {
01100    if (a.tv_usec >= ONE_MILLION) {
01101       ast_log(LOG_WARNING, "warning too large timestamp %ld.%ld\n",
01102          (long) a.tv_sec, (long int) a.tv_usec);
01103       a.tv_sec += a.tv_usec / ONE_MILLION;
01104       a.tv_usec %= ONE_MILLION;
01105    } else if (a.tv_usec < 0) {
01106       ast_log(LOG_WARNING, "warning negative timestamp %ld.%ld\n",
01107          (long) a.tv_sec, (long int) a.tv_usec);
01108       a.tv_usec = 0;
01109    }
01110    return a;
01111 }
01112 
01113 struct timeval ast_tvadd(struct timeval a, struct timeval b)
01114 {
01115    /* consistency checks to guarantee usec in 0..999999 */
01116    a = tvfix(a);
01117    b = tvfix(b);
01118    a.tv_sec += b.tv_sec;
01119    a.tv_usec += b.tv_usec;
01120    if (a.tv_usec >= ONE_MILLION) {
01121       a.tv_sec++;
01122       a.tv_usec -= ONE_MILLION;
01123    }
01124    return a;
01125 }
01126 
01127 struct timeval ast_tvsub(struct timeval a, struct timeval b)
01128 {
01129    /* consistency checks to guarantee usec in 0..999999 */
01130    a = tvfix(a);
01131    b = tvfix(b);
01132    a.tv_sec -= b.tv_sec;
01133    a.tv_usec -= b.tv_usec;
01134    if (a.tv_usec < 0) {
01135       a.tv_sec-- ;
01136       a.tv_usec += ONE_MILLION;
01137    }
01138    return a;
01139 }
01140 #undef ONE_MILLION
01141 
01142 /*! \brief glibc puts a lock inside random(3), so that the results are thread-safe.
01143  * BSD libc (and others) do not. */
01144 #ifndef linux
01145 
01146 AST_MUTEX_DEFINE_STATIC(randomlock);
01147 
01148 long int ast_random(void)
01149 {
01150    long int res;
01151    ast_mutex_lock(&randomlock);
01152    res = random();
01153    ast_mutex_unlock(&randomlock);
01154    return res;
01155 }
01156 #endif
01157 
01158 char *ast_process_quotes_and_slashes(char *start, char find, char replace_with)
01159 {
01160    char *dataPut = start;
01161    int inEscape = 0;
01162    int inQuotes = 0;
01163 
01164    for (; *start; start++) {
01165       if (inEscape) {
01166          *dataPut++ = *start;       /* Always goes verbatim */
01167          inEscape = 0;
01168       } else {
01169          if (*start == '\\') {
01170             inEscape = 1;      /* Do not copy \ into the data */
01171          } else if (*start == '\'') {
01172             inQuotes = 1 - inQuotes;   /* Do not copy ' into the data */
01173          } else {
01174             /* Replace , with |, unless in quotes */
01175             *dataPut++ = inQuotes ? *start : ((*start == find) ? replace_with : *start);
01176          }
01177       }
01178    }
01179    if (start != dataPut)
01180       *dataPut = 0;
01181    return dataPut;
01182 }
01183 
01184 void ast_join(char *s, size_t len, char * const w[])
01185 {
01186    int x, ofs = 0;
01187    const char *src;
01188 
01189    /* Join words into a string */
01190    if (!s)
01191       return;
01192    for (x = 0; ofs < len && w[x]; x++) {
01193       if (x > 0)
01194          s[ofs++] = ' ';
01195       for (src = w[x]; *src && ofs < len; src++)
01196          s[ofs++] = *src;
01197    }
01198    if (ofs == len)
01199       ofs--;
01200    s[ofs] = '\0';
01201 }
01202 
01203 const char __ast_string_field_empty[] = "";
01204 
01205 static int add_string_pool(struct ast_string_field_mgr *mgr, size_t size)
01206 {
01207    struct ast_string_field_pool *pool;
01208 
01209    if (!(pool = ast_calloc(1, sizeof(*pool) + size)))
01210       return -1;
01211    
01212    pool->prev = mgr->pool;
01213    mgr->pool = pool;
01214    mgr->size = size;
01215    mgr->space = size;
01216    mgr->used = 0;
01217 
01218    return 0;
01219 }
01220 
01221 int __ast_string_field_init(struct ast_string_field_mgr *mgr, size_t size,
01222              ast_string_field *fields, int num_fields)
01223 {
01224    int index;
01225 
01226    if (add_string_pool(mgr, size))
01227       return -1;
01228 
01229    for (index = 0; index < num_fields; index++)
01230       fields[index] = __ast_string_field_empty;
01231 
01232    return 0;
01233 }
01234 
01235 ast_string_field __ast_string_field_alloc_space(struct ast_string_field_mgr *mgr, size_t needed,
01236                   ast_string_field *fields, int num_fields)
01237 {
01238    char *result = NULL;
01239 
01240    if (__builtin_expect(needed > mgr->space, 0)) {
01241       size_t new_size = mgr->size * 2;
01242 
01243       while (new_size < needed)
01244          new_size *= 2;
01245 
01246       if (add_string_pool(mgr, new_size))
01247          return NULL;
01248    }
01249 
01250    result = mgr->pool->base + mgr->used;
01251    mgr->used += needed;
01252    mgr->space -= needed;
01253    return result;
01254 }
01255 
01256 void __ast_string_field_index_build_va(struct ast_string_field_mgr *mgr,
01257                    ast_string_field *fields, int num_fields,
01258                    int index, const char *format, va_list ap1, va_list ap2)
01259 {
01260    size_t needed;
01261    size_t available;
01262    char *target;
01263 
01264    /* if the field already has space allocated, try to reuse it;
01265       otherwise, use the empty space at the end of the current
01266       pool
01267    */
01268    if (fields[index][0] != '\0') {
01269       target = (char *) fields[index];
01270       available = strlen(fields[index]) + 1;
01271    } else {
01272       target = mgr->pool->base + mgr->used;
01273       available = mgr->space;
01274    }
01275 
01276    needed = vsnprintf(target, available, format, ap1) + 1;
01277 
01278    va_end(ap1);
01279 
01280    if (needed > available) {
01281       /* if the space needed can be satisfied by using the current
01282          pool (which could only occur if we tried to use the field's
01283          allocated space and failed), then use that space; otherwise
01284          allocate a new pool
01285       */
01286       if (needed <= mgr->space) {
01287          target = mgr->pool->base + mgr->used;
01288       } else {
01289          size_t new_size = mgr->size * 2;
01290 
01291          while (new_size < needed)
01292             new_size *= 2;
01293          
01294          if (add_string_pool(mgr, new_size))
01295             return;
01296          
01297          target = mgr->pool->base + mgr->used;
01298       }
01299 
01300       vsprintf(target, format, ap2);
01301    }
01302 
01303    if (fields[index] != target) {
01304       fields[index] = target;
01305       mgr->used += needed;
01306       mgr->space -= needed;
01307    }
01308 }
01309 
01310 void __ast_string_field_index_build(struct ast_string_field_mgr *mgr,
01311                 ast_string_field *fields, int num_fields,
01312                 int index, const char *format, ...)
01313 {
01314    va_list ap1, ap2;
01315 
01316    va_start(ap1, format);
01317    va_start(ap2, format);     /* va_copy does not exist on FreeBSD */
01318 
01319    __ast_string_field_index_build_va(mgr, fields, num_fields, index, format, ap1, ap2);
01320 
01321    va_end(ap1);
01322    va_end(ap2);
01323 }
01324 
01325 AST_MUTEX_DEFINE_STATIC(fetchadd_m); /* used for all fetc&add ops */
01326 
01327 int ast_atomic_fetchadd_int_slow(volatile int *p, int v)
01328 {
01329         int ret;
01330         ast_mutex_lock(&fetchadd_m);
01331         ret = *p;
01332         *p += v;
01333         ast_mutex_unlock(&fetchadd_m);
01334         return ret;
01335 }
01336 
01337 /*! \brief
01338  * get values from config variables.
01339  */
01340 int ast_get_time_t(const char *src, time_t *dst, time_t _default, int *consumed)
01341 {
01342    long t;
01343    int scanned;
01344 
01345    if (dst == NULL)
01346       return -1;
01347 
01348    *dst = _default;
01349 
01350    if (ast_strlen_zero(src))
01351       return -1;
01352 
01353    /* only integer at the moment, but one day we could accept more formats */
01354    if (sscanf(src, "%30ld%n", &t, &scanned) == 1) {
01355       *dst = t;
01356       if (consumed)
01357          *consumed = scanned;
01358       return 0;
01359    } else
01360       return -1;
01361 }
01362 
01363 int ast_dynamic_str_thread_build_va(struct ast_dynamic_str **buf, size_t max_len,
01364    struct ast_threadstorage *ts, int append, const char *fmt, va_list ap)
01365 {
01366    int res;
01367    int offset = (append && (*buf)->len) ? strlen((*buf)->str) : 0;
01368 #if defined(DEBUG_THREADLOCALS)
01369    struct ast_dynamic_str *old_buf = *buf;
01370 #endif /* defined(DEBUG_THREADLOCALS) */
01371 
01372    res = vsnprintf((*buf)->str + offset, (*buf)->len - offset, fmt, ap);
01373 
01374    /* Check to see if there was not enough space in the string buffer to prepare
01375     * the string.  Also, if a maximum length is present, make sure the current
01376     * length is less than the maximum before increasing the size. */
01377    if ((res + offset + 1) > (*buf)->len && (max_len ? ((*buf)->len < max_len) : 1)) {
01378       /* Set the new size of the string buffer to be the size needed
01379        * to hold the resulting string (res) plus one byte for the
01380        * terminating '\0'.  If this size is greater than the max, set
01381        * the new length to be the maximum allowed. */
01382       if (max_len)
01383          (*buf)->len = ((res + offset + 1) < max_len) ? (res + offset + 1) : max_len;
01384       else
01385          (*buf)->len = res + offset + 1;
01386 
01387       if (!(*buf = ast_realloc(*buf, (*buf)->len + sizeof(*(*buf)))))
01388          return AST_DYNSTR_BUILD_FAILED;
01389 
01390       if (append)
01391          (*buf)->str[offset] = '\0';
01392 
01393       if (ts) {
01394          pthread_setspecific(ts->key, *buf);
01395 #if defined(DEBUG_THREADLOCALS)
01396          __ast_threadstorage_object_replace(old_buf, *buf, (*buf)->len + sizeof(*(*buf)));
01397 #endif /* defined(DEBUG_THREADLOCALS) */
01398       }
01399 
01400       /* va_end() and va_start() must be done before calling
01401        * vsnprintf() again. */
01402       return AST_DYNSTR_BUILD_RETRY;
01403    }
01404 
01405    return res;
01406 }
01407 
01408 void ast_enable_packet_fragmentation(int sock)
01409 {
01410 #if defined(HAVE_IP_MTU_DISCOVER)
01411    int val = IP_PMTUDISC_DONT;
01412    
01413    if (setsockopt(sock, IPPROTO_IP, IP_MTU_DISCOVER, &val, sizeof(val)))
01414       ast_log(LOG_WARNING, "Unable to disable PMTU discovery. Large UDP packets may fail to be delivered when sent from this socket.\n");
01415 #endif /* HAVE_IP_MTU_DISCOVER */
01416 }
01417 
01418 int ast_utils_init(void)
01419 {
01420    base64_init();
01421 #ifdef DEBUG_THREADS
01422 #if !defined(LOW_MEMORY)
01423    ast_cli_register_multiple(utils_cli, sizeof(utils_cli) / sizeof(utils_cli[0]));
01424 #endif
01425 #endif
01426    return 0;
01427 }
01428 
01429 #ifndef __AST_DEBUG_MALLOC
01430 int _ast_asprintf(char **ret, const char *file, int lineno, const char *func, const char *fmt, ...)
01431 {
01432    int res;
01433    va_list ap;
01434 
01435    va_start(ap, fmt);
01436    if ((res = vasprintf(ret, fmt, ap)) == -1) {
01437       MALLOC_FAILURE_MSG;
01438    }
01439    va_end(ap);
01440 
01441    return res;
01442 }
01443 #endif
01444 
01445 char *ast_utils_which(const char *binary, char *fullpath, size_t fullpath_size)
01446 {
01447    const char *envPATH = getenv("PATH");
01448    char *tpath, *path;
01449    struct stat unused;
01450    if (!envPATH) {
01451       return NULL;
01452    }
01453    tpath = ast_strdupa(envPATH);
01454    while ((path = strsep(&tpath, ":"))) {
01455       snprintf(fullpath, fullpath_size, "%s/%s", path, binary);
01456       if (!stat(fullpath, &unused)) {
01457          return fullpath;
01458       }
01459    }
01460    return NULL;
01461 }
01462 

Generated on Sat Aug 6 00:39:33 2011 for Asterisk - the Open Source PBX by  doxygen 1.4.7