Sat Aug 6 00:39:55 2011

Asterisk developer's documentation


devicestate.c File Reference

Device state management. More...

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

Go to the source code of this file.

Data Structures

struct  devstate_cb
 A device state watcher (callback). More...
struct  devstate_cbs
 A device state watcher list. More...
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...

Functions

int 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.
int ast_device_state_changed_literal (const char *device)
 Tells Asterisk the State for Device is changed.
int ast_device_state_engine_init (void)
 Initialize the device state engine in separate thread.
int ast_devstate_add (ast_devstate_cb_type callback, void *data)
 Registers a device state change callback.
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.
void ast_devstate_del (ast_devstate_cb_type callback, void *data)
 Unregisters a device state change callback.
int ast_devstate_prov_add (const char *label, ast_devstate_prov_cb_type callback)
 Add device state provider.
void ast_devstate_prov_del (const char *label)
 Remove device state provider.
int ast_parse_device_state (const char *device)
 Search the Channels by Name.
const char * devstate2str (enum ast_device_state devstate)
 Convert device state to text string for output.
static void * do_devstate_changes (void *data)
 Go through the dev state change queue and update changes in the dev state thread.
static void do_state_change (const char *device)
 Notify callback watchers of change, and notify PBX core for hint updates Normally executed within a separate thread.
static int getproviderstate (const char *provider, const char *address)
 Get provider device state.

Variables

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


Detailed Description

Device state management.

Author:
Mark Spencer <markster@digium.com>

Definition in file devicestate.c.


Function Documentation

int ast_device_state ( const char *  device  ) 

Asks a channel for device state.

Parameters:
device like a dialstring Asks a channel for device state, data is normaly a number from dialstring used by the low level module Trys the channel devicestate callback if not supported search in the active channels list for the device. Returns an AST_DEVICE_??? state -1 on failure

Channel driver that provides device state

Another provider of device state

Definition at line 132 of file devicestate.c.

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

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

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

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

Tells Asterisk the State for Device is changed.

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

Definition at line 323 of file devicestate.c.

References ast_device_state_changed_literal(), and AST_MAX_EXTENSION.

Referenced by __expire_registry(), __iax2_poke_noanswer(), __login_exec(), action_agent_callback_login(), agent_call(), agent_devicestate_cb(), agent_hangup(), agent_logoff_maintenance(), agent_read(), conf_run(), expire_register(), handle_response_peerpoke(), notify_metermaids(), reg_source_db(), register_verify(), reload_agents(), sip_peer_hold(), sip_poke_noanswer(), sla_change_trunk_state(), sla_handle_hold_event(), sla_station_exec(), socket_process(), update_call_counter(), and update_registry().

00324 {
00325    char buf[AST_MAX_EXTENSION];
00326    va_list ap;
00327 
00328    va_start(ap, fmt);
00329    vsnprintf(buf, sizeof(buf), fmt, ap);
00330    va_end(ap);
00331    return ast_device_state_changed_literal(buf);
00332 }

int ast_device_state_changed_literal ( const char *  device  ) 

Tells Asterisk the State for Device is changed.

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

Definition at line 297 of file devicestate.c.

References ast_calloc, ast_cond_signal(), AST_LIST_FIRST, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), AST_PTHREADT_NULL, change_pending, change_thread, do_state_change(), devstate_prov::list, LOG_DEBUG, and option_debug.

Referenced by ast_channel_free(), ast_device_state_changed(), and ast_setstate().

00298 {
00299    struct state_change *change;
00300 
00301    if (option_debug > 2)
00302       ast_log(LOG_DEBUG, "Notification of state change to be queued on device/channel %s\n", device);
00303 
00304    if (change_thread == AST_PTHREADT_NULL || !(change = ast_calloc(1, sizeof(*change) + strlen(device)))) {
00305       /* we could not allocate a change struct, or */
00306       /* there is no background thread, so process the change now */
00307       do_state_change(device);
00308    } else {
00309       /* queue the change */
00310       strcpy(change->device, device);
00311       AST_LIST_LOCK(&state_changes);
00312       AST_LIST_INSERT_TAIL(&state_changes, change, list);
00313       if (AST_LIST_FIRST(&state_changes) == change)
00314          /* the list was empty, signal the thread */
00315          ast_cond_signal(&change_pending);
00316       AST_LIST_UNLOCK(&state_changes);
00317    }
00318 
00319    return 1;
00320 }

int ast_device_state_engine_init ( void   ) 

Initialize the device state engine in separate thread.

Definition at line 360 of file devicestate.c.

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

Referenced by main().

00361 {
00362    ast_cond_init(&change_pending, NULL);
00363    if (ast_pthread_create_background(&change_thread, NULL, do_devstate_changes, NULL) < 0) {
00364       ast_log(LOG_ERROR, "Unable to start device state change thread.\n");
00365       return -1;
00366    }
00367 
00368    return 0;
00369 }

int ast_devstate_add ( ast_devstate_cb_type  callback,
void *  data 
)

Registers a device state change callback.

Parameters:
callback Callback
data to pass to callback The callback is called if the state for extension is changed Return -1 on failure, ID on success

Definition at line 243 of file devicestate.c.

References ast_calloc, AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_UNLOCK, and devstate_prov::list.

Referenced by load_module().

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

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

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

00381 {
00382    switch (state) {
00383    case AST_DEVICE_NOT_INUSE:
00384       agg->all_unknown = 0;
00385       agg->all_unavail = 0;
00386       agg->all_busy = 0;
00387       break;
00388    case AST_DEVICE_INUSE:
00389       agg->in_use = 1;
00390       agg->all_unavail = 0;
00391       agg->all_free = 0;
00392       agg->all_unknown = 0;
00393       break;
00394    case AST_DEVICE_RINGING:
00395       agg->ring = 1;
00396       agg->all_unavail = 0;
00397       agg->all_free = 0;
00398       agg->all_unknown = 0;
00399       break;
00400    case AST_DEVICE_RINGINUSE:
00401       agg->in_use = 1;
00402       agg->ring = 1;
00403       agg->all_unavail = 0;
00404       agg->all_free = 0;
00405       agg->all_unknown = 0;
00406       break;
00407    case AST_DEVICE_ONHOLD:
00408       agg->all_unknown = 0;
00409       agg->all_unavail = 0;
00410       agg->all_free = 0;
00411       agg->on_hold = 1;
00412       break;
00413    case AST_DEVICE_BUSY:
00414       agg->all_unknown = 0;
00415       agg->all_unavail = 0;
00416       agg->all_free = 0;
00417       agg->busy = 1;
00418       agg->in_use = 1;
00419       break;
00420    case AST_DEVICE_UNAVAILABLE:
00421       agg->all_unknown = 0;
00422    case AST_DEVICE_INVALID:
00423       agg->all_busy = 0;
00424       agg->all_free = 0;
00425       break;
00426    case AST_DEVICE_UNKNOWN:
00427       agg->all_busy = 0;
00428       agg->all_free = 0;
00429       break;
00430    case AST_DEVICE_TOTAL: /* not a device state, included for completeness. */
00431       break;
00432    }
00433 }

void ast_devstate_aggregate_init ( struct ast_devstate_aggregate agg  ) 

Initialize aggregate device state.

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

Definition at line 371 of file devicestate.c.

Referenced by ast_extension_state2().

00372 {
00373    memset(agg, 0, sizeof(*agg));
00374    agg->all_unknown = 1;
00375    agg->all_unavail = 1;
00376    agg->all_busy = 1;
00377    agg->all_free = 1;
00378 }

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.

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

00436 {
00437    if (agg->all_free)
00438       return AST_DEVICE_NOT_INUSE;
00439    if ((agg->in_use || agg->on_hold) && agg->ring)
00440       return AST_DEVICE_RINGINUSE;
00441    if (agg->ring)
00442       return AST_DEVICE_RINGING;
00443    if (agg->busy)
00444       return AST_DEVICE_BUSY;
00445    if (agg->in_use)
00446       return AST_DEVICE_INUSE;
00447    if (agg->on_hold)
00448       return AST_DEVICE_ONHOLD;
00449    if (agg->all_busy)
00450       return AST_DEVICE_BUSY;
00451    if (agg->all_unknown)
00452       return AST_DEVICE_UNKNOWN;
00453    if (agg->all_unavail)
00454       return AST_DEVICE_UNAVAILABLE;
00455 
00456    return AST_DEVICE_NOT_INUSE;
00457 }

void ast_devstate_del ( ast_devstate_cb_type  callback,
void *  data 
)

Unregisters a device state change callback.

Parameters:
callback Callback
data to pass to callback The callback is called if the state for extension is changed Return -1 on failure, ID on success

Definition at line 261 of file devicestate.c.

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

Referenced by unload_module().

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

int ast_devstate_prov_add ( const char *  label,
ast_devstate_prov_cb_type  callback 
)

Add device state provider.

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

Definition at line 186 of file devicestate.c.

References ast_calloc, ast_copy_string(), AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_UNLOCK, and devstate_prov::list.

Referenced by load_module().

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

void ast_devstate_prov_del ( const char *  label  ) 

Remove device state provider.

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

Definition at line 204 of file devicestate.c.

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

Referenced by unload_module().

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

int 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 108 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_UNKNOWN, ast_get_channel_by_name_prefix_locked(), AST_STATE_RINGING, and match().

Referenced by ast_device_state().

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

const char* devstate2str ( enum ast_device_state  devstate  ) 

Convert device state to text string for output.

Parameters:
devstate Current device state

Definition at line 98 of file devicestate.c.

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

00099 {
00100    return devstatestring[devstate];
00101 }

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

References ast_cond_wait(), AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, change_pending, do_state_change(), free, and devstate_prov::list.

Referenced by ast_device_state_engine_init().

00336 {
00337    struct state_change *cur;
00338 
00339    AST_LIST_LOCK(&state_changes);
00340    for(;;) {
00341       /* the list lock will _always_ be held at this point in the loop */
00342       cur = AST_LIST_REMOVE_HEAD(&state_changes, list);
00343       if (cur) {
00344          /* we got an entry, so unlock the list while we process it */
00345          AST_LIST_UNLOCK(&state_changes);
00346          do_state_change(cur->device);
00347          free(cur);
00348          AST_LIST_LOCK(&state_changes);
00349       } else {
00350          /* there was no entry, so atomically unlock the list and wait for
00351             the condition to be signalled (returns with the lock held) */
00352          ast_cond_wait(&change_pending, &state_changes.lock);
00353       }
00354    }
00355 
00356    return NULL;
00357 }

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

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

Definition at line 280 of file devicestate.c.

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

Referenced by ast_device_state_changed_literal(), and do_devstate_changes().

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

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

Get provider device state.

Definition at line 221 of file devicestate.c.

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

Referenced by ast_device_state().

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


Variable Documentation

ast_cond_t change_pending [static]

Flag for the queue.

Definition at line 92 of file devicestate.c.

Referenced by ast_device_state_changed_literal(), ast_device_state_engine_init(), and do_devstate_changes().

pthread_t change_thread = AST_PTHREADT_NULL [static]

The device state change notification thread.

Definition at line 89 of file devicestate.c.

Referenced by ast_device_state_changed_literal(), and ast_device_state_engine_init().

const char* devstatestring[] [static]

Device state strings for printing.

Definition at line 47 of file devicestate.c.


Generated on Sat Aug 6 00:39:55 2011 for Asterisk - the Open Source PBX by  doxygen 1.4.7