Coverage Report

Created: 2023-09-25 06:44

/src/rtpproxy/src/commands/rpcpv1_ul.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (c) 2004-2006 Maxim Sobolev <sobomax@FreeBSD.org>
3
 * Copyright (c) 2006-2014 Sippy Software, Inc., http://www.sippysoft.com
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions
7
 * are met:
8
 * 1. Redistributions of source code must retain the above copyright
9
 *    notice, this list of conditions and the following disclaimer.
10
 * 2. Redistributions in binary form must reproduce the above copyright
11
 *    notice, this list of conditions and the following disclaimer in the
12
 *    documentation and/or other materials provided with the distribution.
13
 *
14
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24
 * SUCH DAMAGE.
25
 *
26
 */
27
28
#include <sys/types.h>
29
#include <sys/socket.h>
30
#include <netinet/in.h>
31
#include <ctype.h>
32
#include <netdb.h>
33
#include <stdatomic.h>
34
#include <stdio.h>
35
#include <stdlib.h>
36
#include <string.h>
37
38
#include "config.h"
39
40
#include "rtpp_debug.h"
41
#include "rtpp_types.h"
42
#include "rtpp_refcnt.h"
43
#include "rtpp_weakref.h"
44
#include "rtpp_log.h"
45
#include "rtpp_log_obj.h"
46
#include "rtpp_cfg.h"
47
#include "rtpp_defines.h"
48
#include "rtpp_bindaddrs.h"
49
#include "rtpp_time.h"
50
#include "rtpp_command.h"
51
#include "rtpp_command_async.h"
52
#include "commands/rpcpv1_copy.h"
53
#include "rtpp_command_ecodes.h"
54
#include "rtpp_command_args.h"
55
#include "rtpp_command_sub.h"
56
#include "rtpp_command_private.h"
57
#include "rtpp_hash_table.h"
58
#include "rtpp_pipe.h"
59
#include "rtpp_stream.h"
60
#include "rtpp_session.h"
61
#include "rtpp_sessinfo.h"
62
#include "rtpp_socket.h"
63
#include "rtp_resizer.h"
64
#include "rtpp_mallocs.h"
65
#include "rtpp_network.h"
66
#include "rtpp_tnotify_set.h"
67
#include "rtpp_timeout_data.h"
68
#include "rtpp_util.h"
69
#include "rtpp_ttl.h"
70
#include "rtpp_nofile.h"
71
#include "rtpp_proc_async.h"
72
#include "commands/rpcpv1_ul.h"
73
#include "commands/rpcpv1_ul_subc.h"
74
75
3.56k
#define FREE_IF_NULL(p) {if ((p) != NULL) {free(p); (p) = NULL;}}
76
77
struct ul_reply {
78
    const struct sockaddr *ia;
79
    const char *ia_ov;
80
    int port;
81
};
82
83
struct ul_opts {
84
    int asymmetric;
85
    int weak;
86
    int requested_ptime;
87
    char *codecs;
88
    const rtpp_str_t *addr;
89
    const rtpp_str_t *port;
90
    struct sockaddr *ia[2];
91
    const struct sockaddr *lia[2];
92
93
    struct ul_reply reply;
94
    
95
    int lidx;
96
    const struct sockaddr *local_addr;
97
    const rtpp_str_t *notify_socket;
98
    rtpp_str_const_t notify_tag;
99
    int pf;
100
    int new_port;
101
102
    int onhold;
103
};
104
105
void
106
ul_reply_port(struct rtpp_command *cmd, struct ul_reply *ulr)
107
44
{
108
44
    int len, rport;
109
44
    char saddr[MAX_ADDR_STRLEN];
110
111
44
    if (ulr == NULL || ulr->ia == NULL || ishostnull(ulr->ia)) {
112
44
        rport = (ulr == NULL) ? 0 : ulr->port;
113
44
        len = snprintf(cmd->buf_t, sizeof(cmd->buf_t), "%d", rport);
114
44
    } else {
115
0
        if (ulr->ia_ov == NULL) {
116
0
            addr2char_r(ulr->ia, saddr, sizeof(saddr));
117
0
            len = snprintf(cmd->buf_t, sizeof(cmd->buf_t), "%d %s%s", ulr->port,
118
0
              saddr, (ulr->ia->sa_family == AF_INET) ? "" : " 6");
119
0
        } else {
120
0
            len = snprintf(cmd->buf_t, sizeof(cmd->buf_t), "%d %s%s", ulr->port,
121
0
              ulr->ia_ov, (ulr->ia->sa_family == AF_INET) ? "" : " 6");
122
0
        }
123
0
    }
124
44
    int skipped = 0;
125
50
    for (int i = 0; i < cmd->subc.n; i++) {
126
6
        if (cmd->subc.res[i].result != 0) {
127
0
            while (skipped > 0) {
128
0
                len += snprintf(cmd->buf_t + len, sizeof(cmd->buf_t) - len,
129
0
                  " && 0");
130
0
                skipped -= 1;
131
0
            }
132
0
            len += snprintf(cmd->buf_t + len, sizeof(cmd->buf_t) - len,
133
0
              " && %d", cmd->subc.res[i].result);
134
6
        } else if (cmd->subc.res[i].buf_t[0] != '\0') {
135
0
            while (skipped > 0) {
136
0
                len += snprintf(cmd->buf_t + len, sizeof(cmd->buf_t) - len,
137
0
                  " && 0");
138
0
                skipped -= 1;
139
0
            }
140
0
            len += snprintf(cmd->buf_t + len, sizeof(cmd->buf_t) - len,
141
0
              " && %s", cmd->subc.res[i].buf_t);
142
6
        } else {
143
6
            skipped += 1;
144
6
        }
145
6
    }
146
44
    cmd->buf_t[len] = '\n';
147
44
    len += 1;
148
44
    cmd->buf_t[len] = '\0';
149
44
    rtpc_doreply(cmd, cmd->buf_t, len, (ulr != NULL) ? 0 : 1);
150
44
}
151
152
static void
153
ul_opts_init(const struct rtpp_cfg *cfsp, struct ul_opts *ulop)
154
1.18k
{
155
156
1.18k
    ulop->asymmetric = (cfsp->aforce != 0) ? 1 : 0;
157
1.18k
    ulop->requested_ptime = -1;
158
1.18k
    ulop->lia[0] = ulop->lia[1] = ulop->reply.ia = cfsp->bindaddr[0];
159
1.18k
    ulop->lidx = 1;
160
1.18k
    ulop->pf = AF_INET;
161
1.18k
}
162
163
void
164
rtpp_command_ul_opts_free(struct ul_opts *ulop)
165
1.18k
{
166
167
1.18k
    FREE_IF_NULL(ulop->codecs);
168
1.18k
    FREE_IF_NULL(ulop->ia[0]);
169
1.18k
    FREE_IF_NULL(ulop->ia[1]);
170
1.18k
    free(ulop);
171
1.18k
}
172
173
782
#define IPSTR_MIN_LENv4 7  /* "1.1.1.1" */
174
42
#define IPSTR_MAX_LENv4 15  /* "255.255.255.255" */
175
754
#define IPSTR_MIN_LENv6 2  /* "::" */
176
364
#define IPSTR_MAX_LENv6 45
177
178
768
#define IS_IPSTR_VALID(ips, pf) ((pf) == AF_INET ? \
179
768
  (strlen(ips) >= IPSTR_MIN_LENv4 && strlen(ips) <= IPSTR_MAX_LENv4) : \
180
768
  (strlen(ips) >= IPSTR_MIN_LENv6 && strlen(ips) <= IPSTR_MAX_LENv6))
181
182
struct ul_opts *
183
rtpp_command_ul_opts_parse(const struct rtpp_cfg *cfsp, struct rtpp_command *cmd)
184
1.18k
{
185
1.18k
    int len, tpf, n, i, ai_flags;
186
1.18k
    char *hostname;
187
1.18k
    const char *cp, *t;
188
1.18k
    rtpp_str_const_t notify_tag;
189
1.18k
    const char *errmsg;
190
1.18k
    struct sockaddr_storage tia;
191
1.18k
    struct ul_opts *ulop;
192
193
1.18k
    ulop = rtpp_zmalloc(sizeof(struct ul_opts));
194
1.18k
    if (ulop == NULL) {
195
0
        reply_error(cmd, ECODE_NOMEM_1);
196
0
        goto err_undo_0;
197
0
    }
198
1.18k
    ul_opts_init(cfsp, ulop);
199
1.18k
    if (cmd->cca.op == UPDATE && cmd->args.c > 6) {
200
77
        if (cmd->args.c == 8) {
201
5
            ulop->notify_socket = rtpp_str_fix(&cmd->args.v[6]);
202
5
            notify_tag = cmd->args.v[7];
203
72
        } else {
204
72
            ulop->notify_socket = rtpp_str_fix(&cmd->args.v[5]);
205
72
            notify_tag = cmd->args.v[6];
206
72
            cmd->cca.to_tag = NULL;
207
72
        }
208
77
        len = url_unquote((uint8_t *)notify_tag.s, notify_tag.len);
209
77
        if (len == -1) {
210
16
            RTPP_LOG(cmd->glog, RTPP_LOG_ERR,
211
16
              "command syntax error - invalid URL encoding");
212
16
            reply_error(cmd, ECODE_PARSE_10);
213
16
            goto err_undo_1;
214
16
        }
215
61
        notify_tag.len = len;
216
61
        ulop->notify_tag = notify_tag;
217
61
    }
218
1.17k
    ulop->addr = rtpp_str_fix(&cmd->args.v[2]);
219
1.17k
    ulop->port = rtpp_str_fix(&cmd->args.v[3]);
220
    /* Process additional command modifiers */
221
259k
    for (cp = cmd->args.v[0].s + 1; *cp != '\0'; cp++) {
222
258k
        switch (*cp) {
223
339
        case 'a':
224
583
        case 'A':
225
583
            ulop->asymmetric = 1;
226
583
            break;
227
228
3
        case 'e':
229
4
        case 'E':
230
4
            if (ulop->lidx < 0 || cfsp->bindaddr[1] == NULL) {
231
4
                RTPP_LOG(cmd->glog, RTPP_LOG_ERR, "command syntax error");
232
4
                reply_error(cmd, ECODE_PARSE_11);
233
4
                goto err_undo_1;
234
4
            }
235
0
            ulop->lia[ulop->lidx] = cfsp->bindaddr[1];
236
0
            ulop->lidx--;
237
0
            break;
238
239
2
        case 'i':
240
3
        case 'I':
241
3
            if (ulop->lidx < 0 || cfsp->bindaddr[1] == NULL) {
242
3
                RTPP_LOG(cmd->glog, RTPP_LOG_ERR, "command syntax error");
243
3
                reply_error(cmd, ECODE_PARSE_12);
244
3
                goto err_undo_1;
245
3
            }
246
0
            ulop->lia[ulop->lidx] = cfsp->bindaddr[0];
247
0
            ulop->lidx--;
248
0
            break;
249
250
799
        case '6':
251
799
            ulop->pf = AF_INET6;
252
799
            break;
253
254
252
        case 's':
255
970
        case 'S':
256
970
            ulop->asymmetric = 0;
257
970
            break;
258
259
383
        case 'w':
260
627
        case 'W':
261
627
            ulop->weak = 1;
262
627
            break;
263
264
376
        case 'z':
265
615
        case 'Z':
266
615
            ulop->requested_ptime = strtol(cp + 1, (char **)&cp, 10);
267
615
            if (ulop->requested_ptime <= 0 || ulop->requested_ptime >= 1000) {
268
88
                RTPP_LOG(cmd->glog, RTPP_LOG_ERR, "command syntax error");
269
88
                reply_error(cmd, ECODE_PARSE_13);
270
88
                goto err_undo_1;
271
88
            }
272
527
            cp--;
273
527
            break;
274
275
29
        case 'c':
276
61
        case 'C':
277
61
            cp += 1;
278
9.78k
            for (t = cp; *cp != '\0'; cp++) {
279
9.76k
                if (!isdigit(*cp) && *cp != ',')
280
42
                    break;
281
9.76k
            }
282
61
            if (t == cp || ulop->codecs != NULL) {
283
22
                RTPP_LOG(cmd->glog, RTPP_LOG_ERR, "command syntax error");
284
22
                reply_error(cmd, ECODE_PARSE_14);
285
22
                goto err_undo_1;
286
22
            }
287
39
            ulop->codecs = malloc(cp - t + 1);
288
39
            if (ulop->codecs == NULL) {
289
0
                reply_error(cmd, ECODE_NOMEM_2);
290
0
                goto err_undo_1;
291
0
            }
292
39
            memcpy(ulop->codecs, t, cp - t);
293
39
            ulop->codecs[cp - t] = '\0';
294
39
            cp--;
295
39
            break;
296
297
693
        case 'l':
298
248k
        case 'L':
299
248k
            len = extractaddr(cp + 1, &t, &cp, &tpf);
300
248k
            if (len == -1) {
301
144
                RTPP_LOG(cmd->glog, RTPP_LOG_ERR, "command syntax error");
302
144
                reply_error(cmd, ECODE_PARSE_15);
303
144
                goto err_undo_1;
304
144
            }
305
248k
            hostname = alloca(len + 1);
306
248k
            memcpy(hostname, t, len);
307
248k
            hostname[len] = '\0';
308
248k
            ai_flags = cfsp->no_resolve ? AI_NUMERICHOST : AI_PASSIVE;
309
248k
            ulop->local_addr = CALL_METHOD(cfsp->bindaddrs_cf, host2, hostname,
310
248k
              tpf, ai_flags, &errmsg);
311
248k
            if (ulop->local_addr == NULL) {
312
80
                RTPP_LOG(cmd->glog, RTPP_LOG_ERR,
313
80
                  "invalid local address: %s: %s", hostname, errmsg);
314
80
                reply_error(cmd, ECODE_INVLARG_1);
315
80
                goto err_undo_1;
316
80
            }
317
248k
            cp--;
318
248k
            break;
319
320
5.40k
        case 'r':
321
5.44k
        case 'R':
322
5.44k
            len = extractaddr(cp + 1, &t, &cp, &tpf);
323
5.44k
            if (len == -1) {
324
6
                RTPP_LOG(cmd->glog, RTPP_LOG_ERR, "command syntax error");
325
6
                reply_error(cmd, ECODE_PARSE_16);
326
6
                goto err_undo_1;
327
6
            }
328
5.44k
            hostname = alloca(len + 1);
329
5.44k
            memcpy(hostname, t, len);
330
5.44k
            hostname[len] = '\0';
331
5.44k
            struct sockaddr_storage local_addr;
332
5.44k
            ai_flags = cfsp->no_resolve ? AI_NUMERICHOST : AI_PASSIVE;
333
5.44k
            n = resolve(sstosa(&local_addr), tpf, hostname, SERVICE, AI_PASSIVE);
334
5.44k
            if (n != 0) {
335
13
                RTPP_LOG(cmd->glog, RTPP_LOG_ERR,
336
13
                  "invalid remote address: %s: %s", hostname, gai_strerror(n));
337
13
                reply_error(cmd, ECODE_INVLARG_2);
338
13
                goto err_undo_1;
339
13
            }
340
5.42k
            if (local4remote(sstosa(&local_addr), &local_addr) == -1) {
341
1
                RTPP_LOG(cmd->glog, RTPP_LOG_ERR,
342
1
                  "can't find local address for remote address: %s", hostname);
343
1
                reply_error(cmd, ECODE_INVLARG_3);
344
1
                goto err_undo_1;
345
1
            }
346
5.42k
            ulop->local_addr = CALL_METHOD(cfsp->bindaddrs_cf, addr2,
347
5.42k
              sstosa(&local_addr), &errmsg);
348
5.42k
            if (ulop->local_addr == NULL) {
349
0
                RTPP_LOG(cmd->glog, RTPP_LOG_ERR,
350
0
                  "invalid local address: %s", errmsg);
351
0
                reply_error(cmd, ECODE_INVLARG_4);
352
0
                goto err_undo_1;
353
0
            }
354
5.42k
            cp--;
355
5.42k
            break;
356
357
277
        case 'n':
358
550
        case 'N':
359
550
            ulop->new_port = 1;
360
550
            break;
361
362
34
        default:
363
34
            RTPP_LOG(cmd->glog, RTPP_LOG_ERR, "unknown command modifier `%c'",
364
34
              *cp);
365
34
            reply_error(cmd, ECODE_INVLARG_5);
366
34
            goto err_undo_1;
367
258k
        }
368
258k
    }
369
777
    if (ulop->local_addr == NULL && ulop->lidx == 1 &&
370
777
      ulop->pf != ulop->lia[0]->sa_family) {
371
        /*
372
         * When there is no explicit direction specified via "E"/"I" and no
373
         * local/remote address provided either via "R" or "L" make sure we
374
         * pick up address that matches the address family of the stream.
375
         */
376
372
        ulop->local_addr = CALL_METHOD(cfsp->bindaddrs_cf, foraf,
377
372
          ulop->pf);
378
372
        if (ulop->local_addr == NULL) {
379
9
            RTPP_LOG(cmd->glog, RTPP_LOG_ERR, "cannot match local "
380
18
              "address for the %s session", AF2STR(ulop->pf));
381
9
            reply_error(cmd, ECODE_INVLARG_6);
382
9
            goto err_undo_1;
383
9
        }
384
372
    }
385
768
    if (ulop->addr != NULL && ulop->port != NULL && IS_IPSTR_VALID(ulop->addr->s, ulop->pf)) {
386
369
        n = resolve(sstosa(&tia), ulop->pf, ulop->addr->s, ulop->port->s, AI_NUMERICHOST);
387
369
        if (n == 0) {
388
186
            if (!ishostnull(sstosa(&tia))) {
389
555
                for (i = 0; i < 2; i++) {
390
370
                    ulop->ia[i] = malloc(SS_LEN(&tia));
391
370
                    if (ulop->ia[i] == NULL) {
392
0
                        reply_error(cmd, ECODE_NOMEM_3);
393
0
                        goto err_undo_1;
394
0
                    }
395
370
                    memcpy(ulop->ia[i], &tia, SS_LEN(&tia));
396
370
                }
397
                /* Set port for RTCP, will work both for IPv4 and IPv6 */
398
185
                n = ntohs(satosin(ulop->ia[1])->sin_port);
399
185
                satosin(ulop->ia[1])->sin_port = htons(n + 1);
400
185
            } else {
401
1
                ulop->onhold = 1;
402
1
            }
403
186
        } else {
404
183
            RTPP_LOG(cmd->glog, RTPP_LOG_ERR, "getaddrinfo(pf=%d, addr=%s, port=%s): %s",
405
183
              ulop->pf, ulop->addr->s, ulop->port->s, gai_strerror(n));
406
183
            reply_error(cmd, ECODE_INVLARG_7);
407
183
            goto err_undo_1;
408
183
        }
409
369
    }
410
585
    return (ulop);
411
412
603
err_undo_1:
413
603
    rtpp_command_ul_opts_free(ulop);
414
603
err_undo_0:
415
603
    return (NULL);
416
603
}
417
418
static void
419
handle_nomem(struct rtpp_command *cmd, int ecode, struct rtpp_session *spa)
420
0
{
421
422
0
    RTPP_LOG(cmd->glog, RTPP_LOG_ERR, "can't allocate memory");
423
0
    if (spa != NULL) {
424
0
        RTPP_OBJ_DECREF(spa);
425
0
    }
426
0
    reply_error(cmd, ecode);
427
0
}
428
429
int
430
rtpp_command_ul_handle(const struct rtpp_cfg *cfsp, struct rtpp_command *cmd, int sidx)
431
539
{
432
539
    int pidx, lport, sessions_active;
433
539
    struct rtpp_socket *fds[2];
434
539
    const char *actor;
435
539
    struct rtpp_session *spa, *spb;
436
539
    struct rtpp_socket *fd;
437
539
    struct ul_opts *ulop;
438
439
539
    pidx = 1;
440
539
    lport = 0;
441
539
    spa = spb = NULL;
442
539
    fds[0] = fds[1] = NULL;
443
539
    ulop = cmd->cca.opts.ul;
444
445
539
    if (cmd->cca.op == UPDATE) {
446
539
        if (!CALL_METHOD(cfsp->rtpp_tnset_cf, isenabled) && ulop->notify_socket != NULL) {
447
0
            RTPP_LOG(cmd->glog, RTPP_LOG_ERR, "must permit notification socket with -n");
448
0
            reply_error(cmd, ECODE_NSOFF);
449
0
            goto err_undo_0;
450
0
        }
451
539
    }
452
453
539
    if (sidx != -1) {
454
0
        RTPP_DBG_ASSERT(cmd->cca.op == UPDATE || cmd->cca.op == LOOKUP);
455
0
        spa = cmd->sp;
456
0
        fd = CALL_SMETHOD(spa->rtp->stream[sidx], get_skt);
457
0
        if (fd == NULL || ulop->new_port != 0) {
458
0
            if (ulop->local_addr != NULL) {
459
0
                spa->rtp->stream[sidx]->laddr = ulop->local_addr;
460
0
            }
461
0
            if (rtpp_create_listener(cfsp, spa->rtp->stream[sidx]->laddr, &lport, fds) == -1) {
462
0
                RTPP_LOG(spa->log, RTPP_LOG_ERR, "can't create listener");
463
0
                reply_error(cmd, ECODE_LSTFAIL_1);
464
0
                goto err_undo_0;
465
0
            }
466
0
            if (fd != NULL && ulop->new_port != 0) {
467
0
                RTPP_LOG(spa->log, RTPP_LOG_INFO,
468
0
                  "new port requested, releasing %d/%d, replacing with %d/%d",
469
0
                  spa->rtp->stream[sidx]->port, spa->rtcp->stream[sidx]->port, lport, lport + 1);
470
0
                CALL_SMETHOD(cfsp->sessinfo, update, spa, sidx, fds);
471
0
            } else {
472
0
                CALL_SMETHOD(cfsp->sessinfo, append, spa, sidx, fds);
473
0
            }
474
0
            CALL_METHOD(cfsp->rtpp_proc_cf, nudge);
475
0
            RTPP_OBJ_DECREF(fds[0]);
476
0
            RTPP_OBJ_DECREF(fds[1]);
477
0
            spa->rtp->stream[sidx]->port = lport;
478
0
            spa->rtcp->stream[sidx]->port = lport + 1;
479
0
            if (spa->complete == 0) {
480
0
                cmd->csp->nsess_complete.cnt++;
481
0
                CALL_SMETHOD(spa->rtp->stream[0]->ttl, reset_with,
482
0
                  cfsp->max_ttl);
483
0
                CALL_SMETHOD(spa->rtp->stream[1]->ttl, reset_with,
484
0
                  cfsp->max_ttl);
485
0
            }
486
0
            spa->complete = 1;
487
0
        }
488
0
        if (fd != NULL) {
489
0
            RTPP_OBJ_DECREF(fd);
490
0
        }
491
0
        if (ulop->weak)
492
0
            spa->rtp->stream[sidx]->weak = 1;
493
0
        else if (cmd->cca.op == UPDATE)
494
0
            spa->strong = 1;
495
0
        lport = spa->rtp->stream[sidx]->port;
496
0
        ulop->lia[0] = spa->rtp->stream[sidx]->laddr;
497
0
        pidx = (sidx == 0) ? 1 : 0;
498
0
        if (cmd->cca.op == UPDATE) {
499
0
            RTPP_LOG(spa->log, RTPP_LOG_INFO,
500
0
              "adding %s flag to existing session, new=%d/%d/%d",
501
0
              ulop->weak ? ( sidx ? "weak[1]" : "weak[0]" ) : "strong",
502
0
              spa->strong, spa->rtp->stream[0]->weak, spa->rtp->stream[1]->weak);
503
0
        }
504
0
        CALL_SMETHOD(spa->rtp->stream[0]->ttl, reset);
505
0
        CALL_SMETHOD(spa->rtp->stream[1]->ttl, reset);
506
0
        RTPP_LOG(spa->log, RTPP_LOG_INFO,
507
0
          "lookup on ports %d/%d, session timer restarted", spa->rtp->stream[0]->port,
508
0
          spa->rtp->stream[1]->port);
509
539
    } else {
510
539
        struct rtpp_hash_table_entry *hte;
511
512
539
        RTPP_DBG_ASSERT(cmd->cca.op == UPDATE);
513
539
        if (ulop->local_addr != NULL) {
514
358
            ulop->lia[0] = ulop->lia[1] = ulop->local_addr;
515
358
        }
516
539
        RTPP_LOG(cmd->glog, RTPP_LOG_INFO,
517
539
          "new %s/%s session %.*s, tag %.*s requested, type %s",
518
539
          SA_AF2STR(ulop->lia[0]), SA_AF2STR(ulop->lia[1]), FMTSTR(cmd->cca.call_id),
519
539
          FMTSTR(cmd->cca.from_tag), ulop->weak ? "weak" : "strong");
520
539
        if (cfsp->slowshutdown != 0) {
521
539
            RTPP_LOG(cmd->glog, RTPP_LOG_INFO,
522
539
              "proxy is in the deorbiting-burn mode, new session rejected");
523
539
            reply_error(cmd, ECODE_SLOWSHTDN);
524
539
            goto err_undo_0;
525
539
        }
526
0
        if (cfsp->overload_prot.ecode != 0 &&
527
0
          CALL_METHOD(cfsp->rtpp_cmd_cf, chk_overload) != 0) {
528
0
            RTPP_LOG(cmd->glog, RTPP_LOG_ERR,
529
0
              "proxy is overloaded, new session rejected");
530
0
            reply_error(cmd, cfsp->overload_prot.ecode);
531
0
            goto err_undo_0;
532
0
        }
533
0
        if (rtpp_create_listener(cfsp, ulop->lia[0], &lport, fds) == -1) {
534
0
            RTPP_LOG(cmd->glog, RTPP_LOG_ERR, "can't create listener");
535
0
            reply_error(cmd, ECODE_LSTFAIL_2);
536
0
            goto err_undo_0;
537
0
        }
538
539
        /*
540
         * Session creation. If creation is requested with weak flag,
541
         * set weak[0].
542
         */
543
0
        spa = rtpp_session_ctor(cfsp, &cmd->cca, cmd->dtime, ulop->lia,
544
0
          ulop->weak, lport, fds);
545
0
        RTPP_OBJ_DECREF(fds[0]);
546
0
        RTPP_OBJ_DECREF(fds[1]);
547
0
        if (spa == NULL) {
548
0
            handle_nomem(cmd, ECODE_NOMEM_4, NULL);
549
0
            return (-1);
550
0
        }
551
552
0
        cmd->csp->nsess_created.cnt++;
553
554
0
        hte = CALL_SMETHOD(cfsp->sessions_ht, append_str_refcnt, spa->call_id,
555
0
          spa->rcnt, NULL);
556
0
        if (hte == NULL) {
557
0
            handle_nomem(cmd, ECODE_NOMEM_5, spa);
558
0
            return (-1);
559
0
        }
560
0
        if (CALL_SMETHOD(cfsp->sessions_wrt, reg, spa->rcnt, spa->seuid) != 0) {
561
0
            CALL_SMETHOD(cfsp->sessions_ht, remove_str, spa->call_id, hte);
562
0
            handle_nomem(cmd, ECODE_NOMEM_8, spa);
563
0
            return (-1);
564
0
        }
565
566
        /*
567
         * Each session can consume up to 5 open file descriptors (2 RTP,
568
         * 2 RTCP and 1 logging) so that warn user when he is likely to
569
         * exceed 80% mark on hard limit.
570
         */
571
0
        sessions_active = CALL_SMETHOD(cfsp->sessions_wrt, get_length);
572
0
        if (sessions_active > (rtpp_rlim_max(cfsp) * 80 / (100 * 5)) &&
573
0
          atomic_load(&cfsp->nofile->warned) == 0) {
574
0
            atomic_store(&(cfsp->nofile->warned), 1);
575
0
            RTPP_LOG(cmd->glog, RTPP_LOG_WARN, "passed 80%% "
576
0
              "threshold on the open file descriptors limit (%d), "
577
0
              "consider increasing the limit using -L command line "
578
0
              "option", (int)rtpp_rlim_max(cfsp));
579
0
        }
580
581
0
        RTPP_LOG(spa->log, RTPP_LOG_INFO, "new session on %s port %d created, "
582
0
          "tag %.*s", AF2STR(ulop->pf), lport, FMTSTR(cmd->cca.from_tag));
583
0
        if (cfsp->record_all != 0) {
584
0
            handle_copy(cfsp, spa, 0, NULL, RSF_MODE_DFLT(cfsp));
585
0
            handle_copy(cfsp, spa, 1, NULL, RSF_MODE_DFLT(cfsp));
586
0
        }
587
        /* Save ref, it will be decref'd by the command disposal code */
588
0
        RTPP_DBG_ASSERT(cmd->sp == NULL);
589
0
        cmd->sp = spa;
590
0
    }
591
592
0
    if (cmd->cca.op == UPDATE) {
593
0
        if (spa->timeout_data != NULL) {
594
0
            RTPP_OBJ_DECREF(spa->timeout_data);
595
0
            spa->timeout_data = NULL;
596
0
        }
597
0
        if (ulop->notify_socket != NULL) {
598
0
            struct rtpp_tnotify_target *rttp;
599
600
0
            rttp = CALL_METHOD(cfsp->rtpp_tnset_cf, lookup, ulop->notify_socket->s,
601
0
              (cmd->rlen > 0) ? sstosa(&cmd->raddr) : NULL, (cmd->rlen > 0) ? cmd->laddr : NULL);
602
0
            if (rttp == NULL) {
603
0
                RTPP_LOG(spa->log, RTPP_LOG_ERR, "invalid socket name %.*s",
604
0
                  FMTSTR(ulop->notify_socket));
605
0
                ulop->notify_socket = NULL;
606
0
            } else {
607
0
                RTPP_LOG(spa->log, RTPP_LOG_INFO, "setting timeout handler");
608
0
                RTPP_DBG_ASSERT(ulop->notify_tag.s != NULL);
609
0
                spa->timeout_data = rtpp_timeout_data_ctor(rttp,
610
0
                  rtpp_str_fix(&ulop->notify_tag));
611
0
                if (spa->timeout_data == NULL) {
612
0
                    RTPP_LOG(spa->log, RTPP_LOG_ERR,
613
0
                      "setting timeout handler: ENOMEM");
614
0
                }
615
0
            }
616
0
        } else if (spa->timeout_data != NULL) {
617
0
            RTPP_OBJ_DECREF(spa->timeout_data);
618
0
            spa->timeout_data = NULL;
619
0
            RTPP_LOG(spa->log, RTPP_LOG_INFO, "disabling timeout handler");
620
0
        }
621
0
    }
622
623
0
    if (ulop->ia[0] != NULL && ulop->ia[1] != NULL) {
624
0
        CALL_SMETHOD(spa->rtp->stream[pidx], prefill_addr, &(ulop->ia[0]),
625
0
          cmd->dtime->mono);
626
0
        CALL_SMETHOD(spa->rtcp->stream[pidx], prefill_addr, &(ulop->ia[1]),
627
0
          cmd->dtime->mono);
628
0
    }
629
0
    if (ulop->onhold != 0) {
630
0
        CALL_SMETHOD(spa->rtp->stream[pidx], reg_onhold);
631
0
        CALL_SMETHOD(spa->rtcp->stream[pidx], reg_onhold);
632
0
    }
633
0
    spa->rtp->stream[pidx]->asymmetric = spa->rtcp->stream[pidx]->asymmetric = ulop->asymmetric;
634
0
    if (ulop->asymmetric) {
635
0
        CALL_SMETHOD(spa->rtp->stream[pidx], locklatch);
636
0
        CALL_SMETHOD(spa->rtcp->stream[pidx], locklatch);
637
0
    }
638
0
    if (spa->rtp->stream[pidx]->codecs != NULL) {
639
0
        free(spa->rtp->stream[pidx]->codecs);
640
0
        spa->rtp->stream[pidx]->codecs = NULL;
641
0
    }
642
0
    if (ulop->codecs != NULL) {
643
0
        spa->rtp->stream[pidx]->codecs = ulop->codecs;
644
0
        ulop->codecs = NULL;
645
0
    }
646
0
    spa->rtp->stream[NOT(pidx)]->ptime = ulop->requested_ptime;
647
0
    actor = CALL_SMETHOD(spa->rtp->stream[pidx], get_actor);
648
0
    if (ulop->requested_ptime > 0) {
649
0
        RTPP_LOG(spa->log, RTPP_LOG_INFO, "RTP packets from %s "
650
0
          "will be resized to %d milliseconds", actor, ulop->requested_ptime);
651
0
    } else if (spa->rtp->stream[pidx]->resizer != NULL) {
652
0
          RTPP_LOG(spa->log, RTPP_LOG_INFO, "Resizing of RTP "
653
0
          "packets from %s has been disabled", actor);
654
0
    }
655
0
    if (ulop->requested_ptime > 0) {
656
0
        if (spa->rtp->stream[pidx]->resizer != NULL) {
657
0
            rtp_resizer_set_ptime(spa->rtp->stream[pidx]->resizer, ulop->requested_ptime);
658
0
        } else {
659
0
            spa->rtp->stream[pidx]->resizer = rtp_resizer_new(ulop->requested_ptime);
660
0
        }
661
0
    } else if (spa->rtp->stream[pidx]->resizer != NULL) {
662
0
        rtp_resizer_free(cfsp->rtpp_stats, spa->rtp->stream[pidx]->resizer);
663
0
        spa->rtp->stream[pidx]->resizer = NULL;
664
0
    }
665
666
0
    RTPP_DBG_ASSERT(lport != 0);
667
0
    ulop->reply.port = lport;
668
0
    ulop->reply.ia = ulop->lia[0];
669
0
    if (cfsp->advaddr[0] != NULL) {
670
0
        if (cfsp->bmode != 0 && cfsp->advaddr[1] != NULL &&
671
0
          ulop->lia[0] == cfsp->bindaddr[1]) {
672
0
            ulop->reply.ia_ov = cfsp->advaddr[1];
673
0
        } else {
674
0
            ulop->reply.ia_ov = cfsp->advaddr[0];
675
0
        }
676
0
    }
677
0
    for (int i = 0; i < cmd->subc.n; i++) {
678
0
        struct rtpp_subc_ctx rsc = {
679
0
            .sessp = spa,
680
0
            .strmp_in = spa->rtp->stream[pidx],
681
0
            .strmp_out = spa->rtp->stream[NOT(pidx)],
682
0
            .subc_args = &(cmd->subc.args[i]),
683
0
            .resp = &(cmd->subc.res[i])
684
0
        };
685
0
        rsc.resp->result = cmd->after_success[i].handler(
686
0
          &cmd->after_success[i].args, &rsc);
687
0
        if (rsc.resp->result != 0)
688
0
            break;
689
0
    }
690
0
    ul_reply_port(cmd, &ulop->reply);
691
0
    return (0);
692
693
539
err_undo_0:
694
539
    return (-1);
695
539
}