/src/rtpproxy/src/rtpp_util.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) 2004-2006 Maxim Sobolev <sobomax@FreeBSD.org> |
3 | | * Copyright (c) 2006-2023 Sippy Software, Inc., http://www.sippysoft.com |
4 | | * All rights reserved. |
5 | | * |
6 | | * Redistribution and use in source and binary forms, with or without |
7 | | * modification, are permitted provided that the following conditions |
8 | | * are met: |
9 | | * 1. Redistributions of source code must retain the above copyright |
10 | | * notice, this list of conditions and the following disclaimer. |
11 | | * 2. Redistributions in binary form must reproduce the above copyright |
12 | | * notice, this list of conditions and the following disclaimer in the |
13 | | * documentation and/or other materials provided with the distribution. |
14 | | * |
15 | | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
16 | | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
17 | | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
18 | | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
19 | | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
20 | | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
21 | | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
22 | | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
23 | | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
24 | | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
25 | | * SUCH DAMAGE. |
26 | | * |
27 | | */ |
28 | | |
29 | | #include <sys/time.h> |
30 | | #include <sys/types.h> |
31 | | #include <sys/resource.h> |
32 | | #include <errno.h> |
33 | | #include <fcntl.h> |
34 | | #include <stdint.h> |
35 | | #include <signal.h> |
36 | | #include <stdlib.h> |
37 | | #include <string.h> |
38 | | #include <unistd.h> |
39 | | |
40 | | #include "config.h" |
41 | | |
42 | | #ifdef HAVE_SYS_SYSCTL_H |
43 | | #include <sys/sysctl.h> |
44 | | #endif |
45 | | |
46 | | #include "rtpp_types.h" |
47 | | #include "rtpp_log.h" |
48 | | #include "rtpp_cfg.h" |
49 | | #include "rtpp_util.h" |
50 | | #include "rtpp_log_obj.h" |
51 | | #include "rtpp_runcreds.h" |
52 | | #include "rtpp_debug.h" |
53 | | |
54 | | #if defined(RTPP_DEBUG) |
55 | | #include "rtpp_coverage.h" |
56 | | #endif |
57 | | |
58 | | void |
59 | | seedrandom(void) |
60 | 4 | { |
61 | | #if !defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) |
62 | | int fd; |
63 | | unsigned long junk; |
64 | | struct timeval tv; |
65 | | |
66 | | fd = open("/dev/urandom", O_RDONLY, 0); |
67 | | if (fd >= 0) { |
68 | | read(fd, &junk, sizeof(junk)); |
69 | | close(fd); |
70 | | } else { |
71 | | junk = 0; |
72 | | } |
73 | | |
74 | | gettimeofday(&tv, NULL); |
75 | | srandom((unsigned int)(getpid() << 14) ^ tv.tv_sec ^ tv.tv_usec ^ junk); |
76 | | #else |
77 | 4 | srandom(42); |
78 | 4 | #endif |
79 | 4 | } |
80 | | |
81 | | int |
82 | | set_rlimits(const struct rtpp_cfg *cfsp) |
83 | 2 | { |
84 | 2 | struct rlimit rlp; |
85 | | |
86 | 2 | if (getrlimit(RLIMIT_CORE, &rlp) < 0) { |
87 | 0 | RTPP_ELOG(cfsp->glog, RTPP_LOG_ERR, "getrlimit(RLIMIT_CORE)"); |
88 | 0 | return (-1); |
89 | 0 | } |
90 | 2 | rlp.rlim_cur = RLIM_INFINITY; |
91 | 2 | rlp.rlim_max = RLIM_INFINITY; |
92 | 2 | if (setrlimit(RLIMIT_CORE, &rlp) < 0) { |
93 | 0 | RTPP_ELOG(cfsp->glog, RTPP_LOG_ERR, "setrlimit(RLIMIT_CORE)"); |
94 | 0 | return (-1); |
95 | 0 | } |
96 | 2 | return (0); |
97 | 2 | } |
98 | | |
99 | | int |
100 | | drop_privileges(const struct rtpp_cfg *cfsp) |
101 | 0 | { |
102 | |
|
103 | 0 | if (cfsp->runcreds->gname != NULL) { |
104 | 0 | if (setgid(cfsp->runcreds->gid) != 0) { |
105 | 0 | RTPP_ELOG(cfsp->glog, RTPP_LOG_ERR, "can't set current group ID: %d", |
106 | 0 | (int)cfsp->runcreds->gid); |
107 | 0 | return -1; |
108 | 0 | } |
109 | 0 | } |
110 | 0 | if (cfsp->runcreds->uname == NULL) |
111 | 0 | return 0; |
112 | 0 | if (setuid(cfsp->runcreds->uid) != 0) { |
113 | 0 | RTPP_ELOG(cfsp->glog, RTPP_LOG_ERR, "can't set current user ID: %d", |
114 | 0 | (int)cfsp->runcreds->uid); |
115 | 0 | return -1; |
116 | 0 | } |
117 | 0 | return 0; |
118 | 0 | } |
119 | | |
120 | | /* |
121 | | * Portable strsep(3) implementation, borrowed from FreeBSD. For license |
122 | | * and other information see: |
123 | | * |
124 | | * $FreeBSD: src/lib/libc/string/strsep.c,v 1.6 2007/01/09 00:28:12 imp Exp $ |
125 | | */ |
126 | | char * |
127 | | rtpp_strsep(char **stringp, const char *delim) |
128 | 0 | { |
129 | 0 | char *s; |
130 | 0 | const char *spanp; |
131 | 0 | int c, sc; |
132 | 0 | char *tok; |
133 | |
|
134 | 0 | if ((s = *stringp) == NULL) |
135 | 0 | return (NULL); |
136 | 0 | for (tok = s;;) { |
137 | 0 | c = *s++; |
138 | 0 | spanp = delim; |
139 | 0 | do { |
140 | 0 | if ((sc = *spanp++) == c) { |
141 | 0 | if (c == 0) |
142 | 0 | s = NULL; |
143 | 0 | else |
144 | 0 | s[-1] = 0; |
145 | 0 | *stringp = s; |
146 | 0 | return (tok); |
147 | 0 | } |
148 | 0 | } while (sc != 0); |
149 | 0 | } |
150 | | /* NOTREACHED */ |
151 | 0 | } |
152 | | |
153 | | static void __attribute__ ((noreturn)) |
154 | | rtpp_daemon_parent(const struct rtpp_daemon_rope *rp) |
155 | 0 | { |
156 | 0 | char buf[rp->msglen]; |
157 | 0 | int r, e = 0; |
158 | |
|
159 | 0 | do { |
160 | 0 | r = read(rp->pipe, buf, rp->msglen); |
161 | 0 | } while (r < 0 && errno == EINTR); |
162 | 0 | if (r < rp->msglen || memcmp(buf, rp->ok_msg, rp->msglen) != 0) { |
163 | 0 | e = 1; |
164 | 0 | } |
165 | | #if defined(RTPP_DEBUG) |
166 | | rtpp_gcov_flush(); |
167 | | #endif |
168 | 0 | _exit(e); |
169 | 0 | } |
170 | | |
171 | | int |
172 | | rtpp_daemon_rel_parent(const struct rtpp_daemon_rope *rp) |
173 | 0 | { |
174 | 0 | int r; |
175 | |
|
176 | 0 | do { |
177 | 0 | r = write(rp->pipe, rp->ok_msg, rp->msglen); |
178 | 0 | } while (r < 0 && errno == EINTR); |
179 | 0 | (void)close(rp->pipe); |
180 | 0 | if (r == rp->msglen) |
181 | 0 | return (0); |
182 | 0 | return (-1); |
183 | 0 | } |
184 | | |
185 | | /* |
186 | | * Portable daemon(3) implementation, derived from FreeBSD. For license |
187 | | * and other information see: |
188 | | * |
189 | | * $FreeBSD: src/lib/libc/gen/daemon.c,v 1.8 2007/01/09 00:27:53 imp Exp $ |
190 | | * |
191 | | * This version has since been extended to permit simple protocol |
192 | | * to be implemented between parent and a child to keep parent |
193 | | * alive until child done everything it needs to do in order to get |
194 | | * up and running, so that any error condition can be propagated |
195 | | * back. |
196 | | */ |
197 | | |
198 | | struct rtpp_daemon_rope |
199 | | rtpp_daemon(int nochdir, int noclose, int noredir) |
200 | 0 | { |
201 | 0 | struct sigaction osa, sa; |
202 | 0 | int fd; |
203 | 0 | pid_t newgrp; |
204 | 0 | int oerrno; |
205 | 0 | int osa_ok; |
206 | 0 | int ropefd[2]; |
207 | 0 | struct rtpp_daemon_rope res = {.result = 0, .ok_msg = "OK", .msglen = 2}; |
208 | |
|
209 | 0 | if (!noclose) { |
210 | 0 | fd = open("/dev/null", O_RDWR, 0); |
211 | 0 | if (fd < 0) |
212 | 0 | goto fail; |
213 | 0 | } |
214 | 0 | if (pipe(ropefd) != 0) { |
215 | 0 | goto e0; |
216 | 0 | } |
217 | | /* A SIGHUP may be thrown when the parent exits below. */ |
218 | 0 | sigemptyset(&sa.sa_mask); |
219 | 0 | sa.sa_handler = SIG_IGN; |
220 | 0 | sa.sa_flags = 0; |
221 | 0 | osa_ok = sigaction(SIGHUP, &sa, &osa); |
222 | |
|
223 | 0 | switch (fork()) { |
224 | 0 | case -1: |
225 | 0 | goto e1; |
226 | 0 | case 0: /* child */ |
227 | 0 | (void)close(ropefd[0]); |
228 | 0 | res.pipe = ropefd[1]; |
229 | 0 | break; |
230 | 0 | default: /* parent */ |
231 | 0 | (void)close(ropefd[1]); |
232 | 0 | res.pipe = ropefd[0]; |
233 | 0 | rtpp_daemon_parent(&res); |
234 | | /* noreturn */ |
235 | 0 | } |
236 | | |
237 | 0 | newgrp = setsid(); |
238 | 0 | oerrno = errno; |
239 | 0 | if (osa_ok != -1) |
240 | 0 | sigaction(SIGHUP, &osa, NULL); |
241 | |
|
242 | 0 | if (newgrp == -1) { |
243 | 0 | errno = oerrno; |
244 | 0 | goto child_fail; |
245 | 0 | } |
246 | | |
247 | 0 | if (!nochdir) |
248 | 0 | (void)chdir("/"); |
249 | |
|
250 | 0 | if (!noclose) { |
251 | 0 | if (fd != STDIN_FILENO) { |
252 | 0 | if (dup2(fd, STDIN_FILENO) < 0) { |
253 | 0 | (void)close(fd); |
254 | 0 | goto child_fail; |
255 | 0 | } |
256 | 0 | (void)close(fd); |
257 | 0 | } |
258 | 0 | #if !defined(RTPP_DEBUG) |
259 | 0 | if (!noredir) { |
260 | 0 | if (dup2(STDIN_FILENO, STDOUT_FILENO) < 0) { |
261 | 0 | goto child_fail; |
262 | 0 | } |
263 | 0 | if (dup2(STDIN_FILENO, STDERR_FILENO) < 0) { |
264 | 0 | goto child_fail; |
265 | 0 | } |
266 | 0 | } |
267 | 0 | #endif |
268 | 0 | } |
269 | 0 | return (res); |
270 | 0 | child_fail: |
271 | 0 | (void)close(res.pipe); |
272 | 0 | goto fail; |
273 | 0 | e1: |
274 | 0 | (void)close(ropefd[0]); |
275 | 0 | (void)close(ropefd[1]); |
276 | 0 | e0: |
277 | 0 | if (!noclose) |
278 | 0 | (void)close(fd); |
279 | 0 | fail: |
280 | 0 | return ((struct rtpp_daemon_rope){.result = -1}); |
281 | 0 | } |
282 | | |
283 | | static int8_t hex2char[128] = { |
284 | | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
285 | | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
286 | | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
287 | | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, |
288 | | -1, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
289 | | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
290 | | -1, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
291 | | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 |
292 | | }; |
293 | | |
294 | | int |
295 | | url_unquote2(const char *ibuf, char *obuf, int len) |
296 | 10.5k | { |
297 | 10.5k | int outlen; |
298 | 10.5k | uint8_t *ocp = (uint8_t *)obuf; |
299 | 10.5k | const unsigned char *cp, *endp; |
300 | | |
301 | 10.5k | outlen = len; |
302 | 10.5k | endp = (const unsigned char *)ibuf + len; |
303 | 79.3k | for (cp = (const unsigned char *)ibuf; cp < endp; cp++, ocp++) { |
304 | 70.0k | switch (cp[0]) { |
305 | 2.61k | case '%': |
306 | 2.61k | if (cp + 2 > endp) |
307 | 411 | return (-1); |
308 | 2.20k | if (cp[1] > 127 || cp[2] > 127 || |
309 | 1.79k | hex2char[cp[1]] == -1 || hex2char[cp[2]] == -1) |
310 | 906 | return (-1); |
311 | 1.29k | ocp[0] = (hex2char[cp[1]] << 4) | hex2char[cp[2]]; |
312 | 1.29k | cp += 2; |
313 | 1.29k | outlen -= 2; |
314 | 1.29k | break; |
315 | | |
316 | 1.66k | case '+': |
317 | 1.66k | ocp[0] = ' '; |
318 | 1.66k | break; |
319 | | |
320 | 65.7k | default: |
321 | 65.7k | if (ocp != cp) |
322 | 28.2k | ocp[0] = cp[0]; |
323 | 65.7k | break; |
324 | 70.0k | } |
325 | 70.0k | } |
326 | 9.22k | return (outlen); |
327 | 10.5k | } |
328 | | |
329 | | int |
330 | | url_unquote(unsigned char *buf, int len) |
331 | 8.66k | { |
332 | | |
333 | 8.66k | return (url_unquote2((char *)buf, (char *)buf, len)); |
334 | 8.66k | } |
335 | | |
336 | | int |
337 | 86.6k | url_quote(const char *ibuf, char *obuf, int ilen, int olen) { |
338 | 86.6k | const char *hex = "0123456789ABCDEF"; |
339 | 86.6k | const unsigned char *cp; |
340 | 86.6k | unsigned char *ocp = (unsigned char *)obuf; |
341 | 86.6k | int outlen = 0; |
342 | | |
343 | 397k | for (cp = (const unsigned char *)ibuf; ilen-- > 0; cp++) { |
344 | 311k | if ((*cp >= 'A' && *cp <= 'Z') || (*cp >= 'a' && *cp <= 'z') || |
345 | 245k | (*cp >= '0' && *cp <= '9') || *cp == '-' || *cp == '_' || |
346 | 264k | *cp == '.' || *cp == '~') { |
347 | 264k | if ((olen - outlen) == 0) |
348 | 0 | return -1; |
349 | 264k | *ocp++ = *cp; |
350 | 264k | outlen++; |
351 | 264k | } else { |
352 | 47.0k | if ((olen - outlen) < 3) |
353 | 241 | return -1; |
354 | 46.7k | *ocp++ = '%'; |
355 | 46.7k | *ocp++ = hex[*cp >> 4]; |
356 | 46.7k | *ocp++ = hex[*cp & 0x0F]; |
357 | 46.7k | outlen += 3; |
358 | 46.7k | } |
359 | 311k | } |
360 | 86.3k | return outlen; |
361 | 86.6k | } |
362 | | |
363 | | enum atoi_rval |
364 | | atoi_safe_sep(const char *s, int *res, char sep, const char * *next) |
365 | 80.8k | { |
366 | 80.8k | int rval; |
367 | 80.8k | char *cp; |
368 | | |
369 | 80.8k | rval = strtol(s, &cp, 10); |
370 | 80.8k | if (cp == s || *cp != sep) { |
371 | 2.23k | return (ATOI_NOTINT); |
372 | 2.23k | } |
373 | 78.6k | *res = rval; |
374 | 78.6k | if (next != NULL) { |
375 | 37.6k | *next = cp + 1; |
376 | 37.6k | } |
377 | 78.6k | return (ATOI_OK); |
378 | 80.8k | } |
379 | | |
380 | | enum atoi_rval |
381 | | atoi_safe(const char *s, int *res) |
382 | 42.3k | { |
383 | | |
384 | 42.3k | return (atoi_safe_sep(s, res, '\0', NULL)); |
385 | 42.3k | } |
386 | | |
387 | | enum atoi_rval |
388 | | atoi_saferange(const char *s, int *res, int min, int max) |
389 | 1.87k | { |
390 | 1.87k | int rval; |
391 | | |
392 | 1.87k | if (atoi_safe(s, &rval)) { |
393 | 465 | return (ATOI_NOTINT); |
394 | 465 | } |
395 | 1.40k | if (rval < min || (max >= min && rval > max)) { |
396 | 185 | return (ATOI_OUTRANGE); |
397 | 185 | } |
398 | 1.22k | *res = rval; |
399 | 1.22k | return (ATOI_OK); |
400 | 1.40k | } |
401 | | |
402 | | enum atoi_rval |
403 | | rtpp_parse_rtp_rtcp_val(const char *s, int *rtp_val, int *rtcp_val, int minval) |
404 | 2.58k | { |
405 | 2.58k | int rval, rval_rtcp; |
406 | 2.58k | const char *rtcp_val_s; |
407 | | |
408 | 2.58k | if (atoi_safe(s, &rval) == ATOI_OK) { |
409 | 2.13k | rval_rtcp = rval; |
410 | 2.13k | goto check_range; |
411 | 2.13k | } |
412 | 448 | if (atoi_safe_sep(s, &rval, ',', &rtcp_val_s) != ATOI_OK) |
413 | 177 | return (ATOI_NOTINT); |
414 | 271 | if (atoi_safe(rtcp_val_s, &rval_rtcp) != ATOI_OK) |
415 | 136 | return (ATOI_NOTINT); |
416 | 2.26k | check_range: |
417 | 2.26k | if (rval < minval || rval_rtcp < minval) |
418 | 191 | return (ATOI_OUTRANGE); |
419 | 2.07k | *rtp_val = rval; |
420 | 2.07k | *rtcp_val = rval_rtcp; |
421 | 2.07k | return (ATOI_OK); |
422 | 2.26k | } |
423 | | |
424 | | enum atoi_rval |
425 | | strtol_saferange(const char *s, long *res, long min, long max, |
426 | | const char **next) |
427 | 0 | { |
428 | 0 | char *cp; |
429 | 0 | long rval; |
430 | |
|
431 | 0 | errno = 0; |
432 | 0 | rval = strtol(s, &cp, 10); |
433 | 0 | if (cp == s) { |
434 | 0 | return (ATOI_NOTINT); |
435 | 0 | } |
436 | 0 | if (errno == ERANGE) { |
437 | 0 | return (ATOI_OUTRANGE); |
438 | 0 | } |
439 | 0 | if (rval < min || (max >= min && rval > max)) { |
440 | 0 | return (ATOI_OUTRANGE); |
441 | 0 | } |
442 | 0 | if (next != NULL) { |
443 | 0 | *next = cp; |
444 | 0 | } |
445 | 0 | *res = rval; |
446 | 0 | return (ATOI_OK); |
447 | 0 | } |
448 | | |
449 | | #if defined(_SC_CLK_TCK) && !defined(__FreeBSD__) |
450 | | #if defined(LINUX_XXX) |
451 | | static int |
452 | | rtpp_get_sched_hz_linux(void) |
453 | 2 | { |
454 | 2 | int fd, rlen; |
455 | 2 | char buf[16], *cp; |
456 | 2 | int64_t n; |
457 | | |
458 | 2 | fd = open("/proc/sys/kernel/sched_min_granularity_ns", O_RDONLY, 0); |
459 | 2 | if (fd == -1) { |
460 | 0 | return (-1); |
461 | 0 | } |
462 | 2 | rlen = read(fd, buf, sizeof(buf) - 1); |
463 | 2 | close(fd); |
464 | 2 | if (rlen <= 0) { |
465 | 0 | return (-1); |
466 | 0 | } |
467 | 2 | buf[rlen] = '\0'; |
468 | 2 | n = strtol(buf, &cp, 10); |
469 | 2 | if (cp == buf) { |
470 | 0 | return (-1); |
471 | 0 | } |
472 | 2 | if (n <= 0) { |
473 | 0 | return (-1); |
474 | 0 | } |
475 | 2 | return ((int64_t)1000000000 / n); |
476 | 2 | } |
477 | | #endif |
478 | | |
479 | | int |
480 | | rtpp_get_sched_hz(void) |
481 | 2 | { |
482 | 2 | int sched_hz; |
483 | | |
484 | 2 | #if defined (LINUX_XXX) |
485 | 2 | sched_hz = rtpp_get_sched_hz_linux(); |
486 | 2 | if (sched_hz > 0) { |
487 | 2 | return (sched_hz); |
488 | 2 | } |
489 | 0 | #endif |
490 | 0 | sched_hz = sysconf(_SC_CLK_TCK); |
491 | 0 | return (sched_hz > 0 ? sched_hz : 100); |
492 | 2 | } |
493 | | #else |
494 | | int |
495 | | rtpp_get_sched_hz(void) |
496 | | { |
497 | | int sched_hz; |
498 | | size_t len; |
499 | | |
500 | | len = sizeof(sched_hz); |
501 | | if (sysctlbyname("kern.hz", &sched_hz, &len, NULL, 0) == -1 || sched_hz <= 0) |
502 | | return 1000; |
503 | | return (sched_hz); |
504 | | } |
505 | | #endif |
506 | | |
507 | | #ifndef HAVE_STRLCPY |
508 | | /* |
509 | | * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com> |
510 | | * All rights reserved. |
511 | | * |
512 | | * Redistribution and use in source and binary forms, with or without |
513 | | * modification, are permitted provided that the following conditions |
514 | | * are met: |
515 | | * 1. Redistributions of source code must retain the above copyright |
516 | | * notice, this list of conditions and the following disclaimer. |
517 | | * 2. Redistributions in binary form must reproduce the above copyright |
518 | | * notice, this list of conditions and the following disclaimer in the |
519 | | * documentation and/or other materials provided with the distribution. |
520 | | * 3. The name of the author may not be used to endorse or promote products |
521 | | * derived from this software without specific prior written permission. |
522 | | * |
523 | | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, |
524 | | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY |
525 | | * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL |
526 | | * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
527 | | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
528 | | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; |
529 | | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
530 | | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR |
531 | | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
532 | | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
533 | | */ |
534 | | |
535 | | /* |
536 | | * Copy src to string dst of size siz. At most siz-1 characters |
537 | | * will be copied. Always NUL terminates (unless siz == 0). |
538 | | * Returns strlen(src); if retval >= siz, truncation occurred. |
539 | | */ |
540 | | size_t strlcpy(char *dst, const char *src, size_t siz) |
541 | 33.0k | { |
542 | 33.0k | char *d = dst; |
543 | 33.0k | const char *s = src; |
544 | 33.0k | size_t n = siz; |
545 | | |
546 | | /* Copy as many bytes as will fit */ |
547 | 33.0k | if (n != 0 && --n != 0) { |
548 | 1.44M | do { |
549 | 1.44M | if ((*d++ = *s++) == 0) |
550 | 30.6k | break; |
551 | 1.44M | } while (--n != 0); |
552 | 32.0k | } |
553 | | |
554 | | /* Not enough room in dst, add NUL and traverse rest of src */ |
555 | 33.0k | if (n == 0) { |
556 | 2.40k | if (siz != 0) |
557 | 1.71k | *d = '\0'; /* NUL-terminate dst */ |
558 | 51.5k | while (*s++) |
559 | 49.1k | ; |
560 | 2.40k | } |
561 | | |
562 | 33.0k | return(s - src - 1); /* count does not include NUL */ |
563 | 33.0k | } |
564 | | |
565 | | #endif /* !HAVE_STRLCPY */ |
566 | | |
567 | 8.69M | #define populate(n, t) (~((t)0) / 255 * (n)) |
568 | 2.45M | #define haszero(v) ~(((((v) & populate(0x7f, typeof(v))) + populate(0x7f, typeof(v))) | \ |
569 | 2.45M | (v)) | populate(0x7f, typeof(v))) |
570 | | |
571 | | void |
572 | | rtpp_strsplit(char *ibuf, char *mbuf, size_t dlen, size_t blen) |
573 | 180k | { |
574 | 180k | const uint64_t sep_masks[4] = { |
575 | 180k | populate('\t', uint64_t), |
576 | 180k | populate('\n', uint64_t), |
577 | 180k | populate('\r', uint64_t), |
578 | 180k | populate(' ', uint64_t) |
579 | 180k | }; |
580 | | |
581 | 180k | RTPP_DBG_ASSERT(blen >= dlen && (blen % sizeof(uint64_t)) == 0); |
582 | | |
583 | 180k | uint64_t *cp = (uint64_t *)ibuf; |
584 | 180k | uint64_t *obp = (uint64_t *)mbuf; |
585 | | |
586 | 793k | for (int i = 0; i < dlen; i += sizeof(uint64_t)) { |
587 | 613k | uint64_t ww; |
588 | 613k | uint64_t ow = populate(0xff, uint64_t); |
589 | 613k | ww = *cp; |
590 | 3.06M | for (int j = 0; j < 4; j++) { |
591 | 2.45M | ow &= ~(haszero(ww ^ sep_masks[j]) / 0x80 * 0xff); |
592 | 2.45M | } |
593 | 613k | *obp = ow; |
594 | 613k | ww &= ow; |
595 | 613k | *cp = ww; |
596 | 613k | obp += 1; |
597 | 613k | cp += 1; |
598 | 613k | } |
599 | 180k | } |
600 | | |
601 | | void |
602 | | generate_random_string(char *buffer, int length) |
603 | 7.91k | { |
604 | 7.91k | const char charset[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" |
605 | 7.91k | "abcdefghijklmnopqrstuvwxyz" |
606 | 7.91k | "0123456789" |
607 | 7.91k | "+/"; |
608 | 7.91k | int charset_size = sizeof(charset) - 1; |
609 | | |
610 | 189k | for (int i = 0; i < length; i++) { |
611 | 181k | int key = random() % charset_size; |
612 | 181k | buffer[i] = charset[key]; |
613 | 181k | } |
614 | 7.91k | buffer[length] = '\0'; |
615 | 7.91k | } |