Coverage Report

Created: 2026-01-09 06:08

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/rtpproxy/src/main.c
Line
Count
Source
1
/*
2
 * Copyright (c) 2004-2006 Maxim Sobolev <sobomax@FreeBSD.org>
3
 * Copyright (c) 2006-2007 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
#ifdef LINUX_XXX
30
/* Apparently needed for drand48(3) */
31
#define _SVID_SOURCE  1
32
/* Needed for the asprintf(3) */
33
#define _GNU_SOURCE 1
34
#endif
35
36
#include <sys/types.h>
37
#include <sys/resource.h>
38
#include <sys/socket.h>
39
#include <sys/stat.h>
40
#include <assert.h>
41
#include <fcntl.h>
42
#include <getopt.h>
43
#include <grp.h>
44
#include <limits.h>
45
#include <math.h>
46
#include <netdb.h>
47
#include <pthread.h>
48
#include <pwd.h>
49
#include <stdatomic.h>
50
#include <stdbool.h>
51
#include <stdio.h>
52
#include <stdint.h>
53
#include <stdlib.h>
54
#include <signal.h>
55
#include <string.h>
56
#include <syslog.h>
57
#include <unistd.h>
58
59
#include <elperiodic.h>
60
61
#include "config_pp.h"
62
63
#include "rtpp_types.h"
64
65
#if !defined(NO_ERR_H)
66
#include <err.h>
67
#include "rtpp_util.h"
68
#else
69
#include "rtpp_util.h"
70
#endif
71
72
#ifdef HAVE_SYSTEMD_DAEMON
73
#include <systemd/sd-daemon.h>
74
#endif
75
76
#include "rtpp_codeptr.h"
77
#include "rtpp_refcnt.h"
78
#include "rtpp_runcreds.h"
79
#include "rtpp_cfile.h"
80
#include "rtpp_log.h"
81
#include "rtpp_log_obj.h"
82
#include "rtpp_cfg.h"
83
#include "rtpp_defines.h"
84
#include "rtpp_command.h"
85
#include "rtpp_controlfd.h"
86
#include "rtpp_genuid.h"
87
#include "rtpp_hash_table.h"
88
#include "commands/rpcpv1_ver.h"
89
#include "rtpp_command_async.h"
90
#include "rtpp_command_ecodes.h"
91
#include "rtpp_port_table.h"
92
#include "rtpp_proc_async.h"
93
#include "rtpp_proc_servers.h"
94
#include "rtpp_proc_ttl.h"
95
#include "rtpp_bindaddrs.h"
96
#include "rtpp_network.h"
97
#include "rtpp_notify.h"
98
#include "rtpp_math.h"
99
#include "rtpp_mallocs.h"
100
#include "rtpp_list.h"
101
#if ENABLE_MODULE_IF
102
#include "rtpp_module_if.h"
103
#include "rtpp_modman.h"
104
#endif
105
#include "rtpp_stats.h"
106
#include "rtpp_sessinfo.h"
107
#include "rtpp_time.h"
108
#include "rtpp_timed.h"
109
#include "rtpp_timed_task.h"
110
#include "rtpp_tnotify_set.h"
111
#include "rtpp_weakref.h"
112
#include "rtpp_debug.h"
113
#include "rtpp_locking.h"
114
#include "rtpp_nofile.h"
115
#include "advanced/pproc_manager.h"
116
#include "ucl.h"
117
#include "rtpp_ucl.h"
118
#ifdef RTPP_CHECK_LEAKS
119
#include "libexecinfo/stacktraverse.h"
120
#include "libexecinfo/execinfo.h"
121
#include "rtpp_memdeb_internal.h"
122
#endif
123
#include "rtpp_stacktrace.h"
124
#if defined(LIBRTPPROXY)
125
#include "librtpproxy.h"
126
#include "librtpp_main.h"
127
#include "rtpp_module_if_static.h"
128
static const int is_lib = 1;
129
#else
130
static const int is_lib = 0;
131
#endif
132
133
#ifndef RTPP_DEBUG
134
# define RTPP_DEBUG 0
135
#else
136
# define RTPP_DEBUG 1
137
#endif
138
139
8
#define PRIO_UNSET (PRIO_MIN - 1)
140
141
static void usage(void);
142
143
#ifdef RTPP_CHECK_LEAKS
144
RTPP_MEMDEB_APP_STATIC;
145
#endif
146
147
static void
148
usage(void)
149
0
{
150
151
0
    fprintf(stderr, "usage:\trtpproxy [-2fvFiPaRbD] [-l addr1[/addr2]] "
152
0
      "[-6 addr1[/addr2]] [-s path]\n\t  [-t tos] [-r rdir [-S sdir]] [-T ttl] "
153
0
      "[-L nfiles] [-m port_min]\n\t  [-M port_max] [-u uname[:gname]] [-w sock_mode] "
154
0
      "[-n timeout_socket]\n\t  [-d log_level[:log_facility]] [-p pid_file]\n"
155
0
      "\t  [-c fifo|rr] [-A addr1[/addr2] [-W setup_ttl]\n"
156
0
      "\trtpproxy -V\n");
157
0
}
158
159
static struct rtpp_cfg *_sig_cf;
160
161
static void rtpp_exit(int, int) __attribute__ ((noreturn));
162
163
static void
164
rtpp_exit(int memdeb, int rval)
165
0
{
166
0
    int ecode;
167
168
0
    ecode = 0;
169
#ifdef RTPP_CHECK_LEAKS
170
    if (memdeb) {
171
        ecode = rtpp_memdeb_dumpstats(MEMDEB_SYM, 0) == 0 ? 0 : 1;
172
    }
173
#endif
174
0
    exit(rval == 0 ? ecode : rval);
175
0
}
176
177
#if !defined(LIBRTPPROXY)
178
static void
179
rtpp_glog_fin(void)
180
{
181
182
    RTPP_OBJ_DECREF(_sig_cf->glog);
183
#ifdef RTPP_CHECK_LEAKS
184
    RTPP_MEMDEB_FIN(rtpproxy);
185
#ifdef RTPP_MEMDEB_STDOUT
186
    fclose(stdout);
187
#endif
188
#endif
189
    rtpp_sys_free(_sig_cf);
190
}
191
#endif
192
193
static void
194
badsignal(int sig)
195
0
{
196
0
    static volatile sig_atomic_t in_handler = 0;
197
198
0
    signal(sig, SIG_DFL);
199
0
    if (!in_handler) {
200
0
        in_handler = 1;
201
202
0
        RTPP_LOG(_sig_cf->glog, RTPP_LOG_CRIT, "got BAD signal %d, fastshutdown = %d",
203
0
          sig, _sig_cf->fastshutdown);
204
0
    }
205
0
    raise(sig);
206
0
    _exit(128 + sig);
207
0
}
208
209
static void
210
fatsignal(int sig)
211
0
{
212
213
0
    RTPP_LOG(_sig_cf->glog, RTPP_LOG_INFO, "got signal %d", sig);
214
0
    if (_sig_cf->fastshutdown == 0) {
215
0
        _sig_cf->fastshutdown = 1;
216
0
        return;
217
0
    }
218
    /*
219
     * Got second signal while already in the fastshutdown mode, something
220
     * probably jammed, do quick exit right from sighandler, with an error
221
     * code.
222
     */
223
0
    rtpp_exit(1, 128 + sig);
224
0
}
225
226
static void
227
sighup(int sig)
228
0
{
229
230
0
    if (_sig_cf->slowshutdown == 0) {
231
0
        RTPP_LOG(_sig_cf->glog, RTPP_LOG_INFO,
232
0
          "got SIGHUP, initiating deorbiting-burn sequence");
233
0
    }
234
0
    _sig_cf->slowshutdown = 1;
235
0
}
236
237
#if !defined(LIBRTPPROXY)
238
static void
239
ehandler(void)
240
{
241
242
    RTPP_DBGCODE(catchtrace) {
243
        rtpp_stacktrace_print("Exiting from: ehandler()");
244
    }
245
    if (_sig_cf->ctrl_socks != NULL)
246
        rtpp_controlfd_cleanup(_sig_cf);
247
    unlink(_sig_cf->pid_file);
248
    RTPP_LOG(_sig_cf->glog, RTPP_LOG_INFO, "rtpproxy ended");
249
}
250
#endif
251
252
16
#define LOPT_DSO      256
253
0
#define LOPT_BRSYM    257
254
0
#define LOPT_NICE     258
255
0
#define LOPT_OVL_PROT 259
256
0
#define LOPT_CONFIG   260
257
0
#define LOPT_FORC_ASM 261
258
0
#define LOPT_NO_RESOL 262
259
0
#define LOPT_NO_REDIR 263
260
261
const static struct option longopts[] = {
262
    { "dso", required_argument, NULL, LOPT_DSO },
263
    { "bridge_symmetric", no_argument, NULL, LOPT_BRSYM },
264
    { "nice", required_argument, NULL, LOPT_NICE },
265
    { "overload_prot", optional_argument, NULL, LOPT_OVL_PROT },
266
    { "config", required_argument, NULL, LOPT_CONFIG },
267
    { "force_asymmetric", no_argument, NULL, LOPT_FORC_ASM },
268
    { "no_resolve", no_argument, NULL, LOPT_NO_RESOL },
269
    { "no_redirect", no_argument, NULL, LOPT_NO_REDIR },
270
    { NULL,  0,                 NULL, 0 }
271
};
272
273
#ifdef LIBRTPPROXY
274
0
#define IC_BAIL(c, r, m, mdb) do {  \
275
0
    init_config_bail(c, r, m, mdb); \
276
0
    return (-1);                    \
277
0
} while (0)
278
0
#define IC_ERR(code, fmt, ...) do { \
279
0
    warn(fmt, ##__VA_ARGS__);       \
280
0
    return -code;                   \
281
0
} while (0)
282
0
#define IC_ERRX(code, fmt, ...) do {\
283
0
    warnx(fmt, ##__VA_ARGS__);      \
284
0
    return -code;                   \
285
0
} while (0)
286
#else
287
#define IC_BAIL(c, r, m, mdb) do {  \
288
    init_config_bail(c, r, m, mdb); \
289
} while (0)
290
#define IC_ERR(code, fmt, ...) do { \
291
    err(code, fmt, ##__VA_ARGS__);  \
292
} while (0)
293
#define IC_ERRX(code, fmt, ...) do {\
294
    errx(code, fmt, ##__VA_ARGS__); \
295
} while (0)
296
#endif
297
298
static void
299
init_config_bail(struct rtpp_cfg *cfsp, int rval, const char *msg, int memdeb)
300
0
{
301
0
    struct rtpp_ctrl_sock *ctrl_sock, *ctrl_sock_next;
302
303
0
    if (msg != NULL) {
304
0
        RTPP_LOG(cfsp->glog, RTPP_LOG_ERR, "%s", msg);
305
0
    }
306
0
    CALL_METHOD(cfsp->bindaddrs_cf, dtor);
307
0
    free(cfsp->locks);
308
0
    CALL_METHOD(cfsp->rtpp_tnset_cf, dtor);
309
0
    CALL_METHOD(cfsp->nofile, dtor);
310
0
    RTPP_OBJ_DECREF(cfsp->sessions_wrt);
311
312
0
    for (ctrl_sock = RTPP_LIST_HEAD(cfsp->ctrl_socks);
313
0
      ctrl_sock != NULL; ctrl_sock = ctrl_sock_next) {
314
0
        ctrl_sock_next = RTPP_ITER_NEXT(ctrl_sock);
315
0
        free(ctrl_sock);
316
0
    }
317
0
    free(cfsp->ctrl_socks);
318
0
    free(cfsp->runcreds);
319
0
#if ENABLE_MODULE_IF
320
0
    RTPP_OBJ_DECREF(cfsp->modules_cf);
321
#else
322
    assert(cfsp->_pad == (void *)0x12345678);
323
    cfsp->_pad = (void *)((uintptr_t)cfsp->_pad ^ 0x87654321);
324
#endif
325
0
    RTPP_OBJ_DECREF(cfsp->guid);
326
#if !defined(LIBRTPPROXY)
327
    rtpp_exit(memdeb, rval);
328
#else
329
0
    rtpp_sys_free(cfsp);
330
0
#endif
331
0
}
332
333
static int
334
init_config(struct rtpp_cfg *cfsp, int argc, const char * const *argv)
335
4
{
336
4
    int ch, i, umode, stdio_mode;
337
4
    char *bh[2], *bh6[2], *cp;
338
4
    const char *errmsg;
339
4
    struct passwd *pp;
340
4
    struct group *gp;
341
4
    struct rtpp_ctrl_sock *ctrl_sock;
342
4
    int option_index, brsym;
343
4
    const struct proto_cap *pcp;
344
4
#if ENABLE_MODULE_IF
345
4
    struct rtpp_module_if *mif;
346
4
    char mpath[PATH_MAX + 1];
347
4
    struct rtpp_module_conf *mcp;
348
4
#endif
349
350
4
    bh[0] = bh[1] = bh6[0] = bh6[1] = NULL;
351
352
4
    umode = stdio_mode = 0;
353
354
4
    cfsp->pid_file = PID_FILE;
355
356
4
    cfsp->port_min = PORT_MIN;
357
4
    cfsp->port_max = PORT_MAX;
358
4
    cfsp->port_ctl = 0;
359
360
4
    cfsp->advaddr[0] = NULL;
361
4
    cfsp->advaddr[1] = NULL;
362
363
4
    cfsp->max_ttl = SESSION_TIMEOUT;
364
4
    cfsp->tos = TOS;
365
4
    cfsp->rrtcp = 1;
366
4
    cfsp->runcreds->sock_mode = 0;
367
4
    cfsp->ttl_mode = TTL_UNIFIED;
368
4
    cfsp->is_lib = is_lib;
369
4
    cfsp->log_level = -1;
370
4
    cfsp->log_facility = -1;
371
4
    cfsp->sched_hz = rtpp_get_sched_hz();
372
4
    cfsp->sched_policy = SCHED_OTHER;
373
4
    cfsp->sched_nice = PRIO_UNSET;
374
4
    cfsp->target_pfreq = MIN(POLL_RATE, cfsp->sched_hz);
375
4
    cfsp->slowshutdown = 0;
376
4
    cfsp->fastshutdown = 0;
377
4
#if defined(RTPP_DEBUG)
378
4
    cfsp->no_redirect = 1;
379
4
#endif
380
381
4
    cfsp->rtpp_tnset_cf = rtpp_tnotify_set_ctor();
382
4
    if (cfsp->rtpp_tnset_cf == NULL) {
383
0
        IC_ERR(1, "rtpp_tnotify_set_ctor");
384
0
    }
385
386
4
    cfsp->locks = malloc(sizeof(*cfsp->locks));
387
4
    if (cfsp->locks == NULL) {
388
0
        IC_ERR(1, "malloc(rtpp_cfg->locks)");
389
0
    }
390
4
    if (pthread_mutex_init(&(cfsp->locks->glob), NULL) != 0) {
391
0
        IC_ERRX(1, "pthread_mutex_init(rtpp_cfg->locks->glob)");
392
0
    }
393
4
    cfsp->bindaddrs_cf = rtpp_bindaddrs_ctor();
394
4
    if (cfsp->bindaddrs_cf == NULL) {
395
0
        IC_ERR(1, "malloc(rtpp_cfg->bindaddrs_cf)");
396
0
    }
397
398
4
    cfsp->nofile = rtpp_nofile_ctor();
399
4
    if (cfsp->nofile == NULL)
400
0
        IC_ERR(1, "malloc(rtpp_cfg->nofile)");
401
402
4
    cfsp->sessions_wrt = rtpp_weakref_ctor();
403
4
    if (cfsp->sessions_wrt == NULL) {
404
0
        IC_ERR(1, "can't allocate memory for the sessions weakref table");
405
         /* NOTREACHED */
406
0
    }
407
408
4
    option_index = -1;
409
4
    brsym = 0;
410
52
    while ((ch = getopt_long(argc, (char *const *)argv, "vf2Rl:6:s:S:t:r:p:T:L:m:M:u:Fin:Pad:"
411
52
      "Vc:A:w:bW:DC", longopts, &option_index)) != -1) {
412
48
  switch (ch) {
413
0
#if ENABLE_MODULE_IF
414
16
        case LOPT_DSO:
415
16
            cp = NULL;
416
16
#if defined(LIBRTPPROXY)
417
16
            if (rtpp_static_modules_lookup(optarg) != NULL) {
418
16
                cp = optarg;
419
16
            } else {
420
0
                IC_ERRX(1, "%s: static module is not compiled in", optarg);
421
0
            }
422
16
#endif
423
16
            if (cp == NULL)
424
0
                cp = realpath(optarg, mpath);
425
16
            if (cp == NULL) {
426
0
                 IC_ERR(1, "realpath: %s", optarg);
427
0
            }
428
16
            mif = rtpp_module_if_ctor(cp);
429
16
            if (mif == NULL) {
430
0
                IC_ERR(1, "%s: dymanic module constructor has failed", cp);
431
0
            }
432
16
            if (CALL_METHOD(mif, load, cfsp, cfsp->glog) != 0) {
433
0
                IC_ERRX(1, "%p: dymanic module load has failed", mif);
434
0
            }
435
16
            if (CALL_METHOD(mif, get_mconf, &mcp) != 0) {
436
0
                IC_ERRX(1, "%p->get_mconf() method has failed: %s", mif, cp);
437
0
            }
438
16
            if (mcp != NULL) {
439
0
                 RTPP_OBJ_DECREF(mcp);
440
0
                 IC_ERRX(1, "%s: dymanic module requires configuration, cannot be "
441
0
                   "loaded via --dso option", cp);
442
0
            }
443
16
            CALL_METHOD(cfsp->modules_cf, insert, mif);
444
#else
445
            IC_ERRX(1, "%s: dymanic module support is not compiled in", cp);
446
#endif
447
16
            break;
448
449
0
        case LOPT_BRSYM:
450
0
            brsym = 1;
451
0
            break;
452
453
0
        case LOPT_NICE:
454
0
            switch (atoi_saferange(optarg, &cfsp->sched_nice, PRIO_MIN, PRIO_MAX)) {
455
0
            case ATOI_OK:
456
0
                break;
457
0
            case ATOI_OUTRANGE:
458
0
                IC_ERRX(1, "%s: nice level is out of range %d..%d", optarg,
459
0
                  PRIO_MIN, PRIO_MAX);
460
0
            default:
461
0
                IC_ERRX(1, "%s: nice level argument is invalid", optarg);
462
0
            }
463
0
            break;
464
465
0
        case LOPT_OVL_PROT:
466
0
            cfsp->overload_prot.low_trs = 0.85;
467
0
            cfsp->overload_prot.high_trs = 0.90;
468
0
            cfsp->overload_prot.ecode = ECODE_OVERLOAD;
469
0
            break;
470
471
0
        case LOPT_CONFIG:
472
0
            cfsp->cfile = optarg;
473
0
            break;
474
475
0
        case LOPT_FORC_ASM:
476
0
            cfsp->aforce = 1;
477
0
            break;
478
479
0
        case LOPT_NO_RESOL:
480
0
            cfsp->no_resolve = 1;
481
0
            break;
482
483
0
        case LOPT_NO_REDIR:
484
0
            cfsp->no_redirect = 1;
485
0
            break;
486
487
0
        case 'c':
488
0
            if (strcmp(optarg, "fifo") == 0) {
489
0
                 cfsp->sched_policy = SCHED_FIFO;
490
0
                 break;
491
0
            }
492
0
            if (strcmp(optarg, "rr") == 0) {
493
0
                 cfsp->sched_policy = SCHED_RR;
494
0
                 break;
495
0
            }
496
0
            IC_ERRX(1, "%s: unknown scheduling policy", optarg);
497
0
            break;
498
499
4
  case 'f':
500
4
      cfsp->ropts.no_daemon = 1;
501
4
      break;
502
503
0
  case 'l':
504
0
      bh[0] = optarg;
505
0
      bh[1] = strchr(bh[0], '/');
506
0
      if (bh[1] != NULL) {
507
0
    *bh[1] = '\0';
508
0
    bh[1]++;
509
0
    cfsp->bmode = 1;
510
    /*
511
     * Historically, in bridge mode all clients are assumed to
512
     * be asymmetric
513
     */
514
0
    cfsp->aforce = 1;
515
0
      }
516
0
      break;
517
518
0
  case '6':
519
0
      bh6[0] = optarg;
520
0
      bh6[1] = strchr(bh6[0], '/');
521
0
      if (bh6[1] != NULL) {
522
0
    *bh6[1] = '\0';
523
0
    bh6[1]++;
524
0
    cfsp->bmode = 1;
525
0
    cfsp->aforce = 1;
526
0
      }
527
0
      break;
528
529
0
    case 'A':
530
0
        if (*optarg == '\0') {
531
0
            IC_ERRX(1, "first advertised address is invalid");
532
0
        }
533
0
        cfsp->advaddr[0] = optarg;
534
0
        cp = strchr(optarg, '/');
535
0
        if (cp != NULL) {
536
0
            *cp = '\0';
537
0
            cp++;
538
0
            if (*cp == '\0') {
539
0
                IC_ERRX(1, "second advertised address is invalid");
540
0
            }
541
0
        }
542
0
        cfsp->advaddr[1] = cp;
543
0
        break;
544
545
4
  case 's':
546
4
            ctrl_sock = rtpp_ctrl_sock_parse(optarg, is_lib);
547
4
            if (ctrl_sock == NULL) {
548
0
                IC_ERRX(1, "can't parse control socket argument");
549
0
            }
550
4
            rtpp_list_append(cfsp->ctrl_socks, ctrl_sock);
551
4
            if (RTPP_CTRL_ISDG(ctrl_sock)) {
552
0
                umode = 1;
553
4
            } else if (ctrl_sock->type == RTPC_STDIO) {
554
0
                stdio_mode = 1;
555
0
            }
556
4
      break;
557
558
0
  case 't':
559
0
            switch (atoi_saferange(optarg, &cfsp->tos, 0, 255)) {
560
0
            case ATOI_OK:
561
0
                break;
562
0
            case ATOI_OUTRANGE:
563
0
                IC_ERRX(1, "%s: TOS is too small/large", optarg);
564
0
            default:
565
0
                IC_ERRX(1, "%s: TOS argument is invalid", optarg);
566
0
      }
567
0
            break;
568
569
0
  case '2':
570
0
      cfsp->dmode = 1;
571
0
      break;
572
573
0
  case 'v':
574
0
      printf("Basic version: %d\n", CPROTOVER);
575
0
      for (pcp = iterate_proto_caps(NULL); pcp != NULL; pcp = iterate_proto_caps(pcp)) {
576
0
    printf("Extension %s: %s\n", pcp->pc_id, pcp->pc_description);
577
0
      }
578
0
      IC_BAIL(cfsp, 0, NULL, 0);
579
0
      break;
580
581
4
  case 'r':
582
4
      cfsp->rdir = optarg;
583
4
      break;
584
585
4
  case 'S':
586
4
      cfsp->sdir = optarg;
587
4
      break;
588
589
0
  case 'R':
590
0
      cfsp->rrtcp = 0;
591
0
      break;
592
593
0
  case 'p':
594
0
      cfsp->pid_file = optarg;
595
0
      break;
596
597
4
  case 'T':
598
4
      if (atoi_saferange(optarg, &cfsp->max_ttl, 1, -1))
599
0
                IC_ERRX(1, "%s: max TTL argument is invalid", optarg);
600
4
      break;
601
602
4
  case 'L': {
603
0
            int rlim_max_opt;
604
605
0
            if (atoi_saferange(optarg, &rlim_max_opt, 0, -1))
606
0
                IC_ERRX(1, "%s: max file rlimit argument is invalid", optarg);
607
0
      cfsp->nofile->limit->rlim_cur = rlim_max_opt;
608
0
      cfsp->nofile->limit->rlim_max = rlim_max_opt;
609
0
      if (setrlimit(RLIMIT_NOFILE, cfsp->nofile->limit) != 0)
610
0
    IC_ERR(1, "setrlimit");
611
0
      if (getrlimit(RLIMIT_NOFILE, cfsp->nofile->limit) != 0)
612
0
    IC_ERR(1, "getrlimit");
613
0
      if (cfsp->nofile->limit->rlim_max < rlim_max_opt)
614
0
    warnx("limit allocated by setrlimit (%d) is less than "
615
0
      "requested (%d)", (int) cfsp->nofile->limit->rlim_max,
616
0
      rlim_max_opt);
617
0
      break;
618
0
            }
619
620
0
  case 'm':
621
0
      switch (atoi_saferange(optarg, &cfsp->port_min, 1, 65535)) {
622
0
            case ATOI_OK:
623
0
                break;
624
0
            case ATOI_OUTRANGE:
625
0
                IC_ERRX(1, "invalid value of the port_min argument, "
626
0
                  "not in the range 1-65535");
627
0
            default:
628
0
                IC_ERRX(1, "%s: min port argument is invalid", optarg);
629
0
            }
630
0
      break;
631
632
0
  case 'M':
633
0
      switch (atoi_saferange(optarg, &cfsp->port_max, 1, 65535)) {
634
0
            case ATOI_OK:
635
0
                break;
636
0
            case ATOI_OUTRANGE:
637
0
                IC_ERRX(1, "invalid value of the port_max argument, "
638
0
                  "not in the range 1-65535");
639
0
            default:
640
0
                IC_ERRX(1, "%s: max port argument is invalid", optarg);
641
0
            }
642
0
      break;
643
644
0
  case 'u':
645
0
      cfsp->runcreds->uname = optarg;
646
0
      cp = strchr(optarg, ':');
647
0
      if (cp != NULL) {
648
0
    if (cp == optarg)
649
0
        cfsp->runcreds->uname = NULL;
650
0
    cp[0] = '\0';
651
0
    cp++;
652
0
      }
653
0
      cfsp->runcreds->gname = cp;
654
0
      cfsp->runcreds->uid = -1;
655
0
      cfsp->runcreds->gid = -1;
656
0
      if (cfsp->runcreds->uname != NULL) {
657
0
    pp = getpwnam(cfsp->runcreds->uname);
658
0
    if (pp == NULL)
659
0
        IC_ERRX(1, "can't find ID for the user: %s", cfsp->runcreds->uname);
660
0
    cfsp->runcreds->uid = pp->pw_uid;
661
0
    if (cfsp->runcreds->gname == NULL)
662
0
        cfsp->runcreds->gid = pp->pw_gid;
663
0
      }
664
0
      if (cfsp->runcreds->gname != NULL) {
665
0
    gp = getgrnam(cfsp->runcreds->gname);
666
0
    if (gp == NULL)
667
0
        IC_ERRX(1, "can't find ID for the group: %s", cfsp->runcreds->gname);
668
0
    cfsp->runcreds->gid = gp->gr_gid;
669
0
                if (cfsp->runcreds->sock_mode == 0) {
670
0
                    cfsp->runcreds->sock_mode = 0755;
671
0
                }
672
0
      }
673
0
      break;
674
675
0
  case 'w': {
676
0
            int sock_mode;
677
678
0
      if (atoi_saferange(optarg, &sock_mode, 0, 4095))
679
0
                IC_ERRX(1, "%s: socket mode argument is invalid", optarg);
680
0
            cfsp->runcreds->sock_mode = sock_mode;
681
0
      break;
682
0
            }
683
684
0
  case 'F':
685
0
      cfsp->no_check = 1;
686
0
      break;
687
688
0
  case 'i':
689
0
      cfsp->ttl_mode = TTL_INDEPENDENT;
690
0
      break;
691
692
4
  case 'n':
693
4
      if(strlen(optarg) == 0)
694
0
    IC_ERRX(1, "timeout notification socket name too short");
695
4
            if (CALL_METHOD(cfsp->rtpp_tnset_cf, append, optarg, is_lib,
696
4
              &errmsg) != 0) {
697
0
                IC_ERRX(1, "error adding timeout notification: %s", errmsg);
698
0
            }
699
4
      break;
700
701
4
  case 'P':
702
0
      cfsp->record_pcap = 1;
703
0
      break;
704
705
0
  case 'a':
706
0
      cfsp->record_all = 1;
707
0
      break;
708
709
4
  case 'd':
710
4
      cp = strchr(optarg, ':');
711
4
      if (cp != NULL) {
712
0
    cfsp->log_facility = rtpp_log_str2fac(cp + 1);
713
0
    if (cfsp->log_facility == -1)
714
0
        IC_ERRX(1, "%s: invalid log facility", cp + 1);
715
0
    *cp = '\0';
716
0
      }
717
4
      cfsp->log_level = rtpp_log_str2lvl(optarg);
718
4
      if (cfsp->log_level == -1)
719
0
    IC_ERRX(1, "%s: invalid log level", optarg);
720
4
            CALL_METHOD(cfsp->glog, setlevel, cfsp->log_level);
721
4
      break;
722
723
0
  case 'V':
724
0
      printf("%s\n", RTPP_SW_VERSION);
725
0
      IC_BAIL(cfsp, 0, NULL, 0);
726
0
      break;
727
728
4
        case 'W':
729
4
            if (atoi_saferange(optarg, &cfsp->max_setup_ttl, 1, -1))
730
0
                IC_ERRX(1, "%s: max setup TTL argument is invalid", optarg);
731
4
            break;
732
733
4
        case 'b':
734
0
            cfsp->seq_ports = 1;
735
0
            break;
736
737
0
        case 'D':
738
0
      cfsp->ropts.no_chdir = 1;
739
0
      break;
740
741
0
        case 'C':
742
0
      printf("%s\n", get_mclock_name());
743
0
      IC_BAIL(cfsp, 0, NULL, 0);
744
0
      break;
745
746
0
  case '?':
747
0
  default:
748
0
      usage();
749
0
      return(-1);
750
48
  }
751
48
    }
752
753
4
    if (optind != argc) {
754
0
       warnx("%d extra unhandled argument%s at the end of the command line",
755
0
         argc - optind, (argc - optind) > 1 ? "s" : "");
756
0
       usage();
757
0
       return(-1);
758
0
    }
759
760
4
    if (cfsp->cfile != NULL) {
761
0
        if (rtpp_cfile_process(cfsp) < 0) {
762
0
            IC_BAIL(cfsp, 1, "rtpp_cfile_process() failed", 1);
763
0
        }
764
0
    }
765
766
4
    if (cfsp->bmode != 0 && brsym != 0) {
767
0
        cfsp->aforce = 0;
768
0
    }
769
770
4
    if (cfsp->max_setup_ttl == 0) {
771
0
        cfsp->max_setup_ttl = cfsp->max_ttl;
772
0
    }
773
774
    /* No control socket has been specified, add a default one */
775
4
    if (RTPP_LIST_IS_EMPTY(cfsp->ctrl_socks)) {
776
0
        ctrl_sock = rtpp_ctrl_sock_parse(CMD_SOCK, is_lib);
777
0
        if (ctrl_sock == NULL) {
778
0
            IC_ERRX(1, "can't parse control socket: \"%s\"", CMD_SOCK);
779
0
        }
780
0
        rtpp_list_append(cfsp->ctrl_socks, ctrl_sock);
781
0
    }
782
783
4
    if (cfsp->rdir == NULL && cfsp->sdir != NULL)
784
0
  IC_ERRX(1, "-S switch requires -r switch");
785
786
4
    if (cfsp->ropts.no_daemon == 0 && stdio_mode != 0)
787
0
        IC_ERRX(1, "stdio command mode requires -f switch");
788
789
4
    if (cfsp->no_check == 0 && getuid() == 0 && cfsp->runcreds->uname == NULL) {
790
4
  if (umode != 0) {
791
0
      IC_ERRX(1, "running this program as superuser in a remote control "
792
0
        "mode is strongly not recommended, as it poses serious security "
793
0
        "threat to your system. Use -u option to run as an unprivileged "
794
0
        "user or -F is you want to run as a superuser anyway.");
795
4
  } else {
796
4
      warnx("WARNING!!! Running this program as superuser is strongly "
797
4
        "not recommended, as it may pose serious security threat to "
798
4
        "your system. Use -u option to run as an unprivileged user "
799
4
        "or -F to surpress this warning.");
800
4
  }
801
4
    }
802
803
    /* make sure that port_min and port_max are even */
804
4
    if ((cfsp->port_min % 2) != 0)
805
0
  cfsp->port_min++;
806
4
    if ((cfsp->port_max % 2) != 0) {
807
0
  cfsp->port_max--;
808
4
    } else {
809
  /*
810
   * If port_max is already even then there is no
811
   * "room" for the RTCP port, go back by two ports.
812
   */
813
4
  cfsp->port_max -= 2;
814
4
    }
815
816
4
    if (cfsp->port_min > cfsp->port_max)
817
0
  IC_ERRX(1, "port_min should be less than port_max");
818
819
4
    if (bh[0] == NULL && bh[1] == NULL && bh6[0] == NULL && bh6[1] == NULL) {
820
4
  bh[0] = "*";
821
4
    }
822
823
12
    for (i = 0; i < 2; i++) {
824
8
  if (bh[i] != NULL && *bh[i] == '\0')
825
0
      bh[i] = NULL;
826
8
  if (bh6[i] != NULL && *bh6[i] == '\0')
827
0
      bh6[i] = NULL;
828
8
    }
829
830
4
    i = ((bh[0] == NULL) ? 0 : 1) + ((bh[1] == NULL) ? 0 : 1) +
831
4
      ((bh6[0] == NULL) ? 0 : 1) + ((bh6[1] == NULL) ? 0 : 1);
832
4
    if (cfsp->bmode != 0) {
833
0
  if (bh[0] != NULL && bh6[0] != NULL)
834
0
      IC_ERRX(1, "either IPv4 or IPv6 should be configured for external "
835
0
        "interface in bridging mode, not both");
836
0
  if (bh[1] != NULL && bh6[1] != NULL)
837
0
      IC_ERRX(1, "either IPv4 or IPv6 should be configured for internal "
838
0
        "interface in bridging mode, not both");
839
0
        if (cfsp->advaddr[0] != NULL && cfsp->advaddr[1] == NULL)
840
0
            IC_ERRX(1, "two advertised addresses are required for internal "
841
0
              "and external interfaces in bridging mode");
842
0
  if (i != 2)
843
0
      IC_ERRX(1, "incomplete configuration of the bridging mode - exactly "
844
0
        "2 listen addresses required, %d provided", i);
845
4
    } else if (i != 1) {
846
0
  IC_ERRX(1, "exactly 1 listen addresses required, %d provided", i);
847
0
    }
848
849
12
    for (i = 0; i < 2; i++) {
850
8
  int rmode = AI_ADDRCONFIG | AI_PASSIVE;
851
8
  rmode |= cfsp->no_resolve ? AI_NUMERICHOST : 0;
852
8
  cfsp->bindaddr[i] = NULL;
853
8
  if (bh[i] != NULL) {
854
4
      cfsp->bindaddr[i] = CALL_METHOD(cfsp->bindaddrs_cf,
855
4
              host2, bh[i], AF_INET, rmode, &errmsg);
856
4
      if (cfsp->bindaddr[i] == NULL)
857
0
    IC_ERRX(1, "host2bindaddr(%s): %s", bh[i], errmsg);
858
4
      continue;
859
4
  }
860
4
  if (bh6[i] != NULL) {
861
0
      cfsp->bindaddr[i] = CALL_METHOD(cfsp->bindaddrs_cf,
862
0
              host2, bh6[i], AF_INET6, rmode, &errmsg);
863
0
      if (cfsp->bindaddr[i] == NULL)
864
0
    IC_ERRX(1, "host2bindaddr(%s): %s", bh6[i], errmsg);
865
0
      continue;
866
0
  }
867
4
    }
868
4
    if (cfsp->bindaddr[0] == NULL) {
869
0
  cfsp->bindaddr[0] = cfsp->bindaddr[1];
870
0
  cfsp->bindaddr[1] = NULL;
871
0
    }
872
4
    return 0;
873
4
}
874
875
static enum rtpp_timed_cb_rvals
876
update_derived_stats(double dtime, void *argp)
877
18
{
878
18
    struct rtpp_stats *rtpp_stats;
879
880
18
    rtpp_stats = (struct rtpp_stats *)argp;
881
18
    CALL_SMETHOD(rtpp_stats, update_derived, dtime);
882
18
    return (CB_MORE);
883
18
}
884
885
#if !defined(LIBRTPPROXY)
886
static void
887
#else
888
void
889
#endif
890
rtpp_shutdown(struct rtpp_cfg *cfsp)
891
4
{
892
4
    struct rtpp_ctrl_sock *ctrl_sock, *ctrl_sock_next;
893
894
4
    CALL_METHOD(cfsp->rtpp_cmd_cf, dtor);
895
4
    CALL_SMETHOD(cfsp->sessions_wrt, purge);
896
4
    CALL_SMETHOD(cfsp->sessions_ht, purge);
897
898
4
    while ((CALL_SMETHOD(cfsp->rtp_streams_wrt, get_length) > 0) ||
899
4
      (CALL_SMETHOD(cfsp->rtcp_streams_wrt, get_length) > 0))
900
0
        continue;
901
902
4
#if ENABLE_MODULE_IF
903
4
    RTPP_OBJ_DECREF(cfsp->modules_cf);
904
#else
905
    assert(cfsp->_pad == (void *)0x12345678);
906
    cfsp->_pad = (void *)((uintptr_t)cfsp->_pad ^ 0x87654321);
907
#endif
908
4
    RTPP_OBJ_DECREF(cfsp->pproc_manager);
909
4
    free(cfsp->runcreds);
910
4
    RTPP_OBJ_DECREF(cfsp->rtpp_notify_cf);
911
4
    CALL_METHOD(cfsp->bindaddrs_cf, dtor);
912
4
    free(cfsp->locks);
913
4
    CALL_METHOD(cfsp->rtpp_tnset_cf, dtor);
914
4
    CALL_SMETHOD(cfsp->rtpp_timed_cf, shutdown);
915
4
    RTPP_OBJ_DECREF(cfsp->rtpp_timed_cf);
916
4
    CALL_METHOD(cfsp->rtpp_proc_ttl_cf, dtor);
917
4
    RTPP_OBJ_DECREF(cfsp->proc_servers);
918
4
    RTPP_OBJ_DECREF(cfsp->rtpp_proc_cf);
919
4
    RTPP_OBJ_DECREF(cfsp->sessinfo);
920
4
    RTPP_OBJ_DECREF(cfsp->rtpp_stats);
921
12
    for (int i = 0; i <= RTPP_PT_MAX; i++) {
922
8
        RTPP_OBJ_DECREF(cfsp->port_table[i]);
923
8
    }
924
4
    RTPP_OBJ_DECREF(cfsp->sessions_wrt);
925
4
    RTPP_OBJ_DECREF(cfsp->sessions_ht);
926
4
    RTPP_OBJ_DECREF(cfsp->rtp_streams_wrt);
927
4
    RTPP_OBJ_DECREF(cfsp->rtcp_streams_wrt);
928
4
    CALL_METHOD(cfsp->nofile, dtor);
929
4
    rtpp_controlfd_cleanup(cfsp);
930
4
    for (ctrl_sock = RTPP_LIST_HEAD(cfsp->ctrl_socks);
931
8
      ctrl_sock != NULL; ctrl_sock = ctrl_sock_next) {
932
4
        ctrl_sock_next = RTPP_ITER_NEXT(ctrl_sock);
933
4
        free(ctrl_sock);
934
4
    }
935
4
    free(cfsp->ctrl_socks);
936
4
    cfsp->ctrl_socks = NULL;
937
4
    RTPP_OBJ_DECREF(cfsp->guid);
938
4
#if defined(LIBRTPPROXY)
939
4
    RTPP_OBJ_DECREF(cfsp->glog);
940
4
#endif
941
4
}
942
943
#ifdef LIBRTPPROXY
944
0
#define MAIN_ERR(code, fmt, ...) do { \
945
0
    warn(fmt, ##__VA_ARGS__);         \
946
0
    return NULL;                      \
947
0
} while (0)
948
0
#define MAIN_ERRX(code, fmt, ...) do {\
949
0
    warnx(fmt, ##__VA_ARGS__);        \
950
0
    return NULL;                      \
951
0
} while (0)
952
0
#define MAIN_EXIT(code)          do { \
953
0
    return NULL;                      \
954
0
} while (0)
955
#else
956
#define MAIN_ERR(code, fmt, ...) do { \
957
    err(code, fmt, ##__VA_ARGS__);    \
958
} while (0)
959
#define MAIN_ERRX(code, fmt, ...) do {\
960
    errx(code, fmt, ##__VA_ARGS__);   \
961
} while (0)
962
#define MAIN_EXIT(code)          do { \
963
    exit(code);                       \
964
} while (0)
965
#endif
966
967
#if !defined(LIBRTPPROXY)
968
int
969
main(int argc, const char * const *argv)
970
#else
971
struct rtpp_cfg *
972
_rtpp_main(int argc, const char * const *argv)
973
#endif
974
4
{
975
4
    int i, len, pid_fd;
976
4
    struct rtpp_cfg *cfsp;
977
4
    char buf[256];
978
4
    struct sched_param sparam;
979
4
    void *elp;
980
4
    struct rtpp_timed_task *tp;
981
4
    struct rtpp_daemon_rope drop;
982
983
4
    cfsp = rtpp_sys_malloc(sizeof(*cfsp));
984
4
    if (cfsp == NULL)
985
0
        MAIN_ERR(1, "allocating struct rtpp_cfg failed");
986
4
    memset(cfsp, '\0', sizeof(*cfsp));
987
988
4
#if defined(LIBRTPPROXY)
989
4
    cfsp->ropts = (struct rtpp_run_options){
990
4
        .no_pid = 1, .no_chdir = 1, .no_daemon = 1, .no_sigtrap = 1
991
4
    };
992
4
#endif
993
994
#ifdef RTPP_CHECK_LEAKS
995
    RTPP_MEMDEB_APP_INIT();
996
#endif
997
4
    if (getdtime() == -1) {
998
0
        MAIN_ERR(1, "timer self-test has failed: please check your build configuration");
999
        /* NOTREACHED */
1000
0
    }
1001
1002
#ifdef RTPP_CHECK_LEAKS
1003
    if (rtpp_memdeb_selftest(MEMDEB_SYM) != 0) {
1004
        MAIN_ERRX(1, "MEMDEB self-test has failed");
1005
        /* NOTREACHED */
1006
    }
1007
#endif
1008
1009
4
    cfsp->ctrl_socks = rtpp_zmalloc(sizeof(struct rtpp_list));
1010
4
    if (cfsp->ctrl_socks == NULL) {
1011
0
         MAIN_ERR(1, "can't allocate memory for the struct ctrl_socks");
1012
         /* NOTREACHED */
1013
0
    }
1014
1015
4
#if ENABLE_MODULE_IF
1016
4
    cfsp->modules_cf = rtpp_modman_ctor();
1017
4
    if (cfsp->modules_cf == NULL) {
1018
0
         MAIN_ERR(1, "can't allocate memory for the struct modules_cf");
1019
         /* NOTREACHED */
1020
0
    }
1021
#else
1022
    cfsp->_pad = (void *)0x12345678;
1023
#endif
1024
1025
4
    cfsp->runcreds = rtpp_zmalloc(sizeof(struct rtpp_runcreds));
1026
4
    if (cfsp->runcreds == NULL) {
1027
0
         MAIN_ERR(1, "can't allocate memory for the struct runcreds");
1028
         /* NOTREACHED */
1029
0
    }
1030
1031
4
    seedrandom();
1032
4
    cfsp->guid = rtpp_genuid_ctor();
1033
4
    if (cfsp->guid == NULL) {
1034
0
        MAIN_ERR(1, "rtpp_genuid_ctor() failed");
1035
        /* NOTREACHED */
1036
0
    }
1037
1038
4
    cfsp->glog = rtpp_log_ctor("rtpproxy", NULL, LF_REOPEN);
1039
4
    if (cfsp->glog == NULL) {
1040
0
        MAIN_ERR(1, "can't initialize logging subsystem");
1041
        /* NOTREACHED */
1042
0
    }
1043
4
    CALL_METHOD(cfsp->glog, setlevel, RTPP_LOG_ERR);
1044
 #ifdef RTPP_CHECK_LEAKS
1045
    rtpp_memdeb_setlog(MEMDEB_SYM, cfsp->glog);
1046
    rtpp_memdeb_approve(MEMDEB_SYM, "_rtpp_log_open", 1, "Referenced by memdeb itself");
1047
 #endif
1048
1049
#if !defined(LIBRTPPROXY)
1050
    _sig_cf = cfsp;
1051
    atexit(rtpp_glog_fin);
1052
#endif
1053
1054
4
    int r = init_config(cfsp, argc, argv);
1055
4
    if (r < 0) {
1056
0
        MAIN_EXIT(-r);
1057
0
    }
1058
1059
4
    cfsp->sessions_ht = rtpp_hash_table_ctor(rtpp_ht_key_str_t, 0);
1060
4
    if (cfsp->sessions_ht == NULL) {
1061
0
        MAIN_ERR(1, "can't allocate memory for the hash table");
1062
         /* NOTREACHED */
1063
0
    }
1064
4
    cfsp->rtp_streams_wrt = rtpp_weakref_ctor();
1065
4
    if (cfsp->rtp_streams_wrt == NULL) {
1066
0
        MAIN_ERR(1, "can't allocate memory for the RTP streams weakref table");
1067
         /* NOTREACHED */
1068
0
    }
1069
4
    cfsp->rtcp_streams_wrt = rtpp_weakref_ctor();
1070
4
    if (cfsp->rtcp_streams_wrt == NULL) {
1071
0
        MAIN_ERR(1, "can't allocate memory for the RTCP streams weakref table");
1072
         /* NOTREACHED */
1073
0
    }
1074
4
    cfsp->sessinfo = rtpp_sessinfo_ctor(cfsp);
1075
4
    if (cfsp->sessinfo == NULL) {
1076
0
        MAIN_ERRX(1, "cannot construct rtpp_sessinfo structure");
1077
0
    }
1078
1079
4
    cfsp->rtpp_stats = rtpp_stats_ctor();
1080
4
    if (cfsp->rtpp_stats == NULL) {
1081
0
        MAIN_ERR(1, "can't allocate memory for the stats data");
1082
         /* NOTREACHED */
1083
0
    }
1084
1085
12
    for (i = 0; i <= RTPP_PT_MAX; i++) {
1086
8
        cfsp->port_table[i] = rtpp_port_table_ctor(cfsp->port_min,
1087
8
          cfsp->port_max, cfsp->seq_ports, cfsp->port_ctl);
1088
8
        if (cfsp->port_table[i] == NULL) {
1089
0
            MAIN_ERR(1, "can't allocate memory for the ports data");
1090
            /* NOTREACHED */
1091
0
        }
1092
8
    }
1093
1094
4
    if (rtpp_controlfd_init(cfsp) != 0) {
1095
0
        MAIN_ERR(1, "can't initialize control socket%s",
1096
0
          cfsp->ctrl_socks->len > 1 ? "s" : "");
1097
0
    }
1098
1099
4
    if (cfsp->ropts.no_daemon == 0) {
1100
0
        if (cfsp->ropts.no_chdir == 0) {
1101
0
            cfsp->cwd_orig = getcwd(NULL, 0);
1102
0
            if (cfsp->cwd_orig == NULL) {
1103
0
                MAIN_ERR(1, "getcwd");
1104
0
            }
1105
0
        }
1106
0
  drop = rtpp_daemon(cfsp->ropts.no_chdir, 0, cfsp->no_redirect);
1107
0
  if (drop.result == -1)
1108
0
      MAIN_ERR(1, "can't switch into daemon mode");
1109
      /* NOTREACHED */
1110
0
    }
1111
1112
4
    if (CALL_METHOD(cfsp->glog, start, cfsp) != 0) {
1113
        /* We cannot possibly function with broken logs, bail out */
1114
0
        syslog(LOG_CRIT, "rtpproxy pid %d has failed to initialize logging"
1115
0
            " facilities: crash", getpid());
1116
0
        MAIN_ERR(1, "rtpproxy has failed to initialize logging facilities");
1117
0
    }
1118
1119
#if !defined(LIBRTPPROXY)
1120
    atexit(ehandler);
1121
#endif
1122
4
    RTPP_LOG(cfsp->glog, RTPP_LOG_INFO, "rtpproxy started, pid %d", getpid());
1123
1124
4
    if (cfsp->sched_policy != SCHED_OTHER) {
1125
0
        sparam.sched_priority = sched_get_priority_max(cfsp->sched_policy);
1126
0
        if (sched_setscheduler(0, cfsp->sched_policy, &sparam) == -1) {
1127
0
            RTPP_ELOG(cfsp->glog, RTPP_LOG_ERR, "sched_setscheduler(SCHED_%s, %d)",
1128
0
              (cfsp->sched_policy == SCHED_FIFO) ? "FIFO" : "RR", sparam.sched_priority);
1129
0
        }
1130
0
    }
1131
4
    if (cfsp->sched_nice != PRIO_UNSET) {
1132
0
        if (setpriority(PRIO_PROCESS, 0, cfsp->sched_nice) == -1) {
1133
0
            RTPP_ELOG(cfsp->glog, RTPP_LOG_ERR, "can't set scheduling "
1134
0
              "priority to %d", cfsp->sched_nice);
1135
0
            MAIN_EXIT(1);
1136
0
        }
1137
0
    }
1138
1139
4
    if (cfsp->ropts.no_pid == 0) {
1140
0
        pid_fd = open(cfsp->pid_file, O_WRONLY | O_CREAT, DEFFILEMODE);
1141
0
        if (pid_fd < 0) {
1142
0
            RTPP_ELOG(cfsp->glog, RTPP_LOG_ERR, "can't open pidfile for writing");
1143
0
        }
1144
4
    } else {
1145
4
        pid_fd = -1;
1146
4
    }
1147
1148
4
    if (cfsp->runcreds->uname != NULL || cfsp->runcreds->gname != NULL) {
1149
0
  if (drop_privileges(cfsp) != 0) {
1150
0
      RTPP_ELOG(cfsp->glog, RTPP_LOG_ERR,
1151
0
        "can't switch to requested user/group");
1152
0
      MAIN_EXIT(1);
1153
0
  }
1154
0
    }
1155
4
    set_rlimits(cfsp);
1156
1157
4
    cfsp->pproc_manager = pproc_manager_ctor(cfsp->rtpp_stats, 0);
1158
4
    if (cfsp->pproc_manager == NULL) {
1159
0
        RTPP_LOG(cfsp->glog, RTPP_LOG_ERR,
1160
0
          "can't init packet prosessing subsystem");
1161
0
        MAIN_EXIT(1);
1162
0
    }
1163
1164
4
    cfsp->rtpp_proc_cf = rtpp_proc_async_ctor(cfsp);
1165
4
    if (cfsp->rtpp_proc_cf == NULL) {
1166
0
        RTPP_LOG(cfsp->glog, RTPP_LOG_ERR,
1167
0
          "can't init RTP processing subsystem");
1168
0
        MAIN_EXIT(1);
1169
0
    }
1170
1171
4
    cfsp->proc_servers = rtpp_proc_servers_ctor(cfsp, cfsp->rtpp_proc_cf->netio);
1172
4
    if (cfsp->proc_servers == NULL) {
1173
0
        RTPP_LOG(cfsp->glog, RTPP_LOG_ERR,
1174
0
          "can't init RTP playback subsystem");
1175
0
        MAIN_EXIT(1);
1176
0
    }
1177
1178
4
    cfsp->rtpp_timed_cf = rtpp_timed_ctor(0.01);
1179
4
    if (cfsp->rtpp_timed_cf == NULL) {
1180
0
        RTPP_ELOG(cfsp->glog, RTPP_LOG_ERR,
1181
0
          "can't init scheduling subsystem");
1182
0
        MAIN_EXIT(1);
1183
0
    }
1184
1185
4
    tp = CALL_SMETHOD(cfsp->rtpp_timed_cf, schedule_rc, 1.0,
1186
4
      cfsp->rtpp_stats->rcnt, update_derived_stats, NULL,
1187
4
      cfsp->rtpp_stats);
1188
4
    if (tp == NULL) {
1189
0
        RTPP_ELOG(cfsp->glog, RTPP_LOG_ERR,
1190
0
          "can't schedule notification to derive stats");
1191
0
        MAIN_EXIT(1);
1192
0
    }
1193
4
    RTPP_OBJ_DECREF(tp);
1194
1195
4
    cfsp->rtpp_notify_cf = rtpp_notify_ctor(cfsp->glog);
1196
4
    if (cfsp->rtpp_notify_cf == NULL) {
1197
0
        RTPP_ELOG(cfsp->glog, RTPP_LOG_ERR,
1198
0
          "can't init timeout notification subsystem");
1199
0
        MAIN_EXIT(1);
1200
0
    }
1201
1202
4
    cfsp->rtpp_proc_ttl_cf = rtpp_proc_ttl_ctor(cfsp);
1203
4
    if (cfsp->rtpp_proc_ttl_cf == NULL) {
1204
0
        RTPP_LOG(cfsp->glog, RTPP_LOG_ERR,
1205
0
          "can't init TTL processing subsystem");
1206
0
        MAIN_EXIT(1);
1207
0
    }
1208
1209
4
#if ENABLE_MODULE_IF
1210
4
    const char *failmod;
1211
4
    if (CALL_METHOD(cfsp->modules_cf, startall, cfsp, &failmod) != 0) {
1212
0
        RTPP_ELOG(cfsp->glog, RTPP_LOG_ERR,
1213
0
          "%s: dymanic module start has failed", failmod);
1214
0
        MAIN_EXIT(1);
1215
0
    }
1216
4
#endif
1217
1218
4
    cfsp->rtpp_cmd_cf = rtpp_command_async_ctor(cfsp);
1219
4
    if (cfsp->rtpp_cmd_cf == NULL) {
1220
0
        RTPP_ELOG(cfsp->glog, RTPP_LOG_ERR,
1221
0
          "can't init command processing subsystem");
1222
0
        MAIN_EXIT(1);
1223
0
    }
1224
1225
4
    if (cfsp->ropts.no_sigtrap == 0) {
1226
0
        signal(SIGHUP, sighup);
1227
0
        signal(SIGINT, fatsignal);
1228
0
        signal(SIGKILL, fatsignal);
1229
0
        signal(SIGPIPE, SIG_IGN);
1230
0
        signal(SIGTERM, fatsignal);
1231
0
        signal(SIGXCPU, fatsignal);
1232
0
        signal(SIGXFSZ, fatsignal);
1233
0
        signal(SIGVTALRM, fatsignal);
1234
0
        signal(SIGPROF, fatsignal);
1235
0
        signal(SIGUSR1, fatsignal);
1236
0
        signal(SIGUSR2, fatsignal);
1237
0
        void (*bad_handler)(int) = badsignal;
1238
0
        RTPP_DBGCODE(catchtrace) {
1239
0
            bad_handler = rtpp_stacktrace;
1240
0
        }
1241
0
        signal(SIGQUIT, bad_handler);
1242
0
        signal(SIGILL, bad_handler);
1243
0
        signal(SIGTRAP, bad_handler);
1244
0
        signal(SIGABRT, bad_handler);
1245
#if defined(SIGEMT)
1246
        signal(SIGEMT, bad_handler);
1247
#endif
1248
0
        signal(SIGFPE, bad_handler);
1249
0
        signal(SIGBUS, bad_handler);
1250
0
        signal(SIGSEGV, bad_handler);
1251
0
        signal(SIGSYS, bad_handler);
1252
0
    }
1253
1254
#if !defined(LIBRTPPROXY)
1255
    elp = prdic_init(cfsp->target_pfreq / 10.0, 0.0);
1256
    if (elp == NULL) {
1257
        RTPP_LOG(cfsp->glog, RTPP_LOG_ERR, "prdic_init() failed");
1258
        MAIN_EXIT(1);
1259
    }
1260
#endif
1261
1262
4
    if (pid_fd >= 0) {
1263
0
        if (ftruncate(pid_fd, 0) != 0) {
1264
0
            RTPP_ELOG(cfsp->glog, RTPP_LOG_ERR, "can't truncate pidfile");
1265
0
            MAIN_EXIT(1);
1266
0
        }
1267
0
        len = sprintf(buf, "%u\n", (unsigned int)getpid());
1268
0
        if (write(pid_fd, buf, len) != len) {
1269
0
            RTPP_ELOG(cfsp->glog, RTPP_LOG_ERR, "can't write pidfile");
1270
0
            MAIN_EXIT(1);
1271
0
        }
1272
0
        close(pid_fd);
1273
0
    }
1274
1275
#ifdef HAVE_SYSTEMD_DAEMON
1276
    sd_notify(0, "READY=1");
1277
#endif
1278
1279
4
    if (cfsp->ropts.no_daemon == 0) {
1280
0
        if (rtpp_daemon_rel_parent(&drop) != 0) {
1281
0
            RTPP_LOG(cfsp->glog, RTPP_LOG_ERR, "parent died prematurely #cry #die");
1282
0
            MAIN_EXIT(1);
1283
0
        }
1284
0
    }
1285
1286
4
#if defined(LIBRTPPROXY)
1287
4
    return (cfsp);
1288
0
#endif
1289
1290
0
    for (;;) {
1291
0
        if (cfsp->fastshutdown != 0) {
1292
0
            break;
1293
0
        }
1294
0
        if (cfsp->slowshutdown != 0 &&
1295
0
          CALL_SMETHOD(cfsp->sessions_wrt, get_length) == 0) {
1296
0
            RTPP_LOG(cfsp->glog, RTPP_LOG_INFO,
1297
0
              "deorbiting-burn sequence completed, exiting");
1298
0
            break;
1299
0
        }
1300
0
        prdic_procrastinate(elp);
1301
0
    }
1302
0
    prdic_free(elp);
1303
1304
0
    rtpp_shutdown(cfsp);
1305
1306
#ifdef HAVE_SYSTEMD_DAEMON
1307
    sd_notify(0, "STATUS=Exited");
1308
#endif
1309
1310
0
    rtpp_exit(1, 0);
1311
4
}