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 #include <sys/types.h>
30 #include <sys/socket.h>
31 #include <stdint.h>
32 #include <stdlib.h>
33 #include <string.h>
34
35 #include "rtpp_debug.h"
36 #include "rtpp_types.h"
37 #include "rtpp_log.h"
38 #include "rtpp_log_obj.h"
39 #include "rtpp_cfg_stable.h"
40 #include "rtpp_defines.h"
41 #include "rtpp_acct_pipe.h"
42 #include "rtpp_acct.h"
43 #include "rtpp_analyzer.h"
44 #include "rtpp_command_private.h"
45 #include "rtpp_genuid_singlet.h"
46 #include "rtpp_hash_table.h"
47 #include "rtpp_mallocs.h"
48 #include "rtpp_module_if.h"
49 #include "rtpp_pipe.h"
50 #include "rtpp_socket.h"
51 #include "rtpp_stream.h"
52 #include "rtpp_session.h"
53 #include "rtpp_sessinfo.h"
54 #include "rtpp_stats.h"
55 #include "rtpp_time.h"
56 #include "rtpp_ttl.h"
57 #include "rtpp_refcnt.h"
58
59 struct rtpp_session_priv
60 {
61 struct rtpp_session pub;
62 struct rtpp_sessinfo *sessinfo;
63 struct rtpp_module_if *modules_cf;
64 struct rtpp_acct *acct;
65 };
66
67 #define PUB2PVT(pubp) \
68 ((struct rtpp_session_priv *)((char *)(pubp) - offsetof(struct rtpp_session_priv, pub)))
69
70 static void rtpp_session_dtor(struct rtpp_session_priv *);
71
72 struct rtpp_session *
rtpp_session_ctor(struct rtpp_cfg_stable * cfs,struct common_cmd_args * ccap,double dtime,struct sockaddr ** lia,int weak,int lport,struct rtpp_socket ** fds)73 rtpp_session_ctor(struct rtpp_cfg_stable *cfs, struct common_cmd_args *ccap,
74 double dtime, struct sockaddr **lia, int weak, int lport,
75 struct rtpp_socket **fds)
76 {
77 struct rtpp_session_priv *pvt;
78 struct rtpp_session *pub;
79 struct rtpp_log *log;
80 struct rtpp_refcnt *rcnt;
81 int i;
82 char *cp;
83
84 pvt = rtpp_rzmalloc(sizeof(struct rtpp_session_priv), &rcnt);
85 if (pvt == NULL) {
86 goto e0;
87 }
88
89 pub = &(pvt->pub);
90 pub->rcnt = rcnt;
91 rtpp_gen_uid(&pub->seuid);
92
93 log = rtpp_log_ctor(cfs, "rtpproxy", ccap->call_id, 0);
94 if (log == NULL) {
95 goto e1;
96 }
97 CALL_METHOD(log, setlevel, cfs->log_level);
98 pub->rtp = rtpp_pipe_ctor(pub->seuid, cfs->rtp_streams_wrt,
99 cfs->servers_wrt, log, cfs->rtpp_stats, PIPE_RTP);
100 if (pub->rtp == NULL) {
101 goto e2;
102 }
103 /* spb is RTCP twin session for this one. */
104 pub->rtcp = rtpp_pipe_ctor(pub->seuid, cfs->rtcp_streams_wrt,
105 cfs->servers_wrt, log, cfs->rtpp_stats, PIPE_RTCP);
106 if (pub->rtcp == NULL) {
107 goto e3;
108 }
109 pvt->acct = rtpp_acct_ctor(pub->seuid);
110 if (pvt->acct == NULL) {
111 goto e4;
112 }
113 pvt->acct->init_ts = dtime;
114 pub->call_id = strdup(ccap->call_id);
115 if (pub->call_id == NULL) {
116 goto e5;
117 }
118 pub->tag = strdup(ccap->from_tag);
119 if (pub->tag == NULL) {
120 goto e6;
121 }
122 pub->tag_nomedianum = strdup(ccap->from_tag);
123 if (pub->tag_nomedianum == NULL) {
124 goto e7;
125 }
126 cp = strrchr(pub->tag_nomedianum, ';');
127 if (cp != NULL)
128 *cp = '\0';
129 for (i = 0; i < 2; i++) {
130 pub->rtp->stream[i]->laddr = lia[i];
131 pub->rtcp->stream[i]->laddr = lia[i];
132 }
133 if (weak) {
134 pub->rtp->stream[0]->weak = 1;
135 } else {
136 pub->strong = 1;
137 }
138
139 pub->rtp->stream[0]->port = lport;
140 pub->rtcp->stream[0]->port = lport + 1;
141 for (i = 0; i < 2; i++) {
142 if (i == 0 || cfs->ttl_mode == TTL_INDEPENDENT) {
143 pub->rtp->stream[i]->ttl = rtpp_ttl_ctor(cfs->max_setup_ttl);
144 if (pub->rtp->stream[i]->ttl == NULL) {
145 goto e8;
146 }
147 } else {
148 pub->rtp->stream[i]->ttl = pub->rtp->stream[0]->ttl;
149 CALL_SMETHOD(pub->rtp->stream[0]->ttl->rcnt, incref);
150 }
151 /* RTCP shares the same TTL */
152 pub->rtcp->stream[i]->ttl = pub->rtp->stream[i]->ttl;
153 CALL_SMETHOD(pub->rtp->stream[i]->ttl->rcnt, incref);
154 }
155 for (i = 0; i < 2; i++) {
156 pub->rtp->stream[i]->stuid_rtcp = pub->rtcp->stream[i]->stuid;
157 pub->rtcp->stream[i]->stuid_rtp = pub->rtp->stream[i]->stuid;
158 }
159
160 pvt->pub.rtpp_stats = cfs->rtpp_stats;
161 pvt->pub.log = log;
162 pvt->sessinfo = cfs->sessinfo;
163 if (cfs->modules_cf != NULL) {
164 CALL_SMETHOD(cfs->modules_cf->rcnt, incref);
165 pvt->modules_cf = cfs->modules_cf;
166 }
167
168 CALL_METHOD(cfs->sessinfo, append, pub, 0, fds);
169
170 CALL_SMETHOD(pub->rcnt, attach, (rtpp_refcnt_dtor_t)&rtpp_session_dtor,
171 pvt);
172 return (&pvt->pub);
173
174 e8:
175 free(pub->tag_nomedianum);
176 e7:
177 free(pub->tag);
178 e6:
179 free(pub->call_id);
180 e5:
181 CALL_SMETHOD(pvt->acct->rcnt, decref);
182 e4:
183 CALL_SMETHOD(pub->rtcp->rcnt, decref);
184 e3:
185 CALL_SMETHOD(pub->rtp->rcnt, decref);
186 e2:
187 CALL_SMETHOD(log->rcnt, decref);
188 e1:
189 CALL_SMETHOD(pub->rcnt, decref);
190 free(pvt);
191 e0:
192 return (NULL);
193 }
194
195 #define MT2RT_NZ(mt) ((mt) == 0.0 ? 0.0 : dtime2rtime(mt))
196 #define DRTN_NZ(bmt, emt) ((emt) == 0.0 || (bmt) == 0.0 ? 0.0 : ((emt) - (bmt)))
197
198 static void
rtpp_session_dtor(struct rtpp_session_priv * pvt)199 rtpp_session_dtor(struct rtpp_session_priv *pvt)
200 {
201 int i;
202 double session_time;
203 struct rtpp_session *pub;
204
205 pub = &(pvt->pub);
206 pvt->acct->destroy_ts = getdtime();
207 session_time = pvt->acct->destroy_ts - pvt->acct->init_ts;
208
209 CALL_METHOD(pub->rtp, get_stats, &pvt->acct->rtp);
210 CALL_METHOD(pub->rtcp, get_stats, &pvt->acct->rtcp);
211 if (pub->complete != 0) {
212 CALL_METHOD(pub->rtp, upd_cntrs, &pvt->acct->rtp);
213 CALL_METHOD(pub->rtcp, upd_cntrs, &pvt->acct->rtcp);
214 }
215 RTPP_LOG(pub->log, RTPP_LOG_INFO, "session on ports %d/%d is cleaned up",
216 pub->rtp->stream[0]->port, pub->rtp->stream[1]->port);
217 for (i = 0; i < 2; i++) {
218 CALL_METHOD(pvt->sessinfo, remove, pub, i);
219 }
220 CALL_METHOD(pub->rtpp_stats, updatebyname, "nsess_destroyed", 1);
221 CALL_METHOD(pub->rtpp_stats, updatebyname_d, "total_duration",
222 session_time);
223 if (pvt->modules_cf != NULL) {
224 pvt->acct->call_id = pvt->pub.call_id;
225 pvt->pub.call_id = NULL;
226 pvt->acct->from_tag = pvt->pub.tag;
227 pvt->pub.tag = NULL;
228 CALL_METHOD(pub->rtp->stream[0]->analyzer, get_stats, \
229 pvt->acct->rasto);
230 CALL_METHOD(pub->rtp->stream[1]->analyzer, get_stats, \
231 pvt->acct->rasta);
232 CALL_METHOD(pub->rtp->stream[0]->analyzer, get_jstats, \
233 pvt->acct->jrasto);
234 CALL_METHOD(pub->rtp->stream[1]->analyzer, get_jstats, \
235 pvt->acct->jrasta);
236
237 CALL_METHOD(pvt->modules_cf, do_acct, pvt->acct);
238 CALL_SMETHOD(pvt->modules_cf->rcnt, decref);
239 }
240 CALL_SMETHOD(pvt->acct->rcnt, decref);
241
242 CALL_SMETHOD(pvt->pub.log->rcnt, decref);
243 if (pvt->pub.timeout_data.notify_tag != NULL)
244 free(pvt->pub.timeout_data.notify_tag);
245 if (pvt->pub.call_id != NULL)
246 free(pvt->pub.call_id);
247 if (pvt->pub.tag != NULL)
248 free(pvt->pub.tag);
249 if (pvt->pub.tag_nomedianum != NULL)
250 free(pvt->pub.tag_nomedianum);
251
252 CALL_SMETHOD(pvt->pub.rtcp->rcnt, decref);
253 CALL_SMETHOD(pvt->pub.rtp->rcnt, decref);
254 free(pvt);
255 }
256
257 int
compare_session_tags(const char * tag1,const char * tag0,unsigned * medianum_p)258 compare_session_tags(const char *tag1, const char *tag0, unsigned *medianum_p)
259 {
260 size_t len0 = strlen(tag0);
261
262 if (!strncmp(tag1, tag0, len0)) {
263 if (tag1[len0] == ';') {
264 if (medianum_p != NULL)
265 *medianum_p = strtoul(tag1 + len0 + 1, NULL, 10);
266 return 2;
267 }
268 if (tag1[len0] == '\0')
269 return 1;
270 return 0;
271 }
272 return 0;
273 }
274
275 struct session_match_args {
276 const char *from_tag;
277 const char *to_tag;
278 struct rtpp_session *sp;
279 int rval;
280 };
281
282 static int
rtpp_session_ematch(void * dp,void * ap)283 rtpp_session_ematch(void *dp, void *ap)
284 {
285 struct rtpp_session *rsp;
286 struct session_match_args *map;
287 const char *cp1, *cp2;
288
289 rsp = (struct rtpp_session *)dp;
290 map = (struct session_match_args *)ap;
291
292 if (strcmp(rsp->tag, map->from_tag) == 0) {
293 map->rval = 0;
294 goto found;
295 }
296 if (map->to_tag != NULL) {
297 switch (compare_session_tags(rsp->tag, map->to_tag, NULL)) {
298 case 1:
299 /* Exact tag match */
300 map->rval = 1;
301 goto found;
302
303 case 2:
304 /*
305 * Reverse tag match without medianum. Medianum is always
306 * applied to the from tag, verify that.
307 */
308 cp1 = strrchr(rsp->tag, ';');
309 cp2 = strrchr(map->from_tag, ';');
310 if (cp2 != NULL && strcmp(cp1, cp2) == 0) {
311 map->rval = 1;
312 goto found;
313 }
314 break;
315
316 default:
317 break;
318 }
319 }
320 return (RTPP_HT_MATCH_CONT);
321
322 found:
323 CALL_SMETHOD(rsp->rcnt, incref);
324 RTPP_DBG_ASSERT(map->sp == NULL);
325 map->sp = rsp;
326 return (RTPP_HT_MATCH_BRK);
327 }
328
329 int
find_stream(struct cfg * cf,const char * call_id,const char * from_tag,const char * to_tag,struct rtpp_session ** spp)330 find_stream(struct cfg *cf, const char *call_id, const char *from_tag,
331 const char *to_tag, struct rtpp_session **spp)
332 {
333 struct session_match_args ma;
334
335 memset(&ma, '\0', sizeof(ma));
336 ma.from_tag = from_tag;
337 ma.to_tag = to_tag;
338 ma.rval = -1;
339
340 CALL_METHOD(cf->stable->sessions_ht, foreach_key, call_id,
341 rtpp_session_ematch, &ma);
342 if (ma.rval != -1) {
343 *spp = ma.sp;
344 }
345 return ma.rval;
346 }
347