Newer
Older
* Asterisk -- An open source telephony toolkit.
* Copyright (C) 1999 - 2006, Digium, Inc.
* See http://www.asterisk.org for more information about
* the Asterisk project. Please do not directly contact
* any of the maintainers of this project for assistance;
* the project provides a web site, mailing lists and IRC
* channels for your use.
*
* This program is free software, distributed under the terms of
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree.
*/
*
* \brief Utility functions
*
* \note These are important for portability and security,
* so please use them in favour of other routines.
* Please consult the CODING GUIDELINES for more information.
/*** MODULEINFO
<support_level>core</support_level>
***/
Kevin P. Fleming
committed
#include "asterisk.h"
Tilghman Lesher
committed
#include <sys/stat.h>
#include <sys/syscall.h>
#if defined(__APPLE__)
#include <mach/mach.h>
#elif defined(__NetBSD__)
#include <lwp.h>
#elif defined(HAVE_SYS_THR_H)
#include <sys/thr.h>
#endif
#include "asterisk/network.h"
#define AST_API_MODULE /* ensure that inlinable API functions will be built in lock.h if required */
Kevin P. Fleming
committed
#include "asterisk/lock.h"
#include "asterisk/io.h"
#include "asterisk/md5.h"
Tilghman Lesher
committed
#include "asterisk/sha1.h"
#include "asterisk/cli.h"
#include "asterisk/linkedlists.h"
#include "asterisk/astobj2.h"
#define AST_API_MODULE /* ensure that inlinable API functions will be built in this module if required */
#include "asterisk/strings.h"
#define AST_API_MODULE /* ensure that inlinable API functions will be built in this module if required */
#include "asterisk/time.h"
Kevin P. Fleming
committed
#define AST_API_MODULE /* ensure that inlinable API functions will be built in this module if required */
#include "asterisk/utils.h"
#define AST_API_MODULE
#include "asterisk/threadstorage.h"
#define AST_API_MODULE
#include "asterisk/config.h"
#define AST_API_MODULE
#include "asterisk/alertpipe.h"
/* These arrays are global static variables because they are only modified
* once - in base64_init. The only purpose they have is to serve as a dictionary
* for encoding and decoding base64 and base64 URL, so there's no harm in
* accessing these arrays in multiple threads.
*/
Russell Bryant
committed
AST_THREADSTORAGE(inet_ntoa_buf);
Russell Bryant
committed
#if !defined(HAVE_GETHOSTBYNAME_R_5) && !defined(HAVE_GETHOSTBYNAME_R_6)
#define ERANGE 34 /*!< duh? ERANGE value copied from web... */
#undef gethostbyname
AST_MUTEX_DEFINE_STATIC(__mutex);
/*! \brief Reentrant replacement for gethostbyname for BSD-based systems.
routine is derived from code originally written and placed in the public
domain by Enzo Michelangeli <em@em.no-ip.com> */
Mark Spencer
committed
static int gethostbyname_r (const char *name, struct hostent *ret, char *buf,
size_t buflen, struct hostent **result,
int *h_errnop)
{
int hsave;
struct hostent *ph;
ast_mutex_lock(&__mutex); /* begin critical area */
hsave = h_errno;
ph = gethostbyname(name);
*h_errnop = h_errno; /* copy h_errno to *h_herrnop */
if (ph == NULL) {
*result = NULL;
} else {
char **p, **q;
char *pbuf;
int nbytes = 0;
int naddr = 0, naliases = 0;
/* determine if we have enough space in buf */
/* count how many addresses */
for (p = ph->h_addr_list; *p != 0; p++) {
nbytes += ph->h_length; /* addresses */
nbytes += sizeof(*p); /* pointers */
naddr++;
}
nbytes += sizeof(*p); /* one more for the terminating NULL */
/* count how many aliases, and total length of strings */
for (p = ph->h_aliases; *p != 0; p++) {
nbytes += (strlen(*p)+1); /* aliases */
nbytes += sizeof(*p); /* pointers */
naliases++;
}
nbytes += sizeof(*p); /* one more for the terminating NULL */
/* here nbytes is the number of bytes required in buffer */
/* as a terminator must be there, the minimum value is ph->h_length */
*result = NULL;
ast_mutex_unlock(&__mutex); /* end critical area */
return ERANGE; /* not enough space in buf!! */
}
/* There is enough space. Now we need to do a deep copy! */
/* Allocation in buffer:
from [0] to [(naddr-1) * sizeof(*p)]:
pointers to addresses
at [naddr * sizeof(*p)]:
NULL
from [(naddr+1) * sizeof(*p)] to [(naddr+naliases) * sizeof(*p)] :
pointers to aliases
at [(naddr+naliases+1) * sizeof(*p)]:
NULL
then naddr addresses (fixed length), and naliases aliases (asciiz).
*/
*ret = *ph; /* copy whole structure (not its address!) */
/* copy addresses */
q = (char **)buf; /* pointer to pointers area (type: char **) */
ret->h_addr_list = q; /* update pointer to address list */
pbuf = buf + ((naddr + naliases + 2) * sizeof(*p)); /* skip that area */
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
for (p = ph->h_addr_list; *p != 0; p++) {
memcpy(pbuf, *p, ph->h_length); /* copy address bytes */
*q++ = pbuf; /* the pointer is the one inside buf... */
pbuf += ph->h_length; /* advance pbuf */
}
*q++ = NULL; /* address list terminator */
/* copy aliases */
ret->h_aliases = q; /* update pointer to aliases list */
for (p = ph->h_aliases; *p != 0; p++) {
strcpy(pbuf, *p); /* copy alias strings */
*q++ = pbuf; /* the pointer is the one inside buf... */
pbuf += strlen(*p); /* advance pbuf */
*pbuf++ = 0; /* string terminator */
}
*q++ = NULL; /* terminator */
strcpy(pbuf, ph->h_name); /* copy alias strings */
ret->h_name = pbuf;
pbuf += strlen(ph->h_name); /* advance pbuf */
*pbuf++ = 0; /* string terminator */
*result = ret; /* and let *result point to structure */
}
h_errno = hsave; /* restore h_errno */
ast_mutex_unlock(&__mutex); /* end critical area */
return (*result == NULL); /* return 0 on success, non-zero on error */
}
#endif
/*! \brief Re-entrant (thread safe) version of gethostbyname that replaces the
standard gethostbyname (which is not thread safe)
struct hostent *ast_gethostbyname(const char *host, struct ast_hostent *hp)
{
#ifndef HAVE_GETHOSTBYNAME_R_5
struct hostent *result = NULL;
/* Although it is perfectly legitimate to lookup a pure integer, for
the sake of the sanity of people who like to name their peers as
integers, we break with tradition and refuse to look up a
pure integer */
s = host;
Joshua Colp
committed
while (s && *s) {
if (*s == '.')
dots++;
else if (!isdigit(*s))
if (!s || !*s) {
/* Forge a reply for IP's to avoid octal IP's being interpreted as octal */
if (dots != 3)
return NULL;
memset(hp, 0, sizeof(struct ast_hostent));
hp->hp.h_addr = hp->buf + sizeof(void *);
/* For AF_INET, this will always be 4 */
hp->hp.h_length = 4;
if (inet_pton(AF_INET, host, hp->hp.h_addr) > 0)
return &hp->hp;
result = gethostbyname_r(host, &hp->hp, hp->buf, sizeof(hp->buf), &herrno);
if (!result || !hp->hp.h_addr_list || !hp->hp.h_addr_list[0])
return NULL;
#else
res = gethostbyname_r(host, &hp->hp, hp->buf, sizeof(hp->buf), &result, &herrno);
if (res || !result || !hp->hp.h_addr_list || !hp->hp.h_addr_list[0])
#endif
return &hp->hp;
}
Mark Spencer
committed
void ast_md5_hash(char *output, const char *input)
Kevin P. Fleming
committed
struct MD5Context md5;
unsigned char digest[16];
char *ptr;
int x;
MD5Init(&md5);
MD5Update(&md5, (const unsigned char *) input, strlen(input));
Kevin P. Fleming
committed
MD5Final(digest, &md5);
ptr = output;
ptr += sprintf(ptr, "%02hhx", digest[x]);
void ast_sha1_hash(char *output, const char *input)
Tilghman Lesher
committed
{
struct SHA1Context sha;
char *ptr;
int x;
uint8_t Message_Digest[20];
SHA1Reset(&sha);
Tilghman Lesher
committed
SHA1Input(&sha, (const unsigned char *) input, strlen(input));
SHA1Result(&sha, Message_Digest);
ptr = output;
for (x = 0; x < 20; x++)
ptr += sprintf(ptr, "%02hhx", Message_Digest[x]);
Tilghman Lesher
committed
}
Joshua Colp
committed
/*! \brief Produce a 20 byte SHA1 hash of value. */
void ast_sha1_hash_uint(uint8_t *digest, const char *input)
{
struct SHA1Context sha;
SHA1Reset(&sha);
SHA1Input(&sha, (const unsigned char *) input, strlen(input));
SHA1Result(&sha, digest);
}
int ast_base64decode(unsigned char *dst, const char *src, int max)
{
int cnt = 0;
unsigned int byte = 0;
unsigned int bits = 0;
int incnt = 0;
while(*src && *src != '=' && (cnt < max)) {
/* Shift in 6 bits of input */
byte <<= 6;
byte |= (b2a[(int)(*src)]) & 0x3f;
bits += 6;
src++;
incnt++;
/* If we have at least 8 bits left over, take that character
off the top */
if (bits >= 8) {
bits -= 8;
*dst = (byte >> bits) & 0xff;
dst++;
cnt++;
}
}
/* Don't worry about left over bits, they're extra anyway */
/*! \brief Decode BASE64 encoded text and return the string */
char *ast_base64decode_string(const char *src)
{
size_t encoded_len;
size_t decoded_len;
int padding = 0;
unsigned char *decoded_string;
if (ast_strlen_zero(src)) {
return NULL;
}
encoded_len = strlen(src);
if (encoded_len > 2 && src[encoded_len - 1] == '=') {
padding++;
if (src[encoded_len - 2] == '=') {
padding++;
}
}
decoded_len = (encoded_len / 4 * 3) - padding;
decoded_string = ast_malloc(decoded_len + 1);
if (!decoded_string) {
return NULL;
}
ast_base64decode(decoded_string, src, decoded_len);
decoded_string[decoded_len] = '\0';
return (char *)decoded_string;
}
int ast_base64encode_full(char *dst, const unsigned char *src, int srclen, int max, int linebreaks)
unsigned int byte = 0;
int bits = 0;
int cntin = 0;
/* Reserve space for null byte at end of string */
byte <<= 8;
byte |= *(src++);
bits += 8;
cntin++;
if ((bits == 24) && (cnt + 4 <= max)) {
*dst++ = base64[(byte >> 18) & 0x3f];
*dst++ = base64[(byte >> 12) & 0x3f];
*dst++ = base64[(byte >> 6) & 0x3f];
*dst++ = base64[byte & 0x3f];
cnt += 4;
col += 4;
bits = 0;
byte = 0;
}
if (linebreaks && (cnt < max) && (col == 64)) {
*dst++ = '\n';
if (bits && (cnt + 4 <= max)) {
/* Add one last character for the remaining bits,
byte <<= 24 - bits;
*dst++ = base64[(byte >> 18) & 0x3f];
*dst++ = base64[(byte >> 12) & 0x3f];
if (bits == 16)
*dst++ = base64[(byte >> 6) & 0x3f];
else
*dst++ = '=';
*dst++ = '=';
cnt += 4;
}
if (linebreaks && (cnt < max)) {
*dst++ = '\n';
cnt++;
}
*dst = '\0';
return cnt;
}
int ast_base64encode(char *dst, const unsigned char *src, int srclen, int max)
{
return ast_base64encode_full(dst, src, srclen, max, 0);
}
/*! \brief Encode to BASE64 and return encoded string */
char *ast_base64encode_string(const char *src)
{
size_t encoded_len;
char *encoded_string;
if (ast_strlen_zero(src)) {
return NULL;
}
encoded_len = ((strlen(src) * 4 / 3 + 3) & ~3) + 1;
encoded_string = ast_calloc(1, encoded_len);
ast_base64encode(encoded_string, (const unsigned char *)src, strlen(src), encoded_len);
return encoded_string;
}
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
int ast_base64url_decode(unsigned char *dst, const char *src, int max)
{
int cnt = 0;
unsigned int byte = 0;
unsigned int bits = 0;
while (*src && (cnt < max)) {
byte <<= 6;
byte |= (b2a_url[(int)(*src)]) & 0x3f;
bits += 6;
src++;
if (bits >= 8) {
bits -= 8;
*dst = (byte >> bits) & 0xff;
dst++;
cnt++;
}
}
return cnt;
}
char *ast_base64url_decode_string(const char *src)
{
size_t decoded_len;
unsigned char *decoded_string;
if (ast_strlen_zero(src)) {
return NULL;
}
decoded_len = strlen(src) * 3 / 4;
decoded_string = ast_malloc(decoded_len + 1);
if (!decoded_string) {
return NULL;
}
ast_base64url_decode(decoded_string, src, decoded_len);
decoded_string[decoded_len] = '\0';
return (char *)decoded_string;
}
int ast_base64url_encode_full(char *dst, const unsigned char *src, int srclen, int max, int linebreaks)
{
int cnt = 0;
int col = 0;
unsigned int byte = 0;
int bits = 0;
int cntin = 0;
max--;
while ((cntin < srclen) && (cnt < max)) {
byte <<= 8;
byte |= *(src++);
bits += 8;
cntin++;
if ((bits == 24) && (cnt + 4 <= max)) {
*dst++ = base64url[(byte >> 18) & 0x3f];
*dst++ = base64url[(byte >> 12) & 0x3f];
*dst++ = base64url[(byte >> 6) & 0x3f];
*dst++ = base64url[(byte) & 0x3f];
cnt += 4;
col += 4;
bits = 0;
byte = 0;
}
if (linebreaks && (cnt < max) && (col == 64)) {
*dst++ = '\n';
cnt++;
col = 0;
}
}
if (bits && (cnt + 4 <= max)) {
byte <<= 24 - bits;
*dst++ = base64url[(byte >> 18) & 0x3f];
*dst++ = base64url[(byte >> 12) & 0x3f];
if (bits == 16) {
*dst++ = base64url[(byte >> 6) & 0x3f];
}
cnt += 4;
}
if (linebreaks && (cnt < max)) {
*dst++ = '\n';
cnt++;
}
*dst = '\0';
return cnt;
}
int ast_base64url_encode(char *dst, const unsigned char *src, int srclen, int max)
{
return ast_base64url_encode_full(dst, src, srclen, max, 0);
}
char *ast_base64url_encode_string(const char *src)
{
size_t encoded_len;
char *encoded_string;
if (ast_strlen_zero(src)) {
return NULL;
}
encoded_len = ((strlen(src) * 4 / 3 + 3) & ~3) + 1;
encoded_string = ast_malloc(encoded_len);
ast_base64url_encode(encoded_string, (const unsigned char *)src, strlen(src), encoded_len);
return encoded_string;
}
static void base64_init(void)
{
int x;
memset(b2a, -1, sizeof(b2a));
memset(b2a_url, -1, sizeof(b2a_url));
/* 0-9 */
if (x < 10) {
base64[x + 52] = '0' + x;
}
}
base64[62] = '+';
base64[63] = '/';
base64url[62] = '-';
base64url[63] = '_';
b2a_url[(int)'-'] = 62;
b2a_url[(int)'_'] = 63;
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
#define BASELINELEN 72 /*!< Line length for Base 64 encoded messages */
#define BASEMAXINLINE 256 /*!< Buffer size for Base 64 attachment encoding */
/*! \brief Structure used for base64 encoding */
struct baseio {
int iocp;
int iolen;
int linelength;
int ateof;
unsigned char iobuf[BASEMAXINLINE];
};
/*!
* \brief utility used by inchar(), for base_encode()
*/
static int inbuf(struct baseio *bio, FILE *fi)
{
int l;
if (bio->ateof) {
return 0;
}
if ((l = fread(bio->iobuf, 1, BASEMAXINLINE, fi)) != BASEMAXINLINE) {
bio->ateof = 1;
if (l == 0) {
/* Assume EOF */
return 0;
}
}
bio->iolen = l;
bio->iocp = 0;
return 1;
}
/*!
* \brief utility used by base_encode()
*/
static int inchar(struct baseio *bio, FILE *fi)
{
if (bio->iocp >= bio->iolen) {
if (!inbuf(bio, fi)) {
return EOF;
}
}
return bio->iobuf[bio->iocp++];
}
/*!
* \brief utility used by base_encode()
*/
static int ochar(struct baseio *bio, int c, FILE *so, const char *endl)
{
if (bio->linelength >= BASELINELEN) {
if (fputs(endl, so) == EOF) {
return -1;
}
bio->linelength = 0;
}
if (putc(((unsigned char) c), so) == EOF) {
return -1;
}
bio->linelength++;
return 1;
}
int ast_base64_encode_file(FILE *inputfile, FILE *outputfile, const char *endl)
{
static const unsigned char dtable[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0',
'1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
int i, hiteof = 0;
struct baseio bio;
memset(&bio, 0, sizeof(bio));
bio.iocp = BASEMAXINLINE;
while (!hiteof){
unsigned char igroup[3], ogroup[4];
int c, n;
memset(igroup, 0, sizeof(igroup));
for (n = 0; n < 3; n++) {
if ((c = inchar(&bio, inputfile)) == EOF) {
hiteof = 1;
break;
}
igroup[n] = (unsigned char) c;
}
if (n > 0) {
ogroup[0]= dtable[igroup[0] >> 2];
ogroup[1]= dtable[((igroup[0] & 3) << 4) | (igroup[1] >> 4)];
ogroup[2]= dtable[((igroup[1] & 0xF) << 2) | (igroup[2] >> 6)];
ogroup[3]= dtable[igroup[2] & 0x3F];
if (n < 3) {
ogroup[3] = '=';
if (n < 2) {
ogroup[2] = '=';
}
}
for (i = 0; i < 4; i++) {
ochar(&bio, ogroup[i], outputfile, endl);
}
}
}
if (fputs(endl, outputfile) == EOF) {
return 0;
}
return 1;
}
int ast_base64_encode_file_path(const char *filename, FILE *outputfile, const char *endl)
{
FILE *fi;
int res;
if (!(fi = fopen(filename, "rb"))) {
ast_log(AST_LOG_WARNING, "Failed to open file: %s: %s\n", filename, strerror(errno));
return -1;
}
res = ast_base64_encode_file(fi, outputfile, endl);
fclose(fi);
return res;
}
const struct ast_flags ast_uri_http = {AST_URI_UNRESERVED};
const struct ast_flags ast_uri_http_legacy = {AST_URI_LEGACY_SPACE | AST_URI_UNRESERVED};
const struct ast_flags ast_uri_sip_user = {AST_URI_UNRESERVED | AST_URI_SIP_USER_UNRESERVED};
char *ast_uri_encode(const char *string, char *outbuf, int buflen, struct ast_flags spec)
const char *ptr = string; /* Start with the string */
const char *mark = "-_.!~*'()"; /* no encode set, RFC 2396 section 2.3, RFC 3261 sec 25 */
const char *user_unreserved = "&=+$,;?/"; /* user-unreserved set, RFC 3261 sec 25 */
while (*ptr && out - outbuf < buflen - 1) {
if (ast_test_flag(&spec, AST_URI_LEGACY_SPACE) && *ptr == ' ') {
/* for legacy encoding, encode spaces as '+' */
*out = '+';
out++;
} else if (!(ast_test_flag(&spec, AST_URI_MARK)
&& strchr(mark, *ptr))
&& !(ast_test_flag(&spec, AST_URI_ALPHANUM)
&& ((*ptr >= '0' && *ptr <= '9')
|| (*ptr >= 'A' && *ptr <= 'Z')
|| (*ptr >= 'a' && *ptr <= 'z')))
&& !(ast_test_flag(&spec, AST_URI_SIP_USER_UNRESERVED)
&& strchr(user_unreserved, *ptr))) {
if (out - outbuf >= buflen - 3) {
break;
out += sprintf(out, "%%%02hhX", (unsigned char) *ptr);
*out = *ptr; /* Continue copying the string */
out++;
return outbuf;
}
void ast_uri_decode(char *s, struct ast_flags spec)
{
char *o;
unsigned int tmp;
for (o = s; *s; s++, o++) {
if (ast_test_flag(&spec, AST_URI_LEGACY_SPACE) && *s == '+') {
/* legacy mode, decode '+' as space */
*o = ' ';
} else if (*s == '%' && s[1] != '\0' && s[2] != '\0' && sscanf(s + 1, "%2x", &tmp) == 1) {
/* have '%', two chars and correct parsing */
*o = tmp;
s += 2; /* Will be incremented once more when we break out */
} else /* all other cases, just copy */
*o = *s;
}
*o = '\0';
}
char *ast_escape_quoted(const char *string, char *outbuf, int buflen)
{
const char *ptr = string;
char *out = outbuf;
char *allow = "\t\v !"; /* allow LWS (minus \r and \n) and "!" */
while (*ptr && out - outbuf < buflen - 1) {
if (!(strchr(allow, *ptr))
&& !(*ptr >= '#' && *ptr <= '[') /* %x23 - %x5b */
&& !(*ptr >= ']' && *ptr <= '~') /* %x5d - %x7e */
Matthew Nicholson
committed
&& !((unsigned char) *ptr > 0x7f)) { /* UTF8-nonascii */
if (out - outbuf >= buflen - 2) {
break;
}
out += sprintf(out, "\\%c", (unsigned char) *ptr);
} else {
*out = *ptr;
out++;
}
ptr++;
}
if (buflen) {
*out = '\0';
}
return outbuf;
}
George Joseph
committed
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
char *ast_escape_semicolons(const char *string, char *outbuf, int buflen)
{
const char *ptr = string;
char *out = outbuf;
if (string == NULL || outbuf == NULL) {
ast_assert(string != NULL && outbuf != NULL);
return NULL;
}
while (*ptr && out - outbuf < buflen - 1) {
if (*ptr == ';') {
if (out - outbuf >= buflen - 2) {
break;
}
strcpy(out, "\\;");
out += 2;
} else {
*out = *ptr;
out++;
}
ptr++;
}
if (buflen) {
*out = '\0';
}
return outbuf;
}
void ast_unescape_quoted(char *quote_str)
{
int esc_pos;
int unesc_pos;
int quote_str_len = strlen(quote_str);
for (esc_pos = 0, unesc_pos = 0;
esc_pos < quote_str_len;
esc_pos++, unesc_pos++) {
if (quote_str[esc_pos] == '\\') {
/* at least one more char and current is \\ */
esc_pos++;
if (esc_pos >= quote_str_len) {
break;
}
}
quote_str[unesc_pos] = quote_str[esc_pos];
}
quote_str[unesc_pos] = '\0';
}
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
int ast_xml_escape(const char *string, char * const outbuf, const size_t buflen)
{
char *dst = outbuf;
char *end = outbuf + buflen - 1; /* save one for the null terminator */
/* Handle the case for the empty output buffer */
if (buflen == 0) {
return -1;
}
/* Escaping rules from http://www.w3.org/TR/REC-xml/#syntax */
/* This also prevents partial entities at the end of a string */
while (*string && dst < end) {
const char *entity = NULL;
int len = 0;
switch (*string) {
case '<':
entity = "<";
len = 4;
break;
case '&':
entity = "&";
len = 5;
break;
case '>':
/* necessary if ]]> is in the string; easier to escape them all */
entity = ">";
len = 4;
break;
case '\'':
/* necessary in single-quoted strings; easier to escape them all */
entity = "'";
len = 6;
break;
case '"':
/* necessary in double-quoted strings; easier to escape them all */
entity = """;
len = 6;
break;
default:
*dst++ = *string++;
break;
}
if (entity) {
ast_assert(len == strlen(entity));
if (end - dst < len) {
/* no room for the entity; stop */
break;
}
/* just checked for length; strcpy is fine */
strcpy(dst, entity);
dst += len;
++string;
}
}
/* Write null terminator */
*dst = '\0';
/* If any chars are left in string, return failure */
return *string == '\0' ? 0 : -1;
}
/*! \brief ast_inet_ntoa: Recursive thread safe replacement of inet_ntoa */
Russell Bryant
committed
const char *ast_inet_ntoa(struct in_addr ia)
Mark Spencer
committed
{
Russell Bryant
committed
char *buf;
if (!(buf = ast_threadstorage_get(&inet_ntoa_buf, INET_ADDRSTRLEN)))
return "";
Russell Bryant
committed
return inet_ntop(AF_INET, &ia, buf, INET_ADDRSTRLEN);
Mark Spencer
committed
}
Joshua Colp
committed
#ifndef __linux__
#undef pthread_create /* For ast_pthread_create function only */
Kevin P. Fleming
committed
#endif /* !__linux__ */
/*! \brief A reasonable maximum number of locks a thread would be holding ... */
/* Allow direct use of pthread_mutex_t and friends */
#undef pthread_mutex_t
#undef pthread_mutex_lock
#undef pthread_mutex_unlock
#undef pthread_mutex_init
#undef pthread_mutex_destroy
/*!
* \brief Keep track of which locks a thread holds
*
* There is an instance of this struct for every active thread
*/
struct thr_lock_info {
/*! The thread's ID */
pthread_t thread_id;
/*! The thread name which includes where the thread was started */
const char *thread_name;
/*! This is the actual container of info for what locks this thread holds */
struct {
const char *file;
const char *func;
const char *lock_name;
void *lock_addr;
int times_locked;
/*! This thread is waiting on this lock */
/*! A condition has suspended this lock */
int suspended:1;
#ifdef HAVE_BKTR
struct ast_bt *backtrace;
#endif
} locks[AST_MAX_LOCKS];
/*! This is the number of locks currently held by this thread.
* The index (num_locks - 1) has the info on the last one in the
* locks member */
unsigned int num_locks;
/*! The LWP id (which GDB prints) */
int lwp;
/*! Protects the contents of the locks member
* Intentionally not ast_mutex_t */
pthread_mutex_t lock;
AST_LIST_ENTRY(thr_lock_info) entry;
};
/*!
* \brief Locked when accessing the lock_infos list
*/
AST_MUTEX_DEFINE_STATIC(lock_infos_lock);
/*!