Merge OSS fixes for FreeBSD, implement rtptimeout and rtpholdtimeout
authorMark Spencer <markster@digium.com>
Thu, 27 May 2004 22:12:55 +0000 (22:12 +0000)
committerMark Spencer <markster@digium.com>
Thu, 27 May 2004 22:12:55 +0000 (22:12 +0000)
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@3097 65c4cc65-6c06-0410-ace0-fbb531ad65f3

apps/Makefile
apps/app_intercom.c
channels/Makefile
channels/chan_oss.c
channels/chan_sip.c
configs/sip.conf.sample

index 708ac94..e10209e 100755 (executable)
@@ -30,10 +30,8 @@ APPS=app_dial.so app_playback.so app_voicemail.so app_directory.so app_mp3.so\
      app_groupcount.so app_txtcidname.so app_controlplayback.so
 
 ifneq (${OSARCH},Darwin)
-ifneq (${OSARCH},FreeBSD)
 APPS+=app_intercom.so
 endif
-endif
 
 #APPS+=app_sql_postgres.so
 #APPS+=app_sql_odbc.so
index 925ea37..1652aaa 100755 (executable)
@@ -29,7 +29,7 @@
 #ifdef __linux__
 #include <linux/soundcard.h>
 #elif defined(__FreeBSD__)
-#include <machine/soundcard.h>
+#include <sys/soundcard.h>
 #else
 #include <soundcard.h>
 #endif
index 32f611c..40f5024 100755 (executable)
@@ -47,10 +47,8 @@ CHANH323LIB=-ldl
 endif
 
 ifneq (${OSARCH},Darwin)
-ifneq (${OSARCH},FreeBSD)
 CHANNEL_LIBS+=chan_oss.so
 endif
-endif
 
 CHANNEL_LIBS+=$(shell [ -f /usr/include/linux/ixjuser.h ] && echo chan_phone.so)
 CHANNEL_LIBS+=$(shell [ -f h323/libchanh323.a ] && echo chan_h323.so)
@@ -64,6 +62,7 @@ CFLAGS+=$(shell [ -f alsa-monitor.h ] && echo " -DALSA_MONITOR")
 ZAPPRI=$(shell [ -f /usr/lib/libpri.so.1 ] && echo "-lpri")
 ZAPR2=$(shell [ -f /usr/lib/libmfcr2.so.1 ] && echo "-lmfcr2")
 CFLAGS+=$(shell [ -f /usr/include/linux/zaptel.h ] && echo "-DIAX_TRUNKING")
+# xxx CFLAGS+=$(shell [ -f /usr/local/include/zaptel.h ] && echo "-DIAX_TRUNKING")
 CHANNEL_LIBS+=$(shell [ -f /usr/include/vpbapi.h ] && echo "chan_vpb.so" )
 CFLAGS+=$(shell [ -f /usr/include/vpbapi.h ] && echo " -DLINUX")
 
index 89eec2e..731ae30 100755 (executable)
@@ -36,7 +36,7 @@
 #ifdef __linux
 #include <linux/soundcard.h>
 #elif defined(__FreeBSD__)
-#include <machine/soundcard.h>
+#include <sys/soundcard.h>
 #else
 #include <soundcard.h>
 #endif
index 8968ea8..14abfcf 100755 (executable)
@@ -150,6 +150,10 @@ static int autocreatepeer = 0;
 
 static int relaxdtmf = 0;
 
+static int globalrtptimeout = 0;
+
+static int globalrtpholdtimeout = 0;
+
 static int usecnt =0;
 static ast_mutex_t usecnt_lock = AST_MUTEX_INITIALIZER;
 
@@ -314,6 +318,9 @@ static struct sip_pvt {
        int maxtime;                            /* Max time for first response */
        int initid;                             /* Auto-congest ID if appropriate */
        int autokillid;                         /* Auto-kill ID */
+       time_t lastrtprx;                       /* Last RTP received */
+       int rtptimeout;                         /* RTP timeout time */
+       int rtpholdtimeout;                     /* RTP timeout when on hold */
 
        int subscribed;
        int stateid;
@@ -396,6 +403,8 @@ struct sip_peer {
        int expire;
        int expiry;
        int capability;
+       int rtptimeout;
+       int rtpholdtimeout;
        int insecure;
        int nat;
        int canreinvite;
@@ -1519,7 +1528,7 @@ static int sip_hangup(struct ast_channel *ast)
        ast_mutex_unlock(&usecnt_lock);
        ast_update_use_count();
 
-       needdestroy = 1;
+       needdestroy = 1; 
        /* Start the process if it's not already started */
        if (!p->alreadygone && !ast_strlen_zero(p->initreq.data)) {
                if (needcancel) {
@@ -1982,6 +1991,7 @@ static struct ast_frame *sip_read(struct ast_channel *ast)
        struct sip_pvt *p = ast->pvt->pvt;
        ast_mutex_lock(&p->lock);
        fr = sip_rtp_read(ast, p);
+       time(&p->lastrtprx);
        ast_mutex_unlock(&p->lock);
        return fr;
 }
@@ -2059,6 +2069,8 @@ static struct sip_pvt *sip_alloc(char *callid, struct sockaddr_in *sin, int useg
        /* Assign default music on hold class */
         strncpy(p->musicclass, globalmusicclass, sizeof(p->musicclass));
        p->dtmfmode = globaldtmfmode;
+       p->rtptimeout = globalrtptimeout;
+       p->rtpholdtimeout = globalrtpholdtimeout;
        p->capability = capability;
        if (p->dtmfmode & SIP_DTMF_RFC2833)
                p->noncodeccapability |= AST_RTP_DTMF;
@@ -2360,6 +2372,9 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req)
        int sendonly = 0;
        int x;
 
+       /* Update our last rtprx when we receive an SDP, too */
+       time(&p->lastrtprx);
+
        /* Get codec and RTP info from SDP */
        if (strcasecmp(get_header(req, "Content-Type"), "application/sdp")) {
                ast_log(LOG_NOTICE, "Content is '%s', not 'application/sdp'\n", get_header(req, "Content-Type"));
@@ -3181,6 +3196,8 @@ static int add_sdp(struct sip_request *resp, struct sip_pvt *p)
                add_line(resp, m2);
                add_line(resp, a2);
        }
+       /* Update lastrtprx when we send our SDP */
+       time(&p->lastrtprx);
        return 0;
 }
 
@@ -5428,8 +5445,10 @@ static void receive_info(struct sip_pvt *p, struct sip_request *req)
                   }
                   transmit_response(p, "200 OK", req);
                   return;
+               } else {
+                       transmit_response(p, "481 Call leg/transaction does not exist", req);
+                       p->needdestroy = 1;
                }
-               transmit_response(p, "481 Call leg/transaction does not exist", req);
                return;
        }
        /* Other type of INFO message, not really understood by Asterisk */
@@ -6353,7 +6372,7 @@ static int handle_request(struct sip_pvt *p, struct sip_request *req, struct soc
                        /* This call is no longer outgoing if it ever was */
                        p->outgoing = 0;
                        /* This also counts as a pending invite */
-                       p->pendinginvite = 1;
+                       p->pendinginvite = seqno;
                        copy_request(&p->initreq, req);
                        check_via(p, req);
                        if (!ast_strlen_zero(get_header(req, "Content-Type"))) {
@@ -6675,7 +6694,6 @@ static int handle_request(struct sip_pvt *p, struct sip_request *req, struct soc
                                ast_verbose("Receiving DTMF!\n");
                        receive_info(p, req);
                }
-               transmit_response(p, "200 OK", req);
        } else if (!strcasecmp(cmd, "REGISTER")) {
                /* Use this as the basis */
                if (sip_debug_test_pvt(p))
@@ -6690,16 +6708,16 @@ static int handle_request(struct sip_pvt *p, struct sip_request *req, struct soc
                    sip_scheddestroy(p, 15*1000);
                }
        } else if (!strcasecmp(cmd, "ACK")) {
-               /* Uhm, I haven't figured out the point of the ACK yet.  Are we
-                  supposed to retransmit responses until we get an ack? 
-                  Make sure this is on a valid call */
-               p->pendinginvite = 0;
-               __sip_ack(p, seqno, FLAG_RESPONSE);
-               if (!ast_strlen_zero(get_header(req, "Content-Type"))) {
-                       if (process_sdp(p, req))
-                               return -1;
-               } 
-               check_pendings(p);
+               /* Make sure we don't ignore this */
+               if (seqno == p->pendinginvite) {
+                       p->pendinginvite = 0;
+                       __sip_ack(p, seqno, FLAG_RESPONSE);
+                       if (!ast_strlen_zero(get_header(req, "Content-Type"))) {
+                               if (process_sdp(p, req))
+                                       return -1;
+                       } 
+                       check_pendings(p);
+               }
                if (!p->lastinvite && ast_strlen_zero(p->randdata))
                        p->needdestroy = 1;
        } else if (!strcasecmp(cmd, "SIP/2.0")) {
@@ -6857,9 +6875,35 @@ static void *do_monitor(void *data)
                /* Check for interfaces needing to be killed */
                ast_mutex_lock(&iflock);
 restartsearch:         
+               time(&t);
                sip = iflist;
                while(sip) {
                        ast_mutex_lock(&sip->lock);
+                       if (sip->rtp && sip->lastrtprx && (sip->rtptimeout || sip->rtpholdtimeout)) {
+                               if (t > sip->lastrtprx + sip->rtptimeout) {
+                                       /* Might be a timeout now -- see if we're on hold */
+                                       struct sockaddr_in sin;
+                                       ast_rtp_get_peer(sip->rtp, &sin);
+                                       if (sin.sin_addr.s_addr || 
+                                                       (sip->rtpholdtimeout && 
+                                                         (t > sip->lastrtprx + sip->rtpholdtimeout))) {
+                                               /* Needs a hangup */
+                                               if (sip->rtptimeout) {
+                                                       while(sip->owner && ast_mutex_trylock(&sip->owner->lock)) {
+                                                               ast_mutex_unlock(&sip->lock);
+                                                               usleep(1);
+                                                               ast_mutex_lock(&sip->lock);
+                                                       }
+                                                       if (sip->owner) {
+                                                               ast_log(LOG_NOTICE, "Disconnecting call '%s' for lack of RTP activity in %ld seconds\n", sip->owner->name, (long)(t - sip->lastrtprx));
+                                                               /* Issue a softhangup */
+                                                               ast_softhangup(sip->owner, AST_SOFTHANGUP_DEV);
+                                                               ast_mutex_unlock(&sip->owner->lock);
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
                        if (sip->needdestroy && !sip->packets) {
                                ast_mutex_unlock(&sip->lock);
                                __sip_destroy(sip, 1);
@@ -7262,6 +7306,8 @@ static struct sip_peer *temp_peer(char *name)
        peer->canreinvite = globalcanreinvite;
        peer->dtmfmode = globaldtmfmode;
        peer->nat = globalnat;
+       peer->rtptimeout = globalrtptimeout;
+       peer->rtpholdtimeout = globalrtpholdtimeout;
        peer->selfdestruct = 1;
        peer->dynamic = 1;
        reg_source_db(peer);
@@ -7320,6 +7366,8 @@ static struct sip_peer *build_peer(char *name, struct ast_variable *v)
                peer->capability = capability;
                /* Assume can reinvite */
                peer->canreinvite = globalcanreinvite;
+               peer->rtptimeout = globalrtptimeout;
+               peer->rtpholdtimeout = globalrtpholdtimeout;
                peer->dtmfmode = 0;
                while(v) {
                        if (!strcasecmp(v->name, "secret")) 
@@ -7425,6 +7473,16 @@ static struct sip_peer *build_peer(char *name, struct ast_variable *v)
                                        peer->insecure = 1;
                                else
                                        peer->insecure = 0;
+                       } else if (!strcasecmp(v->name, "rtptimeout")) {
+                               if ((sscanf(v->value, "%d", &peer->rtptimeout) != 1) || (peer->rtptimeout < 0)) {
+                                       ast_log(LOG_WARNING, "'%s' is not a valid RTP hold time at line %d.  Using default.\n", v->value, v->lineno);
+                                       peer->rtptimeout = globalrtptimeout;
+                               }
+                       } else if (!strcasecmp(v->name, "rtpholdtimeout")) {
+                               if ((sscanf(v->value, "%d", &peer->rtpholdtimeout) != 1) || (peer->rtpholdtimeout < 0)) {
+                                       ast_log(LOG_WARNING, "'%s' is not a valid RTP hold time at line %d.  Using default.\n", v->value, v->lineno);
+                                       peer->rtpholdtimeout = globalrtpholdtimeout;
+                               }
                        } else if (!strcasecmp(v->name, "qualify")) {
                                if (!strcasecmp(v->value, "no")) {
                                        peer->maxms = 0;
@@ -7493,6 +7551,8 @@ static int reload_config(void)
        globalcanreinvite = REINVITE_INVITE;
        videosupport = 0;
        relaxdtmf = 0;
+       globalrtptimeout = 0;
+       globalrtpholdtimeout = 0;
        pedanticsipchecking=0;
        v = ast_variable_browse(cfg, "general");
        while(v) {
@@ -7517,6 +7577,16 @@ static int reload_config(void)
                                ast_log(LOG_WARNING, "Unknown dtmf mode '%s', using rfc2833\n", v->value);
                                globaldtmfmode = SIP_DTMF_RFC2833;
                        }
+               } else if (!strcasecmp(v->name, "rtptimeout")) {
+                       if ((sscanf(v->value, "%d", &globalrtptimeout) != 1) || (globalrtptimeout < 0)) {
+                               ast_log(LOG_WARNING, "'%s' is not a valid RTP hold time at line %d.  Using default.\n", v->value, v->lineno);
+                               globalrtptimeout = 0;
+                       }
+               } else if (!strcasecmp(v->name, "rtpholdtimeout")) {
+                       if ((sscanf(v->value, "%d", &globalrtpholdtimeout) != 1) || (globalrtpholdtimeout < 0)) {
+                               ast_log(LOG_WARNING, "'%s' is not a valid RTP hold time at line %d.  Using default.\n", v->value, v->lineno);
+                               globalrtpholdtimeout = 0;
+                       }
                } else if (!strcasecmp(v->name, "videosupport")) {
                        videosupport = ast_true(v->value);
                } else if (!strcasecmp(v->name, "notifymimetype")) {
index c314b70..ddd3354 100755 (executable)
@@ -48,7 +48,10 @@ bindaddr=0.0.0.0             ; IP address to bind to (0.0.0.0 binds to all)
 ;language=en                   ; Default language setting for all users/peers
                                ; This may also be set for individual users/peers
 ;relaxdtmf=yes                 ; Relax dtmf handling
-
+;rtptimeout=60                 ; Terminate call if 60 seconds of no RTP activity
+                               ; when we're not on hold
+;rtpholdtimeout=300            ; Terminate call if 300 seconds of no RTP activity
+                               ; when we're on hold (must be > rtptimeout)
 
 ; Asterisk can register as a SIP user agent to a SIP proxy (provider)
 ; Format for the register statement is:
@@ -128,7 +131,8 @@ bindaddr=0.0.0.0            ; IP address to bind to (0.0.0.0 binds to all)
 ;                             port
 ;                             qualify
 ;                             defaultip
-
+;                             rtptimeout
+;                             rtpholdtimeout
 
 ;[sip_proxy]
 ; For incoming calls only. Example: FWD (Free World Dialup)