- released 0.3.6
- code cleanup for UDP masquerading tunnels
This commit is contained in:
@@ -1,7 +1,13 @@
|
||||
0.3.6
|
||||
=====
|
||||
07-Sep-2003: - IPCHAINS based UPD tunneling (kernel masquerading)
|
||||
for RTP traffic (still experimental - but seems to work)
|
||||
22-Sep-2003: - released 0.3.6
|
||||
- Code cleanup for RTP proxy
|
||||
07-Sep-2003: - IPCHAINS based UDP tunneling (kernel masquerading)
|
||||
for RTP traffic (still experimental - but seems to work).
|
||||
To activate it, just set 'rtp_proxy_enable' equal 2
|
||||
in the config. NOTE: siproxd must then be started by
|
||||
root (but dropping privileges works).
|
||||
05-Sep-2003: - configure.in: test for pthreads before libosip (RH9.0)
|
||||
|
||||
0.3.5
|
||||
=====
|
||||
|
||||
@@ -22,16 +22,7 @@ IP addresses and port numbers.
|
||||
|
||||
REQUIREMENTS
|
||||
============
|
||||
- libosip2-2.0.2 (http://www.fsf.org/software/osip/)
|
||||
- pthreads (should be part of any Linux distribution)
|
||||
|
||||
Up to now, siporxd only has been tested under:
|
||||
- Redhat Linux 6.0
|
||||
- Redhat Linux 7.2
|
||||
- SUSE 5.3 (libc5)
|
||||
|
||||
However, it should build and run under newer versions (feedback is welcome).
|
||||
|
||||
see RELNOTES
|
||||
|
||||
|
||||
HOW TO GET STARTED
|
||||
@@ -210,12 +201,10 @@ and visit the website at http://siproxd.sourceforge.net/
|
||||
There is a siproxd mailinglist available on sourceforge.
|
||||
|
||||
Thomas Ries (tries@gmx.net)
|
||||
GnuPG Public Key:
|
||||
pub 1024D/87BCDC94 2000-03-19 Thomas Ries (tries@gmx.net)
|
||||
Key fingerprint = 13D1 19F5 77D0 4CEC 8D3F A24E 09FC C18A 87BC DC94
|
||||
|
||||
VoIP: 17476691342@proxy01.sipphone.com
|
||||
|
||||
GnuPG: pub 1024D/87BCDC94 2000-03-19 Thomas Ries <tries@gmx.net>
|
||||
- Fingerprint = 13D1 19F5 77D0 4CEC 8D3F A24E 09FC C18A 87BC DC94
|
||||
- Key via pgp.openpkg.org / http://www.ries.ch.vu/87BCDC94.pub
|
||||
VoIP: sip:17476691342@proxy01.sipphone.com | sip:thomas@ries.homeip.net
|
||||
|
||||
|
||||
CREDITS
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Release Notes for siproxd-0.3.5
|
||||
Release Notes for siproxd-0.3.6
|
||||
===============================
|
||||
|
||||
- Fli4l OPT_SIP (still experimental) available, check
|
||||
@@ -8,6 +8,7 @@ Release Notes for siproxd-0.3.5
|
||||
masquerading firewall
|
||||
- Includes an RTP data stream proxy for *incoming* audio data
|
||||
(outgoing RTP data should be handled by IP masquerading by the firewall)
|
||||
- Includes Linux/IPCHAINS support for UDP masquerading tunnels as RTP proxy
|
||||
- Port range to be used for incoming RTP traffic is configurable
|
||||
(-> easy to set up apropriate firewall rules for incoming traffic)
|
||||
- RTP proxy can handle multiple RTP streams (eg. audio + video)
|
||||
@@ -20,7 +21,7 @@ Release Notes for siproxd-0.3.5
|
||||
with individual passwords for each user
|
||||
- Logging to syslog in daemon mode
|
||||
- Access control (IP based) for incoming traffic
|
||||
- RPM support (release includes SRC rpm and binary RPMS for Redhat 6.0, 7.2)
|
||||
- RPM support
|
||||
- works with "dial-up" conenctions (dynamic IP addresses)
|
||||
- The host part of UA registration entries can be masqueraded
|
||||
(mask_host, masked_host config items) Siemens SIP phones seem to
|
||||
@@ -43,6 +44,7 @@ Reported to build on:
|
||||
- OpenBSD 2.9
|
||||
|
||||
Reported interoperability (tested with softphones):
|
||||
- Grandstream BudgeTone-100 series (they only work with IPCHAINS RTP proxy)
|
||||
- Linphone (local and remote UA) (http://www.linphone.org)
|
||||
- Kphone (local and remote UA) (http://www.wirlab.net/kphone/)
|
||||
- MSN messenger 4.6 (remote and local UA)
|
||||
@@ -58,24 +60,14 @@ Known bugs:
|
||||
|
||||
|
||||
-----
|
||||
md5sum for siproxd-0.3.5.tar.gz: 8db82f78bf71a04570a85bf897f5d5e5
|
||||
md5sum for siproxd-0.3.5-1rh60.i386.rpm:5bfe3403b00d2c19af5ca38ea7111337
|
||||
md5sum for siproxd-0.3.5-1rh72.i386.rpm:3e45667fe56608fdf5f641ffc2a7a602
|
||||
md5sum for siproxd-0.3.5-1.src.rpm: cde88a553cc8fc20ede2bca0d694d5c9
|
||||
md5sum for siproxd-0.3.6.tar.gz:
|
||||
|
||||
GnuPG signature for siproxd-0.3.5.tar.gz archive:
|
||||
-----BEGIN PGP SIGNATURE-----
|
||||
Version: GnuPG v1.2.1 (GNU/Linux)
|
||||
|
||||
iD8DBQA/UNGOCfzBioe83JQRAgloAKCaMZGhuqpWMio1vVYmzGm4BcpWSACfZlrb
|
||||
y2OJ7ZqlqO8P8yLlCMOHdbo=
|
||||
=sPU3
|
||||
-----END PGP SIGNATURE-----
|
||||
GnuPG signature for siproxd-0.3.6.tar.gz archive:
|
||||
|
||||
|
||||
GnuPG: pub 1024D/87BCDC94 2000-03-19 Thomas Ries <tries@gmx.net>
|
||||
- Fingerprint = 13D1 19F5 77D0 4CEC 8D3F A24E 09FC C18A 87BC DC94
|
||||
- Key via pgp.openpkg.org / http://www.ries.ch.vu/87BCDC94.pub
|
||||
VoIP: sip:17476691342@proxy01.sipphone.com
|
||||
VoIP: sip:17476691342@proxy01.sipphone.com | sip:thomas@ries.homeip.net
|
||||
|
||||
|
||||
|
||||
@@ -32,11 +32,4 @@ TODOs, in random order:
|
||||
- feature: don't bind to 0.0.0.0 address, but only to inbound/outbound IF's
|
||||
(defined by IFNAME)
|
||||
|
||||
- support for "full duplex" RTP proxying
|
||||
|
||||
- optional: instead of using the RTP proxy, open up UDP masquerading
|
||||
tunnels in the firewall and let the kernel do the work.
|
||||
Anyway, there seems to be an issue with some hardphones (BudgeTone-100)
|
||||
that do not work with the RTP proxy (no audio reception)
|
||||
|
||||
- maybe STUN support
|
||||
|
||||
@@ -159,6 +159,17 @@ A: Yes. Siproxd needs to know the public IP address, as this address is
|
||||
7070 - 7079). Outgoing UDP packets must be masqueraded by the firewall.
|
||||
See 'Q: How do I setup IP masquerading for the outgoing RTP traffic'.
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
Q: How do I configure siproxd to use ICPHAINS based UDP masquerading
|
||||
tunnels for proxying the incomming RTP traffic?
|
||||
|
||||
A: Simple. In the config file set the configuration option
|
||||
rtp_proxy_enable = 2. Siproxd *must* then be started by root, I
|
||||
highly recommend to let siproxd drop privileges after startup
|
||||
(user, chrootjail config options).
|
||||
Note: The UDP port range for incomming RTP data still uses the same
|
||||
range as configured in the config file.
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
yet unstructured:
|
||||
|
||||
+2
-2
@@ -166,7 +166,7 @@ INFO("stopping RTP proxy stream for: %s@%s",
|
||||
osip_message_get_call_id(request)->host);
|
||||
#endif
|
||||
/* stop the RTP proxying stream */
|
||||
rtp_stop_fwd(osip_message_get_call_id(request), 0);
|
||||
rtp_stop_fwd(osip_message_get_call_id(request));
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -241,7 +241,7 @@ INFO("stopping RTP proxy stream for: %s@%s",
|
||||
|
||||
/* if this is CANCEL/BYE request, stop RTP proxying */
|
||||
if (MSG_IS_BYE(request) || MSG_IS_CANCEL(request)) {
|
||||
rtp_stop_fwd(osip_message_get_call_id(request), 0);
|
||||
rtp_stop_fwd(osip_message_get_call_id(request));
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
+39
-476
@@ -20,17 +20,7 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include <osipparser2/osip_parser.h>
|
||||
|
||||
@@ -45,179 +35,29 @@ static char const ident[]="$Id: " __FILE__ ": " PACKAGE "-" VERSION "-"\
|
||||
/* configuration storage */
|
||||
extern struct siproxd_config configuration;
|
||||
|
||||
/* use a 'fast' mutex for synchronizing - as these are portable... */
|
||||
pthread_mutex_t rtp_proxytable_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
/*
|
||||
* table to remember all active rtp proxy streams
|
||||
*/
|
||||
rtp_proxytable_t rtp_proxytable[RTPPROXY_SIZE];
|
||||
|
||||
|
||||
/* thread id of RTP proxy */
|
||||
pthread_t rtpproxy_tid=0;
|
||||
|
||||
/* master fd_set */
|
||||
static fd_set master_fdset;
|
||||
static int master_fd_max;
|
||||
|
||||
/* forward declarations */
|
||||
void *rtpproxy_main(void *i);
|
||||
int rtp_recreate_fdset(void);
|
||||
void sighdl_alm(int sig) {/* do nothing, just wake up from select() */};
|
||||
|
||||
/*
|
||||
* initialize and create rtp_proxy thread
|
||||
* initialize and create rtp_proxy
|
||||
*
|
||||
* RETURNS
|
||||
* STS_SUCCESS on success
|
||||
*/
|
||||
int rtpproxy_init( void ) {
|
||||
int sts;
|
||||
int arg=0;
|
||||
struct sigaction sigact;
|
||||
int sts=STS_FAILURE;
|
||||
|
||||
/* clean proxy table */
|
||||
memset (rtp_proxytable, 0, sizeof(rtp_proxytable));
|
||||
if (configuration.rtp_proxy_enable == 0) {
|
||||
sts = STS_SUCCESS;
|
||||
} else if (configuration.rtp_proxy_enable == 1) { // Relay
|
||||
sts = rtp_relay_init ();
|
||||
} else if (configuration.rtp_proxy_enable == 2) { // MASQ tunnels
|
||||
sts = rtp_masq_init ();
|
||||
} else {
|
||||
ERROR("CONFIG: rtp_proxy_enable has invalid value",
|
||||
configuration.rtp_proxy_enable);
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
||||
return STS_SUCCESS;
|
||||
return sts;
|
||||
}
|
||||
|
||||
/*
|
||||
* main() of rtpproxy
|
||||
*/
|
||||
void *rtpproxy_main(void *arg) {
|
||||
struct timeval tv;
|
||||
fd_set fdset;
|
||||
int fd_max;
|
||||
time_t t, last_t=0;
|
||||
int i;
|
||||
int num_fd;
|
||||
osip_call_id_t callid;
|
||||
|
||||
memcpy(&fdset, &master_fdset, sizeof(fdset));
|
||||
fd_max=master_fd_max;
|
||||
|
||||
/* loop forever... */
|
||||
for (;;) {
|
||||
|
||||
tv.tv_sec = 5;
|
||||
tv.tv_usec = 0;
|
||||
|
||||
num_fd=select(fd_max+1, &fdset, NULL, NULL, &tv);
|
||||
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;
|
||||
}
|
||||
|
||||
#ifdef MOREDEBUG /*&&&&*/
|
||||
if (num_fd<0) {
|
||||
int i;
|
||||
WARN("select() returned error [%s]",strerror(errno));
|
||||
for (i=0;i<RTPPROXY_SIZE;i++) {
|
||||
DEBUGC(DBCLASS_RTP,"maxfd=%i",master_fd_max);
|
||||
if (rtp_proxytable[i].sock != 0) {
|
||||
DEBUGC(DBCLASS_RTP,"[%i] -> socket=%i",i, rtp_proxytable[i].sock);
|
||||
}
|
||||
} /* for i */
|
||||
}
|
||||
#endif
|
||||
time(&t);
|
||||
|
||||
/*
|
||||
* LOCK the MUTEX
|
||||
*/
|
||||
pthread_mutex_lock(&rtp_proxytable_mutex);
|
||||
|
||||
/*
|
||||
* RTP relay configured
|
||||
*/
|
||||
if (configuration.rtp_proxy_enable == 1) {
|
||||
/* do the relaying of received UDP packets */
|
||||
rtp_relay(num_fd, &fdset, t);
|
||||
}
|
||||
|
||||
/*
|
||||
* RTP masquerading configured
|
||||
*/
|
||||
#if 0
|
||||
if (configuration.rtp_proxy_enable == 2) {
|
||||
/* do the masquerading - which means nothing here.
|
||||
* we only have to care that the UDP tunnels are
|
||||
* opened and closed */
|
||||
/* &&&&
|
||||
actually we have a problem here - as the incomming
|
||||
RTP data is out of our hands, how shall I know if
|
||||
this RTP stream now really has timed out or not...
|
||||
We might do a 'poll' for the local maddr & mport
|
||||
if it is still occupied.
|
||||
So... what do we do here? I think for now I just let
|
||||
the RTP stream expire and finished.
|
||||
*/
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* age and clean rtp_proxytable (check every 10 seconds)
|
||||
*/
|
||||
if (t > (last_t+10) ) {
|
||||
last_t = t;
|
||||
for (i=0;i<RTPPROXY_SIZE; i++) {
|
||||
if ( (rtp_proxytable[i].sock != 0) &&
|
||||
(rtp_proxytable[i].timestamp+configuration.rtp_timeout)<t) {
|
||||
/* time one has expired, clean it up */
|
||||
callid.number=rtp_proxytable[i].callid_number;
|
||||
callid.host=rtp_proxytable[i].callid_host;
|
||||
DEBUGC(DBCLASS_RTP,"RTP stream sock=%i %s@%s (idx=%i) "
|
||||
"has expired", rtp_proxytable[i].sock,
|
||||
callid.number, callid.host, i);
|
||||
rtp_stop_fwd(&callid, 1); /* don't lock the mutex, as we own
|
||||
the lock already here */
|
||||
}
|
||||
}
|
||||
} /* if (t>...) */
|
||||
|
||||
/* copy master FD set */
|
||||
memcpy(&fdset, &master_fdset, sizeof(fdset));
|
||||
fd_max=master_fd_max;
|
||||
|
||||
/*
|
||||
* UNLOCK the MUTEX
|
||||
*/
|
||||
pthread_mutex_unlock(&rtp_proxytable_mutex);
|
||||
} /* for(;;) */
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* helper routines to control the RTP proxy thread
|
||||
*/
|
||||
|
||||
/*
|
||||
* start an rtp stream on the proxy
|
||||
*
|
||||
@@ -228,161 +68,23 @@ if (num_fd<0) {
|
||||
int rtp_start_fwd (osip_call_id_t *callid, int media_stream_no,
|
||||
struct in_addr outbound_ipaddr, int *outboundport,
|
||||
struct in_addr lcl_client_ipaddr, int lcl_clientport) {
|
||||
int j;
|
||||
int sock, port;
|
||||
int freeidx;
|
||||
int sts=STS_SUCCESS;
|
||||
int sts=STS_FAILURE;
|
||||
|
||||
if (configuration.rtp_proxy_enable == 0) return STS_SUCCESS;
|
||||
|
||||
if (callid == NULL) {
|
||||
ERROR("rtp_start_fwd: callid is NULL!");
|
||||
return STS_FAILURE;
|
||||
if (configuration.rtp_proxy_enable == 0) {
|
||||
sts = STS_SUCCESS;
|
||||
} else if (configuration.rtp_proxy_enable == 1) { // Relay
|
||||
sts = rtp_relay_start_fwd (callid, media_stream_no,
|
||||
outbound_ipaddr, outboundport,
|
||||
lcl_client_ipaddr, lcl_clientport);
|
||||
} else if (configuration.rtp_proxy_enable == 2) { // MASQ tunnels
|
||||
sts = rtp_masq_start_fwd (callid, media_stream_no,
|
||||
outbound_ipaddr, outboundport,
|
||||
lcl_client_ipaddr, lcl_clientport);
|
||||
} else {
|
||||
ERROR("CONFIG: rtp_proxy_enable has invalid value",
|
||||
configuration.rtp_proxy_enable);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* life insurance: check size of received call_id strings
|
||||
* I don't know what the maximum allowed size within SIP is,
|
||||
* so if this test fails maybe it's just necessary to increase
|
||||
* the constants CALLIDNUM_SIZE and/or CALLIDHOST_SIZE.
|
||||
*/
|
||||
if (strlen(callid->number) > CALLIDNUM_SIZE) {
|
||||
ERROR("rtp_start_fwd: received callid number "
|
||||
"has too many characters (%i, max=%i)",
|
||||
strlen(callid->number),CALLIDNUM_SIZE);
|
||||
return STS_FAILURE;
|
||||
}
|
||||
if (strlen(callid->host) > CALLIDHOST_SIZE) {
|
||||
ERROR("rtp_start_fwd: received callid host "
|
||||
"has too many characters (%i, max=%i)",
|
||||
strlen(callid->host),CALLIDHOST_SIZE);
|
||||
return STS_FAILURE;
|
||||
}
|
||||
|
||||
DEBUGC(DBCLASS_RTP,"starting RTP proxy stream for: %s@%s #=%i",
|
||||
callid->number, callid->host, media_stream_no);
|
||||
|
||||
/* lock mutex */
|
||||
#define return is_forbidden_in_this_code_section
|
||||
pthread_mutex_lock(&rtp_proxytable_mutex);
|
||||
/*
|
||||
* !! We now have a locked MUTEX! It is forbidden to return() from
|
||||
* !! here up to the end of this funtion where the MUTEX is
|
||||
* !! unlocked again.
|
||||
* !! Per design, a mutex is locked (for one purpose) at *exactly one*
|
||||
* !! place in the code and unlocked also at *exactly one* place.
|
||||
* !! this minimizes the risk of deadlocks.
|
||||
*/
|
||||
|
||||
/*
|
||||
* figure out, if this is an request to start an RTP proxy stream
|
||||
* that is already existing (identified by SIP Call-ID and
|
||||
* media_stream_no). This can be due to UDP repetitions of the
|
||||
* INVITE request...
|
||||
*/
|
||||
for (j=0; j<RTPPROXY_SIZE; j++) {
|
||||
if((strcmp(rtp_proxytable[j].callid_number, callid->number)==0) &&
|
||||
(strcmp(rtp_proxytable[j].callid_host, callid->host)==0) &&
|
||||
(rtp_proxytable[j].media_stream_no == media_stream_no) ) {
|
||||
/* return the already known port number */
|
||||
DEBUGC(DBCLASS_RTP,"RTP stream already active (port=%i, "
|
||||
"id=%s, #=%i)", rtp_proxytable[j].outboundport,
|
||||
rtp_proxytable[j].callid_number,
|
||||
rtp_proxytable[j].media_stream_no);
|
||||
*outboundport=rtp_proxytable[j].outboundport;
|
||||
sts = STS_SUCCESS;
|
||||
goto unlock_and_exit;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* find first free slot in rtp_proxytable
|
||||
*/
|
||||
freeidx=-1;
|
||||
for (j=0; j<RTPPROXY_SIZE; j++) {
|
||||
if (rtp_proxytable[j].sock==0) {
|
||||
freeidx=j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* rtp_proxytable port pool full? */
|
||||
if (freeidx == -1) {
|
||||
ERROR("rtp_start_fwd: rtp_proxytable is full!");
|
||||
sts = STS_FAILURE;
|
||||
goto unlock_and_exit;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* RTP relay configured
|
||||
*/
|
||||
if (configuration.rtp_proxy_enable == 1) {
|
||||
sts = rtp_relay_start_fwd(&sock, &port, outbound_ipaddr);
|
||||
|
||||
/* could bind to desired port? */
|
||||
if (sock == 0) {
|
||||
ERROR("rtp_start_fwd: unable to bind to outbound port!");
|
||||
sts = STS_FAILURE;
|
||||
goto unlock_and_exit;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* RTP masquerading configured
|
||||
*/
|
||||
if (configuration.rtp_proxy_enable == 2) {
|
||||
/* do the masquerading - which means to open up
|
||||
* an UDP tunnel in the firewall within the desired range */
|
||||
sts = rtp_masq_start_fwd(freeidx, outbound_ipaddr, &port,
|
||||
lcl_client_ipaddr, lcl_clientport);
|
||||
if (sts != STS_SUCCESS) {
|
||||
ERROR("rtp_start_fwd: unable to create masquerading tunnel!");
|
||||
sts = STS_FAILURE;
|
||||
goto unlock_and_exit;
|
||||
}
|
||||
sock=1; /* 0 indicates 'not allocated' - so we simply put in non-zero */
|
||||
}
|
||||
|
||||
DEBUGC(DBCLASS_RTP,"rtp_start_fwd: port=%i, sock=%i freeidx=%i",
|
||||
port, sock, freeidx);
|
||||
|
||||
/* found an unused port? No -> RTP port pool fully allocated */
|
||||
if (port == 0) {
|
||||
ERROR("rtp_start_fwd: no RTP port available. Check rtp_port_* config!");
|
||||
sts = STS_FAILURE;
|
||||
goto unlock_and_exit;
|
||||
}
|
||||
|
||||
/* write entry into rtp_proxytable slot (freeidx) */
|
||||
rtp_proxytable[freeidx].sock=sock;
|
||||
strcpy(rtp_proxytable[freeidx].callid_number, callid->number);
|
||||
strcpy(rtp_proxytable[freeidx].callid_host, callid->host);
|
||||
rtp_proxytable[freeidx].media_stream_no = media_stream_no;
|
||||
memcpy(&rtp_proxytable[freeidx].outbound_ipaddr,
|
||||
&outbound_ipaddr, sizeof(struct in_addr));
|
||||
rtp_proxytable[freeidx].outboundport=port;
|
||||
memcpy(&rtp_proxytable[freeidx].inbound_client_ipaddr,
|
||||
&lcl_client_ipaddr, sizeof(struct in_addr));
|
||||
rtp_proxytable[freeidx].inbound_client_port=lcl_clientport;
|
||||
time(&rtp_proxytable[freeidx].timestamp);
|
||||
|
||||
*outboundport=port;
|
||||
|
||||
/* prepare FD set for next select operation */
|
||||
rtp_recreate_fdset();
|
||||
|
||||
/* wakeup/signal rtp_proxythread from select() hibernation */
|
||||
if (!pthread_equal(rtpproxy_tid, pthread_self()))
|
||||
pthread_kill(rtpproxy_tid, SIGALRM);
|
||||
|
||||
unlock_and_exit:
|
||||
/* unlock mutex */
|
||||
pthread_mutex_unlock(&rtp_proxytable_mutex);
|
||||
#undef return
|
||||
|
||||
return sts;
|
||||
}
|
||||
|
||||
@@ -394,158 +96,19 @@ unlock_and_exit:
|
||||
* STS_SUCCESS on success
|
||||
* STS_FAILURE on error
|
||||
*/
|
||||
int rtp_stop_fwd (osip_call_id_t *callid, int nolock) {
|
||||
int i, sts;
|
||||
int retsts=STS_SUCCESS;
|
||||
int got_match=0;
|
||||
|
||||
if (configuration.rtp_proxy_enable == 0) return STS_SUCCESS;
|
||||
int rtp_stop_fwd (osip_call_id_t *callid) {
|
||||
int sts = STS_FAILURE;
|
||||
|
||||
if (callid == NULL) {
|
||||
ERROR("rtp_stop_fwd: callid is NULL!");
|
||||
return STS_FAILURE;
|
||||
if (configuration.rtp_proxy_enable == 0) {
|
||||
sts = STS_SUCCESS;
|
||||
} else if (configuration.rtp_proxy_enable == 1) { // Relay
|
||||
sts = rtp_relay_stop_fwd(callid, 0);
|
||||
} else if (configuration.rtp_proxy_enable == 2) { // MASQ tunnels
|
||||
sts = rtp_masq_stop_fwd(callid);
|
||||
} else {
|
||||
ERROR("CONFIG: rtp_proxy_enable has invalid value",
|
||||
configuration.rtp_proxy_enable);
|
||||
}
|
||||
|
||||
DEBUGC(DBCLASS_RTP,"stopping RTP proxy stream for: %s@%s",
|
||||
callid->number, callid->host);
|
||||
|
||||
/*
|
||||
* lock mutex - only if not requested to skip the lock.
|
||||
* this is needed as we are also called from within
|
||||
* the RTP thread itself - and there we already own the lock.
|
||||
*/
|
||||
#define return is_forbidden_in_this_code_section
|
||||
if (nolock == 0) {
|
||||
pthread_mutex_lock(&rtp_proxytable_mutex);
|
||||
/*
|
||||
* !! We now have a locked MUTEX! It is forbidden to return() from
|
||||
* !! here up to the end of this funtion where the MUTEX is
|
||||
* !! unlocked again.
|
||||
* !! Per design, a mutex is locked (for one purpose) at *exactly one*
|
||||
* !! place in the code and unlocked also at *exactly one* place.
|
||||
* !! this minimizes the risk of deadlocks.
|
||||
*/
|
||||
}
|
||||
/*
|
||||
* wakeup/signal rtp_proxythread from select() hibernation.
|
||||
* This must be done here before we close the socket, otherwise
|
||||
* we may get an select() error later from the proxy thread that
|
||||
* is still hibernating in select() now.
|
||||
*/
|
||||
if (!pthread_equal(rtpproxy_tid, pthread_self()))
|
||||
pthread_kill(rtpproxy_tid, SIGALRM);
|
||||
|
||||
/*
|
||||
* find the proper entry in rtp_proxytable
|
||||
* we need to loop the whole table, as there might be multiple
|
||||
* media strema active for the same callid (audio + video stream)
|
||||
*/
|
||||
for (i=0; i<RTPPROXY_SIZE; i++) {
|
||||
if ((callid->number==NULL) && (callid->host==NULL)) break;
|
||||
if( rtp_proxytable[i].sock &&
|
||||
(strcmp(rtp_proxytable[i].callid_number, callid->number)==0) &&
|
||||
(strcmp(rtp_proxytable[i].callid_host, callid->host)==0) ) {
|
||||
|
||||
/*
|
||||
* RTP relay configured
|
||||
*/
|
||||
if (configuration.rtp_proxy_enable == 1) {
|
||||
sts = rtp_relay_stop_fwd(rtp_proxytable[i].sock);
|
||||
DEBUGC(DBCLASS_RTP,"closed socket %i for RTP stream "
|
||||
"%s:%s == %s:%s (idx=%i) sts=%i",
|
||||
rtp_proxytable[i].sock,
|
||||
rtp_proxytable[i].callid_number,
|
||||
rtp_proxytable[i].callid_host,
|
||||
callid->number, callid->host, i, sts);
|
||||
if (sts < 0) {
|
||||
ERROR("Error in close(%i): %s nolock=%i %s:%s\n",
|
||||
rtp_proxytable[i].sock,
|
||||
strerror(errno), nolock,
|
||||
callid->number, callid->host);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* RTP masquerading configured
|
||||
*/
|
||||
if (configuration.rtp_proxy_enable == 2) {
|
||||
/* do the masquerading - which means to open up
|
||||
* an UDP tunnel in the firewall within the desired range */
|
||||
sts = rtp_masq_stop_fwd(i);
|
||||
}
|
||||
|
||||
memset(&rtp_proxytable[i], 0, sizeof(rtp_proxytable[0]));
|
||||
got_match=1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* did not find an active stream... */
|
||||
if (!got_match) {
|
||||
DEBUGC(DBCLASS_RTP,"rtp_stop_fwd: can't find active stream for %s@%s",
|
||||
callid->number, callid->host);
|
||||
retsts = STS_FAILURE;
|
||||
goto unlock_and_exit;
|
||||
}
|
||||
|
||||
|
||||
/* prepare FD set for next select operation */
|
||||
rtp_recreate_fdset();
|
||||
|
||||
|
||||
unlock_and_exit:
|
||||
/*
|
||||
* unlock mutex - only if not requested to skip the lock.
|
||||
* this is needed as we are also called from within
|
||||
* the RTP thread itself - and there we already own the lock.
|
||||
*/
|
||||
if (nolock == 0) {
|
||||
pthread_mutex_unlock(&rtp_proxytable_mutex);
|
||||
}
|
||||
#undef return
|
||||
|
||||
return retsts;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* some sockets have been newly created or removed -
|
||||
* recreate the FD set for next select operation
|
||||
*
|
||||
* RETURNS
|
||||
* STS_SUCCESS on success (always)
|
||||
*/
|
||||
int rtp_recreate_fdset(void) {
|
||||
int i;
|
||||
|
||||
FD_ZERO(&master_fdset);
|
||||
master_fd_max=-1;
|
||||
for (i=0;i<RTPPROXY_SIZE;i++) {
|
||||
if (rtp_proxytable[i].sock != 0) {
|
||||
FD_SET(rtp_proxytable[i].sock, &master_fdset);
|
||||
if (rtp_proxytable[i].sock > master_fd_max) {
|
||||
master_fd_max=rtp_proxytable[i].sock;
|
||||
}
|
||||
}
|
||||
} /* for i */
|
||||
return STS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* kills the rtp_proxy thread
|
||||
*
|
||||
* RETURNS
|
||||
* -
|
||||
*/
|
||||
void rtpproxy_kill( void ) {
|
||||
void *thread_status;
|
||||
|
||||
if (rtpproxy_tid) {
|
||||
pthread_cancel(rtpproxy_tid);
|
||||
pthread_join(rtpproxy_tid, &thread_status);
|
||||
}
|
||||
|
||||
DEBUGC(DBCLASS_RTP,"killed RTP proxy thread");
|
||||
return;
|
||||
return sts;
|
||||
}
|
||||
|
||||
+10
-7
@@ -36,15 +36,18 @@ typedef struct {
|
||||
/*
|
||||
* RTP relay
|
||||
*/
|
||||
void rtp_relay (int num_fd, fd_set *fdset, time_t t);
|
||||
int rtp_relay_start_fwd(int *sock, int *port, struct in_addr outbound_ipaddr);
|
||||
int rtp_relay_stop_fwd(int sock);
|
||||
int rtp_relay_init(void);
|
||||
int rtp_relay_start_fwd (osip_call_id_t *callid, int media_stream_no,
|
||||
struct in_addr outbound_ipaddr, int *outboundport,
|
||||
struct in_addr lcl_client_ipaddr, int lcl_clientport);
|
||||
int rtp_relay_stop_fwd (osip_call_id_t *callid, int nolock);
|
||||
|
||||
|
||||
/*
|
||||
* RTP masquerading
|
||||
*/
|
||||
int rtp_masq_start_fwd(int proxy_idx,
|
||||
struct in_addr outbound_ipaddr, int *outbound_lcl_port,
|
||||
struct in_addr lcl_client_ipaddr, int lcl_clientport);
|
||||
int rtp_masq_stop_fwd(int proxy_idx);
|
||||
int rtp_masq_init(void);
|
||||
int rtp_masq_start_fwd (osip_call_id_t *callid, int media_stream_no,
|
||||
struct in_addr outbound_ipaddr, int *outboundport,
|
||||
struct in_addr lcl_client_ipaddr, int lcl_clientport);
|
||||
int rtp_masq_stop_fwd (osip_call_id_t *callid);
|
||||
|
||||
+162
-13
@@ -60,18 +60,21 @@ extern rtp_proxytable_t rtp_proxytable[];
|
||||
/* socket for controlling the MASQ tunnels */
|
||||
static int masq_ctl_sock=0;
|
||||
|
||||
/*
|
||||
* table to remember all active rtp proxy streams
|
||||
*/
|
||||
rtp_proxytable_t rtp_proxytable[RTPPROXY_SIZE];
|
||||
|
||||
/* table to remember all masquerading tunnels (1:1 with rtp_proxytable) */
|
||||
struct ip_masq_ctl masq_table[RTPPROXY_SIZE];
|
||||
|
||||
/*
|
||||
* local prototypes
|
||||
*/
|
||||
int _create_listening_masq(struct ip_masq_ctl *masq,
|
||||
static int _create_listening_masq(struct ip_masq_ctl *masq,
|
||||
struct in_addr lcl_addr, int lcl_port,
|
||||
struct in_addr msq_addr, int msq_port);
|
||||
|
||||
int _delete_listening_masq(struct ip_masq_ctl *masq);
|
||||
|
||||
/************************************************************
|
||||
THIS HERE WILL ONLY WORK IF SIPROXD IS STARTED SUID ROOT !!
|
||||
However it is working when started root and then changed
|
||||
@@ -79,19 +82,123 @@ int _delete_listening_masq(struct ip_masq_ctl *masq);
|
||||
we need to fiddle with the masquerading
|
||||
*************************************************************/
|
||||
|
||||
int rtp_masq_start_fwd(int proxy_idx,
|
||||
/*
|
||||
* initialize rtp_masq
|
||||
*
|
||||
* RETURNS
|
||||
* STS_SUCCESS on success
|
||||
*/
|
||||
int rtp_masq_init( void ) {
|
||||
|
||||
/* clean proxy table */
|
||||
memset (rtp_proxytable, 0, sizeof(rtp_proxytable));
|
||||
|
||||
return STS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int rtp_masq_start_fwd(osip_call_id_t *callid, int media_stream_no,
|
||||
struct in_addr outbound_ipaddr, int *outbound_lcl_port,
|
||||
struct in_addr lcl_client_ipaddr, int lcl_clientport) {
|
||||
int sts, i;
|
||||
DEBUGC(DBCLASS_RTP,"rtp_masq_start_fwd: local UA:%s:%i",
|
||||
inet_ntoa(lcl_client_ipaddr),lcl_clientport);
|
||||
int freeidx;
|
||||
time_t t;
|
||||
|
||||
if (callid == NULL) {
|
||||
ERROR("rtp_relay_start_fwd: callid is NULL!");
|
||||
return STS_FAILURE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* life insurance: check size of received call_id strings
|
||||
* I don't know what the maximum allowed size within SIP is,
|
||||
* so if this test fails maybe it's just necessary to increase
|
||||
* the constants CALLIDNUM_SIZE and/or CALLIDHOST_SIZE.
|
||||
*/
|
||||
if (strlen(callid->number) > CALLIDNUM_SIZE) {
|
||||
ERROR("rtp_relay_start_fwd: received callid number "
|
||||
"has too many characters (%i, max=%i)",
|
||||
strlen(callid->number),CALLIDNUM_SIZE);
|
||||
return STS_FAILURE;
|
||||
}
|
||||
if (strlen(callid->host) > CALLIDHOST_SIZE) {
|
||||
ERROR("rtp_relay_start_fwd: received callid host "
|
||||
"has too many characters (%i, max=%i)",
|
||||
strlen(callid->host),CALLIDHOST_SIZE);
|
||||
return STS_FAILURE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Age proxy table:
|
||||
* Just throw out expired (timed out) records. The proxy table
|
||||
* here for the MASQ module is only used to eliminate "doubles"
|
||||
* during INVITE/ACK. Later on, managing (aging & cleaning) the
|
||||
* masquerading tunnels is done by the kernel (IPMASQ).
|
||||
*/
|
||||
time(&t);
|
||||
for (i=0; i<RTPPROXY_SIZE; i++) {
|
||||
if ( (rtp_proxytable[i].sock != 0) &&
|
||||
((rtp_proxytable[i].timestamp+configuration.rtp_timeout)<t)) {
|
||||
/* this one has expired, clean it up */
|
||||
DEBUGC(DBCLASS_RTP,"cleaning proxy slot #%i %s@%s", i,
|
||||
rtp_proxytable[i].callid_number,
|
||||
rtp_proxytable[i].callid_host);
|
||||
memset(&rtp_proxytable[i], 0, sizeof(rtp_proxytable[0]));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
DEBUGC(DBCLASS_RTP,"rtp_masq_start_fwd: starting RTP proxy "
|
||||
"stream for: %s@%s #=%i",
|
||||
callid->number, callid->host, media_stream_no);
|
||||
|
||||
/*
|
||||
* figure out, if this is an request to start an RTP proxy stream
|
||||
* that is already existing (identified by SIP Call-ID and
|
||||
* media_stream_no). This can be due to UDP repetitions of the
|
||||
* INVITE request...
|
||||
*/
|
||||
for (i=0; i<RTPPROXY_SIZE; i++) {
|
||||
if((strcmp(rtp_proxytable[i].callid_number, callid->number)==0) &&
|
||||
(strcmp(rtp_proxytable[i].callid_host, callid->host)==0) &&
|
||||
(rtp_proxytable[i].media_stream_no == media_stream_no) ) {
|
||||
/* return the already known port number */
|
||||
DEBUGC(DBCLASS_RTP,"RTP stream already active (port=%i, "
|
||||
"id=%s, #=%i)", rtp_proxytable[i].outboundport,
|
||||
rtp_proxytable[i].callid_number,
|
||||
rtp_proxytable[i].media_stream_no);
|
||||
return STS_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* find first free slot in rtp_proxytable
|
||||
*/
|
||||
freeidx=-1;
|
||||
for (i=0; i<RTPPROXY_SIZE; i++) {
|
||||
if (rtp_proxytable[i].sock==0) {
|
||||
freeidx=i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* rtp_proxytable port pool full? */
|
||||
if (freeidx == -1) {
|
||||
ERROR("rtp_masq_start_fwd: rtp_proxytable is full!");
|
||||
return STS_FAILURE;
|
||||
}
|
||||
|
||||
/*
|
||||
* do loop over the range of available ports (7070-...) until able to
|
||||
* allocate a UDP tunnel. If not successful - Buh! return port=0
|
||||
*/
|
||||
for (i=configuration.rtp_port_low; i<=configuration.rtp_port_high; i++) {
|
||||
*outbound_lcl_port=i;
|
||||
sts = _create_listening_masq(&masq_table[proxy_idx],
|
||||
sts = _create_listening_masq(&masq_table[freeidx],
|
||||
lcl_client_ipaddr, lcl_clientport,
|
||||
outbound_ipaddr, *outbound_lcl_port);
|
||||
/* if success break, else try further on */
|
||||
@@ -99,21 +206,66 @@ int rtp_masq_start_fwd(int proxy_idx,
|
||||
*outbound_lcl_port=0;
|
||||
} /* for i */
|
||||
|
||||
if (*outbound_lcl_port) {
|
||||
/* write entry into rtp_proxytable slot (freeidx) */
|
||||
DEBUGC(DBCLASS_RTP,"rtp_masq_start_fwd: using proxy slot %i",freeidx);
|
||||
rtp_proxytable[freeidx].sock=1;
|
||||
strcpy(rtp_proxytable[freeidx].callid_number, callid->number);
|
||||
strcpy(rtp_proxytable[freeidx].callid_host, callid->host);
|
||||
rtp_proxytable[freeidx].media_stream_no = media_stream_no;
|
||||
memcpy(&rtp_proxytable[freeidx].outbound_ipaddr,
|
||||
&outbound_ipaddr, sizeof(struct in_addr));
|
||||
rtp_proxytable[freeidx].outboundport=*outbound_lcl_port;
|
||||
memcpy(&rtp_proxytable[freeidx].inbound_client_ipaddr,
|
||||
&lcl_client_ipaddr, sizeof(struct in_addr));
|
||||
rtp_proxytable[freeidx].inbound_client_port=lcl_clientport;
|
||||
time(&rtp_proxytable[freeidx].timestamp);
|
||||
}
|
||||
|
||||
DEBUGC(DBCLASS_RTP,"rtp_masq_start_fwd: masq address & port:%s:%i",
|
||||
inet_ntoa(outbound_ipaddr),outbound_lcl_port);
|
||||
return (*outbound_lcl_port)?STS_SUCCESS:STS_FAILURE;
|
||||
}
|
||||
|
||||
|
||||
int rtp_masq_stop_fwd(int proxy_idx) {
|
||||
return _delete_listening_masq(&masq_table[proxy_idx]);
|
||||
int rtp_masq_stop_fwd(osip_call_id_t *callid) {
|
||||
int i;
|
||||
int got_match=0;
|
||||
|
||||
/* let the UDP tunnel time-out */
|
||||
|
||||
if (callid == NULL) {
|
||||
ERROR("rtp_relay_stop_fwd: callid is NULL!");
|
||||
return STS_FAILURE;
|
||||
}
|
||||
|
||||
for (i=0; i<RTPPROXY_SIZE; i++) {
|
||||
if ((callid->number==NULL) || (callid->host==NULL)) break;
|
||||
if( rtp_proxytable[i].sock &&
|
||||
(strcmp(rtp_proxytable[i].callid_number, callid->number)==0) &&
|
||||
(strcmp(rtp_proxytable[i].callid_host, callid->host)==0) ) {
|
||||
DEBUGC(DBCLASS_RTP,"rtp_masq_stop_fwd: cleaning proxy slot %i",i);
|
||||
memset(&rtp_proxytable[i], 0, sizeof(rtp_proxytable[0]));
|
||||
got_match=1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* did not find an active stream... */
|
||||
if (!got_match) {
|
||||
DEBUGC(DBCLASS_RTP,"rtp_masq_stop_fwd: can't find active stream for %s@%s",
|
||||
callid->number, callid->host);
|
||||
return STS_FAILURE;
|
||||
}
|
||||
|
||||
return STS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* helper routines
|
||||
*/
|
||||
int _create_listening_masq(struct ip_masq_ctl *masq,
|
||||
static int _create_listening_masq(struct ip_masq_ctl *masq,
|
||||
struct in_addr lcl_addr, int lcl_port,
|
||||
struct in_addr msq_addr, int msq_port) {
|
||||
int uid,euid;
|
||||
@@ -180,9 +332,6 @@ exit:
|
||||
return sts;
|
||||
}
|
||||
|
||||
int _delete_listening_masq(struct ip_masq_ctl *masq) {
|
||||
return STS_SUCCESS;
|
||||
}
|
||||
#else
|
||||
/*
|
||||
* don't have ipchains or iptables - dummy routines and complain
|
||||
|
||||
+434
-31
@@ -20,13 +20,17 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <sys/time.h>
|
||||
//#include <sys/types.h>
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include <osipparser2/osip_parser.h>
|
||||
|
||||
@@ -44,58 +48,281 @@ extern struct siproxd_config configuration;
|
||||
/*
|
||||
* table to remember all active rtp proxy streams
|
||||
*/
|
||||
extern rtp_proxytable_t rtp_proxytable[];
|
||||
rtp_proxytable_t rtp_proxytable[RTPPROXY_SIZE];
|
||||
|
||||
/* use a 'fast' mutex for synchronizing - as these are portable... */
|
||||
pthread_mutex_t rtp_proxytable_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
/* thread id of RTP proxy */
|
||||
pthread_t rtpproxy_tid=0;
|
||||
|
||||
/* master fd_set */
|
||||
static fd_set master_fdset;
|
||||
static int master_fd_max;
|
||||
|
||||
/* forward declarations */
|
||||
static void *rtpproxy_main(void *i);
|
||||
static int rtp_recreate_fdset(void);
|
||||
void rtpproxy_kill( void );
|
||||
static void sighdl_alm(int sig) {/* just wake up from select() */};
|
||||
|
||||
|
||||
|
||||
void rtp_relay (int num_fd, fd_set *fdset, time_t t) {
|
||||
int i;
|
||||
int count;
|
||||
/*
|
||||
* 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;
|
||||
|
||||
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);
|
||||
|
||||
return STS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* main() of rtpproxy
|
||||
*/
|
||||
static void *rtpproxy_main(void *arg) {
|
||||
struct timeval tv;
|
||||
fd_set fdset;
|
||||
int fd_max;
|
||||
time_t t, last_t=0;
|
||||
int i, sts;
|
||||
int num_fd;
|
||||
osip_call_id_t callid;
|
||||
static int rtp_socket=0;
|
||||
static char rtp_buff[RTP_BUFFER_SIZE];
|
||||
/* check for data available and send to destination */
|
||||
for (i=0;(i<RTPPROXY_SIZE) && (num_fd>0);i++) {
|
||||
if ( (rtp_proxytable[i].sock != 0) &&
|
||||
FD_ISSET(rtp_proxytable[i].sock, fdset) ) {
|
||||
/* yup, have some data to send */
|
||||
int count;
|
||||
|
||||
/* read from sock rtp_proxytable[i].sock*/
|
||||
count=read(rtp_proxytable[i].sock, rtp_buff, RTP_BUFFER_SIZE);
|
||||
memcpy(&fdset, &master_fdset, sizeof(fdset));
|
||||
fd_max=master_fd_max;
|
||||
|
||||
/* loop forever... */
|
||||
for (;;) {
|
||||
|
||||
tv.tv_sec = 5;
|
||||
tv.tv_usec = 0;
|
||||
|
||||
num_fd=select(fd_max+1, &fdset, NULL, NULL, &tv);
|
||||
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;
|
||||
}
|
||||
|
||||
#ifdef MOREDEBUG /*&&&&*/
|
||||
if (num_fd<0) {
|
||||
int i;
|
||||
WARN("select() returned error [%s]",strerror(errno));
|
||||
for (i=0;i<RTPPROXY_SIZE;i++) {
|
||||
DEBUGC(DBCLASS_RTP,"maxfd=%i",master_fd_max);
|
||||
if (rtp_proxytable[i].sock != 0) {
|
||||
DEBUGC(DBCLASS_RTP,"[%i] -> socket=%i",i, rtp_proxytable[i].sock);
|
||||
}
|
||||
} /* for i */
|
||||
}
|
||||
#endif
|
||||
time(&t);
|
||||
|
||||
/*
|
||||
* 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++) {
|
||||
if ( (rtp_proxytable[i].sock != 0) &&
|
||||
FD_ISSET(rtp_proxytable[i].sock, &fdset) ) {
|
||||
/* yup, have some data to send */
|
||||
|
||||
/* read from sock rtp_proxytable[i].sock*/
|
||||
count=read(rtp_proxytable[i].sock, rtp_buff, RTP_BUFFER_SIZE);
|
||||
|
||||
#ifdef MOREDEBUG /*&&&&*/
|
||||
if (count<0) {WARN("read() returned error [%s]",strerror(errno));}
|
||||
#endif
|
||||
|
||||
/* write to dest via socket rtp_inbound*/
|
||||
sts=sipsock_send_udp(&rtp_socket,
|
||||
/* write to dest via socket rtp_inbound*/
|
||||
sts = sipsock_send_udp(&rtp_socket,
|
||||
rtp_proxytable[i].inbound_client_ipaddr,
|
||||
rtp_proxytable[i].inbound_client_port,
|
||||
rtp_buff, count, 0); /* don't dump it */
|
||||
#ifdef MOREDEBUG /*&&&&*/
|
||||
if (sts != STS_SUCCESS) {WARN("sipsock_send_udp() returned error");}
|
||||
#endif
|
||||
/* update timestamp of last usage */
|
||||
rtp_proxytable[i].timestamp=t;
|
||||
/* update timestamp of last usage */
|
||||
rtp_proxytable[i].timestamp=t;
|
||||
|
||||
num_fd--;
|
||||
}
|
||||
} /* for i */
|
||||
num_fd--;
|
||||
}
|
||||
} /* for i */
|
||||
|
||||
/*
|
||||
* age and clean rtp_proxytable (check every 10 seconds)
|
||||
*/
|
||||
if (t > (last_t+10) ) {
|
||||
last_t = t;
|
||||
for (i=0;i<RTPPROXY_SIZE; i++) {
|
||||
if ( (rtp_proxytable[i].sock != 0) &&
|
||||
((rtp_proxytable[i].timestamp+configuration.rtp_timeout)<t)) {
|
||||
/* this one has expired, clean it up */
|
||||
callid.number=rtp_proxytable[i].callid_number;
|
||||
callid.host=rtp_proxytable[i].callid_host;
|
||||
DEBUGC(DBCLASS_RTP,"RTP stream sock=%i %s@%s (idx=%i) "
|
||||
"has expired", rtp_proxytable[i].sock,
|
||||
callid.number, callid.host, i);
|
||||
rtp_relay_stop_fwd(&callid, 1); /* don't lock the mutex, as we own
|
||||
the lock already here */
|
||||
}
|
||||
}
|
||||
} /* if (t>...) */
|
||||
|
||||
/* copy master FD set */
|
||||
memcpy(&fdset, &master_fdset, sizeof(fdset));
|
||||
fd_max=master_fd_max;
|
||||
|
||||
/*
|
||||
* UNLOCK the MUTEX
|
||||
*/
|
||||
pthread_mutex_unlock(&rtp_proxytable_mutex);
|
||||
} /* for(;;) */
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int rtp_relay_start_fwd(int *sock, int *port, struct in_addr outbound_ipaddr) {
|
||||
/*
|
||||
* start an rtp stream on the proxy
|
||||
*
|
||||
* RETURNS
|
||||
* STS_SUCCESS on success
|
||||
* STS_FAILURE on error
|
||||
*/
|
||||
int rtp_relay_start_fwd (osip_call_id_t *callid, int media_stream_no,
|
||||
struct in_addr outbound_ipaddr, int *outboundport,
|
||||
struct in_addr lcl_client_ipaddr, int lcl_clientport) {
|
||||
int i, j;
|
||||
int sock, port;
|
||||
int freeidx;
|
||||
int sts=STS_SUCCESS;
|
||||
|
||||
if (callid == NULL) {
|
||||
ERROR("rtp_relay_start_fwd: callid is NULL!");
|
||||
return STS_FAILURE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* life insurance: check size of received call_id strings
|
||||
* I don't know what the maximum allowed size within SIP is,
|
||||
* so if this test fails maybe it's just necessary to increase
|
||||
* the constants CALLIDNUM_SIZE and/or CALLIDHOST_SIZE.
|
||||
*/
|
||||
if (strlen(callid->number) > CALLIDNUM_SIZE) {
|
||||
ERROR("rtp_relay_start_fwd: received callid number "
|
||||
"has too many characters (%i, max=%i)",
|
||||
strlen(callid->number),CALLIDNUM_SIZE);
|
||||
return STS_FAILURE;
|
||||
}
|
||||
if (strlen(callid->host) > CALLIDHOST_SIZE) {
|
||||
ERROR("rtp_relay_start_fwd: received callid host "
|
||||
"has too many characters (%i, max=%i)",
|
||||
strlen(callid->host),CALLIDHOST_SIZE);
|
||||
return STS_FAILURE;
|
||||
}
|
||||
|
||||
DEBUGC(DBCLASS_RTP,"starting RTP proxy stream for: %s@%s #=%i",
|
||||
callid->number, callid->host, media_stream_no);
|
||||
|
||||
/* lock mutex */
|
||||
#define return is_forbidden_in_this_code_section
|
||||
pthread_mutex_lock(&rtp_proxytable_mutex);
|
||||
/*
|
||||
* !! We now have a locked MUTEX! It is forbidden to return() from
|
||||
* !! here up to the end of this funtion where the MUTEX is
|
||||
* !! unlocked again.
|
||||
* !! Per design, a mutex is locked (for one purpose) at *exactly one*
|
||||
* !! place in the code and unlocked also at *exactly one* place.
|
||||
* !! this minimizes the risk of deadlocks.
|
||||
*/
|
||||
|
||||
/*
|
||||
* figure out, if this is an request to start an RTP proxy stream
|
||||
* that is already existing (identified by SIP Call-ID and
|
||||
* media_stream_no). This can be due to UDP repetitions of the
|
||||
* INVITE request...
|
||||
*/
|
||||
for (j=0; j<RTPPROXY_SIZE; j++) {
|
||||
if((strcmp(rtp_proxytable[j].callid_number, callid->number)==0) &&
|
||||
(strcmp(rtp_proxytable[j].callid_host, callid->host)==0) &&
|
||||
(rtp_proxytable[j].media_stream_no == media_stream_no) ) {
|
||||
/* return the already known port number */
|
||||
DEBUGC(DBCLASS_RTP,"RTP stream already active (port=%i, "
|
||||
"id=%s, #=%i)", rtp_proxytable[j].outboundport,
|
||||
rtp_proxytable[j].callid_number,
|
||||
rtp_proxytable[j].media_stream_no);
|
||||
*outboundport=rtp_proxytable[j].outboundport;
|
||||
sts = STS_SUCCESS;
|
||||
goto unlock_and_exit;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* find first free slot in rtp_proxytable
|
||||
*/
|
||||
freeidx=-1;
|
||||
for (j=0; j<RTPPROXY_SIZE; j++) {
|
||||
if (rtp_proxytable[j].sock==0) {
|
||||
freeidx=j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* rtp_proxytable port pool full? */
|
||||
if (freeidx == -1) {
|
||||
ERROR("rtp_relay_start_fwd: rtp_proxytable is full!");
|
||||
sts = STS_FAILURE;
|
||||
goto unlock_and_exit;
|
||||
}
|
||||
|
||||
/* TODO: randomize the port allocation - start at a random offset to
|
||||
search in the allowed port range (so some modulo stuff w/
|
||||
random start offset
|
||||
- for i=x to (p1-p0)+x; p=p0+mod(x,p1-p0) */
|
||||
|
||||
/* find a local outbound port number to use and bind to it*/
|
||||
*sock=0;
|
||||
*port=0;
|
||||
sock=0;
|
||||
port=0;
|
||||
for (i=configuration.rtp_port_low; i<=configuration.rtp_port_high; i++) {
|
||||
for (j=0; j<RTPPROXY_SIZE; j++) {
|
||||
/* outbound port already in use */
|
||||
@@ -106,20 +333,196 @@ int rtp_relay_start_fwd(int *sock, int *port, struct in_addr outbound_ipaddr) {
|
||||
|
||||
/* port is available, try to allocate */
|
||||
if (j == RTPPROXY_SIZE) {
|
||||
*port=i;
|
||||
*sock=sockbind(outbound_ipaddr, *port, 0);
|
||||
port=i;
|
||||
sock=sockbind(outbound_ipaddr, port, 0);
|
||||
/* if success break, else try further on */
|
||||
if (*sock) break;
|
||||
if (sock) break;
|
||||
}
|
||||
} /* for i */
|
||||
|
||||
return (*sock)?STS_SUCCESS:STS_FAILURE;
|
||||
}
|
||||
DEBUGC(DBCLASS_RTP,"rtp_relay_start_fwd: port=%i, sock=%i freeidx=%i",
|
||||
port, sock, freeidx);
|
||||
|
||||
/* found an unused port? No -> RTP port pool fully allocated */
|
||||
if (port == 0) {
|
||||
ERROR("rtp_relay_start_fwd: no RTP port available. Check rtp_port_* config!");
|
||||
sts = STS_FAILURE;
|
||||
goto unlock_and_exit;
|
||||
}
|
||||
|
||||
int rtp_relay_stop_fwd(int sock) {
|
||||
int sts;
|
||||
/* write entry into rtp_proxytable slot (freeidx) */
|
||||
rtp_proxytable[freeidx].sock=sock;
|
||||
strcpy(rtp_proxytable[freeidx].callid_number, callid->number);
|
||||
strcpy(rtp_proxytable[freeidx].callid_host, callid->host);
|
||||
rtp_proxytable[freeidx].media_stream_no = media_stream_no;
|
||||
memcpy(&rtp_proxytable[freeidx].outbound_ipaddr,
|
||||
&outbound_ipaddr, sizeof(struct in_addr));
|
||||
rtp_proxytable[freeidx].outboundport=port;
|
||||
memcpy(&rtp_proxytable[freeidx].inbound_client_ipaddr,
|
||||
&lcl_client_ipaddr, sizeof(struct in_addr));
|
||||
rtp_proxytable[freeidx].inbound_client_port=lcl_clientport;
|
||||
time(&rtp_proxytable[freeidx].timestamp);
|
||||
|
||||
*outboundport=port;
|
||||
|
||||
/* prepare FD set for next select operation */
|
||||
rtp_recreate_fdset();
|
||||
|
||||
/* wakeup/signal rtp_proxythread from select() hibernation */
|
||||
if (!pthread_equal(rtpproxy_tid, pthread_self()))
|
||||
pthread_kill(rtpproxy_tid, SIGALRM);
|
||||
|
||||
unlock_and_exit:
|
||||
/* unlock mutex */
|
||||
pthread_mutex_unlock(&rtp_proxytable_mutex);
|
||||
#undef return
|
||||
|
||||
sts = close(sock);
|
||||
return sts;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* stop a rtp stream on the proxy
|
||||
*
|
||||
* RETURNS
|
||||
* STS_SUCCESS on success
|
||||
* STS_FAILURE on error
|
||||
*/
|
||||
int rtp_relay_stop_fwd (osip_call_id_t *callid, int nolock) {
|
||||
int i, sts;
|
||||
int retsts=STS_SUCCESS;
|
||||
int got_match=0;
|
||||
|
||||
if (callid == NULL) {
|
||||
ERROR("rtp_relay_stop_fwd: callid is NULL!");
|
||||
return STS_FAILURE;
|
||||
}
|
||||
|
||||
DEBUGC(DBCLASS_RTP,"stopping RTP proxy stream for: %s@%s",
|
||||
callid->number, callid->host);
|
||||
|
||||
/*
|
||||
* lock mutex - only if not requested to skip the lock.
|
||||
* this is needed as we are also called from within
|
||||
* the RTP thread itself - and there we already own the lock.
|
||||
*/
|
||||
#define return is_forbidden_in_this_code_section
|
||||
if (nolock == 0) {
|
||||
pthread_mutex_lock(&rtp_proxytable_mutex);
|
||||
/*
|
||||
* !! We now have a locked MUTEX! It is forbidden to return() from
|
||||
* !! here up to the end of this funtion where the MUTEX is
|
||||
* !! unlocked again.
|
||||
* !! Per design, a mutex is locked (for one purpose) at *exactly one*
|
||||
* !! place in the code and unlocked also at *exactly one* place.
|
||||
* !! this minimizes the risk of deadlocks.
|
||||
*/
|
||||
}
|
||||
/*
|
||||
* wakeup/signal rtp_proxythread from select() hibernation.
|
||||
* This must be done here before we close the socket, otherwise
|
||||
* we may get an select() error later from the proxy thread that
|
||||
* is still hibernating in select() now.
|
||||
*/
|
||||
if (!pthread_equal(rtpproxy_tid, pthread_self()))
|
||||
pthread_kill(rtpproxy_tid, SIGALRM);
|
||||
|
||||
/*
|
||||
* find the proper entry in rtp_proxytable
|
||||
* we need to loop the whole table, as there might be multiple
|
||||
* media strema active for the same callid (audio + video stream)
|
||||
*/
|
||||
for (i=0; i<RTPPROXY_SIZE; i++) {
|
||||
if ((callid->number==NULL) || (callid->host==NULL)) break;
|
||||
if( rtp_proxytable[i].sock &&
|
||||
(strcmp(rtp_proxytable[i].callid_number, callid->number)==0) &&
|
||||
(strcmp(rtp_proxytable[i].callid_host, callid->host)==0) ) {
|
||||
sts = close(rtp_proxytable[i].sock);
|
||||
DEBUGC(DBCLASS_RTP,"closed socket %i for RTP stream "
|
||||
"%s:%s == %s:%s (idx=%i) sts=%i",
|
||||
rtp_proxytable[i].sock,
|
||||
rtp_proxytable[i].callid_number,
|
||||
rtp_proxytable[i].callid_host,
|
||||
callid->number, callid->host, i, sts);
|
||||
if (sts < 0) {
|
||||
ERROR("Error in close(%i): %s nolock=%i %s:%s\n",
|
||||
rtp_proxytable[i].sock,
|
||||
strerror(errno), nolock,
|
||||
callid->number, callid->host);
|
||||
}
|
||||
memset(&rtp_proxytable[i], 0, sizeof(rtp_proxytable[0]));
|
||||
got_match=1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* did not find an active stream... */
|
||||
if (!got_match) {
|
||||
DEBUGC(DBCLASS_RTP,"rtp_relay_stop_fwd: can't find active stream for %s@%s",
|
||||
callid->number, callid->host);
|
||||
retsts = STS_FAILURE;
|
||||
goto unlock_and_exit;
|
||||
}
|
||||
|
||||
|
||||
/* prepare FD set for next select operation */
|
||||
rtp_recreate_fdset();
|
||||
|
||||
|
||||
unlock_and_exit:
|
||||
/*
|
||||
* unlock mutex - only if not requested to skip the lock.
|
||||
* this is needed as we are also called from within
|
||||
* the RTP thread itself - and there we already own the lock.
|
||||
*/
|
||||
if (nolock == 0) {
|
||||
pthread_mutex_unlock(&rtp_proxytable_mutex);
|
||||
}
|
||||
#undef return
|
||||
|
||||
return retsts;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* some sockets have been newly created or removed -
|
||||
* recreate the FD set for next select operation
|
||||
*
|
||||
* RETURNS
|
||||
* STS_SUCCESS on success (always)
|
||||
*/
|
||||
static int rtp_recreate_fdset(void) {
|
||||
int i;
|
||||
|
||||
FD_ZERO(&master_fdset);
|
||||
master_fd_max=-1;
|
||||
for (i=0;i<RTPPROXY_SIZE;i++) {
|
||||
if (rtp_proxytable[i].sock != 0) {
|
||||
FD_SET(rtp_proxytable[i].sock, &master_fdset);
|
||||
if (rtp_proxytable[i].sock > master_fd_max) {
|
||||
master_fd_max=rtp_proxytable[i].sock;
|
||||
}
|
||||
}
|
||||
} /* for i */
|
||||
return STS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* kills the rtp_proxy thread
|
||||
*
|
||||
* RETURNS
|
||||
* -
|
||||
*/
|
||||
void rtpproxy_kill( void ) {
|
||||
void *thread_status;
|
||||
|
||||
if (rtpproxy_tid) {
|
||||
pthread_cancel(rtpproxy_tid);
|
||||
pthread_join(rtpproxy_tid, &thread_status);
|
||||
}
|
||||
|
||||
DEBUGC(DBCLASS_RTP,"killed RTP proxy thread");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
+2
-18
@@ -144,17 +144,10 @@ int main (int argc, char *argv[])
|
||||
/* daemonize if requested to */
|
||||
if (configuration.daemonize) {
|
||||
DEBUGC(DBCLASS_CONFIG,"daemonizing");
|
||||
/* daemon() seems to be broken! starting the threads afterwards
|
||||
with pthread_create will get stuck... */
|
||||
#if HAVE_DAEMONxxSICK
|
||||
if (daemon(1,0) == -1) {
|
||||
ERROR("unable to daemonize: %s", strerror(errno));
|
||||
};
|
||||
# else
|
||||
if (fork()!=0) exit(0);
|
||||
setsid();
|
||||
if (fork()!=0) exit(0);
|
||||
#endif
|
||||
|
||||
log_set_tosyslog(1);
|
||||
}
|
||||
#ifdef MOREDEBUG /*&&&&*/
|
||||
@@ -162,14 +155,7 @@ INFO("daemonizing done (pid=%i)", getpid());
|
||||
#endif
|
||||
|
||||
/* initialize the RTP proxy thread */
|
||||
#ifdef MOREDEBUG /*&&&&*/
|
||||
INFO("b4 rtpproxy_init");
|
||||
#endif
|
||||
atexit(rtpproxy_kill); /* cancel RTP thread at exit */
|
||||
rtpproxy_init();
|
||||
#ifdef MOREDEBUG /*&&&&*/
|
||||
INFO("rtpproxy_init done");
|
||||
#endif
|
||||
|
||||
/* init the oSIP parser */
|
||||
parser_init();
|
||||
@@ -184,9 +170,6 @@ INFO("rtpproxy_init done");
|
||||
ERROR("unable to bind to SIP listening socket - aborting");
|
||||
exit(1);
|
||||
}
|
||||
#ifdef MOREDEBUG /*&&&&*/
|
||||
INFO("sipsock_listen done");
|
||||
#endif
|
||||
|
||||
INFO(PACKAGE"-"VERSION"-"BUILDSTR" started");
|
||||
/*
|
||||
@@ -236,6 +219,7 @@ INFO("got packet from %s [%s]", inet_ntoa(from.sin_addr), tmp);}
|
||||
sts=osip_message_parse(my_msg, buff);
|
||||
if (sts != 0) {
|
||||
ERROR("osip_message_parse() failed... this is not good");
|
||||
DUMP_BUFFER(-1, buff, i);
|
||||
goto end_loop; /* skip and free resources */
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -66,7 +66,7 @@ int rtpproxy_init( void ); /*X*/
|
||||
int rtp_start_fwd (osip_call_id_t *callid, int media_stream_no, /*X*/
|
||||
struct in_addr outbound_ipaddr, int *outboundport,
|
||||
struct in_addr lcl_client_ipaddr, int lcl_clientport);
|
||||
int rtp_stop_fwd (osip_call_id_t *callid, int nolock); /*X*/
|
||||
int rtp_stop_fwd (osip_call_id_t *callid); /*X*/
|
||||
void rtpproxy_kill( void ); /*X*/
|
||||
|
||||
/* accessctl.c */
|
||||
|
||||
Reference in New Issue
Block a user