int rtpp_test(struct rtpp_node *node, int isdisabled, int force) { int rtpp_ver; char *cp; struct iovec v[2] = {{NULL, 0}, {"V", 1}}; struct iovec vf[4] = {{NULL, 0}, {"VF", 2}, {" ", 1}, {REQ_CPROTOVER, 8}}; 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; } cp = send_rtpp_command(node, vf, 4); if (cp == NULL) { LOG(L_WARN,"WARNING: rtpp_test: RTP proxy went down during " "version query\n"); break; } if (cp[0] == 'E' || atoi(cp) != 1) { 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-" : ""); 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; }
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 rtpproxy_stop_stream(struct sip_msg* msg, int stream2uac) { int nitems; str callid, from_tag, to_tag; struct rtpp_node *node; struct iovec v[] = { {NULL, 0}, {"S", 1}, /* 1 */ {" ", 1}, {NULL, 0}, /* 3 callid */ {" ", 1}, {NULL, 0}, /* 5 from tag */ {";1 ", 3}, {NULL, 0}, /* 7 to tag */ {";1", 2} }; if (get_callid(msg, &callid) == -1 || callid.len == 0) { LM_ERR("can't get Call-Id field\n"); return -1; } if (get_to_tag(msg, &to_tag) == -1) { LM_ERR("can't get To tag\n"); return -1; } if (get_from_tag(msg, &from_tag) == -1 || from_tag.len == 0) { LM_ERR("can't get From tag\n"); return -1; } STR2IOVEC(callid, v[3]); node = select_rtpp_node(callid, 1); if (!node) { LM_ERR("no available proxies\n"); return -1; } if (node->rn_ptl_supported == 0) { LM_ERR("required functionality is not " "supported by the version of the RTPproxy running on the selected " "node. Please upgrade the RTPproxy and try again.\n"); return -1; } set_rtp_inst_pvar(msg, &node->rn_url); nitems = 9; if (stream2uac == 0) { 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 -= 2; } send_rtpp_command(node, v, nitems); return 1; }
static int rtpproxy_stream(struct sip_msg* msg, str *pname, int count, int stream2uac) { int nitems; str callid, from_tag, to_tag; struct rtpp_node *node; char cbuf[16]; struct iovec v[] = { {NULL, 0}, {cbuf, 0}, /* 1 P<count> */ {" ", 1}, {NULL, 0}, /* 3 callid */ {" ", 1}, {NULL, 0}, /* 5 pname */ {" session ", 9}, {NULL, 0}, /* 7 from tag */ {";1 ", 3}, {NULL, 0}, /* 9 to tag */ {";1", 2} }; if (get_callid(msg, &callid) == -1 || callid.len == 0) { LM_ERR("can't get Call-Id field\n"); return -1; } if (get_to_tag(msg, &to_tag) == -1) { LM_ERR("can't get To tag\n"); return -1; } if (get_from_tag(msg, &from_tag) == -1 || from_tag.len == 0) { LM_ERR("can't get From tag\n"); return -1; } v[1].iov_len = sprintf(cbuf, "P%d", count); STR2IOVEC(callid, v[3]); STR2IOVEC(*pname, v[5]); node = select_rtpp_node(callid, 1); if (!node) { LM_ERR("no available proxies\n"); return -1; } if (node->rn_ptl_supported == 0) { LM_ERR("required functionality is not " "supported by the version of the RTPproxy running on the selected " "node. Please upgrade the RTPproxy and try again.\n"); return -1; } nitems = 11; if (stream2uac == 0) { if (to_tag.len == 0) return -1; STR2IOVEC(to_tag, v[7]); STR2IOVEC(from_tag, v[9]); } else { STR2IOVEC(from_tag, v[7]); STR2IOVEC(to_tag, v[9]); if (to_tag.len <= 0) nitems -= 2; } send_rtpp_command(node, v, nitems); return 1; }
static int force_rtp_proxy_f(struct sip_msg* msg, char* str1, char* str2) { str body, body1, oldport, oldip, oldip1, newport, newip; int create, port, cldelta; char buf[16]; char *cp; if (msg->first_line.type == SIP_REQUEST && msg->first_line.u.request.method_value == METHOD_INVITE) { create = 1; } else if (msg->first_line.type == SIP_REPLY) { create = 0; } else { return -1; } if (msg->callid == NULL || msg->callid->body.len <= 0) { LOG(L_ERR, "ERROR: force_rtp_proxy: no Call-Id field\n"); return -1; } if (extract_body(msg, &body) == -1 || body.len == 0) return -1; if (extract_mediaip(&body, &oldip) == -1) { LOG(L_ERR, "ERROR: force_rtp_proxy: can't extract media IP from the message\n"); return -1; } body1.s = oldip.s + oldip.len; body1.len = body.s + body.len - body1.s; if (extract_mediaip(&body1, &oldip1) == -1) { oldip1.len = 0; } if (extract_mediaport(&body, &oldport) == -1) { LOG(L_ERR, "ERROR: force_rtp_proxy: can't extract media port from the message\n"); return -1; } cp = send_rtpp_command(&(msg->callid->body), create ? 'U' : 'L', 1); if (cp == NULL) return -1; port = atoi(cp); if (port <= 0 || port > 65535) return -1; newport.s = buf; newport.len = sprintf(buf, "%d", port); newip.s = ip_addr2a(&msg->rcv.dst_ip); newip.len = strlen(newip.s); cldelta = 0; if (alter_mediaip(msg, &body, &oldip, &newip, &cldelta, 0) == -1) return -1; if (oldip1.len > 0 && alter_mediaip(msg, &body1, &oldip1, &newip, &cldelta, 0) == -1) return -1; if (alter_mediaport(msg, &body, &oldport, &newport, &cldelta, 0) == -1) return -1; if (cldelta == 0) return 1; return (update_clen(msg, body.len + cldelta)); }
static int force_rtp_proxy2_f(struct sip_msg* msg, char* str1, char* str2) { str body, body1, oldport, oldip, newport, newip; str callid, from_tag, to_tag, tmp; int create, port, len, asymmetric, flookup, argc, proxied, real; int oidx, pf=0, pf1, force, node_idx; char opts[16]; char *cp, *cp1; char *cpend, *next; char **ap, *argv[10]; struct lump* anchor; struct rtpp_node *node; struct iovec v[14] = { {NULL, 0}, /* command */ {NULL, 0}, /* options */ {" ", 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 */ }; char *v1p, *v2p, *c1p, *c2p, *m1p, *m2p, *bodylimit; char medianum_buf[20]; int medianum, media_multi; str medianum_str, tmpstr1; int c1p_altered; v[1].iov_base=opts; asymmetric = flookup = force = real = 0; oidx = 1; node_idx = -1; for (cp = str1; *cp != '\0'; cp++) { switch (*cp) { case ' ': case '\t': break; case 'a': case 'A': opts[oidx++] = 'A'; asymmetric = 1; real = 1; break; case 'i': case 'I': opts[oidx++] = 'I'; break; case 'e': case 'E': opts[oidx++] = 'E'; break; case 'l': case 'L': flookup = 1; break; case 'f': case 'F': force = 1; break; case 'r': case 'R': real = 1; break; case 'n': case 'N': cp++; for (len = 0; isdigit(cp[len]); len++) continue; if (len == 0) { LOG(L_ERR, "ERROR: force_rtp_proxy2: non-negative integer" "should follow N option\n"); return -1; } node_idx = strtoul(cp, NULL, 10); cp += len - 1; break; default: LOG(L_ERR, "ERROR: force_rtp_proxy2: unknown option `%c'\n", *cp); return -1; } } if (msg->first_line.type == SIP_REQUEST && msg->first_line.u.request.method_value == METHOD_INVITE) { create = 1; } else if (msg->first_line.type == SIP_REPLY) { create = 0; } else { return -1; } /* 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"); return -1; } if (get_callid(msg, &callid) == -1 || callid.len == 0) { LOG(L_ERR, "ERROR: force_rtp_proxy2: can't get Call-Id field\n"); return -1; } if (get_to_tag(msg, &to_tag) == -1) { LOG(L_ERR, "ERROR: force_rtp_proxy2: can't get To tag\n"); return -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"); return -1; } if (flookup != 0) { if (create == 0 || to_tag.len == 0) return -1; create = 0; tmp = from_tag; from_tag = to_tag; to_tag = tmp; } 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) return -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"); return -1; } v2p = find_next_sdp_line(v1p, bodylimit, 'v', bodylimit); media_multi = (v2p != bodylimit); v2p = v1p; medianum = 0; 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"); return -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; /* 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 */ tmpstr1.s = c2p ? c2p : c1p; if (tmpstr1.s == NULL) { /* No "c=" */ LOG(L_ERR, "ERROR: force_rtp_proxy2: can't" " find media IP in the message\n"); return -1; } 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"); return -1; } tmpstr1.s = m1p; tmpstr1.len = m2p - m1p; if (extract_mediaport(&tmpstr1, &oldport) == -1) { LOG(L_ERR, "ERROR: force_rtp_proxy2: can't" " extract media port from the message\n"); return -1; } ++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) { opts[oidx] = '6'; oidx++; } snprintf(medianum_buf, sizeof medianum_buf, "%d", medianum); medianum_str.s = medianum_buf; medianum_str.len = strlen(medianum_buf); opts[0] = (create == 0) ? 'L' : 'U'; v[1].iov_len = oidx; STR2IOVEC(callid, v[3]); STR2IOVEC(newip, v[5]); STR2IOVEC(oldport, v[7]); STR2IOVEC(from_tag, v[9]); if (1 || media_multi) /* XXX netch: can't choose now*/ { STR2IOVEC(medianum_str, v[11]); } else { v[10].iov_len = v[11].iov_len = 0; } STR2IOVEC(to_tag, v[13]); do { node = select_rtpp_node(callid, 1, node_idx); if (!node) { LOG(L_ERR, "ERROR: force_rtp_proxy2: no available proxies\n"); return -1; } cp = send_rtpp_command(node, v, (to_tag.len > 0) ? 14 : 12); } while (cp == NULL); /* 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"); return -1; } port = atoi(argv[0]); if (port <= 0 || port > 65535) { LOG(L_ERR, "force_rtp_proxy2: incorrect port in reply from rtp proxy\n"); return -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 { newip.s = (argc < 2) ? str2 : argv[1]; newip.len = strlen(newip.s); } 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) return -1; /* * Alter IP. Don't alter IP common for the session * more than once. */ if (c2p != NULL || !c1p_altered) { body1.s = c2p ? c2p : c1p; body1.len = bodylimit - body1.s; if (alter_mediaip(msg, &body1, &oldip, pf, &newip, pf1, 0) == -1) return -1; if (!c2p) c1p_altered = 1; } } /* Iterate medias in session */ } /* Iterate sessions */ if (proxied == 0) { cp = pkg_malloc(ANORTPPROXY_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, ANORTPPROXY, ANORTPPROXY_LEN); if (insert_new_lump_after(anchor, cp, ANORTPPROXY_LEN, 0) == NULL) { LOG(L_ERR, "ERROR: force_rtp_proxy2: insert_new_lump_after failed\n"); pkg_free(cp); return -1; } } return 1; }