Skip to content
Snippets Groups Projects
rtp.c 66.1 KiB
Newer Older
  • Learn to ignore specific revisions
  • 	/* External RTP Bridge up, now loop and see if something happes that force us to take the
    		media back to Asterisk */
    
    	cs[0] = c0;
    	cs[1] = c1;
    	cs[2] = NULL;
    
    	oldcodec0 = codec0;
    	oldcodec1 = codec1;
    
    	for (;;) {
    
    		/* Check if something changed... */
    
    		if ((c0->tech_pvt != pvt0)  ||
    			(c1->tech_pvt != pvt1) ||
    
    			(c0->masq || c0->masqr || c1->masq || c1->masqr)) {
    
    				ast_log(LOG_DEBUG, "Oooh, something is weird, backing out\n");
    
    					if (pr0->set_rtp_peer(c0, NULL, NULL, 0, 0)) 
    
    						ast_log(LOG_WARNING, "Channel '%s' failed to break RTP bridge\n", c0->name);
    
    					if (pr1->set_rtp_peer(c1, NULL, NULL, 0, 0)) 
    
    						ast_log(LOG_WARNING, "Channel '%s' failed to break RTP bridge\n", c1->name);
    
    				return AST_BRIDGE_RETRY;
    
    		/* Now check if they have changed address */
    
    		ast_rtp_get_peer(p1, &t1);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		ast_rtp_get_peer(p0, &t0);
    
    		if (pr0->get_codec)
    			codec0 = pr0->get_codec(c0);
    		if (pr1->get_codec)
    			codec1 = pr1->get_codec(c1);
    
    		if (vp1)
    			ast_rtp_get_peer(vp1, &vt1);
    		if (vp0)
    			ast_rtp_get_peer(vp0, &vt0);
    
    		if (inaddrcmp(&t1, &ac1) || (vp1 && inaddrcmp(&vt1, &vac1)) || (codec1 != oldcodec1)) {
    
    			if (option_debug > 1) {
    
    				ast_log(LOG_DEBUG, "Oooh, '%s' changed end address to %s:%d (format %d)\n", 
    					c1->name, ast_inet_ntoa(iabuf, sizeof(iabuf), t1.sin_addr), ntohs(t1.sin_port), codec1);
    				ast_log(LOG_DEBUG, "Oooh, '%s' changed end vaddress to %s:%d (format %d)\n", 
    					c1->name, ast_inet_ntoa(iabuf, sizeof(iabuf), vt1.sin_addr), ntohs(vt1.sin_port), codec1);
    				ast_log(LOG_DEBUG, "Oooh, '%s' was %s:%d/(format %d)\n", 
    					c1->name, ast_inet_ntoa(iabuf, sizeof(iabuf), ac1.sin_addr), ntohs(ac1.sin_port), oldcodec1);
    
    				ast_log(LOG_DEBUG, "Oooh, '%s' was %s:%d/(format %d)\n", 
    
    					c1->name, ast_inet_ntoa(iabuf, sizeof(iabuf), vac1.sin_addr), ntohs(vac1.sin_port), oldcodec1);
    			}
    
    			if (pr0->set_rtp_peer(c0, t1.sin_addr.s_addr ? p1 : NULL, vt1.sin_addr.s_addr ? vp1 : NULL, codec1, ast_test_flag(p1, FLAG_NAT_ACTIVE))) 
    
    				ast_log(LOG_WARNING, "Channel '%s' failed to update to '%s'\n", c0->name, c1->name);
    			memcpy(&ac1, &t1, sizeof(ac1));
    
    			memcpy(&vac1, &vt1, sizeof(vac1));
    
    			oldcodec1 = codec1;
    
    		if (inaddrcmp(&t0, &ac0) || (vp0 && inaddrcmp(&vt0, &vac0))) {
    
    			if (option_debug) {
    				ast_log(LOG_DEBUG, "Oooh, '%s' changed end address to %s:%d (format %d)\n", 
    					c0->name, ast_inet_ntoa(iabuf, sizeof(iabuf), t0.sin_addr), ntohs(t0.sin_port), codec0);
    				ast_log(LOG_DEBUG, "Oooh, '%s' was %s:%d/(format %d)\n", 
    					c0->name, ast_inet_ntoa(iabuf, sizeof(iabuf), ac0.sin_addr), ntohs(ac0.sin_port), oldcodec0);
    			}
    
    			if (pr1->set_rtp_peer(c1, t0.sin_addr.s_addr ? p0 : NULL, vt0.sin_addr.s_addr ? vp0 : NULL, codec0, ast_test_flag(p0, FLAG_NAT_ACTIVE)))
    
    				ast_log(LOG_WARNING, "Channel '%s' failed to update to '%s'\n", c1->name, c0->name);
    			memcpy(&ac0, &t0, sizeof(ac0));
    
    			memcpy(&vac0, &vt0, sizeof(vac0));
    
    			oldcodec0 = codec0;
    
    		who = ast_waitfor_n(cs, 2, &timeoutms);
    
    		if (!who) {
    
    			if (option_debug)
    				ast_log(LOG_DEBUG, "Ooh, empty read...\n");
    
    			/* check for hangup / whentohangup */
    
    			if (ast_check_hangup(c0) || ast_check_hangup(c1))
    				break;
    
    			continue;
    		}
    		f = ast_read(who);
    
    		other = (who == c0) ? c1 : c0; /* the other channel */
    
    		if (!f || ((f->frametype == AST_FRAME_DTMF) &&
    				   (((who == c0) && (flags & AST_BRIDGE_DTMF_CHANNEL_0)) || 
    			       ((who == c1) && (flags & AST_BRIDGE_DTMF_CHANNEL_1))))) {
    
    			/* breaking out of the bridge. */
    
    			*fo = f;
    			*rc = who;
    
    			if (option_debug)
    				ast_log(LOG_DEBUG, "Oooh, got a %s\n", f ? "digit" : "hangup");
    
    				if (pr0->set_rtp_peer(c0, NULL, NULL, 0, 0)) 
    
    					ast_log(LOG_WARNING, "Channel '%s' failed to break RTP bridge\n", c0->name);
    
    				if (pr1->set_rtp_peer(c1, NULL, NULL, 0, 0)) 
    
    					ast_log(LOG_WARNING, "Channel '%s' failed to break RTP bridge\n", c1->name);
    
    			return AST_BRIDGE_COMPLETE;
    
    Mark Spencer's avatar
    Mark Spencer committed
    		} else if ((f->frametype == AST_FRAME_CONTROL) && !(flags & AST_BRIDGE_IGNORE_SIGS)) {
    			if ((f->subclass == AST_CONTROL_HOLD) || (f->subclass == AST_CONTROL_UNHOLD) ||
    			    (f->subclass == AST_CONTROL_VIDUPDATE)) {
    
    				ast_indicate(other, f->subclass);
    
    Mark Spencer's avatar
    Mark Spencer committed
    				ast_frfree(f);
    			} else {
    				*fo = f;
    				*rc = who;
    				ast_log(LOG_DEBUG, "Got a FRAME_CONTROL (%d) frame on channel %s\n", f->subclass, who->name);
    				return AST_BRIDGE_COMPLETE;
    			}
    
    Mark Spencer's avatar
    Mark Spencer committed
    			if ((f->frametype == AST_FRAME_DTMF) || 
    				(f->frametype == AST_FRAME_VOICE) || 
    				(f->frametype == AST_FRAME_VIDEO)) {
    
    				/* Forward voice or DTMF frames if they happen upon us */
    
    				ast_write(other, f);
    
    			ast_frfree(f);
    
    		/* Swap priority not that it's a big deal at this point */
    		cs[2] = cs[0];
    		cs[0] = cs[1];
    		cs[1] = cs[2];
    		
    	}
    
    	return AST_BRIDGE_FAILED;
    
    static int rtp_do_debug_ip(int fd, int argc, char *argv[])
    {
    	struct hostent *hp;
    	struct ast_hostent ahp;
    	char iabuf[INET_ADDRSTRLEN];
    	int port = 0;
    	char *p, *arg;
    
    	if (argc != 4)
    		return RESULT_SHOWUSAGE;
    	arg = argv[3];
    	p = strstr(arg, ":");
    
    		*p = '\0';
    		p++;
    		port = atoi(p);
    	}
    	hp = ast_gethostbyname(arg, &ahp);
    	if (hp == NULL)
    		return RESULT_SHOWUSAGE;
    	rtpdebugaddr.sin_family = AF_INET;
    	memcpy(&rtpdebugaddr.sin_addr, hp->h_addr, sizeof(rtpdebugaddr.sin_addr));
    	rtpdebugaddr.sin_port = htons(port);
    	if (port == 0)
    		ast_cli(fd, "RTP Debugging Enabled for IP: %s\n", ast_inet_ntoa(iabuf, sizeof(iabuf), rtpdebugaddr.sin_addr));
    	else
    		ast_cli(fd, "RTP Debugging Enabled for IP: %s:%d\n", ast_inet_ntoa(iabuf, sizeof(iabuf), rtpdebugaddr.sin_addr), port);
    	rtpdebug = 1;
    	return RESULT_SUCCESS;
    }
    
    static int rtp_do_debug(int fd, int argc, char *argv[])
    {
    
    	if(argc != 2) {
    
    		if(argc != 4)
    			return RESULT_SHOWUSAGE;
    		return rtp_do_debug_ip(fd, argc, argv);
    	}
    	rtpdebug = 1;
    	memset(&rtpdebugaddr,0,sizeof(rtpdebugaddr));
    	ast_cli(fd, "RTP Debugging Enabled\n");
    	return RESULT_SUCCESS;
    }
       
    static int rtp_no_debug(int fd, int argc, char *argv[])
    {
    	if(argc !=3)
    		return RESULT_SHOWUSAGE;
    	rtpdebug = 0;
    	ast_cli(fd,"RTP Debugging Disabled\n");
    	return RESULT_SUCCESS;
    }
    
    
    static int stun_do_debug(int fd, int argc, char *argv[])
    {
    	if(argc != 2) {
    		return RESULT_SHOWUSAGE;
    	}
    	stundebug = 1;
    	ast_cli(fd, "STUN Debugging Enabled\n");
    	return RESULT_SUCCESS;
    }
       
    static int stun_no_debug(int fd, int argc, char *argv[])
    {
    	if(argc !=3)
    		return RESULT_SHOWUSAGE;
    	stundebug = 0;
    	ast_cli(fd,"STUN Debugging Disabled\n");
    	return RESULT_SUCCESS;
    }
    
    
    
    static char debug_usage[] =
      "Usage: rtp debug [ip host[:port]]\n"
      "       Enable dumping of all RTP packets to and from host.\n";
    
    static char no_debug_usage[] =
      "Usage: rtp no debug\n"
      "       Disable all RTP debugging\n";
    
    
    static char stun_debug_usage[] =
      "Usage: stun debug\n"
      "       Enable STUN (Simple Traversal of UDP through NATs) debugging\n";
    
    static char stun_no_debug_usage[] =
      "Usage: stun no debug\n"
      "       Disable STUN debugging\n";
    
    
    
    static struct ast_cli_entry  cli_debug_ip =
    {{ "rtp", "debug", "ip", NULL } , rtp_do_debug, "Enable RTP debugging on IP", debug_usage };
    
    static struct ast_cli_entry  cli_debug =
    {{ "rtp", "debug", NULL } , rtp_do_debug, "Enable RTP debugging", debug_usage };
    
    static struct ast_cli_entry  cli_no_debug =
    {{ "rtp", "no", "debug", NULL } , rtp_no_debug, "Disable RTP debugging", no_debug_usage };
    
    
    static struct ast_cli_entry  cli_stun_debug =
    {{ "stun", "debug", NULL } , stun_do_debug, "Enable STUN debugging", stun_debug_usage };
    
    static struct ast_cli_entry  cli_stun_no_debug =
    {{ "stun", "no", "debug", NULL } , stun_no_debug, "Disable STUN debugging", stun_no_debug_usage };
    
    
    int ast_rtp_reload(void)
    
    {
    	struct ast_config *cfg;
    	char *s;
    
    	rtpstart = 5000;
    	rtpend = 31000;
    
    	dtmftimeout = DEFAULT_DTMF_TIMEOUT;
    
    	cfg = ast_config_load("rtp.conf");
    
    	if (cfg) {
    		if ((s = ast_variable_retrieve(cfg, "general", "rtpstart"))) {
    			rtpstart = atoi(s);
    			if (rtpstart < 1024)
    				rtpstart = 1024;
    			if (rtpstart > 65535)
    				rtpstart = 65535;
    		}
    		if ((s = ast_variable_retrieve(cfg, "general", "rtpend"))) {
    			rtpend = atoi(s);
    			if (rtpend < 1024)
    				rtpend = 1024;
    			if (rtpend > 65535)
    				rtpend = 65535;
    		}
    
    		if ((s = ast_variable_retrieve(cfg, "general", "rtpchecksums"))) {
    
    			if (ast_false(s))
    				nochecksums = 1;
    
    				ast_log(LOG_WARNING, "Disabling RTP checksums is not supported on this operating system!\n");
    #endif
    
    		if ((s = ast_variable_retrieve(cfg, "general", "dtmftimeout"))) {
    			dtmftimeout = atoi(s);
    			if ((dtmftimeout < 0) || (dtmftimeout > 20000)) {
    				ast_log(LOG_WARNING, "DTMF timeout of '%d' outside range, using default of '%d' instead\n",
    					dtmftimeout, DEFAULT_DTMF_TIMEOUT);
    				dtmftimeout = DEFAULT_DTMF_TIMEOUT;
    			};
    		}
    
    		ast_config_destroy(cfg);
    
    	}
    	if (rtpstart >= rtpend) {
    
    		ast_log(LOG_WARNING, "Unreasonable values for RTP start/end port in rtp.conf\n");
    
    		rtpstart = 5000;
    		rtpend = 31000;
    	}
    	if (option_verbose > 1)
    		ast_verbose(VERBOSE_PREFIX_2 "RTP Allocating from port range %d -> %d\n", rtpstart, rtpend);
    
    /*! \brief Initialize the RTP system in Asterisk */
    
    void ast_rtp_init(void)
    {
    
    	ast_cli_register(&cli_debug);
    	ast_cli_register(&cli_debug_ip);
    	ast_cli_register(&cli_no_debug);
    
    	ast_cli_register(&cli_stun_debug);
    	ast_cli_register(&cli_stun_no_debug);
    
    	ast_rtp_reload();
    }