diff --git a/ChangeLog b/ChangeLog index e8c58de..0f48e45 100644 --- a/ChangeLog +++ b/ChangeLog @@ -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 diff --git a/config.h.in b/config.h.in index b182335..4a4c5bc 100644 --- a/config.h.in +++ b/config.h.in @@ -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 diff --git a/configure.in b/configure.in index 4464dbf..6f77184 100644 --- a/configure.in +++ b/configure.in @@ -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,[ diff --git a/src/rtpproxy_relay.c b/src/rtpproxy_relay.c index 0ae2232..380584d 100644 --- a/src/rtpproxy_relay.c +++ b/src/rtpproxy_relay.c @@ -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;(i0);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 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 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 */ diff --git a/src/security.c b/src/security.c index 377fc98..115af5f 100644 --- a/src/security.c +++ b/src/security.c @@ -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; } diff --git a/src/sock.c b/src/sock.c index 5bc4c74..479d636 100644 --- a/src/sock.c +++ b/src/sock.c @@ -29,6 +29,7 @@ #include #include +#include #include #include @@ -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; }