Coverage Report

Created: 2025-08-03 06:23

/src/rtpproxy/src/rtpp_session.c
Line
Count
Source (jump to first uncovered line)
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_stream.h"
60
#include "rtpp_session.h"
61
#include "rtpp_sessinfo.h"
62
#include "rtpp_stats.h"
63
#include "rtpp_ttl.h"
64
#include "rtpp_refcnt.h"
65
#include "rtpp_timeout_data.h"
66
#include "rtpp_proc_async.h"
67
68
struct rtpp_session_priv
69
{
70
    struct rtpp_session pub;
71
    struct rtpp_sessinfo *sessinfo;
72
    struct rtpp_modman *module_cf;
73
    struct rtpp_acct *acct;
74
    struct rtpp_str call_id;
75
    struct rtpp_str from_tag;
76
    struct rtpp_str from_tag_nmn;
77
};
78
79
static void rtpp_session_dtor(struct rtpp_session_priv *);
80
81
struct rtpp_session *
82
rtpp_session_ctor(const struct rtpp_cfg *cfs, struct common_cmd_args *ccap,
83
  const struct rtpp_timestamp *dtime, const struct sockaddr **lia, int weak,
84
  int lport, struct rtpp_socket **fds)
85
22.8k
{
86
22.8k
    struct rtpp_session_priv *pvt;
87
22.8k
    struct rtpp_session *pub;
88
22.8k
    struct rtpp_log *log;
89
22.8k
    struct r_pipe_ctor_args pipe_cfg;
90
22.8k
    int i;
91
92
22.8k
    pvt = rtpp_rzmalloc(sizeof(struct rtpp_session_priv), PVT_RCOFFS(pvt));
93
22.8k
    if (pvt == NULL) {
94
0
        goto e0;
95
0
    }
96
97
22.8k
    pub = &(pvt->pub);
98
22.8k
    pub->seuid = CALL_SMETHOD(cfs->guid, gen);
99
100
22.8k
    log = rtpp_log_ctor("rtpproxy", ccap->call_id->s, 0);
101
22.8k
    if (log == NULL) {
102
0
        goto e1;
103
0
    }
104
22.8k
    CALL_METHOD(log, start, cfs);
105
22.8k
    CALL_METHOD(log, setlevel, cfs->log_level);
106
22.8k
    pipe_cfg = (struct r_pipe_ctor_args){.seuid = pub->seuid,
107
22.8k
      .streams_wrt = cfs->rtp_streams_wrt, .proc_servers = cfs->proc_servers,
108
22.8k
      .log = log, .rtpp_stats = cfs->rtpp_stats, .pipe_type = PIPE_RTP,
109
22.8k
#if ENABLE_MODULE_IF
110
22.8k
      .nmodules  = cfs->modules_cf->count.total,
111
22.8k
#endif
112
22.8k
      .pproc_manager = cfs->pproc_manager,
113
22.8k
      .guid = cfs->guid,
114
22.8k
    };
115
22.8k
    pub->rtp = rtpp_pipe_ctor(&pipe_cfg);
116
22.8k
    if (pub->rtp == NULL) {
117
0
        goto e2;
118
0
    }
119
    /* spb is RTCP twin session for this one. */
120
22.8k
    pipe_cfg.streams_wrt = cfs->rtcp_streams_wrt;
121
22.8k
    pipe_cfg.pipe_type = PIPE_RTCP;
122
22.8k
    pub->rtcp = rtpp_pipe_ctor(&pipe_cfg);
123
22.8k
    if (pub->rtcp == NULL) {
124
0
        goto e3;
125
0
    }
126
22.8k
    pvt->acct = rtpp_acct_ctor(pub->seuid);
127
22.8k
    if (pvt->acct == NULL) {
128
0
        goto e4;
129
0
    }
130
22.8k
    pvt->acct->init_ts->wall = dtime->wall;
131
22.8k
    pvt->acct->init_ts->mono = dtime->mono;
132
133
22.8k
    if (rtpp_str_dup2(ccap->call_id, &pvt->call_id.ro) == NULL) {
134
0
        goto e5;
135
0
    }
136
22.8k
    pub->call_id = &pvt->call_id.fx;
137
22.8k
    if (rtpp_str_dup2(ccap->from_tag, &pvt->from_tag.ro) == NULL) {
138
0
        goto e6;
139
0
    }
140
22.8k
    pub->from_tag = &pvt->from_tag.fx;
141
22.8k
    rtpp_str_const_t tag_nomedianum = {.s = ccap->from_tag->s, .len = ccap->from_tag->len};
142
22.8k
    const char *semi = memchr(tag_nomedianum.s, ';', tag_nomedianum.len);
143
22.8k
    if (semi != NULL) {
144
0
        tag_nomedianum.len = semi - tag_nomedianum.s;
145
0
    }
146
22.8k
    if (rtpp_str_dup2(&tag_nomedianum, &pvt->from_tag_nmn.ro) == NULL) {
147
0
        goto e7;
148
0
    }
149
22.8k
    pub->from_tag_nmn = &pvt->from_tag_nmn.fx;
150
68.4k
    for (i = 0; i < 2; i++) {
151
45.6k
        pub->rtp->stream[i]->laddr = lia[i];
152
45.6k
        pub->rtcp->stream[i]->laddr = lia[i];
153
45.6k
    }
154
22.8k
    if (weak) {
155
0
        pub->rtp->stream[0]->weak = 1;
156
22.8k
    } else {
157
22.8k
        pub->strong = 1;
158
22.8k
    }
159
160
22.8k
    pub->rtp->stream[0]->port = lport;
161
22.8k
    pub->rtcp->stream[0]->port = lport + 1;
162
68.4k
    for (i = 0; i < 2; i++) {
163
45.6k
        if (i == 0 || cfs->ttl_mode == TTL_INDEPENDENT) {
164
22.8k
            pub->rtp->stream[i]->ttl = rtpp_ttl_ctor(cfs->max_setup_ttl);
165
22.8k
            if (pub->rtp->stream[i]->ttl == NULL) {
166
0
                goto e8;
167
0
            }
168
22.8k
        } else {
169
22.8k
            pub->rtp->stream[i]->ttl = pub->rtp->stream[0]->ttl;
170
22.8k
            RTPP_OBJ_INCREF(pub->rtp->stream[0]->ttl);
171
22.8k
        }
172
        /* RTCP shares the same TTL */
173
45.6k
        pub->rtcp->stream[i]->ttl = pub->rtp->stream[i]->ttl;
174
45.6k
        RTPP_OBJ_INCREF(pub->rtp->stream[i]->ttl);
175
45.6k
    }
176
68.4k
    for (i = 0; i < 2; i++) {
177
45.6k
        pub->rtp->stream[i]->stuid_rtcp = pub->rtcp->stream[i]->stuid;
178
45.6k
        pub->rtcp->stream[i]->stuid_rtp = pub->rtp->stream[i]->stuid;
179
45.6k
    }
180
181
22.8k
    pvt->pub.rtpp_stats = cfs->rtpp_stats;
182
22.8k
    pvt->pub.log = log;
183
22.8k
    pvt->sessinfo = cfs->sessinfo;
184
22.8k
    RTPP_OBJ_INCREF(cfs->sessinfo);
185
22.8k
#if ENABLE_MODULE_IF
186
22.8k
    if (cfs->modules_cf->count.sess_acct > 0) {
187
22.8k
        RTPP_OBJ_INCREF(cfs->modules_cf);
188
22.8k
        pvt->module_cf = cfs->modules_cf;
189
22.8k
    }
190
22.8k
#endif
191
192
22.8k
    CALL_SMETHOD(cfs->sessinfo, append, pub, 0, fds);
193
22.8k
    CALL_METHOD(cfs->rtpp_proc_cf, nudge);
194
195
22.8k
    CALL_SMETHOD(pub->rcnt, attach, (rtpp_refcnt_dtor_t)&rtpp_session_dtor,
196
22.8k
      pvt);
197
22.8k
    return (&pvt->pub);
198
199
0
e8:
200
0
    free(pvt->from_tag_nmn.rw.s);
201
0
e7:
202
0
    free(pvt->from_tag.rw.s);
203
0
e6:
204
0
    free(pvt->call_id.rw.s);
205
0
e5:
206
0
    RTPP_OBJ_DECREF(pvt->acct);
207
0
e4:
208
0
    RTPP_OBJ_DECREF(pub->rtcp);
209
0
e3:
210
0
    RTPP_OBJ_DECREF(pub->rtp);
211
0
e2:
212
0
    RTPP_OBJ_DECREF(log);
213
0
e1:
214
0
    RTPP_OBJ_DECREF(pub);
215
0
e0:
216
0
    return (NULL);
217
0
}
218
219
static void
220
rtpp_session_dtor(struct rtpp_session_priv *pvt)
221
22.8k
{
222
22.8k
    int i;
223
22.8k
    double session_time;
224
22.8k
    struct rtpp_session *pub;
225
226
22.8k
    pub = &(pvt->pub);
227
22.8k
    rtpp_timestamp_get(pvt->acct->destroy_ts);
228
22.8k
    session_time = pvt->acct->destroy_ts->mono - pvt->acct->init_ts->mono;
229
230
22.8k
    CALL_SMETHOD(pub->rtp, get_stats, &pvt->acct->rtp);
231
22.8k
    CALL_SMETHOD(pub->rtcp, get_stats, &pvt->acct->rtcp);
232
22.8k
    if (pub->complete != 0) {
233
18.2k
        CALL_SMETHOD(pub->rtp, upd_cntrs, &pvt->acct->rtp);
234
18.2k
        CALL_SMETHOD(pub->rtcp, upd_cntrs, &pvt->acct->rtcp);
235
18.2k
    }
236
22.8k
    RTPP_LOG(pub->log, RTPP_LOG_INFO, "session on ports %d/%d is cleaned up",
237
22.8k
      pub->rtp->stream[0]->port, pub->rtp->stream[1]->port);
238
68.4k
    for (i = 0; i < 2; i++) {
239
45.6k
        CALL_SMETHOD(pvt->sessinfo, remove, pub, i);
240
45.6k
    }
241
22.8k
    RTPP_OBJ_DECREF(pvt->sessinfo);
242
22.8k
    CALL_SMETHOD(pub->rtpp_stats, updatebyname, "nsess_destroyed", 1);
243
22.8k
    CALL_SMETHOD(pub->rtpp_stats, updatebyname_d, "total_duration",
244
22.8k
      session_time);
245
22.8k
    if (pvt->module_cf != NULL) {
246
22.8k
        pvt->acct->call_id = pvt->call_id.rw.s;
247
22.8k
        pvt->call_id.rw.s = NULL;
248
22.8k
        pvt->acct->from_tag = pvt->from_tag.rw.s;
249
22.8k
        pvt->from_tag.rw.s = NULL;
250
22.8k
        CALL_SMETHOD(pub->rtp->stream[0]->analyzer, get_stats, \
251
22.8k
          pvt->acct->rasto);
252
22.8k
        CALL_SMETHOD(pub->rtp->stream[1]->analyzer, get_stats, \
253
22.8k
          pvt->acct->rasta);
254
22.8k
        CALL_SMETHOD(pub->rtp->stream[0]->analyzer, get_jstats, \
255
22.8k
          pvt->acct->jrasto);
256
22.8k
        CALL_SMETHOD(pub->rtp->stream[1]->analyzer, get_jstats, \
257
22.8k
          pvt->acct->jrasta);
258
259
22.8k
        CALL_METHOD(pvt->module_cf, do_acct, pvt->acct);
260
22.8k
        RTPP_OBJ_DECREF(pvt->module_cf);
261
22.8k
    }
262
22.8k
    RTPP_OBJ_DECREF(pvt->acct);
263
264
22.8k
    RTPP_OBJ_DECREF(pvt->pub.log);
265
22.8k
    if (pvt->pub.timeout_data != NULL)
266
22.8k
        RTPP_OBJ_DECREF(pvt->pub.timeout_data);
267
22.8k
    if (pvt->call_id.rw.s != NULL)
268
0
        free(pvt->call_id.rw.s);
269
22.8k
    if (pvt->from_tag.rw.s != NULL)
270
0
        free(pvt->from_tag.rw.s);
271
22.8k
    if (pvt->from_tag_nmn.rw.s != NULL)
272
22.8k
        free(pvt->from_tag_nmn.rw.s);
273
274
22.8k
    RTPP_OBJ_DECREF(pvt->pub.rtcp);
275
22.8k
    RTPP_OBJ_DECREF(pvt->pub.rtp);
276
22.8k
}
277
278
int
279
compare_session_tags(const rtpp_str_t *tag1, const rtpp_str_t *tag0,
280
  unsigned *medianum_p)
281
13.6k
{
282
283
13.6k
    if (tag1->len < tag0->len)
284
0
        return 0;
285
13.6k
    if (!memcmp(tag1->s, tag0->s, tag0->len)) {
286
13.6k
        if (tag1->len == tag0->len)
287
9.12k
            return 1;
288
4.56k
  if (tag1->s[tag0->len] == ';') {
289
0
      if (medianum_p != NULL)
290
0
    *medianum_p = strtoul(tag1->s + tag0->len + 1, NULL, 10);
291
0
      return 2;
292
0
  }
293
4.56k
    }
294
4.56k
    return 0;
295
13.6k
}
296
297
struct session_match_args {
298
    const rtpp_str_t *from_tag;
299
    const rtpp_str_t *to_tag;
300
    struct rtpp_session *sp;
301
    int rval;
302
};
303
304
static int
305
rtpp_session_ematch(void *dp, void *ap)
306
18.2k
{
307
18.2k
    struct rtpp_session *rsp;
308
18.2k
    struct session_match_args *map;
309
18.2k
    const char *cp1, *cp2;
310
311
18.2k
    rsp = (struct rtpp_session *)dp;
312
18.2k
    map = (struct session_match_args *)ap;
313
314
18.2k
    if (rtpp_str_match(rsp->from_tag, map->from_tag)) {
315
4.56k
        map->rval = 0;
316
4.56k
        goto found;
317
4.56k
    }
318
13.6k
    if (map->to_tag != NULL) {
319
13.6k
        switch (compare_session_tags(rsp->from_tag, map->to_tag, NULL)) {
320
9.12k
        case 1:
321
            /* Exact tag match */
322
9.12k
            map->rval = 1;
323
9.12k
            goto found;
324
325
0
        case 2:
326
            /*
327
             * Reverse tag match without medianum. Medianum is always
328
             * applied to the from tag, verify that.
329
             */
330
0
            cp1 = strrchr(rsp->from_tag->s, ';');
331
0
            cp2 = strrchr(map->from_tag->s, ';');
332
0
            if (cp2 != NULL && strcmp(cp1, cp2) == 0) {
333
0
                map->rval = 1;
334
0
                goto found;
335
0
            }
336
0
            break;
337
338
4.56k
        default:
339
4.56k
            break;
340
13.6k
        }
341
13.6k
    }
342
4.56k
    return (RTPP_HT_MATCH_CONT);
343
344
13.6k
found:
345
13.6k
    RTPP_OBJ_INCREF(rsp);
346
13.6k
    RTPP_DBG_ASSERT(map->sp == NULL);
347
13.6k
    map->sp = rsp;
348
13.6k
    return (RTPP_HT_MATCH_BRK);
349
13.6k
}
350
351
int
352
find_stream(const struct rtpp_cfg *cfsp, const rtpp_str_t *call_id,
353
  const rtpp_str_t *from_tag, const rtpp_str_t *to_tag, struct rtpp_session **spp)
354
36.4k
{
355
36.4k
    struct session_match_args ma;
356
357
36.4k
    memset(&ma, '\0', sizeof(ma));
358
36.4k
    ma.from_tag = from_tag;
359
36.4k
    ma.to_tag = to_tag;
360
36.4k
    ma.rval = -1;
361
362
36.4k
    CALL_SMETHOD(cfsp->sessions_ht, foreach_key_str, call_id,
363
36.4k
      rtpp_session_ematch, &ma);
364
36.4k
    if (ma.rval != -1) {
365
13.6k
        *spp = ma.sp;
366
13.6k
    }
367
36.4k
    return ma.rval;
368
36.4k
}