📄 rtpproxy_relay.c
字号:
/* Copyright (C) 2003-2007 Thomas Ries <tries@gmx.net> This file is part of Siproxd. Siproxd 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. Siproxd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warrantry 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 Siproxd; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */#include "config.h"#include <pthread.h>#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <errno.h>#include <string.h>#include <sys/time.h>#include <sys/socket.h>#include <netinet/in.h>#include <signal.h>#ifdef HAVE_PTHREAD_SETSCHEDPARAM #include <sched.h>#endif#include <osipparser2/osip_parser.h>#include "siproxd.h"#include "rtpproxy.h"#include "log.h"#ifdef GPL #include "dejitter.h"#endif#if !defined(SOL_IP)#define SOL_IP IPPROTO_IP#endifstatic char const ident[]="$Id: rtpproxy_relay.c,v 1.51 2007/06/08 19:39:03 hb9xar Exp $";/* configuration storage */extern struct siproxd_config configuration;/* * table to remember all active rtp proxy streams */rtp_proxytable_t rtp_proxytable[RTPPROXY_SIZE];/* * Mutex for thread synchronization (locking when accessing common * data structures -> rtp_proxytable[]). * * use a 'fast' mutex for synchronizing - as these are portable... */static pthread_mutex_t rtp_proxytable_mutex = PTHREAD_MUTEX_INITIALIZER;/* thread id of RTP proxy */static pthread_t rtpproxy_tid=0;/* master fd_set */static fd_set master_fdset;static int master_fd_max;/* * forward declarations of internal functions */static void sighdl_alm(int sig) {/* just wake up from select() */};static void *rtpproxy_main(void *i);static void rtpproxy_kill( void );static int rtp_recreate_fdset(void);static void match_socket (int rtp_proxytable_idx);static void error_handler (int rtp_proxytable_idx, int socket_type);/* * initialize and create rtp_relay proxy thread * * RETURNS * STS_SUCCESS on success */int rtp_relay_init( void ) { int sts; int arg=0; struct sigaction sigact;#ifdef USE_DEJITTER dejitter_init();#endif atexit(rtpproxy_kill); /* cancel RTP thread at exit */ /* clean proxy table */ memset (rtp_proxytable, 0, sizeof(rtp_proxytable)); /* initialize fd set for RTP proxy thread */ FD_ZERO(&master_fdset); /* start with an empty fdset */ master_fd_max=-1; /* install signal handler for SIGALRM - used to wake up the rtpproxy thread from select() hibernation */ sigact.sa_handler = sighdl_alm; sigemptyset(&sigact.sa_mask); sigact.sa_flags=0; sigaction(SIGALRM, &sigact, NULL); DEBUGC(DBCLASS_RTP,"create thread"); sts=pthread_create(&rtpproxy_tid, NULL, rtpproxy_main, (void *)&arg); DEBUGC(DBCLASS_RTP,"created, sts=%i", sts); /* set realtime scheduling - if started by root */#ifdef HAVE_PTHREAD_SETSCHEDPARAM { int uid,euid; struct sched_param schedparam;#ifndef _CYGWIN uid=getuid(); euid=geteuid(); DEBUGC(DBCLASS_RTP,"uid=%i, euid=%i", uid, euid); if (uid != euid) seteuid(0); if (geteuid()==0) {#endif#if defined(HAVE_SCHED_GET_PRIORITY_MAX) && defined(HAVE_SCHED_GET_PRIORITY_MIN) int pmin, pmax; /* place ourself at 1/3 of the available priority space */ pmin=sched_get_priority_min(SCHED_RR); pmax=sched_get_priority_max(SCHED_RR); schedparam.sched_priority=pmin+(pmax-pmin)/3; DEBUGC(DBCLASS_RTP,"pmin=%i, pmax=%i, using p=%i", pmin, pmax, schedparam.sched_priority);#else /* just taken a number out of thin air */ schedparam.sched_priority=10; DEBUGC(DBCLASS_RTP,"using p=%i", schedparam.sched_priority);#endif sts=pthread_setschedparam(rtpproxy_tid, SCHED_RR, &schedparam); if (sts != 0) { ERROR("pthread_setschedparam failed: %s", strerror(errno)); }#ifndef _CYGWIN } else { INFO("Unable to use realtime scheduling for RTP proxy"); INFO("You may want to start siproxd as root and switch UID afterwards"); } if (uid != euid) seteuid(euid);#endif }#endif return STS_SUCCESS;}/* * main() of rtpproxy */static void *rtpproxy_main(void *arg) { fd_set fdset; int fd_max; int i, sts; int num_fd; static rtp_buff_t rtp_buff; int count; struct timeval last_tv ; struct timeval sleep_tv ; struct timeval current_tv ; struct timezone tz ; memcpy(&fdset, &master_fdset, sizeof(fdset)); fd_max=master_fd_max; last_tv.tv_sec = 0; last_tv.tv_usec = 0; /* loop forever... */ for (;;) {#ifdef USE_DEJITTER /* calculate time until next packet to send from dejitter buffer */ if (!dejitter_delay_of_next_tx(&sleep_tv, ¤t_tv)) { sleep_tv.tv_sec = 5; sleep_tv.tv_usec = 0; };#else sleep_tv.tv_sec = 5; sleep_tv.tv_usec = 0;#endif num_fd=select(fd_max+1, &fdset, NULL, NULL, &sleep_tv); gettimeofday(¤t_tv, &tz);#ifdef USE_DEJITTER /* Send delayed Packets that are timed to be send */ dejitter_flush(¤t_tv, LOCK_FDSET);#endif /* exit point for this thread in case of program terminaction */ pthread_testcancel(); if ((num_fd<0) && (errno==EINTR)) { /* * wakeup due to a change in the proxy table: * lock mutex, copy master FD set and unlock */ pthread_mutex_lock(&rtp_proxytable_mutex); memcpy(&fdset, &master_fdset, sizeof(fdset)); fd_max=master_fd_max; pthread_mutex_unlock(&rtp_proxytable_mutex); continue; } /* * LOCK the MUTEX */ pthread_mutex_lock(&rtp_proxytable_mutex); /* check for data available and send to destination */ for (i=0;(i<RTPPROXY_SIZE) && (num_fd>0);i++) { /* * RTCP control socket */ if ( (rtp_proxytable[i].rtp_con_rx_sock != 0) && FD_ISSET(rtp_proxytable[i].rtp_con_rx_sock, &fdset) ) { /* yup, have some data to send */ num_fd--; /* read from sock rtp_proxytable[i].rtp_con_rx_sock */ count=read(rtp_proxytable[i].rtp_con_rx_sock, rtp_buff, RTP_BUFFER_SIZE); /* check if something went banana */ if (count < 0) error_handler(i,1) ; /* Buffer really full? This may indicate a too small buffer! */ if (count == RTP_BUFFER_SIZE) { LIMIT_LOG_RATE(30) { WARN("received an RTCP datagram bigger than buffer size"); } } /* * forwarding an RTCP packet only makes sense if we really * have got some data in it (count > 0) */ if (count > 0) { /* find the corresponding TX socket */ if (rtp_proxytable[i].rtp_con_tx_sock == 0) match_socket(i); if (rtp_proxytable[i].rtp_con_tx_sock != 0) { struct sockaddr_in dst_addr; /* write to dest via socket rtp_con_tx_sock */ dst_addr.sin_family = AF_INET; memcpy(&dst_addr.sin_addr.s_addr, &rtp_proxytable[i].remote_ipaddr, sizeof(struct in_addr)); dst_addr.sin_port= htons(rtp_proxytable[i].remote_port+1); /* Don't dejitter RTCP packets */ sts = sendto(rtp_proxytable[i].rtp_con_tx_sock, rtp_buff, count, 0, (const struct sockaddr *)&dst_addr, (socklen_t)sizeof(dst_addr)); /* ignore errors here. We don't know if the remote site does receive RTCP messages at all (or reject them with ICMP-whatever). If it fails, it is lost. Basta, end of story. */ } } /* count > 0 */ /* RTCP does not wind up the keepalive timestamp. */ } /* if */ /* * RTP data stream */ if ( (rtp_proxytable[i].rtp_rx_sock != 0) && FD_ISSET(rtp_proxytable[i].rtp_rx_sock, &fdset) ) { /* yup, have some data to send */ num_fd--; /* read from sock rtp_proxytable[i].rtp_rx_sock */ count=read(rtp_proxytable[i].rtp_rx_sock, rtp_buff, RTP_BUFFER_SIZE); /* check if something went banana */ if (count < 0) error_handler (i,0); /* Buffer really full? This may indicate a too small buffer! */ if (count == RTP_BUFFER_SIZE) { LIMIT_LOG_RATE(30) { WARN("received an RTP datagram bigger than buffer size"); } } /* * forwarding an RTP packet only makes sense if we really * have got some data in it (count > 0) */ if (count > 0) { /* find the corresponding TX socket */ if (rtp_proxytable[i].rtp_tx_sock == 0) match_socket(i); if (rtp_proxytable[i].rtp_tx_sock != 0) { struct sockaddr_in dst_addr;#ifdef USE_DEJITTER struct timeval ttv;#endif /* write to dest via socket rtp_tx_sock */ dst_addr.sin_family = AF_INET; memcpy(&dst_addr.sin_addr.s_addr, &rtp_proxytable[i].remote_ipaddr, sizeof(struct in_addr)); dst_addr.sin_port= htons(rtp_proxytable[i].remote_port);#ifdef USE_DEJITTER dejitter_calc_tx_time(&rtp_buff, &(rtp_proxytable[i].tc), ¤t_tv, &ttv); dejitter_delayedsendto(rtp_proxytable[i].rtp_tx_sock, rtp_buff, count, 0, &dst_addr, &ttv, ¤t_tv, &rtp_proxytable[i], NOLOCK_FDSET);#else sts = sendto(rtp_proxytable[i].rtp_tx_sock, rtp_buff, count, 0, (const struct sockaddr *)&dst_addr, (socklen_t)sizeof(dst_addr)); if (sts == -1) { if (errno != ECONNREFUSED) { osip_call_id_t callid; ERROR("sendto() [%s:%i size=%i] call failed: %s", utils_inet_ntoa(rtp_proxytable[i].remote_ipaddr), rtp_proxytable[i].remote_port, count, strerror(errno)); /* if sendto() fails with bad filedescriptor, * this means that the opposite stream has been * canceled or timed out. * we should then cancel this stream as well.*/ WARN("stopping opposite stream");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -