Wed Aug 15 01:25:04 2007

Asterisk developer's documentation


devicestate.c File Reference

Device state management. More...

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

Include dependency graph for devicestate.c:

Go to the source code of this file.

Data Structures

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

Functions

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

Variables

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


Detailed Description

Device state management.

Author:
Mark Spencer <markster@digium.com>

Definition in file devicestate.c.


Function Documentation

static int __ast_device_state_changed_literal ( char *  buf  )  [static]

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, do_state_change(), LOG_DEBUG, and option_debug.

Referenced by ast_device_state_changed(), and ast_device_state_changed_literal().

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

int ast_device_state ( const char *  device  ) 

Check device state through channel specific function or generic function.

Asks a channel for device state.

Channel driver that provides device state

Another provider of device state

Definition at line 132 of file devicestate.c.

Referenced by ast_extension_state2(), chanavail_exec(), create_queue_member(), do_state_change(), reload_queues(), 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 (!provider)
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,
  ... 
)

Accept change notification, add it to change queue.

Definition at line 338 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_hangup(), agent_logoff_maintenance(), conf_run(), expire_register(), handle_response_peerpoke(), notify_metermaids(), reg_source_db(), register_verify(), reload_agents(), reload_config(), 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().

00339 {
00340    char buf[AST_MAX_EXTENSION];
00341    va_list ap;
00342 
00343    va_start(ap, fmt);
00344    vsnprintf(buf, sizeof(buf), fmt, ap);
00345    va_end(ap);
00346    return __ast_device_state_changed_literal(buf);
00347 }

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

Referenced by ast_channel_free(), and ast_setstate().

00331 {
00332    char *buf;
00333    buf = ast_strdupa(dev);
00334    return __ast_device_state_changed_literal(buf);
00335 }

int ast_device_state_engine_init ( void   ) 

Initialize the device state engine in separate thread.

Definition at line 375 of file devicestate.c.

Referenced by main().

00376 {
00377    ast_cond_init(&change_pending, NULL);
00378    if (ast_pthread_create_background(&change_thread, NULL, do_devstate_changes, NULL) < 0) {
00379       ast_log(LOG_ERROR, "Unable to start device state change thread.\n");
00380       return -1;
00381    }
00382 
00383    return 0;
00384 }

int ast_devstate_add ( ast_devstate_cb_type  callback,
void *  data 
)

Add device state watcher.

Registers a device state change callback.

Definition at line 243 of file devicestate.c.

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_del ( ast_devstate_cb_type  callback,
void *  data 
)

Remove device state watcher.

Unregisters a device state change callback.

Definition at line 261 of file devicestate.c.

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.

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.

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 }

static AST_LIST_HEAD_STATIC ( state_changes  ,
state_change   
) [static]

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

static AST_LIST_HEAD_STATIC ( devstate_cbs  ,
devstate_cb   
) [static]

A device state watcher list.

static AST_LIST_HEAD_STATIC ( devstate_provs  ,
devstate_prov   
) [static]

A list of providers.

int ast_parse_device_state ( const char *  device  ) 

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

Search the Channels by Name.

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

Definition at line 108 of file devicestate.c.

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 ( int  devstate  ) 

Find devicestate as text message for output.

Convert device state to text string for output.

Definition at line 98 of file devicestate.c.

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

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

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

Referenced by ast_device_state_engine_init().

00351 {
00352    struct state_change *cur;
00353 
00354    AST_LIST_LOCK(&state_changes);
00355    for(;;) {
00356       /* the list lock will _always_ be held at this point in the loop */
00357       cur = AST_LIST_REMOVE_HEAD(&state_changes, list);
00358       if (cur) {
00359          /* we got an entry, so unlock the list while we process it */
00360          AST_LIST_UNLOCK(&state_changes);
00361          do_state_change(cur->device);
00362          free(cur);
00363          AST_LIST_LOCK(&state_changes);
00364       } else {
00365          /* there was no entry, so atomically unlock the list and wait for
00366             the condition to be signalled (returns with the lock held) */
00367          ast_cond_wait(&change_pending, &state_changes.lock);
00368       }
00369    }
00370 
00371    return NULL;
00372 }

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

pthread_t change_thread = AST_PTHREADT_NULL [static]

The device state change notification thread.

Definition at line 89 of file devicestate.c.

const char* devstatestring[] [static]

Device state strings for printing.

Definition at line 47 of file devicestate.c.


Generated on Wed Aug 15 01:25:04 2007 for Asterisk - the Open Source PBX by  doxygen 1.5.3