/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 | } |