- RTP proxy: fixed a bug that could lead to a deadlock

on very rapid HOLD/unHOLD sequences.
This commit is contained in:
Thomas Ries
2004-02-07 20:55:03 +00:00
parent 9df56bc3b8
commit d0a2ac463a
6 changed files with 102 additions and 38 deletions
+2
View File
@@ -3,6 +3,8 @@
7-Feb-2004: - Fix for local-UA to local-UA RTP proxying, symmetric
RTP was not working.
- logging routines now use a MUTEX to be thread safe.
- RTP proxy: fixed a bug that could lead to a deadlock
on very rapid HOLD/unHOLD sequences.
1-Feb-2004: - Added handling of Max-Forwards header
- a detected via loop results in an 482 Loop detected
31-Jan-2004: - Allow 2 of my vias in header to let 2 UA's sitting
+3
View File
@@ -30,6 +30,9 @@
/* Define if you have the daemon function. */
#undef HAVE_DAEMON
/* Define if you have the fcntl function. */
#undef HAVE_FCNTL
/* Define if you have the fgets function. */
#undef HAVE_FGETS
+1 -1
View File
@@ -327,7 +327,7 @@ ACX_WHICH_GETHOSTBYNAME_R()
AC_CHECK_FUNCS(getopt_long daemon syslog)
AC_CHECK_FUNCS(getuid setuid getgid setgid getpwnam chroot)
AC_CHECK_FUNCS(socket bind select read send sendto)
AC_CHECK_FUNCS(socket bind select read send sendto fcntl)
AC_CHECK_FUNCS(strncpy strchr strstr sprintf vfprintf vsnprintf)
AC_CHECK_FUNCS(fgets sscanf)
AC_CHECK_FUNCS(hstrerror,,AC_CHECK_LIB(resolv,hstrerror,[
+54 -27
View File
@@ -135,7 +135,7 @@ static void *rtpproxy_main(void *arg) {
if ((num_fd<0) && (errno==EINTR)) {
/*
* wakeup due to a change in the proxy table:
* lock mutex copy master FD set and unlock
* lock mutex, copy master FD set and unlock
*/
pthread_mutex_lock(&rtp_proxytable_mutex);
memcpy(&fdset, &master_fdset, sizeof(fdset));
@@ -154,35 +154,64 @@ static void *rtpproxy_main(void *arg) {
/* check for data available and send to destination */
for (i=0;(i<RTPPROXY_SIZE) && (num_fd>0);i++) {
if ( (rtp_proxytable[i].rtp_rx_sock != 0) &&
FD_ISSET(rtp_proxytable[i].rtp_rx_sock, &fdset) ) {
FD_ISSET(rtp_proxytable[i].rtp_rx_sock, &fdset) ) {
/* yup, have some data to send */
num_fd--;
/* read from sock rtp_proxytable[i].sock*/
count=read(rtp_proxytable[i].rtp_rx_sock, rtp_buff, RTP_BUFFER_SIZE);
#if 0
/* looks like for some reason sometimes the socket
is not yet ready (right after start of rtp stream) */
if (count<0) {
int j;
WARN("read() [fd=%i, %s:%i] returned error [%s]",
rtp_proxytable[i].rtp_rx_sock,
utils_inet_ntoa(rtp_proxytable[i].local_ipaddr),
rtp_proxytable[i].local_port, strerror(errno));
for (j=0; j<RTPPROXY_SIZE;j++) {
DEBUGC(DBCLASS_RTP, "%i - rx:%i tx:%i %s@%s dir:%i "
"lp:%i, rp:%i",
j,
rtp_proxytable[j].rtp_rx_sock,
rtp_proxytable[j].rtp_tx_sock,
rtp_proxytable[j].callid_number,
rtp_proxytable[j].callid_host,
rtp_proxytable[j].direction,
rtp_proxytable[j].local_port,
rtp_proxytable[j].remote_port);
/* check if something went banana */
if (count < 0) {
/*
* It has been seen on linux 2.2.x systems that for some
* reason (kernel bug?) inside the RTP relay, select()
* claims that a certain file descriptor has data available to
* read, a subsequent call to read() or recv() the does block!!
* So lets make the FD's we are going to use non-blocking, so
* we will at least survive and not run into a deadlock.
*
* We catch this here with this workaround (pronounce "hack")
* and hope that next time we pass by it will be ok again.
*/
if (errno == EAGAIN) {
continue;
}
}
#endif
/*
* I *MAY* receive ICMP destination unreachable messages when I
* try to send RTP traffic to a destination that is in HOLD
* (better: is not listening on the UDP port where I send
* my RTP data to).
* So I should *not* do this - or ignore errors originating
* by this -> ECONNREFUSED
*
* Note: This error is originating from a previous send() on the
* same socket and has nothing to do with the read() we have
* done above!
*/
if (errno != ECONNREFUSED) {
int j;
WARN("read() [fd=%i, %s:%i] returned error [%i:%s]",
rtp_proxytable[i].rtp_rx_sock,
utils_inet_ntoa(rtp_proxytable[i].local_ipaddr),
rtp_proxytable[i].local_port, errno, strerror(errno));
for (j=0; j<RTPPROXY_SIZE;j++) {
DEBUGC(DBCLASS_RTP, "%i - rx:%i tx:%i %s@%s dir:%i "
"lp:%i, rp:%i rip:%s",
j,
rtp_proxytable[j].rtp_rx_sock,
rtp_proxytable[j].rtp_tx_sock,
rtp_proxytable[j].callid_number,
rtp_proxytable[j].callid_host,
rtp_proxytable[j].direction,
rtp_proxytable[j].local_port,
rtp_proxytable[j].remote_port,
utils_inet_ntoa(rtp_proxytable[j].remote_ipaddr));
} /* for j */
} /* if errno != ECONNREFUSED */
} /* count < 0 */
/*
* forwarding an RTP packet only makes sense if we really
* have got some data in it (count > 0)
@@ -217,7 +246,7 @@ static void *rtpproxy_main(void *arg) {
rtp_proxytable[i].rtp_tx_sock = rtp_proxytable[j].rtp_rx_sock;
DEBUGC(DBCLASS_RTP, "connected entry %i (fd=%i) <-> entry %i (fd=%i)",
j, rtp_proxytable[j].rtp_rx_sock,
i, rtp_proxytable[j].rtp_rx_sock);
i, rtp_proxytable[i].rtp_rx_sock);
break;
}
}
@@ -248,8 +277,6 @@ static void *rtpproxy_main(void *arg) {
/* update timestamp of last usage */
rtp_proxytable[i].timestamp=t;
num_fd--;
}
} /* for i */
+14 -8
View File
@@ -68,10 +68,19 @@ int security_check_raw(char *sip_buffer, int size){
*/
int security_check_sip(osip_message_t *sip){
/* check for existing SIP URI in request */
if (MSG_IS_REQUEST(sip) && (sip->req_uri == NULL)) {
ERROR("security check failed: NULL SIP URI");
return STS_FAILURE;
if (MSG_IS_REQUEST(sip)) {
/* check for existing SIP URI in request */
if ((sip->req_uri == NULL) || (sip->req_uri->scheme == NULL)) {
ERROR("security check failed: NULL SIP URI");
return STS_FAILURE;
}
/* check SIP URI scheme */
if (osip_strcasecmp(sip->req_uri->scheme, "sip")) {
ERROR("security check failed: unknown scheme: %s",
sip->req_uri->scheme);
return STS_FAILURE;
}
}
/* check for existing To: header */
@@ -79,13 +88,11 @@ int security_check_sip(osip_message_t *sip){
ERROR("security check failed: NULL To Header");
return STS_FAILURE;
}
/* check for existing To: URL */
if (sip->to->url == NULL) {
ERROR("security check failed: NULL To->url Header");
return STS_FAILURE;
}
/* check for existing TO URL host*/
if (sip->to->url->host == NULL) {
ERROR("security check failed: NULL To->url->host Header");
@@ -97,19 +104,18 @@ int security_check_sip(osip_message_t *sip){
ERROR("security check failed: NULL From Header");
return STS_FAILURE;
}
/* check for existing FROM URL */
if (sip->from->url == NULL) {
ERROR("security check failed: NULL From->url Header");
return STS_FAILURE;
}
/* check for existing FROM URL host*/
if (sip->from->url->host == NULL) {
ERROR("security check failed: NULL From->url->host Header");
return STS_FAILURE;
}
/* TODO: still way to go here ... */
return STS_SUCCESS;
}
+28 -2
View File
@@ -29,6 +29,7 @@
#include <sys/time.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
@@ -190,6 +191,7 @@ int sockbind(struct in_addr ipaddr, int localport, int errflg) {
struct sockaddr_in my_addr;
int sts;
int sock;
int flags;
memset(&my_addr, 0, sizeof(my_addr));
@@ -199,13 +201,37 @@ int sockbind(struct in_addr ipaddr, int localport, int errflg) {
sock=socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (sock < 0) {
ERROR("socket() call failed:%s",strerror(errno));
ERROR("socket() call failed: %s",strerror(errno));
return 0;
}
sts=bind(sock, (struct sockaddr *)&my_addr, sizeof(my_addr));
if (sts != 0) {
if (errflg) ERROR("bind failed:%s",strerror(errno));
if (errflg) ERROR("bind failed: %s",strerror(errno));
close(sock);
return 0;
}
/*
* It has been seen on linux 2.2.x systems that for some
* reason (kernel bug?) inside the RTP relay, select()
* claims that a certain file descriptor has data available to
* read, a subsequent call to read() or recv() the does block!!
* So lets make the FD's we are going to use non-blocking, so
* we will at least survive and not run into a deadlock.
*
* There is a way to (more or less) reproduce this effect:
* Make a local UA to local UA call and then very quickly do
* HOLD/unHOLD, several times.
*/
flags = fcntl(sock, F_GETFL);
if (flags < 0) {
ERROR("fcntl(F_SETFL) failed: %s",strerror(errno));
close(sock);
return 0;
}
if (fcntl(sock, F_SETFL, (long) flags | O_NONBLOCK) < 0) {
ERROR("fcntl(F_SETFL) failed: %s",strerror(errno));
close(sock);
return 0;
}