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