Merge lp:~davewalker/ubuntu/lucid/asterisk/lp_705014 into lp:ubuntu/lucid/asterisk

Proposed by Dave Walker
Status: Superseded
Proposed branch: lp:~davewalker/ubuntu/lucid/asterisk/lp_705014
Merge into: lp:ubuntu/lucid/asterisk
Diff against target: 4314 lines (+4076/-31)
18 files modified
.pc/.quilt_patches (+1/-0)
.pc/.quilt_series (+1/-0)
.pc/AST-2011-001-1.6.2/main/utils.c (+1828/-0)
.pc/applied-patches (+3/-0)
.pc/dnsmgr-A-SRV-handling/include/asterisk/dnsmgr.h (+105/-0)
.pc/dnsmgr-A-SRV-handling/main/acl.c (+541/-0)
.pc/dnsmgr-A-SRV-handling/main/dnsmgr.c (+439/-0)
.pc/unattended_fix/channels/chan_local.c (+885/-0)
channels/chan_local.c (+4/-3)
debian/changelog (+27/-0)
debian/patches/AST-2011-001-1.6.2 (+52/-0)
debian/patches/dnsmgr-A-SRV-handling (+132/-0)
debian/patches/series (+3/-0)
debian/patches/unattended_fix (+18/-0)
include/asterisk/dnsmgr.h (+4/-3)
main/acl.c (+1/-0)
main/dnsmgr.c (+18/-10)
main/utils.c (+14/-15)
To merge this branch: bzr merge lp:~davewalker/ubuntu/lucid/asterisk/lp_705014
Reviewer Review Type Date Requested Status
Jamie Strandboge Disapprove
Review via email: mp+46997@code.launchpad.net

This proposal has been superseded by a proposal from 2011-01-20.

Description of the change

Waiting on 1:1.6.2.5-0ubuntu1.2 to clear -proposed, which has verification-done.

To post a comment you must log in.
Revision history for this message
Jamie Strandboge (jdstrand) :
review: Disapprove

Unmerged revisions

59. By Dave Walker

* SECURITY UPDATE: Stack buffer overflow in SIP channel driver. (LP: #705014)
  - debian/patches/AST-2011-001-1.6.2: The size of the output buffer passed
    to the ast_uri_encode function is now properly respected in main/utils.c.
    Patch courtesy of upstream.
  - CVE-2011-0495

58. By Lionel Porcheron

debian/patches/unattended_fix: Fix attended transfer call in 1.2.6.5
Patch based on Asterisk project's upstream patch (between 1.2.6.5 and
1.2.6.6 where issue is declared to be fixed see issue 16816 on Asterisk
bug tracker). (LP: #686625)

57. By Dave Walker

debian/patches/dnsmgr-A-SRV-handling: Resolve handling of A and SRV
record changes and problem with multiple A/SRV records returned.
Patch based on Asterisk project's upstream patch. (LP: #605358)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== added file '.pc/.quilt_patches'
--- .pc/.quilt_patches 1970-01-01 00:00:00 +0000
+++ .pc/.quilt_patches 2011-01-20 23:43:55 +0000
@@ -0,0 +1,1 @@
1debian/patches
02
=== added file '.pc/.quilt_series'
--- .pc/.quilt_series 1970-01-01 00:00:00 +0000
+++ .pc/.quilt_series 2011-01-20 23:43:55 +0000
@@ -0,0 +1,1 @@
1series
02
=== added directory '.pc/AST-2011-001-1.6.2'
=== added file '.pc/AST-2011-001-1.6.2/.timestamp'
=== added directory '.pc/AST-2011-001-1.6.2/main'
=== added file '.pc/AST-2011-001-1.6.2/main/utils.c'
--- .pc/AST-2011-001-1.6.2/main/utils.c 1970-01-01 00:00:00 +0000
+++ .pc/AST-2011-001-1.6.2/main/utils.c 2011-01-20 23:43:55 +0000
@@ -0,0 +1,1828 @@
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#include "asterisk.h"
27
28ASTERISK_FILE_VERSION(__FILE__, "$Revision: 237743 $")
29
30#include <ctype.h>
31#include <sys/stat.h>
32
33#ifdef HAVE_DEV_URANDOM
34#include <fcntl.h>
35#endif
36
37#include "asterisk/network.h"
38
39#define AST_API_MODULE /* ensure that inlinable API functions will be built in lock.h if required */
40#include "asterisk/lock.h"
41#include "asterisk/io.h"
42#include "asterisk/md5.h"
43#include "asterisk/sha1.h"
44#include "asterisk/cli.h"
45#include "asterisk/linkedlists.h"
46
47#define AST_API_MODULE /* ensure that inlinable API functions will be built in this module if required */
48#include "asterisk/strings.h"
49
50#define AST_API_MODULE /* ensure that inlinable API functions will be built in this module if required */
51#include "asterisk/time.h"
52
53#define AST_API_MODULE /* ensure that inlinable API functions will be built in this module if required */
54#include "asterisk/stringfields.h"
55
56#define AST_API_MODULE /* ensure that inlinable API functions will be built in this module if required */
57#include "asterisk/utils.h"
58
59#define AST_API_MODULE
60#include "asterisk/threadstorage.h"
61
62#define AST_API_MODULE
63#include "asterisk/config.h"
64
65static char base64[64];
66static char b2a[256];
67
68AST_THREADSTORAGE(inet_ntoa_buf);
69
70#if !defined(HAVE_GETHOSTBYNAME_R_5) && !defined(HAVE_GETHOSTBYNAME_R_6)
71
72#define ERANGE 34 /*!< duh? ERANGE value copied from web... */
73#undef gethostbyname
74
75AST_MUTEX_DEFINE_STATIC(__mutex);
76
77/*! \brief Reentrant replacement for gethostbyname for BSD-based systems.
78\note This
79routine is derived from code originally written and placed in the public
80domain by Enzo Michelangeli <em@em.no-ip.com> */
81
82static int gethostbyname_r (const char *name, struct hostent *ret, char *buf,
83 size_t buflen, struct hostent **result,
84 int *h_errnop)
85{
86 int hsave;
87 struct hostent *ph;
88 ast_mutex_lock(&__mutex); /* begin critical area */
89 hsave = h_errno;
90
91 ph = gethostbyname(name);
92 *h_errnop = h_errno; /* copy h_errno to *h_herrnop */
93 if (ph == NULL) {
94 *result = NULL;
95 } else {
96 char **p, **q;
97 char *pbuf;
98 int nbytes = 0;
99 int naddr = 0, naliases = 0;
100 /* determine if we have enough space in buf */
101
102 /* count how many addresses */
103 for (p = ph->h_addr_list; *p != 0; p++) {
104 nbytes += ph->h_length; /* addresses */
105 nbytes += sizeof(*p); /* pointers */
106 naddr++;
107 }
108 nbytes += sizeof(*p); /* one more for the terminating NULL */
109
110 /* count how many aliases, and total length of strings */
111 for (p = ph->h_aliases; *p != 0; p++) {
112 nbytes += (strlen(*p)+1); /* aliases */
113 nbytes += sizeof(*p); /* pointers */
114 naliases++;
115 }
116 nbytes += sizeof(*p); /* one more for the terminating NULL */
117
118 /* here nbytes is the number of bytes required in buffer */
119 /* as a terminator must be there, the minimum value is ph->h_length */
120 if (nbytes > buflen) {
121 *result = NULL;
122 ast_mutex_unlock(&__mutex); /* end critical area */
123 return ERANGE; /* not enough space in buf!! */
124 }
125
126 /* There is enough space. Now we need to do a deep copy! */
127 /* Allocation in buffer:
128 from [0] to [(naddr-1) * sizeof(*p)]:
129 pointers to addresses
130 at [naddr * sizeof(*p)]:
131 NULL
132 from [(naddr+1) * sizeof(*p)] to [(naddr+naliases) * sizeof(*p)] :
133 pointers to aliases
134 at [(naddr+naliases+1) * sizeof(*p)]:
135 NULL
136 then naddr addresses (fixed length), and naliases aliases (asciiz).
137 */
138
139 *ret = *ph; /* copy whole structure (not its address!) */
140
141 /* copy addresses */
142 q = (char **)buf; /* pointer to pointers area (type: char **) */
143 ret->h_addr_list = q; /* update pointer to address list */
144 pbuf = buf + ((naddr + naliases + 2) * sizeof(*p)); /* skip that area */
145 for (p = ph->h_addr_list; *p != 0; p++) {
146 memcpy(pbuf, *p, ph->h_length); /* copy address bytes */
147 *q++ = pbuf; /* the pointer is the one inside buf... */
148 pbuf += ph->h_length; /* advance pbuf */
149 }
150 *q++ = NULL; /* address list terminator */
151
152 /* copy aliases */
153 ret->h_aliases = q; /* update pointer to aliases list */
154 for (p = ph->h_aliases; *p != 0; p++) {
155 strcpy(pbuf, *p); /* copy alias strings */
156 *q++ = pbuf; /* the pointer is the one inside buf... */
157 pbuf += strlen(*p); /* advance pbuf */
158 *pbuf++ = 0; /* string terminator */
159 }
160 *q++ = NULL; /* terminator */
161
162 strcpy(pbuf, ph->h_name); /* copy alias strings */
163 ret->h_name = pbuf;
164 pbuf += strlen(ph->h_name); /* advance pbuf */
165 *pbuf++ = 0; /* string terminator */
166
167 *result = ret; /* and let *result point to structure */
168
169 }
170 h_errno = hsave; /* restore h_errno */
171 ast_mutex_unlock(&__mutex); /* end critical area */
172
173 return (*result == NULL); /* return 0 on success, non-zero on error */
174}
175
176
177#endif
178
179/*! \brief Re-entrant (thread safe) version of gethostbyname that replaces the
180 standard gethostbyname (which is not thread safe)
181*/
182struct hostent *ast_gethostbyname(const char *host, struct ast_hostent *hp)
183{
184 int res;
185 int herrno;
186 int dots = 0;
187 const char *s;
188 struct hostent *result = NULL;
189 /* Although it is perfectly legitimate to lookup a pure integer, for
190 the sake of the sanity of people who like to name their peers as
191 integers, we break with tradition and refuse to look up a
192 pure integer */
193 s = host;
194 res = 0;
195 while (s && *s) {
196 if (*s == '.')
197 dots++;
198 else if (!isdigit(*s))
199 break;
200 s++;
201 }
202 if (!s || !*s) {
203 /* Forge a reply for IP's to avoid octal IP's being interpreted as octal */
204 if (dots != 3)
205 return NULL;
206 memset(hp, 0, sizeof(struct ast_hostent));
207 hp->hp.h_addrtype = AF_INET;
208 hp->hp.h_addr_list = (void *) hp->buf;
209 hp->hp.h_addr = hp->buf + sizeof(void *);
210 if (inet_pton(AF_INET, host, hp->hp.h_addr) > 0)
211 return &hp->hp;
212 return NULL;
213
214 }
215#ifdef HAVE_GETHOSTBYNAME_R_5
216 result = gethostbyname_r(host, &hp->hp, hp->buf, sizeof(hp->buf), &herrno);
217
218 if (!result || !hp->hp.h_addr_list || !hp->hp.h_addr_list[0])
219 return NULL;
220#else
221 res = gethostbyname_r(host, &hp->hp, hp->buf, sizeof(hp->buf), &result, &herrno);
222
223 if (res || !result || !hp->hp.h_addr_list || !hp->hp.h_addr_list[0])
224 return NULL;
225#endif
226 return &hp->hp;
227}
228
229/*! \brief Produce 32 char MD5 hash of value. */
230void ast_md5_hash(char *output, char *input)
231{
232 struct MD5Context md5;
233 unsigned char digest[16];
234 char *ptr;
235 int x;
236
237 MD5Init(&md5);
238 MD5Update(&md5, (unsigned char *)input, strlen(input));
239 MD5Final(digest, &md5);
240 ptr = output;
241 for (x = 0; x < 16; x++)
242 ptr += sprintf(ptr, "%2.2x", digest[x]);
243}
244
245/*! \brief Produce 40 char SHA1 hash of value. */
246void ast_sha1_hash(char *output, char *input)
247{
248 struct SHA1Context sha;
249 char *ptr;
250 int x;
251 uint8_t Message_Digest[20];
252
253 SHA1Reset(&sha);
254
255 SHA1Input(&sha, (const unsigned char *) input, strlen(input));
256
257 SHA1Result(&sha, Message_Digest);
258 ptr = output;
259 for (x = 0; x < 20; x++)
260 ptr += sprintf(ptr, "%2.2x", Message_Digest[x]);
261}
262
263/*! \brief decode BASE64 encoded text */
264int ast_base64decode(unsigned char *dst, const char *src, int max)
265{
266 int cnt = 0;
267 unsigned int byte = 0;
268 unsigned int bits = 0;
269 int incnt = 0;
270 while(*src && *src != '=' && (cnt < max)) {
271 /* Shift in 6 bits of input */
272 byte <<= 6;
273 byte |= (b2a[(int)(*src)]) & 0x3f;
274 bits += 6;
275 src++;
276 incnt++;
277 /* If we have at least 8 bits left over, take that character
278 off the top */
279 if (bits >= 8) {
280 bits -= 8;
281 *dst = (byte >> bits) & 0xff;
282 dst++;
283 cnt++;
284 }
285 }
286 /* Dont worry about left over bits, they're extra anyway */
287 return cnt;
288}
289
290/*! \brief encode text to BASE64 coding */
291int ast_base64encode_full(char *dst, const unsigned char *src, int srclen, int max, int linebreaks)
292{
293 int cnt = 0;
294 int col = 0;
295 unsigned int byte = 0;
296 int bits = 0;
297 int cntin = 0;
298 /* Reserve space for null byte at end of string */
299 max--;
300 while ((cntin < srclen) && (cnt < max)) {
301 byte <<= 8;
302 byte |= *(src++);
303 bits += 8;
304 cntin++;
305 if ((bits == 24) && (cnt + 4 <= max)) {
306 *dst++ = base64[(byte >> 18) & 0x3f];
307 *dst++ = base64[(byte >> 12) & 0x3f];
308 *dst++ = base64[(byte >> 6) & 0x3f];
309 *dst++ = base64[byte & 0x3f];
310 cnt += 4;
311 col += 4;
312 bits = 0;
313 byte = 0;
314 }
315 if (linebreaks && (cnt < max) && (col == 64)) {
316 *dst++ = '\n';
317 cnt++;
318 col = 0;
319 }
320 }
321 if (bits && (cnt + 4 <= max)) {
322 /* Add one last character for the remaining bits,
323 padding the rest with 0 */
324 byte <<= 24 - bits;
325 *dst++ = base64[(byte >> 18) & 0x3f];
326 *dst++ = base64[(byte >> 12) & 0x3f];
327 if (bits == 16)
328 *dst++ = base64[(byte >> 6) & 0x3f];
329 else
330 *dst++ = '=';
331 *dst++ = '=';
332 cnt += 4;
333 }
334 if (linebreaks && (cnt < max)) {
335 *dst++ = '\n';
336 cnt++;
337 }
338 *dst = '\0';
339 return cnt;
340}
341
342int ast_base64encode(char *dst, const unsigned char *src, int srclen, int max)
343{
344 return ast_base64encode_full(dst, src, srclen, max, 0);
345}
346
347static void base64_init(void)
348{
349 int x;
350 memset(b2a, -1, sizeof(b2a));
351 /* Initialize base-64 Conversion table */
352 for (x = 0; x < 26; x++) {
353 /* A-Z */
354 base64[x] = 'A' + x;
355 b2a['A' + x] = x;
356 /* a-z */
357 base64[x + 26] = 'a' + x;
358 b2a['a' + x] = x + 26;
359 /* 0-9 */
360 if (x < 10) {
361 base64[x + 52] = '0' + x;
362 b2a['0' + x] = x + 52;
363 }
364 }
365 base64[62] = '+';
366 base64[63] = '/';
367 b2a[(int)'+'] = 62;
368 b2a[(int)'/'] = 63;
369}
370
371/*! \brief ast_uri_encode: Turn text string to URI-encoded %XX version
372\note At this point, we're converting from ISO-8859-x (8-bit), not UTF8
373 as in the SIP protocol spec
374 If doreserved == 1 we will convert reserved characters also.
375 RFC 2396, section 2.4
376 outbuf needs to have more memory allocated than the instring
377 to have room for the expansion. Every char that is converted
378 is replaced by three ASCII characters.
379
380 Note: The doreserved option is needed for replaces header in
381 SIP transfers.
382*/
383char *ast_uri_encode(const char *string, char *outbuf, int buflen, int doreserved)
384{
385 char *reserved = ";/?:@&=+$,# "; /* Reserved chars */
386
387 const char *ptr = string; /* Start with the string */
388 char *out = NULL;
389 char *buf = NULL;
390
391 ast_copy_string(outbuf, string, buflen);
392
393 /* If there's no characters to convert, just go through and don't do anything */
394 while (*ptr) {
395 if ((*ptr < 32) || (doreserved && strchr(reserved, *ptr))) {
396 /* Oops, we need to start working here */
397 if (!buf) {
398 buf = outbuf;
399 out = buf + (ptr - string) ; /* Set output ptr */
400 }
401 out += sprintf(out, "%%%02x", (unsigned char) *ptr);
402 } else if (buf) {
403 *out = *ptr; /* Continue copying the string */
404 out++;
405 }
406 ptr++;
407 }
408 if (buf)
409 *out = '\0';
410 return outbuf;
411}
412
413/*! \brief ast_uri_decode: Decode SIP URI, URN, URL (overwrite the string) */
414void ast_uri_decode(char *s)
415{
416 char *o;
417 unsigned int tmp;
418
419 for (o = s; *s; s++, o++) {
420 if (*s == '%' && strlen(s) > 2 && sscanf(s + 1, "%2x", &tmp) == 1) {
421 /* have '%', two chars and correct parsing */
422 *o = tmp;
423 s += 2; /* Will be incremented once more when we break out */
424 } else /* all other cases, just copy */
425 *o = *s;
426 }
427 *o = '\0';
428}
429
430/*! \brief ast_inet_ntoa: Recursive thread safe replacement of inet_ntoa */
431const char *ast_inet_ntoa(struct in_addr ia)
432{
433 char *buf;
434
435 if (!(buf = ast_threadstorage_get(&inet_ntoa_buf, INET_ADDRSTRLEN)))
436 return "";
437
438 return inet_ntop(AF_INET, &ia, buf, INET_ADDRSTRLEN);
439}
440
441#ifdef HAVE_DEV_URANDOM
442static int dev_urandom_fd;
443#endif
444
445#ifndef __linux__
446#undef pthread_create /* For ast_pthread_create function only */
447#endif /* !__linux__ */
448
449#if !defined(LOW_MEMORY)
450
451#ifdef DEBUG_THREADS
452
453/*! \brief A reasonable maximum number of locks a thread would be holding ... */
454#define AST_MAX_LOCKS 64
455
456/* Allow direct use of pthread_mutex_t and friends */
457#undef pthread_mutex_t
458#undef pthread_mutex_lock
459#undef pthread_mutex_unlock
460#undef pthread_mutex_init
461#undef pthread_mutex_destroy
462
463/*!
464 * \brief Keep track of which locks a thread holds
465 *
466 * There is an instance of this struct for every active thread
467 */
468struct thr_lock_info {
469 /*! The thread's ID */
470 pthread_t thread_id;
471 /*! The thread name which includes where the thread was started */
472 const char *thread_name;
473 /*! This is the actual container of info for what locks this thread holds */
474 struct {
475 const char *file;
476 int line_num;
477 const char *func;
478 const char *lock_name;
479 void *lock_addr;
480 int times_locked;
481 enum ast_lock_type type;
482 /*! This thread is waiting on this lock */
483 int pending:2;
484#ifdef HAVE_BKTR
485 struct ast_bt *backtrace;
486#endif
487 } locks[AST_MAX_LOCKS];
488 /*! This is the number of locks currently held by this thread.
489 * The index (num_locks - 1) has the info on the last one in the
490 * locks member */
491 unsigned int num_locks;
492 /*! Protects the contents of the locks member
493 * Intentionally not ast_mutex_t */
494 pthread_mutex_t lock;
495 AST_LIST_ENTRY(thr_lock_info) entry;
496};
497
498/*!
499 * \brief Locked when accessing the lock_infos list
500 */
501AST_MUTEX_DEFINE_STATIC(lock_infos_lock);
502/*!
503 * \brief A list of each thread's lock info
504 */
505static AST_LIST_HEAD_NOLOCK_STATIC(lock_infos, thr_lock_info);
506
507/*!
508 * \brief Destroy a thread's lock info
509 *
510 * This gets called automatically when the thread stops
511 */
512static void lock_info_destroy(void *data)
513{
514 struct thr_lock_info *lock_info = data;
515 int i;
516
517 pthread_mutex_lock(&lock_infos_lock.mutex);
518 AST_LIST_REMOVE(&lock_infos, lock_info, entry);
519 pthread_mutex_unlock(&lock_infos_lock.mutex);
520
521
522 for (i = 0; i < lock_info->num_locks; i++) {
523 if (lock_info->locks[i].pending == -1) {
524 /* This just means that the last lock this thread went for was by
525 * using trylock, and it failed. This is fine. */
526 break;
527 }
528
529 ast_log(LOG_ERROR,
530 "Thread '%s' still has a lock! - '%s' (%p) from '%s' in %s:%d!\n",
531 lock_info->thread_name,
532 lock_info->locks[i].lock_name,
533 lock_info->locks[i].lock_addr,
534 lock_info->locks[i].func,
535 lock_info->locks[i].file,
536 lock_info->locks[i].line_num
537 );
538 }
539
540 pthread_mutex_destroy(&lock_info->lock);
541 if (lock_info->thread_name)
542 free((void *) lock_info->thread_name);
543 free(lock_info);
544}
545
546/*!
547 * \brief The thread storage key for per-thread lock info
548 */
549AST_THREADSTORAGE_CUSTOM(thread_lock_info, NULL, lock_info_destroy);
550#ifdef HAVE_BKTR
551void ast_store_lock_info(enum ast_lock_type type, const char *filename,
552 int line_num, const char *func, const char *lock_name, void *lock_addr, struct ast_bt *bt)
553#else
554void ast_store_lock_info(enum ast_lock_type type, const char *filename,
555 int line_num, const char *func, const char *lock_name, void *lock_addr)
556#endif
557{
558 struct thr_lock_info *lock_info;
559 int i;
560
561 if (!(lock_info = ast_threadstorage_get(&thread_lock_info, sizeof(*lock_info))))
562 return;
563
564 pthread_mutex_lock(&lock_info->lock);
565
566 for (i = 0; i < lock_info->num_locks; i++) {
567 if (lock_info->locks[i].lock_addr == lock_addr) {
568 lock_info->locks[i].times_locked++;
569#ifdef HAVE_BKTR
570 lock_info->locks[i].backtrace = bt;
571#endif
572 pthread_mutex_unlock(&lock_info->lock);
573 return;
574 }
575 }
576
577 if (lock_info->num_locks == AST_MAX_LOCKS) {
578 /* Can't use ast_log here, because it will cause infinite recursion */
579 fprintf(stderr, "XXX ERROR XXX A thread holds more locks than '%d'."
580 " Increase AST_MAX_LOCKS!\n", AST_MAX_LOCKS);
581 pthread_mutex_unlock(&lock_info->lock);
582 return;
583 }
584
585 if (i && lock_info->locks[i - 1].pending == -1) {
586 /* The last lock on the list was one that this thread tried to lock but
587 * failed at doing so. It has now moved on to something else, so remove
588 * the old lock from the list. */
589 i--;
590 lock_info->num_locks--;
591 memset(&lock_info->locks[i], 0, sizeof(lock_info->locks[0]));
592 }
593
594 lock_info->locks[i].file = filename;
595 lock_info->locks[i].line_num = line_num;
596 lock_info->locks[i].func = func;
597 lock_info->locks[i].lock_name = lock_name;
598 lock_info->locks[i].lock_addr = lock_addr;
599 lock_info->locks[i].times_locked = 1;
600 lock_info->locks[i].type = type;
601 lock_info->locks[i].pending = 1;
602#ifdef HAVE_BKTR
603 lock_info->locks[i].backtrace = bt;
604#endif
605 lock_info->num_locks++;
606
607 pthread_mutex_unlock(&lock_info->lock);
608}
609
610void ast_mark_lock_acquired(void *lock_addr)
611{
612 struct thr_lock_info *lock_info;
613
614 if (!(lock_info = ast_threadstorage_get(&thread_lock_info, sizeof(*lock_info))))
615 return;
616
617 pthread_mutex_lock(&lock_info->lock);
618 if (lock_info->locks[lock_info->num_locks - 1].lock_addr == lock_addr) {
619 lock_info->locks[lock_info->num_locks - 1].pending = 0;
620 }
621 pthread_mutex_unlock(&lock_info->lock);
622}
623
624void ast_mark_lock_failed(void *lock_addr)
625{
626 struct thr_lock_info *lock_info;
627
628 if (!(lock_info = ast_threadstorage_get(&thread_lock_info, sizeof(*lock_info))))
629 return;
630
631 pthread_mutex_lock(&lock_info->lock);
632 if (lock_info->locks[lock_info->num_locks - 1].lock_addr == lock_addr) {
633 lock_info->locks[lock_info->num_locks - 1].pending = -1;
634 lock_info->locks[lock_info->num_locks - 1].times_locked--;
635 }
636 pthread_mutex_unlock(&lock_info->lock);
637}
638
639int 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)
640{
641 struct thr_lock_info *lock_info;
642 int i = 0;
643
644 if (!(lock_info = ast_threadstorage_get(&thread_lock_info, sizeof(*lock_info))))
645 return -1;
646
647 pthread_mutex_lock(&lock_info->lock);
648
649 for (i = lock_info->num_locks - 1; i >= 0; i--) {
650 if (lock_info->locks[i].lock_addr == lock_addr)
651 break;
652 }
653
654 if (i == -1) {
655 /* Lock not found :( */
656 pthread_mutex_unlock(&lock_info->lock);
657 return -1;
658 }
659
660 ast_copy_string(filename, lock_info->locks[i].file, filename_size);
661 *lineno = lock_info->locks[i].line_num;
662 ast_copy_string(func, lock_info->locks[i].func, func_size);
663 ast_copy_string(mutex_name, lock_info->locks[i].lock_name, mutex_name_size);
664
665 pthread_mutex_unlock(&lock_info->lock);
666
667 return 0;
668}
669
670#ifdef HAVE_BKTR
671void ast_remove_lock_info(void *lock_addr, struct ast_bt *bt)
672#else
673void ast_remove_lock_info(void *lock_addr)
674#endif
675{
676 struct thr_lock_info *lock_info;
677 int i = 0;
678
679 if (!(lock_info = ast_threadstorage_get(&thread_lock_info, sizeof(*lock_info))))
680 return;
681
682 pthread_mutex_lock(&lock_info->lock);
683
684 for (i = lock_info->num_locks - 1; i >= 0; i--) {
685 if (lock_info->locks[i].lock_addr == lock_addr)
686 break;
687 }
688
689 if (i == -1) {
690 /* Lock not found :( */
691 pthread_mutex_unlock(&lock_info->lock);
692 return;
693 }
694
695 if (lock_info->locks[i].times_locked > 1) {
696 lock_info->locks[i].times_locked--;
697#ifdef HAVE_BKTR
698 lock_info->locks[i].backtrace = bt;
699#endif
700 pthread_mutex_unlock(&lock_info->lock);
701 return;
702 }
703
704 if (i < lock_info->num_locks - 1) {
705 /* Not the last one ... *should* be rare! */
706 memmove(&lock_info->locks[i], &lock_info->locks[i + 1],
707 (lock_info->num_locks - (i + 1)) * sizeof(lock_info->locks[0]));
708 }
709
710 lock_info->num_locks--;
711
712 pthread_mutex_unlock(&lock_info->lock);
713}
714
715static const char *locktype2str(enum ast_lock_type type)
716{
717 switch (type) {
718 case AST_MUTEX:
719 return "MUTEX";
720 case AST_RDLOCK:
721 return "RDLOCK";
722 case AST_WRLOCK:
723 return "WRLOCK";
724 }
725
726 return "UNKNOWN";
727}
728
729#ifdef HAVE_BKTR
730static void append_backtrace_information(struct ast_str **str, struct ast_bt *bt)
731{
732 char **symbols;
733
734 if (!bt) {
735 ast_str_append(str, 0, "\tNo backtrace to print\n");
736 return;
737 }
738
739 if ((symbols = backtrace_symbols(bt->addresses, bt->num_frames))) {
740 int frame_iterator;
741
742 for (frame_iterator = 0; frame_iterator < bt->num_frames; ++frame_iterator) {
743 ast_str_append(str, 0, "\t%s\n", symbols[frame_iterator]);
744 }
745
746 free(symbols);
747 } else {
748 ast_str_append(str, 0, "\tCouldn't retrieve backtrace symbols\n");
749 }
750}
751#endif
752
753static void append_lock_information(struct ast_str **str, struct thr_lock_info *lock_info, int i)
754{
755 int j;
756 ast_mutex_t *lock;
757 struct ast_lock_track *lt;
758
759 ast_str_append(str, 0, "=== ---> %sLock #%d (%s): %s %d %s %s %p (%d)\n",
760 lock_info->locks[i].pending > 0 ? "Waiting for " :
761 lock_info->locks[i].pending < 0 ? "Tried and failed to get " : "", i,
762 lock_info->locks[i].file,
763 locktype2str(lock_info->locks[i].type),
764 lock_info->locks[i].line_num,
765 lock_info->locks[i].func, lock_info->locks[i].lock_name,
766 lock_info->locks[i].lock_addr,
767 lock_info->locks[i].times_locked);
768#ifdef HAVE_BKTR
769 append_backtrace_information(str, lock_info->locks[i].backtrace);
770#endif
771
772 if (!lock_info->locks[i].pending || lock_info->locks[i].pending == -1)
773 return;
774
775 /* We only have further details for mutexes right now */
776 if (lock_info->locks[i].type != AST_MUTEX)
777 return;
778
779 lock = lock_info->locks[i].lock_addr;
780 lt = &lock->track;
781 ast_reentrancy_lock(lt);
782 for (j = 0; *str && j < lt->reentrancy; j++) {
783 ast_str_append(str, 0, "=== --- ---> Locked Here: %s line %d (%s)\n",
784 lt->file[j], lt->lineno[j], lt->func[j]);
785 }
786 ast_reentrancy_unlock(lt);
787}
788
789
790/*! This function can help you find highly temporal locks; locks that happen for a
791 short time, but at unexpected times, usually at times that create a deadlock,
792 Why is this thing locked right then? Who is locking it? Who am I fighting
793 with for this lock?
794
795 To answer such questions, just call this routine before you would normally try
796 to aquire a lock. It doesn't do anything if the lock is not acquired. If the
797 lock is taken, it will publish a line or two to the console via ast_log().
798
799 Sometimes, the lock message is pretty uninformative. For instance, you might
800 find that the lock is being aquired deep within the astobj2 code; this tells
801 you little about higher level routines that call the astobj2 routines.
802 But, using gdb, you can set a break at the ast_log below, and for that
803 breakpoint, you can set the commands:
804 where
805 cont
806 which will give a stack trace and continue. -- that aught to do the job!
807
808*/
809void log_show_lock(void *this_lock_addr)
810{
811 struct thr_lock_info *lock_info;
812 struct ast_str *str;
813
814 if (!(str = ast_str_create(4096))) {
815 ast_log(LOG_NOTICE,"Could not create str\n");
816 return;
817 }
818
819
820 pthread_mutex_lock(&lock_infos_lock.mutex);
821 AST_LIST_TRAVERSE(&lock_infos, lock_info, entry) {
822 int i;
823 pthread_mutex_lock(&lock_info->lock);
824 for (i = 0; str && i < lock_info->num_locks; i++) {
825 /* ONLY show info about this particular lock, if
826 it's acquired... */
827 if (lock_info->locks[i].lock_addr == this_lock_addr) {
828 append_lock_information(&str, lock_info, i);
829 ast_log(LOG_NOTICE, "%s", ast_str_buffer(str));
830 break;
831 }
832 }
833 pthread_mutex_unlock(&lock_info->lock);
834 }
835 pthread_mutex_unlock(&lock_infos_lock.mutex);
836 ast_free(str);
837}
838
839
840static char *handle_show_locks(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
841{
842 struct thr_lock_info *lock_info;
843 struct ast_str *str;
844
845 if (!(str = ast_str_create(4096)))
846 return CLI_FAILURE;
847
848 switch (cmd) {
849 case CLI_INIT:
850 e->command = "core show locks";
851 e->usage =
852 "Usage: core show locks\n"
853 " This command is for lock debugging. It prints out which locks\n"
854 "are owned by each active thread.\n";
855 return NULL;
856
857 case CLI_GENERATE:
858 return NULL;
859 }
860
861 ast_str_append(&str, 0, "\n"
862 "=======================================================================\n"
863 "=== Currently Held Locks ==============================================\n"
864 "=======================================================================\n"
865 "===\n"
866 "=== <pending> <lock#> (<file>): <lock type> <line num> <function> <lock name> <lock addr> (times locked)\n"
867 "===\n");
868
869 if (!str)
870 return CLI_FAILURE;
871
872 pthread_mutex_lock(&lock_infos_lock.mutex);
873 AST_LIST_TRAVERSE(&lock_infos, lock_info, entry) {
874 int i;
875 if (lock_info->num_locks) {
876 ast_str_append(&str, 0, "=== Thread ID: %ld (%s)\n", (long) lock_info->thread_id,
877 lock_info->thread_name);
878 pthread_mutex_lock(&lock_info->lock);
879 for (i = 0; str && i < lock_info->num_locks; i++) {
880 append_lock_information(&str, lock_info, i);
881 }
882 pthread_mutex_unlock(&lock_info->lock);
883 if (!str)
884 break;
885 ast_str_append(&str, 0, "=== -------------------------------------------------------------------\n"
886 "===\n");
887 if (!str)
888 break;
889 }
890 }
891 pthread_mutex_unlock(&lock_infos_lock.mutex);
892
893 if (!str)
894 return CLI_FAILURE;
895
896 ast_str_append(&str, 0, "=======================================================================\n"
897 "\n");
898
899 if (!str)
900 return CLI_FAILURE;
901
902 ast_cli(a->fd, "%s", ast_str_buffer(str));
903
904 ast_free(str);
905
906 return CLI_SUCCESS;
907}
908
909static struct ast_cli_entry utils_cli[] = {
910 AST_CLI_DEFINE(handle_show_locks, "Show which locks are held by which thread"),
911};
912
913#endif /* DEBUG_THREADS */
914
915/*
916 * support for 'show threads'. The start routine is wrapped by
917 * dummy_start(), so that ast_register_thread() and
918 * ast_unregister_thread() know the thread identifier.
919 */
920struct thr_arg {
921 void *(*start_routine)(void *);
922 void *data;
923 char *name;
924};
925
926/*
927 * on OS/X, pthread_cleanup_push() and pthread_cleanup_pop()
928 * are odd macros which start and end a block, so they _must_ be
929 * used in pairs (the latter with a '1' argument to call the
930 * handler on exit.
931 * On BSD we don't need this, but we keep it for compatibility.
932 */
933static void *dummy_start(void *data)
934{
935 void *ret;
936 struct thr_arg a = *((struct thr_arg *) data); /* make a local copy */
937#ifdef DEBUG_THREADS
938 struct thr_lock_info *lock_info;
939 pthread_mutexattr_t mutex_attr;
940#endif
941
942 /* note that even though data->name is a pointer to allocated memory,
943 we are not freeing it here because ast_register_thread is going to
944 keep a copy of the pointer and then ast_unregister_thread will
945 free the memory
946 */
947 ast_free(data);
948 ast_register_thread(a.name);
949 pthread_cleanup_push(ast_unregister_thread, (void *) pthread_self());
950
951#ifdef DEBUG_THREADS
952 if (!(lock_info = ast_threadstorage_get(&thread_lock_info, sizeof(*lock_info))))
953 return NULL;
954
955 lock_info->thread_id = pthread_self();
956 lock_info->thread_name = strdup(a.name);
957
958 pthread_mutexattr_init(&mutex_attr);
959 pthread_mutexattr_settype(&mutex_attr, AST_MUTEX_KIND);
960 pthread_mutex_init(&lock_info->lock, &mutex_attr);
961 pthread_mutexattr_destroy(&mutex_attr);
962
963 pthread_mutex_lock(&lock_infos_lock.mutex); /* Intentionally not the wrapper */
964 AST_LIST_INSERT_TAIL(&lock_infos, lock_info, entry);
965 pthread_mutex_unlock(&lock_infos_lock.mutex); /* Intentionally not the wrapper */
966#endif /* DEBUG_THREADS */
967
968 ret = a.start_routine(a.data);
969
970 pthread_cleanup_pop(1);
971
972 return ret;
973}
974
975#endif /* !LOW_MEMORY */
976
977int ast_pthread_create_stack(pthread_t *thread, pthread_attr_t *attr, void *(*start_routine)(void *),
978 void *data, size_t stacksize, const char *file, const char *caller,
979 int line, const char *start_fn)
980{
981#if !defined(LOW_MEMORY)
982 struct thr_arg *a;
983#endif
984
985 if (!attr) {
986 attr = alloca(sizeof(*attr));
987 pthread_attr_init(attr);
988 }
989
990#ifdef __linux__
991 /* On Linux, pthread_attr_init() defaults to PTHREAD_EXPLICIT_SCHED,
992 which is kind of useless. Change this here to
993 PTHREAD_INHERIT_SCHED; that way the -p option to set realtime
994 priority will propagate down to new threads by default.
995 This does mean that callers cannot set a different priority using
996 PTHREAD_EXPLICIT_SCHED in the attr argument; instead they must set
997 the priority afterwards with pthread_setschedparam(). */
998 if ((errno = pthread_attr_setinheritsched(attr, PTHREAD_INHERIT_SCHED)))
999 ast_log(LOG_WARNING, "pthread_attr_setinheritsched: %s\n", strerror(errno));
1000#endif
1001
1002 if (!stacksize)
1003 stacksize = AST_STACKSIZE;
1004
1005 if ((errno = pthread_attr_setstacksize(attr, stacksize ? stacksize : AST_STACKSIZE)))
1006 ast_log(LOG_WARNING, "pthread_attr_setstacksize: %s\n", strerror(errno));
1007
1008#if !defined(LOW_MEMORY)
1009 if ((a = ast_malloc(sizeof(*a)))) {
1010 a->start_routine = start_routine;
1011 a->data = data;
1012 start_routine = dummy_start;
1013 if (asprintf(&a->name, "%-20s started at [%5d] %s %s()",
1014 start_fn, line, file, caller) < 0) {
1015 ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno));
1016 a->name = NULL;
1017 }
1018 data = a;
1019 }
1020#endif /* !LOW_MEMORY */
1021
1022 return pthread_create(thread, attr, start_routine, data); /* We're in ast_pthread_create, so it's okay */
1023}
1024
1025
1026int ast_pthread_create_detached_stack(pthread_t *thread, pthread_attr_t *attr, void *(*start_routine)(void *),
1027 void *data, size_t stacksize, const char *file, const char *caller,
1028 int line, const char *start_fn)
1029{
1030 unsigned char attr_destroy = 0;
1031 int res;
1032
1033 if (!attr) {
1034 attr = alloca(sizeof(*attr));
1035 pthread_attr_init(attr);
1036 attr_destroy = 1;
1037 }
1038
1039 if ((errno = pthread_attr_setdetachstate(attr, PTHREAD_CREATE_DETACHED)))
1040 ast_log(LOG_WARNING, "pthread_attr_setdetachstate: %s\n", strerror(errno));
1041
1042 res = ast_pthread_create_stack(thread, attr, start_routine, data,
1043 stacksize, file, caller, line, start_fn);
1044
1045 if (attr_destroy)
1046 pthread_attr_destroy(attr);
1047
1048 return res;
1049}
1050
1051int ast_wait_for_input(int fd, int ms)
1052{
1053 struct pollfd pfd[1];
1054 memset(pfd, 0, sizeof(pfd));
1055 pfd[0].fd = fd;
1056 pfd[0].events = POLLIN|POLLPRI;
1057 return ast_poll(pfd, 1, ms);
1058}
1059
1060static int ast_wait_for_output(int fd, int timeoutms)
1061{
1062 struct pollfd pfd = {
1063 .fd = fd,
1064 .events = POLLOUT,
1065 };
1066 int res;
1067 struct timeval start = ast_tvnow();
1068 int elapsed = 0;
1069
1070 /* poll() until the fd is writable without blocking */
1071 while ((res = ast_poll(&pfd, 1, timeoutms - elapsed)) <= 0) {
1072 if (res == 0) {
1073 /* timed out. */
1074#ifndef STANDALONE
1075 ast_debug(1, "Timed out trying to write\n");
1076#endif
1077 return -1;
1078 } else if (res == -1) {
1079 /* poll() returned an error, check to see if it was fatal */
1080
1081 if (errno == EINTR || errno == EAGAIN) {
1082 elapsed = ast_tvdiff_ms(ast_tvnow(), start);
1083 if (elapsed >= timeoutms) {
1084 return -1;
1085 }
1086 /* This was an acceptable error, go back into poll() */
1087 continue;
1088 }
1089
1090 /* Fatal error, bail. */
1091 ast_log(LOG_ERROR, "poll returned error: %s\n", strerror(errno));
1092
1093 return -1;
1094 }
1095 elapsed = ast_tvdiff_ms(ast_tvnow(), start);
1096 if (elapsed >= timeoutms) {
1097 return -1;
1098 }
1099 }
1100
1101 return 0;
1102}
1103
1104/*!
1105 * Try to write string, but wait no more than ms milliseconds before timing out.
1106 *
1107 * \note The code assumes that the file descriptor has NONBLOCK set,
1108 * so there is only one system call made to do a write, unless we actually
1109 * have a need to wait. This way, we get better performance.
1110 * If the descriptor is blocking, all assumptions on the guaranteed
1111 * detail do not apply anymore.
1112 */
1113int ast_carefulwrite(int fd, char *s, int len, int timeoutms)
1114{
1115 struct timeval start = ast_tvnow();
1116 int res = 0;
1117 int elapsed = 0;
1118
1119 while (len) {
1120 if (ast_wait_for_output(fd, timeoutms - elapsed)) {
1121 return -1;
1122 }
1123
1124 res = write(fd, s, len);
1125
1126 if (res < 0 && errno != EAGAIN && errno != EINTR) {
1127 /* fatal error from write() */
1128 ast_log(LOG_ERROR, "write() returned error: %s\n", strerror(errno));
1129 return -1;
1130 }
1131
1132 if (res < 0) {
1133 /* It was an acceptable error */
1134 res = 0;
1135 }
1136
1137 /* Update how much data we have left to write */
1138 len -= res;
1139 s += res;
1140 res = 0;
1141
1142 elapsed = ast_tvdiff_ms(ast_tvnow(), start);
1143 if (elapsed >= timeoutms) {
1144 /* We've taken too long to write
1145 * This is only an error condition if we haven't finished writing. */
1146 res = len ? -1 : 0;
1147 break;
1148 }
1149 }
1150
1151 return res;
1152}
1153
1154int ast_careful_fwrite(FILE *f, int fd, const char *src, size_t len, int timeoutms)
1155{
1156 struct timeval start = ast_tvnow();
1157 int n = 0;
1158 int elapsed = 0;
1159
1160 while (len) {
1161 if (ast_wait_for_output(fd, timeoutms - elapsed)) {
1162 /* poll returned a fatal error, so bail out immediately. */
1163 return -1;
1164 }
1165
1166 /* Clear any errors from a previous write */
1167 clearerr(f);
1168
1169 n = fwrite(src, 1, len, f);
1170
1171 if (ferror(f) && errno != EINTR && errno != EAGAIN) {
1172 /* fatal error from fwrite() */
1173 if (!feof(f)) {
1174 /* Don't spam the logs if it was just that the connection is closed. */
1175 ast_log(LOG_ERROR, "fwrite() returned error: %s\n", strerror(errno));
1176 }
1177 n = -1;
1178 break;
1179 }
1180
1181 /* Update for data already written to the socket */
1182 len -= n;
1183 src += n;
1184
1185 elapsed = ast_tvdiff_ms(ast_tvnow(), start);
1186 if (elapsed >= timeoutms) {
1187 /* We've taken too long to write
1188 * This is only an error condition if we haven't finished writing. */
1189 n = len ? -1 : 0;
1190 break;
1191 }
1192 }
1193
1194 while (fflush(f)) {
1195 if (errno == EAGAIN || errno == EINTR) {
1196 continue;
1197 }
1198 if (!feof(f)) {
1199 /* Don't spam the logs if it was just that the connection is closed. */
1200 ast_log(LOG_ERROR, "fflush() returned error: %s\n", strerror(errno));
1201 }
1202 n = -1;
1203 break;
1204 }
1205
1206 return n < 0 ? -1 : 0;
1207}
1208
1209char *ast_strip_quoted(char *s, const char *beg_quotes, const char *end_quotes)
1210{
1211 char *e;
1212 char *q;
1213
1214 s = ast_strip(s);
1215 if ((q = strchr(beg_quotes, *s)) && *q != '\0') {
1216 e = s + strlen(s) - 1;
1217 if (*e == *(end_quotes + (q - beg_quotes))) {
1218 s++;
1219 *e = '\0';
1220 }
1221 }
1222
1223 return s;
1224}
1225
1226char *ast_unescape_semicolon(char *s)
1227{
1228 char *e;
1229 char *work = s;
1230
1231 while ((e = strchr(work, ';'))) {
1232 if ((e > work) && (*(e-1) == '\\')) {
1233 memmove(e - 1, e, strlen(e) + 1);
1234 work = e;
1235 } else {
1236 work = e + 1;
1237 }
1238 }
1239
1240 return s;
1241}
1242
1243/* !\brief unescape some C sequences in place, return pointer to the original string.
1244 */
1245char *ast_unescape_c(char *src)
1246{
1247 char c, *ret, *dst;
1248
1249 if (src == NULL)
1250 return NULL;
1251 for (ret = dst = src; (c = *src++); *dst++ = c ) {
1252 if (c != '\\')
1253 continue; /* copy char at the end of the loop */
1254 switch ((c = *src++)) {
1255 case '\0': /* special, trailing '\' */
1256 c = '\\';
1257 break;
1258 case 'b': /* backspace */
1259 c = '\b';
1260 break;
1261 case 'f': /* form feed */
1262 c = '\f';
1263 break;
1264 case 'n':
1265 c = '\n';
1266 break;
1267 case 'r':
1268 c = '\r';
1269 break;
1270 case 't':
1271 c = '\t';
1272 break;
1273 }
1274 /* default, use the char literally */
1275 }
1276 *dst = '\0';
1277 return ret;
1278}
1279
1280int ast_build_string_va(char **buffer, size_t *space, const char *fmt, va_list ap)
1281{
1282 int result;
1283
1284 if (!buffer || !*buffer || !space || !*space)
1285 return -1;
1286
1287 result = vsnprintf(*buffer, *space, fmt, ap);
1288
1289 if (result < 0)
1290 return -1;
1291 else if (result > *space)
1292 result = *space;
1293
1294 *buffer += result;
1295 *space -= result;
1296 return 0;
1297}
1298
1299int ast_build_string(char **buffer, size_t *space, const char *fmt, ...)
1300{
1301 va_list ap;
1302 int result;
1303
1304 va_start(ap, fmt);
1305 result = ast_build_string_va(buffer, space, fmt, ap);
1306 va_end(ap);
1307
1308 return result;
1309}
1310
1311int ast_true(const char *s)
1312{
1313 if (ast_strlen_zero(s))
1314 return 0;
1315
1316 /* Determine if this is a true value */
1317 if (!strcasecmp(s, "yes") ||
1318 !strcasecmp(s, "true") ||
1319 !strcasecmp(s, "y") ||
1320 !strcasecmp(s, "t") ||
1321 !strcasecmp(s, "1") ||
1322 !strcasecmp(s, "on"))
1323 return -1;
1324
1325 return 0;
1326}
1327
1328int ast_false(const char *s)
1329{
1330 if (ast_strlen_zero(s))
1331 return 0;
1332
1333 /* Determine if this is a false value */
1334 if (!strcasecmp(s, "no") ||
1335 !strcasecmp(s, "false") ||
1336 !strcasecmp(s, "n") ||
1337 !strcasecmp(s, "f") ||
1338 !strcasecmp(s, "0") ||
1339 !strcasecmp(s, "off"))
1340 return -1;
1341
1342 return 0;
1343}
1344
1345#define ONE_MILLION 1000000
1346/*
1347 * put timeval in a valid range. usec is 0..999999
1348 * negative values are not allowed and truncated.
1349 */
1350static struct timeval tvfix(struct timeval a)
1351{
1352 if (a.tv_usec >= ONE_MILLION) {
1353 ast_log(LOG_WARNING, "warning too large timestamp %ld.%ld\n",
1354 (long)a.tv_sec, (long int) a.tv_usec);
1355 a.tv_sec += a.tv_usec / ONE_MILLION;
1356 a.tv_usec %= ONE_MILLION;
1357 } else if (a.tv_usec < 0) {
1358 ast_log(LOG_WARNING, "warning negative timestamp %ld.%ld\n",
1359 (long)a.tv_sec, (long int) a.tv_usec);
1360 a.tv_usec = 0;
1361 }
1362 return a;
1363}
1364
1365struct timeval ast_tvadd(struct timeval a, struct timeval b)
1366{
1367 /* consistency checks to guarantee usec in 0..999999 */
1368 a = tvfix(a);
1369 b = tvfix(b);
1370 a.tv_sec += b.tv_sec;
1371 a.tv_usec += b.tv_usec;
1372 if (a.tv_usec >= ONE_MILLION) {
1373 a.tv_sec++;
1374 a.tv_usec -= ONE_MILLION;
1375 }
1376 return a;
1377}
1378
1379struct timeval ast_tvsub(struct timeval a, struct timeval b)
1380{
1381 /* consistency checks to guarantee usec in 0..999999 */
1382 a = tvfix(a);
1383 b = tvfix(b);
1384 a.tv_sec -= b.tv_sec;
1385 a.tv_usec -= b.tv_usec;
1386 if (a.tv_usec < 0) {
1387 a.tv_sec-- ;
1388 a.tv_usec += ONE_MILLION;
1389 }
1390 return a;
1391}
1392#undef ONE_MILLION
1393
1394/*! \brief glibc puts a lock inside random(3), so that the results are thread-safe.
1395 * BSD libc (and others) do not. */
1396
1397#ifndef linux
1398AST_MUTEX_DEFINE_STATIC(randomlock);
1399#endif
1400
1401long int ast_random(void)
1402{
1403 long int res;
1404#ifdef HAVE_DEV_URANDOM
1405 if (dev_urandom_fd >= 0) {
1406 int read_res = read(dev_urandom_fd, &res, sizeof(res));
1407 if (read_res > 0) {
1408 long int rm = RAND_MAX;
1409 res = res < 0 ? ~res : res;
1410 rm++;
1411 return res % rm;
1412 }
1413 }
1414#endif
1415#ifdef linux
1416 res = random();
1417#else
1418 ast_mutex_lock(&randomlock);
1419 res = random();
1420 ast_mutex_unlock(&randomlock);
1421#endif
1422 return res;
1423}
1424
1425char *ast_process_quotes_and_slashes(char *start, char find, char replace_with)
1426{
1427 char *dataPut = start;
1428 int inEscape = 0;
1429 int inQuotes = 0;
1430
1431 for (; *start; start++) {
1432 if (inEscape) {
1433 *dataPut++ = *start; /* Always goes verbatim */
1434 inEscape = 0;
1435 } else {
1436 if (*start == '\\') {
1437 inEscape = 1; /* Do not copy \ into the data */
1438 } else if (*start == '\'') {
1439 inQuotes = 1 - inQuotes; /* Do not copy ' into the data */
1440 } else {
1441 /* Replace , with |, unless in quotes */
1442 *dataPut++ = inQuotes ? *start : ((*start == find) ? replace_with : *start);
1443 }
1444 }
1445 }
1446 if (start != dataPut)
1447 *dataPut = 0;
1448 return dataPut;
1449}
1450
1451void ast_join(char *s, size_t len, char * const w[])
1452{
1453 int x, ofs = 0;
1454 const char *src;
1455
1456 /* Join words into a string */
1457 if (!s)
1458 return;
1459 for (x = 0; ofs < len && w[x]; x++) {
1460 if (x > 0)
1461 s[ofs++] = ' ';
1462 for (src = w[x]; *src && ofs < len; src++)
1463 s[ofs++] = *src;
1464 }
1465 if (ofs == len)
1466 ofs--;
1467 s[ofs] = '\0';
1468}
1469
1470/*
1471 * stringfields support routines.
1472 */
1473
1474const char __ast_string_field_empty[] = ""; /*!< the empty string */
1475
1476/*! \brief add a new block to the pool.
1477 * We can only allocate from the topmost pool, so the
1478 * fields in *mgr reflect the size of that only.
1479 */
1480static int add_string_pool(struct ast_string_field_mgr *mgr, struct ast_string_field_pool **pool_head,
1481 size_t size, const char *file, int lineno, const char *func)
1482{
1483 struct ast_string_field_pool *pool;
1484
1485#if defined(__AST_DEBUG_MALLOC)
1486 if (!(pool = __ast_calloc(1, sizeof(*pool) + size, file, lineno, func))) {
1487 return -1;
1488 }
1489#else
1490 if (!(pool = ast_calloc(1, sizeof(*pool) + size))) {
1491 return -1;
1492 }
1493#endif
1494
1495 pool->prev = *pool_head;
1496 *pool_head = pool;
1497 mgr->size = size;
1498 mgr->used = 0;
1499 mgr->last_alloc = NULL;
1500
1501 return 0;
1502}
1503
1504/*
1505 * This is an internal API, code should not use it directly.
1506 * It initializes all fields as empty, then uses 'size' for 3 functions:
1507 * size > 0 means initialize the pool list with a pool of given size.
1508 * This must be called right after allocating the object.
1509 * size = 0 means release all pools except the most recent one.
1510 * This is useful to e.g. reset an object to the initial value.
1511 * size < 0 means release all pools.
1512 * This must be done before destroying the object.
1513 */
1514int __ast_string_field_init(struct ast_string_field_mgr *mgr, struct ast_string_field_pool **pool_head,
1515 int needed, const char *file, int lineno, const char *func)
1516{
1517 const char **p = (const char **) pool_head + 1;
1518 struct ast_string_field_pool *cur = NULL;
1519 struct ast_string_field_pool *preserve = NULL;
1520
1521 /* clear fields - this is always necessary */
1522 while ((struct ast_string_field_mgr *) p != mgr)
1523 *p++ = __ast_string_field_empty;
1524 mgr->last_alloc = NULL;
1525#if defined(__AST_DEBUG_MALLOC)
1526 mgr->owner_file = file;
1527 mgr->owner_func = func;
1528 mgr->owner_line = lineno;
1529#endif
1530 if (needed > 0) { /* allocate the initial pool */
1531 *pool_head = NULL;
1532 return add_string_pool(mgr, pool_head, needed, file, lineno, func);
1533 }
1534 if (needed < 0) { /* reset all pools */
1535 if (*pool_head == NULL) {
1536 ast_log(LOG_WARNING, "trying to reset empty pool\n");
1537 return -1;
1538 }
1539 cur = *pool_head;
1540 } else { /* preserve the last pool */
1541 if (*pool_head == NULL) {
1542 ast_log(LOG_WARNING, "trying to reset empty pool\n");
1543 return -1;
1544 }
1545 mgr->used = 0;
1546 preserve = *pool_head;
1547 cur = preserve->prev;
1548 }
1549
1550 if (preserve) {
1551 preserve->prev = NULL;
1552 }
1553
1554 while (cur) {
1555 struct ast_string_field_pool *prev = cur->prev;
1556
1557 if (cur != preserve) {
1558 ast_free(cur);
1559 }
1560 cur = prev;
1561 }
1562
1563 *pool_head = preserve;
1564
1565 return 0;
1566}
1567
1568ast_string_field __ast_string_field_alloc_space(struct ast_string_field_mgr *mgr,
1569 struct ast_string_field_pool **pool_head, size_t needed)
1570{
1571 char *result = NULL;
1572 size_t space = mgr->size - mgr->used;
1573
1574 if (__builtin_expect(needed > space, 0)) {
1575 size_t new_size = mgr->size * 2;
1576
1577 while (new_size < needed)
1578 new_size *= 2;
1579
1580#if defined(__AST_DEBUG_MALLOC)
1581 if (add_string_pool(mgr, pool_head, new_size, mgr->owner_file, mgr->owner_line, mgr->owner_func))
1582 return NULL;
1583#else
1584 if (add_string_pool(mgr, pool_head, new_size, __FILE__, __LINE__, __FUNCTION__))
1585 return NULL;
1586#endif
1587 }
1588
1589 result = (*pool_head)->base + mgr->used;
1590 mgr->used += needed;
1591 mgr->last_alloc = result;
1592 return result;
1593}
1594
1595int __ast_string_field_ptr_grow(struct ast_string_field_mgr *mgr, size_t needed,
1596 const ast_string_field *ptr)
1597{
1598 int grow = needed - (strlen(*ptr) + 1);
1599 size_t space = mgr->size - mgr->used;
1600
1601 if (grow <= 0) {
1602 return 0;
1603 }
1604
1605 if (*ptr != mgr->last_alloc) {
1606 return 1;
1607 }
1608
1609 if (space < grow) {
1610 return 1;
1611 }
1612
1613 mgr->used += grow;
1614
1615 return 0;
1616}
1617
1618void __ast_string_field_ptr_build_va(struct ast_string_field_mgr *mgr,
1619 struct ast_string_field_pool **pool_head,
1620 ast_string_field *ptr, const char *format, va_list ap1, va_list ap2)
1621{
1622 size_t needed;
1623 size_t available;
1624 size_t space = mgr->size - mgr->used;
1625 char *target;
1626
1627 /* if the field already has space allocated, try to reuse it;
1628 otherwise, use the empty space at the end of the current
1629 pool
1630 */
1631 if ((*ptr)[0] != '\0') {
1632 target = (char *) *ptr;
1633 available = strlen(target) + 1;
1634 } else {
1635 target = (*pool_head)->base + mgr->used;
1636 available = space;
1637 }
1638
1639 needed = vsnprintf(target, available, format, ap1) + 1;
1640
1641 va_end(ap1);
1642
1643 if (needed > available) {
1644 /* if the space needed can be satisfied by using the current
1645 pool (which could only occur if we tried to use the field's
1646 allocated space and failed), then use that space; otherwise
1647 allocate a new pool
1648 */
1649 if (needed > space) {
1650 size_t new_size = mgr->size * 2;
1651
1652 while (new_size < needed)
1653 new_size *= 2;
1654
1655#if defined(__AST_DEBUG_MALLOC)
1656 if (add_string_pool(mgr, pool_head, new_size, mgr->owner_file, mgr->owner_line, mgr->owner_func))
1657 return;
1658#else
1659 if (add_string_pool(mgr, pool_head, new_size, NULL, 0, NULL))
1660 return;
1661#endif
1662 }
1663
1664 target = (*pool_head)->base + mgr->used;
1665 vsprintf(target, format, ap2);
1666 }
1667
1668 if (*ptr != target) {
1669 mgr->last_alloc = *ptr = target;
1670 mgr->used += needed;
1671 }
1672}
1673
1674void __ast_string_field_ptr_build(struct ast_string_field_mgr *mgr,
1675 struct ast_string_field_pool **pool_head,
1676 ast_string_field *ptr, const char *format, ...)
1677{
1678 va_list ap1, ap2;
1679
1680 va_start(ap1, format);
1681 va_start(ap2, format); /* va_copy does not exist on FreeBSD */
1682
1683 __ast_string_field_ptr_build_va(mgr, pool_head, ptr, format, ap1, ap2);
1684
1685 va_end(ap1);
1686 va_end(ap2);
1687}
1688/* end of stringfields support */
1689
1690AST_MUTEX_DEFINE_STATIC(fetchadd_m); /* used for all fetc&add ops */
1691
1692int ast_atomic_fetchadd_int_slow(volatile int *p, int v)
1693{
1694 int ret;
1695 ast_mutex_lock(&fetchadd_m);
1696 ret = *p;
1697 *p += v;
1698 ast_mutex_unlock(&fetchadd_m);
1699 return ret;
1700}
1701
1702/*! \brief
1703 * get values from config variables.
1704 */
1705int ast_get_timeval(const char *src, struct timeval *dst, struct timeval _default, int *consumed)
1706{
1707 long double dtv = 0.0;
1708 int scanned;
1709
1710 if (dst == NULL)
1711 return -1;
1712
1713 *dst = _default;
1714
1715 if (ast_strlen_zero(src))
1716 return -1;
1717
1718 /* only integer at the moment, but one day we could accept more formats */
1719 if (sscanf(src, "%30Lf%n", &dtv, &scanned) > 0) {
1720 dst->tv_sec = dtv;
1721 dst->tv_usec = (dtv - dst->tv_sec) * 1000000.0;
1722 if (consumed)
1723 *consumed = scanned;
1724 return 0;
1725 } else
1726 return -1;
1727}
1728
1729/*! \brief
1730 * get values from config variables.
1731 */
1732int ast_get_time_t(const char *src, time_t *dst, time_t _default, int *consumed)
1733{
1734 long t;
1735 int scanned;
1736
1737 if (dst == NULL)
1738 return -1;
1739
1740 *dst = _default;
1741
1742 if (ast_strlen_zero(src))
1743 return -1;
1744
1745 /* only integer at the moment, but one day we could accept more formats */
1746 if (sscanf(src, "%30ld%n", &t, &scanned) == 1) {
1747 *dst = t;
1748 if (consumed)
1749 *consumed = scanned;
1750 return 0;
1751 } else
1752 return -1;
1753}
1754
1755void ast_enable_packet_fragmentation(int sock)
1756{
1757#if defined(HAVE_IP_MTU_DISCOVER)
1758 int val = IP_PMTUDISC_DONT;
1759
1760 if (setsockopt(sock, IPPROTO_IP, IP_MTU_DISCOVER, &val, sizeof(val)))
1761 ast_log(LOG_WARNING, "Unable to disable PMTU discovery. Large UDP packets may fail to be delivered when sent from this socket.\n");
1762#endif /* HAVE_IP_MTU_DISCOVER */
1763}
1764
1765int ast_mkdir(const char *path, int mode)
1766{
1767 char *ptr;
1768 int len = strlen(path), count = 0, x, piececount = 0;
1769 char *tmp = ast_strdupa(path);
1770 char **pieces;
1771 char *fullpath = alloca(len + 1);
1772 int res = 0;
1773
1774 for (ptr = tmp; *ptr; ptr++) {
1775 if (*ptr == '/')
1776 count++;
1777 }
1778
1779 /* Count the components to the directory path */
1780 pieces = alloca(count * sizeof(*pieces));
1781 for (ptr = tmp; *ptr; ptr++) {
1782 if (*ptr == '/') {
1783 *ptr = '\0';
1784 pieces[piececount++] = ptr + 1;
1785 }
1786 }
1787
1788 *fullpath = '\0';
1789 for (x = 0; x < piececount; x++) {
1790 /* This looks funky, but the buffer is always ideally-sized, so it's fine. */
1791 strcat(fullpath, "/");
1792 strcat(fullpath, pieces[x]);
1793 res = mkdir(fullpath, mode);
1794 if (res && errno != EEXIST)
1795 return errno;
1796 }
1797 return 0;
1798}
1799
1800int ast_utils_init(void)
1801{
1802#ifdef HAVE_DEV_URANDOM
1803 dev_urandom_fd = open("/dev/urandom", O_RDONLY);
1804#endif
1805 base64_init();
1806#ifdef DEBUG_THREADS
1807#if !defined(LOW_MEMORY)
1808 ast_cli_register_multiple(utils_cli, ARRAY_LEN(utils_cli));
1809#endif
1810#endif
1811 return 0;
1812}
1813
1814#ifndef __AST_DEBUG_MALLOC
1815int _ast_asprintf(char **ret, const char *file, int lineno, const char *func, const char *fmt, ...)
1816{
1817 int res;
1818 va_list ap;
1819
1820 va_start(ap, fmt);
1821 if ((res = vasprintf(ret, fmt, ap)) == -1) {
1822 MALLOC_FAILURE_MSG;
1823 }
1824 va_end(ap);
1825
1826 return res;
1827}
1828#endif
01829
=== modified file '.pc/applied-patches'
--- .pc/applied-patches 2010-03-02 10:00:03 +0000
+++ .pc/applied-patches 2011-01-20 23:43:55 +0000
@@ -11,3 +11,6 @@
11dahdi_ptmp_nt11dahdi_ptmp_nt
12dahdi_pri_debug_spannums12dahdi_pri_debug_spannums
13sound_files13sound_files
14dnsmgr-A-SRV-handling
15unattended_fix
16AST-2011-001-1.6.2
1417
=== added directory '.pc/dnsmgr-A-SRV-handling'
=== added directory '.pc/dnsmgr-A-SRV-handling/include'
=== added directory '.pc/dnsmgr-A-SRV-handling/include/asterisk'
=== added file '.pc/dnsmgr-A-SRV-handling/include/asterisk/dnsmgr.h'
--- .pc/dnsmgr-A-SRV-handling/include/asterisk/dnsmgr.h 1970-01-01 00:00:00 +0000
+++ .pc/dnsmgr-A-SRV-handling/include/asterisk/dnsmgr.h 2011-01-20 23:43:55 +0000
@@ -0,0 +1,105 @@
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 1999 - 2005, Digium, Inc.
5 *
6 * Kevin P. Fleming <kpfleming@digium.com>
7 *
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
13 *
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
17 */
18
19/*! \file
20 * \brief Background DNS update manager
21 */
22
23#ifndef _ASTERISK_DNSMGR_H
24#define _ASTERISK_DNSMGR_H
25
26#if defined(__cplusplus) || defined(c_plusplus)
27extern "C" {
28#endif
29
30#include "asterisk/network.h"
31#include "asterisk/srv.h"
32
33/*!
34 * \brief A DNS manager entry
35 *
36 * This is an opaque type.
37 */
38struct ast_dnsmgr_entry;
39
40/*!
41 * \brief Allocate a new DNS manager entry
42 *
43 * \param name the hostname
44 * \param result where the DNS manager should store the IP address as it refreshes it.
45 * it.
46 *
47 * This function allocates a new DNS manager entry object, and fills it with the
48 * provided hostname and IP address. This function does not force an initial lookup
49 * of the IP address. So, generally, this should be used when the initial address
50 * is already known.
51 *
52 * \return a DNS manager entry
53 * \version 1.6.1 result changed from struct in_addr to struct sockaddr_in to store port number
54 */
55struct ast_dnsmgr_entry *ast_dnsmgr_get(const char *name, struct sockaddr_in *result, const char *service);
56
57/*!
58 * \brief Free a DNS manager entry
59 *
60 * \param entry the DNS manager entry to free
61 *
62 * \return nothing
63 */
64void ast_dnsmgr_release(struct ast_dnsmgr_entry *entry);
65
66/*!
67 * \brief Allocate and initialize a DNS manager entry
68 *
69 * \param name the hostname
70 * \param result where to store the IP address as the DNS manager refreshes it
71 * \param dnsmgr Where to store the allocate DNS manager entry
72 *
73 * This function allocates a new DNS manager entry object, and fills it with
74 * the provided hostname and IP address. This function _does_ force an initial
75 * lookup, so it may block for some period of time.
76 *
77 * \retval 0 success
78 * \retval non-zero failure
79 * \version 1.6.1 result changed from struct in_addr to struct aockaddr_in to store port number
80 */
81int ast_dnsmgr_lookup(const char *name, struct sockaddr_in *result, struct ast_dnsmgr_entry **dnsmgr, const char *service);
82
83/*!
84 * \brief Force a refresh of a dnsmgr entry
85 *
86 * \retval non-zero if the result is different than the previous result
87 * \retval zero if the result is the same as the previous result
88 */
89int ast_dnsmgr_refresh(struct ast_dnsmgr_entry *entry);
90
91/*!
92 * \brief Check is see if a dnsmgr entry has changed
93 *
94 * \retval non-zero if the dnsmgr entry has changed since the last call to
95 * this function
96 * \retval zero if the dnsmgr entry has not changed since the last call to
97 * this function
98 */
99int ast_dnsmgr_changed(struct ast_dnsmgr_entry *entry);
100
101#if defined(__cplusplus) || defined(c_plusplus)
102}
103#endif /* c_plusplus */
104
105#endif /* ASTERISK_DNSMGR_H */
0106
=== added directory '.pc/dnsmgr-A-SRV-handling/main'
=== added file '.pc/dnsmgr-A-SRV-handling/main/acl.c'
--- .pc/dnsmgr-A-SRV-handling/main/acl.c 1970-01-01 00:00:00 +0000
+++ .pc/dnsmgr-A-SRV-handling/main/acl.c 2011-01-20 23:43:55 +0000
@@ -0,0 +1,541 @@
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 1999 - 2006, Digium, Inc.
5 *
6 * Mark Spencer <markster@digium.com>
7 *
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
13 *
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
17 */
18
19/*! \file
20 *
21 * \brief Various sorts of access control
22 *
23 * \author Mark Spencer <markster@digium.com>
24 */
25
26#include "asterisk.h"
27
28ASTERISK_FILE_VERSION(__FILE__, "$Revision: 248849 $")
29
30#include "asterisk/network.h"
31
32#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__Darwin__)
33#include <fcntl.h>
34#include <net/route.h>
35#endif
36
37#if defined(SOLARIS)
38#include <sys/sockio.h>
39#include <net/if.h>
40#elif defined(HAVE_GETIFADDRS)
41#include <ifaddrs.h>
42#endif
43
44#include "asterisk/acl.h"
45#include "asterisk/channel.h"
46#include "asterisk/utils.h"
47#include "asterisk/lock.h"
48#include "asterisk/srv.h"
49
50#if (!defined(SOLARIS) && !defined(HAVE_GETIFADDRS))
51static int get_local_address(struct in_addr *ourip)
52{
53 return -1;
54}
55#else
56static void score_address(const struct sockaddr_in *sin, struct in_addr *best_addr, int *best_score)
57{
58 const char *address;
59 int score;
60
61 address = ast_inet_ntoa(sin->sin_addr);
62
63 /* RFC 1700 alias for the local network */
64 if (address[0] == '0') {
65 score = -25;
66 /* RFC 1700 localnet */
67 } else if (strncmp(address, "127", 3) == 0) {
68 score = -20;
69 /* RFC 1918 non-public address space */
70 } else if (strncmp(address, "10.", 3) == 0) {
71 score = -5;
72 /* RFC 1918 non-public address space */
73 } else if (strncmp(address, "172", 3) == 0) {
74 /* 172.16.0.0 - 172.19.255.255, but not 172.160.0.0 - 172.169.255.255 */
75 if (address[4] == '1' && address[5] >= '6' && address[6] == '.') {
76 score = -5;
77 /* 172.20.0.0 - 172.29.255.255, but not 172.200.0.0 - 172.255.255.255 nor 172.2.0.0 - 172.2.255.255 */
78 } else if (address[4] == '2' && address[6] == '.') {
79 score = -5;
80 /* 172.30.0.0 - 172.31.255.255 */
81 } else if (address[4] == '3' && address[5] <= '1') {
82 score = -5;
83 /* All other 172 addresses are public */
84 } else {
85 score = 0;
86 }
87 /* RFC 2544 Benchmark test range (198.18.0.0 - 198.19.255.255, but not 198.180.0.0 - 198.199.255.255) */
88 } else if (strncmp(address, "198.1", 5) == 0 && address[5] >= '8' && address[6] == '.') {
89 score = -10;
90 /* RFC 1918 non-public address space */
91 } else if (strncmp(address, "192.168", 7) == 0) {
92 score = -5;
93 /* RFC 3330 Zeroconf network */
94 } else if (strncmp(address, "169.254", 7) == 0) {
95 /*!\note Better score than a test network, but not quite as good as RFC 1918
96 * address space. The reason is that some Linux distributions automatically
97 * configure a Zeroconf address before trying DHCP, so we want to prefer a
98 * DHCP lease to a Zeroconf address.
99 */
100 score = -10;
101 /* RFC 3330 Test network */
102 } else if (strncmp(address, "192.0.2.", 8) == 0) {
103 score = -15;
104 /* Every other address should be publically routable */
105 } else {
106 score = 0;
107 }
108
109 if (score > *best_score) {
110 *best_score = score;
111 memcpy(best_addr, &sin->sin_addr, sizeof(*best_addr));
112 }
113}
114
115static int get_local_address(struct in_addr *ourip)
116{
117 int s, res = -1;
118#ifdef SOLARIS
119 struct lifreq *ifr = NULL;
120 struct lifnum ifn;
121 struct lifconf ifc;
122 struct sockaddr_in *sa;
123 char *buf = NULL;
124 int bufsz, x;
125#endif /* SOLARIS */
126#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__linux__) || defined(__Darwin__)
127 struct ifaddrs *ifap, *ifaphead;
128 int rtnerr;
129 const struct sockaddr_in *sin;
130#endif /* BSD_OR_LINUX */
131 struct in_addr best_addr;
132 int best_score = -100;
133 memset(&best_addr, 0, sizeof(best_addr));
134
135#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__linux__) || defined(__Darwin__)
136 rtnerr = getifaddrs(&ifaphead);
137 if (rtnerr) {
138 perror(NULL);
139 return -1;
140 }
141#endif /* BSD_OR_LINUX */
142
143 s = socket(AF_INET, SOCK_STREAM, 0);
144
145 if (s > 0) {
146#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__linux__) || defined(__Darwin__)
147 for (ifap = ifaphead; ifap; ifap = ifap->ifa_next) {
148
149 if (ifap->ifa_addr && ifap->ifa_addr->sa_family == AF_INET) {
150 sin = (const struct sockaddr_in *) ifap->ifa_addr;
151 score_address(sin, &best_addr, &best_score);
152 res = 0;
153
154 if (best_score == 0) {
155 break;
156 }
157 }
158 }
159#endif /* BSD_OR_LINUX */
160
161 /* There is no reason whatsoever that this shouldn't work on Linux or BSD also. */
162#ifdef SOLARIS
163 /* Get a count of interfaces on the machine */
164 ifn.lifn_family = AF_INET;
165 ifn.lifn_flags = 0;
166 ifn.lifn_count = 0;
167 if (ioctl(s, SIOCGLIFNUM, &ifn) < 0) {
168 close(s);
169 return -1;
170 }
171
172 bufsz = ifn.lifn_count * sizeof(struct lifreq);
173 if (!(buf = malloc(bufsz))) {
174 close(s);
175 return -1;
176 }
177 memset(buf, 0, bufsz);
178
179 /* Get a list of interfaces on the machine */
180 ifc.lifc_len = bufsz;
181 ifc.lifc_buf = buf;
182 ifc.lifc_family = AF_INET;
183 ifc.lifc_flags = 0;
184 if (ioctl(s, SIOCGLIFCONF, &ifc) < 0) {
185 close(s);
186 free(buf);
187 return -1;
188 }
189
190 for (ifr = ifc.lifc_req, x = 0; x < ifn.lifn_count; ifr++, x++) {
191 sa = (struct sockaddr_in *)&(ifr->lifr_addr);
192 score_address(sa, &best_addr, &best_score);
193 res = 0;
194
195 if (best_score == 0) {
196 break;
197 }
198 }
199
200 free(buf);
201#endif /* SOLARIS */
202
203 close(s);
204 }
205#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__linux__) || defined(__Darwin__)
206 freeifaddrs(ifaphead);
207#endif /* BSD_OR_LINUX */
208
209 if (res == 0 && ourip) {
210 memcpy(ourip, &best_addr, sizeof(*ourip));
211 }
212 return res;
213}
214#endif /* HAVE_GETIFADDRS */
215
216/* Free HA structure */
217void ast_free_ha(struct ast_ha *ha)
218{
219 struct ast_ha *hal;
220 while (ha) {
221 hal = ha;
222 ha = ha->next;
223 ast_free(hal);
224 }
225}
226
227/* Copy HA structure */
228void ast_copy_ha(const struct ast_ha *from, struct ast_ha *to)
229{
230 memcpy(&to->netaddr, &from->netaddr, sizeof(from->netaddr));
231 memcpy(&to->netmask, &from->netmask, sizeof(from->netmask));
232 to->sense = from->sense;
233}
234
235/* Create duplicate of ha structure */
236static struct ast_ha *ast_duplicate_ha(struct ast_ha *original)
237{
238 struct ast_ha *new_ha;
239
240 if ((new_ha = ast_malloc(sizeof(*new_ha)))) {
241 /* Copy from original to new object */
242 ast_copy_ha(original, new_ha);
243 }
244
245 return new_ha;
246}
247
248/* Create duplicate HA link list */
249/* Used in chan_sip2 templates */
250struct ast_ha *ast_duplicate_ha_list(struct ast_ha *original)
251{
252 struct ast_ha *start = original;
253 struct ast_ha *ret = NULL;
254 struct ast_ha *current, *prev = NULL;
255
256 while (start) {
257 current = ast_duplicate_ha(start); /* Create copy of this object */
258 if (prev) {
259 prev->next = current; /* Link previous to this object */
260 }
261
262 if (!ret) {
263 ret = current; /* Save starting point */
264 }
265
266 start = start->next; /* Go to next object */
267 prev = current; /* Save pointer to this object */
268 }
269 return ret; /* Return start of list */
270}
271
272struct ast_ha *ast_append_ha(const char *sense, const char *stuff, struct ast_ha *path, int *error)
273{
274 struct ast_ha *ha;
275 char *nm;
276 struct ast_ha *prev = NULL;
277 struct ast_ha *ret;
278 int x;
279 char *tmp = ast_strdupa(stuff);
280
281 ret = path;
282 while (path) {
283 prev = path;
284 path = path->next;
285 }
286
287 if (!(ha = ast_malloc(sizeof(*ha)))) {
288 return ret;
289 }
290
291 if (!(nm = strchr(tmp, '/'))) {
292 /* assume /32. Yes, htonl does not do anything for this particular mask
293 but we better use it to show we remember about byte order */
294 ha->netmask.s_addr = htonl(0xFFFFFFFF);
295 } else {
296 *nm = '\0';
297 nm++;
298
299 if (!strchr(nm, '.')) {
300 if ((sscanf(nm, "%30d", &x) == 1) && (x >= 0) && (x <= 32)) {
301 if (x == 0) {
302 /* This is special-cased to prevent unpredictable
303 * behavior of shifting left 32 bits
304 */
305 ha->netmask.s_addr = 0;
306 } else {
307 ha->netmask.s_addr = htonl(0xFFFFFFFF << (32 - x));
308 }
309 } else {
310 ast_log(LOG_WARNING, "Invalid CIDR in %s\n", stuff);
311 ast_free(ha);
312 if (error) {
313 *error = 1;
314 }
315 return ret;
316 }
317 } else if (!inet_aton(nm, &ha->netmask)) {
318 ast_log(LOG_WARNING, "Invalid mask in %s\n", stuff);
319 ast_free(ha);
320 if (error) {
321 *error = 1;
322 }
323 return ret;
324 }
325 }
326
327 if (!inet_aton(tmp, &ha->netaddr)) {
328 ast_log(LOG_WARNING, "Invalid IP address in %s\n", stuff);
329 ast_free(ha);
330 if (error) {
331 *error = 1;
332 }
333 return ret;
334 }
335
336 ha->netaddr.s_addr &= ha->netmask.s_addr;
337
338 ha->sense = strncasecmp(sense, "p", 1) ? AST_SENSE_DENY : AST_SENSE_ALLOW;
339
340 ha->next = NULL;
341 if (prev) {
342 prev->next = ha;
343 } else {
344 ret = ha;
345 }
346
347 ast_debug(1, "%s/%s sense %d appended to acl for peer\n", ast_strdupa(ast_inet_ntoa(ha->netaddr)), ast_strdupa(ast_inet_ntoa(ha->netmask)), ha->sense);
348
349 return ret;
350}
351
352int ast_apply_ha(struct ast_ha *ha, struct sockaddr_in *sin)
353{
354 /* Start optimistic */
355 int res = AST_SENSE_ALLOW;
356 while (ha) {
357#if 0 /* debugging code */
358 char iabuf[INET_ADDRSTRLEN];
359 char iabuf2[INET_ADDRSTRLEN];
360 /* DEBUG */
361 ast_copy_string(iabuf, ast_inet_ntoa(sin->sin_addr), sizeof(iabuf));
362 ast_copy_string(iabuf2, ast_inet_ntoa(ha->netaddr), sizeof(iabuf2));
363 ast_debug(1, "##### Testing %s with %s\n", iabuf, iabuf2);
364#endif
365 /* For each rule, if this address and the netmask = the net address
366 apply the current rule */
367 if ((sin->sin_addr.s_addr & ha->netmask.s_addr) == ha->netaddr.s_addr) {
368 res = ha->sense;
369 }
370 ha = ha->next;
371 }
372 return res;
373}
374
375int ast_get_ip_or_srv(struct sockaddr_in *sin, const char *value, const char *service)
376{
377 struct hostent *hp;
378 struct ast_hostent ahp;
379 char srv[256];
380 char host[256];
381 int tportno = ntohs(sin->sin_port);
382 if (service) {
383 snprintf(srv, sizeof(srv), "%s.%s", service, value);
384 if (ast_get_srv(NULL, host, sizeof(host), &tportno, srv) > 0) {
385 sin->sin_port = htons(tportno);
386 value = host;
387 }
388 }
389 if ((hp = ast_gethostbyname(value, &ahp))) {
390 memcpy(&sin->sin_addr, hp->h_addr, sizeof(sin->sin_addr));
391 } else {
392 ast_log(LOG_WARNING, "Unable to lookup '%s'\n", value);
393 return -1;
394 }
395 return 0;
396}
397
398struct dscp_codepoint {
399 char *name;
400 unsigned int space;
401};
402
403/* IANA registered DSCP codepoints */
404
405static const struct dscp_codepoint dscp_pool1[] = {
406 { "CS0", 0x00 },
407 { "CS1", 0x08 },
408 { "CS2", 0x10 },
409 { "CS3", 0x18 },
410 { "CS4", 0x20 },
411 { "CS5", 0x28 },
412 { "CS6", 0x30 },
413 { "CS7", 0x38 },
414 { "AF11", 0x0A },
415 { "AF12", 0x0C },
416 { "AF13", 0x0E },
417 { "AF21", 0x12 },
418 { "AF22", 0x14 },
419 { "AF23", 0x16 },
420 { "AF31", 0x1A },
421 { "AF32", 0x1C },
422 { "AF33", 0x1E },
423 { "AF41", 0x22 },
424 { "AF42", 0x24 },
425 { "AF43", 0x26 },
426 { "EF", 0x2E },
427};
428
429int ast_str2cos(const char *value, unsigned int *cos)
430{
431 int fval;
432
433 if (sscanf(value, "%30d", &fval) == 1) {
434 if (fval < 8) {
435 *cos = fval;
436 return 0;
437 }
438 }
439
440 return -1;
441}
442
443int ast_str2tos(const char *value, unsigned int *tos)
444{
445 int fval;
446 unsigned int x;
447
448 if (sscanf(value, "%30i", &fval) == 1) {
449 *tos = fval & 0xFF;
450 return 0;
451 }
452
453 for (x = 0; x < ARRAY_LEN(dscp_pool1); x++) {
454 if (!strcasecmp(value, dscp_pool1[x].name)) {
455 *tos = dscp_pool1[x].space << 2;
456 return 0;
457 }
458 }
459
460 return -1;
461}
462
463const char *ast_tos2str(unsigned int tos)
464{
465 unsigned int x;
466
467 for (x = 0; x < ARRAY_LEN(dscp_pool1); x++) {
468 if (dscp_pool1[x].space == (tos >> 2)) {
469 return dscp_pool1[x].name;
470 }
471 }
472
473 return "unknown";
474}
475
476int ast_get_ip(struct sockaddr_in *sin, const char *value)
477{
478 return ast_get_ip_or_srv(sin, value, NULL);
479}
480
481int ast_ouraddrfor(struct in_addr *them, struct in_addr *us)
482{
483 int s;
484 struct sockaddr_in sin;
485 socklen_t slen;
486
487 if ((s = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
488 ast_log(LOG_ERROR, "Cannot create socket\n");
489 return -1;
490 }
491 sin.sin_family = AF_INET;
492 sin.sin_port = htons(5060);
493 sin.sin_addr = *them;
494 if (connect(s, (struct sockaddr *)&sin, sizeof(sin))) {
495 ast_log(LOG_WARNING, "Cannot connect\n");
496 close(s);
497 return -1;
498 }
499 slen = sizeof(sin);
500 if (getsockname(s, (struct sockaddr *)&sin, &slen)) {
501 ast_log(LOG_WARNING, "Cannot get socket name\n");
502 close(s);
503 return -1;
504 }
505 close(s);
506 ast_debug(3, "Found IP address for this socket\n");
507 *us = sin.sin_addr;
508 return 0;
509}
510
511int ast_find_ourip(struct in_addr *ourip, struct sockaddr_in bindaddr)
512{
513 char ourhost[MAXHOSTNAMELEN] = "";
514 struct ast_hostent ahp;
515 struct hostent *hp;
516 struct in_addr saddr;
517
518 /* just use the bind address if it is nonzero */
519 if (ntohl(bindaddr.sin_addr.s_addr)) {
520 memcpy(ourip, &bindaddr.sin_addr, sizeof(*ourip));
521 ast_debug(3, "Attached to given IP address\n");
522 return 0;
523 }
524 /* try to use our hostname */
525 if (gethostname(ourhost, sizeof(ourhost) - 1)) {
526 ast_log(LOG_WARNING, "Unable to get hostname\n");
527 } else {
528 if ((hp = ast_gethostbyname(ourhost, &ahp))) {
529 memcpy(ourip, hp->h_addr, sizeof(*ourip));
530 ast_debug(3, "Found one IP address based on local hostname %s.\n", ourhost);
531 return 0;
532 }
533 }
534 ast_debug(3, "Trying to check A.ROOT-SERVERS.NET and get our IP address for that connection\n");
535 /* A.ROOT-SERVERS.NET. */
536 if (inet_aton("198.41.0.4", &saddr) && !ast_ouraddrfor(&saddr, ourip)) {
537 return 0;
538 }
539 return get_local_address(ourip);
540}
541
0542
=== added file '.pc/dnsmgr-A-SRV-handling/main/dnsmgr.c'
--- .pc/dnsmgr-A-SRV-handling/main/dnsmgr.c 1970-01-01 00:00:00 +0000
+++ .pc/dnsmgr-A-SRV-handling/main/dnsmgr.c 2011-01-20 23:43:55 +0000
@@ -0,0 +1,439 @@
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 2005-2006, Kevin P. Fleming
5 *
6 * Kevin P. Fleming <kpfleming@digium.com>
7 *
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
13 *
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
17 */
18
19/*! \file
20 *
21 * \brief Background DNS update manager
22 *
23 * \author Kevin P. Fleming <kpfleming@digium.com>
24 *
25 * \bug There is a minor race condition. In the event that an IP address
26 * of a dnsmgr managed host changes, there is the potential for the consumer
27 * of that address to access the in_addr data at the same time that the dnsmgr
28 * thread is in the middle of updating it to the new address.
29 */
30
31#include "asterisk.h"
32
33ASTERISK_FILE_VERSION(__FILE__, "$Revision: 211580 $")
34
35#include "asterisk/_private.h"
36#include <regex.h>
37#include <signal.h>
38
39#include "asterisk/dnsmgr.h"
40#include "asterisk/linkedlists.h"
41#include "asterisk/utils.h"
42#include "asterisk/config.h"
43#include "asterisk/sched.h"
44#include "asterisk/cli.h"
45#include "asterisk/manager.h"
46#include "asterisk/acl.h"
47
48static struct sched_context *sched;
49static int refresh_sched = -1;
50static pthread_t refresh_thread = AST_PTHREADT_NULL;
51
52struct ast_dnsmgr_entry {
53 /*! where we will store the resulting IP address and port number */
54 struct sockaddr_in *result;
55 /*! the last result, used to check if address/port has changed */
56 struct sockaddr_in last;
57 /*! SRV record to lookup, if provided. Composed of service, protocol, and domain name: _Service._Proto.Name */
58 char *service;
59 /*! Set to 1 if the entry changes */
60 unsigned int changed:1;
61 ast_mutex_t lock;
62 AST_RWLIST_ENTRY(ast_dnsmgr_entry) list;
63 /*! just 1 here, but we use calloc to allocate the correct size */
64 char name[1];
65};
66
67static AST_RWLIST_HEAD_STATIC(entry_list, ast_dnsmgr_entry);
68
69AST_MUTEX_DEFINE_STATIC(refresh_lock);
70
71#define REFRESH_DEFAULT 300
72
73static int enabled;
74static int refresh_interval;
75
76struct refresh_info {
77 struct entry_list *entries;
78 int verbose;
79 unsigned int regex_present:1;
80 regex_t filter;
81};
82
83static struct refresh_info master_refresh_info = {
84 .entries = &entry_list,
85 .verbose = 0,
86};
87
88struct ast_dnsmgr_entry *ast_dnsmgr_get(const char *name, struct sockaddr_in *result, const char *service)
89{
90 struct ast_dnsmgr_entry *entry;
91 int total_size = sizeof(*entry) + strlen(name) + (service ? strlen(service) + 1 : 0);
92
93 if (!result || ast_strlen_zero(name) || !(entry = ast_calloc(1, total_size)))
94 return NULL;
95
96 entry->result = result;
97 ast_mutex_init(&entry->lock);
98 strcpy(entry->name, name);
99 memcpy(&entry->last, result, sizeof(entry->last));
100 if (service) {
101 entry->service = ((char *) entry) + sizeof(*entry) + strlen(name);
102 strcpy(entry->service, service);
103 }
104
105 AST_RWLIST_WRLOCK(&entry_list);
106 AST_RWLIST_INSERT_HEAD(&entry_list, entry, list);
107 AST_RWLIST_UNLOCK(&entry_list);
108
109 return entry;
110}
111
112void ast_dnsmgr_release(struct ast_dnsmgr_entry *entry)
113{
114 if (!entry)
115 return;
116
117 AST_RWLIST_WRLOCK(&entry_list);
118 AST_RWLIST_REMOVE(&entry_list, entry, list);
119 AST_RWLIST_UNLOCK(&entry_list);
120 ast_verb(4, "removing dns manager for '%s'\n", entry->name);
121
122 ast_mutex_destroy(&entry->lock);
123 ast_free(entry);
124}
125
126int ast_dnsmgr_lookup(const char *name, struct sockaddr_in *result, struct ast_dnsmgr_entry **dnsmgr, const char *service)
127{
128 if (ast_strlen_zero(name) || !result || !dnsmgr)
129 return -1;
130
131 if (*dnsmgr && !strcasecmp((*dnsmgr)->name, name))
132 return 0;
133
134 /* if it's actually an IP address and not a name,
135 there's no need for a managed lookup */
136 if (inet_aton(name, &result->sin_addr))
137 return 0;
138
139 ast_verb(4, "doing dnsmgr_lookup for '%s'\n", name);
140
141 /* do a lookup now but add a manager so it will automagically get updated in the background */
142 ast_get_ip_or_srv(result, name, service);
143
144 /* if dnsmgr is not enable don't bother adding an entry */
145 if (!enabled)
146 return 0;
147
148 ast_verb(3, "adding dns manager for '%s'\n", name);
149 *dnsmgr = ast_dnsmgr_get(name, result, service);
150 return !*dnsmgr;
151}
152
153/*
154 * Refresh a dnsmgr entry
155 */
156static int dnsmgr_refresh(struct ast_dnsmgr_entry *entry, int verbose)
157{
158 char iabuf[INET_ADDRSTRLEN];
159 char iabuf2[INET_ADDRSTRLEN];
160 struct sockaddr_in tmp;
161 int changed = 0;
162
163 ast_mutex_lock(&entry->lock);
164 if (verbose)
165 ast_verb(3, "refreshing '%s'\n", entry->name);
166
167 tmp.sin_port = entry->last.sin_port;
168
169 if (!ast_get_ip_or_srv(&tmp, entry->name, entry->service) && inaddrcmp(&tmp, &entry->last)) {
170 ast_copy_string(iabuf, ast_inet_ntoa(entry->last.sin_addr), sizeof(iabuf));
171 ast_copy_string(iabuf2, ast_inet_ntoa(tmp.sin_addr), sizeof(iabuf2));
172 ast_log(LOG_NOTICE, "dnssrv: host '%s' changed from %s:%d to %s:%d\n",
173 entry->name, iabuf, ntohs(entry->last.sin_port), iabuf2, ntohs(tmp.sin_port));
174 *entry->result = tmp;
175 entry->last = tmp;
176 changed = entry->changed = 1;
177 }
178
179 ast_mutex_unlock(&entry->lock);
180 return changed;
181}
182
183int ast_dnsmgr_refresh(struct ast_dnsmgr_entry *entry)
184{
185 return dnsmgr_refresh(entry, 0);
186}
187
188/*
189 * Check if dnsmgr entry has changed from since last call to this function
190 */
191int ast_dnsmgr_changed(struct ast_dnsmgr_entry *entry)
192{
193 int changed;
194
195 ast_mutex_lock(&entry->lock);
196
197 changed = entry->changed;
198 entry->changed = 0;
199
200 ast_mutex_unlock(&entry->lock);
201
202 return changed;
203}
204
205static void *do_refresh(void *data)
206{
207 for (;;) {
208 pthread_testcancel();
209 usleep((ast_sched_wait(sched)*1000));
210 pthread_testcancel();
211 ast_sched_runq(sched);
212 }
213 return NULL;
214}
215
216static int refresh_list(const void *data)
217{
218 struct refresh_info *info = (struct refresh_info *)data;
219 struct ast_dnsmgr_entry *entry;
220
221 /* if a refresh or reload is already in progress, exit now */
222 if (ast_mutex_trylock(&refresh_lock)) {
223 if (info->verbose)
224 ast_log(LOG_WARNING, "DNS Manager refresh already in progress.\n");
225 return -1;
226 }
227
228 ast_verb(3, "Refreshing DNS lookups.\n");
229 AST_RWLIST_RDLOCK(info->entries);
230 AST_RWLIST_TRAVERSE(info->entries, entry, list) {
231 if (info->regex_present && regexec(&info->filter, entry->name, 0, NULL, 0))
232 continue;
233
234 dnsmgr_refresh(entry, info->verbose);
235 }
236 AST_RWLIST_UNLOCK(info->entries);
237
238 ast_mutex_unlock(&refresh_lock);
239
240 /* automatically reschedule based on the interval */
241 return refresh_interval * 1000;
242}
243
244void dnsmgr_start_refresh(void)
245{
246 if (refresh_sched > -1) {
247 AST_SCHED_DEL(sched, refresh_sched);
248 refresh_sched = ast_sched_add_variable(sched, 100, refresh_list, &master_refresh_info, 1);
249 }
250}
251
252static int do_reload(int loading);
253
254static char *handle_cli_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
255{
256 switch (cmd) {
257 case CLI_INIT:
258 e->command = "dnsmgr reload";
259 e->usage =
260 "Usage: dnsmgr reload\n"
261 " Reloads the DNS manager configuration.\n";
262 return NULL;
263 case CLI_GENERATE:
264 return NULL;
265 }
266 if (a->argc > 2)
267 return CLI_SHOWUSAGE;
268
269 do_reload(0);
270 return CLI_SUCCESS;
271}
272
273static char *handle_cli_refresh(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
274{
275 struct refresh_info info = {
276 .entries = &entry_list,
277 .verbose = 1,
278 };
279 switch (cmd) {
280 case CLI_INIT:
281 e->command = "dnsmgr refresh";
282 e->usage =
283 "Usage: dnsmgr refresh [pattern]\n"
284 " Peforms an immediate refresh of the managed DNS entries.\n"
285 " Optional regular expression pattern is used to filter the entries to refresh.\n";
286 return NULL;
287 case CLI_GENERATE:
288 return NULL;
289 }
290
291 if (!enabled) {
292 ast_cli(a->fd, "DNS Manager is disabled.\n");
293 return 0;
294 }
295
296 if (a->argc > 3) {
297 return CLI_SHOWUSAGE;
298 }
299
300 if (a->argc == 3) {
301 if (regcomp(&info.filter, a->argv[2], REG_EXTENDED | REG_NOSUB)) {
302 return CLI_SHOWUSAGE;
303 } else {
304 info.regex_present = 1;
305 }
306 }
307
308 refresh_list(&info);
309
310 if (info.regex_present) {
311 regfree(&info.filter);
312 }
313
314 return CLI_SUCCESS;
315}
316
317static char *handle_cli_status(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
318{
319 int count = 0;
320 struct ast_dnsmgr_entry *entry;
321 switch (cmd) {
322 case CLI_INIT:
323 e->command = "dnsmgr status";
324 e->usage =
325 "Usage: dnsmgr status\n"
326 " Displays the DNS manager status.\n";
327 return NULL;
328 case CLI_GENERATE:
329 return NULL;
330 }
331
332 if (a->argc > 2)
333 return CLI_SHOWUSAGE;
334
335 ast_cli(a->fd, "DNS Manager: %s\n", enabled ? "enabled" : "disabled");
336 ast_cli(a->fd, "Refresh Interval: %d seconds\n", refresh_interval);
337 AST_RWLIST_RDLOCK(&entry_list);
338 AST_RWLIST_TRAVERSE(&entry_list, entry, list)
339 count++;
340 AST_RWLIST_UNLOCK(&entry_list);
341 ast_cli(a->fd, "Number of entries: %d\n", count);
342
343 return CLI_SUCCESS;
344}
345
346static struct ast_cli_entry cli_reload = AST_CLI_DEFINE(handle_cli_reload, "Reloads the DNS manager configuration");
347static struct ast_cli_entry cli_refresh = AST_CLI_DEFINE(handle_cli_refresh, "Performs an immediate refresh");
348static struct ast_cli_entry cli_status = AST_CLI_DEFINE(handle_cli_status, "Display the DNS manager status");
349
350int dnsmgr_init(void)
351{
352 if (!(sched = sched_context_create())) {
353 ast_log(LOG_ERROR, "Unable to create schedule context.\n");
354 return -1;
355 }
356 ast_cli_register(&cli_reload);
357 ast_cli_register(&cli_status);
358 ast_cli_register(&cli_refresh);
359 return do_reload(1);
360}
361
362int dnsmgr_reload(void)
363{
364 return do_reload(0);
365}
366
367static int do_reload(int loading)
368{
369 struct ast_config *config;
370 struct ast_flags config_flags = { loading ? 0 : CONFIG_FLAG_FILEUNCHANGED };
371 const char *interval_value;
372 const char *enabled_value;
373 int interval;
374 int was_enabled;
375 int res = -1;
376
377 config = ast_config_load2("dnsmgr.conf", "dnsmgr", config_flags);
378 if (config == CONFIG_STATUS_FILEMISSING || config == CONFIG_STATUS_FILEUNCHANGED || config == CONFIG_STATUS_FILEINVALID) {
379 return 0;
380 }
381
382 /* ensure that no refresh cycles run while the reload is in progress */
383 ast_mutex_lock(&refresh_lock);
384
385 /* reset defaults in preparation for reading config file */
386 refresh_interval = REFRESH_DEFAULT;
387 was_enabled = enabled;
388 enabled = 0;
389
390 AST_SCHED_DEL(sched, refresh_sched);
391
392 if (config) {
393 if ((enabled_value = ast_variable_retrieve(config, "general", "enable"))) {
394 enabled = ast_true(enabled_value);
395 }
396 if ((interval_value = ast_variable_retrieve(config, "general", "refreshinterval"))) {
397 if (sscanf(interval_value, "%30d", &interval) < 1)
398 ast_log(LOG_WARNING, "Unable to convert '%s' to a numeric value.\n", interval_value);
399 else if (interval < 0)
400 ast_log(LOG_WARNING, "Invalid refresh interval '%d' specified, using default\n", interval);
401 else
402 refresh_interval = interval;
403 }
404 ast_config_destroy(config);
405 }
406
407 if (enabled && refresh_interval)
408 ast_log(LOG_NOTICE, "Managed DNS entries will be refreshed every %d seconds.\n", refresh_interval);
409
410 /* if this reload enabled the manager, create the background thread
411 if it does not exist */
412 if (enabled) {
413 if (!was_enabled && (refresh_thread == AST_PTHREADT_NULL)) {
414 if (ast_pthread_create_background(&refresh_thread, NULL, do_refresh, NULL) < 0) {
415 ast_log(LOG_ERROR, "Unable to start refresh thread.\n");
416 }
417 }
418 /* make a background refresh happen right away */
419 refresh_sched = ast_sched_add_variable(sched, 100, refresh_list, &master_refresh_info, 1);
420 res = 0;
421 }
422 /* if this reload disabled the manager and there is a background thread,
423 kill it */
424 else if (!enabled && was_enabled && (refresh_thread != AST_PTHREADT_NULL)) {
425 /* wake up the thread so it will exit */
426 pthread_cancel(refresh_thread);
427 pthread_kill(refresh_thread, SIGURG);
428 pthread_join(refresh_thread, NULL);
429 refresh_thread = AST_PTHREADT_NULL;
430 res = 0;
431 }
432 else
433 res = 0;
434
435 ast_mutex_unlock(&refresh_lock);
436 manager_event(EVENT_FLAG_SYSTEM, "Reload", "Module: DNSmgr\r\nStatus: %s\r/nMessage: DNSmgr reload Requested\r\n", enabled ? "Enabled" : "Disabled");
437
438 return res;
439}
0440
=== added directory '.pc/unattended_fix'
=== added directory '.pc/unattended_fix/channels'
=== added file '.pc/unattended_fix/channels/chan_local.c'
--- .pc/unattended_fix/channels/chan_local.c 1970-01-01 00:00:00 +0000
+++ .pc/unattended_fix/channels/chan_local.c 2011-01-20 23:43:55 +0000
@@ -0,0 +1,885 @@
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 1999 - 2005, Digium, Inc.
5 *
6 * Mark Spencer <markster@digium.com>
7 *
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
13 *
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
17 */
18
19/*! \file
20 *
21 * \author Mark Spencer <markster@digium.com>
22 *
23 * \brief Local Proxy Channel
24 *
25 * \ingroup channel_drivers
26 */
27
28#include "asterisk.h"
29
30ASTERISK_FILE_VERSION(__FILE__, "$Revision: 237322 $")
31
32#include <fcntl.h>
33#include <sys/signal.h>
34
35#include "asterisk/lock.h"
36#include "asterisk/channel.h"
37#include "asterisk/config.h"
38#include "asterisk/module.h"
39#include "asterisk/pbx.h"
40#include "asterisk/sched.h"
41#include "asterisk/io.h"
42#include "asterisk/rtp.h"
43#include "asterisk/acl.h"
44#include "asterisk/callerid.h"
45#include "asterisk/file.h"
46#include "asterisk/cli.h"
47#include "asterisk/app.h"
48#include "asterisk/musiconhold.h"
49#include "asterisk/manager.h"
50#include "asterisk/stringfields.h"
51#include "asterisk/devicestate.h"
52
53static const char tdesc[] = "Local Proxy Channel Driver";
54
55#define IS_OUTBOUND(a,b) (a == b->chan ? 1 : 0)
56
57static struct ast_jb_conf g_jb_conf = {
58 .flags = 0,
59 .max_size = -1,
60 .resync_threshold = -1,
61 .impl = "",
62};
63
64static struct ast_channel *local_request(const char *type, int format, void *data, int *cause);
65static int local_digit_begin(struct ast_channel *ast, char digit);
66static int local_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
67static int local_call(struct ast_channel *ast, char *dest, int timeout);
68static int local_hangup(struct ast_channel *ast);
69static int local_answer(struct ast_channel *ast);
70static struct ast_frame *local_read(struct ast_channel *ast);
71static int local_write(struct ast_channel *ast, struct ast_frame *f);
72static int local_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen);
73static int local_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
74static int local_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen);
75static int local_sendtext(struct ast_channel *ast, const char *text);
76static int local_devicestate(void *data);
77static struct ast_channel *local_bridgedchannel(struct ast_channel *chan, struct ast_channel *bridge);
78
79/* PBX interface structure for channel registration */
80static const struct ast_channel_tech local_tech = {
81 .type = "Local",
82 .description = tdesc,
83 .capabilities = -1,
84 .requester = local_request,
85 .send_digit_begin = local_digit_begin,
86 .send_digit_end = local_digit_end,
87 .call = local_call,
88 .hangup = local_hangup,
89 .answer = local_answer,
90 .read = local_read,
91 .write = local_write,
92 .write_video = local_write,
93 .exception = local_read,
94 .indicate = local_indicate,
95 .fixup = local_fixup,
96 .send_html = local_sendhtml,
97 .send_text = local_sendtext,
98 .devicestate = local_devicestate,
99 .bridged_channel = local_bridgedchannel,
100};
101
102struct local_pvt {
103 ast_mutex_t lock; /* Channel private lock */
104 unsigned int flags; /* Private flags */
105 char context[AST_MAX_CONTEXT]; /* Context to call */
106 char exten[AST_MAX_EXTENSION]; /* Extension to call */
107 int reqformat; /* Requested format */
108 struct ast_jb_conf jb_conf; /*!< jitterbuffer configuration for this local channel */
109 struct ast_channel *owner; /* Master Channel - Bridging happens here */
110 struct ast_channel *chan; /* Outbound channel - PBX is run here */
111 struct ast_module_user *u_owner; /*! reference to keep the module loaded while in use */
112 struct ast_module_user *u_chan; /*! reference to keep the module loaded while in use */
113 AST_LIST_ENTRY(local_pvt) list; /* Next entity */
114};
115
116#define LOCAL_GLARE_DETECT (1 << 0) /*!< Detect glare on hangup */
117#define LOCAL_CANCEL_QUEUE (1 << 1) /*!< Cancel queue */
118#define LOCAL_ALREADY_MASQED (1 << 2) /*!< Already masqueraded */
119#define LOCAL_LAUNCHED_PBX (1 << 3) /*!< PBX was launched */
120#define LOCAL_NO_OPTIMIZATION (1 << 4) /*!< Do not optimize using masquerading */
121#define LOCAL_BRIDGE (1 << 5) /*!< Report back the "true" channel as being bridged to */
122#define LOCAL_MOH_PASSTHRU (1 << 6) /*!< Pass through music on hold start/stop frames */
123
124static AST_LIST_HEAD_STATIC(locals, local_pvt);
125
126/*! \brief Adds devicestate to local channels */
127static int local_devicestate(void *data)
128{
129 char *exten = ast_strdupa(data);
130 char *context = NULL, *opts = NULL;
131 int res;
132 struct local_pvt *lp;
133
134 if (!(context = strchr(exten, '@'))) {
135 ast_log(LOG_WARNING, "Someone used Local/%s somewhere without a @context. This is bad.\n", exten);
136 return AST_DEVICE_INVALID;
137 }
138
139 *context++ = '\0';
140
141 /* Strip options if they exist */
142 if ((opts = strchr(context, '/')))
143 *opts = '\0';
144
145 ast_debug(3, "Checking if extension %s@%s exists (devicestate)\n", exten, context);
146
147 res = ast_exists_extension(NULL, context, exten, 1, NULL);
148 if (!res)
149 return AST_DEVICE_INVALID;
150
151 res = AST_DEVICE_NOT_INUSE;
152 AST_LIST_LOCK(&locals);
153 AST_LIST_TRAVERSE(&locals, lp, list) {
154 if (!strcmp(exten, lp->exten) && !strcmp(context, lp->context) && lp->owner) {
155 res = AST_DEVICE_INUSE;
156 break;
157 }
158 }
159 AST_LIST_UNLOCK(&locals);
160
161 return res;
162}
163
164/*!
165 * \note Assumes the pvt is no longer in the pvts list
166 */
167static struct local_pvt *local_pvt_destroy(struct local_pvt *pvt)
168{
169 ast_mutex_destroy(&pvt->lock);
170 ast_free(pvt);
171 return NULL;
172}
173
174/*! \brief Return the bridged channel of a Local channel */
175static struct ast_channel *local_bridgedchannel(struct ast_channel *chan, struct ast_channel *bridge)
176{
177 struct local_pvt *p = bridge->tech_pvt;
178 struct ast_channel *bridged = bridge;
179
180 if (!p) {
181 ast_debug(1, "Asked for bridged channel on '%s'/'%s', returning <none>\n",
182 chan->name, bridge->name);
183 return NULL;
184 }
185
186 ast_mutex_lock(&p->lock);
187
188 if (ast_test_flag(p, LOCAL_BRIDGE)) {
189 /* Find the opposite channel */
190 bridged = (bridge == p->owner ? p->chan : p->owner);
191
192 /* Now see if the opposite channel is bridged to anything */
193 if (!bridged) {
194 bridged = bridge;
195 } else if (bridged->_bridge) {
196 bridged = bridged->_bridge;
197 }
198 }
199
200 ast_mutex_unlock(&p->lock);
201
202 return bridged;
203}
204
205static int local_queue_frame(struct local_pvt *p, int isoutbound, struct ast_frame *f,
206 struct ast_channel *us, int us_locked)
207{
208 struct ast_channel *other = NULL;
209
210 /* Recalculate outbound channel */
211 other = isoutbound ? p->owner : p->chan;
212
213 if (!other) {
214 return 0;
215 }
216
217 /* do not queue frame if generator is on both local channels */
218 if (us && us->generator && other->generator) {
219 return 0;
220 }
221
222 /* Set glare detection */
223 ast_set_flag(p, LOCAL_GLARE_DETECT);
224
225 /* Ensure that we have both channels locked */
226 while (other && ast_channel_trylock(other)) {
227 ast_mutex_unlock(&p->lock);
228 if (us && us_locked) {
229 do {
230 CHANNEL_DEADLOCK_AVOIDANCE(us);
231 } while (ast_mutex_trylock(&p->lock));
232 } else {
233 usleep(1);
234 ast_mutex_lock(&p->lock);
235 }
236 other = isoutbound ? p->owner : p->chan;
237 }
238
239 /* Since glare detection only occurs within this function, and because
240 * a pvt flag cannot be set without having the pvt lock, this is the only
241 * location where we could detect a cancelling of the queue. */
242 if (ast_test_flag(p, LOCAL_CANCEL_QUEUE)) {
243 /* We had a glare on the hangup. Forget all this business,
244 return and destroy p. */
245 ast_mutex_unlock(&p->lock);
246 p = local_pvt_destroy(p);
247 if (other) {
248 ast_channel_unlock(other);
249 }
250 return -1;
251 }
252
253 if (other) {
254 if (other->pbx || other->_bridge || !ast_strlen_zero(other->appl)) {
255 ast_queue_frame(other, f);
256 } /* else the frame won't go anywhere */
257 ast_channel_unlock(other);
258 }
259
260 ast_clear_flag(p, LOCAL_GLARE_DETECT);
261
262 return 0;
263}
264
265static int local_answer(struct ast_channel *ast)
266{
267 struct local_pvt *p = ast->tech_pvt;
268 int isoutbound;
269 int res = -1;
270
271 if (!p)
272 return -1;
273
274 ast_mutex_lock(&p->lock);
275 isoutbound = IS_OUTBOUND(ast, p);
276 if (isoutbound) {
277 /* Pass along answer since somebody answered us */
278 struct ast_frame answer = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER };
279 res = local_queue_frame(p, isoutbound, &answer, ast, 1);
280 } else
281 ast_log(LOG_WARNING, "Huh? Local is being asked to answer?\n");
282 if (!res)
283 ast_mutex_unlock(&p->lock);
284 return res;
285}
286
287static void check_bridge(struct local_pvt *p, int isoutbound)
288{
289 struct ast_channel_monitor *tmp;
290 if (ast_test_flag(p, LOCAL_ALREADY_MASQED) || ast_test_flag(p, LOCAL_NO_OPTIMIZATION) || !p->chan || !p->owner || (p->chan->_bridge != ast_bridged_channel(p->chan)))
291 return;
292
293 /* only do the masquerade if we are being called on the outbound channel,
294 if it has been bridged to another channel and if there are no pending
295 frames on the owner channel (because they would be transferred to the
296 outbound channel during the masquerade)
297 */
298 if (isoutbound && p->chan->_bridge /* Not ast_bridged_channel! Only go one step! */ && AST_LIST_EMPTY(&p->owner->readq)) {
299 /* Masquerade bridged channel into owner */
300 /* Lock everything we need, one by one, and give up if
301 we can't get everything. Remember, we'll get another
302 chance in just a little bit */
303 if (!ast_channel_trylock(p->chan->_bridge)) {
304 if (!ast_check_hangup(p->chan->_bridge)) {
305 if (!ast_channel_trylock(p->owner)) {
306 if (!ast_check_hangup(p->owner)) {
307 if (p->owner->monitor && !p->chan->_bridge->monitor) {
308 /* If a local channel is being monitored, we don't want a masquerade
309 * to cause the monitor to go away. Since the masquerade swaps the monitors,
310 * pre-swapping the monitors before the masquerade will ensure that the monitor
311 * ends up where it is expected.
312 */
313 tmp = p->owner->monitor;
314 p->owner->monitor = p->chan->_bridge->monitor;
315 p->chan->_bridge->monitor = tmp;
316 }
317 if (p->chan->audiohooks) {
318 struct ast_audiohook_list *audiohooks_swapper;
319 audiohooks_swapper = p->chan->audiohooks;
320 p->chan->audiohooks = p->owner->audiohooks;
321 p->owner->audiohooks = audiohooks_swapper;
322 }
323 ast_app_group_update(p->chan, p->owner);
324 ast_channel_masquerade(p->owner, p->chan->_bridge);
325 ast_set_flag(p, LOCAL_ALREADY_MASQED);
326 }
327 ast_channel_unlock(p->owner);
328 }
329 ast_channel_unlock(p->chan->_bridge);
330 }
331 }
332 /* We only allow masquerading in one 'direction'... it's important to preserve the state
333 (group variables, etc.) that live on p->chan->_bridge (and were put there by the dialplan)
334 when the local channels go away.
335 */
336#if 0
337 } else if (!isoutbound && p->owner && p->owner->_bridge && p->chan && AST_LIST_EMPTY(&p->chan->readq)) {
338 /* Masquerade bridged channel into chan */
339 if (!ast_mutex_trylock(&(p->owner->_bridge)->lock)) {
340 if (!ast_check_hangup(p->owner->_bridge)) {
341 if (!ast_mutex_trylock(&p->chan->lock)) {
342 if (!ast_check_hangup(p->chan)) {
343 ast_channel_masquerade(p->chan, p->owner->_bridge);
344 ast_set_flag(p, LOCAL_ALREADY_MASQED);
345 }
346 ast_mutex_unlock(&p->chan->lock);
347 }
348 }
349 ast_mutex_unlock(&(p->owner->_bridge)->lock);
350 }
351#endif
352 }
353}
354
355static struct ast_frame *local_read(struct ast_channel *ast)
356{
357 return &ast_null_frame;
358}
359
360static int local_write(struct ast_channel *ast, struct ast_frame *f)
361{
362 struct local_pvt *p = ast->tech_pvt;
363 int res = -1;
364 int isoutbound;
365
366 if (!p)
367 return -1;
368
369 /* Just queue for delivery to the other side */
370 ast_mutex_lock(&p->lock);
371 isoutbound = IS_OUTBOUND(ast, p);
372 if (f && (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO))
373 check_bridge(p, isoutbound);
374 if (!ast_test_flag(p, LOCAL_ALREADY_MASQED))
375 res = local_queue_frame(p, isoutbound, f, ast, 1);
376 else {
377 ast_debug(1, "Not posting to queue since already masked on '%s'\n", ast->name);
378 res = 0;
379 }
380 if (!res)
381 ast_mutex_unlock(&p->lock);
382 return res;
383}
384
385static int local_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
386{
387 struct local_pvt *p = newchan->tech_pvt;
388
389 if (!p)
390 return -1;
391
392 ast_mutex_lock(&p->lock);
393
394 if ((p->owner != oldchan) && (p->chan != oldchan)) {
395 ast_log(LOG_WARNING, "Old channel wasn't %p but was %p/%p\n", oldchan, p->owner, p->chan);
396 ast_mutex_unlock(&p->lock);
397 return -1;
398 }
399 if (p->owner == oldchan)
400 p->owner = newchan;
401 else
402 p->chan = newchan;
403 ast_mutex_unlock(&p->lock);
404 return 0;
405}
406
407static int local_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen)
408{
409 struct local_pvt *p = ast->tech_pvt;
410 int res = 0;
411 struct ast_frame f = { AST_FRAME_CONTROL, };
412 int isoutbound;
413
414 if (!p)
415 return -1;
416
417 /* If this is an MOH hold or unhold, do it on the Local channel versus real channel */
418 if (!ast_test_flag(p, LOCAL_MOH_PASSTHRU) && condition == AST_CONTROL_HOLD) {
419 ast_moh_start(ast, data, NULL);
420 } else if (!ast_test_flag(p, LOCAL_MOH_PASSTHRU) && condition == AST_CONTROL_UNHOLD) {
421 ast_moh_stop(ast);
422 } else {
423 /* Queue up a frame representing the indication as a control frame */
424 ast_mutex_lock(&p->lock);
425 isoutbound = IS_OUTBOUND(ast, p);
426 f.subclass = condition;
427 f.data.ptr = (void*)data;
428 f.datalen = datalen;
429 if (!(res = local_queue_frame(p, isoutbound, &f, ast, 1)))
430 ast_mutex_unlock(&p->lock);
431 }
432
433 return res;
434}
435
436static int local_digit_begin(struct ast_channel *ast, char digit)
437{
438 struct local_pvt *p = ast->tech_pvt;
439 int res = -1;
440 struct ast_frame f = { AST_FRAME_DTMF_BEGIN, };
441 int isoutbound;
442
443 if (!p)
444 return -1;
445
446 ast_mutex_lock(&p->lock);
447 isoutbound = IS_OUTBOUND(ast, p);
448 f.subclass = digit;
449 if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0)))
450 ast_mutex_unlock(&p->lock);
451
452 return res;
453}
454
455static int local_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
456{
457 struct local_pvt *p = ast->tech_pvt;
458 int res = -1;
459 struct ast_frame f = { AST_FRAME_DTMF_END, };
460 int isoutbound;
461
462 if (!p)
463 return -1;
464
465 ast_mutex_lock(&p->lock);
466 isoutbound = IS_OUTBOUND(ast, p);
467 f.subclass = digit;
468 f.len = duration;
469 if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0)))
470 ast_mutex_unlock(&p->lock);
471
472 return res;
473}
474
475static int local_sendtext(struct ast_channel *ast, const char *text)
476{
477 struct local_pvt *p = ast->tech_pvt;
478 int res = -1;
479 struct ast_frame f = { AST_FRAME_TEXT, };
480 int isoutbound;
481
482 if (!p)
483 return -1;
484
485 ast_mutex_lock(&p->lock);
486 isoutbound = IS_OUTBOUND(ast, p);
487 f.data.ptr = (char *) text;
488 f.datalen = strlen(text) + 1;
489 if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0)))
490 ast_mutex_unlock(&p->lock);
491 return res;
492}
493
494static int local_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen)
495{
496 struct local_pvt *p = ast->tech_pvt;
497 int res = -1;
498 struct ast_frame f = { AST_FRAME_HTML, };
499 int isoutbound;
500
501 if (!p)
502 return -1;
503
504 ast_mutex_lock(&p->lock);
505 isoutbound = IS_OUTBOUND(ast, p);
506 f.subclass = subclass;
507 f.data.ptr = (char *)data;
508 f.datalen = datalen;
509 if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0)))
510 ast_mutex_unlock(&p->lock);
511 return res;
512}
513
514/*! \brief Initiate new call, part of PBX interface
515 * dest is the dial string */
516static int local_call(struct ast_channel *ast, char *dest, int timeout)
517{
518 struct local_pvt *p = ast->tech_pvt;
519 int res;
520 struct ast_var_t *varptr = NULL, *new;
521 size_t len, namelen;
522
523 if (!p)
524 return -1;
525
526 ast_mutex_lock(&p->lock);
527
528 /*
529 * Note that cid_num and cid_name aren't passed in the ast_channel_alloc
530 * call, so it's done here instead.
531 */
532 p->chan->cid.cid_dnid = ast_strdup(p->owner->cid.cid_dnid);
533 p->chan->cid.cid_num = ast_strdup(p->owner->cid.cid_num);
534 p->chan->cid.cid_name = ast_strdup(p->owner->cid.cid_name);
535 p->chan->cid.cid_rdnis = ast_strdup(p->owner->cid.cid_rdnis);
536 p->chan->cid.cid_ani = ast_strdup(p->owner->cid.cid_ani);
537 p->chan->cid.cid_pres = p->owner->cid.cid_pres;
538 p->chan->cid.cid_ani2 = p->owner->cid.cid_ani2;
539 p->chan->cid.cid_ton = p->owner->cid.cid_ton;
540 p->chan->cid.cid_tns = p->owner->cid.cid_tns;
541 ast_string_field_set(p->chan, language, p->owner->language);
542 ast_string_field_set(p->chan, accountcode, p->owner->accountcode);
543 ast_string_field_set(p->chan, musicclass, p->owner->musicclass);
544 ast_cdr_update(p->chan);
545 p->chan->cdrflags = p->owner->cdrflags;
546
547 if (!ast_exists_extension(NULL, p->chan->context, p->chan->exten, 1, p->owner->cid.cid_num)) {
548 ast_log(LOG_NOTICE, "No such extension/context %s@%s while calling Local channel\n", p->chan->exten, p->chan->context);
549 ast_mutex_unlock(&p->lock);
550 return -1;
551 }
552
553 /* Make sure we inherit the ANSWERED_ELSEWHERE flag if it's set on the queue/dial call request in the dialplan */
554 if (ast_test_flag(ast, AST_FLAG_ANSWERED_ELSEWHERE)) {
555 ast_set_flag(p->chan, AST_FLAG_ANSWERED_ELSEWHERE);
556 }
557
558 /* copy the channel variables from the incoming channel to the outgoing channel */
559 /* Note that due to certain assumptions, they MUST be in the same order */
560 AST_LIST_TRAVERSE(&p->owner->varshead, varptr, entries) {
561 namelen = strlen(varptr->name);
562 len = sizeof(struct ast_var_t) + namelen + strlen(varptr->value) + 2;
563 if ((new = ast_calloc(1, len))) {
564 memcpy(new, varptr, len);
565 new->value = &(new->name[0]) + namelen + 1;
566 AST_LIST_INSERT_TAIL(&p->chan->varshead, new, entries);
567 }
568 }
569 ast_channel_datastore_inherit(p->owner, p->chan);
570
571 /* Start switch on sub channel */
572 if (!(res = ast_pbx_start(p->chan)))
573 ast_set_flag(p, LOCAL_LAUNCHED_PBX);
574
575 ast_mutex_unlock(&p->lock);
576 return res;
577}
578
579/*! \brief Hangup a call through the local proxy channel */
580static int local_hangup(struct ast_channel *ast)
581{
582 struct local_pvt *p = ast->tech_pvt;
583 int isoutbound;
584 struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_HANGUP, .data.uint32 = ast->hangupcause };
585 struct ast_channel *ochan = NULL;
586 int glaredetect = 0, res = 0;
587
588 if (!p)
589 return -1;
590
591 ast_mutex_lock(&p->lock);
592
593 isoutbound = IS_OUTBOUND(ast, p);
594
595 if (p->chan && ast_test_flag(ast, AST_FLAG_ANSWERED_ELSEWHERE)) {
596 ast_set_flag(p->chan, AST_FLAG_ANSWERED_ELSEWHERE);
597 ast_debug(2, "This local call has the ANSWERED_ELSEWHERE flag set.\n");
598 }
599
600 if (isoutbound) {
601 const char *status = pbx_builtin_getvar_helper(p->chan, "DIALSTATUS");
602 if ((status) && (p->owner)) {
603 /* Deadlock avoidance */
604 while (p->owner && ast_channel_trylock(p->owner)) {
605 ast_mutex_unlock(&p->lock);
606 if (ast) {
607 ast_channel_unlock(ast);
608 }
609 usleep(1);
610 if (ast) {
611 ast_channel_lock(ast);
612 }
613 ast_mutex_lock(&p->lock);
614 }
615 if (p->owner) {
616 pbx_builtin_setvar_helper(p->owner, "CHANLOCALSTATUS", status);
617 ast_channel_unlock(p->owner);
618 }
619 }
620 p->chan = NULL;
621 ast_clear_flag(p, LOCAL_LAUNCHED_PBX);
622 ast_module_user_remove(p->u_chan);
623 } else {
624 ast_module_user_remove(p->u_owner);
625 while (p->chan && ast_channel_trylock(p->chan)) {
626 DEADLOCK_AVOIDANCE(&p->lock);
627 }
628 p->owner = NULL;
629 if (p->chan) {
630 ast_queue_hangup(p->chan);
631 ast_channel_unlock(p->chan);
632 }
633 }
634
635 ast->tech_pvt = NULL;
636
637 if (!p->owner && !p->chan) {
638 /* Okay, done with the private part now, too. */
639 glaredetect = ast_test_flag(p, LOCAL_GLARE_DETECT);
640 /* If we have a queue holding, don't actually destroy p yet, but
641 let local_queue do it. */
642 if (glaredetect)
643 ast_set_flag(p, LOCAL_CANCEL_QUEUE);
644 /* Remove from list */
645 AST_LIST_LOCK(&locals);
646 AST_LIST_REMOVE(&locals, p, list);
647 AST_LIST_UNLOCK(&locals);
648 ast_mutex_unlock(&p->lock);
649 /* And destroy */
650 if (!glaredetect) {
651 p = local_pvt_destroy(p);
652 }
653 return 0;
654 }
655 if (p->chan && !ast_test_flag(p, LOCAL_LAUNCHED_PBX))
656 /* Need to actually hangup since there is no PBX */
657 ochan = p->chan;
658 else
659 res = local_queue_frame(p, isoutbound, &f, NULL, 1);
660 if (!res)
661 ast_mutex_unlock(&p->lock);
662 if (ochan)
663 ast_hangup(ochan);
664 return 0;
665}
666
667/*! \brief Create a call structure */
668static struct local_pvt *local_alloc(const char *data, int format)
669{
670 struct local_pvt *tmp = NULL;
671 char *c = NULL, *opts = NULL;
672
673 if (!(tmp = ast_calloc(1, sizeof(*tmp))))
674 return NULL;
675
676 /* Initialize private structure information */
677 ast_mutex_init(&tmp->lock);
678 ast_copy_string(tmp->exten, data, sizeof(tmp->exten));
679
680 memcpy(&tmp->jb_conf, &g_jb_conf, sizeof(tmp->jb_conf));
681
682 /* Look for options */
683 if ((opts = strchr(tmp->exten, '/'))) {
684 *opts++ = '\0';
685 if (strchr(opts, 'n'))
686 ast_set_flag(tmp, LOCAL_NO_OPTIMIZATION);
687 if (strchr(opts, 'j')) {
688 if (ast_test_flag(tmp, LOCAL_NO_OPTIMIZATION))
689 ast_set_flag(&tmp->jb_conf, AST_JB_ENABLED);
690 else {
691 ast_log(LOG_ERROR, "You must use the 'n' option for chan_local "
692 "to use the 'j' option to enable the jitterbuffer\n");
693 }
694 }
695 if (strchr(opts, 'b')) {
696 ast_set_flag(tmp, LOCAL_BRIDGE);
697 }
698 if (strchr(opts, 'm')) {
699 ast_set_flag(tmp, LOCAL_MOH_PASSTHRU);
700 }
701 }
702
703 /* Look for a context */
704 if ((c = strchr(tmp->exten, '@')))
705 *c++ = '\0';
706
707 ast_copy_string(tmp->context, c ? c : "default", sizeof(tmp->context));
708
709 tmp->reqformat = format;
710
711#if 0
712 /* We can't do this check here, because we don't know the CallerID yet, and
713 * the CallerID could potentially affect what step is actually taken (or
714 * even if that step exists). */
715 if (!ast_exists_extension(NULL, tmp->context, tmp->exten, 1, NULL)) {
716 ast_log(LOG_NOTICE, "No such extension/context %s@%s creating local channel\n", tmp->exten, tmp->context);
717 tmp = local_pvt_destroy(tmp);
718 } else {
719#endif
720 /* Add to list */
721 AST_LIST_LOCK(&locals);
722 AST_LIST_INSERT_HEAD(&locals, tmp, list);
723 AST_LIST_UNLOCK(&locals);
724#if 0
725 }
726#endif
727
728 return tmp;
729}
730
731/*! \brief Start new local channel */
732static struct ast_channel *local_new(struct local_pvt *p, int state)
733{
734 struct ast_channel *tmp = NULL, *tmp2 = NULL;
735 int randnum = ast_random() & 0xffff, fmt = 0;
736 const char *t;
737 int ama;
738
739 /* Allocate two new Asterisk channels */
740 /* safe accountcode */
741 if (p->owner && p->owner->accountcode)
742 t = p->owner->accountcode;
743 else
744 t = "";
745
746 if (p->owner)
747 ama = p->owner->amaflags;
748 else
749 ama = 0;
750 if (!(tmp = ast_channel_alloc(1, state, 0, 0, t, p->exten, p->context, ama, "Local/%s@%s-%04x;1", p->exten, p->context, randnum))
751 || !(tmp2 = ast_channel_alloc(1, AST_STATE_RING, 0, 0, t, p->exten, p->context, ama, "Local/%s@%s-%04x;2", p->exten, p->context, randnum))) {
752 if (tmp)
753 ast_channel_free(tmp);
754 if (tmp2)
755 ast_channel_free(tmp2);
756 ast_log(LOG_WARNING, "Unable to allocate channel structure(s)\n");
757 return NULL;
758 }
759
760 tmp2->tech = tmp->tech = &local_tech;
761
762 tmp->nativeformats = p->reqformat;
763 tmp2->nativeformats = p->reqformat;
764
765 /* Determine our read/write format and set it on each channel */
766 fmt = ast_best_codec(p->reqformat);
767 tmp->writeformat = fmt;
768 tmp2->writeformat = fmt;
769 tmp->rawwriteformat = fmt;
770 tmp2->rawwriteformat = fmt;
771 tmp->readformat = fmt;
772 tmp2->readformat = fmt;
773 tmp->rawreadformat = fmt;
774 tmp2->rawreadformat = fmt;
775
776 tmp->tech_pvt = p;
777 tmp2->tech_pvt = p;
778
779 p->owner = tmp;
780 p->chan = tmp2;
781 p->u_owner = ast_module_user_add(p->owner);
782 p->u_chan = ast_module_user_add(p->chan);
783
784 ast_copy_string(tmp->context, p->context, sizeof(tmp->context));
785 ast_copy_string(tmp2->context, p->context, sizeof(tmp2->context));
786 ast_copy_string(tmp2->exten, p->exten, sizeof(tmp->exten));
787 tmp->priority = 1;
788 tmp2->priority = 1;
789
790 ast_jb_configure(tmp, &p->jb_conf);
791
792 return tmp;
793}
794
795/*! \brief Part of PBX interface */
796static struct ast_channel *local_request(const char *type, int format, void *data, int *cause)
797{
798 struct local_pvt *p = NULL;
799 struct ast_channel *chan = NULL;
800
801 /* Allocate a new private structure and then Asterisk channel */
802 if ((p = local_alloc(data, format))) {
803 if (!(chan = local_new(p, AST_STATE_DOWN))) {
804 AST_LIST_LOCK(&locals);
805 AST_LIST_REMOVE(&locals, p, list);
806 AST_LIST_UNLOCK(&locals);
807 p = local_pvt_destroy(p);
808 }
809 }
810
811 return chan;
812}
813
814/*! \brief CLI command "local show channels" */
815static char *locals_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
816{
817 struct local_pvt *p = NULL;
818
819 switch (cmd) {
820 case CLI_INIT:
821 e->command = "local show channels";
822 e->usage =
823 "Usage: local show channels\n"
824 " Provides summary information on active local proxy channels.\n";
825 return NULL;
826 case CLI_GENERATE:
827 return NULL;
828 }
829
830 if (a->argc != 3)
831 return CLI_SHOWUSAGE;
832
833 AST_LIST_LOCK(&locals);
834 if (!AST_LIST_EMPTY(&locals)) {
835 AST_LIST_TRAVERSE(&locals, p, list) {
836 ast_mutex_lock(&p->lock);
837 ast_cli(a->fd, "%s -- %s@%s\n", p->owner ? p->owner->name : "<unowned>", p->exten, p->context);
838 ast_mutex_unlock(&p->lock);
839 }
840 } else
841 ast_cli(a->fd, "No local channels in use\n");
842 AST_LIST_UNLOCK(&locals);
843
844 return CLI_SUCCESS;
845}
846
847static struct ast_cli_entry cli_local[] = {
848 AST_CLI_DEFINE(locals_show, "List status of local channels"),
849};
850
851/*! \brief Load module into PBX, register channel */
852static int load_module(void)
853{
854 /* Make sure we can register our channel type */
855 if (ast_channel_register(&local_tech)) {
856 ast_log(LOG_ERROR, "Unable to register channel class 'Local'\n");
857 return AST_MODULE_LOAD_FAILURE;
858 }
859 ast_cli_register_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry));
860 return AST_MODULE_LOAD_SUCCESS;
861}
862
863/*! \brief Unload the local proxy channel from Asterisk */
864static int unload_module(void)
865{
866 struct local_pvt *p = NULL;
867
868 /* First, take us out of the channel loop */
869 ast_cli_unregister_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry));
870 ast_channel_unregister(&local_tech);
871 if (!AST_LIST_LOCK(&locals)) {
872 /* Hangup all interfaces if they have an owner */
873 AST_LIST_TRAVERSE(&locals, p, list) {
874 if (p->owner)
875 ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
876 }
877 AST_LIST_UNLOCK(&locals);
878 } else {
879 ast_log(LOG_WARNING, "Unable to lock the monitor\n");
880 return -1;
881 }
882 return 0;
883}
884
885AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Local Proxy Channel (Note: used internally by other modules)");
0886
=== modified file 'channels/chan_local.c'
--- channels/chan_local.c 2010-02-16 14:08:54 +0000
+++ channels/chan_local.c 2011-01-20 23:43:55 +0000
@@ -251,9 +251,10 @@
251 }251 }
252252
253 if (other) {253 if (other) {
254 if (other->pbx || other->_bridge || !ast_strlen_zero(other->appl)) {254 if (f->frametype == AST_FRAME_CONTROL && f->subclass == AST_CONTROL_RINGING) {
255 ast_queue_frame(other, f);255 ast_setstate(other, AST_STATE_RINGING);
256 } /* else the frame won't go anywhere */256 }
257 ast_queue_frame(other, f);
257 ast_channel_unlock(other);258 ast_channel_unlock(other);
258 }259 }
259260
260261
=== modified file 'debian/changelog'
--- debian/changelog 2010-04-13 16:27:27 +0000
+++ debian/changelog 2011-01-20 23:43:55 +0000
@@ -1,3 +1,30 @@
1asterisk (1:1.6.2.5-0ubuntu1.3) lucid-security; urgency=low
2
3 * SECURITY UPDATE: Stack buffer overflow in SIP channel driver. (LP: #705014)
4 - debian/patches/AST-2011-001-1.6.2: The size of the output buffer passed
5 to the ast_uri_encode function is now properly respected in main/utils.c.
6 Patch courtesy of upstream.
7 - CVE-2011-0495
8
9 -- Dave Walker (Daviey) <DaveWalker@ubuntu.com> Thu, 20 Jan 2011 23:31:55 +0000
10
11asterisk (1:1.6.2.5-0ubuntu1.2) lucid-proposed; urgency=low
12
13 * debian/patches/unattended_fix: Fix attended transfer call in 1.2.6.5
14 Patch based on Asterisk project's upstream patch (between 1.2.6.5 and
15 1.2.6.6 where issue is declared to be fixed see issue 16816 on Asterisk
16 bug tracker). (LP: #686625)
17
18 -- Lionel Porcheron <lionel@alveonet.org> Mon, 06 Dec 2010 16:56:12 +0100
19
20asterisk (1:1.6.2.5-0ubuntu1.1) lucid-proposed; urgency=low
21
22 * debian/patches/dnsmgr-A-SRV-handling: Resolve handling of A and SRV
23 record changes and problem with multiple A/SRV records returned.
24 Patch based on Asterisk project's upstream patch. (LP: #605358)
25
26 -- Dave Walker (Daviey) <DaveWalker@ubuntu.com> Wed, 14 Jul 2010 11:40:55 +0100
27
1asterisk (1:1.6.2.5-0ubuntu1) lucid; urgency=low28asterisk (1:1.6.2.5-0ubuntu1) lucid; urgency=low
229
3 * New upstream bugfix release (1.6.2.5)30 * New upstream bugfix release (1.6.2.5)
431
=== added file 'debian/patches/AST-2011-001-1.6.2'
--- debian/patches/AST-2011-001-1.6.2 1970-01-01 00:00:00 +0000
+++ debian/patches/AST-2011-001-1.6.2 2011-01-20 23:43:55 +0000
@@ -0,0 +1,52 @@
1Description: Stack buffer overflow in SIP channel driver.
2 Prevent buffer overflows in ast_uri_encode()
3Origin: upstream, http://downloads.asterisk.org/pub/security/AST-2011-001.html
4Bug-Ubuntu: https://launchpad.net/bugs/705014
5Bug-Debian: http://bugs.debian.org/610487
6Applied-Upstream: http://svnview.digium.com/svn/asterisk?view=revision&revision=301307
7Last-Update: 2011-01-20
8
9--- a/main/utils.c
10+++ b/main/utils.c
11@@ -385,28 +385,27 @@
12 char *reserved = ";/?:@&=+$,# "; /* Reserved chars */
13
14 const char *ptr = string; /* Start with the string */
15- char *out = NULL;
16- char *buf = NULL;
17+ char *out = outbuf;
18
19- ast_copy_string(outbuf, string, buflen);
20-
21- /* If there's no characters to convert, just go through and don't do anything */
22- while (*ptr) {
23+ /* If there's no characters to convert, just go through and copy the string */
24+ while (*ptr && out - outbuf < buflen - 1) {
25 if ((*ptr < 32) || (doreserved && strchr(reserved, *ptr))) {
26- /* Oops, we need to start working here */
27- if (!buf) {
28- buf = outbuf;
29- out = buf + (ptr - string) ; /* Set output ptr */
30+ if (out - outbuf >= buflen - 3) {
31+ break;
32 }
33+
34 out += sprintf(out, "%%%02x", (unsigned char) *ptr);
35- } else if (buf) {
36- *out = *ptr; /* Continue copying the string */
37+ } else {
38+ *out = *ptr; /* copy the character */
39 out++;
40- }
41+ }
42 ptr++;
43 }
44- if (buf)
45+
46+ if (buflen) {
47 *out = '\0';
48+ }
49+
50 return outbuf;
51 }
52
053
=== added file 'debian/patches/dnsmgr-A-SRV-handling'
--- debian/patches/dnsmgr-A-SRV-handling 1970-01-01 00:00:00 +0000
+++ debian/patches/dnsmgr-A-SRV-handling 2011-01-20 23:43:55 +0000
@@ -0,0 +1,132 @@
1Description: Resolve handling of A and SRV record changes and problem with multiple A/SRV records returned.
2Origin: upstream, https://issues.asterisk.org/file_download.php?file_id=25360&type=bug
3Bug: https://issues.asterisk.org/view.php?id=15827
4Bug-Ubuntu: https://launchpad.net/bugs/605358
5Last-Update: 2010-07-14
6--- a/include/asterisk/dnsmgr.h
7+++ b/include/asterisk/dnsmgr.h
8@@ -42,12 +42,12 @@
9 *
10 * \param name the hostname
11 * \param result where the DNS manager should store the IP address as it refreshes it.
12- * it.
13+ * \param service SRV prefix (optional, set to NULL to disable SRV)
14 *
15 * This function allocates a new DNS manager entry object, and fills it with the
16 * provided hostname and IP address. This function does not force an initial lookup
17- * of the IP address. So, generally, this should be used when the initial address
18- * is already known.
19+ * of the IP address. So, this should be used when the initial address
20+ * is already known and stored in result.
21 *
22 * \return a DNS manager entry
23 * \version 1.6.1 result changed from struct in_addr to struct sockaddr_in to store port number
24@@ -69,6 +69,7 @@
25 * \param name the hostname
26 * \param result where to store the IP address as the DNS manager refreshes it
27 * \param dnsmgr Where to store the allocate DNS manager entry
28+ * \param service SRV prefix (optional, set to NULL to disable SRV)
29 *
30 * This function allocates a new DNS manager entry object, and fills it with
31 * the provided hostname and IP address. This function _does_ force an initial
32--- a/main/acl.c
33+++ b/main/acl.c
34@@ -387,6 +387,7 @@
35 }
36 }
37 if ((hp = ast_gethostbyname(value, &ahp))) {
38+ sin->sin_family = hp->h_addrtype;
39 memcpy(&sin->sin_addr, hp->h_addr, sizeof(sin->sin_addr));
40 } else {
41 ast_log(LOG_WARNING, "Unable to lookup '%s'\n", value);
42--- a/main/dnsmgr.c
43+++ b/main/dnsmgr.c
44@@ -52,8 +52,6 @@
45 struct ast_dnsmgr_entry {
46 /*! where we will store the resulting IP address and port number */
47 struct sockaddr_in *result;
48- /*! the last result, used to check if address/port has changed */
49- struct sockaddr_in last;
50 /*! SRV record to lookup, if provided. Composed of service, protocol, and domain name: _Service._Proto.Name */
51 char *service;
52 /*! Set to 1 if the entry changes */
53@@ -85,6 +83,9 @@
54 .verbose = 0,
55 };
56
57+/*
58+ * Allocate a new DNS manager entry
59+ */
60 struct ast_dnsmgr_entry *ast_dnsmgr_get(const char *name, struct sockaddr_in *result, const char *service)
61 {
62 struct ast_dnsmgr_entry *entry;
63@@ -96,7 +97,6 @@
64 entry->result = result;
65 ast_mutex_init(&entry->lock);
66 strcpy(entry->name, name);
67- memcpy(&entry->last, result, sizeof(entry->last));
68 if (service) {
69 entry->service = ((char *) entry) + sizeof(*entry) + strlen(name);
70 strcpy(entry->service, service);
71@@ -109,6 +109,9 @@
72 return entry;
73 }
74
75+/*
76+ * Free a DNS manager entry
77+ */
78 void ast_dnsmgr_release(struct ast_dnsmgr_entry *entry)
79 {
80 if (!entry)
81@@ -123,6 +126,9 @@
82 ast_free(entry);
83 }
84
85+/*
86+ * Allocate a new DNS manager entry and perform the initial lookup before returning
87+ */
88 int ast_dnsmgr_lookup(const char *name, struct sockaddr_in *result, struct ast_dnsmgr_entry **dnsmgr, const char *service)
89 {
90 if (ast_strlen_zero(name) || !result || !dnsmgr)
91@@ -133,8 +139,10 @@
92
93 /* if it's actually an IP address and not a name,
94 there's no need for a managed lookup */
95- if (inet_aton(name, &result->sin_addr))
96+ if (inet_aton(name, &result->sin_addr)) {
97+ result->sin_family = AF_INET;
98 return 0;
99+ }
100
101 ast_verb(4, "doing dnsmgr_lookup for '%s'\n", name);
102
103@@ -151,7 +159,7 @@
104 }
105
106 /*
107- * Refresh a dnsmgr entry
108+ * Force a refresh of a dnsmgr entry
109 */
110 static int dnsmgr_refresh(struct ast_dnsmgr_entry *entry, int verbose)
111 {
112@@ -164,15 +172,15 @@
113 if (verbose)
114 ast_verb(3, "refreshing '%s'\n", entry->name);
115
116- tmp.sin_port = entry->last.sin_port;
117+ memset(&tmp, 0, sizeof(tmp));
118+ tmp.sin_port = entry->result->sin_port;
119
120- if (!ast_get_ip_or_srv(&tmp, entry->name, entry->service) && inaddrcmp(&tmp, &entry->last)) {
121- ast_copy_string(iabuf, ast_inet_ntoa(entry->last.sin_addr), sizeof(iabuf));
122+ if (!ast_get_ip_or_srv(&tmp, entry->name, entry->service) && inaddrcmp(&tmp, entry->result)) {
123+ ast_copy_string(iabuf, ast_inet_ntoa(entry->result->sin_addr), sizeof(iabuf));
124 ast_copy_string(iabuf2, ast_inet_ntoa(tmp.sin_addr), sizeof(iabuf2));
125 ast_log(LOG_NOTICE, "dnssrv: host '%s' changed from %s:%d to %s:%d\n",
126- entry->name, iabuf, ntohs(entry->last.sin_port), iabuf2, ntohs(tmp.sin_port));
127+ entry->name, iabuf, ntohs(entry->result->sin_port), iabuf2, ntohs(tmp.sin_port));
128 *entry->result = tmp;
129- entry->last = tmp;
130 changed = entry->changed = 1;
131 }
132
0133
=== modified file 'debian/patches/series'
--- debian/patches/series 2010-02-16 14:08:54 +0000
+++ debian/patches/series 2011-01-20 23:43:55 +0000
@@ -17,3 +17,6 @@
17dahdi_ptmp_nt17dahdi_ptmp_nt
18dahdi_pri_debug_spannums18dahdi_pri_debug_spannums
19sound_files19sound_files
20dnsmgr-A-SRV-handling
21unattended_fix
22AST-2011-001-1.6.2
2023
=== added file 'debian/patches/unattended_fix'
--- debian/patches/unattended_fix 1970-01-01 00:00:00 +0000
+++ debian/patches/unattended_fix 2011-01-20 23:43:55 +0000
@@ -0,0 +1,18 @@
1Index: asterisk-1.6.2.5/channels/chan_local.c
2===================================================================
3--- asterisk-1.6.2.5.orig/channels/chan_local.c 2010-12-06 16:37:54.000000000 +0100
4+++ asterisk-1.6.2.5/channels/chan_local.c 2010-12-06 16:54:56.000000000 +0100
5@@ -251,9 +251,10 @@
6 }
7
8 if (other) {
9- if (other->pbx || other->_bridge || !ast_strlen_zero(other->appl)) {
10- ast_queue_frame(other, f);
11- } /* else the frame won't go anywhere */
12+ if (f->frametype == AST_FRAME_CONTROL && f->subclass == AST_CONTROL_RINGING) {
13+ ast_setstate(other, AST_STATE_RINGING);
14+ }
15+ ast_queue_frame(other, f);
16 ast_channel_unlock(other);
17 }
18
019
=== modified file 'include/asterisk/dnsmgr.h'
--- include/asterisk/dnsmgr.h 2009-03-29 22:21:47 +0000
+++ include/asterisk/dnsmgr.h 2011-01-20 23:43:55 +0000
@@ -42,12 +42,12 @@
42 *42 *
43 * \param name the hostname43 * \param name the hostname
44 * \param result where the DNS manager should store the IP address as it refreshes it.44 * \param result where the DNS manager should store the IP address as it refreshes it.
45 * it.45 * \param service SRV prefix (optional, set to NULL to disable SRV)
46 *46 *
47 * This function allocates a new DNS manager entry object, and fills it with the47 * This function allocates a new DNS manager entry object, and fills it with the
48 * provided hostname and IP address. This function does not force an initial lookup48 * provided hostname and IP address. This function does not force an initial lookup
49 * of the IP address. So, generally, this should be used when the initial address49 * of the IP address. So, this should be used when the initial address
50 * is already known.50 * is already known and stored in result.
51 *51 *
52 * \return a DNS manager entry52 * \return a DNS manager entry
53 * \version 1.6.1 result changed from struct in_addr to struct sockaddr_in to store port number53 * \version 1.6.1 result changed from struct in_addr to struct sockaddr_in to store port number
@@ -69,6 +69,7 @@
69 * \param name the hostname69 * \param name the hostname
70 * \param result where to store the IP address as the DNS manager refreshes it70 * \param result where to store the IP address as the DNS manager refreshes it
71 * \param dnsmgr Where to store the allocate DNS manager entry71 * \param dnsmgr Where to store the allocate DNS manager entry
72 * \param service SRV prefix (optional, set to NULL to disable SRV)
72 *73 *
73 * This function allocates a new DNS manager entry object, and fills it with74 * This function allocates a new DNS manager entry object, and fills it with
74 * the provided hostname and IP address. This function _does_ force an initial75 * the provided hostname and IP address. This function _does_ force an initial
7576
=== modified file 'main/acl.c'
--- main/acl.c 2010-04-13 16:27:27 +0000
+++ main/acl.c 2011-01-20 23:43:55 +0000
@@ -387,6 +387,7 @@
387 }387 }
388 }388 }
389 if ((hp = ast_gethostbyname(value, &ahp))) {389 if ((hp = ast_gethostbyname(value, &ahp))) {
390 sin->sin_family = hp->h_addrtype;
390 memcpy(&sin->sin_addr, hp->h_addr, sizeof(sin->sin_addr));391 memcpy(&sin->sin_addr, hp->h_addr, sizeof(sin->sin_addr));
391 } else {392 } else {
392 ast_log(LOG_WARNING, "Unable to lookup '%s'\n", value);393 ast_log(LOG_WARNING, "Unable to lookup '%s'\n", value);
393394
=== modified file 'main/dnsmgr.c'
--- main/dnsmgr.c 2010-02-16 14:08:54 +0000
+++ main/dnsmgr.c 2011-01-20 23:43:55 +0000
@@ -52,8 +52,6 @@
52struct ast_dnsmgr_entry {52struct ast_dnsmgr_entry {
53 /*! where we will store the resulting IP address and port number */53 /*! where we will store the resulting IP address and port number */
54 struct sockaddr_in *result;54 struct sockaddr_in *result;
55 /*! the last result, used to check if address/port has changed */
56 struct sockaddr_in last;
57 /*! SRV record to lookup, if provided. Composed of service, protocol, and domain name: _Service._Proto.Name */55 /*! SRV record to lookup, if provided. Composed of service, protocol, and domain name: _Service._Proto.Name */
58 char *service;56 char *service;
59 /*! Set to 1 if the entry changes */57 /*! Set to 1 if the entry changes */
@@ -85,6 +83,9 @@
85 .verbose = 0,83 .verbose = 0,
86};84};
8785
86/*
87 * Allocate a new DNS manager entry
88 */
88struct ast_dnsmgr_entry *ast_dnsmgr_get(const char *name, struct sockaddr_in *result, const char *service)89struct ast_dnsmgr_entry *ast_dnsmgr_get(const char *name, struct sockaddr_in *result, const char *service)
89{90{
90 struct ast_dnsmgr_entry *entry;91 struct ast_dnsmgr_entry *entry;
@@ -96,7 +97,6 @@
96 entry->result = result;97 entry->result = result;
97 ast_mutex_init(&entry->lock);98 ast_mutex_init(&entry->lock);
98 strcpy(entry->name, name);99 strcpy(entry->name, name);
99 memcpy(&entry->last, result, sizeof(entry->last));
100 if (service) {100 if (service) {
101 entry->service = ((char *) entry) + sizeof(*entry) + strlen(name);101 entry->service = ((char *) entry) + sizeof(*entry) + strlen(name);
102 strcpy(entry->service, service);102 strcpy(entry->service, service);
@@ -109,6 +109,9 @@
109 return entry;109 return entry;
110}110}
111111
112/*
113 * Free a DNS manager entry
114 */
112void ast_dnsmgr_release(struct ast_dnsmgr_entry *entry)115void ast_dnsmgr_release(struct ast_dnsmgr_entry *entry)
113{116{
114 if (!entry)117 if (!entry)
@@ -123,6 +126,9 @@
123 ast_free(entry);126 ast_free(entry);
124}127}
125128
129/*
130 * Allocate a new DNS manager entry and perform the initial lookup before returning
131 */
126int ast_dnsmgr_lookup(const char *name, struct sockaddr_in *result, struct ast_dnsmgr_entry **dnsmgr, const char *service)132int ast_dnsmgr_lookup(const char *name, struct sockaddr_in *result, struct ast_dnsmgr_entry **dnsmgr, const char *service)
127{133{
128 if (ast_strlen_zero(name) || !result || !dnsmgr)134 if (ast_strlen_zero(name) || !result || !dnsmgr)
@@ -133,8 +139,10 @@
133139
134 /* if it's actually an IP address and not a name,140 /* if it's actually an IP address and not a name,
135 there's no need for a managed lookup */141 there's no need for a managed lookup */
136 if (inet_aton(name, &result->sin_addr))142 if (inet_aton(name, &result->sin_addr)) {
143 result->sin_family = AF_INET;
137 return 0;144 return 0;
145 }
138146
139 ast_verb(4, "doing dnsmgr_lookup for '%s'\n", name);147 ast_verb(4, "doing dnsmgr_lookup for '%s'\n", name);
140148
@@ -151,7 +159,7 @@
151}159}
152160
153/*161/*
154 * Refresh a dnsmgr entry162 * Force a refresh of a dnsmgr entry
155 */163 */
156static int dnsmgr_refresh(struct ast_dnsmgr_entry *entry, int verbose)164static int dnsmgr_refresh(struct ast_dnsmgr_entry *entry, int verbose)
157{165{
@@ -164,15 +172,15 @@
164 if (verbose)172 if (verbose)
165 ast_verb(3, "refreshing '%s'\n", entry->name);173 ast_verb(3, "refreshing '%s'\n", entry->name);
166174
167 tmp.sin_port = entry->last.sin_port;175 memset(&tmp, 0, sizeof(tmp));
176 tmp.sin_port = entry->result->sin_port;
168 177
169 if (!ast_get_ip_or_srv(&tmp, entry->name, entry->service) && inaddrcmp(&tmp, &entry->last)) {178 if (!ast_get_ip_or_srv(&tmp, entry->name, entry->service) && inaddrcmp(&tmp, entry->result)) {
170 ast_copy_string(iabuf, ast_inet_ntoa(entry->last.sin_addr), sizeof(iabuf));179 ast_copy_string(iabuf, ast_inet_ntoa(entry->result->sin_addr), sizeof(iabuf));
171 ast_copy_string(iabuf2, ast_inet_ntoa(tmp.sin_addr), sizeof(iabuf2));180 ast_copy_string(iabuf2, ast_inet_ntoa(tmp.sin_addr), sizeof(iabuf2));
172 ast_log(LOG_NOTICE, "dnssrv: host '%s' changed from %s:%d to %s:%d\n", 181 ast_log(LOG_NOTICE, "dnssrv: host '%s' changed from %s:%d to %s:%d\n",
173 entry->name, iabuf, ntohs(entry->last.sin_port), iabuf2, ntohs(tmp.sin_port));182 entry->name, iabuf, ntohs(entry->result->sin_port), iabuf2, ntohs(tmp.sin_port));
174 *entry->result = tmp;183 *entry->result = tmp;
175 entry->last = tmp;
176 changed = entry->changed = 1;184 changed = entry->changed = 1;
177 }185 }
178186
179187
=== modified file 'main/utils.c'
--- main/utils.c 2010-02-16 14:08:54 +0000
+++ main/utils.c 2011-01-20 23:43:55 +0000
@@ -385,28 +385,27 @@
385 char *reserved = ";/?:@&=+$,# "; /* Reserved chars */385 char *reserved = ";/?:@&=+$,# "; /* Reserved chars */
386386
387 const char *ptr = string; /* Start with the string */387 const char *ptr = string; /* Start with the string */
388 char *out = NULL;388 char *out = outbuf;
389 char *buf = NULL;389
390390 /* If there's no characters to convert, just go through and copy the string */
391 ast_copy_string(outbuf, string, buflen);391 while (*ptr && out - outbuf < buflen - 1) {
392
393 /* If there's no characters to convert, just go through and don't do anything */
394 while (*ptr) {
395 if ((*ptr < 32) || (doreserved && strchr(reserved, *ptr))) {392 if ((*ptr < 32) || (doreserved && strchr(reserved, *ptr))) {
396 /* Oops, we need to start working here */393 if (out - outbuf >= buflen - 3) {
397 if (!buf) {394 break;
398 buf = outbuf;
399 out = buf + (ptr - string) ; /* Set output ptr */
400 }395 }
396
401 out += sprintf(out, "%%%02x", (unsigned char) *ptr);397 out += sprintf(out, "%%%02x", (unsigned char) *ptr);
402 } else if (buf) {398 } else {
403 *out = *ptr; /* Continue copying the string */399 *out = *ptr; /* copy the character */
404 out++;400 out++;
405 } 401 }
406 ptr++;402 ptr++;
407 }403 }
408 if (buf)404
405 if (buflen) {
409 *out = '\0';406 *out = '\0';
407 }
408
410 return outbuf;409 return outbuf;
411}410}
412411

Subscribers

People subscribed via source and target branches

to all changes: