|
@@ -184,7 +184,6 @@
|
|
|
|
|
|
#include "nhelpr_funcs.h"
|
|
|
#include "nathelper.h"
|
|
|
-#include "rtpproxy_stream.h"
|
|
|
#include "../../flags.h"
|
|
|
#include "../../sr_module.h"
|
|
|
#include "../../dprint.h"
|
|
@@ -240,42 +239,15 @@ MODULE_VERSION
|
|
|
#define NAT_UAC_TEST_RPORT 0x10
|
|
|
#define NAT_UAC_TEST_C_PORT 0x20
|
|
|
|
|
|
-/* Supported version of the RTP proxy command protocol */
|
|
|
-#define SUP_CPROTOVER 20040107
|
|
|
-/* Required additional version of the RTP proxy command protocol */
|
|
|
-#define REQ_CPROTOVER "20050322"
|
|
|
-/* Additional version necessary for re-packetization support */
|
|
|
-#define REP_CPROTOVER "20071116"
|
|
|
-#define PTL_CPROTOVER "20081102"
|
|
|
-#define CPORT "22222"
|
|
|
-
|
|
|
-struct rtpp_head;
|
|
|
|
|
|
static int nat_uac_test_f(struct sip_msg* msg, char* str1, char* str2);
|
|
|
static int fix_nated_contact_f(struct sip_msg *, char *, char *);
|
|
|
static int fix_nated_sdp_f(struct sip_msg *, char *, char *);
|
|
|
static int extract_mediaip(str *, str *, int *);
|
|
|
-static int extract_mediainfo(str *, str *, str *);
|
|
|
static int alter_mediaip(struct sip_msg *, str *, str *, int, str *, int, int);
|
|
|
-static int alter_mediaport(struct sip_msg *, str *, str *, str *, int);
|
|
|
-static char *gencookie();
|
|
|
-static int rtpp_test(struct rtpp_node*, int, int);
|
|
|
-static int unforce_rtp_proxy0_f(struct sip_msg *, char *, char *);
|
|
|
-static int unforce_rtp_proxy1_f(struct sip_msg *, char *, char *);
|
|
|
-static int start_recording0_f(struct sip_msg *, char *, char *);
|
|
|
-static int start_recording1_f(struct sip_msg *, char *, char *);
|
|
|
-static int force_rtp_proxy(struct sip_msg *, char *, char *, int);
|
|
|
-static int force_rtp_proxy1_f(struct sip_msg *, char *, char *);
|
|
|
-static int force_rtp_proxy2_f(struct sip_msg *, char *, char *);
|
|
|
static int fix_nated_register_f(struct sip_msg *, char *, char *);
|
|
|
-static char *find_sdp_line(char *, char *, char);
|
|
|
-static char *find_next_sdp_line(char *, char *, char, char *);
|
|
|
static int fixup_ping_contact(void **param, int param_no);
|
|
|
static int ping_contact_f(struct sip_msg* msg, char* str1, char* str2);
|
|
|
-static int rtpproxy_answer1_f(struct sip_msg *, char *, char *);
|
|
|
-static int rtpproxy_answer2_f(struct sip_msg *, char *, char *);
|
|
|
-static int rtpproxy_offer1_f(struct sip_msg *, char *, char *);
|
|
|
-static int rtpproxy_offer2_f(struct sip_msg *, char *, char *);
|
|
|
|
|
|
static int mod_init(void);
|
|
|
static void mod_cleanup(void);
|
|
@@ -295,63 +267,14 @@ static struct {
|
|
|
{NULL, 0, 0}
|
|
|
};
|
|
|
|
|
|
-static struct {
|
|
|
- const char *s;
|
|
|
- int len;
|
|
|
- int is_rtp;
|
|
|
-} sup_ptypes[] = {
|
|
|
- {.s = "udp", .len = 3, .is_rtp = 0},
|
|
|
- {.s = "udptl", .len = 5, .is_rtp = 0},
|
|
|
- {.s = "rtp/avp", .len = 7, .is_rtp = 1},
|
|
|
- {.s = "rtp/avpf", .len = 8, .is_rtp = 1},
|
|
|
- {.s = "rtp/savp", .len = 8, .is_rtp = 1},
|
|
|
- {.s = "rtp/savpf", .len = 9, .is_rtp = 1},
|
|
|
- {.s = "udp/bfcp", .len = 8, .is_rtp = 0},
|
|
|
- {.s = NULL, .len = 0, .is_rtp = 0}
|
|
|
-};
|
|
|
-
|
|
|
-static char *rtpproxy_sock = "unix:/var/run/rtpproxy.sock"; /* list */
|
|
|
static char *force_socket_str = 0;
|
|
|
-static int rtpproxy_disable = 0;
|
|
|
-static int rtpproxy_disable_tout = 60;
|
|
|
-static int rtpproxy_retr = 5;
|
|
|
-static int rtpproxy_tout = 1;
|
|
|
-static pid_t mypid;
|
|
|
-static unsigned int myseqn = 0;
|
|
|
-
|
|
|
-
|
|
|
-struct rtpp_head {
|
|
|
- struct rtpp_node *rn_first;
|
|
|
- struct rtpp_node *rn_last;
|
|
|
-};
|
|
|
-
|
|
|
-/* RTP proxy balancing list */
|
|
|
-static struct rtpp_head rtpp_list;
|
|
|
-static int rtpp_node_count = 0;
|
|
|
|
|
|
static cmd_export_t cmds[] = {
|
|
|
{"fix_nated_contact", fix_nated_contact_f, 0, NULL, REQUEST_ROUTE | ONREPLY_ROUTE },
|
|
|
{"fix_nated_sdp", fix_nated_sdp_f, 1, fixup_int_1, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE },
|
|
|
- {"unforce_rtp_proxy", unforce_rtp_proxy0_f, 0, NULL, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE },
|
|
|
- {"unforce_rtp_proxy", unforce_rtp_proxy1_f, 1, fixup_var_str_1, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE },
|
|
|
- {"force_rtp_proxy", force_rtp_proxy1_f, 0, NULL, REQUEST_ROUTE | ONREPLY_ROUTE },
|
|
|
- {"force_rtp_proxy", force_rtp_proxy1_f, 1, fixup_var_str_1, REQUEST_ROUTE | ONREPLY_ROUTE },
|
|
|
- {"force_rtp_proxy", force_rtp_proxy2_f, 2, fixup_var_str_12, REQUEST_ROUTE | ONREPLY_ROUTE },
|
|
|
{"nat_uac_test", nat_uac_test_f, 1, fixup_int_1, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE },
|
|
|
{"fix_nated_register", fix_nated_register_f, 0, NULL, REQUEST_ROUTE },
|
|
|
{"ping_contact", ping_contact_f, 1, fixup_ping_contact, REQUEST_ROUTE },
|
|
|
- {"start_recording", start_recording0_f, 0, NULL, REQUEST_ROUTE | ONREPLY_ROUTE },
|
|
|
- {"start_recording", start_recording1_f, 1, fixup_var_str_1, REQUEST_ROUTE | ONREPLY_ROUTE },
|
|
|
- {"rtpproxy_offer", rtpproxy_offer1_f, 0, NULL, REQUEST_ROUTE | ONREPLY_ROUTE },
|
|
|
- {"rtpproxy_offer", rtpproxy_offer1_f, 1, fixup_var_str_1, REQUEST_ROUTE | ONREPLY_ROUTE },
|
|
|
- {"rtpproxy_offer", rtpproxy_offer2_f, 2, fixup_var_str_12, REQUEST_ROUTE | ONREPLY_ROUTE },
|
|
|
- {"rtpproxy_answer", rtpproxy_answer1_f, 0, NULL, REQUEST_ROUTE | ONREPLY_ROUTE },
|
|
|
- {"rtpproxy_answer", rtpproxy_answer1_f, 1, fixup_var_str_1, REQUEST_ROUTE | ONREPLY_ROUTE },
|
|
|
- {"rtpproxy_answer", rtpproxy_answer2_f, 2, fixup_var_str_12, REQUEST_ROUTE | ONREPLY_ROUTE },
|
|
|
- {"rtpproxy_stream2uac",rtpproxy_stream2uac2_f, 2, fixup_var_str_int, REQUEST_ROUTE | ONREPLY_ROUTE },
|
|
|
- {"rtpproxy_stream2uas",rtpproxy_stream2uas2_f, 2, fixup_var_str_int, REQUEST_ROUTE | ONREPLY_ROUTE },
|
|
|
- {"rtpproxy_stop_stream2uac",rtpproxy_stop_stream2uac2_f, 0, NULL, REQUEST_ROUTE | ONREPLY_ROUTE },
|
|
|
- {"rtpproxy_stop_stream2uas",rtpproxy_stop_stream2uas2_f, 0, NULL, REQUEST_ROUTE | ONREPLY_ROUTE },
|
|
|
{0, 0, 0, 0, 0}
|
|
|
};
|
|
|
|
|
@@ -361,11 +284,6 @@ static param_export_t params[] = {
|
|
|
{"natping_method", PARAM_STRING, &natping_method },
|
|
|
{"natping_stateful", PARAM_INT, &natping_stateful },
|
|
|
{"ping_nated_only", PARAM_INT, &ping_nated_only },
|
|
|
- {"rtpproxy_sock", PARAM_STRING, &rtpproxy_sock },
|
|
|
- {"rtpproxy_disable", PARAM_INT, &rtpproxy_disable },
|
|
|
- {"rtpproxy_disable_tout", PARAM_INT, &rtpproxy_disable_tout },
|
|
|
- {"rtpproxy_retr", PARAM_INT, &rtpproxy_retr },
|
|
|
- {"rtpproxy_tout", PARAM_INT, &rtpproxy_tout },
|
|
|
{"force_socket", PARAM_STRING, &force_socket_str },
|
|
|
{0, 0, 0}
|
|
|
};
|
|
@@ -428,74 +346,6 @@ mod_init(void)
|
|
|
nets_1918[i].netaddr = ntohl(addr.s_addr) & nets_1918[i].mask;
|
|
|
}
|
|
|
|
|
|
- memset(&rtpp_list, 0, sizeof(rtpp_list));
|
|
|
- rtpp_node_count = 0;
|
|
|
- if (rtpproxy_disable == 0) {
|
|
|
- /* Make rtp proxies list. */
|
|
|
- char *p, *p1, *p2, *plim;
|
|
|
-
|
|
|
- p = rtpproxy_sock;
|
|
|
- plim = p + strlen(p);
|
|
|
- for(;;) {
|
|
|
- struct rtpp_node *pnode;
|
|
|
- int weight;
|
|
|
-
|
|
|
- weight = 1;
|
|
|
- while (*p && isspace((unsigned char)*p))
|
|
|
- ++p;
|
|
|
- if (p >= plim)
|
|
|
- break;
|
|
|
- p1 = p;
|
|
|
- while (*p && !isspace((unsigned char)*p))
|
|
|
- ++p;
|
|
|
- if (p <= p1)
|
|
|
- break; /* may happen??? */
|
|
|
- /* Have weight specified? If yes, scan it */
|
|
|
- p2 = memchr(p1, '=', p - p1);
|
|
|
- if (p2 != NULL) {
|
|
|
- weight = strtoul(p2 + 1, NULL, 10);
|
|
|
- } else {
|
|
|
- p2 = p;
|
|
|
- }
|
|
|
- pnode = pkg_malloc(sizeof(struct rtpp_node));
|
|
|
- if (pnode == NULL) {
|
|
|
- LOG(L_ERR, "nathelper: Can't allocate memory\n");
|
|
|
- return -1;
|
|
|
- }
|
|
|
- memset(pnode, 0, sizeof(*pnode));
|
|
|
- pnode->rn_recheck_ticks = 0;
|
|
|
- pnode->rn_weight = weight;
|
|
|
- pnode->rn_umode = 0;
|
|
|
- pnode->rn_fd = -1;
|
|
|
- pnode->rn_disabled = 0;
|
|
|
- pnode->rn_url = pkg_malloc(p2 - p1 + 1);
|
|
|
- if (pnode->rn_url == NULL) {
|
|
|
- LOG(L_ERR, "nathelper: Can't allocate memory\n");
|
|
|
- return -1;
|
|
|
- }
|
|
|
- memmove(pnode->rn_url, p1, p2 - p1);
|
|
|
- pnode->rn_url[p2 - p1] = 0;
|
|
|
- if (rtpp_list.rn_first == NULL) {
|
|
|
- rtpp_list.rn_first = pnode;
|
|
|
- } else {
|
|
|
- rtpp_list.rn_last->rn_next = pnode;
|
|
|
- }
|
|
|
- rtpp_list.rn_last = pnode;
|
|
|
- ++rtpp_node_count;
|
|
|
- /* Leave only address in rn_address */
|
|
|
- pnode->rn_address = pnode->rn_url;
|
|
|
- if (strncmp(pnode->rn_address, "udp:", 4) == 0) {
|
|
|
- pnode->rn_umode = 1;
|
|
|
- pnode->rn_address += 4;
|
|
|
- } else if (strncmp(pnode->rn_address, "udp6:", 5) == 0) {
|
|
|
- pnode->rn_umode = 6;
|
|
|
- pnode->rn_address += 5;
|
|
|
- } else if (strncmp(pnode->rn_address, "unix:", 5) == 0) {
|
|
|
- pnode->rn_umode = 0;
|
|
|
- pnode->rn_address += 5;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
register_select_table(sel_declaration);
|
|
|
return 0;
|
|
|
}
|
|
@@ -510,68 +360,9 @@ mod_cleanup(void)
|
|
|
static int
|
|
|
child_init(int rank)
|
|
|
{
|
|
|
- int n;
|
|
|
- char *cp;
|
|
|
- struct addrinfo hints, *res;
|
|
|
- struct rtpp_node *pnode;
|
|
|
-
|
|
|
if (natpinger_child_init(rank) < 0)
|
|
|
return -1;
|
|
|
|
|
|
- /* Iterate known RTP proxies - create sockets */
|
|
|
- mypid = getpid();
|
|
|
- for (pnode = rtpp_list.rn_first; pnode != NULL; pnode = pnode->rn_next) {
|
|
|
- char *old_colon;
|
|
|
-
|
|
|
- if (pnode->rn_umode == 0)
|
|
|
- goto rptest;
|
|
|
- /*
|
|
|
- * This is UDP or UDP6. Detect host and port; lookup host;
|
|
|
- * do connect() in order to specify peer address
|
|
|
- */
|
|
|
- old_colon = cp = strrchr(pnode->rn_address, ':');
|
|
|
- if (cp != NULL) {
|
|
|
- old_colon = cp;
|
|
|
- *cp = '\0';
|
|
|
- cp++;
|
|
|
- }
|
|
|
- if (cp == NULL || *cp == '\0')
|
|
|
- cp = CPORT;
|
|
|
-
|
|
|
- memset(&hints, 0, sizeof(hints));
|
|
|
- hints.ai_flags = 0;
|
|
|
- hints.ai_family = (pnode->rn_umode == 6) ? AF_INET6 : AF_INET;
|
|
|
- hints.ai_socktype = SOCK_DGRAM;
|
|
|
- if ((n = getaddrinfo(pnode->rn_address, cp, &hints, &res)) != 0) {
|
|
|
- LOG(L_ERR, "nathelper: getaddrinfo: %s\n", gai_strerror(n));
|
|
|
- return -1;
|
|
|
- }
|
|
|
- if (old_colon)
|
|
|
- *old_colon = ':'; /* restore rn_address */
|
|
|
-
|
|
|
- pnode->rn_fd = socket((pnode->rn_umode == 6)
|
|
|
- ? AF_INET6 : AF_INET, SOCK_DGRAM, 0);
|
|
|
- if (pnode->rn_fd == -1) {
|
|
|
- LOG(L_ERR, "nathelper: can't create socket\n");
|
|
|
- freeaddrinfo(res);
|
|
|
- return -1;
|
|
|
- }
|
|
|
-
|
|
|
- if (connect(pnode->rn_fd, res->ai_addr, res->ai_addrlen) == -1) {
|
|
|
- LOG(L_ERR, "nathelper: can't connect to a RTP proxy\n");
|
|
|
- close(pnode->rn_fd);
|
|
|
- pnode->rn_fd = -1;
|
|
|
- freeaddrinfo(res);
|
|
|
- return -1;
|
|
|
- }
|
|
|
- freeaddrinfo(res);
|
|
|
-rptest:
|
|
|
- pnode->rn_disabled = rtpp_test(pnode, 0, 1);
|
|
|
- }
|
|
|
-
|
|
|
- if (rtpproxy_disable)
|
|
|
- rtpproxy_disable_tout = -1;
|
|
|
-
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -1043,118 +834,6 @@ extract_mediaip(str *body, str *mediaip, int *pf)
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
|
-static int
|
|
|
-extract_mediainfo(str *body, str *mediaport, str *payload_types)
|
|
|
-{
|
|
|
- char *cp, *cp1;
|
|
|
- int len, i;
|
|
|
- str ptype;
|
|
|
-
|
|
|
- cp1 = NULL;
|
|
|
- for (cp = body->s; (len = body->s + body->len - cp) > 0;) {
|
|
|
- cp1 = ser_memmem(cp, "m=", len, 2);
|
|
|
- if (cp1 == NULL || cp1[-1] == '\n' || cp1[-1] == '\r')
|
|
|
- break;
|
|
|
- cp = cp1 + 2;
|
|
|
- }
|
|
|
- if (cp1 == NULL) {
|
|
|
- LOG(L_ERR, "ERROR: extract_mediainfo: no `m=' in SDP\n");
|
|
|
- return -1;
|
|
|
- }
|
|
|
- mediaport->s = cp1 + 2; /* skip `m=' */
|
|
|
- mediaport->len = eat_line(mediaport->s, body->s + body->len -
|
|
|
- mediaport->s) - mediaport->s;
|
|
|
- trim_len(mediaport->len, mediaport->s, *mediaport);
|
|
|
-
|
|
|
- /* Skip media supertype and spaces after it */
|
|
|
- cp = eat_token_end(mediaport->s, mediaport->s + mediaport->len);
|
|
|
- mediaport->len -= cp - mediaport->s;
|
|
|
- if (mediaport->len <= 0 || cp == mediaport->s) {
|
|
|
- LOG(L_ERR, "ERROR: extract_mediainfo: no port in `m='\n");
|
|
|
- return -1;
|
|
|
- }
|
|
|
- mediaport->s = cp;
|
|
|
- cp = eat_space_end(mediaport->s, mediaport->s + mediaport->len);
|
|
|
- mediaport->len -= cp - mediaport->s;
|
|
|
- if (mediaport->len <= 0 || cp == mediaport->s) {
|
|
|
- LOG(L_ERR, "ERROR: extract_mediainfo: no port in `m='\n");
|
|
|
- return -1;
|
|
|
- }
|
|
|
- /* Extract port */
|
|
|
- mediaport->s = cp;
|
|
|
- cp = eat_token_end(mediaport->s, mediaport->s + mediaport->len);
|
|
|
- ptype.len = mediaport->len - (cp - mediaport->s);
|
|
|
- if (ptype.len <= 0 || cp == mediaport->s) {
|
|
|
- LOG(L_ERR, "ERROR: extract_mediainfo: no port in `m='\n");
|
|
|
- return -1;
|
|
|
- }
|
|
|
- ptype.s = cp;
|
|
|
- mediaport->len = cp - mediaport->s;
|
|
|
- /* Skip spaces after port */
|
|
|
- cp = eat_space_end(ptype.s, ptype.s + ptype.len);
|
|
|
- ptype.len -= cp - ptype.s;
|
|
|
- if (ptype.len <= 0 || cp == ptype.s) {
|
|
|
- LOG(L_ERR, "ERROR: extract_mediainfo: no protocol type in `m='\n");
|
|
|
- return -1;
|
|
|
- }
|
|
|
- /* Extract protocol type */
|
|
|
- ptype.s = cp;
|
|
|
- cp = eat_token_end(ptype.s, ptype.s + ptype.len);
|
|
|
- if (cp == ptype.s) {
|
|
|
- LOG(L_ERR, "ERROR: extract_mediainfo: no protocol type in `m='\n");
|
|
|
- return -1;
|
|
|
- }
|
|
|
- payload_types->len = ptype.len - (cp - ptype.s);
|
|
|
- ptype.len = cp - ptype.s;
|
|
|
- payload_types->s = cp;
|
|
|
-
|
|
|
- for (i = 0; sup_ptypes[i].s != NULL; i++) {
|
|
|
- if (ptype.len != sup_ptypes[i].len ||
|
|
|
- strncasecmp(ptype.s, sup_ptypes[i].s, ptype.len) != 0)
|
|
|
- continue;
|
|
|
- if (sup_ptypes[i].is_rtp == 0) {
|
|
|
- payload_types->len = 0;
|
|
|
- return 0;
|
|
|
- }
|
|
|
- cp = eat_space_end(payload_types->s, payload_types->s +
|
|
|
- payload_types->len);
|
|
|
- if (cp == payload_types->s) {
|
|
|
- LOG(L_ERR, "ERROR: extract_mediainfo: no payload types in `m='\n");
|
|
|
- return -1;
|
|
|
- }
|
|
|
- payload_types->len -= cp - payload_types->s;
|
|
|
- payload_types->s = cp;
|
|
|
- return 0;
|
|
|
- }
|
|
|
- /* Unproxyable protocol type. Generally it isn't error. */
|
|
|
- return -1;
|
|
|
-}
|
|
|
-
|
|
|
-static int
|
|
|
-extract_rtcp(str *body, str *rtcpport)
|
|
|
-{
|
|
|
- char *cp, *cp1;
|
|
|
- int len;
|
|
|
-
|
|
|
- cp1 = NULL;
|
|
|
- for (cp = body->s; (len = body->s + body->len - cp) > 0;) {
|
|
|
- cp1 = ser_memmem(cp, "a=rtcp:", len, 7);
|
|
|
- if (cp1 == NULL || cp1[-1] == '\n' || cp1[-1] == '\r')
|
|
|
- break;
|
|
|
- cp = cp1 + 7;
|
|
|
- }
|
|
|
-
|
|
|
- if (cp1 == NULL)
|
|
|
- return -1;
|
|
|
-
|
|
|
- rtcpport->s = cp1 + 7; /* skip `a=rtcp:' */
|
|
|
- rtcpport->len = eat_line(rtcpport->s, body->s + body->len -
|
|
|
- rtcpport->s) - rtcpport->s;
|
|
|
- trim_len(rtcpport->len, rtcpport->s, *rtcpport);
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
static int
|
|
|
alter_mediaip(struct sip_msg *msg, str *body, str *oldip, int oldpf,
|
|
|
str *newip, int newpf, int preserve)
|
|
@@ -1269,1251 +948,11 @@ alter_mediaip(struct sip_msg *msg, str *body, str *oldip, int oldpf,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static int
|
|
|
-alter_mediaport(struct sip_msg *msg, str *body, str *oldport, str *newport,
|
|
|
- int preserve)
|
|
|
-{
|
|
|
- char *buf;
|
|
|
- int offset;
|
|
|
- struct lump* anchor;
|
|
|
-
|
|
|
- /* check that updating mediaport is really necessary */
|
|
|
- if (newport->len == oldport->len &&
|
|
|
- memcmp(newport->s, oldport->s, newport->len) == 0)
|
|
|
- return 0;
|
|
|
-
|
|
|
- /*
|
|
|
- * Since rewriting the same info twice will mess SDP up,
|
|
|
- * apply simple anti foot shooting measure - put flag on
|
|
|
- * messages that have been altered and check it when
|
|
|
- * another request comes.
|
|
|
- */
|
|
|
-#if 0
|
|
|
- /* disabled: - it propagates to the reply and we don't want this
|
|
|
- * -- andrei */
|
|
|
- if (msg->msg_flags & FL_SDP_PORT_AFS) {
|
|
|
- LOG(L_ERR, "ERROR: alter_mediaip: you can't rewrite the same "
|
|
|
- "SDP twice, check your config!\n");
|
|
|
- return -1;
|
|
|
- }
|
|
|
-#endif
|
|
|
-
|
|
|
- if (preserve != 0) {
|
|
|
- anchor = anchor_lump(msg, body->s + body->len - msg->buf, 0, 0);
|
|
|
- if (anchor == NULL) {
|
|
|
- LOG(L_ERR, "ERROR: alter_mediaport: anchor_lump failed\n");
|
|
|
- return -1;
|
|
|
- }
|
|
|
- buf = pkg_malloc(AOLDMEDPRT_LEN + oldport->len + CRLF_LEN);
|
|
|
- if (buf == NULL) {
|
|
|
- LOG(L_ERR, "ERROR: alter_mediaport: out of memory\n");
|
|
|
- return -1;
|
|
|
- }
|
|
|
- memcpy(buf, CRLF, CRLF_LEN);
|
|
|
- memcpy(buf + CRLF_LEN, AOLDMEDPRT, AOLDMEDPRT_LEN);
|
|
|
- memcpy(buf + CRLF_LEN + AOLDMEDPRT_LEN, oldport->s, oldport->len);
|
|
|
- if (insert_new_lump_after(anchor, buf,
|
|
|
- AOLDMEDPRT_LEN + oldport->len + CRLF_LEN, 0) == NULL) {
|
|
|
- LOG(L_ERR, "ERROR: alter_mediaport: insert_new_lump_after failed\n");
|
|
|
- pkg_free(buf);
|
|
|
- return -1;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- buf = pkg_malloc(newport->len);
|
|
|
- if (buf == NULL) {
|
|
|
- LOG(L_ERR, "ERROR: alter_mediaport: out of memory\n");
|
|
|
- return -1;
|
|
|
- }
|
|
|
- offset = oldport->s - msg->buf;
|
|
|
- anchor = del_lump(msg, offset, oldport->len, 0);
|
|
|
- if (anchor == NULL) {
|
|
|
- LOG(L_ERR, "ERROR: alter_mediaport: del_lump failed\n");
|
|
|
- pkg_free(buf);
|
|
|
- return -1;
|
|
|
- }
|
|
|
- memcpy(buf, newport->s, newport->len);
|
|
|
- if (insert_new_lump_after(anchor, buf, newport->len, 0) == 0) {
|
|
|
- LOG(L_ERR, "ERROR: alter_mediaport: insert_new_lump_after failed\n");
|
|
|
- pkg_free(buf);
|
|
|
- return -1;
|
|
|
- }
|
|
|
-
|
|
|
-#if 0
|
|
|
- msg->msg_flags |= FL_SDP_PORT_AFS;
|
|
|
-#endif
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-static int
|
|
|
-alter_rtcp(struct sip_msg *msg, str *body, str *oldport, str *newport)
|
|
|
-{
|
|
|
- char *buf;
|
|
|
- int offset;
|
|
|
- struct lump* anchor;
|
|
|
-
|
|
|
- /* check that updating rtcpport is really necessary */
|
|
|
- if (newport->len == oldport->len &&
|
|
|
- memcmp(newport->s, oldport->s, newport->len) == 0)
|
|
|
- return 0;
|
|
|
-
|
|
|
- buf = pkg_malloc(newport->len);
|
|
|
- if (buf == NULL) {
|
|
|
- LOG(L_ERR, "ERROR: alter_rtcp: out of memory\n");
|
|
|
- return -1;
|
|
|
- }
|
|
|
- offset = oldport->s - msg->buf;
|
|
|
- anchor = del_lump(msg, offset, oldport->len, 0);
|
|
|
- if (anchor == NULL) {
|
|
|
- LOG(L_ERR, "ERROR: alter_rtcp: del_lump failed\n");
|
|
|
- pkg_free(buf);
|
|
|
- return -1;
|
|
|
- }
|
|
|
- memcpy(buf, newport->s, newport->len);
|
|
|
- if (insert_new_lump_after(anchor, buf, newport->len, 0) == 0) {
|
|
|
- LOG(L_ERR, "ERROR: alter_rtcp: insert_new_lump_after failed\n");
|
|
|
- pkg_free(buf);
|
|
|
- return -1;
|
|
|
- }
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-static char *
|
|
|
-gencookie()
|
|
|
-{
|
|
|
- static char cook[34];
|
|
|
-
|
|
|
- sprintf(cook, "%d_%u ", (int)mypid, myseqn);
|
|
|
- myseqn++;
|
|
|
- return cook;
|
|
|
-}
|
|
|
-
|
|
|
-static int
|
|
|
-rtpp_checkcap(struct rtpp_node *node, char *cap, int caplen)
|
|
|
-{
|
|
|
- char *cp;
|
|
|
- struct iovec vf[4] = {{NULL, 0}, {"VF", 2}, {" ", 1}, {NULL, 0}};
|
|
|
-
|
|
|
- vf[3].iov_base = cap;
|
|
|
- vf[3].iov_len = caplen;
|
|
|
-
|
|
|
- cp = send_rtpp_command(node, vf, 4);
|
|
|
- if (cp == NULL)
|
|
|
- return -1;
|
|
|
- if (cp[0] == 'E' || atoi(cp) != 1)
|
|
|
- return 0;
|
|
|
- return 1;
|
|
|
-}
|
|
|
-
|
|
|
-static int
|
|
|
-rtpp_test(struct rtpp_node *node, int isdisabled, int force)
|
|
|
-{
|
|
|
- int rtpp_ver, rval;
|
|
|
- char *cp;
|
|
|
- struct iovec v[2] = {{NULL, 0}, {"V", 1}};
|
|
|
-
|
|
|
- if (force == 0) {
|
|
|
- if (isdisabled == 0)
|
|
|
- return 0;
|
|
|
- if (node->rn_recheck_ticks > get_ticks())
|
|
|
- return 1;
|
|
|
- }
|
|
|
- do {
|
|
|
- cp = send_rtpp_command(node, v, 2);
|
|
|
- if (cp == NULL) {
|
|
|
- LOG(L_WARN,"WARNING: rtpp_test: can't get version of "
|
|
|
- "the RTP proxy\n");
|
|
|
- break;
|
|
|
- }
|
|
|
- rtpp_ver = atoi(cp);
|
|
|
- if (rtpp_ver != SUP_CPROTOVER) {
|
|
|
- LOG(L_WARN, "WARNING: rtpp_test: unsupported "
|
|
|
- "version of RTP proxy <%s> found: %d supported, "
|
|
|
- "%d present\n", node->rn_url,
|
|
|
- SUP_CPROTOVER, rtpp_ver);
|
|
|
- break;
|
|
|
- }
|
|
|
- rval = rtpp_checkcap(node, REQ_CPROTOVER, sizeof(REQ_CPROTOVER) - 1);
|
|
|
- if (rval == -1) {
|
|
|
- LOG(L_WARN,"WARNING: rtpp_test: RTP proxy went down during "
|
|
|
- "version query\n");
|
|
|
- break;
|
|
|
- }
|
|
|
- if (rval == 0) {
|
|
|
- LOG(L_WARN, "WARNING: rtpp_test: of RTP proxy <%s>"
|
|
|
- "doesn't support required protocol version %s\n",
|
|
|
- node->rn_url, REQ_CPROTOVER);
|
|
|
- break;
|
|
|
- }
|
|
|
- LOG(L_INFO, "rtpp_test: RTP proxy <%s> found, support for "
|
|
|
- "it %senabled\n",
|
|
|
- node->rn_url, force == 0 ? "re-" : "");
|
|
|
- /* Check for optional capabilities */
|
|
|
- rval = rtpp_checkcap(node, REP_CPROTOVER, sizeof(REP_CPROTOVER) - 1);
|
|
|
- if (rval != -1) {
|
|
|
- node->rn_rep_supported = rval;
|
|
|
- } else {
|
|
|
- node->rn_rep_supported = 0;
|
|
|
- }
|
|
|
- rval = rtpp_checkcap(node, PTL_CPROTOVER, sizeof(PTL_CPROTOVER) - 1);
|
|
|
- if (rval != -1) {
|
|
|
- node->rn_ptl_supported = rval;
|
|
|
- } else {
|
|
|
- node->rn_ptl_supported = 0;
|
|
|
- }
|
|
|
- return 0;
|
|
|
- } while(0);
|
|
|
- LOG(L_WARN, "WARNING: rtpp_test: support for RTP proxy <%s>"
|
|
|
- "has been disabled%s\n", node->rn_url,
|
|
|
- rtpproxy_disable_tout < 0 ? "" : " temporarily");
|
|
|
- if (rtpproxy_disable_tout >= 0)
|
|
|
- node->rn_recheck_ticks = get_ticks() + rtpproxy_disable_tout;
|
|
|
-
|
|
|
- return 1;
|
|
|
-}
|
|
|
-
|
|
|
-char *
|
|
|
-send_rtpp_command(struct rtpp_node *node, struct iovec *v, int vcnt)
|
|
|
-{
|
|
|
- struct sockaddr_un addr;
|
|
|
- int fd, len, i;
|
|
|
- char *cp;
|
|
|
- static char buf[256];
|
|
|
- struct pollfd fds[1];
|
|
|
-
|
|
|
- len = 0;
|
|
|
- cp = buf;
|
|
|
- if (node->rn_umode == 0) {
|
|
|
- memset(&addr, 0, sizeof(addr));
|
|
|
- addr.sun_family = AF_LOCAL;
|
|
|
- strncpy(addr.sun_path, node->rn_address,
|
|
|
- sizeof(addr.sun_path) - 1);
|
|
|
-#ifdef HAVE_SOCKADDR_SA_LEN
|
|
|
- addr.sun_len = strlen(addr.sun_path);
|
|
|
-#endif
|
|
|
-
|
|
|
- fd = socket(AF_LOCAL, SOCK_STREAM, 0);
|
|
|
- if (fd < 0) {
|
|
|
- LOG(L_ERR, "ERROR: send_rtpp_command: can't create socket\n");
|
|
|
- goto badproxy;
|
|
|
- }
|
|
|
- if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
|
|
|
- close(fd);
|
|
|
- LOG(L_ERR, "ERROR: send_rtpp_command: can't connect to RTP proxy\n");
|
|
|
- goto badproxy;
|
|
|
- }
|
|
|
-
|
|
|
- do {
|
|
|
- len = writev(fd, v + 1, vcnt - 1);
|
|
|
- } while (len == -1 && errno == EINTR);
|
|
|
- if (len <= 0) {
|
|
|
- close(fd);
|
|
|
- LOG(L_ERR, "ERROR: send_rtpp_command: can't send command to a RTP proxy\n");
|
|
|
- goto badproxy;
|
|
|
- }
|
|
|
- do {
|
|
|
- len = read(fd, buf, sizeof(buf) - 1);
|
|
|
- } while (len == -1 && errno == EINTR);
|
|
|
- close(fd);
|
|
|
- if (len <= 0) {
|
|
|
- LOG(L_ERR, "ERROR: send_rtpp_command: can't read reply from a RTP proxy\n");
|
|
|
- goto badproxy;
|
|
|
- }
|
|
|
- } else {
|
|
|
- fds[0].fd = node->rn_fd;
|
|
|
- fds[0].events = POLLIN;
|
|
|
- fds[0].revents = 0;
|
|
|
- /* Drain input buffer */
|
|
|
- while ((poll(fds, 1, 0) == 1) &&
|
|
|
- ((fds[0].revents & POLLIN) != 0)) {
|
|
|
- recv(node->rn_fd, buf, sizeof(buf) - 1, 0);
|
|
|
- fds[0].revents = 0;
|
|
|
- }
|
|
|
- v[0].iov_base = gencookie();
|
|
|
- v[0].iov_len = strlen(v[0].iov_base);
|
|
|
- for (i = 0; i < rtpproxy_retr; i++) {
|
|
|
- do {
|
|
|
- len = writev(node->rn_fd, v, vcnt);
|
|
|
- } while (len == -1 && (errno == EINTR || errno == ENOBUFS));
|
|
|
- if (len <= 0) {
|
|
|
- LOG(L_ERR, "ERROR: send_rtpp_command: "
|
|
|
- "can't send command to a RTP proxy\n");
|
|
|
- goto badproxy;
|
|
|
- }
|
|
|
- while ((poll(fds, 1, rtpproxy_tout * 1000) == 1) &&
|
|
|
- (fds[0].revents & POLLIN) != 0) {
|
|
|
- do {
|
|
|
- len = recv(node->rn_fd, buf, sizeof(buf) - 1, 0);
|
|
|
- } while (len == -1 && errno == EINTR);
|
|
|
- if (len <= 0) {
|
|
|
- LOG(L_ERR, "ERROR: send_rtpp_command: "
|
|
|
- "can't read reply from a RTP proxy\n");
|
|
|
- goto badproxy;
|
|
|
- }
|
|
|
- if (len >= (v[0].iov_len - 1) &&
|
|
|
- memcmp(buf, v[0].iov_base, (v[0].iov_len - 1)) == 0) {
|
|
|
- len -= (v[0].iov_len - 1);
|
|
|
- cp += (v[0].iov_len - 1);
|
|
|
- if (len != 0) {
|
|
|
- len--;
|
|
|
- cp++;
|
|
|
- }
|
|
|
- goto out;
|
|
|
- }
|
|
|
- fds[0].revents = 0;
|
|
|
- }
|
|
|
- }
|
|
|
- if (i == rtpproxy_retr) {
|
|
|
- LOG(L_ERR, "ERROR: send_rtpp_command: "
|
|
|
- "timeout waiting reply from a RTP proxy\n");
|
|
|
- goto badproxy;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
-out:
|
|
|
- cp[len] = '\0';
|
|
|
- return cp;
|
|
|
-badproxy:
|
|
|
- LOG(L_ERR, "send_rtpp_command(): proxy <%s> does not responding, disable it\n", node->rn_url);
|
|
|
- node->rn_disabled = 1;
|
|
|
- node->rn_recheck_ticks = get_ticks() + rtpproxy_disable_tout;
|
|
|
- return NULL;
|
|
|
-}
|
|
|
-
|
|
|
-/*
|
|
|
- * Main balancing routine. This does not try to keep the same proxy for
|
|
|
- * the call if some proxies were disabled or enabled; proxy death considered
|
|
|
- * too rare. Otherwise we should implement "mature" HA clustering, which is
|
|
|
- * too expensive here.
|
|
|
- */
|
|
|
-struct rtpp_node *
|
|
|
-select_rtpp_node(str callid, int do_test, int node_idx)
|
|
|
-{
|
|
|
- unsigned sum, sumcut, weight_sum;
|
|
|
- struct rtpp_node* node;
|
|
|
- int was_forced;
|
|
|
-
|
|
|
- /* Most popular case: 1 proxy, nothing to calculate */
|
|
|
- if (rtpp_node_count == 1) {
|
|
|
- if (node_idx > 0) {
|
|
|
- LOG(L_ERR, "ERROR: select_rtpp_node: node index out or range\n");
|
|
|
- return NULL;
|
|
|
- }
|
|
|
- node = rtpp_list.rn_first;
|
|
|
- if (node->rn_disabled && node->rn_recheck_ticks <= get_ticks()) {
|
|
|
- /* Try to enable if it's time to try. */
|
|
|
- node->rn_disabled = rtpp_test(node, 1, 0);
|
|
|
- }
|
|
|
- return node->rn_disabled ? NULL : node;
|
|
|
- }
|
|
|
-
|
|
|
- if (node_idx != -1) {
|
|
|
- for (node = rtpp_list.rn_first; node != NULL; node = node->rn_next) {
|
|
|
- if (node_idx > 0) {
|
|
|
- node_idx--;
|
|
|
- continue;
|
|
|
- }
|
|
|
- if (node->rn_disabled && node->rn_recheck_ticks <= get_ticks()) {
|
|
|
- /* Try to enable if it's time to try. */
|
|
|
- node->rn_disabled = rtpp_test(node, 1, 0);
|
|
|
- }
|
|
|
- return node->rn_disabled ? NULL : node;
|
|
|
- }
|
|
|
- LOG(L_ERR, "ERROR: select_rtpp_node: node index out or range\n");
|
|
|
- return NULL;
|
|
|
- }
|
|
|
-
|
|
|
- /* XXX Use quick-and-dirty hashing algo */
|
|
|
- for(sum = 0; callid.len > 0; callid.len--)
|
|
|
- sum += callid.s[callid.len - 1];
|
|
|
- sum &= 0xff;
|
|
|
-
|
|
|
- was_forced = 0;
|
|
|
-retry:
|
|
|
- weight_sum = 0;
|
|
|
- for (node = rtpp_list.rn_first; node != NULL; node = node->rn_next) {
|
|
|
- if (node->rn_disabled && node->rn_recheck_ticks <= get_ticks()) {
|
|
|
- /* Try to enable if it's time to try. */
|
|
|
- node->rn_disabled = rtpp_test(node, 1, 0);
|
|
|
- }
|
|
|
- if (!node->rn_disabled)
|
|
|
- weight_sum += node->rn_weight;
|
|
|
- }
|
|
|
- if (weight_sum == 0) {
|
|
|
- /* No proxies? Force all to be redetected, if not yet */
|
|
|
- if (was_forced)
|
|
|
- return NULL;
|
|
|
- was_forced = 1;
|
|
|
- for (node = rtpp_list.rn_first; node != NULL; node = node->rn_next) {
|
|
|
- node->rn_disabled = rtpp_test(node, 1, 1);
|
|
|
- }
|
|
|
- goto retry;
|
|
|
- }
|
|
|
- sumcut = sum % weight_sum;
|
|
|
- /*
|
|
|
- * sumcut here lays from 0 to weight_sum-1.
|
|
|
- * Scan proxy list and decrease until appropriate proxy is found.
|
|
|
- */
|
|
|
- for (node = rtpp_list.rn_first; node != NULL; node = node->rn_next) {
|
|
|
- if (node->rn_disabled)
|
|
|
- continue;
|
|
|
- if (sumcut < node->rn_weight)
|
|
|
- goto found;
|
|
|
- sumcut -= node->rn_weight;
|
|
|
- }
|
|
|
- /* No node list */
|
|
|
- return NULL;
|
|
|
-found:
|
|
|
- if (do_test) {
|
|
|
- node->rn_disabled = rtpp_test(node, node->rn_disabled, 0);
|
|
|
- if (node->rn_disabled)
|
|
|
- goto retry;
|
|
|
- }
|
|
|
- return node;
|
|
|
-}
|
|
|
-
|
|
|
-static int
|
|
|
-unforce_rtp_proxy_f(struct sip_msg* msg, int node_idx)
|
|
|
-{
|
|
|
- str callid, from_tag, to_tag;
|
|
|
- struct rtpp_node *node;
|
|
|
- struct iovec v[1 + 4 + 3] = {{NULL, 0}, {"D", 1}, {" ", 1}, {NULL, 0}, {" ", 1}, {NULL, 0}, {" ", 1}, {NULL, 0}};
|
|
|
- /* 1 */ /* 2 */ /* 3 */ /* 4 */ /* 5 */ /* 6 */ /* 1 */
|
|
|
-
|
|
|
- if (get_callid(msg, &callid) == -1 || callid.len == 0) {
|
|
|
- LOG(L_ERR, "ERROR: unforce_rtp_proxy: can't get Call-Id field\n");
|
|
|
- return -1;
|
|
|
- }
|
|
|
- if (get_to_tag(msg, &to_tag) == -1) {
|
|
|
- LOG(L_ERR, "ERROR: unforce_rtp_proxy: can't get To tag\n");
|
|
|
- return -1;
|
|
|
- }
|
|
|
- if (get_from_tag(msg, &from_tag) == -1 || from_tag.len == 0) {
|
|
|
- LOG(L_ERR, "ERROR: unforce_rtp_proxy: can't get From tag\n");
|
|
|
- return -1;
|
|
|
- }
|
|
|
- STR2IOVEC(callid, v[3]);
|
|
|
- STR2IOVEC(from_tag, v[5]);
|
|
|
- STR2IOVEC(to_tag, v[7]);
|
|
|
- node = select_rtpp_node(callid, 1, node_idx);
|
|
|
- if (!node) {
|
|
|
- LOG(L_ERR, "ERROR: unforce_rtp_proxy: no available proxies\n");
|
|
|
- return -1;
|
|
|
- }
|
|
|
- send_rtpp_command(node, v, (to_tag.len > 0) ? 8 : 6);
|
|
|
-
|
|
|
- return 1;
|
|
|
-}
|
|
|
-
|
|
|
-static int
|
|
|
-unforce_rtp_proxy0_f(struct sip_msg* msg, char* str1, char* str2)
|
|
|
-{
|
|
|
-
|
|
|
- return unforce_rtp_proxy_f(msg, -1);
|
|
|
-}
|
|
|
-
|
|
|
-static int
|
|
|
-unforce_rtp_proxy1_f(struct sip_msg* msg, char* str1, char* str2)
|
|
|
-{
|
|
|
- int node_idx;
|
|
|
- str rtpnode;
|
|
|
-
|
|
|
- if (get_str_fparam(&rtpnode, msg, (fparam_t*) str1) < -1) {
|
|
|
- ERR("force_rtp_proxy(): Error while getting rtp_proxy node (fparam '%s')\n", ((fparam_t*)str1)->orig);
|
|
|
-
|
|
|
- return -1;
|
|
|
- }
|
|
|
-
|
|
|
- str2int(&rtpnode, (unsigned int*)&node_idx);
|
|
|
- return unforce_rtp_proxy_f(msg, node_idx);
|
|
|
-}
|
|
|
-
|
|
|
-static int
|
|
|
-start_recording_f(struct sip_msg* msg, int node_idx)
|
|
|
-{
|
|
|
- int nitems;
|
|
|
- str callid, from_tag, to_tag;
|
|
|
- struct rtpp_node *node;
|
|
|
- struct iovec v[1 + 4 + 3] = {{NULL, 0}, {"R", 1}, {" ", 1}, {NULL, 0}, {" ", 1}, {NULL, 0}, {" ", 1}, {NULL, 0}};
|
|
|
- /* 1 */ /* 2 */ /* 3 */ /* 4 */ /* 5 */ /* 6 */ /* 1 */
|
|
|
-
|
|
|
- if (get_callid(msg, &callid) == -1 || callid.len == 0) {
|
|
|
- LOG(L_ERR, "ERROR: start_recording: can't get Call-Id field\n");
|
|
|
- return -1;
|
|
|
- }
|
|
|
- if (get_to_tag(msg, &to_tag) == -1) {
|
|
|
- LOG(L_ERR, "ERROR: start_recording: can't get To tag\n");
|
|
|
- return -1;
|
|
|
- }
|
|
|
- if (get_from_tag(msg, &from_tag) == -1 || from_tag.len == 0) {
|
|
|
- LOG(L_ERR, "ERROR: start_recording: can't get From tag\n");
|
|
|
- return -1;
|
|
|
- }
|
|
|
- STR2IOVEC(callid, v[3]);
|
|
|
- STR2IOVEC(from_tag, v[5]);
|
|
|
- STR2IOVEC(to_tag, v[7]);
|
|
|
- node = select_rtpp_node(callid, 1, node_idx);
|
|
|
- if (!node) {
|
|
|
- LOG(L_ERR, "ERROR: start_recording: no available proxies\n");
|
|
|
- return -1;
|
|
|
- }
|
|
|
- nitems = 8;
|
|
|
- if (msg->first_line.type == SIP_REPLY) {
|
|
|
- if (to_tag.len == 0)
|
|
|
- return -1;
|
|
|
- STR2IOVEC(to_tag, v[5]);
|
|
|
- STR2IOVEC(from_tag, v[7]);
|
|
|
- } else {
|
|
|
- STR2IOVEC(from_tag, v[5]);
|
|
|
- STR2IOVEC(to_tag, v[7]);
|
|
|
- if (to_tag.len <= 0)
|
|
|
- nitems = 6;
|
|
|
- }
|
|
|
- send_rtpp_command(node, v, nitems);
|
|
|
-
|
|
|
- return 1;
|
|
|
-}
|
|
|
-
|
|
|
-static int
|
|
|
-start_recording0_f(struct sip_msg* msg, char* str1, char* str2)
|
|
|
-{
|
|
|
-
|
|
|
- return start_recording_f(msg, -1);
|
|
|
-}
|
|
|
-
|
|
|
-static int
|
|
|
-start_recording1_f(struct sip_msg* msg, char* str1, char* str2)
|
|
|
-{
|
|
|
- int node_idx;
|
|
|
- str rtpnode;
|
|
|
-
|
|
|
- if (get_str_fparam(&rtpnode, msg, (fparam_t*) str1) < -1) {
|
|
|
- ERR("start_recording(): Error while getting rtp_proxy node (fparam '%s')\n", ((fparam_t*)str1)->orig);
|
|
|
- return -1;
|
|
|
- }
|
|
|
-
|
|
|
- str2int(&rtpnode, (unsigned int*)&node_idx);
|
|
|
- return start_recording_f(msg, node_idx);
|
|
|
-}
|
|
|
-
|
|
|
/*
|
|
|
* Auxiliary for some functions.
|
|
|
* Returns pointer to first character of found line, or NULL if no such line.
|
|
|
*/
|
|
|
|
|
|
-static char *
|
|
|
-find_sdp_line(char* p, char* plimit, char linechar)
|
|
|
-{
|
|
|
- static char linehead[3] = "x=";
|
|
|
- char *cp, *cp1;
|
|
|
- linehead[0] = linechar;
|
|
|
- /* Iterate thru body */
|
|
|
- cp = p;
|
|
|
- for (;;) {
|
|
|
- if (cp >= plimit)
|
|
|
- return NULL;
|
|
|
- cp1 = ser_memmem(cp, linehead, plimit-cp, 2);
|
|
|
- if (cp1 == NULL)
|
|
|
- return NULL;
|
|
|
- /*
|
|
|
- * As it is body, we assume it has previous line and we can
|
|
|
- * lookup previous character.
|
|
|
- */
|
|
|
- if (cp1[-1] == '\n' || cp1[-1] == '\r')
|
|
|
- return cp1;
|
|
|
- /*
|
|
|
- * Having such data, but not at line beginning.
|
|
|
- * Skip them and reiterate. ser_memmem() will find next
|
|
|
- * occurence.
|
|
|
- */
|
|
|
- if (plimit - cp1 < 2)
|
|
|
- return NULL;
|
|
|
- cp = cp1 + 2;
|
|
|
- }
|
|
|
- /*UNREACHED*/
|
|
|
- return NULL;
|
|
|
-}
|
|
|
-
|
|
|
-/* This function assumes p points to a line of requested type. */
|
|
|
-
|
|
|
-static char *
|
|
|
-find_next_sdp_line(char* p, char* plimit, char linechar, char* defptr)
|
|
|
-{
|
|
|
- char *t;
|
|
|
- if (p >= plimit || plimit - p < 3)
|
|
|
- return defptr;
|
|
|
- t = find_sdp_line(p + 2, plimit, linechar);
|
|
|
- return t ? t : defptr;
|
|
|
-}
|
|
|
-
|
|
|
-static int
|
|
|
-rtpproxy_offer1_f(struct sip_msg *msg, char *str1, char *str2)
|
|
|
-{
|
|
|
- char *cp;
|
|
|
- fparam_t param2;
|
|
|
-
|
|
|
- char newip[IP_ADDR_MAX_STR_SIZE];
|
|
|
-
|
|
|
- cp = ip_addr2a(&msg->rcv.dst_ip);
|
|
|
- strcpy(newip, cp);
|
|
|
- param2.type = FPARAM_STRING;
|
|
|
- param2.orig = param2.v.asciiz = newip;
|
|
|
- return rtpproxy_offer2_f(msg, str1, (char*)¶m2);
|
|
|
-}
|
|
|
-
|
|
|
-static int
|
|
|
-rtpproxy_offer2_f(struct sip_msg *msg, char *param1, char *param2)
|
|
|
-{
|
|
|
-
|
|
|
- if (msg->first_line.type == SIP_REQUEST)
|
|
|
- if (msg->first_line.u.request.method_value != METHOD_INVITE)
|
|
|
- return -1;
|
|
|
-
|
|
|
- return force_rtp_proxy(msg, param1, param2, 1);
|
|
|
-}
|
|
|
-
|
|
|
-static int
|
|
|
-rtpproxy_answer1_f(struct sip_msg *msg, char *str1, char *str2)
|
|
|
-{
|
|
|
- char *cp;
|
|
|
- fparam_t param2;
|
|
|
-
|
|
|
- char newip[IP_ADDR_MAX_STR_SIZE];
|
|
|
-
|
|
|
- cp = ip_addr2a(&msg->rcv.dst_ip);
|
|
|
- strcpy(newip, cp);
|
|
|
- param2.type = FPARAM_STRING;
|
|
|
- param2.orig = param2.v.asciiz = newip;
|
|
|
- return rtpproxy_answer2_f(msg, str1, (char*)¶m2);
|
|
|
-}
|
|
|
-
|
|
|
-static int
|
|
|
-rtpproxy_answer2_f(struct sip_msg *msg, char *param1, char *param2)
|
|
|
-{
|
|
|
-
|
|
|
- if (msg->first_line.type == SIP_REQUEST)
|
|
|
- if (msg->first_line.u.request.method_value != METHOD_ACK)
|
|
|
- return -1;
|
|
|
-
|
|
|
- return force_rtp_proxy(msg, param1, param2, 0);
|
|
|
-}
|
|
|
-
|
|
|
-static int
|
|
|
-force_rtp_proxy2_f(struct sip_msg *msg, char *param1, char *param2)
|
|
|
-{
|
|
|
- int offer;
|
|
|
-
|
|
|
- if (msg->first_line.type == SIP_REQUEST &&
|
|
|
- msg->first_line.u.request.method_value == METHOD_INVITE) {
|
|
|
- offer = 1;
|
|
|
- } else if (msg->first_line.type == SIP_REPLY) {
|
|
|
- offer = 0;
|
|
|
- } else {
|
|
|
- return -1;
|
|
|
- }
|
|
|
-
|
|
|
- return force_rtp_proxy(msg, param1, param2, offer);
|
|
|
-}
|
|
|
-
|
|
|
-struct options {
|
|
|
- str s;
|
|
|
- int oidx;
|
|
|
-};
|
|
|
-
|
|
|
-static int
|
|
|
-append_opts(struct options *op, char ch)
|
|
|
-{
|
|
|
- void *p;
|
|
|
-
|
|
|
- if (op->s.len <= op->oidx) {
|
|
|
- p = pkg_realloc(op->s.s, op->oidx + 32);
|
|
|
- if (p == NULL) {
|
|
|
- return (-1);
|
|
|
- }
|
|
|
- op->s.s = p;
|
|
|
- op->s.len = op->oidx + 32;
|
|
|
- }
|
|
|
- op->s.s[op->oidx++] = ch;
|
|
|
- return (0);
|
|
|
-}
|
|
|
-
|
|
|
-static void
|
|
|
-free_opts(struct options *op1, struct options *op2, struct options *op3)
|
|
|
-{
|
|
|
-
|
|
|
- if (op1->s.len > 0 && op1->s.s != NULL) {
|
|
|
- pkg_free(op1->s.s);
|
|
|
- op1->s.len = 0;
|
|
|
- }
|
|
|
- if (op2->s.len > 0 && op2->s.s != NULL) {
|
|
|
- pkg_free(op2->s.s);
|
|
|
- op2->s.len = 0;
|
|
|
- }
|
|
|
- if (op3->s.len > 0 && op3->s.s != NULL) {
|
|
|
- pkg_free(op3->s.s);
|
|
|
- op3->s.len = 0;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-#define FORCE_RTP_PROXY_RET(e) \
|
|
|
- do { \
|
|
|
- free_opts(&opts, &rep_opts, &pt_opts); \
|
|
|
- return (e); \
|
|
|
- } while (0);
|
|
|
-
|
|
|
-static int
|
|
|
-force_rtp_proxy(struct sip_msg *msg, char *param1, char *param2, int offer)
|
|
|
-{
|
|
|
- str body, body1, oldport, oldip, newport, newip, str1, str2, s;
|
|
|
- str callid, from_tag, to_tag, tmp, c1_oldip, payload_types;
|
|
|
- str oldrtcp, newrtcp;
|
|
|
- int create, port, len, asymmetric, flookup, argc, proxied, real, i;
|
|
|
- int pf, pf1, force, c1_pf;
|
|
|
- struct options opts, rep_opts, pt_opts;
|
|
|
- unsigned int node_idx, oldport_i;
|
|
|
- char *cp, *cp1;
|
|
|
- char *cpend, *next;
|
|
|
- char **ap, *argv[10];
|
|
|
- struct lump* anchor;
|
|
|
- struct rtpp_node *node;
|
|
|
- struct iovec v[] = {
|
|
|
- {NULL, 0}, /* reserved (cookie) */
|
|
|
- {NULL, 0}, /* command & common options */
|
|
|
- {NULL, 0}, /* per-media/per-node options 1 */
|
|
|
- {NULL, 0}, /* per-media/per-node options 2 */
|
|
|
- {" ", 1}, /* separator */
|
|
|
- {NULL, 0}, /* callid */
|
|
|
- {" ", 1}, /* separator */
|
|
|
- {NULL, 7}, /* newip */
|
|
|
- {" ", 1}, /* separator */
|
|
|
- {NULL, 1}, /* oldport */
|
|
|
- {" ", 1}, /* separator */
|
|
|
- {NULL, 0}, /* from_tag */
|
|
|
- {";", 1}, /* separator */
|
|
|
- {NULL, 0}, /* medianum */
|
|
|
- {" ", 1}, /* separator */
|
|
|
- {NULL, 0}, /* to_tag */
|
|
|
- {";", 1}, /* separator */
|
|
|
- {NULL, 0} /* medianum */
|
|
|
- };
|
|
|
- char *v1p, *v2p, *c1p, *c2p, *m1p, *m2p, *bodylimit;
|
|
|
- char medianum_buf[20];
|
|
|
- int medianum, media_multi;
|
|
|
- str medianum_str, tmpstr1;
|
|
|
- int c1p_altered;
|
|
|
-
|
|
|
- if (param1) {
|
|
|
- if (get_str_fparam(&str1, msg, (fparam_t*)param1) < 0) {
|
|
|
- LOG(L_ERR, "force_rtp_proxy(): Error while parsing 1st param ('%s')\n",
|
|
|
- ((fparam_t*)param1)->orig);
|
|
|
- return -1;
|
|
|
- }
|
|
|
- }
|
|
|
- else
|
|
|
- str1.len = 0;
|
|
|
-
|
|
|
- if (get_str_fparam(&str2, msg, (fparam_t*)param2) < 0) {
|
|
|
- LOG(L_ERR, "force_rtp_proxy(): Error while parsing 2nd param ('%s')\n",
|
|
|
- ((fparam_t*)param2)->orig);
|
|
|
- return -1;
|
|
|
- }
|
|
|
-
|
|
|
- memset(&opts, '\0', sizeof(opts));
|
|
|
- memset(&rep_opts, '\0', sizeof(rep_opts));
|
|
|
- memset(&pt_opts, '\0', sizeof(pt_opts));
|
|
|
- /* Leave space for U/L prefix TBD later */
|
|
|
- if (append_opts(&opts, '?') == -1) {
|
|
|
- LM_ERR("out of pkg memory\n");
|
|
|
- FORCE_RTP_PROXY_RET (-1);
|
|
|
- }
|
|
|
- asymmetric = flookup = force = real = 0;
|
|
|
- node_idx = -1;
|
|
|
- for (i=0; i<str1.len; i++) {
|
|
|
- switch (str1.s[i]) {
|
|
|
- case ' ':
|
|
|
- case '\t':
|
|
|
- break;
|
|
|
-
|
|
|
- case 'a':
|
|
|
- case 'A':
|
|
|
- if (append_opts(&opts, 'A') == -1) {
|
|
|
- LM_ERR("out of pkg memory\n");
|
|
|
- FORCE_RTP_PROXY_RET (-1);
|
|
|
- }
|
|
|
- asymmetric = 1;
|
|
|
- real = 1;
|
|
|
- break;
|
|
|
-
|
|
|
- case 'i':
|
|
|
- case 'I':
|
|
|
- if (append_opts(&opts, 'I') == -1) {
|
|
|
- LM_ERR("out of pkg memory\n");
|
|
|
- FORCE_RTP_PROXY_RET (-1);
|
|
|
- }
|
|
|
- break;
|
|
|
-
|
|
|
- case 'e':
|
|
|
- case 'E':
|
|
|
- if (append_opts(&opts, 'E') == -1) {
|
|
|
- LM_ERR("out of pkg memory\n");
|
|
|
- FORCE_RTP_PROXY_RET (-1);
|
|
|
- }
|
|
|
- break;
|
|
|
-
|
|
|
- case 'l':
|
|
|
- case 'L':
|
|
|
- if (offer == 0) {
|
|
|
- FORCE_RTP_PROXY_RET (-1);
|
|
|
- }
|
|
|
- flookup = 1;
|
|
|
- break;
|
|
|
-
|
|
|
- case 'f':
|
|
|
- case 'F':
|
|
|
- force = 1;
|
|
|
- break;
|
|
|
-
|
|
|
- case 'r':
|
|
|
- case 'R':
|
|
|
- real = 1;
|
|
|
- break;
|
|
|
-
|
|
|
- case 'n':
|
|
|
- case 'N':
|
|
|
- i++;
|
|
|
- s.s = str1.s+i;
|
|
|
- for (s.len = 0; i<str1.len && isdigit((unsigned char)str1.s[i]);
|
|
|
- i++, s.len++)
|
|
|
- continue;
|
|
|
- if (s.len == 0) {
|
|
|
- LOG(L_ERR, "ERROR: force_rtp_proxy2: non-negative integer"
|
|
|
- "should follow N option\n");
|
|
|
- FORCE_RTP_PROXY_RET (-1);
|
|
|
- }
|
|
|
- str2int(&s, &node_idx);
|
|
|
- break;
|
|
|
-
|
|
|
- case 'z':
|
|
|
- case 'Z':
|
|
|
- if (append_opts(&rep_opts, 'Z') == -1) {
|
|
|
- LM_ERR("out of pkg memory\n");
|
|
|
- FORCE_RTP_PROXY_RET (-1);
|
|
|
- }
|
|
|
- /* If there are any digits following Z copy them into the command */
|
|
|
- for (; i < str1.len - 1 && isdigit(str1.s[i + 1]); i++) {
|
|
|
- if (append_opts(&rep_opts, str1.s[i + 1]) == -1) {
|
|
|
- LM_ERR("out of pkg memory\n");
|
|
|
- FORCE_RTP_PROXY_RET (-1);
|
|
|
- }
|
|
|
- }
|
|
|
- break;
|
|
|
-
|
|
|
- default:
|
|
|
- LOG(L_ERR, "ERROR: force_rtp_proxy2: unknown option `%c'\n", str1.s[i]);
|
|
|
- FORCE_RTP_PROXY_RET (-1);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (offer != 0) {
|
|
|
- create = 1;
|
|
|
- } else {
|
|
|
- create = 0;
|
|
|
- }
|
|
|
- /* extract_body will also parse all the headers in the message as
|
|
|
- * a side effect => don't move get_callid/get_to_tag in front of it
|
|
|
- * -- andrei */
|
|
|
- if (extract_body(msg, &body) == -1) {
|
|
|
- LOG(L_ERR, "ERROR: force_rtp_proxy2: can't extract body "
|
|
|
- "from the message\n");
|
|
|
- FORCE_RTP_PROXY_RET (-1);
|
|
|
- }
|
|
|
- if (get_callid(msg, &callid) == -1 || callid.len == 0) {
|
|
|
- LOG(L_ERR, "ERROR: force_rtp_proxy2: can't get Call-Id field\n");
|
|
|
- FORCE_RTP_PROXY_RET (-1);
|
|
|
- }
|
|
|
- if (get_to_tag(msg, &to_tag) == -1) {
|
|
|
- LOG(L_ERR, "ERROR: force_rtp_proxy2: can't get To tag\n");
|
|
|
- FORCE_RTP_PROXY_RET (-1);
|
|
|
- }
|
|
|
- if (get_from_tag(msg, &from_tag) == -1 || from_tag.len == 0) {
|
|
|
- LOG(L_ERR, "ERROR: force_rtp_proxy2: can't get From tag\n");
|
|
|
- FORCE_RTP_PROXY_RET (-1);
|
|
|
- }
|
|
|
- if (flookup != 0 || (msg->first_line.type == SIP_REPLY && offer != 0)) {
|
|
|
- if (to_tag.len == 0) {
|
|
|
- FORCE_RTP_PROXY_RET (-1);
|
|
|
- }
|
|
|
- tmp = from_tag;
|
|
|
- from_tag = to_tag;
|
|
|
- to_tag = tmp;
|
|
|
- }
|
|
|
- if (flookup != 0)
|
|
|
- create = 0;
|
|
|
- proxied = 0;
|
|
|
- for (cp = body.s; (len = body.s + body.len - cp) >= ANORTPPROXY_LEN;) {
|
|
|
- cp1 = ser_memmem(cp, ANORTPPROXY, len, ANORTPPROXY_LEN);
|
|
|
- if (cp1 == NULL)
|
|
|
- break;
|
|
|
- if (cp1[-1] == '\n' || cp1[-1] == '\r') {
|
|
|
- proxied = 1;
|
|
|
- break;
|
|
|
- }
|
|
|
- cp = cp1 + ANORTPPROXY_LEN;
|
|
|
- }
|
|
|
- if (proxied != 0 && force == 0) {
|
|
|
- FORCE_RTP_PROXY_RET (-1);
|
|
|
- }
|
|
|
- /*
|
|
|
- * Parsing of SDP body.
|
|
|
- * It can contain a few session descriptions (each starts with
|
|
|
- * v-line), and each session may contain a few media descriptions
|
|
|
- * (each starts with m-line).
|
|
|
- * We have to change ports in m-lines, and also change IP addresses in
|
|
|
- * c-lines which can be placed either in session header (fallback for
|
|
|
- * all medias) or media description.
|
|
|
- * Ports should be allocated for any media. IPs all should be changed
|
|
|
- * to the same value (RTP proxy IP), so we can change all c-lines
|
|
|
- * unconditionally.
|
|
|
- */
|
|
|
- bodylimit = body.s + body.len;
|
|
|
- v1p = find_sdp_line(body.s, bodylimit, 'v');
|
|
|
- if (v1p == NULL) {
|
|
|
- LOG(L_ERR, "ERROR: force_rtp_proxy2: no sessions in SDP\n");
|
|
|
- FORCE_RTP_PROXY_RET (-1);
|
|
|
- }
|
|
|
- v2p = find_next_sdp_line(v1p, bodylimit, 'v', bodylimit);
|
|
|
- media_multi = (v2p != bodylimit);
|
|
|
- v2p = v1p;
|
|
|
- medianum = 0;
|
|
|
-
|
|
|
- opts.s.s[0] = (create == 0) ? 'L' : 'U';
|
|
|
- v[1].iov_base = opts.s.s;
|
|
|
- v[1].iov_len = opts.oidx;
|
|
|
- STR2IOVEC(callid, v[5]);
|
|
|
- STR2IOVEC(from_tag, v[11]);
|
|
|
- STR2IOVEC(to_tag, v[15]);
|
|
|
-
|
|
|
- for(;;) {
|
|
|
- /* Per-session iteration. */
|
|
|
- v1p = v2p;
|
|
|
- if (v1p == NULL || v1p >= bodylimit)
|
|
|
- break; /* No sessions left */
|
|
|
- v2p = find_next_sdp_line(v1p, bodylimit, 'v', bodylimit);
|
|
|
- /* v2p is text limit for session parsing. */
|
|
|
- m1p = find_sdp_line(v1p, v2p, 'm');
|
|
|
- /* Have this session media description? */
|
|
|
- if (m1p == NULL) {
|
|
|
- LOG(L_ERR, "ERROR: force_rtp_proxy2: no m= in session\n");
|
|
|
- FORCE_RTP_PROXY_RET (-1);
|
|
|
- }
|
|
|
- /*
|
|
|
- * Find c1p only between session begin and first media.
|
|
|
- * c1p will give common c= for all medias.
|
|
|
- */
|
|
|
- c1p = find_sdp_line(v1p, m1p, 'c');
|
|
|
- c1p_altered = 0;
|
|
|
- c1_oldip.s = NULL;
|
|
|
- c1_oldip.len = 0;
|
|
|
- if (c1p != NULL) {
|
|
|
- tmpstr1.s = c1p;
|
|
|
- tmpstr1.len = v2p - tmpstr1.s; /* limit is session limit text */
|
|
|
- if (extract_mediaip(&tmpstr1, &c1_oldip, &c1_pf) == -1) {
|
|
|
- LOG(L_ERR, "ERROR: force_rtp_proxy2: can't"
|
|
|
- " extract media IP from the message\n");
|
|
|
- /* Try to continue maybe the other IPs are ok */
|
|
|
- c1_oldip.s = NULL;
|
|
|
- c1_oldip.len = 0;
|
|
|
- }
|
|
|
- }
|
|
|
- /* Have session. Iterate media descriptions in session */
|
|
|
- m2p = m1p;
|
|
|
- for (;;) {
|
|
|
- m1p = m2p;
|
|
|
- if (m1p == NULL || m1p >= v2p)
|
|
|
- break;
|
|
|
- m2p = find_next_sdp_line(m1p, v2p, 'm', v2p);
|
|
|
- /* c2p will point to per-media "c=" */
|
|
|
- c2p = find_sdp_line(m1p, m2p, 'c');
|
|
|
- /* Extract address and port */
|
|
|
- if (c2p != NULL) {
|
|
|
- tmpstr1.s = c2p;
|
|
|
- tmpstr1.len = v2p - tmpstr1.s;/* limit is session limit text */
|
|
|
- if (extract_mediaip(&tmpstr1, &oldip, &pf) == -1) {
|
|
|
- LOG(L_ERR, "ERROR: force_rtp_proxy2: can't"
|
|
|
- " extract media IP from the message\n");
|
|
|
- if (c1_oldip.s == NULL) {
|
|
|
- FORCE_RTP_PROXY_RET (-1);
|
|
|
- }
|
|
|
- /* Try to continue if we have the sess. header ip */
|
|
|
- oldip = c1_oldip;
|
|
|
- c2p = NULL;
|
|
|
- }
|
|
|
- } else if (c1_oldip.s != NULL) {
|
|
|
- /* Use session header value */
|
|
|
- oldip = c1_oldip;
|
|
|
- } else {
|
|
|
- /* No "c=" */
|
|
|
- LOG(L_ERR, "ERROR: force_rtp_proxy2: can't"
|
|
|
- " find media IP in the message\n");
|
|
|
- FORCE_RTP_PROXY_RET (-1);
|
|
|
- }
|
|
|
- tmpstr1.s = m1p;
|
|
|
- tmpstr1.len = m2p - m1p;
|
|
|
- if (extract_mediainfo(&tmpstr1, &oldport,
|
|
|
- &payload_types) == -1) {
|
|
|
- LOG(L_ERR, "ERROR: force_rtp_proxy2: can't"
|
|
|
- " extract media port from the message\n");
|
|
|
- FORCE_RTP_PROXY_RET (-1);
|
|
|
- }
|
|
|
- /* Extract rtcp attribute */
|
|
|
- tmpstr1.s = m1p;
|
|
|
- tmpstr1.len = m2p - m1p;
|
|
|
- oldrtcp.s = NULL;
|
|
|
- oldrtcp.len = 0;
|
|
|
- extract_rtcp(&tmpstr1, &oldrtcp);
|
|
|
-
|
|
|
- ++medianum;
|
|
|
- if (asymmetric != 0 || real != 0) {
|
|
|
- newip = oldip;
|
|
|
- } else {
|
|
|
- newip.s = ip_addr2a(&msg->rcv.src_ip);
|
|
|
- newip.len = strlen(newip.s);
|
|
|
- }
|
|
|
- /* XXX must compare address families in all addresses */
|
|
|
- if (pf == AF_INET6) {
|
|
|
- if (append_opts(&opts, '6') == -1) {
|
|
|
- LM_ERR("out of pkg memory\n");
|
|
|
- FORCE_RTP_PROXY_RET (-1);
|
|
|
- }
|
|
|
- }
|
|
|
- str2int(&oldport, &oldport_i);
|
|
|
- /*
|
|
|
- * Do not contact rtpproxy it if old port was 0 and we
|
|
|
- * have a SDP answer here. This means that particular
|
|
|
- * media stream has been rejected.
|
|
|
- */
|
|
|
- if (offer == 0 && oldport_i == 0)
|
|
|
- continue;
|
|
|
- snprintf(medianum_buf, sizeof medianum_buf, "%d", medianum);
|
|
|
- medianum_str.s = medianum_buf;
|
|
|
- medianum_str.len = strlen(medianum_buf);
|
|
|
- STR2IOVEC(newip, v[7]);
|
|
|
- STR2IOVEC(oldport, v[9]);
|
|
|
- if (1 || media_multi) /* XXX netch: can't choose now*/
|
|
|
- {
|
|
|
- STR2IOVEC(medianum_str, v[13]);
|
|
|
- } else {
|
|
|
- v[12].iov_len = v[13].iov_len = 0;
|
|
|
- }
|
|
|
- STR2IOVEC(medianum_str, v[17]);
|
|
|
- do {
|
|
|
- node = select_rtpp_node(callid, 1, node_idx);
|
|
|
- if (!node) {
|
|
|
- LOG(L_ERR, "ERROR: force_rtp_proxy2: no available proxies\n");
|
|
|
- FORCE_RTP_PROXY_RET (-1);
|
|
|
- }
|
|
|
- if (rep_opts.oidx > 0) {
|
|
|
- if (node->rn_rep_supported == 0) {
|
|
|
- LOG(L_WARN, "WARNING: force_rtp_proxy2: "
|
|
|
- "re-packetization is requested but is not "
|
|
|
- "supported by the selected RTP proxy node\n");
|
|
|
- v[2].iov_len = 0;
|
|
|
- } else {
|
|
|
- v[2].iov_base = rep_opts.s.s;
|
|
|
- v[2].iov_len += rep_opts.oidx;
|
|
|
- }
|
|
|
- }
|
|
|
- if (payload_types.len > 0 && node->rn_ptl_supported != 0) {
|
|
|
- pt_opts.oidx = 0;
|
|
|
- if (append_opts(&pt_opts, 'c') == -1) {
|
|
|
- LM_ERR("out of pkg memory\n");
|
|
|
- FORCE_RTP_PROXY_RET (-1);
|
|
|
- }
|
|
|
- /*
|
|
|
- * Convert space-separated payload types list into
|
|
|
- * a comma-separated list.
|
|
|
- */
|
|
|
- for (cp = payload_types.s;
|
|
|
- cp < payload_types.s + payload_types.len; cp++) {
|
|
|
- if (isdigit(*cp)) {
|
|
|
- if (append_opts(&pt_opts, *cp) == -1) {
|
|
|
- LM_ERR("out of pkg memory\n");
|
|
|
- FORCE_RTP_PROXY_RET (-1);
|
|
|
- }
|
|
|
- continue;
|
|
|
- }
|
|
|
- do {
|
|
|
- cp++;
|
|
|
- } while (!isdigit(*cp) &&
|
|
|
- cp < payload_types.s + payload_types.len);
|
|
|
- /* Check EOL */
|
|
|
- if (cp >= payload_types.s + payload_types.len)
|
|
|
- break;
|
|
|
- if (append_opts(&pt_opts, ',') == -1) {
|
|
|
- LM_ERR("out of pkg memory\n");
|
|
|
- FORCE_RTP_PROXY_RET (-1);
|
|
|
- }
|
|
|
- cp--;
|
|
|
- }
|
|
|
- v[3].iov_base = pt_opts.s.s;
|
|
|
- v[3].iov_len = pt_opts.oidx;
|
|
|
- } else {
|
|
|
- v[3].iov_len = 0;
|
|
|
- }
|
|
|
- cp = send_rtpp_command(node, v, (to_tag.len > 0) ? 18 : 14);
|
|
|
- } while (cp == NULL);
|
|
|
- LOG(L_DBG, "force_rtp_proxy2: proxy reply: %s\n", cp);
|
|
|
- /* Parse proxy reply to <argc,argv> */
|
|
|
- argc = 0;
|
|
|
- memset(argv, 0, sizeof(argv));
|
|
|
- cpend=cp+strlen(cp);
|
|
|
- next=eat_token_end(cp, cpend);
|
|
|
- for (ap = argv; cp<cpend; cp=next+1, next=eat_token_end(cp, cpend)){
|
|
|
- *next=0;
|
|
|
- if (*cp != '\0') {
|
|
|
- *ap=cp;
|
|
|
- argc++;
|
|
|
- if ((char*)++ap >= ((char*)argv+sizeof(argv)))
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- if (argc < 1) {
|
|
|
- LOG(L_ERR, "force_rtp_proxy2: no reply from rtp proxy\n");
|
|
|
- FORCE_RTP_PROXY_RET (-1);
|
|
|
- }
|
|
|
- port = atoi(argv[0]);
|
|
|
- if (port <= 0 || port > 65535) {
|
|
|
- /*
|
|
|
- * In forced lookup mode absence of session indicated
|
|
|
- * by port number being zero is not an error condition
|
|
|
- * but merely of indication that there is no such
|
|
|
- * session in the proxy exists.
|
|
|
- */
|
|
|
- if (port != 0 || flookup == 0)
|
|
|
- LOG(L_ERR, "force_rtp_proxy2: incorrect port in reply from rtp proxy\n");
|
|
|
- FORCE_RTP_PROXY_RET (-1);
|
|
|
- }
|
|
|
-
|
|
|
- pf1 = (argc >= 3 && argv[2][0] == '6') ? AF_INET6 : AF_INET;
|
|
|
-
|
|
|
- if (isnulladdr(&oldip, pf)) {
|
|
|
- if (pf1 == AF_INET6) {
|
|
|
- newip.s = "::";
|
|
|
- newip.len = 2;
|
|
|
- } else {
|
|
|
- newip.s = "0.0.0.0";
|
|
|
- newip.len = 7;
|
|
|
- }
|
|
|
- } else {
|
|
|
- if (argc < 2) {
|
|
|
- newip = str2;
|
|
|
- }
|
|
|
- else {
|
|
|
- newip.s = argv[1];
|
|
|
- newip.len = strlen(newip.s);
|
|
|
- }
|
|
|
- }
|
|
|
- /*
|
|
|
- * Don't update port (leave it 0) if it's an SDP
|
|
|
- * offer (answer has been handled above), since
|
|
|
- * originating device apparently doesn't want to
|
|
|
- * receive any media streams yet and besides RTP
|
|
|
- * proxy doesn't have a valid port to sent this
|
|
|
- * stream to anyway.
|
|
|
- */
|
|
|
- if (oldport_i != 0) {
|
|
|
- newport.s = int2str(port, &newport.len); /* beware static buffer */
|
|
|
- /* Alter port. */
|
|
|
- body1.s = m1p;
|
|
|
- body1.len = bodylimit - body1.s;
|
|
|
- if (alter_mediaport(msg, &body1, &oldport, &newport, 0) == -1) {
|
|
|
- FORCE_RTP_PROXY_RET (-1);
|
|
|
- }
|
|
|
- }
|
|
|
- /*
|
|
|
- * Alter RTCP attribute if present. Inserting RTP port + 1 (as allocated
|
|
|
- * by RTP proxy). No IP-address is needed in the new RTCP attribute as the
|
|
|
- * 'c' attribute (altered below) will contain the RTP proxy IP address.
|
|
|
- * See RFC 3605 for definition of RTCP attribute.
|
|
|
- */
|
|
|
- if (oldrtcp.s && oldrtcp.len) {
|
|
|
- newrtcp.s = int2str(port+1, &newrtcp.len); /* beware static buffer */
|
|
|
- /* Alter port. */
|
|
|
- body1.s = m1p;
|
|
|
- body1.len = bodylimit - body1.s;
|
|
|
- if (alter_rtcp(msg, &body1, &oldrtcp, &newrtcp) == -1) {
|
|
|
- FORCE_RTP_PROXY_RET (-1);
|
|
|
- }
|
|
|
- }
|
|
|
- /*
|
|
|
- * Alter IP. Don't alter IP common for the session
|
|
|
- * more than once, but always alter it even if the IP is present
|
|
|
- * also in the media description (for broken UAs that use the
|
|
|
- * fallback IP from the session header instead of the more specific
|
|
|
- * one from the media description).
|
|
|
- */
|
|
|
- if (c1_oldip.s != NULL && !c1p_altered){
|
|
|
- body1.s = c1p;
|
|
|
- body1.len = bodylimit - body1.s;
|
|
|
- if (alter_mediaip(msg, &body1, &c1_oldip, c1_pf,
|
|
|
- &newip, pf1, 0) == -1) {
|
|
|
- FORCE_RTP_PROXY_RET (-1);
|
|
|
- }
|
|
|
- c1p_altered = 1;
|
|
|
- }
|
|
|
- if (c2p != NULL && oldip.s != c1_oldip.s) {
|
|
|
- body1.s = c2p;
|
|
|
- body1.len = bodylimit - body1.s;
|
|
|
- if (alter_mediaip(msg, &body1, &oldip, pf, &newip, pf1, 0) == -1) {
|
|
|
- FORCE_RTP_PROXY_RET (-1);
|
|
|
- }
|
|
|
- }
|
|
|
- } /* Iterate medias in session */
|
|
|
- } /* Iterate sessions */
|
|
|
- free_opts(&opts, &rep_opts, &pt_opts);
|
|
|
-
|
|
|
- if (proxied == 0) {
|
|
|
- cp = pkg_malloc((ANORTPPROXY_LEN + CRLF_LEN) * sizeof(char));
|
|
|
- if (cp == NULL) {
|
|
|
- LOG(L_ERR, "ERROR: force_rtp_proxy2: out of memory\n");
|
|
|
- return -1;
|
|
|
- }
|
|
|
- anchor = anchor_lump(msg, body.s + body.len - msg->buf, 0, 0);
|
|
|
- if (anchor == NULL) {
|
|
|
- LOG(L_ERR, "ERROR: force_rtp_proxy2: anchor_lump failed\n");
|
|
|
- pkg_free(cp);
|
|
|
- return -1;
|
|
|
- }
|
|
|
- memcpy(cp, CRLF, CRLF_LEN);
|
|
|
- memcpy(cp + CRLF_LEN, ANORTPPROXY, ANORTPPROXY_LEN);
|
|
|
- if (insert_new_lump_after(anchor, cp, ANORTPPROXY_LEN + CRLF_LEN, 0) == NULL) {
|
|
|
- LOG(L_ERR, "ERROR: force_rtp_proxy2: insert_new_lump_after failed\n");
|
|
|
- pkg_free(cp);
|
|
|
- return -1;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return 1;
|
|
|
-}
|
|
|
-
|
|
|
-static int
|
|
|
-force_rtp_proxy1_f(struct sip_msg* msg, char* str1, char* str2)
|
|
|
-{
|
|
|
- char *cp;
|
|
|
- fparam_t param2;
|
|
|
-
|
|
|
- char newip[IP_ADDR_MAX_STR_SIZE];
|
|
|
-
|
|
|
- cp = ip_addr2a(&msg->rcv.dst_ip);
|
|
|
- strcpy(newip, cp);
|
|
|
- param2.type = FPARAM_STRING;
|
|
|
- param2.orig = param2.v.asciiz = newip;
|
|
|
- return force_rtp_proxy2_f(msg, str1, (char*)¶m2);
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
#define DSTIP_PARAM ";dstip="
|
|
|
#define DSTIP_PARAM_LEN (sizeof(DSTIP_PARAM) - 1)
|
|
|
|