Asterisk - The Open Source Telephony Project GIT-master-773870a
Loading...
Searching...
No Matches
utils.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 1999 - 2006, Digium, Inc.
5 *
6 * See http://www.asterisk.org for more information about
7 * the Asterisk project. Please do not directly contact
8 * any of the maintainers of this project for assistance;
9 * the project provides a web site, mailing lists and IRC
10 * channels for your use.
11 *
12 * This program is free software, distributed under the terms of
13 * the GNU General Public License Version 2. See the LICENSE file
14 * at the top of the source tree.
15 */
16
17/*! \file
18 *
19 * \brief Utility functions
20 *
21 * \note These are important for portability and security,
22 * so please use them in favour of other routines.
23 * Please consult the CODING GUIDELINES for more information.
24 */
25
26/*** MODULEINFO
27 <support_level>core</support_level>
28 ***/
29
30#include "asterisk.h"
31
32#include <ctype.h>
33#include <fcntl.h>
34#include <sys/stat.h>
35#include <sys/syscall.h>
36#include <unistd.h>
37#if defined(__APPLE__)
38#include <mach/mach.h>
39#elif defined(__FreeBSD__)
40#include <sys/thr.h>
41#elif defined(__NetBSD__)
42#include <lwp.h>
43#endif
44
45#include "asterisk/network.h"
47
48#define AST_API_MODULE /* ensure that inlinable API functions will be built in lock.h if required */
49#include "asterisk/lock.h"
50#include "asterisk/io.h"
51#include "asterisk/md5.h"
52#include "asterisk/sha1.h"
53#include "asterisk/cli.h"
55#include "asterisk/astobj2.h"
56
57#define AST_API_MODULE /* ensure that inlinable API functions will be built in this module if required */
58#include "asterisk/strings.h"
59
60#define AST_API_MODULE /* ensure that inlinable API functions will be built in this module if required */
61#include "asterisk/time.h"
62
63#define AST_API_MODULE /* ensure that inlinable API functions will be built in this module if required */
64#include "asterisk/utils.h"
65
66#define AST_API_MODULE
68
69#define AST_API_MODULE
70#include "asterisk/config.h"
71
72#define AST_API_MODULE
73#include "asterisk/alertpipe.h"
74
75/* These arrays are global static variables because they are only modified
76 * once - in base64_init. The only purpose they have is to serve as a dictionary
77 * for encoding and decoding base64 and base64 URL, so there's no harm in
78 * accessing these arrays in multiple threads.
79 */
80static char base64[64];
81static char base64url[64];
82static char b2a[256];
83static char b2a_url[256];
84
85AST_THREADSTORAGE(inet_ntoa_buf);
86
87#if !defined(HAVE_GETHOSTBYNAME_R_5) && !defined(HAVE_GETHOSTBYNAME_R_6)
88
89#define ERANGE 34 /*!< duh? ERANGE value copied from web... */
90#undef gethostbyname
91
93
94/*! \brief Reentrant replacement for gethostbyname for BSD-based systems.
95\note This
96routine is derived from code originally written and placed in the public
97domain by Enzo Michelangeli <em@em.no-ip.com> */
98
99static int gethostbyname_r (const char *name, struct hostent *ret, char *buf,
100 size_t buflen, struct hostent **result,
101 int *h_errnop)
102{
103 int hsave;
104 struct hostent *ph;
105 ast_mutex_lock(&__mutex); /* begin critical area */
106 hsave = h_errno;
107
108 ph = gethostbyname(name);
109 *h_errnop = h_errno; /* copy h_errno to *h_herrnop */
110 if (ph == NULL) {
111 *result = NULL;
112 } else {
113 char **p, **q;
114 char *pbuf;
115 int nbytes = 0;
116 int naddr = 0, naliases = 0;
117 /* determine if we have enough space in buf */
118
119 /* count how many addresses */
120 for (p = ph->h_addr_list; *p != 0; p++) {
121 nbytes += ph->h_length; /* addresses */
122 nbytes += sizeof(*p); /* pointers */
123 naddr++;
124 }
125 nbytes += sizeof(*p); /* one more for the terminating NULL */
126
127 /* count how many aliases, and total length of strings */
128 for (p = ph->h_aliases; *p != 0; p++) {
129 nbytes += (strlen(*p)+1); /* aliases */
130 nbytes += sizeof(*p); /* pointers */
131 naliases++;
132 }
133 nbytes += sizeof(*p); /* one more for the terminating NULL */
134
135 /* here nbytes is the number of bytes required in buffer */
136 /* as a terminator must be there, the minimum value is ph->h_length */
137 if (nbytes > buflen) {
138 *result = NULL;
139 ast_mutex_unlock(&__mutex); /* end critical area */
140 return ERANGE; /* not enough space in buf!! */
141 }
142
143 /* There is enough space. Now we need to do a deep copy! */
144 /* Allocation in buffer:
145 from [0] to [(naddr-1) * sizeof(*p)]:
146 pointers to addresses
147 at [naddr * sizeof(*p)]:
148 NULL
149 from [(naddr+1) * sizeof(*p)] to [(naddr+naliases) * sizeof(*p)] :
150 pointers to aliases
151 at [(naddr+naliases+1) * sizeof(*p)]:
152 NULL
153 then naddr addresses (fixed length), and naliases aliases (asciiz).
154 */
155
156 *ret = *ph; /* copy whole structure (not its address!) */
157
158 /* copy addresses */
159 q = (char **)buf; /* pointer to pointers area (type: char **) */
160 ret->h_addr_list = q; /* update pointer to address list */
161 pbuf = buf + ((naddr + naliases + 2) * sizeof(*p)); /* skip that area */
162 for (p = ph->h_addr_list; *p != 0; p++) {
163 memcpy(pbuf, *p, ph->h_length); /* copy address bytes */
164 *q++ = pbuf; /* the pointer is the one inside buf... */
165 pbuf += ph->h_length; /* advance pbuf */
166 }
167 *q++ = NULL; /* address list terminator */
168
169 /* copy aliases */
170 ret->h_aliases = q; /* update pointer to aliases list */
171 for (p = ph->h_aliases; *p != 0; p++) {
172 strcpy(pbuf, *p); /* copy alias strings */
173 *q++ = pbuf; /* the pointer is the one inside buf... */
174 pbuf += strlen(*p); /* advance pbuf */
175 *pbuf++ = 0; /* string terminator */
176 }
177 *q++ = NULL; /* terminator */
178
179 strcpy(pbuf, ph->h_name); /* copy alias strings */
180 ret->h_name = pbuf;
181 pbuf += strlen(ph->h_name); /* advance pbuf */
182 *pbuf++ = 0; /* string terminator */
183
184 *result = ret; /* and let *result point to structure */
185
186 }
187 h_errno = hsave; /* restore h_errno */
188 ast_mutex_unlock(&__mutex); /* end critical area */
189
190 return (*result == NULL); /* return 0 on success, non-zero on error */
191}
192
193
194#endif
195
196/*! \brief Re-entrant (thread safe) version of gethostbyname that replaces the
197 standard gethostbyname (which is not thread safe)
198*/
199struct hostent *ast_gethostbyname(const char *host, struct ast_hostent *hp)
200{
201#ifndef HAVE_GETHOSTBYNAME_R_5
202 int res;
203#endif
204 int herrno;
205 int dots = 0;
206 const char *s;
207 struct hostent *result = NULL;
208 /* Although it is perfectly legitimate to lookup a pure integer, for
209 the sake of the sanity of people who like to name their peers as
210 integers, we break with tradition and refuse to look up a
211 pure integer */
212 s = host;
213 while (s && *s) {
214 if (*s == '.')
215 dots++;
216 else if (!isdigit(*s))
217 break;
218 s++;
219 }
220 if (!s || !*s) {
221 /* Forge a reply for IP's to avoid octal IP's being interpreted as octal */
222 if (dots != 3)
223 return NULL;
224 memset(hp, 0, sizeof(struct ast_hostent));
225 hp->hp.h_addrtype = AF_INET;
226 hp->hp.h_addr_list = (void *) hp->buf;
227 hp->hp.h_addr = hp->buf + sizeof(void *);
228 /* For AF_INET, this will always be 4 */
229 hp->hp.h_length = 4;
230 if (inet_pton(AF_INET, host, hp->hp.h_addr) > 0)
231 return &hp->hp;
232 return NULL;
233
234 }
235#ifdef HAVE_GETHOSTBYNAME_R_5
236 result = gethostbyname_r(host, &hp->hp, hp->buf, sizeof(hp->buf), &herrno);
237
238 if (!result || !hp->hp.h_addr_list || !hp->hp.h_addr_list[0])
239 return NULL;
240#else
241 res = gethostbyname_r(host, &hp->hp, hp->buf, sizeof(hp->buf), &result, &herrno);
242
243 if (res || !result || !hp->hp.h_addr_list || !hp->hp.h_addr_list[0])
244 return NULL;
245#endif
246 return &hp->hp;
247}
248
249/*! \brief Produce 32 char MD5 hash of value. */
250void ast_md5_hash(char *output, const char *input)
251{
252 struct MD5Context md5;
253 unsigned char digest[16];
254 char *ptr;
255 int x;
256
257 MD5Init(&md5);
258 MD5Update(&md5, (const unsigned char *) input, strlen(input));
259 MD5Final(digest, &md5);
260 ptr = output;
261 for (x = 0; x < 16; x++)
262 ptr += sprintf(ptr, "%02hhx", digest[x]);
263}
264
265/*! \brief Produce 40 char SHA1 hash of value. */
266void ast_sha1_hash(char *output, const char *input)
267{
268 struct SHA1Context sha;
269 char *ptr;
270 int x;
271 uint8_t Message_Digest[20];
272
273 SHA1Reset(&sha);
274
275 SHA1Input(&sha, (const unsigned char *) input, strlen(input));
276
277 SHA1Result(&sha, Message_Digest);
278 ptr = output;
279 for (x = 0; x < 20; x++)
280 ptr += sprintf(ptr, "%02hhx", Message_Digest[x]);
281}
282
283/*! \brief Produce a 20 byte SHA1 hash of value. */
284void ast_sha1_hash_uint(uint8_t *digest, const char *input)
285{
286 struct SHA1Context sha;
287
288 SHA1Reset(&sha);
289
290 SHA1Input(&sha, (const unsigned char *) input, strlen(input));
291
292 SHA1Result(&sha, digest);
293}
294
295/*! \brief decode BASE64 encoded text */
296int ast_base64decode(unsigned char *dst, const char *src, int max)
297{
298 int cnt = 0;
299 unsigned int byte = 0;
300 unsigned int bits = 0;
301 while(*src && *src != '=' && (cnt < max)) {
302 /* Shift in 6 bits of input */
303 byte <<= 6;
304 byte |= (b2a[(int)(*src)]) & 0x3f;
305 bits += 6;
306 src++;
307 /* If we have at least 8 bits left over, take that character
308 off the top */
309 if (bits >= 8) {
310 bits -= 8;
311 *dst = (byte >> bits) & 0xff;
312 dst++;
313 cnt++;
314 }
315 }
316 /* Don't worry about left over bits, they're extra anyway */
317 return cnt;
318}
319
320/*! \brief Decode BASE64 encoded text and return the string */
321char *ast_base64decode_string(const char *src)
322{
323 size_t encoded_len;
324 size_t decoded_len;
325 int padding = 0;
326 unsigned char *decoded_string;
327
328 if (ast_strlen_zero(src)) {
329 return NULL;
330 }
331
332 encoded_len = strlen(src);
333 if (encoded_len > 2 && src[encoded_len - 1] == '=') {
334 padding++;
335 if (src[encoded_len - 2] == '=') {
336 padding++;
337 }
338 }
339
340 decoded_len = (encoded_len / 4 * 3) - padding;
341 decoded_string = ast_malloc(decoded_len + 1);
342 if (!decoded_string) {
343 return NULL;
344 }
345
346 ast_base64decode(decoded_string, src, decoded_len);
347 decoded_string[decoded_len] = '\0';
348
349 return (char *)decoded_string;
350}
351
352/*! \brief encode text to BASE64 coding */
353int ast_base64encode_full(char *dst, const unsigned char *src, int srclen, int max, int linebreaks)
354{
355 int cnt = 0;
356 int col = 0;
357 unsigned int byte = 0;
358 int bits = 0;
359 int cntin = 0;
360 /* Reserve space for null byte at end of string */
361 max--;
362 while ((cntin < srclen) && (cnt < max)) {
363 byte <<= 8;
364 byte |= *(src++);
365 bits += 8;
366 cntin++;
367 if ((bits == 24) && (cnt + 4 <= max)) {
368 *dst++ = base64[(byte >> 18) & 0x3f];
369 *dst++ = base64[(byte >> 12) & 0x3f];
370 *dst++ = base64[(byte >> 6) & 0x3f];
371 *dst++ = base64[byte & 0x3f];
372 cnt += 4;
373 col += 4;
374 bits = 0;
375 byte = 0;
376 }
377 if (linebreaks && (cnt < max) && (col == 64)) {
378 *dst++ = '\n';
379 cnt++;
380 col = 0;
381 }
382 }
383 if (bits && (cnt + 4 <= max)) {
384 /* Add one last character for the remaining bits,
385 padding the rest with 0 */
386 byte <<= 24 - bits;
387 *dst++ = base64[(byte >> 18) & 0x3f];
388 *dst++ = base64[(byte >> 12) & 0x3f];
389 if (bits == 16)
390 *dst++ = base64[(byte >> 6) & 0x3f];
391 else
392 *dst++ = '=';
393 *dst++ = '=';
394 cnt += 4;
395 }
396 if (linebreaks && (cnt < max)) {
397 *dst++ = '\n';
398 cnt++;
399 }
400 *dst = '\0';
401 return cnt;
402}
403
404int ast_base64encode(char *dst, const unsigned char *src, int srclen, int max)
405{
406 return ast_base64encode_full(dst, src, srclen, max, 0);
407}
408
409/*! \brief Encode to BASE64 and return encoded string */
410char *ast_base64encode_string(const char *src)
411{
412 size_t encoded_len;
413 char *encoded_string;
414
415 if (ast_strlen_zero(src)) {
416 return NULL;
417 }
418
419 encoded_len = ((strlen(src) * 4 / 3 + 3) & ~3) + 1;
420 encoded_string = ast_calloc(1, encoded_len);
421
422 ast_base64encode(encoded_string, (const unsigned char *)src, strlen(src), encoded_len);
423
424 return encoded_string;
425}
426
427int ast_base64url_decode(unsigned char *dst, const char *src, int max)
428{
429 int cnt = 0;
430 unsigned int byte = 0;
431 unsigned int bits = 0;
432
433 while (*src && (cnt < max)) {
434 byte <<= 6;
435 byte |= (b2a_url[(int)(*src)]) & 0x3f;
436 bits += 6;
437 src++;
438 if (bits >= 8) {
439 bits -= 8;
440 *dst = (byte >> bits) & 0xff;
441 dst++;
442 cnt++;
443 }
444 }
445 return cnt;
446}
447
448char *ast_base64url_decode_string(const char *src)
449{
450 size_t decoded_len;
451 unsigned char *decoded_string;
452
453 if (ast_strlen_zero(src)) {
454 return NULL;
455 }
456
457 decoded_len = strlen(src) * 3 / 4;
458 decoded_string = ast_malloc(decoded_len + 1);
459 if (!decoded_string) {
460 return NULL;
461 }
462
463 ast_base64url_decode(decoded_string, src, decoded_len);
464 decoded_string[decoded_len] = '\0';
465
466 return (char *)decoded_string;
467}
468
469int ast_base64url_encode_full(char *dst, const unsigned char *src, int srclen, int max, int linebreaks)
470{
471 int cnt = 0;
472 int col = 0;
473 unsigned int byte = 0;
474 int bits = 0;
475 int cntin = 0;
476
477 max--;
478 while ((cntin < srclen) && (cnt < max)) {
479 byte <<= 8;
480 byte |= *(src++);
481 bits += 8;
482 cntin++;
483 if ((bits == 24) && (cnt + 4 <= max)) {
484 *dst++ = base64url[(byte >> 18) & 0x3f];
485 *dst++ = base64url[(byte >> 12) & 0x3f];
486 *dst++ = base64url[(byte >> 6) & 0x3f];
487 *dst++ = base64url[(byte) & 0x3f];
488 cnt += 4;
489 col += 4;
490 bits = 0;
491 byte = 0;
492 }
493 if (linebreaks && (cnt < max) && (col == 64)) {
494 *dst++ = '\n';
495 cnt++;
496 col = 0;
497 }
498 }
499 if (bits && (cnt + 4 <= max)) {
500 byte <<= 24 - bits;
501 *dst++ = base64url[(byte >> 18) & 0x3f];
502 *dst++ = base64url[(byte >> 12) & 0x3f];
503 if (bits == 16) {
504 *dst++ = base64url[(byte >> 6) & 0x3f];
505 }
506 cnt += 4;
507 }
508 if (linebreaks && (cnt < max)) {
509 *dst++ = '\n';
510 cnt++;
511 }
512 *dst = '\0';
513 return cnt;
514}
515
516int ast_base64url_encode(char *dst, const unsigned char *src, int srclen, int max)
517{
518 return ast_base64url_encode_full(dst, src, srclen, max, 0);
519}
520
521char *ast_base64url_encode_string(const char *src)
522{
523 size_t encoded_len;
524 char *encoded_string;
525
526 if (ast_strlen_zero(src)) {
527 return NULL;
528 }
529
530 encoded_len = ((strlen(src) * 4 / 3 + 3) & ~3) + 1;
531 encoded_string = ast_malloc(encoded_len);
532
533 ast_base64url_encode(encoded_string, (const unsigned char *)src, strlen(src), encoded_len);
534
535 return encoded_string;
536}
537
538static void base64_init(void)
539{
540 int x;
541 memset(b2a, -1, sizeof(b2a));
542 memset(b2a_url, -1, sizeof(b2a_url));
543 /* Initialize base-64 Conversion table */
544 for (x = 0; x < 26; x++) {
545 /* A-Z */
546 base64[x] = 'A' + x;
547 base64url[x] = 'A' + x;
548 b2a['A' + x] = x;
549 b2a_url['A' + x] = x;
550 /* a-z */
551 base64[x + 26] = 'a' + x;
552 base64url[x + 26] = 'a' + x;
553 b2a['a' + x] = x + 26;
554 b2a_url['a' + x] = x + 26;
555 /* 0-9 */
556 if (x < 10) {
557 base64[x + 52] = '0' + x;
558 base64url[x + 52] = '0' + x;
559 b2a['0' + x] = x + 52;
560 b2a_url['0' + x] = x + 52;
561 }
562 }
563 base64[62] = '+';
564 base64[63] = '/';
565 base64url[62] = '-';
566 base64url[63] = '_';
567 b2a[(int)'+'] = 62;
568 b2a[(int)'/'] = 63;
569 b2a_url[(int)'-'] = 62;
570 b2a_url[(int)'_'] = 63;
571}
572
573#define BASELINELEN 72 /*!< Line length for Base 64 encoded messages */
574#define BASEMAXINLINE 256 /*!< Buffer size for Base 64 attachment encoding */
575
576/*! \brief Structure used for base64 encoding */
577struct baseio {
578 int iocp;
579 int iolen;
581 int ateof;
582 unsigned char iobuf[BASEMAXINLINE];
583};
584
585/*!
586 * \brief utility used by inchar(), for base_encode()
587 */
588static int inbuf(struct baseio *bio, FILE *fi)
589{
590 int l;
591
592 if (bio->ateof) {
593 return 0;
594 }
595
596 if ((l = fread(bio->iobuf, 1, BASEMAXINLINE, fi)) != BASEMAXINLINE) {
597 bio->ateof = 1;
598 if (l == 0) {
599 /* Assume EOF */
600 return 0;
601 }
602 }
603
604 bio->iolen = l;
605 bio->iocp = 0;
606
607 return 1;
608}
609
610/*!
611 * \brief utility used by base_encode()
612 */
613static int inchar(struct baseio *bio, FILE *fi)
614{
615 if (bio->iocp >= bio->iolen) {
616 if (!inbuf(bio, fi)) {
617 return EOF;
618 }
619 }
620
621 return bio->iobuf[bio->iocp++];
622}
623
624/*!
625 * \brief utility used by base_encode()
626 */
627static int ochar(struct baseio *bio, int c, FILE *so, const char *endl)
628{
629 if (bio->linelength >= BASELINELEN) {
630 if (fputs(endl, so) == EOF) {
631 return -1;
632 }
633
634 bio->linelength = 0;
635 }
636
637 if (putc(((unsigned char) c), so) == EOF) {
638 return -1;
639 }
640
641 bio->linelength++;
642
643 return 1;
644}
645
646int ast_base64_encode_file(FILE *inputfile, FILE *outputfile, const char *endl)
647{
648 static const unsigned char dtable[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
649 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
650 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0',
651 '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
652 int i, hiteof = 0;
653 struct baseio bio;
654
655 memset(&bio, 0, sizeof(bio));
656 bio.iocp = BASEMAXINLINE;
657
658 while (!hiteof){
659 unsigned char igroup[3], ogroup[4];
660 int c, n;
661
662 memset(igroup, 0, sizeof(igroup));
663
664 for (n = 0; n < 3; n++) {
665 if ((c = inchar(&bio, inputfile)) == EOF) {
666 hiteof = 1;
667 break;
668 }
669
670 igroup[n] = (unsigned char) c;
671 }
672
673 if (n > 0) {
674 ogroup[0]= dtable[igroup[0] >> 2];
675 ogroup[1]= dtable[((igroup[0] & 3) << 4) | (igroup[1] >> 4)];
676 ogroup[2]= dtable[((igroup[1] & 0xF) << 2) | (igroup[2] >> 6)];
677 ogroup[3]= dtable[igroup[2] & 0x3F];
678
679 if (n < 3) {
680 ogroup[3] = '=';
681
682 if (n < 2) {
683 ogroup[2] = '=';
684 }
685 }
686
687 for (i = 0; i < 4; i++) {
688 ochar(&bio, ogroup[i], outputfile, endl);
689 }
690 }
691 }
692
693 if (fputs(endl, outputfile) == EOF) {
694 return 0;
695 }
696
697 return 1;
698}
699
700int ast_base64_encode_file_path(const char *filename, FILE *outputfile, const char *endl)
701{
702 FILE *fi;
703 int res;
704
705 if (!(fi = fopen(filename, "rb"))) {
706 ast_log(AST_LOG_WARNING, "Failed to open file: %s: %s\n", filename, strerror(errno));
707 return -1;
708 }
709
710 res = ast_base64_encode_file(fi, outputfile, endl);
711
712 fclose(fi);
713
714 return res;
715}
716
720
721char *ast_uri_encode(const char *string, char *outbuf, int buflen, struct ast_flags spec)
722{
723 const char *ptr = string; /* Start with the string */
724 char *out = outbuf;
725 const char *mark = "-_.!~*'()"; /* no encode set, RFC 2396 section 2.3, RFC 3261 sec 25 */
726 const char *user_unreserved = "&=+$,;?/"; /* user-unreserved set, RFC 3261 sec 25 */
727
728 while (*ptr && out - outbuf < buflen - 1) {
729 if (ast_test_flag(&spec, AST_URI_LEGACY_SPACE) && *ptr == ' ') {
730 /* for legacy encoding, encode spaces as '+' */
731 *out = '+';
732 out++;
733 } else if (!(ast_test_flag(&spec, AST_URI_MARK)
734 && strchr(mark, *ptr))
736 && ((*ptr >= '0' && *ptr <= '9')
737 || (*ptr >= 'A' && *ptr <= 'Z')
738 || (*ptr >= 'a' && *ptr <= 'z')))
740 && strchr(user_unreserved, *ptr))) {
741
742 if (out - outbuf >= buflen - 3) {
743 break;
744 }
745 out += sprintf(out, "%%%02hhX", (unsigned char) *ptr);
746 } else {
747 *out = *ptr; /* Continue copying the string */
748 out++;
749 }
750 ptr++;
751 }
752
753 if (buflen) {
754 *out = '\0';
755 }
756
757 return outbuf;
758}
759
760void ast_uri_decode(char *s, struct ast_flags spec)
761{
762 char *o;
763 unsigned int tmp;
764
765 for (o = s; *s; s++, o++) {
766 if (ast_test_flag(&spec, AST_URI_LEGACY_SPACE) && *s == '+') {
767 /* legacy mode, decode '+' as space */
768 *o = ' ';
769 } else if (*s == '%' && s[1] != '\0' && s[2] != '\0' && sscanf(s + 1, "%2x", &tmp) == 1) {
770 /* have '%', two chars and correct parsing */
771 *o = tmp;
772 s += 2; /* Will be incremented once more when we break out */
773 } else /* all other cases, just copy */
774 *o = *s;
775 }
776 *o = '\0';
777}
778
779int ast_uri_verify_encoded(const char *string)
780{
781 const char *ptr = string;
782 size_t length;
783 char *endl;
784
785 if (!string) {
786 return 0;
787 }
788
789 length = strlen(string);
790 endl = (char *)string + length;
791
792 while (*ptr) {
793 if (*ptr == '%') {
794 unsigned int tmp;
795 /* Make sure there are at least 2 characters left to decode */
796 if (ptr + 2 >= endl) {
797 return 0;
798 }
799 /* Try to parse the next two characters as hex */
800 if (sscanf(ptr + 1, "%2x", &tmp) != 1) {
801 return 0;
802 }
803 /* All good, move past the '%' and the two hex digits */
804 ptr += 3;
805 } else if (!isalnum((unsigned char ) *ptr) && !strchr("-_.+", *ptr)) {
806 return 0;
807 } else {
808 ptr++;
809 }
810 }
811
812 return 1; /* all characters are valid */
813}
814
815char *ast_escape_quoted(const char *string, char *outbuf, int buflen)
816{
817 const char *ptr = string;
818 char *out = outbuf;
819 char *allow = "\t\v !"; /* allow LWS (minus \r and \n) and "!" */
820
821 while (*ptr && out - outbuf < buflen - 1) {
822 if (!(strchr(allow, *ptr))
823 && !(*ptr >= '#' && *ptr <= '[') /* %x23 - %x5b */
824 && !(*ptr >= ']' && *ptr <= '~') /* %x5d - %x7e */
825 && !((unsigned char) *ptr > 0x7f)) { /* UTF8-nonascii */
826
827 if (out - outbuf >= buflen - 2) {
828 break;
829 }
830 out += sprintf(out, "\\%c", (unsigned char) *ptr);
831 } else {
832 *out = *ptr;
833 out++;
834 }
835 ptr++;
836 }
837
838 if (buflen) {
839 *out = '\0';
840 }
841
842 return outbuf;
843}
844
845char *ast_escape_semicolons(const char *string, char *outbuf, int buflen)
846{
847 const char *ptr = string;
848 char *out = outbuf;
849
850 if (string == NULL || outbuf == NULL) {
851 ast_assert(string != NULL && outbuf != NULL);
852 return NULL;
853 }
854
855 while (*ptr && out - outbuf < buflen - 1) {
856 if (*ptr == ';') {
857 if (out - outbuf >= buflen - 2) {
858 break;
859 }
860 strcpy(out, "\\;");
861 out += 2;
862 } else {
863 *out = *ptr;
864 out++;
865 }
866 ptr++;
867 }
868
869 if (buflen) {
870 *out = '\0';
871 }
872
873 return outbuf;
874}
875
876void ast_unescape_quoted(char *quote_str)
877{
878 int esc_pos;
879 int unesc_pos;
880 int quote_str_len = strlen(quote_str);
881
882 for (esc_pos = 0, unesc_pos = 0;
883 esc_pos < quote_str_len;
884 esc_pos++, unesc_pos++) {
885 if (quote_str[esc_pos] == '\\') {
886 /* at least one more char and current is \\ */
887 esc_pos++;
888 if (esc_pos >= quote_str_len) {
889 break;
890 }
891 }
892
893 quote_str[unesc_pos] = quote_str[esc_pos];
894 }
895 quote_str[unesc_pos] = '\0';
896}
897
898int ast_xml_escape(const char *string, char * const outbuf, const size_t buflen)
899{
900 char *dst = outbuf;
901 char *end = outbuf + buflen - 1; /* save one for the null terminator */
902
903 /* Handle the case for the empty output buffer */
904 if (buflen == 0) {
905 return -1;
906 }
907
908 /* Escaping rules from http://www.w3.org/TR/REC-xml/#syntax */
909 /* This also prevents partial entities at the end of a string */
910 while (*string && dst < end) {
911 const char *entity = NULL;
912 int len = 0;
913
914 switch (*string) {
915 case '<':
916 entity = "&lt;";
917 len = 4;
918 break;
919 case '&':
920 entity = "&amp;";
921 len = 5;
922 break;
923 case '>':
924 /* necessary if ]]> is in the string; easier to escape them all */
925 entity = "&gt;";
926 len = 4;
927 break;
928 case '\'':
929 /* necessary in single-quoted strings; easier to escape them all */
930 entity = "&apos;";
931 len = 6;
932 break;
933 case '"':
934 /* necessary in double-quoted strings; easier to escape them all */
935 entity = "&quot;";
936 len = 6;
937 break;
938 default:
939 *dst++ = *string++;
940 break;
941 }
942
943 if (entity) {
944 ast_assert(len == strlen(entity));
945 if (end - dst < len) {
946 /* no room for the entity; stop */
947 break;
948 }
949 /* just checked for length; strcpy is fine */
950 strcpy(dst, entity);
951 dst += len;
952 ++string;
953 }
954 }
955 /* Write null terminator */
956 *dst = '\0';
957 /* If any chars are left in string, return failure */
958 return *string == '\0' ? 0 : -1;
959}
960
961/*! \brief ast_inet_ntoa: Recursive thread safe replacement of inet_ntoa */
962const char *ast_inet_ntoa(struct in_addr ia)
963{
964 char *buf;
965
966 if (!(buf = ast_threadstorage_get(&inet_ntoa_buf, INET_ADDRSTRLEN)))
967 return "";
968
969 return inet_ntop(AF_INET, &ia, buf, INET_ADDRSTRLEN);
970}
971
972static int dev_urandom_fd = -1;
973
974#ifndef __linux__
975#undef pthread_create /* For ast_pthread_create function only */
976#endif /* !__linux__ */
977
978#ifdef DEBUG_THREADS
979
980#if !defined(LOW_MEMORY)
981/*! \brief A reasonable maximum number of locks a thread would be holding ... */
982#define AST_MAX_LOCKS 64
983
984/* Allow direct use of pthread_mutex_t and friends */
985#undef pthread_mutex_t
986#undef pthread_mutex_lock
987#undef pthread_mutex_unlock
988#undef pthread_mutex_init
989#undef pthread_mutex_destroy
990
991/*!
992 * \brief Keep track of which locks a thread holds
993 *
994 * There is an instance of this struct for every active thread
995 */
996struct thr_lock_info {
997 /*! The thread's ID */
998 pthread_t thread_id;
999 /*! The thread name which includes where the thread was started */
1000 const char *thread_name;
1001 /*! This is the actual container of info for what locks this thread holds */
1002 struct {
1003 const char *file;
1004 const char *func;
1005 const char *lock_name;
1006 void *lock_addr;
1007 int times_locked;
1008 int times_lock_attempted;
1009 struct timeval last_locked;
1010 struct timeval last_unlocked;
1011 int line_num;
1012 enum ast_lock_type type;
1013 /*! This thread is waiting on this lock */
1014 int pending:2;
1015 /*! A condition has suspended this lock */
1016 int suspended:1;
1017#ifdef HAVE_BKTR
1018 struct ast_bt *backtrace;
1019#endif
1020 } locks[AST_MAX_LOCKS];
1021 /*! This is the number of locks currently held by this thread.
1022 * The index (num_locks - 1) has the info on the last one in the
1023 * locks member */
1024 unsigned int num_locks;
1025 /*! The LWP id (which GDB prints) */
1026 int lwp;
1027 /*! Protects the contents of the locks member
1028 * Intentionally not ast_mutex_t */
1030 AST_LIST_ENTRY(thr_lock_info) entry;
1031};
1032
1033/*!
1034 * \brief Locked when accessing the lock_infos list
1035 */
1036AST_MUTEX_DEFINE_STATIC(lock_infos_lock);
1037/*!
1038 * \brief A list of each thread's lock info
1039 */
1040static AST_LIST_HEAD_NOLOCK_STATIC(lock_infos, thr_lock_info);
1041
1042/*!
1043 * \brief Destroy a thread's lock info
1044 *
1045 * This gets called automatically when the thread stops
1046 */
1047static void lock_info_destroy(void *data)
1048{
1049 struct thr_lock_info *lock_info = data;
1050 int i;
1051
1052 pthread_mutex_lock(&lock_infos_lock.mutex);
1053 AST_LIST_REMOVE(&lock_infos, lock_info, entry);
1054 pthread_mutex_unlock(&lock_infos_lock.mutex);
1055
1056
1057 for (i = 0; i < lock_info->num_locks; i++) {
1058 if (lock_info->locks[i].pending == -1) {
1059 /* This just means that the last lock this thread went for was by
1060 * using trylock, and it failed. This is fine. */
1061 break;
1062 }
1063
1065 "Thread '%s' still has a lock! - '%s' (%p) from '%s' in %s:%d!\n",
1066 lock_info->thread_name,
1067 lock_info->locks[i].lock_name,
1068 lock_info->locks[i].lock_addr,
1069 lock_info->locks[i].func,
1070 lock_info->locks[i].file,
1071 lock_info->locks[i].line_num
1072 );
1073 }
1074
1076 if (lock_info->thread_name) {
1077 ast_free((void *) lock_info->thread_name);
1078 }
1080}
1081
1082/*!
1083 * \brief The thread storage key for per-thread lock info
1084 */
1085AST_THREADSTORAGE_CUSTOM(thread_lock_info, NULL, lock_info_destroy);
1086#endif /* ! LOW_MEMORY */
1087
1088void ast_store_lock_info(enum ast_lock_type type, const char *filename,
1089 int line_num, const char *func, const char *lock_name, void *lock_addr, struct ast_bt *bt)
1090{
1091#if !defined(LOW_MEMORY)
1092 struct thr_lock_info *lock_info;
1093 int i;
1094
1095 if (!(lock_info = ast_threadstorage_get(&thread_lock_info, sizeof(*lock_info))))
1096 return;
1097
1099
1100 for (i = 0; i < lock_info->num_locks; i++) {
1101 if (lock_info->locks[i].lock_addr == lock_addr) {
1102 lock_info->locks[i].times_locked++;
1103 lock_info->locks[i].times_lock_attempted++;
1104 lock_info->locks[i].last_locked = ast_tvnow();
1105#ifdef HAVE_BKTR
1106 lock_info->locks[i].backtrace = bt;
1107#endif
1109 return;
1110 }
1111 }
1112
1113 if (lock_info->num_locks == AST_MAX_LOCKS) {
1114 /* Can't use ast_log here, because it will cause infinite recursion */
1115 fprintf(stderr, "XXX ERROR XXX A thread holds more locks than '%d'."
1116 " Increase AST_MAX_LOCKS!\n", AST_MAX_LOCKS);
1118 return;
1119 }
1120
1121 if (i && lock_info->locks[i - 1].pending == -1) {
1122 /* The last lock on the list was one that this thread tried to lock but
1123 * failed at doing so. It has now moved on to something else, so remove
1124 * the old lock from the list. */
1125 i--;
1126 lock_info->num_locks--;
1127 memset(&lock_info->locks[i], 0, sizeof(lock_info->locks[0]));
1128 }
1129
1130 lock_info->locks[i].file = filename;
1131 lock_info->locks[i].line_num = line_num;
1132 lock_info->locks[i].func = func;
1133 lock_info->locks[i].lock_name = lock_name;
1134 lock_info->locks[i].lock_addr = lock_addr;
1135 lock_info->locks[i].times_locked = 1;
1136 lock_info->locks[i].times_lock_attempted = 1;
1137 lock_info->locks[i].last_locked = ast_tvnow();
1138 lock_info->locks[i].type = type;
1139 lock_info->locks[i].pending = 1;
1140#ifdef HAVE_BKTR
1141 lock_info->locks[i].backtrace = bt;
1142#endif
1143 lock_info->num_locks++;
1144
1146#endif /* ! LOW_MEMORY */
1147}
1148
1149void ast_mark_lock_acquired(void *lock_addr)
1150{
1151#if !defined(LOW_MEMORY)
1152 struct thr_lock_info *lock_info;
1153
1154 if (!(lock_info = ast_threadstorage_get(&thread_lock_info, sizeof(*lock_info))))
1155 return;
1156
1158 if (lock_info->locks[lock_info->num_locks - 1].lock_addr == lock_addr) {
1159 lock_info->locks[lock_info->num_locks - 1].pending = 0;
1160 }
1162#endif /* ! LOW_MEMORY */
1163}
1164
1165void ast_mark_lock_failed(void *lock_addr)
1166{
1167#if !defined(LOW_MEMORY)
1168 struct thr_lock_info *lock_info;
1169
1170 if (!(lock_info = ast_threadstorage_get(&thread_lock_info, sizeof(*lock_info))))
1171 return;
1172
1174 if (lock_info->locks[lock_info->num_locks - 1].lock_addr == lock_addr) {
1175 lock_info->locks[lock_info->num_locks - 1].pending = -1;
1176 lock_info->locks[lock_info->num_locks - 1].times_locked--;
1177 lock_info->locks[lock_info->num_locks - 1].last_unlocked = ast_tvnow();
1178 }
1180#endif /* ! LOW_MEMORY */
1181}
1182
1183int 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)
1184{
1185#if !defined(LOW_MEMORY)
1186 struct thr_lock_info *lock_info;
1187 int i = 0;
1188
1189 if (!(lock_info = ast_threadstorage_get(&thread_lock_info, sizeof(*lock_info))))
1190 return -1;
1191
1193
1194 for (i = lock_info->num_locks - 1; i >= 0; i--) {
1195 if (lock_info->locks[i].lock_addr == lock_addr)
1196 break;
1197 }
1198
1199 if (i == -1) {
1200 /* Lock not found :( */
1202 return -1;
1203 }
1204
1205 ast_copy_string(filename, lock_info->locks[i].file, filename_size);
1206 *lineno = lock_info->locks[i].line_num;
1207 ast_copy_string(func, lock_info->locks[i].func, func_size);
1208 ast_copy_string(mutex_name, lock_info->locks[i].lock_name, mutex_name_size);
1209
1211
1212 return 0;
1213#else /* if defined(LOW_MEMORY) */
1214 return -1;
1215#endif
1216}
1217
1218void ast_suspend_lock_info(void *lock_addr)
1219{
1220#if !defined(LOW_MEMORY)
1221 struct thr_lock_info *lock_info;
1222 int i = 0;
1223
1224 if (!(lock_info = ast_threadstorage_get(&thread_lock_info, sizeof(*lock_info)))) {
1225 return;
1226 }
1227
1229
1230 for (i = lock_info->num_locks - 1; i >= 0; i--) {
1231 if (lock_info->locks[i].lock_addr == lock_addr)
1232 break;
1233 }
1234
1235 if (i == -1) {
1236 /* Lock not found :( */
1238 return;
1239 }
1240
1241 lock_info->locks[i].suspended = 1;
1242
1244#endif /* ! LOW_MEMORY */
1245}
1246
1247void ast_restore_lock_info(void *lock_addr)
1248{
1249#if !defined(LOW_MEMORY)
1250 struct thr_lock_info *lock_info;
1251 int i = 0;
1252
1253 if (!(lock_info = ast_threadstorage_get(&thread_lock_info, sizeof(*lock_info))))
1254 return;
1255
1257
1258 for (i = lock_info->num_locks - 1; i >= 0; i--) {
1259 if (lock_info->locks[i].lock_addr == lock_addr)
1260 break;
1261 }
1262
1263 if (i == -1) {
1264 /* Lock not found :( */
1266 return;
1267 }
1268
1269 lock_info->locks[i].suspended = 0;
1270
1272#endif /* ! LOW_MEMORY */
1273}
1274
1275
1276void ast_remove_lock_info(void *lock_addr, struct ast_bt *bt)
1277{
1278#if !defined(LOW_MEMORY)
1279 struct thr_lock_info *lock_info;
1280 int i = 0;
1281
1282 if (!(lock_info = ast_threadstorage_get(&thread_lock_info, sizeof(*lock_info))))
1283 return;
1284
1286
1287 for (i = lock_info->num_locks - 1; i >= 0; i--) {
1288 if (lock_info->locks[i].lock_addr == lock_addr)
1289 break;
1290 }
1291
1292 if (i == -1) {
1293 /* Lock not found :( */
1295 return;
1296 }
1297
1298 if (lock_info->locks[i].times_locked > 1) {
1299 lock_info->locks[i].times_locked--;
1300 lock_info->locks[i].last_unlocked = ast_tvnow();
1301#ifdef HAVE_BKTR
1302 lock_info->locks[i].backtrace = bt;
1303#endif
1305 return;
1306 }
1307
1308 if (i < lock_info->num_locks - 1) {
1309 /* Not the last one ... *should* be rare! */
1310 memmove(&lock_info->locks[i], &lock_info->locks[i + 1],
1311 (lock_info->num_locks - (i + 1)) * sizeof(lock_info->locks[0]));
1312 }
1313
1314 lock_info->num_locks--;
1315
1317#endif /* ! LOW_MEMORY */
1318}
1319
1320#if !defined(LOW_MEMORY)
1321static const char *locktype2str(enum ast_lock_type type)
1322{
1323 switch (type) {
1324 case AST_MUTEX:
1325 return "MUTEX";
1326 case AST_RDLOCK:
1327 return "RDLOCK";
1328 case AST_WRLOCK:
1329 return "WRLOCK";
1330 }
1331
1332 return "UNKNOWN";
1333}
1334
1335#ifdef HAVE_BKTR
1336static void append_backtrace_information(struct ast_str **str, struct ast_bt *bt)
1337{
1338 struct ast_vector_string *symbols;
1339 int num_frames;
1340
1341 if (!bt) {
1342 ast_str_append(str, 0, "\tNo backtrace to print\n");
1343 return;
1344 }
1345
1346 /* store frame count locally to avoid the memory corruption that
1347 * sometimes happens on virtualized CentOS 6.x systems */
1348 num_frames = bt->num_frames;
1349 if ((symbols = ast_bt_get_symbols(bt->addresses, num_frames))) {
1350 int frame_iterator;
1351
1352 for (frame_iterator = 1; frame_iterator < AST_VECTOR_SIZE(symbols); ++frame_iterator) {
1353 ast_str_append(str, 0, "\t%s\n", AST_VECTOR_GET(symbols, frame_iterator));
1354 }
1355
1356 ast_bt_free_symbols(symbols);
1357 } else {
1358 ast_str_append(str, 0, "\tCouldn't retrieve backtrace symbols\n");
1359 }
1360}
1361#endif
1362
1363static void append_lock_information(struct ast_str **str, struct thr_lock_info *lock_info, int i)
1364{
1365 int j;
1367 struct ast_lock_track *lt;
1368 struct timeval held_for;
1369 struct timeval now = ast_tvnow();
1370 char lock_time[32], unlock_time[32], held_time[32];
1371
1372 held_for = ast_tvsub(now, lock_info->locks[i].last_locked);
1373 /* format time duration strings */
1374 ast_format_duration_hh_mm_ss(lock_info->locks[i].last_locked.tv_sec,
1375 lock_time, sizeof(lock_time));
1376 ast_format_duration_hh_mm_ss(lock_info->locks[i].last_unlocked.tv_sec,
1377 unlock_time, sizeof(unlock_time));
1378 ast_format_duration_hh_mm_ss(held_for.tv_sec, held_time, sizeof(held_time));
1379
1380 ast_str_append(str, 0, "=== ---> %sLock #%d (%s): %s %d %s %s %p\n"
1381 "=== %s.%06ld, %s.%06ld, %s.%06ld (%d, %d%s)\n",
1382 lock_info->locks[i].pending > 0 ? "Waiting for " :
1383 lock_info->locks[i].pending < 0 ? "Tried and failed to get " : "", i,
1384 lock_info->locks[i].file,
1385 locktype2str(lock_info->locks[i].type),
1386 lock_info->locks[i].line_num,
1387 lock_info->locks[i].func,
1388 lock_info->locks[i].lock_name,
1389 lock_info->locks[i].lock_addr,
1390 lock_time,
1391 lock_info->locks[i].last_locked.tv_usec,
1392 unlock_time,
1393 lock_info->locks[i].last_unlocked.tv_usec,
1394 held_time,
1395 held_for.tv_usec,
1396 lock_info->locks[i].times_locked,
1397 lock_info->locks[i].times_lock_attempted,
1398 lock_info->locks[i].suspended ? " - suspended" : "");
1399#ifdef HAVE_BKTR
1400 append_backtrace_information(str, lock_info->locks[i].backtrace);
1401#endif
1402
1403 if (!lock_info->locks[i].pending || lock_info->locks[i].pending == -1)
1404 return;
1405
1406 /* We only have further details for mutexes right now */
1407 if (lock_info->locks[i].type != AST_MUTEX)
1408 return;
1409
1410 lock = lock_info->locks[i].lock_addr;
1411 lt = lock->track;
1412 ast_reentrancy_lock(lt);
1413 for (j = 0; *str && j < lt->reentrancy; j++) {
1414 ast_str_append(str, 0, "=== --- ---> Locked Here: %s line %d (%s)\n",
1415 lt->file[j], lt->lineno[j], lt->func[j]);
1416 }
1417 ast_reentrancy_unlock(lt);
1418}
1419#endif /* ! LOW_MEMORY */
1420
1421/*! This function can help you find highly temporal locks; locks that happen for a
1422 short time, but at unexpected times, usually at times that create a deadlock,
1423 Why is this thing locked right then? Who is locking it? Who am I fighting
1424 with for this lock?
1425
1426 To answer such questions, just call this routine before you would normally try
1427 to acquire a lock. It doesn't do anything if the lock is not acquired. If the
1428 lock is taken, it will publish a line or two to the console via ast_log().
1429
1430 Sometimes, the lock message is pretty uninformative. For instance, you might
1431 find that the lock is being acquired deep within the astobj2 code; this tells
1432 you little about higher level routines that call the astobj2 routines.
1433 But, using gdb, you can set a break at the ast_log below, and for that
1434 breakpoint, you can set the commands:
1435 where
1436 cont
1437 which will give a stack trace and continue. -- that aught to do the job!
1438
1439*/
1440void ast_log_show_lock(void *this_lock_addr)
1441{
1442#if !defined(LOW_MEMORY)
1443 struct thr_lock_info *lock_info;
1444 struct ast_str *str;
1445
1446 if (!(str = ast_str_create(4096))) {
1447 ast_log(LOG_NOTICE,"Could not create str\n");
1448 return;
1449 }
1450
1451
1452 pthread_mutex_lock(&lock_infos_lock.mutex);
1453 AST_LIST_TRAVERSE(&lock_infos, lock_info, entry) {
1454 int i;
1456 for (i = 0; str && i < lock_info->num_locks; i++) {
1457 /* ONLY show info about this particular lock, if
1458 it's acquired... */
1459 if (lock_info->locks[i].lock_addr == this_lock_addr) {
1460 append_lock_information(&str, lock_info, i);
1462 break;
1463 }
1464 }
1466 }
1467 pthread_mutex_unlock(&lock_infos_lock.mutex);
1468 ast_free(str);
1469#endif /* ! LOW_MEMORY */
1470}
1471
1472
1473struct ast_str *ast_dump_locks(void)
1474{
1475#if !defined(LOW_MEMORY)
1476 struct thr_lock_info *lock_info;
1477 struct ast_str *str;
1478 char print_time[32];
1479 struct timeval now = ast_tvnow();
1480
1481 if (!(str = ast_str_create(4096))) {
1482 return NULL;
1483 }
1484
1485 ast_format_duration_hh_mm_ss(now.tv_sec, print_time, sizeof(print_time));
1486
1487 ast_str_append(&str, 0, "\n"
1488 "=======================================================================\n"
1489 "=== %s\n"
1490 "=== Currently Held Locks at Time: %s.%06ld =================\n"
1491 "=======================================================================\n"
1492 "===\n"
1493 "=== <pending> <lock#> (<file>): <lock type> <line num> <function> <lock name> <lock addr>\n"
1494 "=== <locked at>, <failed at>, <held for> (attempts, times locked)\n"
1495 "===\n", ast_get_version(), print_time, now.tv_usec);
1496 if (!str) {
1497 return NULL;
1498 }
1499
1500 pthread_mutex_lock(&lock_infos_lock.mutex);
1501 AST_LIST_TRAVERSE(&lock_infos, lock_info, entry) {
1502 int i;
1503 int header_printed = 0;
1505 for (i = 0; str && i < lock_info->num_locks; i++) {
1506 /* Don't show suspended locks */
1507 if (lock_info->locks[i].suspended) {
1508 continue;
1509 }
1510
1511 if (!header_printed) {
1512 if (lock_info->lwp != -1) {
1513 ast_str_append(&str, 0, "=== Thread ID: 0x%lx LWP:%d (%s)\n",
1514 (long unsigned) lock_info->thread_id, lock_info->lwp, lock_info->thread_name);
1515 } else {
1516 ast_str_append(&str, 0, "=== Thread ID: 0x%lx (%s)\n",
1517 (long unsigned) lock_info->thread_id, lock_info->thread_name);
1518 }
1519 header_printed = 1;
1520 }
1521
1522 append_lock_information(&str, lock_info, i);
1523 }
1525 if (!str) {
1526 break;
1527 }
1528 if (header_printed) {
1529 ast_str_append(&str, 0, "=== -------------------------------------------------------------------\n"
1530 "===\n");
1531 }
1532 if (!str) {
1533 break;
1534 }
1535 }
1536 pthread_mutex_unlock(&lock_infos_lock.mutex);
1537
1538 if (!str) {
1539 return NULL;
1540 }
1541
1542 ast_str_append(&str, 0, "=======================================================================\n"
1543 "\n");
1544
1545 return str;
1546#else /* if defined(LOW_MEMORY) */
1547 return NULL;
1548#endif
1549}
1550
1551#if !defined(LOW_MEMORY)
1552static char *handle_show_locks(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1553{
1554 struct ast_str *str;
1555
1556 switch (cmd) {
1557 case CLI_INIT:
1558 e->command = "core show locks";
1559 e->usage =
1560 "Usage: core show locks\n"
1561 " This command is for lock debugging. It prints out which locks\n"
1562 "are owned by each active thread.\n";
1564 return NULL;
1565
1566 case CLI_GENERATE:
1567 return NULL;
1568 }
1569
1570 str = ast_dump_locks();
1571 if (!str) {
1572 return CLI_FAILURE;
1573 }
1574
1575 ast_cli(a->fd, "%s", ast_str_buffer(str));
1576
1577 ast_free(str);
1578
1579 return CLI_SUCCESS;
1580}
1581
1582static struct ast_cli_entry utils_cli[] = {
1583 AST_CLI_DEFINE(handle_show_locks, "Show which locks are held by which thread"),
1584};
1585#endif /* ! LOW_MEMORY */
1586#endif /* DEBUG_THREADS */
1587
1588#if !defined(LOW_MEMORY)
1589/*
1590 * support for 'show threads'. The start routine is wrapped by
1591 * dummy_start(), so that ast_register_thread() and
1592 * ast_unregister_thread() know the thread identifier.
1593 */
1594struct thr_arg {
1595 void *(*start_routine)(void *);
1596 void *data;
1597 char *name;
1598};
1599
1600/*
1601 * on OS/X, pthread_cleanup_push() and pthread_cleanup_pop()
1602 * are odd macros which start and end a block, so they _must_ be
1603 * used in pairs (the latter with a '1' argument to call the
1604 * handler on exit.
1605 * On BSD we don't need this, but we keep it for compatibility.
1606 */
1607static void *dummy_start(void *data)
1608{
1609 void *ret;
1610 struct thr_arg a = *((struct thr_arg *) data); /* make a local copy */
1611#ifdef DEBUG_THREADS
1612 struct thr_lock_info *lock_info;
1613 pthread_mutexattr_t mutex_attr;
1614
1615 if (!(lock_info = ast_threadstorage_get(&thread_lock_info, sizeof(*lock_info))))
1616 return NULL;
1617
1618 lock_info->thread_id = pthread_self();
1619 lock_info->lwp = ast_get_tid();
1620 lock_info->thread_name = ast_strdup(a.name);
1621
1622 pthread_mutexattr_init(&mutex_attr);
1623 pthread_mutexattr_settype(&mutex_attr, AST_MUTEX_KIND);
1624 pthread_mutex_init(&lock_info->lock, &mutex_attr);
1625 pthread_mutexattr_destroy(&mutex_attr);
1626
1627 pthread_mutex_lock(&lock_infos_lock.mutex); /* Intentionally not the wrapper */
1628 AST_LIST_INSERT_TAIL(&lock_infos, lock_info, entry);
1629 pthread_mutex_unlock(&lock_infos_lock.mutex); /* Intentionally not the wrapper */
1630#endif /* DEBUG_THREADS */
1631
1632 /* note that even though data->name is a pointer to allocated memory,
1633 we are not freeing it here because ast_register_thread is going to
1634 keep a copy of the pointer and then ast_unregister_thread will
1635 free the memory
1636 */
1637 ast_free(data);
1639 pthread_cleanup_push(ast_unregister_thread, (void *) pthread_self());
1640
1641 ret = a.start_routine(a.data);
1642
1643 pthread_cleanup_pop(1);
1644
1645 return ret;
1646}
1647
1648#endif /* !LOW_MEMORY */
1649
1651{
1652#if !defined(LOW_MEMORY)
1653 return AST_STACKSIZE;
1654#else
1655 return AST_STACKSIZE_LOW;
1656#endif
1657}
1658
1659int ast_pthread_create_stack(pthread_t *thread, pthread_attr_t *attr, void *(*start_routine)(void *),
1660 void *data, size_t stacksize, const char *file, const char *caller,
1661 int line, const char *start_fn)
1662{
1663#if !defined(LOW_MEMORY)
1664 struct thr_arg *a;
1665#endif
1666
1667 if (!attr) {
1668 attr = ast_alloca(sizeof(*attr));
1669 pthread_attr_init(attr);
1670 }
1671
1672#if defined(__linux__) || defined(__FreeBSD__)
1673 /* On Linux and FreeBSD , pthread_attr_init() defaults to PTHREAD_EXPLICIT_SCHED,
1674 which is kind of useless. Change this here to
1675 PTHREAD_INHERIT_SCHED; that way the -p option to set realtime
1676 priority will propagate down to new threads by default.
1677 This does mean that callers cannot set a different priority using
1678 PTHREAD_EXPLICIT_SCHED in the attr argument; instead they must set
1679 the priority afterwards with pthread_setschedparam(). */
1680 if ((errno = pthread_attr_setinheritsched(attr, PTHREAD_INHERIT_SCHED)))
1681 ast_log(LOG_WARNING, "pthread_attr_setinheritsched: %s\n", strerror(errno));
1682#endif
1683
1684 if (!stacksize)
1685 stacksize = AST_STACKSIZE;
1686
1687 if ((errno = pthread_attr_setstacksize(attr, stacksize ? stacksize : AST_STACKSIZE)))
1688 ast_log(LOG_WARNING, "pthread_attr_setstacksize: %s\n", strerror(errno));
1689
1690#if !defined(LOW_MEMORY)
1691 if ((a = ast_malloc(sizeof(*a)))) {
1692 a->start_routine = start_routine;
1693 a->data = data;
1695 if (ast_asprintf(&a->name, "%-20s started at [%5d] %s %s()",
1696 start_fn, line, file, caller) < 0) {
1697 a->name = NULL;
1698 }
1699 data = a;
1700 }
1701#endif /* !LOW_MEMORY */
1702
1703 return pthread_create(thread, attr, start_routine, data); /* We're in ast_pthread_create, so it's okay */
1704}
1705
1706
1707int ast_pthread_create_detached_stack(pthread_t *thread, pthread_attr_t *attr, void *(*start_routine)(void *),
1708 void *data, size_t stacksize, const char *file, const char *caller,
1709 int line, const char *start_fn)
1710{
1711 unsigned char attr_destroy = 0;
1712 int res;
1713
1714 if (!attr) {
1715 attr = ast_alloca(sizeof(*attr));
1716 pthread_attr_init(attr);
1717 attr_destroy = 1;
1718 }
1719
1720 if ((errno = pthread_attr_setdetachstate(attr, PTHREAD_CREATE_DETACHED)))
1721 ast_log(LOG_WARNING, "pthread_attr_setdetachstate: %s\n", strerror(errno));
1722
1724 stacksize, file, caller, line, start_fn);
1725
1726 if (attr_destroy)
1727 pthread_attr_destroy(attr);
1728
1729 return res;
1730}
1731
1732int ast_wait_for_input(int fd, int ms)
1733{
1734 struct pollfd pfd[1];
1735
1736 memset(pfd, 0, sizeof(pfd));
1737 pfd[0].fd = fd;
1738 pfd[0].events = POLLIN | POLLPRI;
1739 return ast_poll(pfd, 1, ms);
1740}
1741
1742int ast_wait_for_output(int fd, int ms)
1743{
1744 struct pollfd pfd[1];
1745
1746 memset(pfd, 0, sizeof(pfd));
1747 pfd[0].fd = fd;
1748 pfd[0].events = POLLOUT;
1749 return ast_poll(pfd, 1, ms);
1750}
1751
1752static int wait_for_output(int fd, int timeoutms)
1753{
1754 struct pollfd pfd = {
1755 .fd = fd,
1756 .events = POLLOUT,
1757 };
1758 int res;
1759 struct timeval start = ast_tvnow();
1760 int elapsed = 0;
1761
1762 /* poll() until the fd is writable without blocking */
1763 while ((res = ast_poll(&pfd, 1, timeoutms - elapsed)) <= 0) {
1764 if (res == 0) {
1765 /* timed out. */
1766#ifndef STANDALONE
1767 ast_debug(1, "Timed out trying to write\n");
1768#endif
1769 return -1;
1770 } else if (res == -1) {
1771 /* poll() returned an error, check to see if it was fatal */
1772
1773 if (errno == EINTR || errno == EAGAIN) {
1774 elapsed = ast_tvdiff_ms(ast_tvnow(), start);
1775 if (elapsed >= timeoutms) {
1776 return -1;
1777 }
1778 /* This was an acceptable error, go back into poll() */
1779 continue;
1780 }
1781
1782 /* Fatal error, bail. */
1783 ast_log(LOG_ERROR, "poll returned error: %s\n", strerror(errno));
1784
1785 return -1;
1786 }
1787 elapsed = ast_tvdiff_ms(ast_tvnow(), start);
1788 if (elapsed >= timeoutms) {
1789 return -1;
1790 }
1791 }
1792
1793 return 0;
1794}
1795
1796/*!
1797 * Try to write string, but wait no more than ms milliseconds before timing out.
1798 *
1799 * \note The code assumes that the file descriptor has NONBLOCK set,
1800 * so there is only one system call made to do a write, unless we actually
1801 * have a need to wait. This way, we get better performance.
1802 * If the descriptor is blocking, all assumptions on the guaranteed
1803 * detail do not apply anymore.
1804 */
1805int ast_carefulwrite(int fd, char *s, int len, int timeoutms)
1806{
1807 struct timeval start = ast_tvnow();
1808 int res = 0;
1809 int elapsed = 0;
1810
1811 while (len) {
1812 if (wait_for_output(fd, timeoutms - elapsed)) {
1813 return -1;
1814 }
1815
1816 res = write(fd, s, len);
1817
1818 if (res < 0 && errno != EAGAIN && errno != EINTR) {
1819 /* fatal error from write() */
1820 if (errno == EPIPE) {
1821#ifndef STANDALONE
1822 ast_debug(1, "write() failed due to reading end being closed: %s\n", strerror(errno));
1823#endif
1824 } else {
1825 ast_log(LOG_ERROR, "write() returned error: %s\n", strerror(errno));
1826 }
1827 return -1;
1828 }
1829
1830 if (res < 0) {
1831 /* It was an acceptable error */
1832 res = 0;
1833 }
1834
1835 /* Update how much data we have left to write */
1836 len -= res;
1837 s += res;
1838 res = 0;
1839
1840 elapsed = ast_tvdiff_ms(ast_tvnow(), start);
1841 if (elapsed >= timeoutms) {
1842 /* We've taken too long to write
1843 * This is only an error condition if we haven't finished writing. */
1844 res = len ? -1 : 0;
1845 break;
1846 }
1847 }
1848
1849 return res;
1850}
1851
1852char *ast_strip_quoted(char *s, const char *beg_quotes, const char *end_quotes)
1853{
1854 char *e;
1855 const char *q;
1856
1857 s = ast_strip(s);
1858 if ((q = strchr(beg_quotes, *s)) && *q != '\0') {
1859 e = s + strlen(s) - 1;
1860 if (*e == *(end_quotes + (q - beg_quotes))) {
1861 s++;
1862 *e = '\0';
1863 }
1864 }
1865
1866 return s;
1867}
1868
1869char *ast_strsep(char **iss, const char sep, uint32_t flags)
1870{
1871 char *st = *iss;
1872 char *is;
1873 int inquote = 0;
1874 int found = 0;
1875 char stack[8];
1876
1877 if (ast_strlen_zero(st)) {
1878 *iss = NULL;
1879 return st;
1880 }
1881
1882 memset(stack, 0, sizeof(stack));
1883
1884 for(is = st; *is; is++) {
1885 if (*is == '\\') {
1886 if (*++is != '\0') {
1887 is++;
1888 } else {
1889 break;
1890 }
1891 }
1892
1893 if (*is == '\'' || *is == '"') {
1894 if (*is == stack[inquote]) {
1895 stack[inquote--] = '\0';
1896 } else {
1897 if (++inquote >= sizeof(stack)) {
1898 return NULL;
1899 }
1900 stack[inquote] = *is;
1901 }
1902 }
1903
1904 if (*is == sep && !inquote) {
1905 *is = '\0';
1906 found = 1;
1907 *iss = is + 1;
1908 break;
1909 }
1910 }
1911 if (!found) {
1912 *iss = NULL;
1913 }
1914
1915 if (flags & AST_STRSEP_STRIP) {
1916 st = ast_strip_quoted(st, "'\"", "'\"");
1917 }
1918
1919 if (flags & AST_STRSEP_TRIM) {
1920 char *trimmed = ast_strip(st);
1921 if (!ast_strlen_zero(trimmed)) {
1922 st = trimmed;
1923 }
1924 }
1925
1926 if (flags & AST_STRSEP_UNESCAPE) {
1928 }
1929
1930 return st;
1931}
1932
1933char *ast_strsep_quoted(char **iss, const char sep, const char quote, uint32_t flags)
1934{
1935 char *st = *iss;
1936 char *is;
1937 int inquote = 0;
1938 int found = 0;
1939 char stack[8];
1940 const char qstr[] = { quote };
1941
1942 if (ast_strlen_zero(st)) {
1943 *iss = NULL;
1944 return st;
1945 }
1946
1947 memset(stack, 0, sizeof(stack));
1948
1949 for(is = st; *is; is++) {
1950 if (*is == '\\') {
1951 if (*++is != '\0') {
1952 is++;
1953 } else {
1954 break;
1955 }
1956 }
1957
1958 if (*is == quote) {
1959 if (*is == stack[inquote]) {
1960 stack[inquote--] = '\0';
1961 } else {
1962 if (++inquote >= sizeof(stack)) {
1963 return NULL;
1964 }
1965 stack[inquote] = *is;
1966 }
1967 }
1968
1969 if (*is == sep && !inquote) {
1970 *is = '\0';
1971 found = 1;
1972 *iss = is + 1;
1973 break;
1974 }
1975 }
1976 if (!found) {
1977 *iss = NULL;
1978 }
1979
1980 if (flags & AST_STRSEP_STRIP) {
1981 st = ast_strip_quoted(st, qstr, qstr);
1982 }
1983
1984 if (flags & AST_STRSEP_TRIM) {
1985 char *trimmed = ast_strip(st);
1986 if (!ast_strlen_zero(trimmed)) {
1987 st = trimmed;
1988 }
1989 }
1990
1991 if (flags & AST_STRSEP_UNESCAPE) {
1993 }
1994
1995 return st;
1996}
1997
1999{
2000 char *e;
2001 char *work = s;
2002
2003 while ((e = strchr(work, ';'))) {
2004 if ((e > work) && (*(e-1) == '\\')) {
2005 memmove(e - 1, e, strlen(e) + 1);
2006 work = e;
2007 } else {
2008 work = e + 1;
2009 }
2010 }
2011
2012 return s;
2013}
2014
2015/* !\brief unescape some C sequences in place, return pointer to the original string.
2016 */
2017char *ast_unescape_c(char *src)
2018{
2019 char c, *ret, *dst;
2020
2021 if (src == NULL)
2022 return NULL;
2023 for (ret = dst = src; (c = *src++); *dst++ = c ) {
2024 if (c != '\\')
2025 continue; /* copy char at the end of the loop */
2026 switch ((c = *src++)) {
2027 case '\0': /* special, trailing '\' */
2028 c = '\\';
2029 break;
2030 case 'b': /* backspace */
2031 c = '\b';
2032 break;
2033 case 'f': /* form feed */
2034 c = '\f';
2035 break;
2036 case 'n':
2037 c = '\n';
2038 break;
2039 case 'r':
2040 c = '\r';
2041 break;
2042 case 't':
2043 c = '\t';
2044 break;
2045 }
2046 /* default, use the char literally */
2047 }
2048 *dst = '\0';
2049 return ret;
2050}
2051
2052/*
2053 * Standard escape sequences - Note, '\0' is not included as a valid character
2054 * to escape, but instead is used here as a NULL terminator for the string.
2055 */
2057 '\a', '\b', '\f', '\n', '\r', '\t', '\v', '\\', '\'', '\"', '\?', '\0'
2058};
2059
2060/*
2061 * Standard escape sequences output map (has to maintain matching order with
2062 * escape_sequences). '\0' is included here as a NULL terminator for the string.
2063 */
2064static char escape_sequences_map[] = {
2065 'a', 'b', 'f', 'n', 'r', 't', 'v', '\\', '\'', '"', '?', '\0'
2066};
2067
2068char *ast_escape(char *dest, const char *s, size_t size, const char *to_escape)
2069{
2070 char *p;
2071 char *c;
2072
2073 if (!dest || !size) {
2074 return dest;
2075 }
2076 if (ast_strlen_zero(s)) {
2077 *dest = '\0';
2078 return dest;
2079 }
2080
2081 if (ast_strlen_zero(to_escape)) {
2082 ast_copy_string(dest, s, size);
2083 return dest;
2084 }
2085
2086 for (p = dest; *s && --size; ++s, ++p) {
2087 /* If in the list of characters to escape then escape it */
2088 if (strchr(to_escape, *s)) {
2089 if (!--size) {
2090 /* Not enough room left for the escape sequence. */
2091 break;
2092 }
2093
2094 /*
2095 * See if the character to escape is part of the standard escape
2096 * sequences. If so we'll have to use its mapped counterpart
2097 * otherwise just use the current character.
2098 */
2099 c = strchr(escape_sequences, *s);
2100 *p++ = '\\';
2102 } else {
2103 *p = *s;
2104 }
2105 }
2106 *p = '\0';
2107
2108 return dest;
2109}
2110
2111char *ast_escape_c(char *dest, const char *s, size_t size)
2112{
2113 /*
2114 * Note - This is an optimized version of ast_escape. When looking only
2115 * for escape_sequences a couple of checks used in the generic case can
2116 * be left out thus making it slightly more efficient.
2117 */
2118 char *p;
2119 char *c;
2120
2121 if (!dest || !size) {
2122 return dest;
2123 }
2124 if (ast_strlen_zero(s)) {
2125 *dest = '\0';
2126 return dest;
2127 }
2128
2129 for (p = dest; *s && --size; ++s, ++p) {
2130 /*
2131 * See if the character to escape is part of the standard escape
2132 * sequences. If so use its mapped counterpart.
2133 */
2134 c = strchr(escape_sequences, *s);
2135 if (c) {
2136 if (!--size) {
2137 /* Not enough room left for the escape sequence. */
2138 break;
2139 }
2140
2141 *p++ = '\\';
2143 } else {
2144 *p = *s;
2145 }
2146 }
2147 *p = '\0';
2148
2149 return dest;
2150}
2151
2152static char *escape_alloc(const char *s, size_t *size)
2153{
2154 if (!s) {
2155 return NULL;
2156 }
2157
2158 /*
2159 * The result string needs to be twice the size of the given
2160 * string just in case every character in it needs to be escaped.
2161 */
2162 *size = strlen(s) * 2 + 1;
2163 return ast_malloc(*size);
2164}
2165
2166char *ast_escape_alloc(const char *s, const char *to_escape)
2167{
2168 size_t size = 0;
2169 char *dest = escape_alloc(s, &size);
2170
2171 return ast_escape(dest, s, size, to_escape);
2172}
2173
2174char *ast_escape_c_alloc(const char *s)
2175{
2176 size_t size = 0;
2177 char *dest = escape_alloc(s, &size);
2178
2179 return ast_escape_c(dest, s, size);
2180}
2181
2182int ast_build_string_va(char **buffer, size_t *space, const char *fmt, va_list ap)
2183{
2184 int result;
2185
2186 if (!buffer || !*buffer || !space || !*space)
2187 return -1;
2188
2189 result = vsnprintf(*buffer, *space, fmt, ap);
2190
2191 if (result < 0)
2192 return -1;
2193 else if (result > *space)
2194 result = *space;
2195
2196 *buffer += result;
2197 *space -= result;
2198 return 0;
2199}
2200
2201int ast_build_string(char **buffer, size_t *space, const char *fmt, ...)
2202{
2203 va_list ap;
2204 int result;
2205
2206 va_start(ap, fmt);
2207 result = ast_build_string_va(buffer, space, fmt, ap);
2208 va_end(ap);
2209
2210 return result;
2211}
2212
2213int ast_regex_string_to_regex_pattern(const char *regex_string, struct ast_str **regex_pattern)
2214{
2215 int regex_len = strlen(regex_string);
2216 int ret = 3;
2217
2218 /* Chop off the leading / if there is one */
2219 if ((regex_len >= 1) && (regex_string[0] == '/')) {
2220 ast_str_set(regex_pattern, 0, "%s", regex_string + 1);
2221 ret -= 2;
2222 }
2223
2224 /* Chop off the ending / if there is one */
2225 if ((regex_len > 1) && (regex_string[regex_len - 1] == '/')) {
2226 ast_str_truncate(*regex_pattern, -1);
2227 ret -= 1;
2228 }
2229
2230 return ret;
2231}
2232
2233int ast_true(const char *s)
2234{
2235 if (ast_strlen_zero(s))
2236 return 0;
2237
2238 /* Determine if this is a true value */
2239 if (!strcasecmp(s, "yes") ||
2240 !strcasecmp(s, "true") ||
2241 !strcasecmp(s, "y") ||
2242 !strcasecmp(s, "t") ||
2243 !strcasecmp(s, "1") ||
2244 !strcasecmp(s, "on"))
2245 return -1;
2246
2247 return 0;
2248}
2249
2250int ast_false(const char *s)
2251{
2252 if (ast_strlen_zero(s))
2253 return 0;
2254
2255 /* Determine if this is a false value */
2256 if (!strcasecmp(s, "no") ||
2257 !strcasecmp(s, "false") ||
2258 !strcasecmp(s, "n") ||
2259 !strcasecmp(s, "f") ||
2260 !strcasecmp(s, "0") ||
2261 !strcasecmp(s, "off"))
2262 return -1;
2263
2264 return 0;
2265}
2266
2267#define ONE_MILLION 1000000
2268/*
2269 * put timeval in a valid range. usec is 0..999999
2270 * negative values are not allowed and truncated.
2271 */
2272static struct timeval tvfix(struct timeval a)
2273{
2274 if (a.tv_usec >= ONE_MILLION) {
2275 ast_log(LOG_WARNING, "warning too large timestamp %ld.%ld\n",
2276 (long)a.tv_sec, (long int) a.tv_usec);
2277 a.tv_sec += a.tv_usec / ONE_MILLION;
2278 a.tv_usec %= ONE_MILLION;
2279 } else if (a.tv_usec < 0) {
2280 ast_log(LOG_WARNING, "warning negative timestamp %ld.%ld\n",
2281 (long)a.tv_sec, (long int) a.tv_usec);
2282 a.tv_usec = 0;
2283 }
2284 return a;
2285}
2286
2287struct timeval ast_tvadd(struct timeval a, struct timeval b)
2288{
2289 /* consistency checks to guarantee usec in 0..999999 */
2290 a = tvfix(a);
2291 b = tvfix(b);
2292 a.tv_sec += b.tv_sec;
2293 a.tv_usec += b.tv_usec;
2294 if (a.tv_usec >= ONE_MILLION) {
2295 a.tv_sec++;
2296 a.tv_usec -= ONE_MILLION;
2297 }
2298 return a;
2299}
2300
2301struct timeval ast_tvsub(struct timeval a, struct timeval b)
2302{
2303 /* consistency checks to guarantee usec in 0..999999 */
2304 a = tvfix(a);
2305 b = tvfix(b);
2306 a.tv_sec -= b.tv_sec;
2307 a.tv_usec -= b.tv_usec;
2308 if (a.tv_usec < 0) {
2309 a.tv_sec-- ;
2310 a.tv_usec += ONE_MILLION;
2311 }
2312 return a;
2313}
2314
2315int ast_remaining_ms(struct timeval start, int max_ms)
2316{
2317 int ms;
2318
2319 if (max_ms < 0) {
2320 ms = max_ms;
2321 } else {
2322 ms = max_ms - ast_tvdiff_ms(ast_tvnow(), start);
2323 if (ms < 0) {
2324 ms = 0;
2325 }
2326 }
2327
2328 return ms;
2329}
2330
2331void ast_format_duration_hh_mm_ss(int duration, char *buf, size_t length)
2332{
2333 int durh, durm, durs;
2334 durh = duration / 3600;
2335 durm = (duration % 3600) / 60;
2336 durs = duration % 60;
2337 snprintf(buf, length, "%02d:%02d:%02d", durh, durm, durs);
2338}
2339
2340#undef ONE_MILLION
2341
2342#ifndef linux
2344#endif
2345
2346long int ast_random(void)
2347{
2348 long int res;
2349
2350 if (dev_urandom_fd >= 0) {
2351 int read_res = read(dev_urandom_fd, &res, sizeof(res));
2352 if (read_res > 0) {
2353 long int rm = RAND_MAX;
2354 res = res < 0 ? ~res : res;
2355 rm++;
2356 return res % rm;
2357 }
2358 }
2359
2360 /* XXX - Thread safety really depends on the libc, not the OS.
2361 *
2362 * But... popular Linux libc's (uClibc, glibc, eglibc), all have a
2363 * somewhat thread safe random(3) (results are random, but not
2364 * reproducible). The libc's for other systems (BSD, et al.), not so
2365 * much.
2366 */
2367#ifdef linux
2368 res = random();
2369#else
2371 res = random();
2373#endif
2374 return res;
2375}
2376
2378{
2379 for (; *s; s++) {
2380 if (*s == '^') {
2381 *s = ',';
2382 }
2383 }
2384}
2385
2386char *ast_process_quotes_and_slashes(char *start, char find, char replace_with)
2387{
2388 char *dataPut = start;
2389 int inEscape = 0;
2390 int inQuotes = 0;
2391
2392 for (; *start; start++) {
2393 if (inEscape) {
2394 *dataPut++ = *start; /* Always goes verbatim */
2395 inEscape = 0;
2396 } else {
2397 if (*start == '\\') {
2398 inEscape = 1; /* Do not copy \ into the data */
2399 } else if (*start == '\'') {
2400 inQuotes = 1 - inQuotes; /* Do not copy ' into the data */
2401 } else {
2402 /* Replace , with |, unless in quotes */
2403 *dataPut++ = inQuotes ? *start : ((*start == find) ? replace_with : *start);
2404 }
2405 }
2406 }
2407 if (start != dataPut)
2408 *dataPut = 0;
2409 return dataPut;
2410}
2411
2412void ast_join_delim(char *s, size_t len, const char * const w[], unsigned int size, char delim)
2413{
2414 int x, ofs = 0;
2415 const char *src;
2416
2417 /* Join words into a string */
2418 if (!s)
2419 return;
2420 for (x = 0; ofs < len && x < size && w[x] ; x++) {
2421 if (x > 0)
2422 s[ofs++] = delim;
2423 for (src = w[x]; *src && ofs < len; src++)
2424 s[ofs++] = *src;
2425 }
2426 if (ofs == len)
2427 ofs--;
2428 s[ofs] = '\0';
2429}
2430
2431char *ast_to_camel_case_delim(const char *s, const char *delim)
2432{
2433 char *res = ast_strdup(s);
2434 char *front, *back, *buf = res;
2435 int size;
2436
2437 front = strtok_r(buf, delim, &back);
2438
2439 while (front) {
2440 size = strlen(front);
2441 *front = toupper(*front);
2442 ast_copy_string(buf, front, size + 1);
2443 buf += size;
2444 front = strtok_r(NULL, delim, &back);
2445 }
2446
2447 return res;
2448}
2449
2450/*! \brief
2451 * get values from config variables.
2452 */
2453int ast_get_timeval(const char *src, struct timeval *dst, struct timeval _default, int *consumed)
2454{
2455 long double dtv = 0.0;
2456 int scanned;
2457
2458 if (dst == NULL)
2459 return -1;
2460
2461 *dst = _default;
2462
2463 if (ast_strlen_zero(src))
2464 return -1;
2465
2466 /* only integer at the moment, but one day we could accept more formats */
2467 if (sscanf(src, "%30Lf%n", &dtv, &scanned) > 0) {
2468 dst->tv_sec = dtv;
2469 dst->tv_usec = (dtv - dst->tv_sec) * 1000000.0;
2470 if (consumed)
2471 *consumed = scanned;
2472 return 0;
2473 } else
2474 return -1;
2475}
2476
2477/*! \brief
2478 * get values from config variables.
2479 */
2480int ast_get_time_t(const char *src, time_t *dst, time_t _default, int *consumed)
2481{
2482 long t;
2483 int scanned;
2484
2485 if (dst == NULL)
2486 return -1;
2487
2488 *dst = _default;
2489
2490 if (ast_strlen_zero(src))
2491 return -1;
2492
2493 /* only integer at the moment, but one day we could accept more formats */
2494 if (sscanf(src, "%30ld%n", &t, &scanned) == 1) {
2495 *dst = t;
2496 if (consumed)
2497 *consumed = scanned;
2498 return 0;
2499 } else
2500 return -1;
2501}
2502
2504{
2505#if defined(HAVE_IP_MTU_DISCOVER)
2506 int val = IP_PMTUDISC_DONT;
2507
2508 if (setsockopt(sock, IPPROTO_IP, IP_MTU_DISCOVER, &val, sizeof(val)))
2509 ast_log(LOG_WARNING, "Unable to disable PMTU discovery. Large UDP packets may fail to be delivered when sent from this socket.\n");
2510#endif /* HAVE_IP_MTU_DISCOVER */
2511}
2512
2513int ast_mkdir(const char *path, int mode)
2514{
2515 char *ptr;
2516 int len = strlen(path), count = 0, x, piececount = 0;
2517 char *tmp = ast_strdupa(path);
2518 char **pieces;
2519 char *fullpath = ast_alloca(len + 1);
2520 int res = 0;
2521
2522 for (ptr = tmp; *ptr; ptr++) {
2523 if (*ptr == '/')
2524 count++;
2525 }
2526
2527 /* Count the components to the directory path */
2528 pieces = ast_alloca(count * sizeof(*pieces));
2529 for (ptr = tmp; *ptr; ptr++) {
2530 if (*ptr == '/') {
2531 *ptr = '\0';
2532 pieces[piececount++] = ptr + 1;
2533 }
2534 }
2535
2536 *fullpath = '\0';
2537 for (x = 0; x < piececount; x++) {
2538 /* This looks funky, but the buffer is always ideally-sized, so it's fine. */
2539 strcat(fullpath, "/");
2540 strcat(fullpath, pieces[x]);
2541 res = mkdir(fullpath, mode);
2542 if (res && errno != EEXIST)
2543 return errno;
2544 }
2545 return 0;
2546}
2547
2548static int safe_mkdir(const char *base_path, char *path, int mode)
2549{
2550 RAII_VAR(char *, absolute_path, NULL, ast_std_free);
2551
2552 absolute_path = realpath(path, NULL);
2553
2554 if (absolute_path) {
2555 /* Path exists, but is it in the right place? */
2556 if (!ast_begins_with(absolute_path, base_path)) {
2557 return EPERM;
2558 }
2559
2560 /* It is in the right place! */
2561 return 0;
2562 } else {
2563 /* Path doesn't exist. */
2564
2565 /* The slash terminating the subpath we're checking */
2566 char *path_term = strchr(path, '/');
2567 /* True indicates the parent path is within base_path */
2568 int parent_is_safe = 0;
2569 int res;
2570
2571 while (path_term) {
2572 RAII_VAR(char *, absolute_subpath, NULL, ast_std_free);
2573
2574 /* Truncate the path one past the slash */
2575 char c = *(path_term + 1);
2576 *(path_term + 1) = '\0';
2577 absolute_subpath = realpath(path, NULL);
2578
2579 if (absolute_subpath) {
2580 /* Subpath exists, but is it safe? */
2581 parent_is_safe = ast_begins_with(
2582 absolute_subpath, base_path);
2583 } else if (parent_is_safe) {
2584 /* Subpath does not exist, but parent is safe
2585 * Create it */
2586 res = mkdir(path, mode);
2587 if (res != 0) {
2588 ast_assert(errno != EEXIST);
2589 return errno;
2590 }
2591 } else {
2592 /* Subpath did not exist, parent was not safe
2593 * Fail! */
2594 errno = EPERM;
2595 return errno;
2596 }
2597 /* Restore the path */
2598 *(path_term + 1) = c;
2599 /* Move on to the next slash */
2600 path_term = strchr(path_term + 1, '/');
2601 }
2602
2603 /* Now to build the final path, but only if it's safe */
2604 if (!parent_is_safe) {
2605 errno = EPERM;
2606 return errno;
2607 }
2608
2609 res = mkdir(path, mode);
2610 if (res != 0 && errno != EEXIST) {
2611 return errno;
2612 }
2613
2614 return 0;
2615 }
2616}
2617
2618int ast_safe_mkdir(const char *base_path, const char *path, int mode)
2619{
2620 RAII_VAR(char *, absolute_base_path, NULL, ast_std_free);
2621 RAII_VAR(char *, p, NULL, ast_free);
2622
2623 if (base_path == NULL || path == NULL) {
2624 errno = EFAULT;
2625 return errno;
2626 }
2627
2628 p = ast_strdup(path);
2629 if (p == NULL) {
2630 errno = ENOMEM;
2631 return errno;
2632 }
2633
2634 absolute_base_path = realpath(base_path, NULL);
2635 if (absolute_base_path == NULL) {
2636 return errno;
2637 }
2638
2639 return safe_mkdir(absolute_base_path, p, mode);
2640}
2641
2642static void utils_shutdown(void)
2643{
2644 close(dev_urandom_fd);
2645 dev_urandom_fd = -1;
2646#if defined(DEBUG_THREADS) && !defined(LOW_MEMORY)
2647 ast_cli_unregister_multiple(utils_cli, ARRAY_LEN(utils_cli));
2648#endif
2649}
2650
2652{
2653 dev_urandom_fd = open("/dev/urandom", O_RDONLY);
2654 base64_init();
2655#ifdef DEBUG_THREADS
2656#if !defined(LOW_MEMORY)
2657 ast_cli_register_multiple(utils_cli, ARRAY_LEN(utils_cli));
2658#endif
2659#endif
2661 return 0;
2662}
2663
2664
2665/*!
2666 *\brief Parse digest authorization header.
2667 *\return Returns -1 if we have no auth or something wrong with digest.
2668 *\note This function may be used for Digest request and response header.
2669 * request arg is set to nonzero, if we parse Digest Request.
2670 * pedantic arg can be set to nonzero if we need to do addition Digest check.
2671 */
2672int ast_parse_digest(const char *digest, struct ast_http_digest *d, int request, int pedantic) {
2673 char *c;
2674 struct ast_str *str = ast_str_create(16);
2675
2676 /* table of recognised keywords, and places where they should be copied */
2677 const struct x {
2678 const char *key;
2679 const ast_string_field *field;
2680 } *i, keys[] = {
2681 { "username=", &d->username },
2682 { "realm=", &d->realm },
2683 { "nonce=", &d->nonce },
2684 { "uri=", &d->uri },
2685 { "domain=", &d->domain },
2686 { "response=", &d->response },
2687 { "cnonce=", &d->cnonce },
2688 { "opaque=", &d->opaque },
2689 /* Special cases that cannot be directly copied */
2690 { "algorithm=", NULL },
2691 { "qop=", NULL },
2692 { "nc=", NULL },
2693 { NULL, 0 },
2694 };
2695
2696 if (ast_strlen_zero(digest) || !d || !str) {
2697 ast_free(str);
2698 return -1;
2699 }
2700
2701 ast_str_set(&str, 0, "%s", digest);
2702
2704
2705 if (strncasecmp(c, "Digest ", strlen("Digest "))) {
2706 ast_log(LOG_WARNING, "Missing Digest.\n");
2707 ast_free(str);
2708 return -1;
2709 }
2710 c += strlen("Digest ");
2711
2712 /* lookup for keys/value pair */
2713 while (c && *c && *(c = ast_skip_blanks(c))) {
2714 /* find key */
2715 for (i = keys; i->key != NULL; i++) {
2716 char *src, *separator;
2717 int unescape = 0;
2718 if (strncasecmp(c, i->key, strlen(i->key)) != 0) {
2719 continue;
2720 }
2721
2722 /* Found. Skip keyword, take text in quotes or up to the separator. */
2723 c += strlen(i->key);
2724 if (*c == '"') {
2725 src = ++c;
2726 separator = "\"";
2727 unescape = 1;
2728 } else {
2729 src = c;
2730 separator = ",";
2731 }
2732 strsep(&c, separator); /* clear separator and move ptr */
2733 if (unescape) {
2734 ast_unescape_c(src);
2735 }
2736 if (i->field) {
2737 ast_string_field_ptr_set(d, i->field, src);
2738 } else {
2739 /* Special cases that require additional processing */
2740 if (!strcasecmp(i->key, "algorithm=")) {
2741 if (strcasecmp(src, "MD5")) {
2742 ast_log(LOG_WARNING, "Digest algorithm: \"%s\" not supported.\n", src);
2743 ast_free(str);
2744 return -1;
2745 }
2746 } else if (!strcasecmp(i->key, "qop=") && !strcasecmp(src, "auth")) {
2747 d->qop = 1;
2748 } else if (!strcasecmp(i->key, "nc=")) {
2749 unsigned long u;
2750 if (sscanf(src, "%30lx", &u) != 1) {
2751 ast_log(LOG_WARNING, "Incorrect Digest nc value: \"%s\".\n", src);
2752 ast_free(str);
2753 return -1;
2754 }
2755 ast_string_field_set(d, nc, src);
2756 }
2757 }
2758 break;
2759 }
2760 if (i->key == NULL) { /* not found, try ',' */
2761 strsep(&c, ",");
2762 }
2763 }
2764 ast_free(str);
2765
2766 /* Digest checkout */
2767 if (ast_strlen_zero(d->realm) || ast_strlen_zero(d->nonce)) {
2768 /* "realm" and "nonce" MUST be always exist */
2769 return -1;
2770 }
2771
2772 if (!request) {
2773 /* Additional check for Digest response */
2774 if (ast_strlen_zero(d->username) || ast_strlen_zero(d->uri) || ast_strlen_zero(d->response)) {
2775 return -1;
2776 }
2777
2778 if (pedantic && d->qop && (ast_strlen_zero(d->cnonce) || ast_strlen_zero(d->nc))) {
2779 return -1;
2780 }
2781 }
2782
2783 return 0;
2784}
2785
2787{
2788 int ret = -1;
2789#if defined (__linux) && defined(SYS_gettid)
2790 ret = syscall(SYS_gettid); /* available since Linux 1.4.11 */
2791#elif defined(__sun)
2792 ret = pthread_self();
2793#elif defined(__APPLE__)
2794 ret = mach_thread_self();
2795 mach_port_deallocate(mach_task_self(), ret);
2796#elif defined(__FreeBSD__)
2797 long lwpid;
2798 thr_self(&lwpid);
2799 ret = lwpid;
2800#elif defined(__NetBSD__)
2801 ret = _lwp_self();
2802#elif defined(__OpenBSD__)
2803 ret = getthrid();
2804#endif
2805 return ret;
2806}
2807
2808char *ast_utils_which(const char *binary, char *fullpath, size_t fullpath_size)
2809{
2810 const char *envPATH = getenv("PATH");
2811 char *tpath, *path;
2812 struct stat unused;
2813 if (!envPATH) {
2814 return NULL;
2815 }
2816 tpath = ast_strdupa(envPATH);
2817 while ((path = strsep(&tpath, ":"))) {
2818 snprintf(fullpath, fullpath_size, "%s/%s", path, binary);
2819 if (!stat(fullpath, &unused)) {
2820 return fullpath;
2821 }
2822 }
2823 return NULL;
2824}
2825
2827{
2828 int udp6_socket = socket(AF_INET6, SOCK_DGRAM, 0);
2829
2830 if (udp6_socket < 0) {
2831 return 0;
2832 }
2833
2834 close(udp6_socket);
2835 return 1;
2836}
2837
2839{
2840#if defined(DO_CRASH)
2841 abort();
2842 /*
2843 * Just in case abort() doesn't work or something else super
2844 * silly, and for Qwell's amusement.
2845 */
2846 *((int *) 0) = 0;
2847#endif /* defined(DO_CRASH) */
2848}
2849
2850void DO_CRASH_NORETURN __ast_assert_failed(int condition, const char *condition_str, const char *file, int line, const char *function)
2851{
2852 /*
2853 * Attempt to put it into the logger, but hope that at least
2854 * someone saw the message on stderr ...
2855 */
2856 fprintf(stderr, "FRACK!, Failed assertion %s (%d) at line %d in %s of %s\n",
2857 condition_str, condition, line, function, file);
2858 ast_log(__LOG_ERROR, file, line, function, "FRACK!, Failed assertion %s (%d)\n",
2859 condition_str, condition);
2860
2861 /* Generate a backtrace for the assert */
2863
2864 /*
2865 * Give the logger a chance to get the message out, just in case
2866 * we abort(), or Asterisk crashes due to whatever problem just
2867 * happened after we exit ast_assert().
2868 */
2869 usleep(1);
2870 ast_do_crash();
2871}
2872
2873char *ast_eid_to_str(char *s, int maxlen, struct ast_eid *eid)
2874{
2875 int x;
2876 char *os = s;
2877 if (maxlen < 18) {
2878 if (s && (maxlen > 0)) {
2879 *s = '\0';
2880 }
2881 } else {
2882 for (x = 0; x < 5; x++) {
2883 sprintf(s, "%02hhx:", eid->eid[x]);
2884 s += 3;
2885 }
2886 sprintf(s, "%02hhx", eid->eid[5]);
2887 }
2888 return os;
2889}
2890
2891#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__) || defined(__Darwin__)
2892#include <ifaddrs.h>
2893#include <net/if_dl.h>
2894
2895void ast_set_default_eid(struct ast_eid *eid)
2896{
2897 struct ifaddrs *ifap, *ifaphead;
2898 int rtnerr;
2899 const struct sockaddr_dl *sdl;
2900 int alen;
2901 caddr_t ap;
2902 char eid_str[20];
2903 unsigned char empty_mac[6] = {0, 0, 0, 0, 0, 0};
2904 unsigned char full_mac[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
2905
2906 rtnerr = getifaddrs(&ifaphead);
2907 if (rtnerr) {
2908 ast_log(LOG_WARNING, "No ethernet interface found for seeding global EID. "
2909 "You will have to set it manually.\n");
2910 return;
2911 }
2912
2913 if (!ifaphead) {
2914 ast_log(LOG_WARNING, "No ethernet interface found for seeding global EID. "
2915 "You will have to set it manually.\n");
2916 return;
2917 }
2918
2919 for (ifap = ifaphead; ifap; ifap = ifap->ifa_next) {
2920 if (ifap->ifa_addr->sa_family != AF_LINK) {
2921 continue;
2922 }
2923
2924 sdl = (const struct sockaddr_dl *) ifap->ifa_addr;
2925 ap = ((caddr_t) ((sdl)->sdl_data + (sdl)->sdl_nlen));
2926 alen = sdl->sdl_alen;
2927 if (alen != 6 || !(memcmp(ap, &empty_mac, 6) && memcmp(ap, &full_mac, 6))) {
2928 continue;
2929 }
2930
2931 memcpy(eid, ap, sizeof(*eid));
2932 ast_debug(1, "Seeding global EID '%s'\n",
2933 ast_eid_to_str(eid_str, sizeof(eid_str), eid));
2934 freeifaddrs(ifaphead);
2935 return;
2936 }
2937
2938 ast_log(LOG_WARNING, "No ethernet interface found for seeding global EID. "
2939 "You will have to set it manually.\n");
2940 freeifaddrs(ifaphead);
2941
2942 return;
2943}
2944
2945#elif defined(SOLARIS)
2946#include <sys/sockio.h>
2947#include <net/if_arp.h>
2948
2949void ast_set_default_eid(struct ast_eid *eid)
2950{
2951 int s;
2952 int x;
2953 struct lifreq *ifr = NULL;
2954 struct lifnum ifn;
2955 struct lifconf ifc;
2956 struct arpreq ar;
2957 struct sockaddr_in *sa, *sa2;
2958 char *buf = NULL;
2959 char eid_str[20];
2960 int bufsz;
2961 unsigned char empty_mac[6] = {0, 0, 0, 0, 0, 0};
2962 unsigned char full_mac[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
2963
2964 s = socket(AF_INET, SOCK_STREAM, 0);
2965 if (s <= 0) {
2966 ast_log(LOG_WARNING, "Unable to open a socket for seeding global EID. "
2967 " You will have to set it manually.\n");
2968 return;
2969 }
2970
2971 /* Get a count of interfaces on the machine */
2972 ifn.lifn_family = AF_UNSPEC;
2973 ifn.lifn_flags = 0;
2974 ifn.lifn_count = 0;
2975 if (ioctl(s, SIOCGLIFNUM, &ifn) < 0) {
2976 ast_log(LOG_WARNING, "No ethernet interface found for seeding global EID. "
2977 " You will have to set it manually.\n");
2978 close(s);
2979 return;
2980 }
2981
2982 bufsz = ifn.lifn_count * sizeof(struct lifreq);
2983 if (!(buf = ast_malloc(bufsz))) {
2984 ast_log(LOG_WARNING, "Unable to allocate memory for seeding global EID. "
2985 "You will have to set it manually.\n");
2986 close(s);
2987 return;
2988 }
2989 memset(buf, 0, bufsz);
2990
2991 /* Get a list of interfaces on the machine */
2992 ifc.lifc_len = bufsz;
2993 ifc.lifc_buf = buf;
2994 ifc.lifc_family = AF_UNSPEC;
2995 ifc.lifc_flags = 0;
2996 if (ioctl(s, SIOCGLIFCONF, &ifc) < 0) {
2997 ast_log(LOG_WARNING, "No ethernet interface found for seeding global EID. "
2998 "You will have to set it manually.\n");
2999 ast_free(buf);
3000 close(s);
3001 return;
3002 }
3003
3004 for (ifr = (struct lifreq *)buf, x = 0; x < ifn.lifn_count; ifr++, x++) {
3005 unsigned char *p;
3006
3007 sa = (struct sockaddr_in *)&(ifr->lifr_addr);
3008 sa2 = (struct sockaddr_in *)&(ar.arp_pa);
3009 *sa2 = *sa;
3010
3011 if(ioctl(s, SIOCGARP, &ar) >= 0) {
3012 p = (unsigned char *)&(ar.arp_ha.sa_data);
3013 if (!(memcmp(p, &empty_mac, 6) && memcmp(p, &full_mac, 6))) {
3014 continue;
3015 }
3016
3017 memcpy(eid, p, sizeof(*eid));
3018 ast_debug(1, "Seeding global EID '%s'\n",
3019 ast_eid_to_str(eid_str, sizeof(eid_str), eid));
3020 ast_free(buf);
3021 close(s);
3022 return;
3023 }
3024 }
3025
3026 ast_log(LOG_WARNING, "No ethernet interface found for seeding global EID. "
3027 "You will have to set it manually.\n");
3028 ast_free(buf);
3029 close(s);
3030
3031 return;
3032}
3033
3034#else
3036{
3037 int s;
3038 int i;
3039 struct ifreq *ifr;
3040 struct ifreq *ifrp;
3041 struct ifconf ifc;
3042 char *buf = NULL;
3043 char eid_str[20];
3044 int bufsz, num_interfaces;
3045 unsigned char empty_mac[6] = {0, 0, 0, 0, 0, 0};
3046 unsigned char full_mac[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
3047
3048 s = socket(AF_INET, SOCK_STREAM, 0);
3049 if (s < 0) {
3050 ast_log(LOG_WARNING, "Unable to open socket for seeding global EID. "
3051 "You will have to set it manually.\n");
3052 return;
3053 }
3054
3055 ifc.ifc_len = 0;
3056 ifc.ifc_buf = NULL;
3057 if (ioctl(s, SIOCGIFCONF, &ifc) || ifc.ifc_len <= 0) {
3058 ast_log(LOG_WARNING, "No ethernet interface found for seeding global EID. "
3059 "You will have to set it manually.\n");
3060 close(s);
3061 return;
3062 }
3063 bufsz = ifc.ifc_len;
3064
3065 if (!(buf = ast_malloc(bufsz))) {
3066 ast_log(LOG_WARNING, "Unable to allocate memory for seeding global EID. "
3067 "You will have to set it manually.\n");
3068 close(s);
3069 return;
3070 }
3071
3072 ifc.ifc_buf = buf;
3073 if (ioctl(s, SIOCGIFCONF, &ifc) < 0) {
3074 ast_log(LOG_WARNING, "Unable to retrieve ethernet interfaces for seeding global EID. "
3075 "You will have to set it manually.\n");
3076 ast_free(buf);
3077 close(s);
3078 return;
3079 }
3080
3081 ifrp = ifc.ifc_req;
3082 num_interfaces = ifc.ifc_len / sizeof(*ifr);
3083
3084 for (i = 0; i < num_interfaces; i++) {
3085 ifr = &ifrp[i];
3086 if (!ioctl(s, SIOCGIFHWADDR, ifr)) {
3087 unsigned char *hwaddr = (unsigned char *) ifr->ifr_hwaddr.sa_data;
3088
3089 if (!(memcmp(hwaddr, &empty_mac, 6) && memcmp(hwaddr, &full_mac, 6))) {
3090 continue;
3091 }
3092
3093 memcpy(eid, hwaddr, sizeof(*eid));
3094 ast_debug(1, "Seeding global EID '%s' from '%s' using 'siocgifhwaddr'\n",
3095 ast_eid_to_str(eid_str, sizeof(eid_str), eid), ifr->ifr_name);
3096 ast_free(buf);
3097 close(s);
3098 return;
3099 }
3100 }
3101
3102 ast_log(LOG_WARNING, "No ethernet interface found for seeding global EID. "
3103 "You will have to set it manually.\n");
3104 ast_free(buf);
3105 close(s);
3106
3107 return;
3108}
3109#endif /* LINUX */
3110
3111int ast_str_to_eid(struct ast_eid *eid, const char *s)
3112{
3113 unsigned int eid_int[6];
3114 int x;
3115
3116 if (sscanf(s, "%2x:%2x:%2x:%2x:%2x:%2x", &eid_int[0], &eid_int[1], &eid_int[2],
3117 &eid_int[3], &eid_int[4], &eid_int[5]) != 6) {
3118 return -1;
3119 }
3120
3121 for (x = 0; x < 6; x++) {
3122 eid->eid[x] = eid_int[x];
3123 }
3124
3125 return 0;
3126}
3127
3128int ast_eid_cmp(const struct ast_eid *eid1, const struct ast_eid *eid2)
3129{
3130 return memcmp(eid1, eid2, sizeof(*eid1));
3131}
3132
3133int ast_eid_is_empty(const struct ast_eid *eid)
3134{
3135 struct ast_eid empty_eid;
3136
3137 memset(&empty_eid, 0, sizeof(empty_eid));
3138 return memcmp(eid, &empty_eid, sizeof(empty_eid)) ? 0 : 1;
3139}
3140
3141int ast_file_is_readable(const char *filename)
3142{
3143#if defined(HAVE_EACCESS) || defined(HAVE_EUIDACCESS)
3144#if defined(HAVE_EUIDACCESS) && !defined(HAVE_EACCESS)
3145#define eaccess euidaccess
3146#endif
3147 return eaccess(filename, R_OK) == 0;
3148#else
3149 int fd = open(filename, O_RDONLY | O_NONBLOCK);
3150 if (fd < 0) {
3151 return 0;
3152 }
3153 close(fd);
3154 return 1;
3155#endif
3156}
3157
3158int ast_compare_versions(const char *version1, const char *version2)
3159{
3160 unsigned int major[2] = { 0 };
3161 unsigned int minor[2] = { 0 };
3162 unsigned int patch[2] = { 0 };
3163 unsigned int extra[2] = { 0 };
3164 int res;
3165
3166 sscanf(version1, "%u.%u.%u.%u", &major[0], &minor[0], &patch[0], &extra[0]);
3167 sscanf(version2, "%u.%u.%u.%u", &major[1], &minor[1], &patch[1], &extra[1]);
3168
3169 res = major[0] - major[1];
3170 if (res) {
3171 return res;
3172 }
3173 res = minor[0] - minor[1];
3174 if (res) {
3175 return res;
3176 }
3177 res = patch[0] - patch[1];
3178 if (res) {
3179 return res;
3180 }
3181 return extra[0] - extra[1];
3182}
3183
3184int __ast_fd_set_flags(int fd, int flags, enum ast_fd_flag_operation op,
3185 const char *file, int lineno, const char *function)
3186{
3187 int f;
3188
3189 f = fcntl(fd, F_GETFL);
3190 if (f == -1) {
3191 ast_log(__LOG_ERROR, file, lineno, function,
3192 "Failed to get fcntl() flags for file descriptor: %s\n", strerror(errno));
3193 return -1;
3194 }
3195
3196 switch (op) {
3197 case AST_FD_FLAG_SET:
3198 if ((f & flags) == flags) {
3199 /* There is nothing to set */
3200 return 0;
3201 }
3202 f |= flags;
3203 break;
3204 case AST_FD_FLAG_CLEAR:
3205 if (!(f & flags)) {
3206 /* There is nothing to clear */
3207 return 0;
3208 }
3209 f &= ~flags;
3210 break;
3211 default:
3212 ast_assert(0);
3213 break;
3214 }
3215
3216 f = fcntl(fd, F_SETFL, f);
3217 if (f == -1) {
3218 ast_log(__LOG_ERROR, file, lineno, function,
3219 "Failed to set fcntl() flags for file descriptor: %s\n", strerror(errno));
3220 return -1;
3221 }
3222
3223 return 0;
3224}
3225
3226#ifndef HAVE_SOCK_NONBLOCK
3227int ast_socket_nonblock(int domain, int type, int protocol)
3228{
3229 int s = socket(domain, type, protocol);
3230 if (s < 0) {
3231 return -1;
3232 }
3233
3234 if (ast_fd_set_flags(s, O_NONBLOCK)) {
3235 close(s);
3236 return -1;
3237 }
3238
3239 return s;
3240}
3241#endif
3242
3243#ifndef HAVE_PIPE2
3244int ast_pipe_nonblock(int filedes[2])
3245{
3246 int p = pipe(filedes);
3247 if (p < 0) {
3248 return -1;
3249 }
3250
3251 if (ast_fd_set_flags(filedes[0], O_NONBLOCK)
3252 || ast_fd_set_flags(filedes[1], O_NONBLOCK)) {
3253 close(filedes[0]);
3254 close(filedes[1]);
3255 return -1;
3256 }
3257
3258 return 0;
3259}
3260#endif
3261
3262/*!
3263 * \brief A thread local indicating whether the current thread is a user interface.
3264 */
3265AST_THREADSTORAGE(thread_user_interface_tl);
3266
3267int ast_thread_user_interface_set(int is_user_interface)
3268{
3269 int *thread_user_interface;
3270
3271 thread_user_interface = ast_threadstorage_get(
3272 &thread_user_interface_tl, sizeof(*thread_user_interface));
3273 if (thread_user_interface == NULL) {
3274 ast_log(LOG_ERROR, "Error setting user interface status for current thread\n");
3275 return -1;
3276 }
3277
3278 *thread_user_interface = !!is_user_interface;
3279 return 0;
3280}
3281
3283{
3284 int *thread_user_interface;
3285
3286 thread_user_interface = ast_threadstorage_get(
3287 &thread_user_interface_tl, sizeof(*thread_user_interface));
3288 if (thread_user_interface == NULL) {
3289 ast_log(LOG_ERROR, "Error checking thread's user interface status\n");
3290 /* On error, assume that we are not a user interface thread */
3291 return 0;
3292 }
3293
3294 return *thread_user_interface;
3295}
3296
3297int ast_check_command_in_path(const char *cmd)
3298{
3299 char *token, *saveptr, *path = getenv("PATH");
3300 char filename[PATH_MAX];
3301 int len;
3302
3303 if (path == NULL) {
3304 return 0;
3305 }
3306
3307 path = ast_strdup(path);
3308 if (path == NULL) {
3309 return 0;
3310 }
3311
3312 token = strtok_r(path, ":", &saveptr);
3313 while (token != NULL) {
3314 len = snprintf(filename, sizeof(filename), "%s/%s", token, cmd);
3315 if (len < 0 || len >= sizeof(filename)) {
3316 ast_log(LOG_WARNING, "Path constructed with '%s' too long; skipping\n", token);
3317 continue;
3318 }
3319
3320 if (access(filename, X_OK) == 0) {
3321 ast_free(path);
3322 return 1;
3323 }
3324
3325 token = strtok_r(NULL, ":", &saveptr);
3326 }
3327 ast_free(path);
3328 return 0;
3329}
3330
void ast_cli_unregister_multiple(void)
Definition ael_main.c:408
const char * str
Definition app_jack.c:150
pthread_t thread
Definition app_sla.c:335
ast_mutex_t lock
Definition app_sla.c:337
Asterisk version information.
const char * ast_get_version(void)
Retrieve the Asterisk version string.
char * strsep(char **str, const char *delims)
Asterisk main include file. File version handling, generic pbx functions.
int ast_register_cleanup(void(*func)(void))
Register a function to be executed before Asterisk gracefully exits.
Definition clicompat.c:19
#define PATH_MAX
Definition asterisk.h:40
void ast_std_free(void *ptr)
Definition astmm.c:1734
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition astmm.h:288
#define ast_free(a)
Definition astmm.h:180
#define ast_strdup(str)
A wrapper for strdup()
Definition astmm.h:241
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition astmm.h:298
#define ast_asprintf(ret, fmt,...)
A wrapper for asprintf()
Definition astmm.h:267
#define ast_calloc(num, len)
A wrapper for calloc()
Definition astmm.h:202
#define ast_malloc(len)
A wrapper for malloc()
Definition astmm.h:191
#define ast_log
Definition astobj2.c:42
#define ast_bt_free_symbols(string_vector)
Definition backtrace.h:42
#define ast_bt_get_symbols(addresses, num_frames)
Definition backtrace.h:41
static PGresult * result
Definition cel_pgsql.c:84
static const char type[]
static int request(void *obj)
ast_lock_type
Definition check_expr.c:35
@ AST_RDLOCK
Definition check_expr.c:37
@ AST_WRLOCK
Definition check_expr.c:38
@ AST_MUTEX
Definition check_expr.c:36
Standard Command Line Interface.
#define CLI_SUCCESS
Definition cli.h:44
#define AST_CLI_DEFINE(fn, txt,...)
Definition cli.h:197
void ast_cli(int fd, const char *fmt,...)
Definition clicompat.c:6
int ast_cli_allow_at_shutdown(struct ast_cli_entry *e)
Allow a CLI command to be executed while Asterisk is shutting down.
Definition main/cli.c:3145
@ CLI_INIT
Definition cli.h:152
@ CLI_GENERATE
Definition cli.h:153
#define CLI_FAILURE
Definition cli.h:46
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition cli.h:265
char * end
Definition eagi_proxy.c:73
char buf[BUFSIZE]
Definition eagi_proxy.c:66
void ast_mark_lock_failed(void *lock_addr)
Definition extconf.c:2311
#define max(a, b)
Definition f2c.h:198
static const char name[]
Definition format_mp3.c:68
static const struct ast_datastore_info lock_info
Definition func_lock.c:136
static int md5(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
Definition func_md5.c:55
static int quote(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
Configuration File Parser.
#define __LOG_ERROR
#define AST_LOG_WARNING
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_ERROR
#define LOG_NOTICE
#define LOG_WARNING
void ast_log_backtrace(void)
Log a backtrace of the current thread's execution stack to the Asterisk log.
Definition logger.c:2480
I/O Management (derived from Cheops-NG)
A set of macros to manage forward-linked lists.
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
#define AST_LIST_HEAD_NOLOCK_STATIC(name, type)
Defines a structure to be used to hold a list of specified type, statically initialized.
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
#define AST_LIST_REMOVE(head, elm, field)
Removes a specific entry from a list.
Asterisk locking-related definitions:
#define gethostbyname
Definition lock.h:646
#define pthread_create
Definition lock.h:649
#define pthread_mutex_lock
Definition lock.h:632
#define ast_mutex_unlock(a)
Definition lock.h:197
#define pthread_mutex_t
Definition lock.h:629
#define AST_MUTEX_KIND
Definition lock.h:84
#define pthread_mutex_unlock
Definition lock.h:633
#define pthread_mutex_destroy
Definition lock.h:636
#define ast_mutex_lock(a)
Definition lock.h:196
#define AST_MUTEX_DEFINE_STATIC(mutex)
Definition lock.h:527
#define pthread_mutex_init
Definition lock.h:635
#define R_OK
int errno
MD5 digest functions.
void MD5Update(struct MD5Context *context, unsigned char const *buf, unsigned len)
Definition md5.c:72
void MD5Init(struct MD5Context *context)
Definition md5.c:57
void MD5Final(unsigned char digest[MD5_DIGEST_LENGTH], struct MD5Context *context)
Definition md5.c:120
Wrapper for network related headers, masking differences between various operating systems....
static dundi_eid empty_eid
Definition pbx_dundi.c:223
#define ast_poll(a, b, c)
Definition poll-compat.h:88
const char * string
#define NULL
Definition resample.c:96
int SHA1Result(SHA1Context *, uint8_t Message_Digest[SHA1HashSize])
SHA1Result Returns the resulting 160-bit digest.
Definition sha1.c:226
int SHA1Input(SHA1Context *, const uint8_t *bytes, unsigned int bytecount)
int SHA1Reset(SHA1Context *)
SHA1Reset.
Definition sha1.c:101
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
const char * ast_string_field
#define ast_string_field_ptr_set(x, ptr, data)
Set a field to a simple string value.
String manipulation functions.
char * ast_str_truncate(struct ast_str *buf, ssize_t len)
Truncates the enclosed string to the given length.
Definition strings.h:786
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition strings.h:1139
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition strings.h:65
@ AST_STRSEP_TRIM
Definition strings.h:256
@ AST_STRSEP_UNESCAPE
Definition strings.h:257
@ AST_STRSEP_STRIP
Definition strings.h:255
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition strings.h:659
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition strings.h:1113
char *attribute_pure ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition strings.h:761
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition strings.h:425
static int force_inline attribute_pure ast_begins_with(const char *str, const char *prefix)
Checks whether a string begins with another.
Definition strings.h:97
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
Definition strings.h:223
char *attribute_pure ast_skip_blanks(const char *str)
Gets a pointer to the first non-whitespace character in a string.
Definition strings.h:161
A structure to hold backtrace information. This structure provides an easy means to store backtrace i...
Definition backtrace.h:50
void * addresses[AST_MAX_BT_FRAMES]
Definition backtrace.h:52
int num_frames
Definition backtrace.h:54
descriptor for a cli entry.
Definition cli.h:171
char * command
Definition cli.h:186
const char * usage
Definition cli.h:177
const char * type
Definition datastore.h:32
An Entity ID is essentially a MAC address, brief and unique.
Definition utils.h:853
unsigned char eid[6]
Definition utils.h:854
Structure used to handle boolean flags.
Definition utils.h:220
char buf[1024]
Definition utils.h:231
struct hostent hp
Definition utils.h:230
Lock tracking information.
Definition lock.h:118
int reentrancy
Definition lock.h:121
int lineno[AST_MAX_REENTRANCY]
Definition lock.h:120
const char * file[AST_MAX_REENTRANCY]
Definition lock.h:119
const char * func[AST_MAX_REENTRANCY]
Definition lock.h:122
Structure for mutex and tracking information.
Definition lock.h:142
Support for dynamic strings.
Definition strings.h:623
String vector definitions.
Definition vector.h:55
Structure used for base64 encoding.
Definition utils.c:577
int iolen
Definition utils.c:579
unsigned char iobuf[BASEMAXINLINE]
Definition utils.c:582
int linelength
Definition utils.c:580
int ateof
Definition utils.c:581
int iocp
Definition utils.c:578
const char * name
char * name
Definition utils.c:1597
void * data
Definition utils.c:1596
void *(* start_routine)(void *)
Definition utils.c:1595
static struct test_val b
static struct test_val a
static struct test_val d
static struct test_val c
Definitions to aid in the use of thread local storage.
#define AST_THREADSTORAGE_CUSTOM(a, b, c)
Define a thread storage variable, with custom initialization and cleanup.
void * ast_threadstorage_get(struct ast_threadstorage *ts, size_t init_size)
Retrieve thread storage.
#define AST_THREADSTORAGE(name)
Define a thread storage variable.
Time-related functions and macros.
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
Definition time.h:107
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition time.h:159
FILE * out
Definition utils/frame.c:33
char * ast_to_camel_case_delim(const char *s, const char *delim)
Attempts to convert the given string to camel case using the specified delimiter.
Definition utils.c:2431
int ast_thread_is_user_interface(void)
Indicates whether the current thread is a user interface.
Definition utils.c:3282
void ast_unescape_quoted(char *quote_str)
Unescape quotes in a string.
Definition utils.c:876
static char base64[64]
Definition utils.c:80
int ast_base64url_encode_full(char *dst, const unsigned char *src, int srclen, int max, int linebreaks)
Same as ast_base64encode_full but for base64 URL.
Definition utils.c:469
int ast_base64_encode_file(FILE *inputfile, FILE *outputfile, const char *endl)
Performs a base 64 encode algorithm on the contents of a File.
Definition utils.c:646
#define BASELINELEN
Definition utils.c:573
int ast_base64decode(unsigned char *dst, const char *src, int max)
decode BASE64 encoded text
Definition utils.c:296
int ast_check_command_in_path(const char *cmd)
Test for the presence of an executable command in $PATH.
Definition utils.c:3297
int ast_safe_mkdir(const char *base_path, const char *path, int mode)
Recursively create directory path, but only if it resolves within the given base_path.
Definition utils.c:2618
static char base64url[64]
Definition utils.c:81
static int dev_urandom_fd
Definition utils.c:972
int ast_xml_escape(const char *string, char *const outbuf, const size_t buflen)
Escape reserved characters for use in XML.
Definition utils.c:898
char * ast_base64url_encode_string(const char *src)
Encode string in base64 URL.
Definition utils.c:521
int ast_file_is_readable(const char *filename)
Test that a file exists and is readable by the effective user.
Definition utils.c:3141
int ast_carefulwrite(int fd, char *s, int len, int timeoutms)
Try to write string, but wait no more than ms milliseconds before timing out.
Definition utils.c:1805
int ast_get_time_t(const char *src, time_t *dst, time_t _default, int *consumed)
get values from config variables.
Definition utils.c:2480
int __ast_fd_set_flags(int fd, int flags, enum ast_fd_flag_operation op, const char *file, int lineno, const char *function)
Definition utils.c:3184
int ast_background_stacksize(void)
Definition utils.c:1650
char escape_sequences[]
Definition utils.c:2056
char * ast_utils_which(const char *binary, char *fullpath, size_t fullpath_size)
Resolve a binary to a full pathname.
Definition utils.c:2808
char * ast_uri_encode(const char *string, char *outbuf, int buflen, struct ast_flags spec)
Turn text string to URI-encoded XX version.
Definition utils.c:721
void ast_set_default_eid(struct ast_eid *eid)
Fill in an ast_eid with the default eid of this machine.
Definition utils.c:3035
int ast_thread_user_interface_set(int is_user_interface)
Set the current thread's user interface status.
Definition utils.c:3267
int ast_eid_cmp(const struct ast_eid *eid1, const struct ast_eid *eid2)
Compare two EIDs.
Definition utils.c:3128
char * ast_escape_quoted(const char *string, char *outbuf, int buflen)
Escape characters found in a quoted string.
Definition utils.c:815
static void * dummy_start(void *data)
Definition utils.c:1607
int ast_base64encode(char *dst, const unsigned char *src, int srclen, int max)
Encode data in base64.
Definition utils.c:404
char * ast_unescape_c(char *src)
Convert some C escape sequences.
Definition utils.c:2017
static int inchar(struct baseio *bio, FILE *fi)
utility used by base_encode()
Definition utils.c:613
int ast_build_string(char **buffer, size_t *space, const char *fmt,...)
Build a string in a buffer, designed to be called repeatedly.
Definition utils.c:2201
int ast_wait_for_input(int fd, int ms)
Definition utils.c:1732
int ast_parse_digest(const char *digest, struct ast_http_digest *d, int request, int pedantic)
Parse digest authorization header.
Definition utils.c:2672
char * ast_base64decode_string(const char *src)
Decode BASE64 encoded text and return the string.
Definition utils.c:321
void ast_format_duration_hh_mm_ss(int duration, char *buf, size_t length)
Formats a duration into HH:MM:SS.
Definition utils.c:2331
#define ONE_MILLION
Definition utils.c:2267
static void utils_shutdown(void)
Definition utils.c:2642
int ast_get_timeval(const char *src, struct timeval *dst, struct timeval _default, int *consumed)
get values from config variables.
Definition utils.c:2453
char * ast_unescape_semicolon(char *s)
Strip backslash for "escaped" semicolons, the string to be stripped (will be modified).
Definition utils.c:1998
char * ast_eid_to_str(char *s, int maxlen, struct ast_eid *eid)
Convert an EID to a string.
Definition utils.c:2873
char * ast_base64encode_string(const char *src)
Encode to BASE64 and return encoded string.
Definition utils.c:410
char * ast_escape_c(char *dest, const char *s, size_t size)
Escape standard 'C' sequences in the given string.
Definition utils.c:2111
int ast_get_tid(void)
Get current thread ID.
Definition utils.c:2786
char * ast_strsep(char **iss, const char sep, uint32_t flags)
Act like strsep but ignore separators inside quotes.
Definition utils.c:1869
long int ast_random(void)
Definition utils.c:2346
static void base64_init(void)
Definition utils.c:538
int ast_mkdir(const char *path, int mode)
Recursively create directory path.
Definition utils.c:2513
int ast_build_string_va(char **buffer, size_t *space, const char *fmt, va_list ap)
Build a string in a buffer, designed to be called repeatedly.
Definition utils.c:2182
char * ast_escape_alloc(const char *s, const char *to_escape)
Escape the 'to_escape' characters in the given string.
Definition utils.c:2166
const struct ast_flags ast_uri_http
Definition utils.c:717
int ast_utils_init(void)
Definition utils.c:2651
int ast_wait_for_output(int fd, int ms)
Definition utils.c:1742
static char * escape_alloc(const char *s, size_t *size)
Definition utils.c:2152
static char b2a[256]
Definition utils.c:82
void ast_enable_packet_fragmentation(int sock)
Disable PMTU discovery on a socket.
Definition utils.c:2503
#define BASEMAXINLINE
Definition utils.c:574
int ast_base64url_decode(unsigned char *dst, const char *src, int max)
Decode data from base64 URL.
Definition utils.c:427
int ast_compare_versions(const char *version1, const char *version2)
Compare 2 major.minor.patch.extra version strings.
Definition utils.c:3158
char * ast_strsep_quoted(char **iss, const char sep, const char quote, uint32_t flags)
Like ast_strsep() except you can specify a specific quote character.
Definition utils.c:1933
int ast_remaining_ms(struct timeval start, int max_ms)
Calculate remaining milliseconds given a starting timestamp and upper bound.
Definition utils.c:2315
int ast_eid_is_empty(const struct ast_eid *eid)
Check if EID is empty.
Definition utils.c:3133
char * ast_strip_quoted(char *s, const char *beg_quotes, const char *end_quotes)
Strip leading/trailing whitespace and quotes from a string.
Definition utils.c:1852
int ast_base64url_encode(char *dst, const unsigned char *src, int srclen, int max)
Encode data in base64 URL.
Definition utils.c:516
struct timeval ast_tvadd(struct timeval a, struct timeval b)
Returns the sum of two timevals a + b.
Definition utils.c:2287
void DO_CRASH_NORETURN ast_do_crash(void)
Force a crash if DO_CRASH is defined.
Definition utils.c:2838
char * ast_process_quotes_and_slashes(char *start, char find, char replace_with)
Process a string to find and replace characters.
Definition utils.c:2386
struct timeval ast_tvsub(struct timeval a, struct timeval b)
Returns the difference of two timevals a - b.
Definition utils.c:2301
static int safe_mkdir(const char *base_path, char *path, int mode)
Definition utils.c:2548
static char b2a_url[256]
Definition utils.c:83
char * ast_escape_semicolons(const char *string, char *outbuf, int buflen)
Escape semicolons found in a string.
Definition utils.c:845
int ast_false(const char *s)
Make sure something is false. Determine if a string containing a boolean value is "false"....
Definition utils.c:2250
static char escape_sequences_map[]
Definition utils.c:2064
int ast_base64encode_full(char *dst, const unsigned char *src, int srclen, int max, int linebreaks)
encode text to BASE64 coding
Definition utils.c:353
int ast_true(const char *s)
Make sure something is true. Determine if a string containing a boolean value is "true"....
Definition utils.c:2233
void ast_sha1_hash_uint(uint8_t *digest, const char *input)
Produce a 20 byte SHA1 hash of value.
Definition utils.c:284
static int inbuf(struct baseio *bio, FILE *fi)
utility used by inchar(), for base_encode()
Definition utils.c:588
static int ochar(struct baseio *bio, int c, FILE *so, const char *endl)
utility used by base_encode()
Definition utils.c:627
int ast_uri_verify_encoded(const char *string)
Verify if a string is valid as a URI component.
Definition utils.c:779
int ast_check_ipv6(void)
Test that an OS supports IPv6 Networking.
Definition utils.c:2826
char * ast_base64url_decode_string(const char *src)
Decode string from base64 URL.
Definition utils.c:448
char * ast_escape_c_alloc(const char *s)
Escape standard 'C' sequences in the given string.
Definition utils.c:2174
const char * ast_inet_ntoa(struct in_addr ia)
ast_inet_ntoa: Recursive thread safe replacement of inet_ntoa
Definition utils.c:962
int ast_str_to_eid(struct ast_eid *eid, const char *s)
Convert a string into an EID.
Definition utils.c:3111
void ast_uri_decode(char *s, struct ast_flags spec)
Decode URI, URN, URL (overwrite string)
Definition utils.c:760
int ast_base64_encode_file_path(const char *filename, FILE *outputfile, const char *endl)
Performs a base 64 encode algorithm on the contents of a File.
Definition utils.c:700
struct hostent * ast_gethostbyname(const char *host, struct ast_hostent *hp)
Re-entrant (thread safe) version of gethostbyname that replaces the standard gethostbyname (which is ...
Definition utils.c:199
static struct timeval tvfix(struct timeval a)
Definition utils.c:2272
void ast_replace_subargument_delimiter(char *s)
Replace '^' in a string with ','.
Definition utils.c:2377
void DO_CRASH_NORETURN __ast_assert_failed(int condition, const char *condition_str, const char *file, int line, const char *function)
Definition utils.c:2850
const struct ast_flags ast_uri_sip_user
Definition utils.c:719
void ast_md5_hash(char *output, const char *input)
Produce 32 char MD5 hash of value.
Definition utils.c:250
int ast_pthread_create_detached_stack(pthread_t *thread, pthread_attr_t *attr, void *(*start_routine)(void *), void *data, size_t stacksize, const char *file, const char *caller, int line, const char *start_fn)
Definition utils.c:1707
void ast_sha1_hash(char *output, const char *input)
Produce 40 char SHA1 hash of value.
Definition utils.c:266
int ast_pthread_create_stack(pthread_t *thread, pthread_attr_t *attr, void *(*start_routine)(void *), void *data, size_t stacksize, const char *file, const char *caller, int line, const char *start_fn)
Definition utils.c:1659
int ast_regex_string_to_regex_pattern(const char *regex_string, struct ast_str **regex_pattern)
Given a string regex_string in the form of "/regex/", convert it into the form of "regex".
Definition utils.c:2213
const struct ast_flags ast_uri_http_legacy
Definition utils.c:718
static int wait_for_output(int fd, int timeoutms)
Definition utils.c:1752
void ast_join_delim(char *s, size_t len, const char *const w[], unsigned int size, char delim)
Join an array of strings into a single string.
Definition utils.c:2412
char * ast_escape(char *dest, const char *s, size_t size, const char *to_escape)
Escape the 'to_escape' characters in the given string.
Definition utils.c:2068
static ast_mutex_t randomlock
Definition utils.c:2343
Utility functions.
#define ast_test_flag(p, flag)
Definition utils.h:64
#define AST_URI_LEGACY_SPACE
Definition utils.h:388
#define AST_URI_MARK
Definition utils.h:386
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition utils.h:981
#define ast_assert(a)
Definition utils.h:779
#define AST_URI_SIP_USER_UNRESERVED
Definition utils.h:390
#define DO_CRASH_NORETURN
Definition utils.h:757
ast_fd_flag_operation
Definition utils.h:1061
@ AST_FD_FLAG_SET
Definition utils.h:1062
@ AST_FD_FLAG_CLEAR
Definition utils.h:1063
#define AST_URI_ALPHANUM
Definition utils.h:385
#define AST_STACKSIZE
Definition utils.h:605
#define ast_socket_nonblock(domain, type, protocol)
Create a non-blocking socket.
Definition utils.h:1113
#define AST_URI_UNRESERVED
Definition utils.h:387
#define AST_STACKSIZE_LOW
Definition utils.h:606
#define ast_fd_set_flags(fd, flags)
Set flags on the given file descriptor.
Definition utils.h:1079
void ast_register_thread(char *name)
Definition asterisk.c:422
void ast_unregister_thread(void *id)
Definition asterisk.c:438
#define ast_pipe_nonblock(filedes)
Create a non-blocking pipe.
Definition utils.h:1130
#define ARRAY_LEN(a)
Definition utils.h:706
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition vector.h:620
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition vector.h:691