Coverage Report

Created: 2026-06-10 06:49

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