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