Codename Pineapple

Home page | Mailing list | Docs

Last updated: Sat Feb 3 05:01:52 2007

Asterisk developer's documentation :: Codename Pineapple


sip3_monitor.c File Reference


Detailed Description

The SIP monitor thread Version 3 of chan_sip.

Author:
Mark Spencer <markster@digium.com>

Olle E. Johansson <oej@edvina.net> (all the chan_sip3 changes)

See Also:

Definition in file sip3_monitor.c.

#include "asterisk.h"
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <errno.h>
#include <stdlib.h>
#include <fcntl.h>
#include <netdb.h>
#include <signal.h>
#include <sys/signal.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <arpa/inet.h>
#include <netinet/ip.h>
#include <regex.h>
#include "asterisk/lock.h"
#include "asterisk/channel.h"
#include "asterisk/config.h"
#include "asterisk/logger.h"
#include "asterisk/module.h"
#include "asterisk/pbx.h"
#include "asterisk/options.h"
#include "asterisk/sched.h"
#include "asterisk/io.h"
#include "asterisk/rtp.h"
#include "asterisk/udptl.h"
#include "asterisk/acl.h"
#include "asterisk/manager.h"
#include "asterisk/callerid.h"
#include "asterisk/cli.h"
#include "asterisk/app.h"
#include "asterisk/musiconhold.h"
#include "asterisk/dsp.h"
#include "asterisk/features.h"
#include "asterisk/srv.h"
#include "asterisk/astdb.h"
#include "asterisk/causes.h"
#include "asterisk/utils.h"
#include "asterisk/file.h"
#include "asterisk/astobj.h"
#include "asterisk/dnsmgr.h"
#include "asterisk/devicestate.h"
#include "asterisk/linkedlists.h"
#include "asterisk/stringfields.h"
#include "asterisk/monitor.h"
#include "asterisk/localtime.h"
#include "asterisk/abstract_jb.h"
#include "asterisk/compiler.h"
#include "sip3.h"
#include "sip3funcs.h"

Include dependency graph for sip3_monitor.c:

Go to the source code of this file.

Functions

 AST_MUTEX_DEFINE_STATIC (monlock)
 Protect the monitoring thread, so only one process can kill or start it, and not when it's doing something critical.
static void check_rtp_timeout (struct sip_dialog *dialog, time_t t)
 Check RTP timeouts and send RTP keepalives.
void * do_sip_monitor (void *data)
 The SIP monitoring thread.
static int does_peer_need_mwi (struct sip_device *peer)
 Check whether peer needs a new MWI notification check.
void kill_monitor (void)
 kill monitor thread (only at module unload)
int restart_monitor (void)
 Start the channel monitor thread.

Variables

static pthread_t monitor_thread = AST_PTHREADT_NULL
 This is the thread for the monitor which checks for input on the channels which are not currently in use.


Function Documentation

AST_MUTEX_DEFINE_STATIC monlock   ) 
 

Protect the monitoring thread, so only one process can kill or start it, and not when it's doing something critical.

static void check_rtp_timeout struct sip_dialog dialog,
time_t  t
[static]
 

Check RTP timeouts and send RTP keepalives.

Note:
We're only sending audio keepalives yet.
Todo:
Check video RTP keepalives
Do we need to move the lastrtptx to the RTP structure to have one for audio and one for video? It really does belong to the RTP structure.

Definition at line 158 of file sip3_monitor.c.

References ast_channel::_state, ast_channel_trylock, ast_channel_unlock, ast_log(), ast_rtp_get_bridged(), ast_rtp_get_peer(), ast_rtp_get_rtpholdtimeout(), ast_rtp_get_rtpkeepalive(), ast_rtp_get_rtptimeout(), ast_rtp_sendcng(), ast_rtp_set_rtpholdtimeout(), ast_rtp_set_rtptimeout(), AST_SOFTHANGUP_DEV, ast_softhangup_nolock(), AST_STATE_UP, dialog_lock(), FALSE, sip_dialog::lastrtprx, sip_dialog::lastrtptx, LOG_NOTICE, sip_dialog::owner, sip_dialog::redirip, sip_dialog::rtp, TRUE, and sip_dialog::vrtp.

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 }

void* do_sip_monitor void *  data  ) 
 

The SIP monitoring thread.

Note:
This thread monitors all the SIP sessions and peers that needs notification of mwi (and thus do not have a separate thread) indefinitely

Definition at line 249 of file sip3_monitor.c.

References ast_io_add(), ast_io_change(), AST_IO_IN, ast_verbose(), FALSE, io, option_verbose, sip_network::read_id, sip_do_reload(), sip_reload_check(), sipnet, sip_network::sipsock, sipsock_read(), sipsocket_initialized(), and VERBOSE_PREFIX_1.

Referenced by restart_monitor().

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 }

static int does_peer_need_mwi struct sip_device peer  )  [static]
 

Check whether peer needs a new MWI notification check.

Definition at line 228 of file sip3_monitor.c.

References ast_strlen_zero(), ast_test_flag, FALSE, sip_device::flags, global, sip_mwi_mailbox::lastmsgcheck, sip_device::mailbox, sip_mwi_mailbox::mwipvt, sip_globals::mwitime, SIP_PAGE2_SUBSCRIBEMWIONLY, and TRUE.

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 }

void kill_monitor void   ) 
 

kill monitor thread (only at module unload)

Definition at line 111 of file sip3_monitor.c.

References ast_mutex_lock(), ast_mutex_unlock(), and AST_PTHREADT_STOP.

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 }

int restart_monitor void   ) 
 

Start the channel monitor thread.

Definition at line 126 of file sip3_monitor.c.

References ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_pthread_create_background, AST_PTHREADT_NULL, AST_PTHREADT_STOP, do_sip_monitor(), LOG_ERROR, and LOG_WARNING.

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 }


Variable Documentation

pthread_t monitor_thread = AST_PTHREADT_NULL [static]
 

This is the thread for the monitor which checks for input on the channels which are not currently in use.

Definition at line 103 of file sip3_monitor.c.


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