Fri Jul 24 00:41:40 2009

Asterisk developer's documentation


devicestate.c File Reference

Device state management. More...

#include "asterisk.h"
#include "asterisk/_private.h"
#include "asterisk/channel.h"
#include "asterisk/utils.h"
#include "asterisk/lock.h"
#include "asterisk/linkedlists.h"
#include "asterisk/devicestate.h"
#include "asterisk/pbx.h"
#include "asterisk/app.h"
#include "asterisk/event.h"

Go to the source code of this file.

Data Structures

struct  chan2dev
 Mapping for channel states to device states. More...
struct  change_collection
struct  devstate_change
struct  devstate_prov
 A device state provider (not a channel). More...
struct  devstate_provs
 A list of providers. More...
struct  state_change
struct  state_changes
 The state change queue. State changes are queued for processing by a separate thread. More...

Defines

#define MAX_SERVERS   64

Functions

static enum ast_device_state _ast_device_state (const char *device, int check_cache)
 Check device state through channel specific function or generic function.
enum ast_device_state ast_device_state (const char *device)
 Asks a channel for device state.
int ast_device_state_changed (const char *fmt,...)
 Tells Asterisk the State for Device is changed. (Accept change notification, add it to change queue.).
int ast_device_state_changed_literal (const char *dev)
 Tells Asterisk the State for Device is changed.
int ast_device_state_engine_init (void)
 Initialize the device state engine in separate thread.
void ast_devstate_aggregate_add (struct ast_devstate_aggregate *agg, enum ast_device_state state)
 Add a device state to the aggregate device state.
void ast_devstate_aggregate_init (struct ast_devstate_aggregate *agg)
 Initialize aggregate device state.
enum ast_device_state ast_devstate_aggregate_result (struct ast_devstate_aggregate *agg)
 Get the aggregate device state result.
int ast_devstate_changed (enum ast_device_state state, const char *fmt,...)
 Tells Asterisk the State for Device is changed.
int ast_devstate_changed_literal (enum ast_device_state state, const char *device)
 Tells Asterisk the State for Device is changed.
int ast_devstate_prov_add (const char *label, ast_devstate_prov_cb_type callback)
 Add device state provider.
int ast_devstate_prov_del (const char *label)
 Remove device state provider.
const char * ast_devstate_str (enum ast_device_state state)
 Convert device state to text string that is easier to parse.
enum ast_device_state ast_devstate_val (const char *val)
 Convert device state from text to integer value.
int ast_enable_distributed_devstate (void)
 Enable distributed device state processing.
enum ast_device_state ast_parse_device_state (const char *device)
 Search the Channels by Name.
enum ast_device_state ast_state_chan2dev (enum ast_channel_state chanstate)
 Convert channel state to devicestate.
static void destroy_devstate_change (struct devstate_change *sc)
const char * devstate2str (enum ast_device_state devstate)
 Convert device state to text string for output.
static void devstate_cache_cb (const struct ast_event *event, void *data)
static enum ast_device_state devstate_cached (const char *device)
static void devstate_change_collector_cb (const struct ast_event *event, void *data)
static void devstate_event (const char *device, enum ast_device_state state)
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)
static int getproviderstate (const char *provider, const char *address)
 Get provider device state.
static void handle_devstate_change (struct devstate_change *sc)
static void process_collection (const char *device, struct change_collection *collection)
static void * run_devstate_collector (void *data)

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.
struct {
   ast_cond_t   cond
   struct {
      devstate_change *   first
      devstate_change *   last
   }   devstate_change_q
   unsigned int   enabled:1
   ast_event_sub *   event_sub
   ast_mutex_t   lock
   pthread_t   thread
devstate_collector
static const char * devstatestring []
 Device state strings for printing.


Detailed Description

Device state management.

Author:
Mark Spencer <markster@digium.com>

Russell Bryant <russell@digium.com>

Definition in file devicestate.c.


Define Documentation

#define MAX_SERVERS   64

Definition at line 589 of file devicestate.c.

Referenced by devstate_cache_cb().


Function Documentation

static enum ast_device_state _ast_device_state ( const char *  device,
int  check_cache 
) [static]

Check device state through channel specific function or generic function.

Channel driver that provides device state

Another provider of device state

Definition at line 332 of file devicestate.c.

References ast_debug, AST_DEVICE_INVALID, AST_DEVICE_NOT_INUSE, ast_device_state(), AST_DEVICE_UNKNOWN, ast_get_channel_tech(), ast_parse_device_state(), ast_strdupa, buf, ast_channel_tech::devicestate, devstate_cached(), getproviderstate(), and strsep().

Referenced by ast_device_state(), and do_state_change().

00333 {
00334    char *buf;
00335    char *number;
00336    const struct ast_channel_tech *chan_tech;
00337    enum ast_device_state res;
00338    /*! \brief Channel driver that provides device state */
00339    char *tech;
00340    /*! \brief Another provider of device state */
00341    char *provider = NULL;
00342 
00343    /* If the last known state is cached, just return that */
00344    if (check_cache) {
00345       res = devstate_cached(device);
00346       if (res != AST_DEVICE_UNKNOWN) {
00347          return res;
00348       }
00349    }
00350 
00351    buf = ast_strdupa(device);
00352    tech = strsep(&buf, "/");
00353    if (!(number = buf)) {
00354       if (!(provider = strsep(&tech, ":")))
00355          return AST_DEVICE_INVALID;
00356       /* We have a provider */
00357       number = tech;
00358       tech = NULL;
00359    }
00360 
00361    if (provider)  {
00362       ast_debug(3, "Checking if I can find provider for \"%s\" - number: %s\n", provider, number);
00363       return getproviderstate(provider, number);
00364    }
00365 
00366    ast_debug(4, "No provider found, checking channel drivers for %s - %s\n", tech, number);
00367 
00368    if (!(chan_tech = ast_get_channel_tech(tech)))
00369       return AST_DEVICE_INVALID;
00370 
00371    if (!(chan_tech->devicestate)) /* Does the channel driver support device state notification? */
00372       return ast_parse_device_state(device); /* No, try the generic function */
00373 
00374    res = chan_tech->devicestate(number);
00375 
00376    if (res != AST_DEVICE_UNKNOWN)
00377       return res;
00378 
00379    res = ast_parse_device_state(device);
00380 
00381    if (res == AST_DEVICE_UNKNOWN)
00382       return AST_DEVICE_NOT_INUSE;
00383 
00384    return res;
00385 }

enum ast_device_state ast_device_state ( const char *  device  ) 

Asks a channel for device state.

Parameters:
device like a dial string
Asks a channel for device state, data is normally a number from a dial string used by the low level module Tries the channel device state callback if not supported search in the active channels list for the device.

Return values:
an AST_DEVICE_??? state
-1 on failure

Definition at line 387 of file devicestate.c.

References _ast_device_state().

Referenced by _ast_device_state(), ast_extension_state2(), ast_parse_device_state(), chanavail_exec(), create_queue_member(), device_state_cb(), devstate_cached(), devstate_read(), devstate_write(), do_state_change(), handle_cli_devstate_change(), page_exec(), process_collection(), ring_entry(), skinny_extensionstate_cb(), sla_state(), and transmit_state_notify().

00388 {
00389    /* This function is called from elsewhere in the code to find out the
00390     * current state of a device.  Check the cache, first. */
00391 
00392    return _ast_device_state(device, 1);
00393 }

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

Tells Asterisk the State for Device is changed. (Accept change notification, add it to change queue.).

Parameters:
fmt device name like a dial string with format parameters
Asterisk polls the new extension states and calls the registered callbacks for the changed extensions

Return values:
0 on success
-1 on failure
Note:
This is deprecated in favor of ast_devstate_changed()
Version:
1.6.1 deprecated

Definition at line 547 of file devicestate.c.

References AST_DEVICE_UNKNOWN, ast_devstate_changed_literal(), AST_MAX_EXTENSION, and buf.

00548 {
00549    char buf[AST_MAX_EXTENSION];
00550    va_list ap;
00551 
00552    va_start(ap, fmt);
00553    vsnprintf(buf, sizeof(buf), fmt, ap);
00554    va_end(ap);
00555 
00556    return ast_devstate_changed_literal(AST_DEVICE_UNKNOWN, buf);
00557 }

int ast_device_state_changed_literal ( const char *  device  ) 

Tells Asterisk the State for Device is changed.

Parameters:
device device name like a dial string
Asterisk polls the new extension states and calls the registered callbacks for the changed extensions

Return values:
0 on success
-1 on failure
Note:
This is deprecated in favor of ast_devstate_changed_literal()
Version:
1.6.1 deprecated

Definition at line 530 of file devicestate.c.

References AST_DEVICE_UNKNOWN, and ast_devstate_changed_literal().

00531 {
00532    return ast_devstate_changed_literal(AST_DEVICE_UNKNOWN, dev);
00533 }

int ast_device_state_engine_init ( void   ) 

Initialize the device state engine in separate thread.

Provided by devicestate.c

Definition at line 749 of file devicestate.c.

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

Referenced by main().

00750 {
00751    ast_cond_init(&change_pending, NULL);
00752    if (ast_pthread_create_background(&change_thread, NULL, do_devstate_changes, NULL) < 0) {
00753       ast_log(LOG_ERROR, "Unable to start device state change thread.\n");
00754       return -1;
00755    }
00756 
00757    return 0;
00758 }

void ast_devstate_aggregate_add ( struct ast_devstate_aggregate agg,
enum ast_device_state  state 
)

Add a device state to the aggregate device state.

Parameters:
[in] agg the state object
[in] state the state to add
Returns:
nothing
Since:
1.6.1

Definition at line 770 of file devicestate.c.

References ast_devstate_aggregate::all_busy, ast_devstate_aggregate::all_free, ast_devstate_aggregate::all_on_hold, ast_devstate_aggregate::all_unavail, AST_DEVICE_BUSY, AST_DEVICE_INUSE, AST_DEVICE_INVALID, AST_DEVICE_NOT_INUSE, AST_DEVICE_ONHOLD, AST_DEVICE_RINGING, AST_DEVICE_RINGINUSE, AST_DEVICE_UNAVAILABLE, AST_DEVICE_UNKNOWN, ast_devstate_aggregate::busy, ast_devstate_aggregate::in_use, and ast_devstate_aggregate::ring.

Referenced by ast_extension_state2(), and process_collection().

00771 {
00772    switch (state) {
00773    case AST_DEVICE_NOT_INUSE:
00774       agg->all_unavail = 0;
00775       agg->all_busy = 0;
00776       agg->all_on_hold = 0;
00777       break;
00778    case AST_DEVICE_INUSE:
00779       agg->in_use = 1;
00780       agg->all_busy = 0;
00781       agg->all_unavail = 0;
00782       agg->all_free = 0;
00783       agg->all_on_hold = 0;
00784       break;
00785    case AST_DEVICE_RINGING:
00786       agg->ring = 1;
00787       agg->all_busy = 0;
00788       agg->all_unavail = 0;
00789       agg->all_free = 0;
00790       agg->all_on_hold = 0;
00791       break;
00792    case AST_DEVICE_RINGINUSE:
00793       agg->in_use = 1;
00794       agg->ring = 1;
00795       agg->all_busy = 0;
00796       agg->all_unavail = 0;
00797       agg->all_free = 0;
00798       agg->all_on_hold = 0;
00799       break;
00800    case AST_DEVICE_ONHOLD:
00801       agg->all_unavail = 0;
00802       agg->all_free = 0;
00803       break;
00804    case AST_DEVICE_BUSY:
00805       agg->all_unavail = 0;
00806       agg->all_free = 0;
00807       agg->all_on_hold = 0;
00808       agg->busy = 1;
00809       break;
00810    case AST_DEVICE_UNAVAILABLE:
00811    case AST_DEVICE_INVALID:
00812       agg->all_busy = 0;
00813       agg->all_free = 0;
00814       agg->all_on_hold = 0;
00815       break;
00816    case AST_DEVICE_UNKNOWN:
00817       break;
00818    }
00819 }

void ast_devstate_aggregate_init ( struct ast_devstate_aggregate agg  ) 

Initialize aggregate device state.

Parameters:
[in] agg the state object
Returns:
nothing
Since:
1.6.1

Definition at line 760 of file devicestate.c.

Referenced by ast_extension_state2(), and process_collection().

00761 {
00762    memset(agg, 0, sizeof(*agg));
00763 
00764    agg->all_unavail = 1;
00765    agg->all_busy = 1;
00766    agg->all_free = 1;
00767    agg->all_on_hold = 1;
00768 }

enum ast_device_state ast_devstate_aggregate_result ( struct ast_devstate_aggregate agg  ) 

Get the aggregate device state result.

Parameters:
[in] agg the state object
Returns:
the aggregate device state after adding some number of device states.
Since:
1.6.1

Definition at line 821 of file devicestate.c.

References ast_devstate_aggregate::all_busy, ast_devstate_aggregate::all_free, ast_devstate_aggregate::all_on_hold, ast_devstate_aggregate::all_unavail, AST_DEVICE_BUSY, AST_DEVICE_INUSE, AST_DEVICE_NOT_INUSE, AST_DEVICE_ONHOLD, AST_DEVICE_RINGING, AST_DEVICE_RINGINUSE, AST_DEVICE_UNAVAILABLE, ast_devstate_aggregate::busy, ast_devstate_aggregate::in_use, and ast_devstate_aggregate::ring.

Referenced by ast_extension_state2(), and process_collection().

00822 {
00823    if (agg->all_free)
00824       return AST_DEVICE_NOT_INUSE;
00825    
00826    if (agg->all_on_hold)
00827       return AST_DEVICE_ONHOLD;
00828    
00829    if (agg->all_busy)
00830       return AST_DEVICE_BUSY;
00831 
00832    if (agg->all_unavail)
00833       return AST_DEVICE_UNAVAILABLE;
00834    
00835    if (agg->ring)
00836       return agg->in_use ? AST_DEVICE_RINGINUSE : AST_DEVICE_RINGING;
00837 
00838    if (agg->in_use)
00839       return AST_DEVICE_INUSE;
00840 
00841    if (agg->busy)
00842       return AST_DEVICE_BUSY;
00843    
00844    return AST_DEVICE_NOT_INUSE;
00845 }

int ast_devstate_changed ( enum ast_device_state  state,
const char *  fmt,
  ... 
)

Tells Asterisk the State for Device is changed.

Parameters:
state the new state of the device
fmt device name like a dial string with format parameters
The new state of the device will be sent off to any subscribers of device states. It will also be stored in the internal event cache.

Return values:
0 on success
-1 on failure

Definition at line 535 of file devicestate.c.

References ast_devstate_changed_literal(), AST_MAX_EXTENSION, and buf.

Referenced by __expire_registry(), __iax2_poke_noanswer(), agent_call(), agent_hangup(), agent_logoff_maintenance(), agent_read(), conf_run(), devstate_write(), expire_register(), handle_cli_devstate_change(), handle_offhook_message(), handle_onhook_message(), handle_response_peerpoke(), handle_soft_key_event_message(), handle_stimulus_message(), load_module(), login_exec(), notify_metermaids(), reg_source_db(), register_verify(), reload_agents(), sip_peer_hold(), sip_poke_noanswer(), skinny_register(), skinny_unregister(), sla_change_trunk_state(), sla_handle_hold_event(), sla_station_exec(), socket_process(), update_call_counter(), and update_registry().

00536 {
00537    char buf[AST_MAX_EXTENSION];
00538    va_list ap;
00539 
00540    va_start(ap, fmt);
00541    vsnprintf(buf, sizeof(buf), fmt, ap);
00542    va_end(ap);
00543 
00544    return ast_devstate_changed_literal(state, buf);
00545 }

int ast_devstate_changed_literal ( enum ast_device_state  state,
const char *  device 
)

Tells Asterisk the State for Device is changed.

Parameters:
state the new state of the device
device device name like a dial string with format parameters
The new state of the device will be sent off to any subscribers of device states. It will also be stored in the internal event cache.

Return values:
0 on success
-1 on failure

Definition at line 492 of file devicestate.c.

References ast_calloc, ast_cond_signal(), AST_DEVICE_UNKNOWN, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_UNLOCK, change_thread, devstate_event(), do_state_change(), and devstate_prov::list.

Referenced by ast_channel_free(), ast_device_state_changed(), ast_device_state_changed_literal(), ast_devstate_changed(), ast_setstate(), and dahdi_new().

00493 {
00494    struct state_change *change;
00495 
00496    /* 
00497     * If we know the state change (how nice of the caller of this function!)
00498     * then we can just generate a device state event. 
00499     *
00500     * Otherwise, we do the following:
00501     *   - Queue an event up to another thread that the state has changed
00502     *   - In the processing thread, it calls the callback provided by the
00503     *     device state provider (which may or may not be a channel driver)
00504     *     to determine the state.
00505     *   - If the device state provider does not know the state, or this is
00506     *     for a channel and the channel driver does not implement a device
00507     *     state callback, then we will look through the channel list to
00508     *     see if we can determine a state based on active calls.
00509     *   - Once a state has been determined, a device state event is generated.
00510     */
00511 
00512    if (state != AST_DEVICE_UNKNOWN) {
00513       devstate_event(device, state);
00514    } else if (change_thread == AST_PTHREADT_NULL || !(change = ast_calloc(1, sizeof(*change) + strlen(device)))) {
00515       /* we could not allocate a change struct, or */
00516       /* there is no background thread, so process the change now */
00517       do_state_change(device);
00518    } else {
00519       /* queue the change */
00520       strcpy(change->device, device);
00521       AST_LIST_LOCK(&state_changes);
00522       AST_LIST_INSERT_TAIL(&state_changes, change, list);
00523       ast_cond_signal(&change_pending);
00524       AST_LIST_UNLOCK(&state_changes);
00525    }
00526 
00527    return 1;
00528 }

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:
0 success
-1 failure

Definition at line 396 of file devicestate.c.

References ast_calloc, ast_copy_string(), AST_RWLIST_INSERT_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, and devstate_prov::list.

Referenced by ast_features_init(), and load_module().

00397 {
00398    struct devstate_prov *devprov;
00399 
00400    if (!callback || !(devprov = ast_calloc(1, sizeof(*devprov))))
00401       return -1;
00402 
00403    devprov->callback = callback;
00404    ast_copy_string(devprov->label, label, sizeof(devprov->label));
00405 
00406    AST_RWLIST_WRLOCK(&devstate_provs);
00407    AST_RWLIST_INSERT_HEAD(&devstate_provs, devprov, list);
00408    AST_RWLIST_UNLOCK(&devstate_provs);
00409 
00410    return 0;
00411 }

int ast_devstate_prov_del ( const char *  label  ) 

Remove device state provider.

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

Definition at line 414 of file devicestate.c.

References ast_free, AST_RWLIST_REMOVE_CURRENT, AST_RWLIST_TRAVERSE_SAFE_BEGIN, AST_RWLIST_TRAVERSE_SAFE_END, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, devstate_prov::label, and devstate_prov::list.

Referenced by unload_module().

00415 {
00416    struct devstate_prov *devcb;
00417    int res = -1;
00418 
00419    AST_RWLIST_WRLOCK(&devstate_provs);
00420    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&devstate_provs, devcb, list) {
00421       if (!strcasecmp(devcb->label, label)) {
00422          AST_RWLIST_REMOVE_CURRENT(list);
00423          ast_free(devcb);
00424          res = 0;
00425          break;
00426       }
00427    }
00428    AST_RWLIST_TRAVERSE_SAFE_END;
00429    AST_RWLIST_UNLOCK(&devstate_provs);
00430 
00431    return res;
00432 }

const char* ast_devstate_str ( enum ast_device_state  devstate  ) 

Convert device state to text string that is easier to parse.

Parameters:
devstate Current device state

Definition at line 226 of file devicestate.c.

References AST_DEVICE_BUSY, AST_DEVICE_INUSE, AST_DEVICE_INVALID, AST_DEVICE_NOT_INUSE, AST_DEVICE_ONHOLD, AST_DEVICE_RINGING, AST_DEVICE_RINGINUSE, AST_DEVICE_UNAVAILABLE, and AST_DEVICE_UNKNOWN.

Referenced by devstate_read().

00227 {
00228    const char *res = "UNKNOWN";
00229 
00230    switch (state) {
00231    case AST_DEVICE_UNKNOWN:
00232       break;
00233    case AST_DEVICE_NOT_INUSE:
00234       res = "NOT_INUSE";
00235       break;
00236    case AST_DEVICE_INUSE:
00237       res = "INUSE";
00238       break;
00239    case AST_DEVICE_BUSY:
00240       res = "BUSY";
00241       break;
00242    case AST_DEVICE_INVALID:
00243       res = "INVALID";
00244       break;
00245    case AST_DEVICE_UNAVAILABLE:
00246       res = "UNAVAILABLE";
00247       break;
00248    case AST_DEVICE_RINGING:
00249       res = "RINGING";
00250       break;
00251    case AST_DEVICE_RINGINUSE:
00252       res = "RINGINUSE";
00253       break;
00254    case AST_DEVICE_ONHOLD:
00255       res = "ONHOLD";
00256       break;
00257    }
00258 
00259    return res;
00260 }

enum ast_device_state ast_devstate_val ( const char *  val  ) 

Convert device state from text to integer value.

Parameters:
val The text representing the device state. Valid values are anything that comes after AST_DEVICE_ in one of the defined values.
Returns:
The AST_DEVICE_ integer value

Definition at line 262 of file devicestate.c.

References AST_DEVICE_BUSY, AST_DEVICE_INUSE, AST_DEVICE_INVALID, AST_DEVICE_NOT_INUSE, AST_DEVICE_ONHOLD, AST_DEVICE_RINGING, AST_DEVICE_RINGINUSE, AST_DEVICE_UNAVAILABLE, and AST_DEVICE_UNKNOWN.

Referenced by custom_devstate_callback(), devstate_write(), handle_cli_devstate_change(), and load_module().

00263 {
00264    if (!strcasecmp(val, "NOT_INUSE"))
00265       return AST_DEVICE_NOT_INUSE;
00266    else if (!strcasecmp(val, "INUSE"))
00267       return AST_DEVICE_INUSE;
00268    else if (!strcasecmp(val, "BUSY"))
00269       return AST_DEVICE_BUSY;
00270    else if (!strcasecmp(val, "INVALID"))
00271       return AST_DEVICE_INVALID;
00272    else if (!strcasecmp(val, "UNAVAILABLE"))
00273       return AST_DEVICE_UNAVAILABLE;
00274    else if (!strcasecmp(val, "RINGING"))
00275       return AST_DEVICE_RINGING;
00276    else if (!strcasecmp(val, "RINGINUSE"))
00277       return AST_DEVICE_RINGINUSE;
00278    else if (!strcasecmp(val, "ONHOLD"))
00279       return AST_DEVICE_ONHOLD;
00280 
00281    return AST_DEVICE_UNKNOWN;
00282 }

int ast_enable_distributed_devstate ( void   ) 

Enable distributed device state processing.

By default, Asterisk assumes that device state change events will only be originating from one instance. If a module gets loaded and configured such that multiple instances of Asterisk will be sharing device state, this function should be called to enable distributed device state processing. It is off by default to save on unnecessary processing.

Return values:
0 success
-1 failure

Definition at line 847 of file devicestate.c.

References ast_cond_init(), AST_EVENT_DEVICE_STATE_CHANGE, AST_EVENT_IE_END, ast_event_subscribe(), ast_log(), ast_mutex_init(), ast_pthread_create_background, devstate_change_collector_cb(), devstate_collector, LOG_ERROR, and run_devstate_collector().

00848 {
00849    if (devstate_collector.enabled) {
00850       return 0;
00851    }
00852 
00853    devstate_collector.event_sub = ast_event_subscribe(AST_EVENT_DEVICE_STATE_CHANGE,
00854       devstate_change_collector_cb, NULL, AST_EVENT_IE_END);
00855 
00856    if (!devstate_collector.event_sub) {
00857       ast_log(LOG_ERROR, "Failed to create subscription for the device state change collector\n");
00858       return -1;
00859    }
00860 
00861    ast_mutex_init(&devstate_collector.lock);
00862    ast_cond_init(&devstate_collector.cond, NULL);
00863    if (ast_pthread_create_background(&devstate_collector.thread, NULL, run_devstate_collector, NULL) < 0) {
00864       ast_log(LOG_ERROR, "Unable to start device state collector thread.\n");
00865       return -1;
00866    }
00867 
00868    devstate_collector.enabled = 1;
00869 
00870    return 0;
00871 }

enum ast_device_state ast_parse_device_state ( const char *  device  ) 

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 289 of file devicestate.c.

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

Referenced by _ast_device_state(), and chanavail_exec().

00290 {
00291    struct ast_channel *chan;
00292    char match[AST_CHANNEL_NAME];
00293    enum ast_device_state res;
00294 
00295    ast_copy_string(match, device, sizeof(match)-1);
00296    strcat(match, "-");
00297    chan = ast_get_channel_by_name_prefix_locked(match, strlen(match));
00298 
00299    if (!chan)
00300       return AST_DEVICE_UNKNOWN;
00301 
00302    if (chan->_state == AST_STATE_RINGING)
00303       res = AST_DEVICE_RINGING;
00304    else
00305       res = AST_DEVICE_INUSE;
00306    
00307    ast_channel_unlock(chan);
00308 
00309    return res;
00310 }

enum ast_device_state ast_state_chan2dev ( enum ast_channel_state  chanstate  ) 

Convert channel state to devicestate.

Parameters:
chanstate Current channel state
Since:
1.6.1

Definition at line 214 of file devicestate.c.

References AST_DEVICE_UNKNOWN, and chan.

Referenced by dahdi_new().

00215 {
00216    int i;
00217    chanstate &= 0xFFFF;
00218    for (i = 0; chan2dev[i].chan != -100; i++) {
00219       if (chan2dev[i].chan == chanstate) {
00220          return chan2dev[i].dev;
00221       }
00222    }
00223    return AST_DEVICE_UNKNOWN;
00224 }

static void destroy_devstate_change ( struct devstate_change sc  )  [static]

Definition at line 584 of file devicestate.c.

References ast_free.

Referenced by run_devstate_collector().

00585 {
00586    ast_free(sc);
00587 }

const char* devstate2str ( enum ast_device_state  devstate  ) 

Convert device state to text string for output.

Parameters:
devstate Current device state

Definition at line 209 of file devicestate.c.

Referenced by __queues_show(), do_state_change(), handle_statechange(), notify_metermaids(), page_exec(), and process_collection().

00210 {
00211    return devstatestring[devstate];
00212 }

static void devstate_cache_cb ( const struct ast_event event,
void *  data 
) [static]

Definition at line 595 of file devicestate.c.

References ARRAY_LEN, ast_event_get_ie_raw(), ast_event_get_ie_uint(), AST_EVENT_IE_EID, AST_EVENT_IE_STATE, ast_log(), devstate_change::eid, ast_eid::eid, LOG_ERROR, MAX_SERVERS, change_collection::num_states, devstate_change::state, and change_collection::states.

Referenced by handle_devstate_change().

00596 {
00597    struct change_collection *collection = data;
00598    int i;
00599    const struct ast_eid *eid;
00600 
00601    if (collection->num_states == ARRAY_LEN(collection->states)) {
00602       ast_log(LOG_ERROR, "More per-server state values than we have room for (MAX_SERVERS is %d)\n",
00603          MAX_SERVERS);
00604       return;
00605    }
00606 
00607    if (!(eid = ast_event_get_ie_raw(event, AST_EVENT_IE_EID))) {
00608       ast_log(LOG_ERROR, "Device state change event with no EID\n");
00609       return;
00610    }
00611 
00612    i = collection->num_states;
00613 
00614    collection->states[i].state = ast_event_get_ie_uint(event, AST_EVENT_IE_STATE);
00615    collection->states[i].eid = *eid;
00616 
00617    collection->num_states++;
00618 }

static enum ast_device_state devstate_cached ( const char *  device  )  [static]

Definition at line 312 of file devicestate.c.

References ast_device_state(), AST_DEVICE_UNKNOWN, ast_event_destroy(), AST_EVENT_DEVICE_STATE, ast_event_get_cached(), ast_event_get_ie_uint(), AST_EVENT_IE_DEVICE, AST_EVENT_IE_END, AST_EVENT_IE_PLTYPE_STR, and AST_EVENT_IE_STATE.

Referenced by _ast_device_state().

00313 {
00314    enum ast_device_state res = AST_DEVICE_UNKNOWN;
00315    struct ast_event *event;
00316 
00317    event = ast_event_get_cached(AST_EVENT_DEVICE_STATE,
00318       AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, device,
00319       AST_EVENT_IE_END);
00320 
00321    if (!event)
00322       return res;
00323 
00324    res = ast_event_get_ie_uint(event, AST_EVENT_IE_STATE);
00325 
00326    ast_event_destroy(event);
00327 
00328    return res;
00329 }

static void devstate_change_collector_cb ( const struct ast_event event,
void *  data 
) [static]

Definition at line 719 of file devicestate.c.

References ast_calloc, ast_cond_signal(), ast_event_get_ie_raw(), ast_event_get_ie_str(), ast_event_get_ie_uint(), AST_EVENT_IE_DEVICE, AST_EVENT_IE_EID, AST_EVENT_IE_STATE, AST_LIST_INSERT_TAIL, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_strlen_zero(), devstate_collector, ast_eid::eid, and LOG_ERROR.

Referenced by ast_enable_distributed_devstate().

00720 {
00721    struct devstate_change *sc;
00722    const char *device;
00723    const struct ast_eid *eid;
00724    uint32_t state;
00725 
00726    device = ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE);
00727    eid = ast_event_get_ie_raw(event, AST_EVENT_IE_EID);
00728    state = ast_event_get_ie_uint(event, AST_EVENT_IE_STATE);
00729 
00730    if (ast_strlen_zero(device) || !eid) {
00731       ast_log(LOG_ERROR, "Invalid device state change event received\n");
00732       return;
00733    }
00734 
00735    if (!(sc = ast_calloc(1, sizeof(*sc) + strlen(device))))
00736       return;
00737 
00738    strcpy(sc->device, device);
00739    sc->eid = *eid;
00740    sc->state = state;
00741 
00742    ast_mutex_lock(&devstate_collector.lock);
00743    AST_LIST_INSERT_TAIL(&devstate_collector.devstate_change_q, sc, entry);
00744    ast_cond_signal(&devstate_collector.cond);
00745    ast_mutex_unlock(&devstate_collector.lock);
00746 }

static void devstate_event ( const char *  device,
enum ast_device_state  state 
) [static]

Definition at line 454 of file devicestate.c.

References ast_debug, AST_EVENT_DEVICE_STATE, AST_EVENT_DEVICE_STATE_CHANGE, AST_EVENT_IE_DEVICE, AST_EVENT_IE_END, AST_EVENT_IE_PLTYPE_STR, AST_EVENT_IE_PLTYPE_UINT, AST_EVENT_IE_STATE, ast_event_new(), ast_event_queue_and_cache(), and devstate_collector.

Referenced by ast_devstate_changed_literal(), and do_state_change().

00455 {
00456    struct ast_event *event;
00457    enum ast_event_type event_type;
00458 
00459    if (devstate_collector.enabled) {
00460       /* Distributed device state is enabled, so this state change is a change
00461        * for a single server, not the real state. */
00462       event_type = AST_EVENT_DEVICE_STATE_CHANGE;
00463    } else {
00464       event_type = AST_EVENT_DEVICE_STATE;
00465    }
00466 
00467    ast_debug(3, "device '%s' state '%d'\n", device, state);
00468 
00469    if (!(event = ast_event_new(event_type,
00470          AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, device,
00471          AST_EVENT_IE_STATE, AST_EVENT_IE_PLTYPE_UINT, state,
00472          AST_EVENT_IE_END))) {
00473       return;
00474    }
00475 
00476    ast_event_queue_and_cache(event);
00477 }

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 560 of file devicestate.c.

References ast_cond_wait(), ast_free, AST_LIST_EMPTY, AST_LIST_FIRST, AST_LIST_HEAD_INIT_NOLOCK, AST_LIST_LOCK, AST_LIST_NEXT, AST_LIST_UNLOCK, state_change::device, do_state_change(), devstate_prov::list, state_changes::lock, and devstate_prov::next.

Referenced by ast_device_state_engine_init().

00561 {
00562    struct state_change *next, *current;
00563 
00564    for (;;) {
00565       /* This basically pops off any state change entries, resets the list back to NULL, unlocks, and processes each state change */
00566       AST_LIST_LOCK(&state_changes);
00567       if (AST_LIST_EMPTY(&state_changes))
00568          ast_cond_wait(&change_pending, &state_changes.lock);
00569       next = AST_LIST_FIRST(&state_changes);
00570       AST_LIST_HEAD_INIT_NOLOCK(&state_changes);
00571       AST_LIST_UNLOCK(&state_changes);
00572 
00573       /* Process each state change */
00574       while ((current = next)) {
00575          next = AST_LIST_NEXT(current, list);
00576          do_state_change(current->device);
00577          ast_free(current);
00578       }
00579    }
00580 
00581    return NULL;
00582 }

static void do_state_change ( const char *  device  )  [static]

Called by the state change thread to find out what the state is, and then to queue up the state change event

Definition at line 481 of file devicestate.c.

References _ast_device_state(), ast_debug, ast_device_state(), devstate2str(), and devstate_event().

Referenced by ast_devstate_changed_literal(), and do_devstate_changes().

00482 {
00483    enum ast_device_state state;
00484 
00485    state = _ast_device_state(device, 0);
00486 
00487    ast_debug(3, "Changing state for %s - state %d (%s)\n", device, state, devstate2str(state));
00488 
00489    devstate_event(device, state);
00490 }

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

Get provider device state.

Definition at line 435 of file devicestate.c.

References ast_debug, AST_DEVICE_INVALID, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, devstate_prov::callback, devstate_prov::label, and devstate_prov::list.

Referenced by _ast_device_state().

00436 {
00437    struct devstate_prov *devprov;
00438    int res = AST_DEVICE_INVALID;
00439 
00440    AST_RWLIST_RDLOCK(&devstate_provs);
00441    AST_RWLIST_TRAVERSE(&devstate_provs, devprov, list) {
00442       ast_debug(5, "Checking provider %s with %s\n", devprov->label, provider);
00443 
00444       if (!strcasecmp(devprov->label, provider)) {
00445          res = devprov->callback(address);
00446          break;
00447       }
00448    }
00449    AST_RWLIST_UNLOCK(&devstate_provs);
00450 
00451    return res;
00452 }

static void handle_devstate_change ( struct devstate_change sc  )  [static]

Definition at line 673 of file devicestate.c.

References ast_debug, AST_EVENT_DEVICE_STATE_CHANGE, ast_event_dump_cache(), AST_EVENT_IE_DEVICE, ast_event_sub_append_ie_str(), ast_event_sub_destroy(), ast_event_subscribe_new(), ast_log(), devstate_change::device, devstate_cache_cb(), LOG_ERROR, change_collection::num_states, and process_collection().

Referenced by run_devstate_collector().

00674 {
00675    struct ast_event_sub *tmp_sub;
00676    struct change_collection collection = {
00677       .num_states = 0,
00678    };
00679 
00680    ast_debug(1, "Processing device state change for '%s'\n", sc->device);
00681 
00682    if (!(tmp_sub = ast_event_subscribe_new(AST_EVENT_DEVICE_STATE_CHANGE, devstate_cache_cb, &collection))) {
00683       ast_log(LOG_ERROR, "Failed to create subscription\n");
00684       return;
00685    }
00686 
00687    if (ast_event_sub_append_ie_str(tmp_sub, AST_EVENT_IE_DEVICE, sc->device)) {
00688       ast_log(LOG_ERROR, "Failed to append device IE\n");
00689       ast_event_sub_destroy(tmp_sub);
00690       return;
00691    }
00692 
00693    /* Populate the collection of device states from the cache */
00694    ast_event_dump_cache(tmp_sub);
00695 
00696    process_collection(sc->device, &collection);
00697 
00698    ast_event_sub_destroy(tmp_sub);
00699 }

static void process_collection ( const char *  device,
struct change_collection collection 
) [static]

Definition at line 620 of file devicestate.c.

References ast_debug, ast_device_state(), ast_devstate_aggregate_add(), ast_devstate_aggregate_init(), ast_devstate_aggregate_result(), ast_event_destroy(), AST_EVENT_DEVICE_STATE, ast_event_get_cached(), ast_event_get_ie_uint(), AST_EVENT_IE_DEVICE, AST_EVENT_IE_END, AST_EVENT_IE_PLTYPE_STR, AST_EVENT_IE_PLTYPE_UINT, AST_EVENT_IE_STATE, ast_event_new(), ast_event_queue_and_cache(), devstate2str(), change_collection::num_states, devstate_change::state, and change_collection::states.

Referenced by handle_devstate_change().

00621 {
00622    int i;
00623    struct ast_devstate_aggregate agg;
00624    enum ast_device_state state;
00625    struct ast_event *event;
00626 
00627    ast_devstate_aggregate_init(&agg);
00628 
00629    for (i = 0; i < collection->num_states; i++) {
00630       ast_debug(1, "Adding per-server state of '%s' for '%s'\n", 
00631          devstate2str(collection->states[i].state), device);
00632       ast_devstate_aggregate_add(&agg, collection->states[i].state);
00633    }
00634 
00635    state = ast_devstate_aggregate_result(&agg);
00636 
00637    ast_debug(1, "Aggregate devstate result is %d\n", state);
00638 
00639    event = ast_event_get_cached(AST_EVENT_DEVICE_STATE,
00640       AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, device,
00641       AST_EVENT_IE_END);
00642    
00643    if (event) {
00644       enum ast_device_state old_state;
00645 
00646       old_state = ast_event_get_ie_uint(event, AST_EVENT_IE_STATE);
00647       
00648       ast_event_destroy(event);
00649 
00650       if (state == old_state) {
00651          /* No change since last reported device state */
00652          ast_debug(1, "Aggregate state for device '%s' has not changed from '%s'\n",
00653             device, devstate2str(state));
00654          return;
00655       }
00656    }
00657 
00658    ast_debug(1, "Aggregate state for device '%s' has changed to '%s'\n",
00659       device, devstate2str(state));
00660 
00661    event = ast_event_new(AST_EVENT_DEVICE_STATE,
00662       AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, device,
00663       AST_EVENT_IE_STATE, AST_EVENT_IE_PLTYPE_UINT, state,
00664       AST_EVENT_IE_END);
00665 
00666    if (!event) {
00667       return;
00668    }
00669 
00670    ast_event_queue_and_cache(event);
00671 }

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

Definition at line 701 of file devicestate.c.

References ast_cond_wait(), AST_LIST_REMOVE_HEAD, ast_mutex_lock(), ast_mutex_unlock(), destroy_devstate_change(), devstate_collector, and handle_devstate_change().

Referenced by ast_enable_distributed_devstate().

00702 {
00703    for (;;) {
00704       struct devstate_change *sc;
00705 
00706       ast_mutex_lock(&devstate_collector.lock);
00707       while (!(sc = AST_LIST_REMOVE_HEAD(&devstate_collector.devstate_change_q, entry)))
00708          ast_cond_wait(&devstate_collector.cond, &devstate_collector.lock);
00709       ast_mutex_unlock(&devstate_collector.lock);
00710 
00711       handle_devstate_change(sc);
00712 
00713       destroy_devstate_change(sc);
00714    }
00715 
00716    return NULL;
00717 }


Variable Documentation

ast_cond_t change_pending [static]

Flag for the queue.

Definition at line 184 of file devicestate.c.

pthread_t change_thread = AST_PTHREADT_NULL [static]

The device state change notification thread.

Definition at line 181 of file devicestate.c.

Referenced by ast_device_state_engine_init(), and ast_devstate_changed_literal().

ast_cond_t cond

Definition at line 196 of file devicestate.c.

Referenced by _macro_exec(), gosubif_exec(), and smdi_message_wait().

struct { ... } devstate_change_q

struct { ... } devstate_collector

Referenced by ast_enable_distributed_devstate(), devstate_change_collector_cb(), devstate_event(), and run_devstate_collector().

const char* devstatestring[] [static]

Device state strings for printing.

Definition at line 131 of file devicestate.c.

unsigned int enabled

Definition at line 199 of file devicestate.c.

struct ast_event_sub* event_sub

Definition at line 195 of file devicestate.c.

Referenced by ast_event_dump_cache(), ast_event_report_subs(), and dump_cache_cb().

struct devstate_change* first

Definition at line 198 of file devicestate.c.

Referenced by ast_print_group(), h261_encap(), h263_encap(), h263p_encap(), h264_encap(), log_jack_status(), misdn_lib_init(), mpeg4_encap(), and schedule().

struct devstate_change* last

Definition at line 198 of file devicestate.c.

Referenced by __ao2_callback(), aji_handle_presence(), apply_outgoing(), ast_config_engine_deregister(), ast_db_freetree(), ast_db_gettree(), config_odbc(), config_pgsql(), do_monitor(), gtalk_free_candidates(), jingle_free_candidates(), load_password(), next_channel(), node_lookup(), scan_thread(), schedule(), and try_firmware().

ast_mutex_t lock

Definition at line 197 of file devicestate.c.

Referenced by dahdi_request(), dahdi_restart(), dahdi_set_swgain(), dahdi_show_channel(), dahdi_show_channels(), free_config(), load_config(), load_module(), load_rpt_vars(), rpt_master(), smdi_message_wait(), sqlite3_log(), and unload_module().

pthread_t thread

Definition at line 194 of file devicestate.c.

Referenced by __schedule_action(), __unload_module(), ast_bridge_call_thread_launch(), find_idle_thread(), handle_cli_iax2_show_threads(), handle_deferred_full_frames(), iax2_process_thread(), iax2_process_thread_cleanup(), insert_idle_thread(), launch_monitor_thread(), load_module(), socket_process(), socket_read(), start_network_thread(), and unload_module().


Generated on Fri Jul 24 00:41:40 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7