diff options
Diffstat (limited to 'net/ser/files/patch-modules__nathelper__moh.c')
-rw-r--r-- | net/ser/files/patch-modules__nathelper__moh.c | 434 |
1 files changed, 0 insertions, 434 deletions
diff --git a/net/ser/files/patch-modules__nathelper__moh.c b/net/ser/files/patch-modules__nathelper__moh.c deleted file mode 100644 index 5c8ae4f33059..000000000000 --- a/net/ser/files/patch-modules__nathelper__moh.c +++ /dev/null @@ -1,434 +0,0 @@ - -$FreeBSD$ - ---- modules/nathelper/moh.c -+++ modules/nathelper/moh.c -@@ -0,0 +1,428 @@ -+/* $Id: patch-modules::nathelper::moh.c,v 1.2 2005/04/05 13:10:07 netch Exp $ -+ * -+ * Copyright (C) 2005 Porta Software Ltd -+ * -+ * This file is part of ser, a free SIP server. -+ * -+ * ser is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version -+ * -+ * For a license to use the ser software under conditions -+ * other than those described here, or to purchase support for this -+ * software, please contact iptel.org by e-mail at the following addresses: -+ * info@iptel.org -+ * -+ * ser is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ * -+ */ -+ -+#include <sys/types.h> -+#include <sys/uio.h> -+#include <stdio.h> -+#include <stdlib.h> -+#include "../../parser/parser_f.h" -+#include "../../ut.h" -+#include "nhelpr_funcs.h" -+#include "nathelper.h" -+ -+/* -+ * The following macro is used in force_rtp_proxy2_f() and twice -+ * in start_moh() -+ */ -+ -+#define PARSE_PROXY_REPLY \ -+ do { \ -+ 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; \ -+ } \ -+ } \ -+ } while(0) -+ -+int -+is_hold_f(struct sip_msg* msg, char *str1, char *str2) -+{ -+ /* Look into body and find whether we see 0.0.0.0 as IP address. -+ * extract_mediaport() is designed to parse address from SDP. -+ * XXX Check all addresses or only first one? What if have some -+ * real addresses and some zero ones? -+ */ -+ str body, ip; -+ int pf; -+ -+ if (extract_body(msg, &body) == -1) { -+ LOG(L_ERR,"ERROR: is_hold: cannot extract body from msg!\n"); -+ return 0; -+ } -+ if (extract_mediaip(&body, &ip, &pf) == -1) { -+ LOG(L_ERR, "ERROR: is_hold: can't extract media IP from the SDP\n"); -+ return 0; -+ } -+ return isnulladdr(&ip, pf) ? 1 : -1; -+} -+ -+int -+start_moh_f(struct sip_msg* msg, char* str1, char* str2) -+{ -+ str callid, from_tag, to_tag; -+ int asymmetric, flookup, force, real; -+ int oidx, argc, medianum, c1p_altered, pf, pf1; -+ int seen_audio, seen_video; -+ str body, body1, tmpstr1, oldip, newip, oldport, newport; -+ str medianum_str; -+ char *cpend, *next, *bodylimit, *v1p, *v2p, *c1p, *c2p, *m1p, *m2p; -+ char *cp; -+ char medianum_buf[20], opts[16]; -+ char **ap, *argv[10]; -+ unsigned port; -+ struct rtpp_node *node; -+ struct iovec v_create[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 */ -+ }; -+ struct iovec v_play[14] = { -+ {NULL, 0}, /* command */ -+ {NULL, 0}, /* options */ -+ {" ", 1}, /* separator */ -+ {NULL, 0}, /* callid */ -+ {" ", 1}, /* separator */ -+ {NULL, 7}, /* pname */ -+ {" ", 1}, /* separator */ -+ {NULL, 1}, /* codecs */ -+ {" ", 1}, /* separator */ -+ {NULL, 0}, /* to_tag */ -+ {";", 1}, /* separator */ -+ {NULL, 0}, /* medianum */ -+ {" ", 1}, /* separator */ -+ {NULL, 0} /* from_tag */ -+ }; -+ -+ /* 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: start_moh: can't get Call-Id field\n"); -+ return -1; -+ } -+ if (get_to_tag(msg, &to_tag) == -1 || to_tag.len <= 0) { -+ LOG(L_ERR, "ERROR: start_moh: 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_moh: can't get From tag\n"); -+ return -1; -+ } -+ /* Setting specific options. XXX Do we really need this? */ -+ v_create[1].iov_base = opts; -+ asymmetric = flookup = force = real = 0; -+ force = 1; /* XXX we must force the proxying in this case */ -+ oidx = 2; /* 'UW' */ -+#if 0 -+ for (cp = str1; cp != NULL && *cp != '\0'; cp++) { -+ switch (*cp) { -+ 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; -+ -+ default: -+ LOG(L_ERR, "ERROR: force_rtp_proxy2: unknown option `%c'\n", *cp); -+ return -1; -+ } -+ } -+#endif -+ /* -+ * Parsing of SDP body. -+ * It can contain a few session descriptions (each start with -+ * "v=" line), and each session may contain a few media descriptions -+ * (each start with "m=" line). -+ * We have to change ports in "m=", and also change IP addresses in -+ * "c=" 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=" -+ * unconditionally. -+ * -+ * Note start_moh() specifics: use only audio media or video media -+ * and stop after first of them of both kinds. But, medianum should -+ * reflect all of them. -+ */ -+ bodylimit = body.s + body.len; -+ v2p = v1p = find_sdp_line(body.s, bodylimit, 'v'); -+ if (v1p == NULL) { -+ LOG(L_ERR, "ERROR: start_moh: no sessions in SDP\n"); -+ return -1; -+ } -+ 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: start_moh: 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 */ -+ seen_audio = seen_video = 0; -+ m2p = m1p; -+ while (!seen_audio || !seen_video) { -+ int is_audio, is_video; -+ /* We pass address to proxy and get some port from -+ * its resources. Then, if old address was empty -+ * (0.0.0.0), create a play stream for this media. -+ */ -+ 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'); -+ ++medianum; -+ /* -+ * start_moh() specifics: work only for audio/video -+ * media and apply to first of any in session. -+ */ -+ is_audio = (strncmp(m1p, "m=audio ", 8) == 0); -+ is_video = (strncmp(m1p, "m=video ", 8) == 0); -+ if ((is_audio && seen_audio) || -+ (is_video && seen_video) || -+ (!is_audio && !is_video)) -+ continue; -+ seen_audio = seen_audio || is_audio; -+ seen_video = seen_video || is_video; -+ /* Extract address and port */ -+ tmpstr1.s = c2p ? c2p : c1p; -+ if (tmpstr1.s == NULL) { -+ /* No "c=" */ -+ LOG(L_ERR, "ERROR: start_moh: 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: start_moh: 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: start_moh: can't extract media port " -+ "from the message\n"); -+ return -1; -+ } -+ 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++; -+ } -+ -+ /* -+ * If don't see NULL addr, this is not hold. -+ * So, skip to next one. -+ * XXX should also support "a=sendonly" -+ */ -+ if (!isnulladdr(&oldip, pf)) -+ continue; -+ -+ /* Prepare proxy command strings. */ -+ snprintf(medianum_buf, sizeof medianum_buf, "%d", medianum); -+ medianum_str.s = medianum_buf; -+ medianum_str.len = strlen(medianum_buf); -+ opts[0] = 'U'; opts[1] = 'W'; -+ v_create[1].iov_len = oidx; -+ STR2IOVEC(callid, v_create[3]); -+ STR2IOVEC(newip, v_create[5]); -+ STR2IOVEC(oldport, v_create[7]); -+ STR2IOVEC(from_tag, v_create[9]); -+ STR2IOVEC(medianum_str, v_create[11]); -+ STR2IOVEC(to_tag, v_create[13]); -+ STR2IOVEC(callid, v_play[3]); -+ if (is_audio) { -+ SZ2IOVEC(pname_audio, v_play[5]); -+ SZ2IOVEC(codecs_audio, v_play[7]); -+ } else { -+ SZ2IOVEC(pname_video, v_play[5]); -+ SZ2IOVEC(codecs_video, v_play[7]); -+ } -+ STR2IOVEC(to_tag, v_play[9]); -+ STR2IOVEC(medianum_str, v_play[11]); -+ STR2IOVEC(from_tag, v_play[13]); -+ SZ2IOVEC("P", v_play[1]); -+ /* Send command. */ -+ do { -+ node = select_rtpp_node(callid, 1); -+ if (!node) { -+ LOG(L_ERR, "ERROR: start_moh: no available proxies\n"); -+ return -1; -+ } -+ cp = send_rtpp_command(node, v_create, 14); -+ if (cp == NULL) -+ continue; -+ LOG(L_DBG, "start_moh: proxy reply to update: %s\n", cp); -+ PARSE_PROXY_REPLY; -+ if (argc < 1) { -+ LOG(L_ERR, "start_moh: no reply from rtp proxy\n"); -+ return -1; -+ } -+ port = atoi(argv[0]); -+ if (port <= 0 || port > 65535) { -+ LOG(L_ERR, "start_moh: incorrect port in reply from rtp proxy\n"); -+ return -1; -+ } -+ -+ pf1 = (argc >= 3 && argv[2][0] == '6') ? AF_INET6 : AF_INET; -+ 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) { -+ LOG(L_ERR, "start_mon: alter_mediaport() failed\n"); -+ 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 = m2p - body1.s; -+ if (alter_mediaip(msg, &body1, &oldip, pf, &newip, pf1, 2) == -1) { -+ LOG(L_ERR, "start_moh: alter_mediaip() failed\n"); -+ return -1; -+ } -+ if (!c2p) -+ c1p_altered = 1; -+ } -+ cp = send_rtpp_command(node, v_play, 14); -+ LOG(L_DBG, "start_moh: proxy reply to play: %s\n", cp); -+ if (cp == NULL) -+ continue; -+ PARSE_PROXY_REPLY; -+ if (argc < 1) { -+ LOG(L_ERR, "start_moh: no reply from rtp proxy\n"); -+ return -1; -+ } -+ } while(cp == NULL); -+ } /* Iterate medias in session */ -+ } /* Iterate sessions */ -+ return 1; -+} -+ -+int -+stop_moh_f(struct sip_msg* msg, char* str1, char* str2) -+{ -+ str callid, to_tag, from_tag; -+ struct rtpp_node *node; -+ struct iovec v_noplay[8] = {{NULL, 0}, {"S", 1}, {" ", 1}, -+ {NULL, 0}, {" ", 1}, {NULL, 0}, {" ", 1}, {NULL, 0}}; -+ struct iovec v_del[8] = {{NULL, 0}, {"DW", 2}, {" ", 1}, -+ {NULL, 0}, {" ", 1}, {NULL, 0}, {" ", 1}, {NULL, 0}}; -+ -+ if (get_callid(msg, &callid) == -1 || callid.len == 0) { -+ LOG(L_ERR, "ERROR: stop_moh: can't get Call-Id field\n"); -+ return -1; -+ } -+ if (get_to_tag(msg, &to_tag) == -1 || to_tag.len <= 0) { -+ LOG(L_ERR, "ERROR: stop_moh: can't get To tag\n"); -+ return -1; -+ } -+ if (get_from_tag(msg, &from_tag) == -1 || from_tag.len == 0) { -+ LOG(L_ERR, "ERROR: stop_moh: can't get From tag\n"); -+ return -1; -+ } -+ /* Ask RTP proxy to stop all plays for this tag. We don't iterate -+ * separate sessions; RTP proxy has knowledge of them. -+ */ -+ STR2IOVEC(callid, v_noplay[3]); -+ STR2IOVEC(to_tag, v_noplay[5]); -+ STR2IOVEC(from_tag, v_noplay[7]); -+ node = select_rtpp_node(callid, 1); -+ send_rtpp_command(node, v_noplay, 8); -+ /* Ask weak deletion for the session. The same as previous; -+ * RTP proxy knows all sessions. -+ */ -+ STR2IOVEC(callid, v_del[3]); -+ STR2IOVEC(to_tag, v_del[5]); -+ STR2IOVEC(from_tag, v_del[7]); -+ send_rtpp_command(node, v_del, 8); -+ return 1; -+} |