Main Page | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

utils.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- A telephony toolkit for Linux.
00003  *
00004  * Utility functions
00005  *
00006  * Copyright (C) 2004, Digium
00007  *
00008  * This program is free software, distributed under the terms of
00009  * the GNU General Public License
00010  */
00011 
00012 #ifdef Linux   /* For strcasestr */
00013 #define __USE_GNU
00014 #endif
00015 #include <ctype.h>
00016 #include <string.h>
00017 #include <unistd.h>
00018 #include <stdlib.h>
00019 #include <errno.h>
00020 #include <sys/types.h>
00021 #include <sys/socket.h>
00022 #include <netinet/in.h>
00023 #include <arpa/inet.h>
00024 #include <asterisk/lock.h>
00025 #include <asterisk/utils.h>
00026 #include <asterisk/logger.h>
00027 
00028 static char base64[64];
00029 static char b2a[256];
00030 
00031 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined( __NetBSD__ ) || defined(__APPLE__)
00032 
00033 /* duh? ERANGE value copied from web... */
00034 #define ERANGE 34
00035 #undef gethostbyname
00036 
00037 AST_MUTEX_DEFINE_STATIC(__mutex);
00038 
00039 /* Recursive replacement for gethostbyname for BSD-based systems */
00040 static int gethostbyname_r (const char *name, struct hostent *ret, char *buf,
00041             size_t buflen, struct hostent **result, 
00042             int *h_errnop) 
00043 {
00044    int hsave;
00045    struct hostent *ph;
00046    ast_mutex_lock(&__mutex); /* begin critical area */
00047    hsave = h_errno;
00048 
00049    ph = gethostbyname(name);
00050    *h_errnop = h_errno; /* copy h_errno to *h_herrnop */
00051    if (ph == NULL) {
00052       *result = NULL;
00053    } else {
00054       char **p, **q;
00055       char *pbuf;
00056       int nbytes=0;
00057       int naddr=0, naliases=0;
00058       /* determine if we have enough space in buf */
00059 
00060       /* count how many addresses */
00061       for (p = ph->h_addr_list; *p != 0; p++) {
00062          nbytes += ph->h_length; /* addresses */
00063          nbytes += sizeof(*p); /* pointers */
00064          naddr++;
00065       }
00066       nbytes += sizeof(*p); /* one more for the terminating NULL */
00067 
00068       /* count how many aliases, and total length of strings */
00069       for (p = ph->h_aliases; *p != 0; p++) {
00070          nbytes += (strlen(*p)+1); /* aliases */
00071          nbytes += sizeof(*p);  /* pointers */
00072          naliases++;
00073       }
00074       nbytes += sizeof(*p); /* one more for the terminating NULL */
00075 
00076       /* here nbytes is the number of bytes required in buffer */
00077       /* as a terminator must be there, the minimum value is ph->h_length */
00078       if(nbytes > buflen) {
00079          *result = NULL;
00080          ast_mutex_unlock(&__mutex); /* end critical area */
00081          return ERANGE; /* not enough space in buf!! */
00082       }
00083 
00084       /* There is enough space. Now we need to do a deep copy! */
00085       /* Allocation in buffer:
00086          from [0] to [(naddr-1) * sizeof(*p)]:
00087          pointers to addresses
00088          at [naddr * sizeof(*p)]:
00089          NULL
00090          from [(naddr+1) * sizeof(*p)] to [(naddr+naliases) * sizeof(*p)] :
00091          pointers to aliases
00092          at [(naddr+naliases+1) * sizeof(*p)]:
00093          NULL
00094          then naddr addresses (fixed length), and naliases aliases (asciiz).
00095       */
00096 
00097       *ret = *ph;   /* copy whole structure (not its address!) */
00098 
00099       /* copy addresses */
00100       q = (char **)buf; /* pointer to pointers area (type: char **) */
00101       ret->h_addr_list = q; /* update pointer to address list */
00102       pbuf = buf + ((naddr+naliases+2)*sizeof(*p)); /* skip that area */
00103       for (p = ph->h_addr_list; *p != 0; p++) {
00104          memcpy(pbuf, *p, ph->h_length); /* copy address bytes */
00105          *q++ = pbuf; /* the pointer is the one inside buf... */
00106          pbuf += ph->h_length; /* advance pbuf */
00107       }
00108       *q++ = NULL; /* address list terminator */
00109 
00110       /* copy aliases */
00111       ret->h_aliases = q; /* update pointer to aliases list */
00112       for (p = ph->h_aliases; *p != 0; p++) {
00113          strcpy(pbuf, *p); /* copy alias strings */
00114          *q++ = pbuf; /* the pointer is the one inside buf... */
00115          pbuf += strlen(*p); /* advance pbuf */
00116          *pbuf++ = 0; /* string terminator */
00117       }
00118       *q++ = NULL; /* terminator */
00119 
00120       strcpy(pbuf, ph->h_name); /* copy alias strings */
00121       ret->h_name = pbuf;
00122       pbuf += strlen(ph->h_name); /* advance pbuf */
00123       *pbuf++ = 0; /* string terminator */
00124 
00125       *result = ret;  /* and let *result point to structure */
00126 
00127    }
00128    h_errno = hsave;  /* restore h_errno */
00129    ast_mutex_unlock(&__mutex); /* end critical area */
00130 
00131    return (*result == NULL); /* return 0 on success, non-zero on error */
00132 }
00133 
00134 
00135 #endif
00136 
00137 /* Recursive thread safe version of gethostbyname that replaces the 
00138    standard gethostbyname (which is not recursive)
00139 */
00140 struct hostent *ast_gethostbyname(const char *host, struct ast_hostent *hp)
00141 {
00142    int res;
00143    int herrno;
00144    const char *s;
00145    struct hostent *result = NULL;
00146    /* Although it is perfectly legitimate to lookup a pure integer, for
00147       the sake of the sanity of people who like to name their peers as
00148       integers, we break with tradition and refuse to look up a
00149       pure integer */
00150    s = host;
00151    while(s && *s) {
00152       if (!isdigit(*s))
00153          break;
00154       s++;
00155    }
00156    if (!s || !*s)
00157       return NULL;
00158    res = gethostbyname_r(host, &hp->hp, hp->buf, sizeof(hp->buf), &result, &herrno);
00159 
00160    if (res || !result || !hp->hp.h_addr_list || !hp->hp.h_addr_list[0])
00161       return NULL;
00162    return &hp->hp;
00163 }
00164 
00165 
00166 /* This is a regression test for recursive mutexes.
00167    test_for_thread_safety() will return 0 if recursive mutex locks are
00168    working properly, and non-zero if they are not working properly. */
00169 
00170 AST_MUTEX_DEFINE_STATIC(test_lock);
00171 AST_MUTEX_DEFINE_STATIC(test_lock2);
00172 static pthread_t test_thread; 
00173 static int lock_count = 0;
00174 static int test_errors = 0;
00175 
00176 static void *test_thread_body(void *data) 
00177 { 
00178    ast_mutex_lock(&test_lock);
00179    lock_count += 10;
00180    if (lock_count != 10) 
00181       test_errors++;
00182    ast_mutex_lock(&test_lock);
00183    lock_count += 10;
00184    if (lock_count != 20) 
00185       test_errors++;
00186    ast_mutex_lock(&test_lock2);
00187    ast_mutex_unlock(&test_lock);
00188    lock_count -= 10;
00189    if (lock_count != 10) 
00190       test_errors++;
00191    ast_mutex_unlock(&test_lock);
00192    lock_count -= 10;
00193    ast_mutex_unlock(&test_lock2);
00194    if (lock_count != 0) 
00195       test_errors++;
00196    return NULL;
00197 } 
00198 
00199 int test_for_thread_safety(void)
00200 { 
00201    ast_mutex_lock(&test_lock2);
00202    ast_mutex_lock(&test_lock);
00203    lock_count += 1;
00204    ast_mutex_lock(&test_lock);
00205    lock_count += 1;
00206    ast_pthread_create(&test_thread, NULL, test_thread_body, NULL); 
00207    usleep(100);
00208    if (lock_count != 2) 
00209       test_errors++;
00210    ast_mutex_unlock(&test_lock);
00211    lock_count -= 1;
00212    usleep(100); 
00213    if (lock_count != 1) 
00214       test_errors++;
00215    ast_mutex_unlock(&test_lock);
00216    lock_count -= 1;
00217    if (lock_count != 0) 
00218       test_errors++;
00219    ast_mutex_unlock(&test_lock2);
00220    usleep(100);
00221    if (lock_count != 0) 
00222       test_errors++;
00223    pthread_join(test_thread, NULL);
00224    return(test_errors);          /* return 0 on success. */
00225 }
00226 
00227 int ast_base64decode(unsigned char *dst, char *src, int max)
00228 {
00229    int cnt = 0;
00230    unsigned int byte = 0;
00231    unsigned int bits = 0;
00232    int incnt = 0;
00233 #if 0
00234    unsigned char *odst = dst;
00235 #endif
00236    while(*src && (cnt < max)) {
00237       /* Shift in 6 bits of input */
00238       byte <<= 6;
00239       byte |= (b2a[(int)(*src)]) & 0x3f;
00240       bits += 6;
00241 #if 0
00242       printf("Add: %c %s\n", *src, binary(b2a[(int)(*src)] & 0x3f, 6));
00243 #endif
00244       src++;
00245       incnt++;
00246       /* If we have at least 8 bits left over, take that character 
00247          off the top */
00248       if (bits >= 8)  {
00249          bits -= 8;
00250          *dst = (byte >> bits) & 0xff;
00251 #if 0
00252          printf("Remove: %02x %s\n", *dst, binary(*dst, 8));
00253 #endif
00254          dst++;
00255          cnt++;
00256       }
00257    }
00258 #if 0
00259    dump(odst, cnt);
00260 #endif
00261    /* Dont worry about left over bits, they're extra anyway */
00262    return cnt;
00263 }
00264 
00265 int ast_base64encode(char *dst, unsigned char *src, int srclen, int max)
00266 {
00267    int cnt = 0;
00268    unsigned int byte = 0;
00269    int bits = 0;
00270    int index;
00271    int cntin = 0;
00272 #if 0
00273    char *odst = dst;
00274    dump(src, srclen);
00275 #endif
00276    /* Reserve one bit for end */
00277    max--;
00278    while((cntin < srclen) && (cnt < max)) {
00279       byte <<= 8;
00280 #if 0
00281       printf("Add: %02x %s\n", *src, binary(*src, 8));
00282 #endif
00283       byte |= *(src++);
00284       bits += 8;
00285       cntin++;
00286       while((bits >= 6) && (cnt < max)) {
00287          bits -= 6;
00288          /* We want only the top */
00289          index = (byte >> bits) & 0x3f;
00290          *dst = base64[index];
00291 #if 0
00292          printf("Remove: %c %s\n", *dst, binary(index, 6));
00293 #endif
00294          dst++;
00295          cnt++;
00296       }
00297    }
00298    if (bits && (cnt < max)) {
00299       /* Add one last character for the remaining bits, 
00300          padding the rest with 0 */
00301       byte <<= (6 - bits);
00302       index = (byte) & 0x3f;
00303       *(dst++) = base64[index];
00304       cnt++;
00305    }
00306    *dst = '\0';
00307    return cnt;
00308 }
00309 
00310 static void base64_init(void)
00311 {
00312    int x;
00313    memset(b2a, -1, sizeof(b2a));
00314    /* Initialize base-64 Conversion table */
00315    for (x=0;x<26;x++) {
00316       /* A-Z */
00317       base64[x] = 'A' + x;
00318       b2a['A' + x] = x;
00319       /* a-z */
00320       base64[x + 26] = 'a' + x;
00321       b2a['a' + x] = x + 26;
00322       /* 0-9 */
00323       if (x < 10) {
00324          base64[x + 52] = '0' + x;
00325          b2a['0' + x] = x + 52;
00326       }
00327    }
00328    base64[62] = '+';
00329    base64[63] = '/';
00330    b2a[(int)'+'] = 62;
00331    b2a[(int)'/'] = 63;
00332 #if 0
00333    for (x=0;x<64;x++) {
00334       if (b2a[(int)base64[x]] != x) {
00335          fprintf(stderr, "!!! %d failed\n", x);
00336       } else
00337          fprintf(stderr, "--- %d passed\n", x);
00338    }
00339 #endif
00340 }
00341 
00342 /* Recursive thread safe replacement of inet_ntoa */
00343 const char *ast_inet_ntoa(char *buf, int bufsiz, struct in_addr ia)
00344 {
00345    return inet_ntop(AF_INET, &ia, buf, bufsiz);
00346 }
00347 
00348 int ast_utils_init(void)
00349 {
00350    base64_init();
00351    return 0;
00352 }
00353 
00354 
00355 #ifndef LINUX
00356 #undef pthread_create /* For ast_pthread_create function only */
00357 int ast_pthread_create(pthread_t *thread, pthread_attr_t *attr, void *(*start_routine)(void *), void *data)
00358 {
00359    pthread_attr_t lattr;
00360    if (!attr) {
00361       pthread_attr_init(&lattr);
00362       attr = &lattr;
00363    }
00364    errno = pthread_attr_setstacksize(attr, PTHREAD_ATTR_STACKSIZE);
00365    if (errno)
00366       ast_log(LOG_WARNING, "pthread_attr_setstacksize returned non-zero: %s\n", strerror(errno));
00367    return pthread_create(thread, attr, start_routine, data); /* We're in ast_pthread_create, so it's okay */
00368 }
00369 #endif /* ! LINUX */
00370 
00371 static char *upper(const char *orig, char *buf, int bufsize)
00372 {
00373    int i;
00374    memset(buf, 0, bufsize);
00375    for (i=0; i<bufsize - 1; i++) {
00376       buf[i] = toupper(orig[i]);
00377       if (orig[i] == '\0') {
00378          break;
00379       }
00380    }
00381    return buf;
00382 }
00383 
00384 /* Case-insensitive substring matching */
00385 #ifndef LINUX
00386 char *ast_strcasestr(const char *haystack, const char *needle)
00387 {
00388    char *u1, *u2;
00389    int u1len = strlen(haystack) + 1, u2len = strlen(needle) + 1;
00390 
00391    u1 = alloca(u1len);
00392    u2 = alloca(u2len);
00393    if (u1 && u2) {
00394       char *offset;
00395       if (u2len > u1len) {
00396          /* Needle bigger than haystack */
00397          return NULL;
00398       }
00399       offset = strstr(upper(haystack, u1, u1len), upper(needle, u2, u2len));
00400       if (offset) {
00401          /* Return the offset into the original string */
00402          return ((char *)((unsigned int)haystack + (unsigned int)(offset - u1)));
00403       } else {
00404          return NULL;
00405       }
00406    } else {
00407       ast_log(LOG_ERROR, "Out of memory\n");
00408       return NULL;
00409    }
00410 }
00411 #endif
00412 

Generated on Sat Nov 25 19:09:50 2006 for Asterisk by  doxygen 1.4.2