Merge lp:~davewalker/ubuntu/natty/asterisk/lp_705014 into lp:ubuntu/natty/asterisk
- Natty (11.04)
- lp_705014
- Merge into natty
Proposed by
Dave Walker
Status: | Needs review |
---|---|
Proposed branch: | lp:~davewalker/ubuntu/natty/asterisk/lp_705014 |
Merge into: | lp:ubuntu/natty/asterisk |
Diff against target: |
1987 lines (+1909/-15) 8 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 (+1/-0) debian/changelog (+10/-0) debian/patches/AST-2011-001-1.6.2 (+52/-0) debian/patches/series (+2/-0) main/utils.c (+14/-15) |
To merge this branch: | bzr merge lp:~davewalker/ubuntu/natty/asterisk/lp_705014 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Jamie Strandboge | Approve | ||
Review via email: mp+46977@code.launchpad.net |
Commit message
Description of the change
Fixed in Debian SVN.
To post a comment you must log in.
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
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === added file '.pc/.quilt_patches' |
2 | --- .pc/.quilt_patches 1970-01-01 00:00:00 +0000 |
3 | +++ .pc/.quilt_patches 2011-01-20 21:24:59 +0000 |
4 | @@ -0,0 +1,1 @@ |
5 | +debian/patches |
6 | |
7 | === added file '.pc/.quilt_series' |
8 | --- .pc/.quilt_series 1970-01-01 00:00:00 +0000 |
9 | +++ .pc/.quilt_series 2011-01-20 21:24:59 +0000 |
10 | @@ -0,0 +1,1 @@ |
11 | +series |
12 | |
13 | === added directory '.pc/AST-2011-001-1.6.2' |
14 | === added file '.pc/AST-2011-001-1.6.2/.timestamp' |
15 | === added directory '.pc/AST-2011-001-1.6.2/main' |
16 | === added file '.pc/AST-2011-001-1.6.2/main/utils.c' |
17 | --- .pc/AST-2011-001-1.6.2/main/utils.c 1970-01-01 00:00:00 +0000 |
18 | +++ .pc/AST-2011-001-1.6.2/main/utils.c 2011-01-20 21:24:59 +0000 |
19 | @@ -0,0 +1,1828 @@ |
20 | +/* |
21 | + * Asterisk -- An open source telephony toolkit. |
22 | + * |
23 | + * Copyright (C) 1999 - 2006, Digium, Inc. |
24 | + * |
25 | + * See http://www.asterisk.org for more information about |
26 | + * the Asterisk project. Please do not directly contact |
27 | + * any of the maintainers of this project for assistance; |
28 | + * the project provides a web site, mailing lists and IRC |
29 | + * channels for your use. |
30 | + * |
31 | + * This program is free software, distributed under the terms of |
32 | + * the GNU General Public License Version 2. See the LICENSE file |
33 | + * at the top of the source tree. |
34 | + */ |
35 | + |
36 | +/*! \file |
37 | + * |
38 | + * \brief Utility functions |
39 | + * |
40 | + * \note These are important for portability and security, |
41 | + * so please use them in favour of other routines. |
42 | + * Please consult the CODING GUIDELINES for more information. |
43 | + */ |
44 | + |
45 | +#include "asterisk.h" |
46 | + |
47 | +ASTERISK_FILE_VERSION(__FILE__, "$Revision: 237743 $") |
48 | + |
49 | +#include <ctype.h> |
50 | +#include <sys/stat.h> |
51 | + |
52 | +#ifdef HAVE_DEV_URANDOM |
53 | +#include <fcntl.h> |
54 | +#endif |
55 | + |
56 | +#include "asterisk/network.h" |
57 | + |
58 | +#define AST_API_MODULE /* ensure that inlinable API functions will be built in lock.h if required */ |
59 | +#include "asterisk/lock.h" |
60 | +#include "asterisk/io.h" |
61 | +#include "asterisk/md5.h" |
62 | +#include "asterisk/sha1.h" |
63 | +#include "asterisk/cli.h" |
64 | +#include "asterisk/linkedlists.h" |
65 | + |
66 | +#define AST_API_MODULE /* ensure that inlinable API functions will be built in this module if required */ |
67 | +#include "asterisk/strings.h" |
68 | + |
69 | +#define AST_API_MODULE /* ensure that inlinable API functions will be built in this module if required */ |
70 | +#include "asterisk/time.h" |
71 | + |
72 | +#define AST_API_MODULE /* ensure that inlinable API functions will be built in this module if required */ |
73 | +#include "asterisk/stringfields.h" |
74 | + |
75 | +#define AST_API_MODULE /* ensure that inlinable API functions will be built in this module if required */ |
76 | +#include "asterisk/utils.h" |
77 | + |
78 | +#define AST_API_MODULE |
79 | +#include "asterisk/threadstorage.h" |
80 | + |
81 | +#define AST_API_MODULE |
82 | +#include "asterisk/config.h" |
83 | + |
84 | +static char base64[64]; |
85 | +static char b2a[256]; |
86 | + |
87 | +AST_THREADSTORAGE(inet_ntoa_buf); |
88 | + |
89 | +#if !defined(HAVE_GETHOSTBYNAME_R_5) && !defined(HAVE_GETHOSTBYNAME_R_6) |
90 | + |
91 | +#define ERANGE 34 /*!< duh? ERANGE value copied from web... */ |
92 | +#undef gethostbyname |
93 | + |
94 | +AST_MUTEX_DEFINE_STATIC(__mutex); |
95 | + |
96 | +/*! \brief Reentrant replacement for gethostbyname for BSD-based systems. |
97 | +\note This |
98 | +routine is derived from code originally written and placed in the public |
99 | +domain by Enzo Michelangeli <em@em.no-ip.com> */ |
100 | + |
101 | +static int gethostbyname_r (const char *name, struct hostent *ret, char *buf, |
102 | + size_t buflen, struct hostent **result, |
103 | + int *h_errnop) |
104 | +{ |
105 | + int hsave; |
106 | + struct hostent *ph; |
107 | + ast_mutex_lock(&__mutex); /* begin critical area */ |
108 | + hsave = h_errno; |
109 | + |
110 | + ph = gethostbyname(name); |
111 | + *h_errnop = h_errno; /* copy h_errno to *h_herrnop */ |
112 | + if (ph == NULL) { |
113 | + *result = NULL; |
114 | + } else { |
115 | + char **p, **q; |
116 | + char *pbuf; |
117 | + int nbytes = 0; |
118 | + int naddr = 0, naliases = 0; |
119 | + /* determine if we have enough space in buf */ |
120 | + |
121 | + /* count how many addresses */ |
122 | + for (p = ph->h_addr_list; *p != 0; p++) { |
123 | + nbytes += ph->h_length; /* addresses */ |
124 | + nbytes += sizeof(*p); /* pointers */ |
125 | + naddr++; |
126 | + } |
127 | + nbytes += sizeof(*p); /* one more for the terminating NULL */ |
128 | + |
129 | + /* count how many aliases, and total length of strings */ |
130 | + for (p = ph->h_aliases; *p != 0; p++) { |
131 | + nbytes += (strlen(*p)+1); /* aliases */ |
132 | + nbytes += sizeof(*p); /* pointers */ |
133 | + naliases++; |
134 | + } |
135 | + nbytes += sizeof(*p); /* one more for the terminating NULL */ |
136 | + |
137 | + /* here nbytes is the number of bytes required in buffer */ |
138 | + /* as a terminator must be there, the minimum value is ph->h_length */ |
139 | + if (nbytes > buflen) { |
140 | + *result = NULL; |
141 | + ast_mutex_unlock(&__mutex); /* end critical area */ |
142 | + return ERANGE; /* not enough space in buf!! */ |
143 | + } |
144 | + |
145 | + /* There is enough space. Now we need to do a deep copy! */ |
146 | + /* Allocation in buffer: |
147 | + from [0] to [(naddr-1) * sizeof(*p)]: |
148 | + pointers to addresses |
149 | + at [naddr * sizeof(*p)]: |
150 | + NULL |
151 | + from [(naddr+1) * sizeof(*p)] to [(naddr+naliases) * sizeof(*p)] : |
152 | + pointers to aliases |
153 | + at [(naddr+naliases+1) * sizeof(*p)]: |
154 | + NULL |
155 | + then naddr addresses (fixed length), and naliases aliases (asciiz). |
156 | + */ |
157 | + |
158 | + *ret = *ph; /* copy whole structure (not its address!) */ |
159 | + |
160 | + /* copy addresses */ |
161 | + q = (char **)buf; /* pointer to pointers area (type: char **) */ |
162 | + ret->h_addr_list = q; /* update pointer to address list */ |
163 | + pbuf = buf + ((naddr + naliases + 2) * sizeof(*p)); /* skip that area */ |
164 | + for (p = ph->h_addr_list; *p != 0; p++) { |
165 | + memcpy(pbuf, *p, ph->h_length); /* copy address bytes */ |
166 | + *q++ = pbuf; /* the pointer is the one inside buf... */ |
167 | + pbuf += ph->h_length; /* advance pbuf */ |
168 | + } |
169 | + *q++ = NULL; /* address list terminator */ |
170 | + |
171 | + /* copy aliases */ |
172 | + ret->h_aliases = q; /* update pointer to aliases list */ |
173 | + for (p = ph->h_aliases; *p != 0; p++) { |
174 | + strcpy(pbuf, *p); /* copy alias strings */ |
175 | + *q++ = pbuf; /* the pointer is the one inside buf... */ |
176 | + pbuf += strlen(*p); /* advance pbuf */ |
177 | + *pbuf++ = 0; /* string terminator */ |
178 | + } |
179 | + *q++ = NULL; /* terminator */ |
180 | + |
181 | + strcpy(pbuf, ph->h_name); /* copy alias strings */ |
182 | + ret->h_name = pbuf; |
183 | + pbuf += strlen(ph->h_name); /* advance pbuf */ |
184 | + *pbuf++ = 0; /* string terminator */ |
185 | + |
186 | + *result = ret; /* and let *result point to structure */ |
187 | + |
188 | + } |
189 | + h_errno = hsave; /* restore h_errno */ |
190 | + ast_mutex_unlock(&__mutex); /* end critical area */ |
191 | + |
192 | + return (*result == NULL); /* return 0 on success, non-zero on error */ |
193 | +} |
194 | + |
195 | + |
196 | +#endif |
197 | + |
198 | +/*! \brief Re-entrant (thread safe) version of gethostbyname that replaces the |
199 | + standard gethostbyname (which is not thread safe) |
200 | +*/ |
201 | +struct hostent *ast_gethostbyname(const char *host, struct ast_hostent *hp) |
202 | +{ |
203 | + int res; |
204 | + int herrno; |
205 | + int dots = 0; |
206 | + const char *s; |
207 | + struct hostent *result = NULL; |
208 | + /* Although it is perfectly legitimate to lookup a pure integer, for |
209 | + the sake of the sanity of people who like to name their peers as |
210 | + integers, we break with tradition and refuse to look up a |
211 | + pure integer */ |
212 | + s = host; |
213 | + res = 0; |
214 | + while (s && *s) { |
215 | + if (*s == '.') |
216 | + dots++; |
217 | + else if (!isdigit(*s)) |
218 | + break; |
219 | + s++; |
220 | + } |
221 | + if (!s || !*s) { |
222 | + /* Forge a reply for IP's to avoid octal IP's being interpreted as octal */ |
223 | + if (dots != 3) |
224 | + return NULL; |
225 | + memset(hp, 0, sizeof(struct ast_hostent)); |
226 | + hp->hp.h_addrtype = AF_INET; |
227 | + hp->hp.h_addr_list = (void *) hp->buf; |
228 | + hp->hp.h_addr = hp->buf + sizeof(void *); |
229 | + if (inet_pton(AF_INET, host, hp->hp.h_addr) > 0) |
230 | + return &hp->hp; |
231 | + return NULL; |
232 | + |
233 | + } |
234 | +#ifdef HAVE_GETHOSTBYNAME_R_5 |
235 | + result = gethostbyname_r(host, &hp->hp, hp->buf, sizeof(hp->buf), &herrno); |
236 | + |
237 | + if (!result || !hp->hp.h_addr_list || !hp->hp.h_addr_list[0]) |
238 | + return NULL; |
239 | +#else |
240 | + res = gethostbyname_r(host, &hp->hp, hp->buf, sizeof(hp->buf), &result, &herrno); |
241 | + |
242 | + if (res || !result || !hp->hp.h_addr_list || !hp->hp.h_addr_list[0]) |
243 | + return NULL; |
244 | +#endif |
245 | + return &hp->hp; |
246 | +} |
247 | + |
248 | +/*! \brief Produce 32 char MD5 hash of value. */ |
249 | +void ast_md5_hash(char *output, char *input) |
250 | +{ |
251 | + struct MD5Context md5; |
252 | + unsigned char digest[16]; |
253 | + char *ptr; |
254 | + int x; |
255 | + |
256 | + MD5Init(&md5); |
257 | + MD5Update(&md5, (unsigned char *)input, strlen(input)); |
258 | + MD5Final(digest, &md5); |
259 | + ptr = output; |
260 | + for (x = 0; x < 16; x++) |
261 | + ptr += sprintf(ptr, "%2.2x", digest[x]); |
262 | +} |
263 | + |
264 | +/*! \brief Produce 40 char SHA1 hash of value. */ |
265 | +void ast_sha1_hash(char *output, char *input) |
266 | +{ |
267 | + struct SHA1Context sha; |
268 | + char *ptr; |
269 | + int x; |
270 | + uint8_t Message_Digest[20]; |
271 | + |
272 | + SHA1Reset(&sha); |
273 | + |
274 | + SHA1Input(&sha, (const unsigned char *) input, strlen(input)); |
275 | + |
276 | + SHA1Result(&sha, Message_Digest); |
277 | + ptr = output; |
278 | + for (x = 0; x < 20; x++) |
279 | + ptr += sprintf(ptr, "%2.2x", Message_Digest[x]); |
280 | +} |
281 | + |
282 | +/*! \brief decode BASE64 encoded text */ |
283 | +int ast_base64decode(unsigned char *dst, const char *src, int max) |
284 | +{ |
285 | + int cnt = 0; |
286 | + unsigned int byte = 0; |
287 | + unsigned int bits = 0; |
288 | + int incnt = 0; |
289 | + while(*src && *src != '=' && (cnt < max)) { |
290 | + /* Shift in 6 bits of input */ |
291 | + byte <<= 6; |
292 | + byte |= (b2a[(int)(*src)]) & 0x3f; |
293 | + bits += 6; |
294 | + src++; |
295 | + incnt++; |
296 | + /* If we have at least 8 bits left over, take that character |
297 | + off the top */ |
298 | + if (bits >= 8) { |
299 | + bits -= 8; |
300 | + *dst = (byte >> bits) & 0xff; |
301 | + dst++; |
302 | + cnt++; |
303 | + } |
304 | + } |
305 | + /* Dont worry about left over bits, they're extra anyway */ |
306 | + return cnt; |
307 | +} |
308 | + |
309 | +/*! \brief encode text to BASE64 coding */ |
310 | +int ast_base64encode_full(char *dst, const unsigned char *src, int srclen, int max, int linebreaks) |
311 | +{ |
312 | + int cnt = 0; |
313 | + int col = 0; |
314 | + unsigned int byte = 0; |
315 | + int bits = 0; |
316 | + int cntin = 0; |
317 | + /* Reserve space for null byte at end of string */ |
318 | + max--; |
319 | + while ((cntin < srclen) && (cnt < max)) { |
320 | + byte <<= 8; |
321 | + byte |= *(src++); |
322 | + bits += 8; |
323 | + cntin++; |
324 | + if ((bits == 24) && (cnt + 4 <= max)) { |
325 | + *dst++ = base64[(byte >> 18) & 0x3f]; |
326 | + *dst++ = base64[(byte >> 12) & 0x3f]; |
327 | + *dst++ = base64[(byte >> 6) & 0x3f]; |
328 | + *dst++ = base64[byte & 0x3f]; |
329 | + cnt += 4; |
330 | + col += 4; |
331 | + bits = 0; |
332 | + byte = 0; |
333 | + } |
334 | + if (linebreaks && (cnt < max) && (col == 64)) { |
335 | + *dst++ = '\n'; |
336 | + cnt++; |
337 | + col = 0; |
338 | + } |
339 | + } |
340 | + if (bits && (cnt + 4 <= max)) { |
341 | + /* Add one last character for the remaining bits, |
342 | + padding the rest with 0 */ |
343 | + byte <<= 24 - bits; |
344 | + *dst++ = base64[(byte >> 18) & 0x3f]; |
345 | + *dst++ = base64[(byte >> 12) & 0x3f]; |
346 | + if (bits == 16) |
347 | + *dst++ = base64[(byte >> 6) & 0x3f]; |
348 | + else |
349 | + *dst++ = '='; |
350 | + *dst++ = '='; |
351 | + cnt += 4; |
352 | + } |
353 | + if (linebreaks && (cnt < max)) { |
354 | + *dst++ = '\n'; |
355 | + cnt++; |
356 | + } |
357 | + *dst = '\0'; |
358 | + return cnt; |
359 | +} |
360 | + |
361 | +int ast_base64encode(char *dst, const unsigned char *src, int srclen, int max) |
362 | +{ |
363 | + return ast_base64encode_full(dst, src, srclen, max, 0); |
364 | +} |
365 | + |
366 | +static void base64_init(void) |
367 | +{ |
368 | + int x; |
369 | + memset(b2a, -1, sizeof(b2a)); |
370 | + /* Initialize base-64 Conversion table */ |
371 | + for (x = 0; x < 26; x++) { |
372 | + /* A-Z */ |
373 | + base64[x] = 'A' + x; |
374 | + b2a['A' + x] = x; |
375 | + /* a-z */ |
376 | + base64[x + 26] = 'a' + x; |
377 | + b2a['a' + x] = x + 26; |
378 | + /* 0-9 */ |
379 | + if (x < 10) { |
380 | + base64[x + 52] = '0' + x; |
381 | + b2a['0' + x] = x + 52; |
382 | + } |
383 | + } |
384 | + base64[62] = '+'; |
385 | + base64[63] = '/'; |
386 | + b2a[(int)'+'] = 62; |
387 | + b2a[(int)'/'] = 63; |
388 | +} |
389 | + |
390 | +/*! \brief ast_uri_encode: Turn text string to URI-encoded %XX version |
391 | +\note At this point, we're converting from ISO-8859-x (8-bit), not UTF8 |
392 | + as in the SIP protocol spec |
393 | + If doreserved == 1 we will convert reserved characters also. |
394 | + RFC 2396, section 2.4 |
395 | + outbuf needs to have more memory allocated than the instring |
396 | + to have room for the expansion. Every char that is converted |
397 | + is replaced by three ASCII characters. |
398 | + |
399 | + Note: The doreserved option is needed for replaces header in |
400 | + SIP transfers. |
401 | +*/ |
402 | +char *ast_uri_encode(const char *string, char *outbuf, int buflen, int doreserved) |
403 | +{ |
404 | + char *reserved = ";/?:@&=+$,# "; /* Reserved chars */ |
405 | + |
406 | + const char *ptr = string; /* Start with the string */ |
407 | + char *out = NULL; |
408 | + char *buf = NULL; |
409 | + |
410 | + ast_copy_string(outbuf, string, buflen); |
411 | + |
412 | + /* If there's no characters to convert, just go through and don't do anything */ |
413 | + while (*ptr) { |
414 | + if ((*ptr < 32) || (doreserved && strchr(reserved, *ptr))) { |
415 | + /* Oops, we need to start working here */ |
416 | + if (!buf) { |
417 | + buf = outbuf; |
418 | + out = buf + (ptr - string) ; /* Set output ptr */ |
419 | + } |
420 | + out += sprintf(out, "%%%02x", (unsigned char) *ptr); |
421 | + } else if (buf) { |
422 | + *out = *ptr; /* Continue copying the string */ |
423 | + out++; |
424 | + } |
425 | + ptr++; |
426 | + } |
427 | + if (buf) |
428 | + *out = '\0'; |
429 | + return outbuf; |
430 | +} |
431 | + |
432 | +/*! \brief ast_uri_decode: Decode SIP URI, URN, URL (overwrite the string) */ |
433 | +void ast_uri_decode(char *s) |
434 | +{ |
435 | + char *o; |
436 | + unsigned int tmp; |
437 | + |
438 | + for (o = s; *s; s++, o++) { |
439 | + if (*s == '%' && strlen(s) > 2 && sscanf(s + 1, "%2x", &tmp) == 1) { |
440 | + /* have '%', two chars and correct parsing */ |
441 | + *o = tmp; |
442 | + s += 2; /* Will be incremented once more when we break out */ |
443 | + } else /* all other cases, just copy */ |
444 | + *o = *s; |
445 | + } |
446 | + *o = '\0'; |
447 | +} |
448 | + |
449 | +/*! \brief ast_inet_ntoa: Recursive thread safe replacement of inet_ntoa */ |
450 | +const char *ast_inet_ntoa(struct in_addr ia) |
451 | +{ |
452 | + char *buf; |
453 | + |
454 | + if (!(buf = ast_threadstorage_get(&inet_ntoa_buf, INET_ADDRSTRLEN))) |
455 | + return ""; |
456 | + |
457 | + return inet_ntop(AF_INET, &ia, buf, INET_ADDRSTRLEN); |
458 | +} |
459 | + |
460 | +#ifdef HAVE_DEV_URANDOM |
461 | +static int dev_urandom_fd; |
462 | +#endif |
463 | + |
464 | +#ifndef __linux__ |
465 | +#undef pthread_create /* For ast_pthread_create function only */ |
466 | +#endif /* !__linux__ */ |
467 | + |
468 | +#if !defined(LOW_MEMORY) |
469 | + |
470 | +#ifdef DEBUG_THREADS |
471 | + |
472 | +/*! \brief A reasonable maximum number of locks a thread would be holding ... */ |
473 | +#define AST_MAX_LOCKS 64 |
474 | + |
475 | +/* Allow direct use of pthread_mutex_t and friends */ |
476 | +#undef pthread_mutex_t |
477 | +#undef pthread_mutex_lock |
478 | +#undef pthread_mutex_unlock |
479 | +#undef pthread_mutex_init |
480 | +#undef pthread_mutex_destroy |
481 | + |
482 | +/*! |
483 | + * \brief Keep track of which locks a thread holds |
484 | + * |
485 | + * There is an instance of this struct for every active thread |
486 | + */ |
487 | +struct thr_lock_info { |
488 | + /*! The thread's ID */ |
489 | + pthread_t thread_id; |
490 | + /*! The thread name which includes where the thread was started */ |
491 | + const char *thread_name; |
492 | + /*! This is the actual container of info for what locks this thread holds */ |
493 | + struct { |
494 | + const char *file; |
495 | + int line_num; |
496 | + const char *func; |
497 | + const char *lock_name; |
498 | + void *lock_addr; |
499 | + int times_locked; |
500 | + enum ast_lock_type type; |
501 | + /*! This thread is waiting on this lock */ |
502 | + int pending:2; |
503 | +#ifdef HAVE_BKTR |
504 | + struct ast_bt *backtrace; |
505 | +#endif |
506 | + } locks[AST_MAX_LOCKS]; |
507 | + /*! This is the number of locks currently held by this thread. |
508 | + * The index (num_locks - 1) has the info on the last one in the |
509 | + * locks member */ |
510 | + unsigned int num_locks; |
511 | + /*! Protects the contents of the locks member |
512 | + * Intentionally not ast_mutex_t */ |
513 | + pthread_mutex_t lock; |
514 | + AST_LIST_ENTRY(thr_lock_info) entry; |
515 | +}; |
516 | + |
517 | +/*! |
518 | + * \brief Locked when accessing the lock_infos list |
519 | + */ |
520 | +AST_MUTEX_DEFINE_STATIC(lock_infos_lock); |
521 | +/*! |
522 | + * \brief A list of each thread's lock info |
523 | + */ |
524 | +static AST_LIST_HEAD_NOLOCK_STATIC(lock_infos, thr_lock_info); |
525 | + |
526 | +/*! |
527 | + * \brief Destroy a thread's lock info |
528 | + * |
529 | + * This gets called automatically when the thread stops |
530 | + */ |
531 | +static void lock_info_destroy(void *data) |
532 | +{ |
533 | + struct thr_lock_info *lock_info = data; |
534 | + int i; |
535 | + |
536 | + pthread_mutex_lock(&lock_infos_lock.mutex); |
537 | + AST_LIST_REMOVE(&lock_infos, lock_info, entry); |
538 | + pthread_mutex_unlock(&lock_infos_lock.mutex); |
539 | + |
540 | + |
541 | + for (i = 0; i < lock_info->num_locks; i++) { |
542 | + if (lock_info->locks[i].pending == -1) { |
543 | + /* This just means that the last lock this thread went for was by |
544 | + * using trylock, and it failed. This is fine. */ |
545 | + break; |
546 | + } |
547 | + |
548 | + ast_log(LOG_ERROR, |
549 | + "Thread '%s' still has a lock! - '%s' (%p) from '%s' in %s:%d!\n", |
550 | + lock_info->thread_name, |
551 | + lock_info->locks[i].lock_name, |
552 | + lock_info->locks[i].lock_addr, |
553 | + lock_info->locks[i].func, |
554 | + lock_info->locks[i].file, |
555 | + lock_info->locks[i].line_num |
556 | + ); |
557 | + } |
558 | + |
559 | + pthread_mutex_destroy(&lock_info->lock); |
560 | + if (lock_info->thread_name) |
561 | + free((void *) lock_info->thread_name); |
562 | + free(lock_info); |
563 | +} |
564 | + |
565 | +/*! |
566 | + * \brief The thread storage key for per-thread lock info |
567 | + */ |
568 | +AST_THREADSTORAGE_CUSTOM(thread_lock_info, NULL, lock_info_destroy); |
569 | +#ifdef HAVE_BKTR |
570 | +void ast_store_lock_info(enum ast_lock_type type, const char *filename, |
571 | + int line_num, const char *func, const char *lock_name, void *lock_addr, struct ast_bt *bt) |
572 | +#else |
573 | +void ast_store_lock_info(enum ast_lock_type type, const char *filename, |
574 | + int line_num, const char *func, const char *lock_name, void *lock_addr) |
575 | +#endif |
576 | +{ |
577 | + struct thr_lock_info *lock_info; |
578 | + int i; |
579 | + |
580 | + if (!(lock_info = ast_threadstorage_get(&thread_lock_info, sizeof(*lock_info)))) |
581 | + return; |
582 | + |
583 | + pthread_mutex_lock(&lock_info->lock); |
584 | + |
585 | + for (i = 0; i < lock_info->num_locks; i++) { |
586 | + if (lock_info->locks[i].lock_addr == lock_addr) { |
587 | + lock_info->locks[i].times_locked++; |
588 | +#ifdef HAVE_BKTR |
589 | + lock_info->locks[i].backtrace = bt; |
590 | +#endif |
591 | + pthread_mutex_unlock(&lock_info->lock); |
592 | + return; |
593 | + } |
594 | + } |
595 | + |
596 | + if (lock_info->num_locks == AST_MAX_LOCKS) { |
597 | + /* Can't use ast_log here, because it will cause infinite recursion */ |
598 | + fprintf(stderr, "XXX ERROR XXX A thread holds more locks than '%d'." |
599 | + " Increase AST_MAX_LOCKS!\n", AST_MAX_LOCKS); |
600 | + pthread_mutex_unlock(&lock_info->lock); |
601 | + return; |
602 | + } |
603 | + |
604 | + if (i && lock_info->locks[i - 1].pending == -1) { |
605 | + /* The last lock on the list was one that this thread tried to lock but |
606 | + * failed at doing so. It has now moved on to something else, so remove |
607 | + * the old lock from the list. */ |
608 | + i--; |
609 | + lock_info->num_locks--; |
610 | + memset(&lock_info->locks[i], 0, sizeof(lock_info->locks[0])); |
611 | + } |
612 | + |
613 | + lock_info->locks[i].file = filename; |
614 | + lock_info->locks[i].line_num = line_num; |
615 | + lock_info->locks[i].func = func; |
616 | + lock_info->locks[i].lock_name = lock_name; |
617 | + lock_info->locks[i].lock_addr = lock_addr; |
618 | + lock_info->locks[i].times_locked = 1; |
619 | + lock_info->locks[i].type = type; |
620 | + lock_info->locks[i].pending = 1; |
621 | +#ifdef HAVE_BKTR |
622 | + lock_info->locks[i].backtrace = bt; |
623 | +#endif |
624 | + lock_info->num_locks++; |
625 | + |
626 | + pthread_mutex_unlock(&lock_info->lock); |
627 | +} |
628 | + |
629 | +void ast_mark_lock_acquired(void *lock_addr) |
630 | +{ |
631 | + struct thr_lock_info *lock_info; |
632 | + |
633 | + if (!(lock_info = ast_threadstorage_get(&thread_lock_info, sizeof(*lock_info)))) |
634 | + return; |
635 | + |
636 | + pthread_mutex_lock(&lock_info->lock); |
637 | + if (lock_info->locks[lock_info->num_locks - 1].lock_addr == lock_addr) { |
638 | + lock_info->locks[lock_info->num_locks - 1].pending = 0; |
639 | + } |
640 | + pthread_mutex_unlock(&lock_info->lock); |
641 | +} |
642 | + |
643 | +void ast_mark_lock_failed(void *lock_addr) |
644 | +{ |
645 | + struct thr_lock_info *lock_info; |
646 | + |
647 | + if (!(lock_info = ast_threadstorage_get(&thread_lock_info, sizeof(*lock_info)))) |
648 | + return; |
649 | + |
650 | + pthread_mutex_lock(&lock_info->lock); |
651 | + if (lock_info->locks[lock_info->num_locks - 1].lock_addr == lock_addr) { |
652 | + lock_info->locks[lock_info->num_locks - 1].pending = -1; |
653 | + lock_info->locks[lock_info->num_locks - 1].times_locked--; |
654 | + } |
655 | + pthread_mutex_unlock(&lock_info->lock); |
656 | +} |
657 | + |
658 | +int ast_find_lock_info(void *lock_addr, char *filename, size_t filename_size, int *lineno, char *func, size_t func_size, char *mutex_name, size_t mutex_name_size) |
659 | +{ |
660 | + struct thr_lock_info *lock_info; |
661 | + int i = 0; |
662 | + |
663 | + if (!(lock_info = ast_threadstorage_get(&thread_lock_info, sizeof(*lock_info)))) |
664 | + return -1; |
665 | + |
666 | + pthread_mutex_lock(&lock_info->lock); |
667 | + |
668 | + for (i = lock_info->num_locks - 1; i >= 0; i--) { |
669 | + if (lock_info->locks[i].lock_addr == lock_addr) |
670 | + break; |
671 | + } |
672 | + |
673 | + if (i == -1) { |
674 | + /* Lock not found :( */ |
675 | + pthread_mutex_unlock(&lock_info->lock); |
676 | + return -1; |
677 | + } |
678 | + |
679 | + ast_copy_string(filename, lock_info->locks[i].file, filename_size); |
680 | + *lineno = lock_info->locks[i].line_num; |
681 | + ast_copy_string(func, lock_info->locks[i].func, func_size); |
682 | + ast_copy_string(mutex_name, lock_info->locks[i].lock_name, mutex_name_size); |
683 | + |
684 | + pthread_mutex_unlock(&lock_info->lock); |
685 | + |
686 | + return 0; |
687 | +} |
688 | + |
689 | +#ifdef HAVE_BKTR |
690 | +void ast_remove_lock_info(void *lock_addr, struct ast_bt *bt) |
691 | +#else |
692 | +void ast_remove_lock_info(void *lock_addr) |
693 | +#endif |
694 | +{ |
695 | + struct thr_lock_info *lock_info; |
696 | + int i = 0; |
697 | + |
698 | + if (!(lock_info = ast_threadstorage_get(&thread_lock_info, sizeof(*lock_info)))) |
699 | + return; |
700 | + |
701 | + pthread_mutex_lock(&lock_info->lock); |
702 | + |
703 | + for (i = lock_info->num_locks - 1; i >= 0; i--) { |
704 | + if (lock_info->locks[i].lock_addr == lock_addr) |
705 | + break; |
706 | + } |
707 | + |
708 | + if (i == -1) { |
709 | + /* Lock not found :( */ |
710 | + pthread_mutex_unlock(&lock_info->lock); |
711 | + return; |
712 | + } |
713 | + |
714 | + if (lock_info->locks[i].times_locked > 1) { |
715 | + lock_info->locks[i].times_locked--; |
716 | +#ifdef HAVE_BKTR |
717 | + lock_info->locks[i].backtrace = bt; |
718 | +#endif |
719 | + pthread_mutex_unlock(&lock_info->lock); |
720 | + return; |
721 | + } |
722 | + |
723 | + if (i < lock_info->num_locks - 1) { |
724 | + /* Not the last one ... *should* be rare! */ |
725 | + memmove(&lock_info->locks[i], &lock_info->locks[i + 1], |
726 | + (lock_info->num_locks - (i + 1)) * sizeof(lock_info->locks[0])); |
727 | + } |
728 | + |
729 | + lock_info->num_locks--; |
730 | + |
731 | + pthread_mutex_unlock(&lock_info->lock); |
732 | +} |
733 | + |
734 | +static const char *locktype2str(enum ast_lock_type type) |
735 | +{ |
736 | + switch (type) { |
737 | + case AST_MUTEX: |
738 | + return "MUTEX"; |
739 | + case AST_RDLOCK: |
740 | + return "RDLOCK"; |
741 | + case AST_WRLOCK: |
742 | + return "WRLOCK"; |
743 | + } |
744 | + |
745 | + return "UNKNOWN"; |
746 | +} |
747 | + |
748 | +#ifdef HAVE_BKTR |
749 | +static void append_backtrace_information(struct ast_str **str, struct ast_bt *bt) |
750 | +{ |
751 | + char **symbols; |
752 | + |
753 | + if (!bt) { |
754 | + ast_str_append(str, 0, "\tNo backtrace to print\n"); |
755 | + return; |
756 | + } |
757 | + |
758 | + if ((symbols = backtrace_symbols(bt->addresses, bt->num_frames))) { |
759 | + int frame_iterator; |
760 | + |
761 | + for (frame_iterator = 0; frame_iterator < bt->num_frames; ++frame_iterator) { |
762 | + ast_str_append(str, 0, "\t%s\n", symbols[frame_iterator]); |
763 | + } |
764 | + |
765 | + free(symbols); |
766 | + } else { |
767 | + ast_str_append(str, 0, "\tCouldn't retrieve backtrace symbols\n"); |
768 | + } |
769 | +} |
770 | +#endif |
771 | + |
772 | +static void append_lock_information(struct ast_str **str, struct thr_lock_info *lock_info, int i) |
773 | +{ |
774 | + int j; |
775 | + ast_mutex_t *lock; |
776 | + struct ast_lock_track *lt; |
777 | + |
778 | + ast_str_append(str, 0, "=== ---> %sLock #%d (%s): %s %d %s %s %p (%d)\n", |
779 | + lock_info->locks[i].pending > 0 ? "Waiting for " : |
780 | + lock_info->locks[i].pending < 0 ? "Tried and failed to get " : "", i, |
781 | + lock_info->locks[i].file, |
782 | + locktype2str(lock_info->locks[i].type), |
783 | + lock_info->locks[i].line_num, |
784 | + lock_info->locks[i].func, lock_info->locks[i].lock_name, |
785 | + lock_info->locks[i].lock_addr, |
786 | + lock_info->locks[i].times_locked); |
787 | +#ifdef HAVE_BKTR |
788 | + append_backtrace_information(str, lock_info->locks[i].backtrace); |
789 | +#endif |
790 | + |
791 | + if (!lock_info->locks[i].pending || lock_info->locks[i].pending == -1) |
792 | + return; |
793 | + |
794 | + /* We only have further details for mutexes right now */ |
795 | + if (lock_info->locks[i].type != AST_MUTEX) |
796 | + return; |
797 | + |
798 | + lock = lock_info->locks[i].lock_addr; |
799 | + lt = &lock->track; |
800 | + ast_reentrancy_lock(lt); |
801 | + for (j = 0; *str && j < lt->reentrancy; j++) { |
802 | + ast_str_append(str, 0, "=== --- ---> Locked Here: %s line %d (%s)\n", |
803 | + lt->file[j], lt->lineno[j], lt->func[j]); |
804 | + } |
805 | + ast_reentrancy_unlock(lt); |
806 | +} |
807 | + |
808 | + |
809 | +/*! This function can help you find highly temporal locks; locks that happen for a |
810 | + short time, but at unexpected times, usually at times that create a deadlock, |
811 | + Why is this thing locked right then? Who is locking it? Who am I fighting |
812 | + with for this lock? |
813 | + |
814 | + To answer such questions, just call this routine before you would normally try |
815 | + to aquire a lock. It doesn't do anything if the lock is not acquired. If the |
816 | + lock is taken, it will publish a line or two to the console via ast_log(). |
817 | + |
818 | + Sometimes, the lock message is pretty uninformative. For instance, you might |
819 | + find that the lock is being aquired deep within the astobj2 code; this tells |
820 | + you little about higher level routines that call the astobj2 routines. |
821 | + But, using gdb, you can set a break at the ast_log below, and for that |
822 | + breakpoint, you can set the commands: |
823 | + where |
824 | + cont |
825 | + which will give a stack trace and continue. -- that aught to do the job! |
826 | + |
827 | +*/ |
828 | +void log_show_lock(void *this_lock_addr) |
829 | +{ |
830 | + struct thr_lock_info *lock_info; |
831 | + struct ast_str *str; |
832 | + |
833 | + if (!(str = ast_str_create(4096))) { |
834 | + ast_log(LOG_NOTICE,"Could not create str\n"); |
835 | + return; |
836 | + } |
837 | + |
838 | + |
839 | + pthread_mutex_lock(&lock_infos_lock.mutex); |
840 | + AST_LIST_TRAVERSE(&lock_infos, lock_info, entry) { |
841 | + int i; |
842 | + pthread_mutex_lock(&lock_info->lock); |
843 | + for (i = 0; str && i < lock_info->num_locks; i++) { |
844 | + /* ONLY show info about this particular lock, if |
845 | + it's acquired... */ |
846 | + if (lock_info->locks[i].lock_addr == this_lock_addr) { |
847 | + append_lock_information(&str, lock_info, i); |
848 | + ast_log(LOG_NOTICE, "%s", ast_str_buffer(str)); |
849 | + break; |
850 | + } |
851 | + } |
852 | + pthread_mutex_unlock(&lock_info->lock); |
853 | + } |
854 | + pthread_mutex_unlock(&lock_infos_lock.mutex); |
855 | + ast_free(str); |
856 | +} |
857 | + |
858 | + |
859 | +static char *handle_show_locks(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
860 | +{ |
861 | + struct thr_lock_info *lock_info; |
862 | + struct ast_str *str; |
863 | + |
864 | + if (!(str = ast_str_create(4096))) |
865 | + return CLI_FAILURE; |
866 | + |
867 | + switch (cmd) { |
868 | + case CLI_INIT: |
869 | + e->command = "core show locks"; |
870 | + e->usage = |
871 | + "Usage: core show locks\n" |
872 | + " This command is for lock debugging. It prints out which locks\n" |
873 | + "are owned by each active thread.\n"; |
874 | + return NULL; |
875 | + |
876 | + case CLI_GENERATE: |
877 | + return NULL; |
878 | + } |
879 | + |
880 | + ast_str_append(&str, 0, "\n" |
881 | + "=======================================================================\n" |
882 | + "=== Currently Held Locks ==============================================\n" |
883 | + "=======================================================================\n" |
884 | + "===\n" |
885 | + "=== <pending> <lock#> (<file>): <lock type> <line num> <function> <lock name> <lock addr> (times locked)\n" |
886 | + "===\n"); |
887 | + |
888 | + if (!str) |
889 | + return CLI_FAILURE; |
890 | + |
891 | + pthread_mutex_lock(&lock_infos_lock.mutex); |
892 | + AST_LIST_TRAVERSE(&lock_infos, lock_info, entry) { |
893 | + int i; |
894 | + if (lock_info->num_locks) { |
895 | + ast_str_append(&str, 0, "=== Thread ID: %ld (%s)\n", (long) lock_info->thread_id, |
896 | + lock_info->thread_name); |
897 | + pthread_mutex_lock(&lock_info->lock); |
898 | + for (i = 0; str && i < lock_info->num_locks; i++) { |
899 | + append_lock_information(&str, lock_info, i); |
900 | + } |
901 | + pthread_mutex_unlock(&lock_info->lock); |
902 | + if (!str) |
903 | + break; |
904 | + ast_str_append(&str, 0, "=== -------------------------------------------------------------------\n" |
905 | + "===\n"); |
906 | + if (!str) |
907 | + break; |
908 | + } |
909 | + } |
910 | + pthread_mutex_unlock(&lock_infos_lock.mutex); |
911 | + |
912 | + if (!str) |
913 | + return CLI_FAILURE; |
914 | + |
915 | + ast_str_append(&str, 0, "=======================================================================\n" |
916 | + "\n"); |
917 | + |
918 | + if (!str) |
919 | + return CLI_FAILURE; |
920 | + |
921 | + ast_cli(a->fd, "%s", ast_str_buffer(str)); |
922 | + |
923 | + ast_free(str); |
924 | + |
925 | + return CLI_SUCCESS; |
926 | +} |
927 | + |
928 | +static struct ast_cli_entry utils_cli[] = { |
929 | + AST_CLI_DEFINE(handle_show_locks, "Show which locks are held by which thread"), |
930 | +}; |
931 | + |
932 | +#endif /* DEBUG_THREADS */ |
933 | + |
934 | +/* |
935 | + * support for 'show threads'. The start routine is wrapped by |
936 | + * dummy_start(), so that ast_register_thread() and |
937 | + * ast_unregister_thread() know the thread identifier. |
938 | + */ |
939 | +struct thr_arg { |
940 | + void *(*start_routine)(void *); |
941 | + void *data; |
942 | + char *name; |
943 | +}; |
944 | + |
945 | +/* |
946 | + * on OS/X, pthread_cleanup_push() and pthread_cleanup_pop() |
947 | + * are odd macros which start and end a block, so they _must_ be |
948 | + * used in pairs (the latter with a '1' argument to call the |
949 | + * handler on exit. |
950 | + * On BSD we don't need this, but we keep it for compatibility. |
951 | + */ |
952 | +static void *dummy_start(void *data) |
953 | +{ |
954 | + void *ret; |
955 | + struct thr_arg a = *((struct thr_arg *) data); /* make a local copy */ |
956 | +#ifdef DEBUG_THREADS |
957 | + struct thr_lock_info *lock_info; |
958 | + pthread_mutexattr_t mutex_attr; |
959 | +#endif |
960 | + |
961 | + /* note that even though data->name is a pointer to allocated memory, |
962 | + we are not freeing it here because ast_register_thread is going to |
963 | + keep a copy of the pointer and then ast_unregister_thread will |
964 | + free the memory |
965 | + */ |
966 | + ast_free(data); |
967 | + ast_register_thread(a.name); |
968 | + pthread_cleanup_push(ast_unregister_thread, (void *) pthread_self()); |
969 | + |
970 | +#ifdef DEBUG_THREADS |
971 | + if (!(lock_info = ast_threadstorage_get(&thread_lock_info, sizeof(*lock_info)))) |
972 | + return NULL; |
973 | + |
974 | + lock_info->thread_id = pthread_self(); |
975 | + lock_info->thread_name = strdup(a.name); |
976 | + |
977 | + pthread_mutexattr_init(&mutex_attr); |
978 | + pthread_mutexattr_settype(&mutex_attr, AST_MUTEX_KIND); |
979 | + pthread_mutex_init(&lock_info->lock, &mutex_attr); |
980 | + pthread_mutexattr_destroy(&mutex_attr); |
981 | + |
982 | + pthread_mutex_lock(&lock_infos_lock.mutex); /* Intentionally not the wrapper */ |
983 | + AST_LIST_INSERT_TAIL(&lock_infos, lock_info, entry); |
984 | + pthread_mutex_unlock(&lock_infos_lock.mutex); /* Intentionally not the wrapper */ |
985 | +#endif /* DEBUG_THREADS */ |
986 | + |
987 | + ret = a.start_routine(a.data); |
988 | + |
989 | + pthread_cleanup_pop(1); |
990 | + |
991 | + return ret; |
992 | +} |
993 | + |
994 | +#endif /* !LOW_MEMORY */ |
995 | + |
996 | +int ast_pthread_create_stack(pthread_t *thread, pthread_attr_t *attr, void *(*start_routine)(void *), |
997 | + void *data, size_t stacksize, const char *file, const char *caller, |
998 | + int line, const char *start_fn) |
999 | +{ |
1000 | +#if !defined(LOW_MEMORY) |
1001 | + struct thr_arg *a; |
1002 | +#endif |
1003 | + |
1004 | + if (!attr) { |
1005 | + attr = alloca(sizeof(*attr)); |
1006 | + pthread_attr_init(attr); |
1007 | + } |
1008 | + |
1009 | +#ifdef __linux__ |
1010 | + /* On Linux, pthread_attr_init() defaults to PTHREAD_EXPLICIT_SCHED, |
1011 | + which is kind of useless. Change this here to |
1012 | + PTHREAD_INHERIT_SCHED; that way the -p option to set realtime |
1013 | + priority will propagate down to new threads by default. |
1014 | + This does mean that callers cannot set a different priority using |
1015 | + PTHREAD_EXPLICIT_SCHED in the attr argument; instead they must set |
1016 | + the priority afterwards with pthread_setschedparam(). */ |
1017 | + if ((errno = pthread_attr_setinheritsched(attr, PTHREAD_INHERIT_SCHED))) |
1018 | + ast_log(LOG_WARNING, "pthread_attr_setinheritsched: %s\n", strerror(errno)); |
1019 | +#endif |
1020 | + |
1021 | + if (!stacksize) |
1022 | + stacksize = AST_STACKSIZE; |
1023 | + |
1024 | + if ((errno = pthread_attr_setstacksize(attr, stacksize ? stacksize : AST_STACKSIZE))) |
1025 | + ast_log(LOG_WARNING, "pthread_attr_setstacksize: %s\n", strerror(errno)); |
1026 | + |
1027 | +#if !defined(LOW_MEMORY) |
1028 | + if ((a = ast_malloc(sizeof(*a)))) { |
1029 | + a->start_routine = start_routine; |
1030 | + a->data = data; |
1031 | + start_routine = dummy_start; |
1032 | + if (asprintf(&a->name, "%-20s started at [%5d] %s %s()", |
1033 | + start_fn, line, file, caller) < 0) { |
1034 | + ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno)); |
1035 | + a->name = NULL; |
1036 | + } |
1037 | + data = a; |
1038 | + } |
1039 | +#endif /* !LOW_MEMORY */ |
1040 | + |
1041 | + return pthread_create(thread, attr, start_routine, data); /* We're in ast_pthread_create, so it's okay */ |
1042 | +} |
1043 | + |
1044 | + |
1045 | +int ast_pthread_create_detached_stack(pthread_t *thread, pthread_attr_t *attr, void *(*start_routine)(void *), |
1046 | + void *data, size_t stacksize, const char *file, const char *caller, |
1047 | + int line, const char *start_fn) |
1048 | +{ |
1049 | + unsigned char attr_destroy = 0; |
1050 | + int res; |
1051 | + |
1052 | + if (!attr) { |
1053 | + attr = alloca(sizeof(*attr)); |
1054 | + pthread_attr_init(attr); |
1055 | + attr_destroy = 1; |
1056 | + } |
1057 | + |
1058 | + if ((errno = pthread_attr_setdetachstate(attr, PTHREAD_CREATE_DETACHED))) |
1059 | + ast_log(LOG_WARNING, "pthread_attr_setdetachstate: %s\n", strerror(errno)); |
1060 | + |
1061 | + res = ast_pthread_create_stack(thread, attr, start_routine, data, |
1062 | + stacksize, file, caller, line, start_fn); |
1063 | + |
1064 | + if (attr_destroy) |
1065 | + pthread_attr_destroy(attr); |
1066 | + |
1067 | + return res; |
1068 | +} |
1069 | + |
1070 | +int ast_wait_for_input(int fd, int ms) |
1071 | +{ |
1072 | + struct pollfd pfd[1]; |
1073 | + memset(pfd, 0, sizeof(pfd)); |
1074 | + pfd[0].fd = fd; |
1075 | + pfd[0].events = POLLIN|POLLPRI; |
1076 | + return ast_poll(pfd, 1, ms); |
1077 | +} |
1078 | + |
1079 | +static int ast_wait_for_output(int fd, int timeoutms) |
1080 | +{ |
1081 | + struct pollfd pfd = { |
1082 | + .fd = fd, |
1083 | + .events = POLLOUT, |
1084 | + }; |
1085 | + int res; |
1086 | + struct timeval start = ast_tvnow(); |
1087 | + int elapsed = 0; |
1088 | + |
1089 | + /* poll() until the fd is writable without blocking */ |
1090 | + while ((res = ast_poll(&pfd, 1, timeoutms - elapsed)) <= 0) { |
1091 | + if (res == 0) { |
1092 | + /* timed out. */ |
1093 | +#ifndef STANDALONE |
1094 | + ast_debug(1, "Timed out trying to write\n"); |
1095 | +#endif |
1096 | + return -1; |
1097 | + } else if (res == -1) { |
1098 | + /* poll() returned an error, check to see if it was fatal */ |
1099 | + |
1100 | + if (errno == EINTR || errno == EAGAIN) { |
1101 | + elapsed = ast_tvdiff_ms(ast_tvnow(), start); |
1102 | + if (elapsed >= timeoutms) { |
1103 | + return -1; |
1104 | + } |
1105 | + /* This was an acceptable error, go back into poll() */ |
1106 | + continue; |
1107 | + } |
1108 | + |
1109 | + /* Fatal error, bail. */ |
1110 | + ast_log(LOG_ERROR, "poll returned error: %s\n", strerror(errno)); |
1111 | + |
1112 | + return -1; |
1113 | + } |
1114 | + elapsed = ast_tvdiff_ms(ast_tvnow(), start); |
1115 | + if (elapsed >= timeoutms) { |
1116 | + return -1; |
1117 | + } |
1118 | + } |
1119 | + |
1120 | + return 0; |
1121 | +} |
1122 | + |
1123 | +/*! |
1124 | + * Try to write string, but wait no more than ms milliseconds before timing out. |
1125 | + * |
1126 | + * \note The code assumes that the file descriptor has NONBLOCK set, |
1127 | + * so there is only one system call made to do a write, unless we actually |
1128 | + * have a need to wait. This way, we get better performance. |
1129 | + * If the descriptor is blocking, all assumptions on the guaranteed |
1130 | + * detail do not apply anymore. |
1131 | + */ |
1132 | +int ast_carefulwrite(int fd, char *s, int len, int timeoutms) |
1133 | +{ |
1134 | + struct timeval start = ast_tvnow(); |
1135 | + int res = 0; |
1136 | + int elapsed = 0; |
1137 | + |
1138 | + while (len) { |
1139 | + if (ast_wait_for_output(fd, timeoutms - elapsed)) { |
1140 | + return -1; |
1141 | + } |
1142 | + |
1143 | + res = write(fd, s, len); |
1144 | + |
1145 | + if (res < 0 && errno != EAGAIN && errno != EINTR) { |
1146 | + /* fatal error from write() */ |
1147 | + ast_log(LOG_ERROR, "write() returned error: %s\n", strerror(errno)); |
1148 | + return -1; |
1149 | + } |
1150 | + |
1151 | + if (res < 0) { |
1152 | + /* It was an acceptable error */ |
1153 | + res = 0; |
1154 | + } |
1155 | + |
1156 | + /* Update how much data we have left to write */ |
1157 | + len -= res; |
1158 | + s += res; |
1159 | + res = 0; |
1160 | + |
1161 | + elapsed = ast_tvdiff_ms(ast_tvnow(), start); |
1162 | + if (elapsed >= timeoutms) { |
1163 | + /* We've taken too long to write |
1164 | + * This is only an error condition if we haven't finished writing. */ |
1165 | + res = len ? -1 : 0; |
1166 | + break; |
1167 | + } |
1168 | + } |
1169 | + |
1170 | + return res; |
1171 | +} |
1172 | + |
1173 | +int ast_careful_fwrite(FILE *f, int fd, const char *src, size_t len, int timeoutms) |
1174 | +{ |
1175 | + struct timeval start = ast_tvnow(); |
1176 | + int n = 0; |
1177 | + int elapsed = 0; |
1178 | + |
1179 | + while (len) { |
1180 | + if (ast_wait_for_output(fd, timeoutms - elapsed)) { |
1181 | + /* poll returned a fatal error, so bail out immediately. */ |
1182 | + return -1; |
1183 | + } |
1184 | + |
1185 | + /* Clear any errors from a previous write */ |
1186 | + clearerr(f); |
1187 | + |
1188 | + n = fwrite(src, 1, len, f); |
1189 | + |
1190 | + if (ferror(f) && errno != EINTR && errno != EAGAIN) { |
1191 | + /* fatal error from fwrite() */ |
1192 | + if (!feof(f)) { |
1193 | + /* Don't spam the logs if it was just that the connection is closed. */ |
1194 | + ast_log(LOG_ERROR, "fwrite() returned error: %s\n", strerror(errno)); |
1195 | + } |
1196 | + n = -1; |
1197 | + break; |
1198 | + } |
1199 | + |
1200 | + /* Update for data already written to the socket */ |
1201 | + len -= n; |
1202 | + src += n; |
1203 | + |
1204 | + elapsed = ast_tvdiff_ms(ast_tvnow(), start); |
1205 | + if (elapsed >= timeoutms) { |
1206 | + /* We've taken too long to write |
1207 | + * This is only an error condition if we haven't finished writing. */ |
1208 | + n = len ? -1 : 0; |
1209 | + break; |
1210 | + } |
1211 | + } |
1212 | + |
1213 | + while (fflush(f)) { |
1214 | + if (errno == EAGAIN || errno == EINTR) { |
1215 | + continue; |
1216 | + } |
1217 | + if (!feof(f)) { |
1218 | + /* Don't spam the logs if it was just that the connection is closed. */ |
1219 | + ast_log(LOG_ERROR, "fflush() returned error: %s\n", strerror(errno)); |
1220 | + } |
1221 | + n = -1; |
1222 | + break; |
1223 | + } |
1224 | + |
1225 | + return n < 0 ? -1 : 0; |
1226 | +} |
1227 | + |
1228 | +char *ast_strip_quoted(char *s, const char *beg_quotes, const char *end_quotes) |
1229 | +{ |
1230 | + char *e; |
1231 | + char *q; |
1232 | + |
1233 | + s = ast_strip(s); |
1234 | + if ((q = strchr(beg_quotes, *s)) && *q != '\0') { |
1235 | + e = s + strlen(s) - 1; |
1236 | + if (*e == *(end_quotes + (q - beg_quotes))) { |
1237 | + s++; |
1238 | + *e = '\0'; |
1239 | + } |
1240 | + } |
1241 | + |
1242 | + return s; |
1243 | +} |
1244 | + |
1245 | +char *ast_unescape_semicolon(char *s) |
1246 | +{ |
1247 | + char *e; |
1248 | + char *work = s; |
1249 | + |
1250 | + while ((e = strchr(work, ';'))) { |
1251 | + if ((e > work) && (*(e-1) == '\\')) { |
1252 | + memmove(e - 1, e, strlen(e) + 1); |
1253 | + work = e; |
1254 | + } else { |
1255 | + work = e + 1; |
1256 | + } |
1257 | + } |
1258 | + |
1259 | + return s; |
1260 | +} |
1261 | + |
1262 | +/* !\brief unescape some C sequences in place, return pointer to the original string. |
1263 | + */ |
1264 | +char *ast_unescape_c(char *src) |
1265 | +{ |
1266 | + char c, *ret, *dst; |
1267 | + |
1268 | + if (src == NULL) |
1269 | + return NULL; |
1270 | + for (ret = dst = src; (c = *src++); *dst++ = c ) { |
1271 | + if (c != '\\') |
1272 | + continue; /* copy char at the end of the loop */ |
1273 | + switch ((c = *src++)) { |
1274 | + case '\0': /* special, trailing '\' */ |
1275 | + c = '\\'; |
1276 | + break; |
1277 | + case 'b': /* backspace */ |
1278 | + c = '\b'; |
1279 | + break; |
1280 | + case 'f': /* form feed */ |
1281 | + c = '\f'; |
1282 | + break; |
1283 | + case 'n': |
1284 | + c = '\n'; |
1285 | + break; |
1286 | + case 'r': |
1287 | + c = '\r'; |
1288 | + break; |
1289 | + case 't': |
1290 | + c = '\t'; |
1291 | + break; |
1292 | + } |
1293 | + /* default, use the char literally */ |
1294 | + } |
1295 | + *dst = '\0'; |
1296 | + return ret; |
1297 | +} |
1298 | + |
1299 | +int ast_build_string_va(char **buffer, size_t *space, const char *fmt, va_list ap) |
1300 | +{ |
1301 | + int result; |
1302 | + |
1303 | + if (!buffer || !*buffer || !space || !*space) |
1304 | + return -1; |
1305 | + |
1306 | + result = vsnprintf(*buffer, *space, fmt, ap); |
1307 | + |
1308 | + if (result < 0) |
1309 | + return -1; |
1310 | + else if (result > *space) |
1311 | + result = *space; |
1312 | + |
1313 | + *buffer += result; |
1314 | + *space -= result; |
1315 | + return 0; |
1316 | +} |
1317 | + |
1318 | +int ast_build_string(char **buffer, size_t *space, const char *fmt, ...) |
1319 | +{ |
1320 | + va_list ap; |
1321 | + int result; |
1322 | + |
1323 | + va_start(ap, fmt); |
1324 | + result = ast_build_string_va(buffer, space, fmt, ap); |
1325 | + va_end(ap); |
1326 | + |
1327 | + return result; |
1328 | +} |
1329 | + |
1330 | +int ast_true(const char *s) |
1331 | +{ |
1332 | + if (ast_strlen_zero(s)) |
1333 | + return 0; |
1334 | + |
1335 | + /* Determine if this is a true value */ |
1336 | + if (!strcasecmp(s, "yes") || |
1337 | + !strcasecmp(s, "true") || |
1338 | + !strcasecmp(s, "y") || |
1339 | + !strcasecmp(s, "t") || |
1340 | + !strcasecmp(s, "1") || |
1341 | + !strcasecmp(s, "on")) |
1342 | + return -1; |
1343 | + |
1344 | + return 0; |
1345 | +} |
1346 | + |
1347 | +int ast_false(const char *s) |
1348 | +{ |
1349 | + if (ast_strlen_zero(s)) |
1350 | + return 0; |
1351 | + |
1352 | + /* Determine if this is a false value */ |
1353 | + if (!strcasecmp(s, "no") || |
1354 | + !strcasecmp(s, "false") || |
1355 | + !strcasecmp(s, "n") || |
1356 | + !strcasecmp(s, "f") || |
1357 | + !strcasecmp(s, "0") || |
1358 | + !strcasecmp(s, "off")) |
1359 | + return -1; |
1360 | + |
1361 | + return 0; |
1362 | +} |
1363 | + |
1364 | +#define ONE_MILLION 1000000 |
1365 | +/* |
1366 | + * put timeval in a valid range. usec is 0..999999 |
1367 | + * negative values are not allowed and truncated. |
1368 | + */ |
1369 | +static struct timeval tvfix(struct timeval a) |
1370 | +{ |
1371 | + if (a.tv_usec >= ONE_MILLION) { |
1372 | + ast_log(LOG_WARNING, "warning too large timestamp %ld.%ld\n", |
1373 | + (long)a.tv_sec, (long int) a.tv_usec); |
1374 | + a.tv_sec += a.tv_usec / ONE_MILLION; |
1375 | + a.tv_usec %= ONE_MILLION; |
1376 | + } else if (a.tv_usec < 0) { |
1377 | + ast_log(LOG_WARNING, "warning negative timestamp %ld.%ld\n", |
1378 | + (long)a.tv_sec, (long int) a.tv_usec); |
1379 | + a.tv_usec = 0; |
1380 | + } |
1381 | + return a; |
1382 | +} |
1383 | + |
1384 | +struct timeval ast_tvadd(struct timeval a, struct timeval b) |
1385 | +{ |
1386 | + /* consistency checks to guarantee usec in 0..999999 */ |
1387 | + a = tvfix(a); |
1388 | + b = tvfix(b); |
1389 | + a.tv_sec += b.tv_sec; |
1390 | + a.tv_usec += b.tv_usec; |
1391 | + if (a.tv_usec >= ONE_MILLION) { |
1392 | + a.tv_sec++; |
1393 | + a.tv_usec -= ONE_MILLION; |
1394 | + } |
1395 | + return a; |
1396 | +} |
1397 | + |
1398 | +struct timeval ast_tvsub(struct timeval a, struct timeval b) |
1399 | +{ |
1400 | + /* consistency checks to guarantee usec in 0..999999 */ |
1401 | + a = tvfix(a); |
1402 | + b = tvfix(b); |
1403 | + a.tv_sec -= b.tv_sec; |
1404 | + a.tv_usec -= b.tv_usec; |
1405 | + if (a.tv_usec < 0) { |
1406 | + a.tv_sec-- ; |
1407 | + a.tv_usec += ONE_MILLION; |
1408 | + } |
1409 | + return a; |
1410 | +} |
1411 | +#undef ONE_MILLION |
1412 | + |
1413 | +/*! \brief glibc puts a lock inside random(3), so that the results are thread-safe. |
1414 | + * BSD libc (and others) do not. */ |
1415 | + |
1416 | +#ifndef linux |
1417 | +AST_MUTEX_DEFINE_STATIC(randomlock); |
1418 | +#endif |
1419 | + |
1420 | +long int ast_random(void) |
1421 | +{ |
1422 | + long int res; |
1423 | +#ifdef HAVE_DEV_URANDOM |
1424 | + if (dev_urandom_fd >= 0) { |
1425 | + int read_res = read(dev_urandom_fd, &res, sizeof(res)); |
1426 | + if (read_res > 0) { |
1427 | + long int rm = RAND_MAX; |
1428 | + res = res < 0 ? ~res : res; |
1429 | + rm++; |
1430 | + return res % rm; |
1431 | + } |
1432 | + } |
1433 | +#endif |
1434 | +#ifdef linux |
1435 | + res = random(); |
1436 | +#else |
1437 | + ast_mutex_lock(&randomlock); |
1438 | + res = random(); |
1439 | + ast_mutex_unlock(&randomlock); |
1440 | +#endif |
1441 | + return res; |
1442 | +} |
1443 | + |
1444 | +char *ast_process_quotes_and_slashes(char *start, char find, char replace_with) |
1445 | +{ |
1446 | + char *dataPut = start; |
1447 | + int inEscape = 0; |
1448 | + int inQuotes = 0; |
1449 | + |
1450 | + for (; *start; start++) { |
1451 | + if (inEscape) { |
1452 | + *dataPut++ = *start; /* Always goes verbatim */ |
1453 | + inEscape = 0; |
1454 | + } else { |
1455 | + if (*start == '\\') { |
1456 | + inEscape = 1; /* Do not copy \ into the data */ |
1457 | + } else if (*start == '\'') { |
1458 | + inQuotes = 1 - inQuotes; /* Do not copy ' into the data */ |
1459 | + } else { |
1460 | + /* Replace , with |, unless in quotes */ |
1461 | + *dataPut++ = inQuotes ? *start : ((*start == find) ? replace_with : *start); |
1462 | + } |
1463 | + } |
1464 | + } |
1465 | + if (start != dataPut) |
1466 | + *dataPut = 0; |
1467 | + return dataPut; |
1468 | +} |
1469 | + |
1470 | +void ast_join(char *s, size_t len, char * const w[]) |
1471 | +{ |
1472 | + int x, ofs = 0; |
1473 | + const char *src; |
1474 | + |
1475 | + /* Join words into a string */ |
1476 | + if (!s) |
1477 | + return; |
1478 | + for (x = 0; ofs < len && w[x]; x++) { |
1479 | + if (x > 0) |
1480 | + s[ofs++] = ' '; |
1481 | + for (src = w[x]; *src && ofs < len; src++) |
1482 | + s[ofs++] = *src; |
1483 | + } |
1484 | + if (ofs == len) |
1485 | + ofs--; |
1486 | + s[ofs] = '\0'; |
1487 | +} |
1488 | + |
1489 | +/* |
1490 | + * stringfields support routines. |
1491 | + */ |
1492 | + |
1493 | +const char __ast_string_field_empty[] = ""; /*!< the empty string */ |
1494 | + |
1495 | +/*! \brief add a new block to the pool. |
1496 | + * We can only allocate from the topmost pool, so the |
1497 | + * fields in *mgr reflect the size of that only. |
1498 | + */ |
1499 | +static int add_string_pool(struct ast_string_field_mgr *mgr, struct ast_string_field_pool **pool_head, |
1500 | + size_t size, const char *file, int lineno, const char *func) |
1501 | +{ |
1502 | + struct ast_string_field_pool *pool; |
1503 | + |
1504 | +#if defined(__AST_DEBUG_MALLOC) |
1505 | + if (!(pool = __ast_calloc(1, sizeof(*pool) + size, file, lineno, func))) { |
1506 | + return -1; |
1507 | + } |
1508 | +#else |
1509 | + if (!(pool = ast_calloc(1, sizeof(*pool) + size))) { |
1510 | + return -1; |
1511 | + } |
1512 | +#endif |
1513 | + |
1514 | + pool->prev = *pool_head; |
1515 | + *pool_head = pool; |
1516 | + mgr->size = size; |
1517 | + mgr->used = 0; |
1518 | + mgr->last_alloc = NULL; |
1519 | + |
1520 | + return 0; |
1521 | +} |
1522 | + |
1523 | +/* |
1524 | + * This is an internal API, code should not use it directly. |
1525 | + * It initializes all fields as empty, then uses 'size' for 3 functions: |
1526 | + * size > 0 means initialize the pool list with a pool of given size. |
1527 | + * This must be called right after allocating the object. |
1528 | + * size = 0 means release all pools except the most recent one. |
1529 | + * This is useful to e.g. reset an object to the initial value. |
1530 | + * size < 0 means release all pools. |
1531 | + * This must be done before destroying the object. |
1532 | + */ |
1533 | +int __ast_string_field_init(struct ast_string_field_mgr *mgr, struct ast_string_field_pool **pool_head, |
1534 | + int needed, const char *file, int lineno, const char *func) |
1535 | +{ |
1536 | + const char **p = (const char **) pool_head + 1; |
1537 | + struct ast_string_field_pool *cur = NULL; |
1538 | + struct ast_string_field_pool *preserve = NULL; |
1539 | + |
1540 | + /* clear fields - this is always necessary */ |
1541 | + while ((struct ast_string_field_mgr *) p != mgr) |
1542 | + *p++ = __ast_string_field_empty; |
1543 | + mgr->last_alloc = NULL; |
1544 | +#if defined(__AST_DEBUG_MALLOC) |
1545 | + mgr->owner_file = file; |
1546 | + mgr->owner_func = func; |
1547 | + mgr->owner_line = lineno; |
1548 | +#endif |
1549 | + if (needed > 0) { /* allocate the initial pool */ |
1550 | + *pool_head = NULL; |
1551 | + return add_string_pool(mgr, pool_head, needed, file, lineno, func); |
1552 | + } |
1553 | + if (needed < 0) { /* reset all pools */ |
1554 | + if (*pool_head == NULL) { |
1555 | + ast_log(LOG_WARNING, "trying to reset empty pool\n"); |
1556 | + return -1; |
1557 | + } |
1558 | + cur = *pool_head; |
1559 | + } else { /* preserve the last pool */ |
1560 | + if (*pool_head == NULL) { |
1561 | + ast_log(LOG_WARNING, "trying to reset empty pool\n"); |
1562 | + return -1; |
1563 | + } |
1564 | + mgr->used = 0; |
1565 | + preserve = *pool_head; |
1566 | + cur = preserve->prev; |
1567 | + } |
1568 | + |
1569 | + if (preserve) { |
1570 | + preserve->prev = NULL; |
1571 | + } |
1572 | + |
1573 | + while (cur) { |
1574 | + struct ast_string_field_pool *prev = cur->prev; |
1575 | + |
1576 | + if (cur != preserve) { |
1577 | + ast_free(cur); |
1578 | + } |
1579 | + cur = prev; |
1580 | + } |
1581 | + |
1582 | + *pool_head = preserve; |
1583 | + |
1584 | + return 0; |
1585 | +} |
1586 | + |
1587 | +ast_string_field __ast_string_field_alloc_space(struct ast_string_field_mgr *mgr, |
1588 | + struct ast_string_field_pool **pool_head, size_t needed) |
1589 | +{ |
1590 | + char *result = NULL; |
1591 | + size_t space = mgr->size - mgr->used; |
1592 | + |
1593 | + if (__builtin_expect(needed > space, 0)) { |
1594 | + size_t new_size = mgr->size * 2; |
1595 | + |
1596 | + while (new_size < needed) |
1597 | + new_size *= 2; |
1598 | + |
1599 | +#if defined(__AST_DEBUG_MALLOC) |
1600 | + if (add_string_pool(mgr, pool_head, new_size, mgr->owner_file, mgr->owner_line, mgr->owner_func)) |
1601 | + return NULL; |
1602 | +#else |
1603 | + if (add_string_pool(mgr, pool_head, new_size, __FILE__, __LINE__, __FUNCTION__)) |
1604 | + return NULL; |
1605 | +#endif |
1606 | + } |
1607 | + |
1608 | + result = (*pool_head)->base + mgr->used; |
1609 | + mgr->used += needed; |
1610 | + mgr->last_alloc = result; |
1611 | + return result; |
1612 | +} |
1613 | + |
1614 | +int __ast_string_field_ptr_grow(struct ast_string_field_mgr *mgr, size_t needed, |
1615 | + const ast_string_field *ptr) |
1616 | +{ |
1617 | + int grow = needed - (strlen(*ptr) + 1); |
1618 | + size_t space = mgr->size - mgr->used; |
1619 | + |
1620 | + if (grow <= 0) { |
1621 | + return 0; |
1622 | + } |
1623 | + |
1624 | + if (*ptr != mgr->last_alloc) { |
1625 | + return 1; |
1626 | + } |
1627 | + |
1628 | + if (space < grow) { |
1629 | + return 1; |
1630 | + } |
1631 | + |
1632 | + mgr->used += grow; |
1633 | + |
1634 | + return 0; |
1635 | +} |
1636 | + |
1637 | +void __ast_string_field_ptr_build_va(struct ast_string_field_mgr *mgr, |
1638 | + struct ast_string_field_pool **pool_head, |
1639 | + ast_string_field *ptr, const char *format, va_list ap1, va_list ap2) |
1640 | +{ |
1641 | + size_t needed; |
1642 | + size_t available; |
1643 | + size_t space = mgr->size - mgr->used; |
1644 | + char *target; |
1645 | + |
1646 | + /* if the field already has space allocated, try to reuse it; |
1647 | + otherwise, use the empty space at the end of the current |
1648 | + pool |
1649 | + */ |
1650 | + if ((*ptr)[0] != '\0') { |
1651 | + target = (char *) *ptr; |
1652 | + available = strlen(target) + 1; |
1653 | + } else { |
1654 | + target = (*pool_head)->base + mgr->used; |
1655 | + available = space; |
1656 | + } |
1657 | + |
1658 | + needed = vsnprintf(target, available, format, ap1) + 1; |
1659 | + |
1660 | + va_end(ap1); |
1661 | + |
1662 | + if (needed > available) { |
1663 | + /* if the space needed can be satisfied by using the current |
1664 | + pool (which could only occur if we tried to use the field's |
1665 | + allocated space and failed), then use that space; otherwise |
1666 | + allocate a new pool |
1667 | + */ |
1668 | + if (needed > space) { |
1669 | + size_t new_size = mgr->size * 2; |
1670 | + |
1671 | + while (new_size < needed) |
1672 | + new_size *= 2; |
1673 | + |
1674 | +#if defined(__AST_DEBUG_MALLOC) |
1675 | + if (add_string_pool(mgr, pool_head, new_size, mgr->owner_file, mgr->owner_line, mgr->owner_func)) |
1676 | + return; |
1677 | +#else |
1678 | + if (add_string_pool(mgr, pool_head, new_size, NULL, 0, NULL)) |
1679 | + return; |
1680 | +#endif |
1681 | + } |
1682 | + |
1683 | + target = (*pool_head)->base + mgr->used; |
1684 | + vsprintf(target, format, ap2); |
1685 | + } |
1686 | + |
1687 | + if (*ptr != target) { |
1688 | + mgr->last_alloc = *ptr = target; |
1689 | + mgr->used += needed; |
1690 | + } |
1691 | +} |
1692 | + |
1693 | +void __ast_string_field_ptr_build(struct ast_string_field_mgr *mgr, |
1694 | + struct ast_string_field_pool **pool_head, |
1695 | + ast_string_field *ptr, const char *format, ...) |
1696 | +{ |
1697 | + va_list ap1, ap2; |
1698 | + |
1699 | + va_start(ap1, format); |
1700 | + va_start(ap2, format); /* va_copy does not exist on FreeBSD */ |
1701 | + |
1702 | + __ast_string_field_ptr_build_va(mgr, pool_head, ptr, format, ap1, ap2); |
1703 | + |
1704 | + va_end(ap1); |
1705 | + va_end(ap2); |
1706 | +} |
1707 | +/* end of stringfields support */ |
1708 | + |
1709 | +AST_MUTEX_DEFINE_STATIC(fetchadd_m); /* used for all fetc&add ops */ |
1710 | + |
1711 | +int ast_atomic_fetchadd_int_slow(volatile int *p, int v) |
1712 | +{ |
1713 | + int ret; |
1714 | + ast_mutex_lock(&fetchadd_m); |
1715 | + ret = *p; |
1716 | + *p += v; |
1717 | + ast_mutex_unlock(&fetchadd_m); |
1718 | + return ret; |
1719 | +} |
1720 | + |
1721 | +/*! \brief |
1722 | + * get values from config variables. |
1723 | + */ |
1724 | +int ast_get_timeval(const char *src, struct timeval *dst, struct timeval _default, int *consumed) |
1725 | +{ |
1726 | + long double dtv = 0.0; |
1727 | + int scanned; |
1728 | + |
1729 | + if (dst == NULL) |
1730 | + return -1; |
1731 | + |
1732 | + *dst = _default; |
1733 | + |
1734 | + if (ast_strlen_zero(src)) |
1735 | + return -1; |
1736 | + |
1737 | + /* only integer at the moment, but one day we could accept more formats */ |
1738 | + if (sscanf(src, "%30Lf%n", &dtv, &scanned) > 0) { |
1739 | + dst->tv_sec = dtv; |
1740 | + dst->tv_usec = (dtv - dst->tv_sec) * 1000000.0; |
1741 | + if (consumed) |
1742 | + *consumed = scanned; |
1743 | + return 0; |
1744 | + } else |
1745 | + return -1; |
1746 | +} |
1747 | + |
1748 | +/*! \brief |
1749 | + * get values from config variables. |
1750 | + */ |
1751 | +int ast_get_time_t(const char *src, time_t *dst, time_t _default, int *consumed) |
1752 | +{ |
1753 | + long t; |
1754 | + int scanned; |
1755 | + |
1756 | + if (dst == NULL) |
1757 | + return -1; |
1758 | + |
1759 | + *dst = _default; |
1760 | + |
1761 | + if (ast_strlen_zero(src)) |
1762 | + return -1; |
1763 | + |
1764 | + /* only integer at the moment, but one day we could accept more formats */ |
1765 | + if (sscanf(src, "%30ld%n", &t, &scanned) == 1) { |
1766 | + *dst = t; |
1767 | + if (consumed) |
1768 | + *consumed = scanned; |
1769 | + return 0; |
1770 | + } else |
1771 | + return -1; |
1772 | +} |
1773 | + |
1774 | +void ast_enable_packet_fragmentation(int sock) |
1775 | +{ |
1776 | +#if defined(HAVE_IP_MTU_DISCOVER) |
1777 | + int val = IP_PMTUDISC_DONT; |
1778 | + |
1779 | + if (setsockopt(sock, IPPROTO_IP, IP_MTU_DISCOVER, &val, sizeof(val))) |
1780 | + ast_log(LOG_WARNING, "Unable to disable PMTU discovery. Large UDP packets may fail to be delivered when sent from this socket.\n"); |
1781 | +#endif /* HAVE_IP_MTU_DISCOVER */ |
1782 | +} |
1783 | + |
1784 | +int ast_mkdir(const char *path, int mode) |
1785 | +{ |
1786 | + char *ptr; |
1787 | + int len = strlen(path), count = 0, x, piececount = 0; |
1788 | + char *tmp = ast_strdupa(path); |
1789 | + char **pieces; |
1790 | + char *fullpath = alloca(len + 1); |
1791 | + int res = 0; |
1792 | + |
1793 | + for (ptr = tmp; *ptr; ptr++) { |
1794 | + if (*ptr == '/') |
1795 | + count++; |
1796 | + } |
1797 | + |
1798 | + /* Count the components to the directory path */ |
1799 | + pieces = alloca(count * sizeof(*pieces)); |
1800 | + for (ptr = tmp; *ptr; ptr++) { |
1801 | + if (*ptr == '/') { |
1802 | + *ptr = '\0'; |
1803 | + pieces[piececount++] = ptr + 1; |
1804 | + } |
1805 | + } |
1806 | + |
1807 | + *fullpath = '\0'; |
1808 | + for (x = 0; x < piececount; x++) { |
1809 | + /* This looks funky, but the buffer is always ideally-sized, so it's fine. */ |
1810 | + strcat(fullpath, "/"); |
1811 | + strcat(fullpath, pieces[x]); |
1812 | + res = mkdir(fullpath, mode); |
1813 | + if (res && errno != EEXIST) |
1814 | + return errno; |
1815 | + } |
1816 | + return 0; |
1817 | +} |
1818 | + |
1819 | +int ast_utils_init(void) |
1820 | +{ |
1821 | +#ifdef HAVE_DEV_URANDOM |
1822 | + dev_urandom_fd = open("/dev/urandom", O_RDONLY); |
1823 | +#endif |
1824 | + base64_init(); |
1825 | +#ifdef DEBUG_THREADS |
1826 | +#if !defined(LOW_MEMORY) |
1827 | + ast_cli_register_multiple(utils_cli, ARRAY_LEN(utils_cli)); |
1828 | +#endif |
1829 | +#endif |
1830 | + return 0; |
1831 | +} |
1832 | + |
1833 | +#ifndef __AST_DEBUG_MALLOC |
1834 | +int _ast_asprintf(char **ret, const char *file, int lineno, const char *func, const char *fmt, ...) |
1835 | +{ |
1836 | + int res; |
1837 | + va_list ap; |
1838 | + |
1839 | + va_start(ap, fmt); |
1840 | + if ((res = vasprintf(ret, fmt, ap)) == -1) { |
1841 | + MALLOC_FAILURE_MSG; |
1842 | + } |
1843 | + va_end(ap); |
1844 | + |
1845 | + return res; |
1846 | +} |
1847 | +#endif |
1848 | |
1849 | === modified file '.pc/applied-patches' |
1850 | --- .pc/applied-patches 2010-10-15 22:24:34 +0000 |
1851 | +++ .pc/applied-patches 2011-01-20 21:24:59 +0000 |
1852 | @@ -17,3 +17,4 @@ |
1853 | man_hyphen |
1854 | typos |
1855 | rtcp_cli_fix |
1856 | +AST-2011-001-1.6.2 |
1857 | |
1858 | === modified file 'debian/changelog' |
1859 | --- debian/changelog 2010-10-15 22:24:34 +0000 |
1860 | +++ debian/changelog 2011-01-20 21:24:59 +0000 |
1861 | @@ -1,3 +1,13 @@ |
1862 | +asterisk (1:1.6.2.9-2ubuntu2) natty; urgency=low |
1863 | + |
1864 | + * SECURITY UPDATE: Stack buffer overflow in SIP channel driver. (LP: #705014) |
1865 | + - debian/patches/AST-2011-001-1.6.2: The size of the output buffer passed |
1866 | + to the ast_uri_encode function is now properly respected in main/utils.c. |
1867 | + Patch courtesy of upstream. |
1868 | + - CVE-2011-0495 |
1869 | + |
1870 | + -- Dave Walker (Daviey) <DaveWalker@ubuntu.com> Thu, 20 Jan 2011 21:19:46 +0000 |
1871 | + |
1872 | asterisk (1:1.6.2.9-2ubuntu1) natty; urgency=low |
1873 | |
1874 | * Merge from debian unstable, remaining changes: |
1875 | |
1876 | === added file 'debian/patches/AST-2011-001-1.6.2' |
1877 | --- debian/patches/AST-2011-001-1.6.2 1970-01-01 00:00:00 +0000 |
1878 | +++ debian/patches/AST-2011-001-1.6.2 2011-01-20 21:24:59 +0000 |
1879 | @@ -0,0 +1,52 @@ |
1880 | +Description: Stack buffer overflow in SIP channel driver. |
1881 | + Prevent buffer overflows in ast_uri_encode() |
1882 | +Origin: upstream, http://downloads.asterisk.org/pub/security/AST-2011-001.html |
1883 | +Bug-Ubuntu: https://launchpad.net/bugs/705014 |
1884 | +Bug-Debian: http://bugs.debian.org/610487 |
1885 | +Applied-Upstream: http://svnview.digium.com/svn/asterisk?view=revision&revision=301307 |
1886 | +Last-Update: 2011-01-20 |
1887 | + |
1888 | +--- a/main/utils.c |
1889 | ++++ b/main/utils.c |
1890 | +@@ -385,28 +385,27 @@ |
1891 | + char *reserved = ";/?:@&=+$,# "; /* Reserved chars */ |
1892 | + |
1893 | + const char *ptr = string; /* Start with the string */ |
1894 | +- char *out = NULL; |
1895 | +- char *buf = NULL; |
1896 | ++ char *out = outbuf; |
1897 | + |
1898 | +- ast_copy_string(outbuf, string, buflen); |
1899 | +- |
1900 | +- /* If there's no characters to convert, just go through and don't do anything */ |
1901 | +- while (*ptr) { |
1902 | ++ /* If there's no characters to convert, just go through and copy the string */ |
1903 | ++ while (*ptr && out - outbuf < buflen - 1) { |
1904 | + if ((*ptr < 32) || (doreserved && strchr(reserved, *ptr))) { |
1905 | +- /* Oops, we need to start working here */ |
1906 | +- if (!buf) { |
1907 | +- buf = outbuf; |
1908 | +- out = buf + (ptr - string) ; /* Set output ptr */ |
1909 | ++ if (out - outbuf >= buflen - 3) { |
1910 | ++ break; |
1911 | + } |
1912 | ++ |
1913 | + out += sprintf(out, "%%%02x", (unsigned char) *ptr); |
1914 | +- } else if (buf) { |
1915 | +- *out = *ptr; /* Continue copying the string */ |
1916 | ++ } else { |
1917 | ++ *out = *ptr; /* copy the character */ |
1918 | + out++; |
1919 | +- } |
1920 | ++ } |
1921 | + ptr++; |
1922 | + } |
1923 | +- if (buf) |
1924 | ++ |
1925 | ++ if (buflen) { |
1926 | + *out = '\0'; |
1927 | ++ } |
1928 | ++ |
1929 | + return outbuf; |
1930 | + } |
1931 | + |
1932 | |
1933 | === modified file 'debian/patches/series' |
1934 | --- debian/patches/series 2010-10-15 22:24:34 +0000 |
1935 | +++ debian/patches/series 2011-01-20 21:24:59 +0000 |
1936 | @@ -25,3 +25,5 @@ |
1937 | man_hyphen |
1938 | typos |
1939 | rtcp_cli_fix |
1940 | + |
1941 | +AST-2011-001-1.6.2 |
1942 | |
1943 | === modified file 'main/utils.c' |
1944 | --- main/utils.c 2010-02-16 14:08:54 +0000 |
1945 | +++ main/utils.c 2011-01-20 21:24:59 +0000 |
1946 | @@ -385,28 +385,27 @@ |
1947 | char *reserved = ";/?:@&=+$,# "; /* Reserved chars */ |
1948 | |
1949 | const char *ptr = string; /* Start with the string */ |
1950 | - char *out = NULL; |
1951 | - char *buf = NULL; |
1952 | - |
1953 | - ast_copy_string(outbuf, string, buflen); |
1954 | - |
1955 | - /* If there's no characters to convert, just go through and don't do anything */ |
1956 | - while (*ptr) { |
1957 | + char *out = outbuf; |
1958 | + |
1959 | + /* If there's no characters to convert, just go through and copy the string */ |
1960 | + while (*ptr && out - outbuf < buflen - 1) { |
1961 | if ((*ptr < 32) || (doreserved && strchr(reserved, *ptr))) { |
1962 | - /* Oops, we need to start working here */ |
1963 | - if (!buf) { |
1964 | - buf = outbuf; |
1965 | - out = buf + (ptr - string) ; /* Set output ptr */ |
1966 | + if (out - outbuf >= buflen - 3) { |
1967 | + break; |
1968 | } |
1969 | + |
1970 | out += sprintf(out, "%%%02x", (unsigned char) *ptr); |
1971 | - } else if (buf) { |
1972 | - *out = *ptr; /* Continue copying the string */ |
1973 | + } else { |
1974 | + *out = *ptr; /* copy the character */ |
1975 | out++; |
1976 | - } |
1977 | + } |
1978 | ptr++; |
1979 | } |
1980 | - if (buf) |
1981 | + |
1982 | + if (buflen) { |
1983 | *out = '\0'; |
1984 | + } |
1985 | + |
1986 | return outbuf; |
1987 | } |
1988 |
Thanks!