- RTP proxy: fixed a bug that could lead to a deadlock
on very rapid HOLD/unHOLD sequences.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user