Mon Nov 24 15:34:21 2008

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: 133237 $")
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 = NULL;
00453    char *buf = NULL;
00454 
00455    ast_copy_string(outbuf, string, buflen);
00456 
00457    /* If there's no characters to convert, just go through and don't do anything */
00458    while (*ptr) {
00459       if (((unsigned char) *ptr) > 127 || (doreserved && strchr(reserved, *ptr)) ) {
00460          /* Oops, we need to start working here */
00461          if (!buf) {
00462             buf = outbuf;
00463             out = buf + (ptr - string) ;  /* Set output ptr */
00464          }
00465          out += sprintf(out, "%%%02x", (unsigned char) *ptr);
00466       } else if (buf) {
00467          *out = *ptr;   /* Continue copying the string */
00468          out++;
00469       } 
00470       ptr++;
00471    }
00472    if (buf)
00473       *out = '\0';
00474    return outbuf;
00475 }
00476 
00477 /*! \brief  ast_uri_decode: Decode SIP URI, URN, URL (overwrite the string)  */
00478 void ast_uri_decode(char *s) 
00479 {
00480    char *o;
00481    unsigned int tmp;
00482 
00483    for (o = s; *s; s++, o++) {
00484       if (*s == '%' && strlen(s) > 2 && sscanf(s + 1, "%2x", &tmp) == 1) {
00485          /* have '%', two chars and correct parsing */
00486          *o = tmp;
00487          s += 2;  /* Will be incremented once more when we break out */
00488       } else /* all other cases, just copy */
00489          *o = *s;
00490    }
00491    *o = '\0';
00492 }
00493 
00494 /*! \brief  ast_inet_ntoa: Recursive thread safe replacement of inet_ntoa */
00495 const char *ast_inet_ntoa(struct in_addr ia)
00496 {
00497    char *buf;
00498 
00499    if (!(buf = ast_threadstorage_get(&inet_ntoa_buf, INET_ADDRSTRLEN)))
00500       return "";
00501 
00502    return inet_ntop(AF_INET, &ia, buf, INET_ADDRSTRLEN);
00503 }
00504 
00505 #ifndef __linux__
00506 #undef pthread_create /* For ast_pthread_create function only */
00507 #endif /* !__linux__ */
00508 
00509 #if !defined(LOW_MEMORY)
00510 
00511 #ifdef DEBUG_THREADS
00512 
00513 /*! \brief A reasonable maximum number of locks a thread would be holding ... */
00514 #define AST_MAX_LOCKS 64
00515 
00516 /* Allow direct use of pthread_mutex_t and friends */
00517 #undef pthread_mutex_t
00518 #undef pthread_mutex_lock
00519 #undef pthread_mutex_unlock
00520 #undef pthread_mutex_init
00521 #undef pthread_mutex_destroy
00522 
00523 /*! 
00524  * \brief Keep track of which locks a thread holds 
00525  *
00526  * There is an instance of this struct for every active thread
00527  */
00528 struct thr_lock_info {
00529    /*! The thread's ID */
00530    pthread_t thread_id;
00531    /*! The thread name which includes where the thread was started */
00532    const char *thread_name;
00533    /*! This is the actual container of info for what locks this thread holds */
00534    struct {
00535       const char *file;
00536       int line_num;
00537       const char *func;
00538       const char *lock_name;
00539       void *lock_addr;
00540       int times_locked;
00541       enum ast_lock_type type;
00542       /*! This thread is waiting on this lock */
00543       int pending:2;
00544    } locks[AST_MAX_LOCKS];
00545    /*! This is the number of locks currently held by this thread.
00546     *  The index (num_locks - 1) has the info on the last one in the
00547     *  locks member */
00548    unsigned int num_locks;
00549    /*! Protects the contents of the locks member 
00550     * Intentionally not ast_mutex_t */
00551    pthread_mutex_t lock;
00552    AST_LIST_ENTRY(thr_lock_info) entry;
00553 };
00554 
00555 /*! 
00556  * \brief Locked when accessing the lock_infos list 
00557  */
00558 AST_MUTEX_DEFINE_STATIC(lock_infos_lock);
00559 /*!
00560  * \brief A list of each thread's lock info 
00561  */
00562 static AST_LIST_HEAD_NOLOCK_STATIC(lock_infos, thr_lock_info);
00563 
00564 /*!
00565  * \brief Destroy a thread's lock info
00566  *
00567  * This gets called automatically when the thread stops
00568  */
00569 static void lock_info_destroy(void *data)
00570 {
00571    struct thr_lock_info *lock_info = data;
00572    int i;
00573 
00574    pthread_mutex_lock(&lock_infos_lock.mutex);
00575    AST_LIST_REMOVE(&lock_infos, lock_info, entry);
00576    pthread_mutex_unlock(&lock_infos_lock.mutex);
00577 
00578 
00579    for (i = 0; i < lock_info->num_locks; i++) {
00580       ast_log(LOG_ERROR, 
00581          "Thread '%s' still has a lock! - '%s' (%p) from '%s' in %s:%d!\n", 
00582          lock_info->thread_name,
00583          lock_info->locks[i].lock_name,
00584          lock_info->locks[i].lock_addr,
00585          lock_info->locks[i].func,
00586          lock_info->locks[i].file,
00587          lock_info->locks[i].line_num
00588       );
00589    }
00590 
00591    pthread_mutex_destroy(&lock_info->lock);
00592    free((void *) lock_info->thread_name);
00593    free(lock_info);
00594 }
00595 
00596 /*!
00597  * \brief The thread storage key for per-thread lock info
00598  */
00599 AST_THREADSTORAGE_CUSTOM(thread_lock_info, thread_lock_info_init, lock_info_destroy);
00600 
00601 void ast_store_lock_info(enum ast_lock_type type, const char *filename,
00602    int line_num, const char *func, const char *lock_name, void *lock_addr)
00603 {
00604    struct thr_lock_info *lock_info;
00605    int i;
00606 
00607    if (!(lock_info = ast_threadstorage_get(&thread_lock_info, sizeof(*lock_info))))
00608       return;
00609 
00610    pthread_mutex_lock(&lock_info->lock);
00611 
00612    for (i = 0; i < lock_info->num_locks; i++) {
00613       if (lock_info->locks[i].lock_addr == lock_addr) {
00614          lock_info->locks[i].times_locked++;
00615          pthread_mutex_unlock(&lock_info->lock);
00616          return;
00617       }
00618    }
00619 
00620    if (lock_info->num_locks == AST_MAX_LOCKS) {
00621       /* Can't use ast_log here, because it will cause infinite recursion */
00622       fprintf(stderr, "XXX ERROR XXX A thread holds more locks than '%d'."
00623          "  Increase AST_MAX_LOCKS!\n", AST_MAX_LOCKS);
00624       pthread_mutex_unlock(&lock_info->lock);
00625       return;
00626    }
00627 
00628    if (i && lock_info->locks[i - 1].pending == -1) {
00629       /* The last lock on the list was one that this thread tried to lock but
00630        * failed at doing so.  It has now moved on to something else, so remove
00631        * the old lock from the list. */
00632       i--;
00633       lock_info->num_locks--;
00634       memset(&lock_info->locks[i], 0, sizeof(lock_info->locks[0]));
00635    }
00636 
00637    lock_info->locks[i].file = filename;
00638    lock_info->locks[i].line_num = line_num;
00639    lock_info->locks[i].func = func;
00640    lock_info->locks[i].lock_name = lock_name;
00641    lock_info->locks[i].lock_addr = lock_addr;
00642    lock_info->locks[i].times_locked = 1;
00643    lock_info->locks[i].type = type;
00644    lock_info->locks[i].pending = 1;
00645    lock_info->num_locks++;
00646 
00647    pthread_mutex_unlock(&lock_info->lock);
00648 }
00649 
00650 void ast_mark_lock_acquired(void *lock_addr)
00651 {
00652    struct thr_lock_info *lock_info;
00653 
00654    if (!(lock_info = ast_threadstorage_get(&thread_lock_info, sizeof(*lock_info))))
00655       return;
00656 
00657    pthread_mutex_lock(&lock_info->lock);
00658    if (lock_info->locks[lock_info->num_locks - 1].lock_addr == lock_addr) {
00659       lock_info->locks[lock_info->num_locks - 1].pending = 0;
00660    }
00661    pthread_mutex_unlock(&lock_info->lock);
00662 }
00663 
00664 void ast_mark_lock_failed(void *lock_addr)
00665 {
00666    struct thr_lock_info *lock_info;
00667 
00668    if (!(lock_info = ast_threadstorage_get(&thread_lock_info, sizeof(*lock_info))))
00669       return;
00670 
00671    pthread_mutex_lock(&lock_info->lock);
00672    if (lock_info->locks[lock_info->num_locks - 1].lock_addr == lock_addr) {
00673       lock_info->locks[lock_info->num_locks - 1].pending = -1;
00674       lock_info->locks[lock_info->num_locks - 1].times_locked--;
00675    }
00676    pthread_mutex_unlock(&lock_info->lock);
00677 }
00678 
00679 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)
00680 {
00681    struct thr_lock_info *lock_info;
00682    int i = 0;
00683 
00684    if (!(lock_info = ast_threadstorage_get(&thread_lock_info, sizeof(*lock_info))))
00685       return -1;
00686 
00687    pthread_mutex_lock(&lock_info->lock);
00688 
00689    for (i = lock_info->num_locks - 1; i >= 0; i--) {
00690       if (lock_info->locks[i].lock_addr == lock_addr)
00691          break;
00692    }
00693 
00694    if (i == -1) {
00695       /* Lock not found :( */
00696       pthread_mutex_unlock(&lock_info->lock);
00697       return -1;
00698    }
00699 
00700    ast_copy_string(filename, lock_info->locks[i].file, filename_size);
00701    *lineno = lock_info->locks[i].line_num;
00702    ast_copy_string(func, lock_info->locks[i].func, func_size);
00703    ast_copy_string(mutex_name, lock_info->locks[i].lock_name, mutex_name_size);
00704 
00705    pthread_mutex_unlock(&lock_info->lock);
00706 
00707    return 0;
00708 }
00709 
00710 void ast_remove_lock_info(void *lock_addr)
00711 {
00712    struct thr_lock_info *lock_info;
00713    int i = 0;
00714 
00715    if (!(lock_info = ast_threadstorage_get(&thread_lock_info, sizeof(*lock_info))))
00716       return;
00717 
00718    pthread_mutex_lock(&lock_info->lock);
00719 
00720    for (i = lock_info->num_locks - 1; i >= 0; i--) {
00721       if (lock_info->locks[i].lock_addr == lock_addr)
00722          break;
00723    }
00724 
00725    if (i == -1) {
00726       /* Lock not found :( */
00727       pthread_mutex_unlock(&lock_info->lock);
00728       return;
00729    }
00730 
00731    if (lock_info->locks[i].times_locked > 1) {
00732       lock_info->locks[i].times_locked--;
00733       pthread_mutex_unlock(&lock_info->lock);
00734       return;
00735    }
00736 
00737    if (i < lock_info->num_locks - 1) {
00738       /* Not the last one ... *should* be rare! */
00739       memmove(&lock_info->locks[i], &lock_info->locks[i + 1], 
00740          (lock_info->num_locks - (i + 1)) * sizeof(lock_info->locks[0]));
00741    }
00742 
00743    lock_info->num_locks--;
00744 
00745    pthread_mutex_unlock(&lock_info->lock);
00746 }
00747 
00748 static const char *locktype2str(enum ast_lock_type type)
00749 {
00750    switch (type) {
00751    case AST_MUTEX:
00752       return "MUTEX";
00753    case AST_RDLOCK:
00754       return "RDLOCK";
00755    case AST_WRLOCK:
00756       return "WRLOCK";
00757    }
00758 
00759    return "UNKNOWN";
00760 }
00761 
00762 static int handle_show_locks(int fd, int argc, char *argv[])
00763 {
00764    struct thr_lock_info *lock_info;
00765    struct ast_dynamic_str *str;
00766 
00767    if (!(str = ast_dynamic_str_create(4096)))
00768       return RESULT_FAILURE;
00769 
00770    ast_dynamic_str_append(&str, 0, "\n" 
00771                "=======================================================================\n"
00772                "=== Currently Held Locks ==============================================\n"
00773                "=======================================================================\n"
00774                "===\n"
00775             "=== <file> <line num> <function> <lock name> <lock addr> (times locked)\n"
00776             "===\n");
00777 
00778    if (!str)
00779       return RESULT_FAILURE;
00780 
00781    pthread_mutex_lock(&lock_infos_lock.mutex);
00782    AST_LIST_TRAVERSE(&lock_infos, lock_info, entry) {
00783       int i;
00784       if (lock_info->num_locks) {
00785          ast_dynamic_str_append(&str, 0, "=== Thread ID: %u (%s)\n", (int) lock_info->thread_id,
00786             lock_info->thread_name);
00787          pthread_mutex_lock(&lock_info->lock);
00788          for (i = 0; str && i < lock_info->num_locks; i++) {
00789             int j;
00790             ast_mutex_t *lock;
00791 
00792             ast_dynamic_str_append(&str, 0, "=== ---> %sLock #%d (%s): %s %d %s %s %p (%d)\n", 
00793                lock_info->locks[i].pending > 0 ? "Waiting for " : 
00794                   lock_info->locks[i].pending < 0 ? "Tried and failed to get " : "", i,
00795                lock_info->locks[i].file, 
00796                locktype2str(lock_info->locks[i].type),
00797                lock_info->locks[i].line_num,
00798                lock_info->locks[i].func, lock_info->locks[i].lock_name,
00799                lock_info->locks[i].lock_addr, 
00800                lock_info->locks[i].times_locked);
00801 
00802             if (!lock_info->locks[i].pending || lock_info->locks[i].pending == -1)
00803                continue;
00804 
00805             /* We only have further details for mutexes right now */
00806             if (lock_info->locks[i].type != AST_MUTEX)
00807                continue;
00808 
00809             lock = lock_info->locks[i].lock_addr;
00810 
00811             ast_reentrancy_lock(lock);
00812             for (j = 0; str && j < lock->reentrancy; j++) {
00813                ast_dynamic_str_append(&str, 0, "=== --- ---> Locked Here: %s line %d (%s)\n",
00814                   lock->file[j], lock->lineno[j], lock->func[j]);
00815             }
00816             ast_reentrancy_unlock(lock);  
00817          }
00818          pthread_mutex_unlock(&lock_info->lock);
00819          if (!str)
00820             break;
00821          ast_dynamic_str_append(&str, 0, "=== -------------------------------------------------------------------\n"
00822                      "===\n");
00823          if (!str)
00824             break;
00825       }
00826    }
00827    pthread_mutex_unlock(&lock_infos_lock.mutex);
00828 
00829    if (!str)
00830       return RESULT_FAILURE;
00831 
00832    ast_dynamic_str_append(&str, 0, "=======================================================================\n"
00833                "\n");
00834 
00835    if (!str)
00836       return RESULT_FAILURE;
00837 
00838    ast_cli(fd, "%s", str->str);
00839 
00840    free(str);
00841 
00842    return RESULT_SUCCESS;
00843 }
00844 
00845 static char show_locks_help[] =
00846 "Usage: core show locks\n"
00847 "       This command is for lock debugging.  It prints out which locks\n"
00848 "are owned by each active thread.\n";
00849 
00850 static struct ast_cli_entry utils_cli[] = {
00851    { { "core", "show", "locks", NULL }, handle_show_locks,
00852      "Show which locks are locked by which thread", show_locks_help },
00853 };
00854 
00855 #endif /* DEBUG_THREADS */
00856 
00857 
00858 
00859 /*
00860  * support for 'show threads'. The start routine is wrapped by
00861  * dummy_start(), so that ast_register_thread() and
00862  * ast_unregister_thread() know the thread identifier.
00863  */
00864 struct thr_arg {
00865    void *(*start_routine)(void *);
00866    void *data;
00867    char *name;
00868 };
00869 
00870 /*
00871  * on OS/X, pthread_cleanup_push() and pthread_cleanup_pop()
00872  * are odd macros which start and end a block, so they _must_ be
00873  * used in pairs (the latter with a '1' argument to call the
00874  * handler on exit.
00875  * On BSD we don't need this, but we keep it for compatibility.
00876  */
00877 static void *dummy_start(void *data)
00878 {
00879    void *ret;
00880    struct thr_arg a = *((struct thr_arg *) data);  /* make a local copy */
00881 #ifdef DEBUG_THREADS
00882    struct thr_lock_info *lock_info;
00883    pthread_mutexattr_t mutex_attr;
00884 #endif
00885 
00886    /* note that even though data->name is a pointer to allocated memory,
00887       we are not freeing it here because ast_register_thread is going to
00888       keep a copy of the pointer and then ast_unregister_thread will
00889       free the memory
00890    */
00891    free(data);
00892    ast_register_thread(a.name);
00893    pthread_cleanup_push(ast_unregister_thread, (void *) pthread_self());
00894 
00895 #ifdef DEBUG_THREADS
00896    if (!(lock_info = ast_threadstorage_get(&thread_lock_info, sizeof(*lock_info))))
00897       return NULL;
00898 
00899    lock_info->thread_id = pthread_self();
00900    lock_info->thread_name = strdup(a.name);
00901 
00902    pthread_mutexattr_init(&mutex_attr);
00903    pthread_mutexattr_settype(&mutex_attr, AST_MUTEX_KIND);
00904    pthread_mutex_init(&lock_info->lock, &mutex_attr);
00905    pthread_mutexattr_destroy(&mutex_attr);
00906 
00907    pthread_mutex_lock(&lock_infos_lock.mutex); /* Intentionally not the wrapper */
00908    AST_LIST_INSERT_TAIL(&lock_infos, lock_info, entry);
00909    pthread_mutex_unlock(&lock_infos_lock.mutex); /* Intentionally not the wrapper */
00910 #endif /* DEBUG_THREADS */
00911 
00912    ret = a.start_routine(a.data);
00913 
00914    pthread_cleanup_pop(1);
00915 
00916    return ret;
00917 }
00918 
00919 #endif /* !LOW_MEMORY */
00920 
00921 int ast_pthread_create_stack(pthread_t *thread, pthread_attr_t *attr, void *(*start_routine)(void *),
00922               void *data, size_t stacksize, const char *file, const char *caller,
00923               int line, const char *start_fn)
00924 {
00925 #if !defined(LOW_MEMORY)
00926    struct thr_arg *a;
00927 #endif
00928 
00929    if (!attr) {
00930       attr = alloca(sizeof(*attr));
00931       pthread_attr_init(attr);
00932    }
00933 
00934 #ifdef __linux__
00935    /* On Linux, pthread_attr_init() defaults to PTHREAD_EXPLICIT_SCHED,
00936       which is kind of useless. Change this here to
00937       PTHREAD_INHERIT_SCHED; that way the -p option to set realtime
00938       priority will propagate down to new threads by default.
00939       This does mean that callers cannot set a different priority using
00940       PTHREAD_EXPLICIT_SCHED in the attr argument; instead they must set
00941       the priority afterwards with pthread_setschedparam(). */
00942    if ((errno = pthread_attr_setinheritsched(attr, PTHREAD_INHERIT_SCHED)))
00943       ast_log(LOG_WARNING, "pthread_attr_setinheritsched: %s\n", strerror(errno));
00944 #endif
00945 
00946    if (!stacksize)
00947       stacksize = AST_STACKSIZE;
00948 
00949    if ((errno = pthread_attr_setstacksize(attr, stacksize ? stacksize : AST_STACKSIZE)))
00950       ast_log(LOG_WARNING, "pthread_attr_setstacksize: %s\n", strerror(errno));
00951 
00952 #if !defined(LOW_MEMORY)
00953    if ((a = ast_malloc(sizeof(*a)))) {
00954       a->start_routine = start_routine;
00955       a->data = data;
00956       start_routine = dummy_start;
00957       asprintf(&a->name, "%-20s started at [%5d] %s %s()",
00958           start_fn, line, file, caller);
00959       data = a;
00960    }
00961 #endif /* !LOW_MEMORY */
00962 
00963    return pthread_create(thread, attr, start_routine, data); /* We're in ast_pthread_create, so it's okay */
00964 }
00965 
00966 int ast_wait_for_input(int fd, int ms)
00967 {
00968    struct pollfd pfd[1];
00969    memset(pfd, 0, sizeof(pfd));
00970    pfd[0].fd = fd;
00971    pfd[0].events = POLLIN|POLLPRI;
00972    return poll(pfd, 1, ms);
00973 }
00974 
00975 int ast_carefulwrite(int fd, char *s, int len, int timeoutms) 
00976 {
00977    /* Try to write string, but wait no more than ms milliseconds
00978       before timing out */
00979    int res = 0;
00980    struct pollfd fds[1];
00981    while (len) {
00982       res = write(fd, s, len);
00983       if ((res < 0) && (errno != EAGAIN)) {
00984          return -1;
00985       }
00986       if (res < 0)
00987          res = 0;
00988       len -= res;
00989       s += res;
00990       res = 0;
00991       if (len) {
00992          fds[0].fd = fd;
00993          fds[0].events = POLLOUT;
00994          /* Wait until writable again */
00995          res = poll(fds, 1, timeoutms);
00996          if (res < 1)
00997             return -1;
00998       }
00999    }
01000    return res;
01001 }
01002 
01003 char *ast_strip_quoted(char *s, const char *beg_quotes, const char *end_quotes)
01004 {
01005    char *e;
01006    char *q;
01007 
01008    s = ast_strip(s);
01009    if ((q = strchr(beg_quotes, *s)) && *q != '\0') {
01010       e = s + strlen(s) - 1;
01011       if (*e == *(end_quotes + (q - beg_quotes))) {
01012          s++;
01013          *e = '\0';
01014       }
01015    }
01016 
01017    return s;
01018 }
01019 
01020 char *ast_unescape_semicolon(char *s)
01021 {
01022    char *e;
01023    char *work = s;
01024 
01025    while ((e = strchr(work, ';'))) {
01026       if ((e > work) && (*(e-1) == '\\')) {
01027          memmove(e - 1, e, strlen(e) + 1);
01028          work = e;
01029       } else {
01030          work = e + 1;
01031       }
01032    }
01033 
01034    return s;
01035 }
01036 
01037 int ast_build_string_va(char **buffer, size_t *space, const char *fmt, va_list ap)
01038 {
01039    int result;
01040 
01041    if (!buffer || !*buffer || !space || !*space)
01042       return -1;
01043 
01044    result = vsnprintf(*buffer, *space, fmt, ap);
01045 
01046    if (result < 0)
01047       return -1;
01048    else if (result > *space)
01049       result = *space;
01050 
01051    *buffer += result;
01052    *space -= result;
01053    return 0;
01054 }
01055 
01056 int ast_build_string(char **buffer, size_t *space, const char *fmt, ...)
01057 {
01058    va_list ap;
01059    int result;
01060 
01061    va_start(ap, fmt);
01062    result = ast_build_string_va(buffer, space, fmt, ap);
01063    va_end(ap);
01064 
01065    return result;
01066 }
01067 
01068 int ast_true(const char *s)
01069 {
01070    if (ast_strlen_zero(s))
01071       return 0;
01072 
01073    /* Determine if this is a true value */
01074    if (!strcasecmp(s, "yes") ||
01075        !strcasecmp(s, "true") ||
01076        !strcasecmp(s, "y") ||
01077        !strcasecmp(s, "t") ||
01078        !strcasecmp(s, "1") ||
01079        !strcasecmp(s, "on"))
01080       return -1;
01081 
01082    return 0;
01083 }
01084 
01085 int ast_false(const char *s)
01086 {
01087    if (ast_strlen_zero(s))
01088       return 0;
01089 
01090    /* Determine if this is a false value */
01091    if (!strcasecmp(s, "no") ||
01092        !strcasecmp(s, "false") ||
01093        !strcasecmp(s, "n") ||
01094        !strcasecmp(s, "f") ||
01095        !strcasecmp(s, "0") ||
01096        !strcasecmp(s, "off"))
01097       return -1;
01098 
01099    return 0;
01100 }
01101 
01102 #define ONE_MILLION  1000000
01103 /*
01104  * put timeval in a valid range. usec is 0..999999
01105  * negative values are not allowed and truncated.
01106  */
01107 static struct timeval tvfix(struct timeval a)
01108 {
01109    if (a.tv_usec >= ONE_MILLION) {
01110       ast_log(LOG_WARNING, "warning too large timestamp %ld.%ld\n",
01111          a.tv_sec, (long int) a.tv_usec);
01112       a.tv_sec += a.tv_usec / ONE_MILLION;
01113       a.tv_usec %= ONE_MILLION;
01114    } else if (a.tv_usec < 0) {
01115       ast_log(LOG_WARNING, "warning negative timestamp %ld.%ld\n",
01116          a.tv_sec, (long int) a.tv_usec);
01117       a.tv_usec = 0;
01118    }
01119    return a;
01120 }
01121 
01122 struct timeval ast_tvadd(struct timeval a, struct timeval b)
01123 {
01124    /* consistency checks to guarantee usec in 0..999999 */
01125    a = tvfix(a);
01126    b = tvfix(b);
01127    a.tv_sec += b.tv_sec;
01128    a.tv_usec += b.tv_usec;
01129    if (a.tv_usec >= ONE_MILLION) {
01130       a.tv_sec++;
01131       a.tv_usec -= ONE_MILLION;
01132    }
01133    return a;
01134 }
01135 
01136 struct timeval ast_tvsub(struct timeval a, struct timeval b)
01137 {
01138    /* consistency checks to guarantee usec in 0..999999 */
01139    a = tvfix(a);
01140    b = tvfix(b);
01141    a.tv_sec -= b.tv_sec;
01142    a.tv_usec -= b.tv_usec;
01143    if (a.tv_usec < 0) {
01144       a.tv_sec-- ;
01145       a.tv_usec += ONE_MILLION;
01146    }
01147    return a;
01148 }
01149 #undef ONE_MILLION
01150 
01151 /*! \brief glibc puts a lock inside random(3), so that the results are thread-safe.
01152  * BSD libc (and others) do not. */
01153 #ifndef linux
01154 
01155 AST_MUTEX_DEFINE_STATIC(randomlock);
01156 
01157 long int ast_random(void)
01158 {
01159    long int res;
01160    ast_mutex_lock(&randomlock);
01161    res = random();
01162    ast_mutex_unlock(&randomlock);
01163    return res;
01164 }
01165 #endif
01166 
01167 char *ast_process_quotes_and_slashes(char *start, char find, char replace_with)
01168 {
01169    char *dataPut = start;
01170    int inEscape = 0;
01171    int inQuotes = 0;
01172 
01173    for (; *start; start++) {
01174       if (inEscape) {
01175          *dataPut++ = *start;       /* Always goes verbatim */
01176          inEscape = 0;
01177       } else {
01178          if (*start == '\\') {
01179             inEscape = 1;      /* Do not copy \ into the data */
01180          } else if (*start == '\'') {
01181             inQuotes = 1 - inQuotes;   /* Do not copy ' into the data */
01182          } else {
01183             /* Replace , with |, unless in quotes */
01184             *dataPut++ = inQuotes ? *start : ((*start == find) ? replace_with : *start);
01185          }
01186       }
01187    }
01188    if (start != dataPut)
01189       *dataPut = 0;
01190    return dataPut;
01191 }
01192 
01193 void ast_join(char *s, size_t len, char * const w[])
01194 {
01195    int x, ofs = 0;
01196    const char *src;
01197 
01198    /* Join words into a string */
01199    if (!s)
01200       return;
01201    for (x = 0; ofs < len && w[x]; x++) {
01202       if (x > 0)
01203          s[ofs++] = ' ';
01204       for (src = w[x]; *src && ofs < len; src++)
01205          s[ofs++] = *src;
01206    }
01207    if (ofs == len)
01208       ofs--;
01209    s[ofs] = '\0';
01210 }
01211 
01212 const char __ast_string_field_empty[] = "";
01213 
01214 static int add_string_pool(struct ast_string_field_mgr *mgr, size_t size)
01215 {
01216    struct ast_string_field_pool *pool;
01217 
01218    if (!(pool = ast_calloc(1, sizeof(*pool) + size)))
01219       return -1;
01220    
01221    pool->prev = mgr->pool;
01222    mgr->pool = pool;
01223    mgr->size = size;
01224    mgr->space = size;
01225    mgr->used = 0;
01226 
01227    return 0;
01228 }
01229 
01230 int __ast_string_field_init(struct ast_string_field_mgr *mgr, size_t size,
01231              ast_string_field *fields, int num_fields)
01232 {
01233    int index;
01234 
01235    if (add_string_pool(mgr, size))
01236       return -1;
01237 
01238    for (index = 0; index < num_fields; index++)
01239       fields[index] = __ast_string_field_empty;
01240 
01241    return 0;
01242 }
01243 
01244 ast_string_field __ast_string_field_alloc_space(struct ast_string_field_mgr *mgr, size_t needed,
01245                   ast_string_field *fields, int num_fields)
01246 {
01247    char *result = NULL;
01248 
01249    if (__builtin_expect(needed > mgr->space, 0)) {
01250       size_t new_size = mgr->size * 2;
01251 
01252       while (new_size < needed)
01253          new_size *= 2;
01254 
01255       if (add_string_pool(mgr, new_size))
01256          return NULL;
01257    }
01258 
01259    result = mgr->pool->base + mgr->used;
01260    mgr->used += needed;
01261    mgr->space -= needed;
01262    return result;
01263 }
01264 
01265 void __ast_string_field_index_build_va(struct ast_string_field_mgr *mgr,
01266                    ast_string_field *fields, int num_fields,
01267                    int index, const char *format, va_list ap1, va_list ap2)
01268 {
01269    size_t needed;
01270 
01271    needed = vsnprintf(mgr->pool->base + mgr->used, mgr->space, format, ap1) + 1;
01272 
01273    va_end(ap1);
01274 
01275    if (needed > mgr->space) {
01276       size_t new_size = mgr->size * 2;
01277 
01278       while (new_size < needed)
01279          new_size *= 2;
01280 
01281       if (add_string_pool(mgr, new_size))
01282          return;
01283 
01284       vsprintf(mgr->pool->base + mgr->used, format, ap2);
01285    }
01286 
01287    fields[index] = mgr->pool->base + mgr->used;
01288    mgr->used += needed;
01289    mgr->space -= needed;
01290 }
01291 
01292 void __ast_string_field_index_build(struct ast_string_field_mgr *mgr,
01293                 ast_string_field *fields, int num_fields,
01294                 int index, const char *format, ...)
01295 {
01296    va_list ap1, ap2;
01297 
01298    va_start(ap1, format);
01299    va_start(ap2, format);     /* va_copy does not exist on FreeBSD */
01300 
01301    __ast_string_field_index_build_va(mgr, fields, num_fields, index, format, ap1, ap2);
01302 
01303    va_end(ap1);
01304    va_end(ap2);
01305 }
01306 
01307 AST_MUTEX_DEFINE_STATIC(fetchadd_m); /* used for all fetc&add ops */
01308 
01309 int ast_atomic_fetchadd_int_slow(volatile int *p, int v)
01310 {
01311         int ret;
01312         ast_mutex_lock(&fetchadd_m);
01313         ret = *p;
01314         *p += v;
01315         ast_mutex_unlock(&fetchadd_m);
01316         return ret;
01317 }
01318 
01319 /*! \brief
01320  * get values from config variables.
01321  */
01322 int ast_get_time_t(const char *src, time_t *dst, time_t _default, int *consumed)
01323 {
01324    long t;
01325    int scanned;
01326 
01327    if (dst == NULL)
01328       return -1;
01329 
01330    *dst = _default;
01331 
01332    if (ast_strlen_zero(src))
01333       return -1;
01334 
01335    /* only integer at the moment, but one day we could accept more formats */
01336    if (sscanf(src, "%ld%n", &t, &scanned) == 1) {
01337       *dst = t;
01338       if (consumed)
01339          *consumed = scanned;
01340       return 0;
01341    } else
01342       return -1;
01343 }
01344 
01345 int ast_dynamic_str_thread_build_va(struct ast_dynamic_str **buf, size_t max_len,
01346    struct ast_threadstorage *ts, int append, const char *fmt, va_list ap)
01347 {
01348    int res;
01349    int offset = (append && (*buf)->len) ? strlen((*buf)->str) : 0;
01350 #if defined(DEBUG_THREADLOCALS)
01351    struct ast_dynamic_str *old_buf = *buf;
01352 #endif /* defined(DEBUG_THREADLOCALS) */
01353 
01354    res = vsnprintf((*buf)->str + offset, (*buf)->len - offset, fmt, ap);
01355 
01356    /* Check to see if there was not enough space in the string buffer to prepare
01357     * the string.  Also, if a maximum length is present, make sure the current
01358     * length is less than the maximum before increasing the size. */
01359    if ((res + offset + 1) > (*buf)->len && (max_len ? ((*buf)->len < max_len) : 1)) {
01360       /* Set the new size of the string buffer to be the size needed
01361        * to hold the resulting string (res) plus one byte for the
01362        * terminating '\0'.  If this size is greater than the max, set
01363        * the new length to be the maximum allowed. */
01364       if (max_len)
01365          (*buf)->len = ((res + offset + 1) < max_len) ? (res + offset + 1) : max_len;
01366       else
01367          (*buf)->len = res + offset + 1;
01368 
01369       if (!(*buf = ast_realloc(*buf, (*buf)->len + sizeof(*(*buf)))))
01370          return AST_DYNSTR_BUILD_FAILED;
01371 
01372       if (append)
01373          (*buf)->str[offset] = '\0';
01374 
01375       if (ts) {
01376          pthread_setspecific(ts->key, *buf);
01377 #if defined(DEBUG_THREADLOCALS)
01378          __ast_threadstorage_object_replace(old_buf, *buf, (*buf)->len + sizeof(*(*buf)));
01379 #endif /* defined(DEBUG_THREADLOCALS) */
01380       }
01381 
01382       /* va_end() and va_start() must be done before calling
01383        * vsnprintf() again. */
01384       return AST_DYNSTR_BUILD_RETRY;
01385    }
01386 
01387    return res;
01388 }
01389 
01390 void ast_enable_packet_fragmentation(int sock)
01391 {
01392 #if defined(HAVE_IP_MTU_DISCOVER)
01393    int val = IP_PMTUDISC_DONT;
01394    
01395    if (setsockopt(sock, IPPROTO_IP, IP_MTU_DISCOVER, &val, sizeof(val)))
01396       ast_log(LOG_WARNING, "Unable to disable PMTU discovery. Large UDP packets may fail to be delivered when sent from this socket.\n");
01397 #endif /* HAVE_IP_MTU_DISCOVER */
01398 }
01399 
01400 int ast_utils_init(void)
01401 {
01402    base64_init();
01403 #ifdef DEBUG_THREADS
01404 #if !defined(LOW_MEMORY)
01405    ast_cli_register_multiple(utils_cli, sizeof(utils_cli) / sizeof(utils_cli[0]));
01406 #endif
01407 #endif
01408    return 0;
01409 }
01410 
01411 #ifndef __AST_DEBUG_MALLOC
01412 int _ast_asprintf(char **ret, const char *file, int lineno, const char *func, const char *fmt, ...)
01413 {
01414    int res;
01415    va_list ap;
01416 
01417    va_start(ap, fmt);
01418    if ((res = vasprintf(ret, fmt, ap)) == -1) {
01419       MALLOC_FAILURE_MSG;
01420    }
01421    va_end(ap);
01422 
01423    return res;
01424 }
01425 #endif

Generated on Mon Nov 24 15:34:21 2008 for Asterisk - the Open Source PBX by  doxygen 1.4.7