Coverage Report

Created: 2026-06-10 06:49

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}