Mon Mar 19 11:30:46 2012

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.
const char * ast_devstate2str (enum ast_device_state devstate)
 Find devicestate as text message for output.
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 *const devstatestring [][2]
 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 560 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 304 of file devicestate.c.

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

Referenced by ast_device_state(), and do_state_change().

00305 {
00306    char *buf;
00307    char *number;
00308    const struct ast_channel_tech *chan_tech;
00309    enum ast_device_state res;
00310    /*! \brief Channel driver that provides device state */
00311    char *tech;
00312    /*! \brief Another provider of device state */
00313    char *provider = NULL;
00314 
00315    /* If the last known state is cached, just return that */
00316    if (check_cache) {
00317       res = devstate_cached(device);
00318       if (res != AST_DEVICE_UNKNOWN) {
00319          return res;
00320       }
00321    }
00322 
00323    buf = ast_strdupa(device);
00324    tech = strsep(&buf, "/");
00325    if (!(number = buf)) {
00326       provider = strsep(&tech, ":");
00327       if (!tech) {
00328          return AST_DEVICE_INVALID;
00329       }
00330       /* We have a provider */
00331       number = tech;
00332       tech = NULL;
00333    }
00334 
00335    if (provider)  {
00336       ast_debug(3, "Checking if I can find provider for \"%s\" - number: %s\n", provider, number);
00337       return getproviderstate(provider, number);
00338    }
00339 
00340    ast_debug(4, "No provider found, checking channel drivers for %s - %s\n", tech, number);
00341 
00342    if (!(chan_tech = ast_get_channel_tech(tech)))
00343       return AST_DEVICE_INVALID;
00344 
00345    if (!(chan_tech->devicestate)) /* Does the channel driver support device state notification? */
00346       return ast_parse_device_state(device); /* No, try the generic function */
00347 
00348    res = chan_tech->devicestate(number);
00349 
00350    if (res != AST_DEVICE_UNKNOWN)
00351       return res;
00352 
00353    res = ast_parse_device_state(device);
00354 
00355    return res;
00356 }

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

References _ast_device_state().

Referenced by _ast_device_state(), ast_extension_state3(), ast_parse_device_state(), cc_generic_agent_recall(), cc_generic_agent_status_request(), cc_generic_monitor_suspend(), cc_generic_monitor_unsuspend(), cc_status_response(), chanavail_exec(), create_new_generic_list(), dahdi_pri_update_span_devstate(), device_state_cb(), devstate_cached(), devstate_read(), devstate_write(), do_state_change(), generic_agent_devstate_cb(), generic_monitor_devstate_tp_cb(), get_queue_member_status(), handle_cli_devstate_change(), page_exec(), process_collection(), sip_cc_agent_status_request(), skinny_extensionstate_cb(), sla_state(), and state_notify_build_xml().

00359 {
00360    /* This function is called from elsewhere in the code to find out the
00361     * current state of a device.  Check the cache, first. */
00362 
00363    return _ast_device_state(device, 1);
00364 }

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

References AST_DEVICE_UNKNOWN, ast_devstate_changed_literal(), and AST_MAX_EXTENSION.

00519 {
00520    char buf[AST_MAX_EXTENSION];
00521    va_list ap;
00522 
00523    va_start(ap, fmt);
00524    vsnprintf(buf, sizeof(buf), fmt, ap);
00525    va_end(ap);
00526 
00527    return ast_devstate_changed_literal(AST_DEVICE_UNKNOWN, buf);
00528 }

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

References AST_DEVICE_UNKNOWN, and ast_devstate_changed_literal().

00502 {
00503    return ast_devstate_changed_literal(AST_DEVICE_UNKNOWN, dev);
00504 }

int ast_device_state_engine_init ( void   ) 

Initialize the device state engine in separate thread.

Provided by devicestate.c

Definition at line 721 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().

00722 {
00723    ast_cond_init(&change_pending, NULL);
00724    if (ast_pthread_create_background(&change_thread, NULL, do_devstate_changes, NULL) < 0) {
00725       ast_log(LOG_ERROR, "Unable to start device state change thread.\n");
00726       return -1;
00727    }
00728 
00729    return 0;
00730 }

const char* ast_devstate2str ( enum ast_device_state  devstate  ) 

Find devicestate as text message for output.

Definition at line 209 of file devicestate.c.

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

00210 {
00211    return devstatestring[devstate][0];
00212 }

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

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

Referenced by ast_extension_state3(), and process_collection().

00743 {
00744    switch (state) {
00745    case AST_DEVICE_NOT_INUSE:
00746       agg->all_unknown = 0;
00747       agg->all_unavail = 0;
00748       agg->all_busy = 0;
00749       break;
00750    case AST_DEVICE_INUSE:
00751       agg->in_use = 1;
00752       agg->all_unavail = 0;
00753       agg->all_free = 0;
00754       agg->all_unknown = 0;
00755       break;
00756    case AST_DEVICE_RINGING:
00757       agg->ring = 1;
00758       agg->all_unavail = 0;
00759       agg->all_free = 0;
00760       agg->all_unknown = 0;
00761       break;
00762    case AST_DEVICE_RINGINUSE:
00763       agg->in_use = 1;
00764       agg->ring = 1;
00765       agg->all_unavail = 0;
00766       agg->all_free = 0;
00767       agg->all_unknown = 0;
00768       break;
00769    case AST_DEVICE_ONHOLD:
00770       agg->all_unknown = 0;
00771       agg->all_unavail = 0;
00772       agg->all_free = 0;
00773       agg->on_hold = 1;
00774       break;
00775    case AST_DEVICE_BUSY:
00776       agg->all_unknown = 0;
00777       agg->all_unavail = 0;
00778       agg->all_free = 0;
00779       agg->busy = 1;
00780       agg->in_use = 1;
00781       break;
00782    case AST_DEVICE_UNAVAILABLE:
00783       agg->all_unknown = 0;
00784    case AST_DEVICE_INVALID:
00785       agg->all_busy = 0;
00786       agg->all_free = 0;
00787       break;
00788    case AST_DEVICE_UNKNOWN:
00789       agg->all_busy = 0;
00790       agg->all_free = 0;
00791       break;
00792    case AST_DEVICE_TOTAL: /* not a device state, included for completeness. */
00793       break;
00794    }
00795 }

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

Referenced by ast_extension_state3(), and process_collection().

00733 {
00734    memset(agg, 0, sizeof(*agg));
00735 
00736    agg->all_unknown = 1;
00737    agg->all_unavail = 1;
00738    agg->all_busy = 1;
00739    agg->all_free = 1;
00740 }

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

References ast_devstate_aggregate::all_busy, ast_devstate_aggregate::all_free, ast_devstate_aggregate::all_unavail, ast_devstate_aggregate::all_unknown, AST_DEVICE_BUSY, AST_DEVICE_INUSE, 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, ast_devstate_aggregate::on_hold, and ast_devstate_aggregate::ring.

Referenced by ast_extension_state3(), and process_collection().

00799 {
00800    if (agg->all_free)
00801       return AST_DEVICE_NOT_INUSE;
00802    if ((agg->in_use || agg->on_hold) && agg->ring)
00803       return AST_DEVICE_RINGINUSE;
00804    if (agg->ring)
00805       return AST_DEVICE_RINGING;
00806    if (agg->busy)
00807       return AST_DEVICE_BUSY;
00808    if (agg->in_use)
00809       return AST_DEVICE_INUSE;
00810    if (agg->on_hold)
00811       return AST_DEVICE_ONHOLD;
00812    if (agg->all_busy)
00813       return AST_DEVICE_BUSY;
00814    if (agg->all_unknown)
00815       return AST_DEVICE_UNKNOWN;
00816    if (agg->all_unavail)
00817       return AST_DEVICE_UNAVAILABLE;
00818 
00819    return AST_DEVICE_NOT_INUSE;
00820 }

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

References ast_devstate_changed_literal(), and AST_MAX_EXTENSION.

Referenced by __expire_registry(), __iax2_poke_noanswer(), agent_call(), agent_hangup(), agent_read(), calendar_devstate_change(), conf_run(), dahdi_pri_update_span_devstate(), destroy_event(), 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(), join_conference_bridge(), leave_conference_bridge(), load_module(), login_exec(), notify_metermaids(), reg_source_db(), register_verify(), 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().

00507 {
00508    char buf[AST_MAX_EXTENSION];
00509    va_list ap;
00510 
00511    va_start(ap, fmt);
00512    vsnprintf(buf, sizeof(buf), fmt, ap);
00513    va_end(ap);
00514 
00515    return ast_devstate_changed_literal(state, buf);
00516 }

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 463 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_destructor(), ast_device_state_changed(), ast_device_state_changed_literal(), ast_devstate_changed(), ast_setstate(), and dahdi_new().

00464 {
00465    struct state_change *change;
00466 
00467    /* 
00468     * If we know the state change (how nice of the caller of this function!)
00469     * then we can just generate a device state event. 
00470     *
00471     * Otherwise, we do the following:
00472     *   - Queue an event up to another thread that the state has changed
00473     *   - In the processing thread, it calls the callback provided by the
00474     *     device state provider (which may or may not be a channel driver)
00475     *     to determine the state.
00476     *   - If the device state provider does not know the state, or this is
00477     *     for a channel and the channel driver does not implement a device
00478     *     state callback, then we will look through the channel list to
00479     *     see if we can determine a state based on active calls.
00480     *   - Once a state has been determined, a device state event is generated.
00481     */
00482 
00483    if (state != AST_DEVICE_UNKNOWN) {
00484       devstate_event(device, state);
00485    } else if (change_thread == AST_PTHREADT_NULL || !(change = ast_calloc(1, sizeof(*change) + strlen(device)))) {
00486       /* we could not allocate a change struct, or */
00487       /* there is no background thread, so process the change now */
00488       do_state_change(device);
00489    } else {
00490       /* queue the change */
00491       strcpy(change->device, device);
00492       AST_LIST_LOCK(&state_changes);
00493       AST_LIST_INSERT_TAIL(&state_changes, change, list);
00494       ast_cond_signal(&change_pending);
00495       AST_LIST_UNLOCK(&state_changes);
00496    }
00497 
00498    return 1;
00499 }

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 367 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().

00368 {
00369    struct devstate_prov *devprov;
00370 
00371    if (!callback || !(devprov = ast_calloc(1, sizeof(*devprov))))
00372       return -1;
00373 
00374    devprov->callback = callback;
00375    ast_copy_string(devprov->label, label, sizeof(devprov->label));
00376 
00377    AST_RWLIST_WRLOCK(&devstate_provs);
00378    AST_RWLIST_INSERT_HEAD(&devstate_provs, devprov, list);
00379    AST_RWLIST_UNLOCK(&devstate_provs);
00380 
00381    return 0;
00382 }

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 385 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().

00386 {
00387    struct devstate_prov *devcb;
00388    int res = -1;
00389 
00390    AST_RWLIST_WRLOCK(&devstate_provs);
00391    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&devstate_provs, devcb, list) {
00392       if (!strcasecmp(devcb->label, label)) {
00393          AST_RWLIST_REMOVE_CURRENT(list);
00394          ast_free(devcb);
00395          res = 0;
00396          break;
00397       }
00398    }
00399    AST_RWLIST_TRAVERSE_SAFE_END;
00400    AST_RWLIST_UNLOCK(&devstate_provs);
00401 
00402    return res;
00403 }

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

Referenced by aji_devstate_cb(), and devstate_read().

00234 {
00235    return devstatestring[state][1];
00236 }

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 238 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 aji_handle_pubsub_event(), custom_devstate_callback(), devstate_write(), handle_cli_devstate_change(), and load_module().

00239 {
00240    if (!strcasecmp(val, "NOT_INUSE"))
00241       return AST_DEVICE_NOT_INUSE;
00242    else if (!strcasecmp(val, "INUSE"))
00243       return AST_DEVICE_INUSE;
00244    else if (!strcasecmp(val, "BUSY"))
00245       return AST_DEVICE_BUSY;
00246    else if (!strcasecmp(val, "INVALID"))
00247       return AST_DEVICE_INVALID;
00248    else if (!strcasecmp(val, "UNAVAILABLE"))
00249       return AST_DEVICE_UNAVAILABLE;
00250    else if (!strcasecmp(val, "RINGING"))
00251       return AST_DEVICE_RINGING;
00252    else if (!strcasecmp(val, "RINGINUSE"))
00253       return AST_DEVICE_RINGINUSE;
00254    else if (!strcasecmp(val, "ONHOLD"))
00255       return AST_DEVICE_ONHOLD;
00256 
00257    return AST_DEVICE_UNKNOWN;
00258 }

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 822 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().

Referenced by add_publish_event(), add_subscribe_event(), and aji_init_event_distribution().

00823 {
00824    if (devstate_collector.enabled) {
00825       return 0;
00826    }
00827 
00828    devstate_collector.event_sub = ast_event_subscribe(AST_EVENT_DEVICE_STATE_CHANGE,
00829       devstate_change_collector_cb, "devicestate_engine_enable_distributed", NULL, AST_EVENT_IE_END);
00830 
00831    if (!devstate_collector.event_sub) {
00832       ast_log(LOG_ERROR, "Failed to create subscription for the device state change collector\n");
00833       return -1;
00834    }
00835 
00836    ast_mutex_init(&devstate_collector.lock);
00837    ast_cond_init(&devstate_collector.cond, NULL);
00838    if (ast_pthread_create_background(&devstate_collector.thread, NULL, run_devstate_collector, NULL) < 0) {
00839       ast_log(LOG_ERROR, "Unable to start device state collector thread.\n");
00840       return -1;
00841    }
00842 
00843    devstate_collector.enabled = 1;
00844 
00845    return 0;
00846 }

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

References ast_channel::_state, ast_channel_get_by_name_prefix(), AST_CHANNEL_NAME, ast_channel_unref, AST_DEVICE_INUSE, AST_DEVICE_RINGING, ast_device_state(), AST_DEVICE_UNKNOWN, AST_STATE_RINGING, and match().

Referenced by _ast_device_state(), and chanavail_exec().

00266 {
00267    struct ast_channel *chan;
00268    char match[AST_CHANNEL_NAME];
00269    enum ast_device_state res;
00270 
00271    snprintf(match, sizeof(match), "%s-", device);
00272 
00273    if (!(chan = ast_channel_get_by_name_prefix(match, strlen(match)))) {
00274       return AST_DEVICE_UNKNOWN;
00275    }
00276 
00277    res = (chan->_state == AST_STATE_RINGING) ? AST_DEVICE_RINGING : AST_DEVICE_INUSE;
00278    
00279    chan = ast_channel_unref(chan);
00280 
00281    return res;
00282 }

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

References AST_DEVICE_UNKNOWN.

00221 {
00222    int i;
00223    chanstate &= 0xFFFF;
00224    for (i = 0; chan2dev[i].chan != -100; i++) {
00225       if (chan2dev[i].chan == chanstate) {
00226          return chan2dev[i].dev;
00227       }
00228    }
00229    return AST_DEVICE_UNKNOWN;
00230 }

static void destroy_devstate_change ( struct devstate_change sc  )  [static]

Definition at line 555 of file devicestate.c.

References ast_free.

Referenced by run_devstate_collector().

00556 {
00557    ast_free(sc);
00558 }

const char* devstate2str ( enum ast_device_state  devstate  ) 

Convert device state to text string for output.

Parameters:
devstate Current device state

Definition at line 215 of file devicestate.c.

00216 {
00217    return devstatestring[devstate][0];
00218 }

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

Definition at line 566 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().

00567 {
00568    struct change_collection *collection = data;
00569    int i;
00570    const struct ast_eid *eid;
00571 
00572    if (collection->num_states == ARRAY_LEN(collection->states)) {
00573       ast_log(LOG_ERROR, "More per-server state values than we have room for (MAX_SERVERS is %d)\n",
00574          MAX_SERVERS);
00575       return;
00576    }
00577 
00578    if (!(eid = ast_event_get_ie_raw(event, AST_EVENT_IE_EID))) {
00579       ast_log(LOG_ERROR, "Device state change event with no EID\n");
00580       return;
00581    }
00582 
00583    i = collection->num_states;
00584 
00585    collection->states[i].state = ast_event_get_ie_uint(event, AST_EVENT_IE_STATE);
00586    collection->states[i].eid = *eid;
00587 
00588    collection->num_states++;
00589 }

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

Definition at line 284 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().

00285 {
00286    enum ast_device_state res = AST_DEVICE_UNKNOWN;
00287    struct ast_event *event;
00288 
00289    event = ast_event_get_cached(AST_EVENT_DEVICE_STATE,
00290       AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, device,
00291       AST_EVENT_IE_END);
00292 
00293    if (!event)
00294       return res;
00295 
00296    res = ast_event_get_ie_uint(event, AST_EVENT_IE_STATE);
00297 
00298    ast_event_destroy(event);
00299 
00300    return res;
00301 }

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

Definition at line 691 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().

00692 {
00693    struct devstate_change *sc;
00694    const char *device;
00695    const struct ast_eid *eid;
00696    uint32_t state;
00697 
00698    device = ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE);
00699    eid = ast_event_get_ie_raw(event, AST_EVENT_IE_EID);
00700    state = ast_event_get_ie_uint(event, AST_EVENT_IE_STATE);
00701 
00702    if (ast_strlen_zero(device) || !eid) {
00703       ast_log(LOG_ERROR, "Invalid device state change event received\n");
00704       return;
00705    }
00706 
00707    if (!(sc = ast_calloc(1, sizeof(*sc) + strlen(device))))
00708       return;
00709 
00710    strcpy(sc->device, device);
00711    sc->eid = *eid;
00712    sc->state = state;
00713 
00714    ast_mutex_lock(&devstate_collector.lock);
00715    AST_LIST_INSERT_TAIL(&devstate_collector.devstate_change_q, sc, entry);
00716    ast_cond_signal(&devstate_collector.cond);
00717    ast_mutex_unlock(&devstate_collector.lock);
00718 }

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

Definition at line 425 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().

00426 {
00427    struct ast_event *event;
00428    enum ast_event_type event_type;
00429 
00430    if (devstate_collector.enabled) {
00431       /* Distributed device state is enabled, so this state change is a change
00432        * for a single server, not the real state. */
00433       event_type = AST_EVENT_DEVICE_STATE_CHANGE;
00434    } else {
00435       event_type = AST_EVENT_DEVICE_STATE;
00436    }
00437 
00438    ast_debug(3, "device '%s' state '%d'\n", device, state);
00439 
00440    if (!(event = ast_event_new(event_type,
00441          AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, device,
00442          AST_EVENT_IE_STATE, AST_EVENT_IE_PLTYPE_UINT, state,
00443          AST_EVENT_IE_END))) {
00444       return;
00445    }
00446 
00447    ast_event_queue_and_cache(event);
00448 }

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 531 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().

00532 {
00533    struct state_change *next, *current;
00534 
00535    for (;;) {
00536       /* This basically pops off any state change entries, resets the list back to NULL, unlocks, and processes each state change */
00537       AST_LIST_LOCK(&state_changes);
00538       if (AST_LIST_EMPTY(&state_changes))
00539          ast_cond_wait(&change_pending, &state_changes.lock);
00540       next = AST_LIST_FIRST(&state_changes);
00541       AST_LIST_HEAD_INIT_NOLOCK(&state_changes);
00542       AST_LIST_UNLOCK(&state_changes);
00543 
00544       /* Process each state change */
00545       while ((current = next)) {
00546          next = AST_LIST_NEXT(current, list);
00547          do_state_change(current->device);
00548          ast_free(current);
00549       }
00550    }
00551 
00552    return NULL;
00553 }

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

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

Referenced by ast_devstate_changed_literal(), and do_devstate_changes().

00453 {
00454    enum ast_device_state state;
00455 
00456    state = _ast_device_state(device, 0);
00457 
00458    ast_debug(3, "Changing state for %s - state %d (%s)\n", device, state, ast_devstate2str(state));
00459 
00460    devstate_event(device, state);
00461 }

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

Get provider device state.

Definition at line 406 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().

00407 {
00408    struct devstate_prov *devprov;
00409    int res = AST_DEVICE_INVALID;
00410 
00411    AST_RWLIST_RDLOCK(&devstate_provs);
00412    AST_RWLIST_TRAVERSE(&devstate_provs, devprov, list) {
00413       ast_debug(5, "Checking provider %s with %s\n", devprov->label, provider);
00414 
00415       if (!strcasecmp(devprov->label, provider)) {
00416          res = devprov->callback(address);
00417          break;
00418       }
00419    }
00420    AST_RWLIST_UNLOCK(&devstate_provs);
00421 
00422    return res;
00423 }

static void handle_devstate_change ( struct devstate_change sc  )  [static]

Definition at line 645 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().

00646 {
00647    struct ast_event_sub *tmp_sub;
00648    struct change_collection collection = {
00649       .num_states = 0,
00650    };
00651 
00652    ast_debug(1, "Processing device state change for '%s'\n", sc->device);
00653 
00654    if (!(tmp_sub = ast_event_subscribe_new(AST_EVENT_DEVICE_STATE_CHANGE, devstate_cache_cb, &collection))) {
00655       ast_log(LOG_ERROR, "Failed to create subscription\n");
00656       return;
00657    }
00658 
00659    if (ast_event_sub_append_ie_str(tmp_sub, AST_EVENT_IE_DEVICE, sc->device)) {
00660       ast_log(LOG_ERROR, "Failed to append device IE\n");
00661       ast_event_sub_destroy(tmp_sub);
00662       return;
00663    }
00664 
00665    /* Populate the collection of device states from the cache */
00666    ast_event_dump_cache(tmp_sub);
00667 
00668    process_collection(sc->device, &collection);
00669 
00670    ast_event_sub_destroy(tmp_sub);
00671 }

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

Definition at line 591 of file devicestate.c.

References ast_debug, ast_device_state(), ast_devstate2str(), 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(), change_collection::num_states, devstate_change::state, and change_collection::states.

Referenced by handle_devstate_change().

00592 {
00593    int i;
00594    struct ast_devstate_aggregate agg;
00595    enum ast_device_state state;
00596    struct ast_event *event;
00597 
00598    ast_devstate_aggregate_init(&agg);
00599 
00600    for (i = 0; i < collection->num_states; i++) {
00601       ast_debug(1, "Adding per-server state of '%s' for '%s'\n", 
00602          ast_devstate2str(collection->states[i].state), device);
00603       ast_devstate_aggregate_add(&agg, collection->states[i].state);
00604    }
00605 
00606    state = ast_devstate_aggregate_result(&agg);
00607 
00608    ast_debug(1, "Aggregate devstate result is '%s' for '%s'\n",
00609       ast_devstate2str(state), device);
00610 
00611    event = ast_event_get_cached(AST_EVENT_DEVICE_STATE,
00612       AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, device,
00613       AST_EVENT_IE_END);
00614    
00615    if (event) {
00616       enum ast_device_state old_state;
00617 
00618       old_state = ast_event_get_ie_uint(event, AST_EVENT_IE_STATE);
00619       
00620       ast_event_destroy(event);
00621 
00622       if (state == old_state) {
00623          /* No change since last reported device state */
00624          ast_debug(1, "Aggregate state for device '%s' has not changed from '%s'\n",
00625             device, ast_devstate2str(state));
00626          return;
00627       }
00628    }
00629 
00630    ast_debug(1, "Aggregate state for device '%s' has changed to '%s'\n",
00631       device, ast_devstate2str(state));
00632 
00633    event = ast_event_new(AST_EVENT_DEVICE_STATE,
00634       AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, device,
00635       AST_EVENT_IE_STATE, AST_EVENT_IE_PLTYPE_UINT, state,
00636       AST_EVENT_IE_END);
00637 
00638    if (!event) {
00639       return;
00640    }
00641 
00642    ast_event_queue_and_cache(event);
00643 }

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

Definition at line 673 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().

00674 {
00675    for (;;) {
00676       struct devstate_change *sc;
00677 
00678       ast_mutex_lock(&devstate_collector.lock);
00679       while (!(sc = AST_LIST_REMOVE_HEAD(&devstate_collector.devstate_change_q, entry)))
00680          ast_cond_wait(&devstate_collector.cond, &devstate_collector.lock);
00681       ast_mutex_unlock(&devstate_collector.lock);
00682 
00683       handle_devstate_change(sc);
00684 
00685       destroy_devstate_change(sc);
00686    }
00687 
00688    return NULL;
00689 }


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.

struct { ... } devstate_change_q

struct { ... } devstate_collector [static]

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

const char* const devstatestring[][2] [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.

struct devstate_change* last

Definition at line 198 of file devicestate.c.

ast_mutex_t lock

Definition at line 197 of file devicestate.c.

pthread_t thread

Definition at line 194 of file devicestate.c.


Generated on Mon Mar 19 11:30:46 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7