Wed Oct 28 13:32:30 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"

Include dependency graph for devicestate.c:

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 void __fini_devstate_provs (void)
static void __init_devstate_provs (void)
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)
 Find out if device is active in a call or not.
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 {
      struct devstate_change *   first
      struct devstate_change *   last
   }   devstate_change_q
   unsigned int   enabled:1
   struct 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 558 of file devicestate.c.

Referenced by devstate_cache_cb().


Function Documentation

static void __fini_devstate_provs ( void   )  [static]

Definition at line 169 of file devicestate.c.

00171 {

static void __init_devstate_provs ( void   )  [static]

Definition at line 169 of file devicestate.c.

00171 {

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

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       if (!(provider = strsep(&tech, ":")))
00327          return AST_DEVICE_INVALID;
00328       /* We have a provider */
00329       number = tech;
00330       tech = NULL;
00331    }
00332 
00333    if (provider)  {
00334       ast_debug(3, "Checking if I can find provider for \"%s\" - number: %s\n", provider, number);
00335       return getproviderstate(provider, number);
00336    }
00337 
00338    ast_debug(4, "No provider found, checking channel drivers for %s - %s\n", tech, number);
00339 
00340    if (!(chan_tech = ast_get_channel_tech(tech)))
00341       return AST_DEVICE_INVALID;
00342 
00343    if (!(chan_tech->devicestate)) /* Does the channel driver support device state notification? */
00344       return ast_parse_device_state(device); /* No, try the generic function */
00345 
00346    res = chan_tech->devicestate(number);
00347 
00348    if (res != AST_DEVICE_UNKNOWN)
00349       return res;
00350 
00351    res = ast_parse_device_state(device);
00352 
00353    return res;
00354 }

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

References _ast_device_state().

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

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

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

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

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

References AST_DEVICE_UNKNOWN, and ast_devstate_changed_literal().

00500 {
00501    return ast_devstate_changed_literal(AST_DEVICE_UNKNOWN, dev);
00502 }

int ast_device_state_engine_init ( void   ) 

Initialize the device state engine in separate thread.

Provided by devicestate.c

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

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

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(), 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 739 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_state2(), and process_collection().

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

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

References ast_devstate_aggregate::all_busy, ast_devstate_aggregate::all_free, ast_devstate_aggregate::all_unavail, and ast_devstate_aggregate::all_unknown.

Referenced by ast_extension_state2(), and process_collection().

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

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 795 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_state2(), and process_collection().

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

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 504 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_read(), calendar_devstate_change(), conf_run(), 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(), 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().

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

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 461 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, state_change::device, devstate_event(), and do_state_change().

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

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

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

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

Referenced by ast_features_init(), and load_module().

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

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 383 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, and devstate_prov::label.

Referenced by unload_module().

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

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 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 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 819 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(), and add_subscribe_event().

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

enum ast_device_state 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 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_UNKNOWN, AST_STATE_RINGING, chan, 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, and chan.

Referenced by dahdi_new().

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

References ast_free.

Referenced by run_devstate_collector().

00554 {
00555    ast_free(sc);
00556 }

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 564 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, LOG_ERROR, MAX_SERVERS, change_collection::num_states, devstate_change::state, and change_collection::states.

Referenced by handle_devstate_change().

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

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

Definition at line 284 of file devicestate.c.

References 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 688 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_change::device, devstate_collector, devstate_change::eid, LOG_ERROR, and devstate_change::state.

Referenced by ast_enable_distributed_devstate().

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

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

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

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

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 529 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(), and devstate_prov::next.

Referenced by ast_device_state_engine_init().

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

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

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

Referenced by ast_devstate_changed_literal(), and do_devstate_changes().

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

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

Get provider device state.

Definition at line 404 of file devicestate.c.

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

Referenced by _ast_device_state().

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

static void handle_devstate_change ( struct devstate_change sc  )  [static]

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

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

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

Definition at line 589 of file devicestate.c.

References ast_debug, 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().

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

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

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

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


Variable Documentation

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

Definition at line 196 of file devicestate.c.

struct { ... } devstate_change_q

struct { ... } devstate_collector [static]

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.

Definition at line 195 of file devicestate.c.

Referenced by dump_cache_cb().

Definition at line 198 of file devicestate.c.

Definition at line 198 of file devicestate.c.

Definition at line 197 of file devicestate.c.

pthread_t thread

Definition at line 194 of file devicestate.c.


Generated on Wed Oct 28 13:32:30 2009 for Asterisk - the Open Source PBX by  doxygen 1.5.6