Fri Sep 25 19:28:34 2009

Asterisk developer's documentation


devicestate.c File Reference

Device state management. More...

#include "asterisk.h"
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "asterisk/channel.h"
#include "asterisk/utils.h"
#include "asterisk/lock.h"
#include "asterisk/linkedlists.h"
#include "asterisk/logger.h"
#include "asterisk/devicestate.h"
#include "asterisk/pbx.h"
#include "asterisk/app.h"
#include "asterisk/options.h"

Include dependency graph for devicestate.c:

Go to the source code of this file.

Data Structures

struct  devstate_cb
 A device state watcher (callback). More...
struct  devstate_prov
 A device state provider (not a channel). More...
struct  state_change

Functions

static int __ast_device_state_changed_literal (char *buf, char *cid_num, char *cid_name)
int ast_device_state (const char *device)
 Check device state through channel specific function or generic function.
int ast_device_state_changed (const char *fmt,...)
 Accept change notification, add it to change queue.
int ast_device_state_changed_literal (const char *dev, const char *cid_num, const char *cid_name)
 Tells Asterisk the State for Device is changed.
int ast_device_state_engine_init (void)
 Initialize the device state engine in separate thread.
int ast_devstate_add (ast_devstate_cb_type callback, void *data)
 Add device state watcher.
void ast_devstate_del (ast_devstate_cb_type callback, void *data)
 Remove device state watcher.
int ast_devstate_prov_add (const char *label, ast_devstate_prov_cb_type callback)
 Add device state provider.
void ast_devstate_prov_del (const char *label)
 Remove device state provider.
static AST_LIST_HEAD_STATIC (state_changes, state_change)
 The state change queue. State changes are queued for processing by a separate thread.
static AST_LIST_HEAD_STATIC (devstate_cbs, devstate_cb)
 A device state watcher list.
static AST_LIST_HEAD_STATIC (devstate_provs, devstate_prov)
 A list of providers.
int ast_parse_device_state (const char *device)
 Find out if device is active in a call or not.
const char * devstate2str (int devstate)
 Find devicestate as text message for output.
static void * do_devstate_changes (void *data)
 Go through the dev state change queue and update changes in the dev state thread.
static void do_state_change (const char *device, char *cid_num, char *cid_name)
 Notify callback watchers of change, and notify PBX core for hint updates Normally executed within a separate thread.
static int getproviderstate (const char *provider, const char *address)
 Get provider device state.

Variables

static ast_cond_t change_pending
 Flag for the queue.
static pthread_t change_thread = AST_PTHREADT_NULL
 The device state change notification thread.
static const char * devstatestring []
 Device state strings for printing.


Detailed Description

Device state management.

Author:
Mark Spencer <markster@digium.com>

Definition in file devicestate.c.


Function Documentation

static int __ast_device_state_changed_literal ( char *  buf,
char *  cid_num,
char *  cid_name 
) [static]

Definition at line 299 of file devicestate.c.

References ast_calloc, ast_cond_signal(), AST_LIST_FIRST, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), AST_PTHREADT_NULL, ast_strlen_zero(), do_state_change(), LOG_DEBUG, and option_debug.

Referenced by ast_device_state_changed(), and ast_device_state_changed_literal().

00300 {
00301    char *device;
00302    struct state_change *change;
00303    char *tmp = NULL;
00304 
00305    if (option_debug > 2)
00306       ast_log(LOG_DEBUG, "Notification of state change to be queued on device/channel %s\n", buf);
00307 
00308    device = buf;
00309    
00310    tmp = strrchr(device, '-');
00311    if (tmp)
00312       *tmp = '\0';
00313    
00314    if (change_thread == AST_PTHREADT_NULL || !(change = ast_calloc(1, sizeof(*change) + strlen(device)))) {
00315       /* we could not allocate a change struct, or */
00316       /* there is no background thread, so process the change now */
00317       do_state_change(device, cid_num, cid_name);
00318    } else {
00319       /* queue the change */
00320       strcpy(change->device, device);
00321       if (cid_num && (!ast_strlen_zero(cid_num))) {
00322           strncpy(change->cid_num, cid_num, sizeof(change->cid_num) - 1);
00323       }
00324       if (cid_name && (!ast_strlen_zero(cid_name))) {
00325           strncpy(change->cid_name, cid_name, sizeof(change->cid_name) - 1);
00326       }
00327       AST_LIST_LOCK(&state_changes);
00328       AST_LIST_INSERT_TAIL(&state_changes, change, list);
00329       if (AST_LIST_FIRST(&state_changes) == change)
00330          /* the list was empty, signal the thread */
00331          ast_cond_signal(&change_pending);
00332       AST_LIST_UNLOCK(&state_changes);
00333    }
00334 
00335    return 1;
00336 }

int ast_device_state ( const char *  device  ) 

Check device state through channel specific function or generic function.

Asks a channel for device state.

Channel driver that provides device state

Another provider of device state

Definition at line 134 of file devicestate.c.

References AST_DEVICE_INVALID, AST_DEVICE_NOT_INUSE, AST_DEVICE_UNKNOWN, ast_get_channel_tech(), ast_log(), ast_parse_device_state(), ast_strdupa, ast_channel_tech::devicestate, getproviderstate(), LOG_DEBUG, option_debug, and strsep().

Referenced by ast_extension_state2(), chanavail_exec(), create_queue_member(), devstate_read(), do_state_change(), reload_queues(), and transmit_state_notify().

00135 {
00136    char *buf;
00137    char *number;
00138    const struct ast_channel_tech *chan_tech;
00139    int res = 0;
00140    /*! \brief Channel driver that provides device state */
00141    char *tech;
00142    /*! \brief Another provider of device state */
00143    char *provider = NULL;
00144    
00145    buf = ast_strdupa(device);
00146    tech = strsep(&buf, "/");
00147    number = buf;
00148    if (!number) {
00149       provider = strsep(&tech, ":");
00150       if (!provider)
00151          return AST_DEVICE_INVALID;
00152       /* We have a provider */
00153       number = tech;
00154       tech = NULL;
00155    }
00156 
00157    if (provider)  {
00158       if(option_debug > 2)
00159          ast_log(LOG_DEBUG, "Checking if I can find provider for \"%s\" - number: %s\n", provider, number);
00160       return getproviderstate(provider, number);
00161    }
00162    if (option_debug > 3)
00163       ast_log(LOG_DEBUG, "No provider found, checking channel drivers for %s - %s\n", tech, number);
00164 
00165    chan_tech = ast_get_channel_tech(tech);
00166    if (!chan_tech)
00167       return AST_DEVICE_INVALID;
00168 
00169    if (!chan_tech->devicestate)  /* Does the channel driver support device state notification? */
00170       return ast_parse_device_state(device); /* No, try the generic function */
00171    else {
00172       res = chan_tech->devicestate(number);  /* Ask the channel driver for device state */
00173       if (res == AST_DEVICE_UNKNOWN) {
00174          res = ast_parse_device_state(device);
00175          /* at this point we know the device exists, but the channel driver
00176             could not give us a state; if there is no channel state available,
00177             it must be 'not in use'
00178          */
00179          if (res == AST_DEVICE_UNKNOWN)
00180             res = AST_DEVICE_NOT_INUSE;
00181          return res;
00182       } else
00183          return res;
00184    }
00185 }

int ast_device_state_changed ( const char *  fmt,
  ... 
)

int ast_device_state_changed_literal ( const char *  device,
const char *  cid_num,
const char *  cid_name 
)

Tells Asterisk the State for Device is changed.

Parameters:
device devicename like a dialstring Asterisk polls the new extensionstates and calls the registered callbacks for the changed extensions Returns 0 on success, -1 on failure

Definition at line 338 of file devicestate.c.

References __ast_device_state_changed_literal(), and ast_strdupa.

Referenced by action_devstate(), ast_channel_free(), ast_setstate_and_cid(), devstate_cli(), and devstate_exec().

00339 {
00340    char *buf;
00341    char *buf2 = NULL;
00342    char *buf3 = NULL;
00343    buf = ast_strdupa(dev);
00344    if (cid_num)
00345        buf2 = ast_strdupa(cid_num);
00346    if (cid_name)
00347        buf3 = ast_strdupa(cid_name);
00348    return __ast_device_state_changed_literal(buf, buf2, buf3);
00349 }

int ast_device_state_engine_init ( void   ) 

Initialize the device state engine in separate thread.

Definition at line 389 of file devicestate.c.

References ast_cond_init(), ast_log(), ast_pthread_create_background, do_devstate_changes(), and LOG_ERROR.

Referenced by main().

00390 {
00391    ast_cond_init(&change_pending, NULL);
00392    if (ast_pthread_create_background(&change_thread, NULL, do_devstate_changes, NULL) < 0) {
00393       ast_log(LOG_ERROR, "Unable to start device state change thread.\n");
00394       return -1;
00395    }
00396 
00397    return 0;
00398 }

int ast_devstate_add ( ast_devstate_cb_type  callback,
void *  data 
)

Add device state watcher.

Registers a device state change callback.

Definition at line 245 of file devicestate.c.

References ast_calloc, AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_UNLOCK, devstate_cb::callback, and devstate_cb::data.

Referenced by load_module().

00246 {
00247    struct devstate_cb *devcb;
00248 
00249    if (!callback || !(devcb = ast_calloc(1, sizeof(*devcb))))
00250       return -1;
00251 
00252    devcb->data = data;
00253    devcb->callback = callback;
00254 
00255    AST_LIST_LOCK(&devstate_cbs);
00256    AST_LIST_INSERT_HEAD(&devstate_cbs, devcb, list);
00257    AST_LIST_UNLOCK(&devstate_cbs);
00258 
00259    return 0;
00260 }

void ast_devstate_del ( ast_devstate_cb_type  callback,
void *  data 
)

Remove device state watcher.

Unregisters a device state change callback.

Definition at line 263 of file devicestate.c.

References AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, devstate_cb::callback, devstate_cb::data, and free.

Referenced by unload_module().

00264 {
00265    struct devstate_cb *devcb;
00266 
00267    AST_LIST_LOCK(&devstate_cbs);
00268    AST_LIST_TRAVERSE_SAFE_BEGIN(&devstate_cbs, devcb, list) {
00269       if ((devcb->callback == callback) && (devcb->data == data)) {
00270          AST_LIST_REMOVE_CURRENT(&devstate_cbs, list);
00271          free(devcb);
00272          break;
00273       }
00274    }
00275    AST_LIST_TRAVERSE_SAFE_END;
00276    AST_LIST_UNLOCK(&devstate_cbs);
00277 }

int ast_devstate_prov_add ( const char *  label,
ast_devstate_prov_cb_type  callback 
)

Add device state provider.

Parameters:
label to use in hint, like label:object
callback Callback
Return values:
-1 failure
0 success

Definition at line 188 of file devicestate.c.

References ast_calloc, AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_UNLOCK, devstate_prov::callback, and devstate_prov::label.

Referenced by load_module().

00189 {
00190    struct devstate_prov *devprov;
00191 
00192    if (!callback || !(devprov = ast_calloc(1, sizeof(*devprov))))
00193       return -1;
00194 
00195    devprov->callback = callback;
00196    ast_copy_string(devprov->label, label, sizeof(devprov->label));
00197 
00198    AST_LIST_LOCK(&devstate_provs);
00199    AST_LIST_INSERT_HEAD(&devstate_provs, devprov, list);
00200    AST_LIST_UNLOCK(&devstate_provs);
00201 
00202    return 0;
00203 }

void ast_devstate_prov_del ( const char *  label  ) 

Remove device state provider.

Parameters:
label to use in hint, like label:object
Returns:
nothing

Definition at line 206 of file devicestate.c.

References AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, free, and devstate_prov::label.

Referenced by unload_module().

00207 {
00208    struct devstate_prov *devcb;
00209 
00210    AST_LIST_LOCK(&devstate_provs);
00211    AST_LIST_TRAVERSE_SAFE_BEGIN(&devstate_provs, devcb, list) {
00212       if (!strcasecmp(devcb->label, label)) {
00213          AST_LIST_REMOVE_CURRENT(&devstate_provs, list);
00214          free(devcb);
00215          break;
00216       }
00217    }
00218    AST_LIST_TRAVERSE_SAFE_END;
00219    AST_LIST_UNLOCK(&devstate_provs);
00220 }

static AST_LIST_HEAD_STATIC ( state_changes  ,
state_change   
) [static]

The state change queue. State changes are queued for processing by a separate thread.

static AST_LIST_HEAD_STATIC ( devstate_cbs  ,
devstate_cb   
) [static]

A device state watcher list.

static AST_LIST_HEAD_STATIC ( devstate_provs  ,
devstate_prov   
) [static]

A list of providers.

int ast_parse_device_state ( const char *  device  ) 

Find out if device is active in a call or not.

Search the Channels by Name.

Note:
find channels with the device's name in it This function is only used for channels that does not implement devicestate natively

Definition at line 110 of file devicestate.c.

References ast_channel::_state, AST_CHANNEL_NAME, ast_channel_unlock, AST_DEVICE_INUSE, AST_DEVICE_RINGING, AST_DEVICE_UNKNOWN, ast_get_channel_by_name_prefix_locked(), AST_STATE_RINGING, and match().

Referenced by ast_device_state().

00111 {
00112    struct ast_channel *chan;
00113    char match[AST_CHANNEL_NAME];
00114    int res;
00115 
00116    ast_copy_string(match, device, sizeof(match)-1);
00117    strcat(match, "-");
00118    chan = ast_get_channel_by_name_prefix_locked(match, strlen(match));
00119 
00120    if (!chan)
00121       return AST_DEVICE_UNKNOWN;
00122 
00123    if (chan->_state == AST_STATE_RINGING)
00124       res = AST_DEVICE_RINGING;
00125    else
00126       res = AST_DEVICE_INUSE;
00127    
00128    ast_channel_unlock(chan);
00129 
00130    return res;
00131 }

const char* devstate2str ( int  devstate  ) 

Find devicestate as text message for output.

Convert device state to text string for output.

Definition at line 100 of file devicestate.c.

Referenced by __queues_show(), do_state_change(), and handle_statechange().

00101 {
00102    return devstatestring[devstate];
00103 }

static void* do_devstate_changes ( void *  data  )  [static]

Go through the dev state change queue and update changes in the dev state thread.

Definition at line 364 of file devicestate.c.

References ast_cond_wait(), AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, do_state_change(), and free.

Referenced by ast_device_state_engine_init().

00365 {
00366    struct state_change *cur;
00367 
00368    AST_LIST_LOCK(&state_changes);
00369    for(;;) {
00370       /* the list lock will _always_ be held at this point in the loop */
00371       cur = AST_LIST_REMOVE_HEAD(&state_changes, list);
00372       if (cur) {
00373          /* we got an entry, so unlock the list while we process it */
00374          AST_LIST_UNLOCK(&state_changes);
00375          do_state_change(cur->device, cur->cid_num, cur->cid_name);
00376          free(cur);
00377          AST_LIST_LOCK(&state_changes);
00378       } else {
00379          /* there was no entry, so atomically unlock the list and wait for
00380             the condition to be signalled (returns with the lock held) */
00381          ast_cond_wait(&change_pending, &state_changes.lock);
00382       }
00383    }
00384 
00385    return NULL;
00386 }

static void do_state_change ( const char *  device,
char *  cid_num,
char *  cid_name 
) [static]

Notify callback watchers of change, and notify PBX core for hint updates Normally executed within a separate thread.

Definition at line 282 of file devicestate.c.

References ast_device_state(), ast_hint_state_changed(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), devstate_cb::callback, devstate_cb::data, devstate2str(), LOG_DEBUG, and option_debug.

Referenced by __ast_device_state_changed_literal(), and do_devstate_changes().

00283 {
00284    int state;
00285    struct devstate_cb *devcb;
00286 
00287    state = ast_device_state(device);
00288    if (option_debug > 2)
00289       ast_log(LOG_DEBUG, "Changing state for %s - state %d (%s)\n", device, state, devstate2str(state));
00290 
00291    AST_LIST_LOCK(&devstate_cbs);
00292    AST_LIST_TRAVERSE(&devstate_cbs, devcb, list)
00293       devcb->callback(device, state, devcb->data, cid_num, cid_name);
00294    AST_LIST_UNLOCK(&devstate_cbs);
00295 
00296    ast_hint_state_changed(device, cid_num, cid_name);
00297 }

static int getproviderstate ( const char *  provider,
const char *  address 
) [static]

Get provider device state.

Definition at line 223 of file devicestate.c.

References AST_DEVICE_INVALID, AST_LIST_LOCK, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, ast_log(), devstate_prov::callback, devstate_prov::label, LOG_DEBUG, and option_debug.

Referenced by ast_device_state().

00224 {
00225    struct devstate_prov *devprov;
00226    int res = AST_DEVICE_INVALID;
00227 
00228 
00229    AST_LIST_LOCK(&devstate_provs);
00230    AST_LIST_TRAVERSE_SAFE_BEGIN(&devstate_provs, devprov, list) {
00231       if(option_debug > 4)
00232          ast_log(LOG_DEBUG, "Checking provider %s with %s\n", devprov->label, provider);
00233 
00234       if (!strcasecmp(devprov->label, provider)) {
00235          res = devprov->callback(address);
00236          break;
00237       }
00238    }
00239    AST_LIST_TRAVERSE_SAFE_END;
00240    AST_LIST_UNLOCK(&devstate_provs);
00241    return res;
00242 }


Variable Documentation

Flag for the queue.

Definition at line 94 of file devicestate.c.

pthread_t change_thread = AST_PTHREADT_NULL [static]

The device state change notification thread.

Definition at line 91 of file devicestate.c.

const char* devstatestring[] [static]

Device state strings for printing.

Definition at line 47 of file devicestate.c.


Generated on Fri Sep 25 19:28:34 2009 for Asterisk - the Open Source PBX by  doxygen 1.5.5