Codename Pineapple

Home page | Mailing list | Docs

Last updated: Sat Feb 3 05:00:56 2007

Asterisk developer's documentation :: Codename Pineapple


sip3_monitor.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 1999 - 2007, Digium, Inc.
00005  * and Edvina AB, Sollentuna, Sweden (chan_sip3 changes/additions)
00006  *
00007  * Mark Spencer <markster@digium.com>
00008  *
00009  * See http://www.asterisk.org for more information about
00010  * the Asterisk project. Please do not directly contact
00011  * any of the maintainers of this project for assistance;
00012  * the project provides a web site, mailing lists and IRC
00013  * channels for your use.
00014  *
00015  * This program is free software, distributed under the terms of
00016  * the GNU General Public License Version 2. See the LICENSE file
00017  * at the top of the source tree.
00018  */
00019 
00020 /*!
00021  * \file
00022  * \brief The SIP monitor thread
00023  * Version 3 of chan_sip
00024  *
00025  * \author Mark Spencer <markster@digium.com>
00026  * \author Olle E. Johansson <oej@edvina.net> (all the chan_sip3 changes)
00027  *
00028  * See Also:
00029  * \arg \ref AstCREDITS
00030  *
00031  */
00032 
00033 /*! \page SIP3_monitor Chan_sip3:: The monitor thread
00034  *
00035  * The monitor thread is a background process that takes care of maintenance of the
00036  * SIP channel
00037  *    - Destruction of SIP dialogs at timeout
00038  * - Scheduled items, like retransmits, registrations that expire etc
00039  * - Voicemail notifications
00040 */
00041 
00042 #include "asterisk.h"
00043 
00044 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 47624 $")
00045 
00046 #include <stdio.h>
00047 #include <ctype.h>
00048 #include <string.h>
00049 #include <unistd.h>
00050 #include <sys/socket.h>
00051 #include <sys/ioctl.h>
00052 #include <net/if.h>
00053 #include <errno.h>
00054 #include <stdlib.h>
00055 #include <fcntl.h>
00056 #include <netdb.h>
00057 #include <signal.h>
00058 #include <sys/signal.h>
00059 #include <netinet/in.h>
00060 #include <netinet/in_systm.h>
00061 #include <arpa/inet.h>
00062 #include <netinet/ip.h>
00063 #include <regex.h>
00064 
00065 #include "asterisk/lock.h"
00066 #include "asterisk/channel.h"
00067 #include "asterisk/config.h"
00068 #include "asterisk/logger.h"
00069 #include "asterisk/module.h"
00070 #include "asterisk/pbx.h"
00071 #include "asterisk/options.h"
00072 #include "asterisk/sched.h"
00073 #include "asterisk/io.h"
00074 #include "asterisk/rtp.h"
00075 #include "asterisk/udptl.h"
00076 #include "asterisk/acl.h"
00077 #include "asterisk/manager.h"
00078 #include "asterisk/callerid.h"
00079 #include "asterisk/cli.h"
00080 #include "asterisk/app.h"
00081 #include "asterisk/musiconhold.h"
00082 #include "asterisk/dsp.h"
00083 #include "asterisk/features.h"
00084 #include "asterisk/srv.h"
00085 #include "asterisk/astdb.h"
00086 #include "asterisk/causes.h"
00087 #include "asterisk/utils.h"
00088 #include "asterisk/file.h"
00089 #include "asterisk/astobj.h"
00090 #include "asterisk/dnsmgr.h"
00091 #include "asterisk/devicestate.h"
00092 #include "asterisk/linkedlists.h"
00093 #include "asterisk/stringfields.h"
00094 #include "asterisk/monitor.h"
00095 #include "asterisk/localtime.h"
00096 #include "asterisk/abstract_jb.h"
00097 #include "asterisk/compiler.h"
00098 #include "sip3.h"
00099 #include "sip3funcs.h"
00100 
00101 /*! \brief This is the thread for the monitor which checks for input on the channels
00102    which are not currently in use.  */
00103 static pthread_t monitor_thread = AST_PTHREADT_NULL;
00104 
00105 
00106 /*! \brief Protect the monitoring thread, so only one process can kill or start it, and not
00107    when it's doing something critical. */
00108 AST_MUTEX_DEFINE_STATIC(monlock);
00109 
00110 /*! \brief kill monitor thread (only at module unload) */
00111 void kill_monitor(void)
00112 {
00113    /* Kill the monitor thread */
00114    ast_mutex_lock(&monlock);
00115    if (monitor_thread && (monitor_thread != AST_PTHREADT_STOP)) {
00116       pthread_cancel(monitor_thread);
00117       pthread_kill(monitor_thread, SIGURG);
00118       pthread_join(monitor_thread, NULL);
00119    }
00120    monitor_thread = AST_PTHREADT_STOP;
00121    ast_mutex_unlock(&monlock);
00122 }
00123 
00124 
00125 /*! \brief Start the channel monitor thread */
00126 int restart_monitor(void)
00127 {
00128    /* If we're supposed to be stopped -- stay stopped */
00129    if (monitor_thread == AST_PTHREADT_STOP)
00130       return 0;
00131    /* Lock the monitor lock to keep the new monitor thread under control */
00132    ast_mutex_lock(&monlock);
00133    if (monitor_thread == pthread_self()) {
00134       ast_mutex_unlock(&monlock);
00135       ast_log(LOG_WARNING, "Cannot kill myself\n");
00136       return -1;
00137    }
00138    if (monitor_thread != AST_PTHREADT_NULL) {
00139       /* Wake up the thread */
00140       pthread_kill(monitor_thread, SIGURG);
00141    } else {
00142       /* Start a new monitor */
00143       if (ast_pthread_create_background(&monitor_thread, NULL, do_sip_monitor, NULL) < 0) {
00144          ast_mutex_unlock(&monlock);
00145          ast_log(LOG_ERROR, "Unable to start monitor thread.\n");
00146          return -1;
00147       }
00148    }
00149 
00150    /* Let the monitor run by itself now */
00151    ast_mutex_unlock(&monlock);
00152    return 0;
00153 }
00154 
00155 /*! \brief Check RTP timeouts and send RTP keepalives 
00156    \note We're only sending audio keepalives yet.  
00157 */
00158 static void check_rtp_timeout(struct sip_dialog *dialog, time_t t)
00159 {
00160    /* If we have no RTP or no active owner, no need to check timers */
00161    if (!dialog->rtp || !dialog->owner)
00162       return;
00163    /* If the call is not in UP state or redirected outside Asterisk, no need to check timers */
00164    if (dialog->owner->_state != AST_STATE_UP || dialog->redirip.sin_addr.s_addr)
00165       return;
00166 
00167    /* If we have no timers set, return now */
00168    if (ast_rtp_get_rtpkeepalive(dialog->rtp) == 0 || (ast_rtp_get_rtptimeout(dialog->rtp) == 0 && ast_rtp_get_rtpholdtimeout(dialog->rtp) == 0))
00169       return;
00170 
00171    dialog_lock(dialog, TRUE);
00172 
00173    /* Check AUDIO RTP keepalives */
00174    if (dialog->lastrtptx && ast_rtp_get_rtpkeepalive(dialog->rtp) &&
00175           (t > dialog->lastrtptx + ast_rtp_get_rtpkeepalive(dialog->rtp))) {
00176       /* Need to send an empty RTP packet */
00177       dialog->lastrtptx = time(NULL);
00178       ast_rtp_sendcng(dialog->rtp, 0);
00179    }
00180 
00181    /*! \todo Check video RTP keepalives
00182 
00183       Do we need to move the lastrtptx to the RTP structure to have one for audio and one
00184       for video? It really does belong to the RTP structure.
00185    */
00186 
00187    /* Check AUDIO RTP timers */
00188    if (dialog->lastrtprx && (ast_rtp_get_rtptimeout(dialog->rtp) || ast_rtp_get_rtpholdtimeout(dialog->rtp)) &&
00189           (t > dialog->lastrtprx + ast_rtp_get_rtptimeout(dialog->rtp))) {
00190 
00191       /* Might be a timeout now -- see if we're on hold */
00192       struct sockaddr_in sin;
00193       ast_rtp_get_peer(dialog->rtp, &sin);
00194       if (sin.sin_addr.s_addr || (ast_rtp_get_rtpholdtimeout(dialog->rtp) &&
00195            (t > dialog->lastrtprx + ast_rtp_get_rtpholdtimeout(dialog->rtp)))) {
00196          /* Needs a hangup */
00197          if (ast_rtp_get_rtptimeout(dialog->rtp)) {
00198             while (dialog->owner && ast_channel_trylock(dialog->owner)) {
00199                dialog_lock(dialog, FALSE);
00200                usleep(1);
00201                dialog_lock(dialog, TRUE);
00202             }
00203             if (!(ast_rtp_get_bridged(dialog->rtp))) {
00204                ast_log(LOG_NOTICE, "Disconnecting call '%s' for lack of RTP activity in %ld seconds\n",
00205                   dialog->owner->name, (long) (t - dialog->lastrtprx));
00206                /* Issue a softhangup */
00207                ast_softhangup_nolock(dialog->owner, AST_SOFTHANGUP_DEV);
00208             } else
00209                ast_log(LOG_NOTICE, "'%s' will not be disconnected in %ld seconds because it is directly bridged to another RTP stream\n", dialog->owner->name, (long) (t - dialog->lastrtprx));
00210             ast_channel_unlock(dialog->owner);
00211             /* forget the timeouts for this call, since a hangup
00212                has already been requested and we don't want to
00213                repeatedly request hangups
00214             */
00215             ast_rtp_set_rtptimeout(dialog->rtp, 0);
00216             ast_rtp_set_rtpholdtimeout(dialog->rtp, 0);
00217             if (dialog->vrtp) {
00218                ast_rtp_set_rtptimeout(dialog->vrtp, 0);
00219                ast_rtp_set_rtpholdtimeout(dialog->vrtp, 0);
00220             }
00221          }
00222       }
00223    }
00224    dialog_lock(dialog, FALSE);
00225 }
00226 
00227 /*! \brief Check whether peer needs a new MWI notification check */
00228 static int does_peer_need_mwi(struct sip_device *peer)
00229 {
00230    time_t t = time(NULL);
00231 
00232    if (ast_test_flag(&peer->flags[1], SIP_PAGE2_SUBSCRIBEMWIONLY) &&
00233        !peer->mailbox.mwipvt) {  /* We don't have a subscription */
00234       peer->mailbox.lastmsgcheck = t;  /* Reset timer */
00235       return FALSE;
00236    }
00237 
00238    if (!ast_strlen_zero(peer->mailbox.mailbox) && (t - peer->mailbox.lastmsgcheck) > global.mwitime)
00239       return TRUE;
00240 
00241    return FALSE;
00242 }
00243 
00244 
00245 /*! \brief The SIP monitoring thread 
00246 \note This thread monitors all the SIP sessions and peers that needs notification of mwi
00247    (and thus do not have a separate thread) indefinitely 
00248 */
00249 void *do_sip_monitor(void *data)
00250 {
00251    int res;
00252    struct sip_dialog *sip;
00253    struct sip_device *device = NULL;
00254    time_t now;
00255    int fastrestart = FALSE;
00256    int lastpeernum = -1;
00257    int curpeernum;
00258    static int nowalkmessage = 0;
00259 
00260    /* Add an I/O event to our SIP UDP socket */
00261    if (sipsocket_initialized(&sipnet))
00262       sipnet.read_id = ast_io_add(io, sipnet.sipsock, sipsock_read, AST_IO_IN, NULL);
00263    
00264    /* From here on out, we die whenever asked */
00265    for(;;) {
00266       /*------  Check for a reload request */
00267       if (sip_reload_check()) {
00268          if (option_verbose > 0)
00269             ast_verbose(VERBOSE_PREFIX_1 "Reloading SIP\n");
00270          sip_do_reload();
00271 
00272          /* Change the I/O fd of our UDP socket */
00273          if (sipsocket_initialized(&sipnet))
00274             sipnet.read_id = ast_io_change(io, sipnet.read_id, sipnet.sipsock, NULL, 0, NULL);
00275       }
00276 
00277       /*----- Check for interfaces needing to be killed */
00278       if (dialoglist != NULL && !fastrestart) {
00279          struct sip_dialog *nextdialog;
00280 
00281          if (option_debug > 4)
00282             ast_log(LOG_DEBUG, ":: MONITOR :: Walking dialog list.\n");
00283          dialoglist_lock();
00284 restartsearch:    
00285          now = time(NULL);
00286          /* don't scan the interface list if it hasn't been a reasonable period
00287             of time since the last time we did it (when MWI is being sent, we can
00288             get back to this point every millisecond or less)
00289          */
00290          for (sip = dialoglist;  sip; sip = nextdialog) {
00291             nextdialog = sip->next;
00292             /* Check RTP timeouts and kill calls if we have a timeout set and do not get RTP or RTCP */
00293             check_rtp_timeout(sip, now);
00294 
00295             /* If we have sessions that needs to be destroyed, do it now */
00296             if (ast_test_flag(&sip->flags[0], SIP_NEEDDESTROY) && !sip->packets && !sip->owner) {
00297                __sip_destroy(sip, TRUE, FALSE);
00298                //goto restartsearch;
00299             }
00300          }
00301          dialoglist_unlock();
00302          nowalkmessage = 0;
00303       } else if (!fastrestart && sipdebug && option_debug > 4) {
00304          if (!nowalkmessage)
00305             ast_log(LOG_DEBUG, ":: MONITOR :: Empty dialog list. Pausing channel walks\n");
00306          nowalkmessage = 1;
00307       }
00308 
00309       pthread_testcancel();
00310 
00311       /*------ Wait for sched or io */
00312       res = ast_sched_wait(sched);
00313 
00314       if ((res < 0) || (res > 1000))
00315          res = 1000;
00316       /* If we might need to send more mailboxes, don't wait long at all.*/
00317       if (fastrestart)
00318          res = 1;
00319 
00320       res = ast_io_wait(io, res);
00321       if (option_debug && res > 20)
00322          ast_log(LOG_DEBUG, "chan_sip: ast_io_wait ran %d all at once\n", res);
00323       ast_mutex_lock(&monlock);
00324       if (res >= 0)  {
00325          res = ast_sched_runq(sched);  /* Check for scheduled items, like retransmits */
00326          if (option_debug && res >= 20)
00327             ast_log(LOG_DEBUG, "chan_sip: ast_sched_runq ran %d all at once\n", res);
00328       }
00329 
00330       /*----- Send MWI notifications to devices - static and cached realtime peers */
00331       if (sipcounters.peers_with_mwi > 0 ) {
00332          fastrestart = FALSE;
00333          curpeernum = 0;
00334          device= NULL;
00335          /* Find next device that needs mwi */
00336          ASTOBJ_CONTAINER_TRAVERSE(&devicelist, !device, do {
00337             if ((curpeernum > lastpeernum) && does_peer_need_mwi(iterator)) {
00338                fastrestart = TRUE;
00339                lastpeernum = curpeernum;
00340                device = device_ref(iterator);
00341             };
00342             curpeernum++;
00343          } while (0)
00344          );
00345          /* Send MWI to the peer */
00346          if (device) {
00347             ASTOBJ_WRLOCK(device);
00348             sip_send_mwi_to_peer(device);
00349             ASTOBJ_UNLOCK(device);
00350             device_unref(device);
00351          } else {
00352             /* Reset where we come from */
00353             lastpeernum = -1;
00354          }
00355       }
00356       ast_mutex_unlock(&monlock);
00357    }
00358    /* Never reached */
00359    return NULL;
00360    
00361 }
00362 

Asterisk is a trademark for Digium, inc.. | Edvina.net | Asterisk.org | This documentation was generated with Doxygen