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

Generated on Sun Dec 18 20:55:42 2011 for Asterisk - the Open Source PBX by  doxygen 1.5.6