Coverage Report

Created: 2026-01-17 07:03

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/rtpproxy/src/rtpp_session.c
Line
Count
Source
1
/*
2
 * Copyright (c) 2006-2020 Sippy Software, Inc., http://www.sippysoft.com
3
 * Copyright (c) 2004-2006 Maxim Sobolev <sobomax@FreeBSD.org>
4
 * All rights reserved.
5
 *
6
 * Redistribution and use in source and binary forms, with or without
7
 * modification, are permitted provided that the following conditions
8
 * are met:
9
 * 1. Redistributions of source code must retain the above copyright
10
 *    notice, this list of conditions and the following disclaimer.
11
 * 2. Redistributions in binary form must reproduce the above copyright
12
 *    notice, this list of conditions and the following disclaimer in the
13
 *    documentation and/or other materials provided with the distribution.
14
 *
15
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25
 * SUCH DAMAGE.
26
 *
27
 */
28
29
#include <sys/types.h>
30
#include <sys/socket.h>
31
#include <stddef.h>
32
#include <stdint.h>
33
#include <stdlib.h>
34
#include <string.h>
35
36
#include "config.h"
37
38
#include "rtpp_debug.h"
39
#include "rtpp_types.h"
40
#include "rtpp_log.h"
41
#include "rtpp_log_obj.h"
42
#include "rtpp_cfg.h"
43
#include "rtpp_acct_pipe.h"
44
#include "rtpp_acct.h"
45
#include "rtpp_analyzer.h"
46
#include "rtpp_command.h"
47
#include "rtpp_time.h"
48
#include "rtpp_command_args.h"
49
#include "rtpp_command_sub.h"
50
#include "rtpp_command_private.h"
51
#include "rtpp_genuid.h"
52
#include "rtpp_hash_table.h"
53
#include "rtpp_list.h"
54
#include "rtpp_mallocs.h"
55
#include "rtpp_module_if.h"
56
#include "rtpp_modman.h"
57
#include "rtpp_pipe.h"
58
#include "rtpp_codeptr.h"
59
#include "rtpp_socket.h"
60
#include "rtpp_stream.h"
61
#include "rtpp_session.h"
62
#include "rtpp_sessinfo.h"
63
#include "rtpp_stats.h"
64
#include "rtpp_ttl.h"
65
#include "rtpp_refcnt.h"
66
#include "rtpp_timeout_data.h"
67
#include "rtpp_proc_async.h"
68
69
struct rtpp_session_priv
70
{
71
    struct rtpp_session pub;
72
    struct rtpp_sessinfo *sessinfo;
73
    struct rtpp_modman *module_cf;
74
    struct rtpp_acct *acct;
75
    struct rtpp_str call_id;
76
    struct rtpp_str from_tag;
77
    struct rtpp_str from_tag_nmn;
78
};
79
80
static void rtpp_session_dtor(struct rtpp_session_priv *);
81
82
struct rtpp_session *
83
rtpp_session_ctor(const struct rtpp_session_ctor_args *ap)
84
0
{
85
0
    struct rtpp_session_priv *pvt;
86
0
    struct rtpp_session *pub;
87
0
    struct rtpp_log *log;
88
0
    struct r_pipe_ctor_args pipe_cfg;
89
0
    const struct rtpp_cfg *cfs = ap->cfs;
90
0
    struct common_cmd_args *ccap = ap->ccap;
91
0
    int i, lport = 0;
92
0
    struct rtpp_socket *fds[2];
93
94
0
    log = rtpp_log_ctor("rtpproxy", ccap->call_id->s, 0);
95
0
    if (log == NULL) {
96
0
        goto e0;
97
0
    }
98
99
0
    if (rtpp_create_listener(cfs, ap->lia[0], &lport, fds) == -1) {
100
0
        RTPP_LOG(log, RTPP_LOG_ERR, "can't create listener");
101
0
        goto e1;
102
0
    }
103
104
0
    pvt = rtpp_rzmalloc(sizeof(struct rtpp_session_priv), PVT_RCOFFS(pvt));
105
0
    if (pvt == NULL) {
106
0
        goto e2;
107
0
    }
108
109
0
    pub = &(pvt->pub);
110
0
    pub->seuid = CALL_SMETHOD(cfs->guid, gen);
111
112
0
    CALL_METHOD(log, start, cfs);
113
0
    CALL_METHOD(log, setlevel, cfs->log_level);
114
0
    pipe_cfg = (struct r_pipe_ctor_args){.seuid = pub->seuid,
115
0
      .log = log, .pipe_type = PIPE_RTP, .session_cap = ap,
116
0
    };
117
0
    pub->rtp = rtpp_pipe_ctor(&pipe_cfg);
118
0
    if (pub->rtp == NULL) {
119
0
        goto e3;
120
0
    }
121
    /* spb is RTCP twin session for this one. */
122
0
    pipe_cfg.pipe_type = PIPE_RTCP;
123
0
    pub->rtcp = rtpp_pipe_ctor(&pipe_cfg);
124
0
    if (pub->rtcp == NULL) {
125
0
        goto e4;
126
0
    }
127
0
    pvt->acct = rtpp_acct_ctor(pub->seuid);
128
0
    if (pvt->acct == NULL) {
129
0
        goto e5;
130
0
    }
131
0
    pvt->acct->init_ts->wall = ap->dtime->wall;
132
0
    pvt->acct->init_ts->mono = ap->dtime->mono;
133
134
0
    if (rtpp_str_dup2(ccap->call_id, &pvt->call_id.ro) == NULL) {
135
0
        goto e6;
136
0
    }
137
0
    pub->call_id = &pvt->call_id.fx;
138
0
    if (rtpp_str_dup2(ccap->from_tag, &pvt->from_tag.ro) == NULL) {
139
0
        goto e7;
140
0
    }
141
0
    pub->from_tag = &pvt->from_tag.fx;
142
0
    rtpp_str_const_t tag_nomedianum = {.s = ccap->from_tag->s, .len = ccap->from_tag->len};
143
0
    const char *semi = memchr(tag_nomedianum.s, ';', tag_nomedianum.len);
144
0
    if (semi != NULL) {
145
0
        tag_nomedianum.len = semi - tag_nomedianum.s;
146
0
    }
147
0
    if (rtpp_str_dup2(&tag_nomedianum, &pvt->from_tag_nmn.ro) == NULL) {
148
0
        goto e8;
149
0
    }
150
0
    pub->from_tag_nmn = &pvt->from_tag_nmn.fx;
151
0
    if (ap->weak) {
152
0
        pub->rtp->stream[0]->weak = 1;
153
0
    } else {
154
0
        pub->strong = 1;
155
0
    }
156
157
0
    pub->rtp->stream[0]->port = lport;
158
0
    pub->rtcp->stream[0]->port = lport + 1;
159
0
    for (i = 0; i < 2; i++) {
160
0
        if (i == 0 || cfs->ttl_mode == TTL_INDEPENDENT) {
161
0
            pub->rtp->stream[i]->ttl = rtpp_ttl_ctor(cfs->max_setup_ttl);
162
0
            if (pub->rtp->stream[i]->ttl == NULL) {
163
0
                goto e9;
164
0
            }
165
0
        } else {
166
0
            pub->rtp->stream[i]->ttl = pub->rtp->stream[0]->ttl;
167
0
            RTPP_OBJ_INCREF(pub->rtp->stream[0]->ttl);
168
0
        }
169
        /* RTCP shares the same TTL */
170
0
        pub->rtcp->stream[i]->ttl = pub->rtp->stream[i]->ttl;
171
0
        RTPP_OBJ_INCREF(pub->rtp->stream[i]->ttl);
172
0
    }
173
0
    for (i = 0; i < 2; i++) {
174
0
        pub->rtp->stream[i]->stuid_rtcp = pub->rtcp->stream[i]->stuid;
175
0
        pub->rtcp->stream[i]->stuid_rtp = pub->rtp->stream[i]->stuid;
176
0
    }
177
178
0
    pvt->pub.rtpp_stats = cfs->rtpp_stats;
179
0
    pvt->pub.log = log;
180
0
    pvt->sessinfo = cfs->sessinfo;
181
0
    RTPP_OBJ_INCREF(cfs->sessinfo);
182
0
#if ENABLE_MODULE_IF
183
0
    if (cfs->modules_cf->count.sess_acct > 0) {
184
0
        RTPP_OBJ_INCREF(cfs->modules_cf);
185
0
        pvt->module_cf = cfs->modules_cf;
186
0
    }
187
0
#endif
188
189
0
    CALL_SMETHOD(cfs->sessinfo, append, pub, 0, fds);
190
0
    RTPP_OBJ_DECREF(fds[0]);
191
0
    RTPP_OBJ_DECREF(fds[1]);
192
0
    CALL_METHOD(cfs->rtpp_proc_cf, nudge);
193
194
0
    CALL_SMETHOD(pub->rcnt, attach, (rtpp_refcnt_dtor_t)&rtpp_session_dtor,
195
0
      pvt);
196
0
    return (&pvt->pub);
197
198
0
e9:
199
0
    free(pvt->from_tag_nmn.rw.s);
200
0
e8:
201
0
    free(pvt->from_tag.rw.s);
202
0
e7:
203
0
    free(pvt->call_id.rw.s);
204
0
e6:
205
0
    RTPP_OBJ_DECREF(pvt->acct);
206
0
e5:
207
0
    RTPP_OBJ_DECREF(pub->rtcp);
208
0
e4:
209
0
    RTPP_OBJ_DECREF(pub->rtp);
210
0
e3:
211
0
    RTPP_OBJ_DECREF(pub);
212
0
e2:
213
0
    RTPP_OBJ_DECREF(fds[0]);
214
0
    RTPP_OBJ_DECREF(fds[1]);
215
0
e1:
216
0
    RTPP_OBJ_DECREF(log);
217
0
e0:
218
0
    return (NULL);
219
0
}
220
221
static void
222
rtpp_session_dtor(struct rtpp_session_priv *pvt)
223
0
{
224
0
    int i;
225
0
    double session_time;
226
0
    struct rtpp_session *pub;
227
228
0
    pub = &(pvt->pub);
229
0
    rtpp_timestamp_get(pvt->acct->destroy_ts);
230
0
    session_time = pvt->acct->destroy_ts->mono - pvt->acct->init_ts->mono;
231
232
0
    CALL_SMETHOD(pub->rtp, get_stats, &pvt->acct->rtp);
233
0
    CALL_SMETHOD(pub->rtcp, get_stats, &pvt->acct->rtcp);
234
0
    if (pub->complete != 0) {
235
0
        CALL_SMETHOD(pub->rtp, upd_cntrs, &pvt->acct->rtp);
236
0
        CALL_SMETHOD(pub->rtcp, upd_cntrs, &pvt->acct->rtcp);
237
0
    }
238
0
    RTPP_LOG(pub->log, RTPP_LOG_INFO, "session on ports %d/%d is cleaned up",
239
0
      pub->rtp->stream[0]->port, pub->rtp->stream[1]->port);
240
0
    for (i = 0; i < 2; i++) {
241
0
        CALL_SMETHOD(pvt->sessinfo, remove, pub, i);
242
0
    }
243
0
    RTPP_OBJ_DECREF(pvt->sessinfo);
244
0
    CALL_SMETHOD(pub->rtpp_stats, updatebyname, "nsess_destroyed", 1);
245
0
    CALL_SMETHOD(pub->rtpp_stats, updatebyname_d, "total_duration",
246
0
      session_time);
247
0
    if (pvt->module_cf != NULL) {
248
0
        pvt->acct->call_id = pvt->call_id.rw.s;
249
0
        pvt->call_id.rw.s = NULL;
250
0
        pvt->acct->from_tag = pvt->from_tag.rw.s;
251
0
        pvt->from_tag.rw.s = NULL;
252
0
        CALL_SMETHOD(pub->rtp->stream[0]->analyzer, get_stats, \
253
0
          pvt->acct->rasto);
254
0
        CALL_SMETHOD(pub->rtp->stream[1]->analyzer, get_stats, \
255
0
          pvt->acct->rasta);
256
0
        CALL_SMETHOD(pub->rtp->stream[0]->analyzer, get_jstats, \
257
0
          pvt->acct->jrasto);
258
0
        CALL_SMETHOD(pub->rtp->stream[1]->analyzer, get_jstats, \
259
0
          pvt->acct->jrasta);
260
261
0
        CALL_METHOD(pvt->module_cf, do_acct, pvt->acct);
262
0
        RTPP_OBJ_DECREF(pvt->module_cf);
263
0
    }
264
0
    RTPP_OBJ_DECREF(pvt->acct);
265
266
0
    RTPP_OBJ_DECREF(pvt->pub.log);
267
0
    if (pvt->pub.timeout_data != NULL)
268
0
        RTPP_OBJ_DECREF(pvt->pub.timeout_data);
269
0
    if (pvt->call_id.rw.s != NULL)
270
0
        free(pvt->call_id.rw.s);
271
0
    if (pvt->from_tag.rw.s != NULL)
272
0
        free(pvt->from_tag.rw.s);
273
0
    if (pvt->from_tag_nmn.rw.s != NULL)
274
0
        free(pvt->from_tag_nmn.rw.s);
275
276
0
    RTPP_OBJ_DECREF(pvt->pub.rtcp);
277
0
    RTPP_OBJ_DECREF(pvt->pub.rtp);
278
0
}
279
280
int
281
compare_session_tags(const rtpp_str_t *tag1, const rtpp_str_t *tag0,
282
  unsigned *medianum_p)
283
0
{
284
285
0
    if (tag1->len < tag0->len)
286
0
        return 0;
287
0
    if (!memcmp(tag1->s, tag0->s, tag0->len)) {
288
0
        if (tag1->len == tag0->len)
289
0
            return 1;
290
0
  if (tag1->s[tag0->len] == ';') {
291
0
      if (medianum_p != NULL)
292
0
    *medianum_p = strtoul(tag1->s + tag0->len + 1, NULL, 10);
293
0
      return 2;
294
0
  }
295
0
    }
296
0
    return 0;
297
0
}
298
299
struct session_match_args {
300
    const rtpp_str_t *from_tag;
301
    const rtpp_str_t *to_tag;
302
    struct rtpp_session *sp;
303
    int rval;
304
};
305
306
static int
307
rtpp_session_ematch(void *dp, void *ap)
308
0
{
309
0
    struct rtpp_session *rsp;
310
0
    struct session_match_args *map;
311
0
    const char *cp1, *cp2;
312
313
0
    rsp = (struct rtpp_session *)dp;
314
0
    map = (struct session_match_args *)ap;
315
316
0
    if (rtpp_str_match(rsp->from_tag, map->from_tag)) {
317
0
        map->rval = 0;
318
0
        goto found;
319
0
    }
320
0
    if (map->to_tag != NULL) {
321
0
        switch (compare_session_tags(rsp->from_tag, map->to_tag, NULL)) {
322
0
        case 1:
323
            /* Exact tag match */
324
0
            map->rval = 1;
325
0
            goto found;
326
327
0
        case 2:
328
            /*
329
             * Reverse tag match without medianum. Medianum is always
330
             * applied to the from tag, verify that.
331
             */
332
0
            cp1 = strrchr(rsp->from_tag->s, ';');
333
0
            cp2 = strrchr(map->from_tag->s, ';');
334
0
            if (cp2 != NULL && strcmp(cp1, cp2) == 0) {
335
0
                map->rval = 1;
336
0
                goto found;
337
0
            }
338
0
            break;
339
340
0
        default:
341
0
            break;
342
0
        }
343
0
    }
344
0
    return (RTPP_HT_MATCH_CONT);
345
346
0
found:
347
0
    RTPP_OBJ_INCREF(rsp);
348
0
    RTPP_DBG_ASSERT(map->sp == NULL);
349
0
    map->sp = rsp;
350
0
    return (RTPP_HT_MATCH_BRK);
351
0
}
352
353
int
354
find_stream(const struct rtpp_cfg *cfsp, const rtpp_str_t *call_id,
355
  const rtpp_str_t *from_tag, const rtpp_str_t *to_tag, struct rtpp_session **spp)
356
0
{
357
0
    struct session_match_args ma;
358
359
0
    memset(&ma, '\0', sizeof(ma));
360
0
    ma.from_tag = from_tag;
361
0
    ma.to_tag = to_tag;
362
0
    ma.rval = -1;
363
364
0
    CALL_SMETHOD(cfsp->sessions_ht, foreach_key_str, call_id,
365
0
      rtpp_session_ematch, &ma);
366
0
    if (ma.rval != -1) {
367
0
        *spp = ma.sp;
368
0
    }
369
0
    return ma.rval;
370
0
}
371
372
struct rtpp_stream_pair
373
get_rtcp_pair(const struct rtpp_session *sessp, const struct rtpp_stream *rtp_strmp_in)
374
0
{
375
376
0
    for (int i = 0; i < 2; i++) {
377
0
        if (sessp->rtp->stream[i] != rtp_strmp_in)
378
0
            continue;
379
0
        return (struct rtpp_stream_pair){
380
0
           .in = sessp->rtcp->stream[i], .out = sessp->rtcp->stream[i ^ 1]
381
0
        };
382
0
    }
383
0
    return (struct rtpp_stream_pair){.ret = -1};
384
0
}