Codename Pineapple

Home page | Mailing list | Docs

Last updated: Sat Feb 3 05:01:29 2007

Asterisk developer's documentation :: Codename Pineapple


devicestate.c File Reference


Detailed Description

Device state management.

Author:
Mark Spencer <markster@digium.com>

Definition in file devicestate.c.

#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)
 Asks a channel for device state.
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)
 Registers a device state change callback.
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.
static AST_LIST_HEAD_STATIC (state_changes, state_change)
 The state change queue. State changes are queued for processing by a separate thread.
int ast_parse_device_state (const char *device)
 Search the Channels by Name.
static AST_RWLIST_HEAD_STATIC (devstate_cbs, devstate_cb)
 A device state watcher list.
static AST_RWLIST_HEAD_STATIC (devstate_provs, devstate_prov)
 A list of providers.
const char * devstate2str (int 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.


Function Documentation

static int __ast_device_state_changed_literal char *  buf  )  [static]
 

Definition at line 376 of file devicestate.c.

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

00377 {
00378    char *device, *tmp;
00379    struct state_change *change;
00380 
00381    if (option_debug > 2)
00382       ast_log(LOG_DEBUG, "Notification of state change to be queued on device/channel %s\n", buf);
00383 
00384    device = buf;
00385    if ((tmp = strrchr(device, '-')))
00386       *tmp = '\0';
00387 
00388    if (change_thread == AST_PTHREADT_NULL || !(change = ast_calloc(1, sizeof(*change) + strlen(device)))) {
00389       /* we could not allocate a change struct, or */
00390       /* there is no background thread, so process the change now */
00391       do_state_change(device);
00392    } else {
00393       /* queue the change */
00394       strcpy(change->device, device);
00395       AST_LIST_LOCK(&state_changes);
00396       AST_LIST_INSERT_TAIL(&state_changes, change, list);
00397       ast_cond_signal(&change_pending);
00398       AST_LIST_UNLOCK(&state_changes);
00399    }
00400 
00401    return 1;
00402 }

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

Definition at line 216 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, ast_channel_tech::devicestate, getproviderstate(), LOG_DEBUG, option_debug, and strsep().

Referenced by ast_extension_state2(), do_state_change(), and transmit_state_notify().

00217 {
00218    char *buf;
00219    char *number;
00220    const struct ast_channel_tech *chan_tech;
00221    int res = 0;
00222    /*! \brief Channel driver that provides device state */
00223    char *tech;
00224    /*! \brief Another provider of device state */
00225    char *provider = NULL;
00226    
00227    buf = ast_strdupa(device);
00228    tech = strsep(&buf, "/");
00229    if (!(number = buf)) {
00230       if (!(provider = strsep(&tech, ":")))
00231          return AST_DEVICE_INVALID;
00232       /* We have a provider */
00233       number = tech;
00234       tech = NULL;
00235    }
00236 
00237    if (provider)  {
00238       if (option_debug > 2)
00239          ast_log(LOG_DEBUG, "Checking if I can find provider for \"%s\" - number: %s\n", provider, number);
00240       return getproviderstate(provider, number);
00241    }
00242 
00243    if (option_debug > 3)
00244       ast_log(LOG_DEBUG, "No provider found, checking channel drivers for %s - %s\n", tech, number);
00245 
00246    if (!(chan_tech = ast_get_channel_tech(tech)))
00247       return AST_DEVICE_INVALID;
00248 
00249    if (!(chan_tech->devicestate)) /* Does the channel driver support device state notification? */
00250       return ast_parse_device_state(device); /* No, try the generic function */
00251 
00252    res = chan_tech->devicestate(number);
00253 
00254    if (res != AST_DEVICE_UNKNOWN)
00255       return res;
00256 
00257    res = ast_parse_device_state(device);
00258 
00259    if (res == AST_DEVICE_UNKNOWN)
00260       return AST_DEVICE_NOT_INUSE;
00261 
00262    return res;
00263 }

int ast_device_state_changed const char *  fmt,
  ...
 

Accept change notification, add it to change queue.

Definition at line 412 of file devicestate.c.

References __ast_device_state_changed_literal(), and AST_MAX_EXTENSION.

Referenced by __expire_registry(), __iax2_poke_noanswer(), __login_exec(), agent_hangup(), agent_logoff_maintenance(), expire_register(), handle_response_peerpoke(), notify_metermaids(), reg_source_db(), register_verify(), reload_agents(), sip_peer_hold(), sip_poke_noanswer(), socket_process(), update_call_counter(), and update_registry().

00413 {
00414    char buf[AST_MAX_EXTENSION];
00415    va_list ap;
00416 
00417    va_start(ap, fmt);
00418    vsnprintf(buf, sizeof(buf), fmt, ap);
00419    va_end(ap);
00420    return __ast_device_state_changed_literal(buf);
00421 }

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

References __ast_device_state_changed_literal(), and ast_strdupa.

Referenced by ast_channel_free(), and ast_setstate().

00405 {
00406    char *buf;
00407    buf = ast_strdupa(dev);
00408    return __ast_device_state_changed_literal(buf);
00409 }

int ast_device_state_engine_init void   ) 
 

Initialize the device state engine in separate thread.

Definition at line 449 of file devicestate.c.

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

00450 {
00451    ast_cond_init(&change_pending, NULL);
00452    if (ast_pthread_create_background(&change_thread, NULL, do_devstate_changes, NULL) < 0) {
00453       ast_log(LOG_ERROR, "Unable to start device state change thread.\n");
00454       return -1;
00455    }
00456 
00457    return 0;
00458 }

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

References ast_calloc, AST_RWLIST_INSERT_HEAD, AST_RWLIST_UNLOCK, and AST_RWLIST_WRLOCK.

00323 {
00324    struct devstate_cb *devcb;
00325 
00326    if (!callback || !(devcb = ast_calloc(1, sizeof(*devcb))))
00327       return -1;
00328 
00329    devcb->data = data;
00330    devcb->callback = callback;
00331 
00332    AST_RWLIST_WRLOCK(&devstate_cbs);
00333    AST_RWLIST_INSERT_HEAD(&devstate_cbs, devcb, list);
00334    AST_RWLIST_UNLOCK(&devstate_cbs);
00335 
00336    return 0;
00337 }

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

References AST_RWLIST_REMOVE_CURRENT, AST_RWLIST_TRAVERSE_SAFE_BEGIN, AST_RWLIST_TRAVERSE_SAFE_END, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, devstate_cb::callback, devstate_cb::data, and free.

00341 {
00342    struct devstate_cb *devcb;
00343 
00344    AST_RWLIST_WRLOCK(&devstate_cbs);
00345    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&devstate_cbs, devcb, list) {
00346       if ((devcb->callback == callback) && (devcb->data == data)) {
00347          AST_RWLIST_REMOVE_CURRENT(&devstate_cbs, list);
00348          free(devcb);
00349          break;
00350       }
00351    }
00352    AST_RWLIST_TRAVERSE_SAFE_END;
00353    AST_RWLIST_UNLOCK(&devstate_cbs);
00354 }

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 -1 on failure, ID on success

Definition at line 266 of file devicestate.c.

References ast_calloc, AST_RWLIST_INSERT_HEAD, AST_RWLIST_UNLOCK, and AST_RWLIST_WRLOCK.

Referenced by load_module().

00267 {
00268    struct devstate_prov *devprov;
00269 
00270    if (!callback || !(devprov = ast_calloc(1, sizeof(*devprov))))
00271       return -1;
00272 
00273    devprov->callback = callback;
00274    ast_copy_string(devprov->label, label, sizeof(devprov->label));
00275 
00276    AST_RWLIST_WRLOCK(&devstate_provs);
00277    AST_RWLIST_INSERT_HEAD(&devstate_provs, devprov, list);
00278    AST_RWLIST_UNLOCK(&devstate_provs);
00279 
00280    return 0;
00281 }

void ast_devstate_prov_del const char *  label  ) 
 

Remove device state provider.

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

Definition at line 284 of file devicestate.c.

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

Referenced by unload_module().

00285 {
00286    struct devstate_prov *devcb;
00287 
00288    AST_RWLIST_WRLOCK(&devstate_provs);
00289    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&devstate_provs, devcb, list) {
00290       if (!strcasecmp(devcb->label, label)) {
00291          AST_RWLIST_REMOVE_CURRENT(&devstate_provs, list);
00292          free(devcb);
00293          break;
00294       }
00295    }
00296    AST_RWLIST_TRAVERSE_SAFE_END;
00297    AST_RWLIST_UNLOCK(&devstate_provs);
00298 }

static AST_LIST_HEAD_STATIC state_changes  ,
state_change 
[static]
 

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

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

References ast_channel::_state, AST_CHANNEL_NAME, ast_channel_unlock, 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().

00193 {
00194    struct ast_channel *chan;
00195    char match[AST_CHANNEL_NAME];
00196    int res;
00197 
00198    ast_copy_string(match, device, sizeof(match)-1);
00199    strcat(match, "-");
00200    chan = ast_get_channel_by_name_prefix_locked(match, strlen(match));
00201 
00202    if (!chan)
00203       return AST_DEVICE_UNKNOWN;
00204 
00205    if (chan->_state == AST_STATE_RINGING)
00206       res = AST_DEVICE_RINGING;
00207    else
00208       res = AST_DEVICE_INUSE;
00209    
00210    ast_channel_unlock(chan);
00211 
00212    return res;
00213 }

static AST_RWLIST_HEAD_STATIC devstate_cbs  ,
devstate_cb 
[static]
 

A device state watcher list.

static AST_RWLIST_HEAD_STATIC devstate_provs  ,
devstate_prov 
[static]
 

A list of providers.

const char* devstate2str int  devstate  ) 
 

Convert device state to text string for output.

Parameters:
devstate Current device state

Definition at line 182 of file devicestate.c.

Referenced by do_state_change().

00183 {
00184    return devstatestring[devstate];
00185 }

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

References ast_cond_wait(), AST_LIST_EMPTY, AST_LIST_FIRST, AST_LIST_HEAD_INIT_NOLOCK, AST_LIST_LOCK, AST_LIST_NEXT, AST_LIST_UNLOCK, do_state_change(), and free.

Referenced by ast_device_state_engine_init().

00425 {
00426    struct state_change *next, *current;
00427 
00428    for (;;) {
00429       /* This basically pops off any state change entries, resets the list back to NULL, unlocks, and processes each state change */
00430       AST_LIST_LOCK(&state_changes);
00431       if (AST_LIST_EMPTY(&state_changes))
00432          ast_cond_wait(&change_pending, &state_changes.lock);
00433       next = AST_LIST_FIRST(&state_changes);
00434       AST_LIST_HEAD_INIT_NOLOCK(&state_changes);
00435       AST_LIST_UNLOCK(&state_changes);
00436 
00437       /* Process each state change */
00438       while ((current = next)) {
00439          next = AST_LIST_NEXT(current, list);
00440          do_state_change(current->device);
00441          free(current);
00442       }
00443    }
00444 
00445    return NULL;
00446 }

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

References ast_device_state(), ast_hint_state_changed(), ast_log(), AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, devstate_cb::callback, devstate_cb::data, devstate2str(), LOG_DEBUG, and option_debug.

Referenced by __ast_device_state_changed_literal(), and do_devstate_changes().

00360 {
00361    int state;
00362    struct devstate_cb *devcb;
00363 
00364    state = ast_device_state(device);
00365    if (option_debug > 2)
00366       ast_log(LOG_DEBUG, "Changing state for %s - state %d (%s)\n", device, state, devstate2str(state));
00367 
00368    AST_RWLIST_RDLOCK(&devstate_cbs);
00369    AST_RWLIST_TRAVERSE(&devstate_cbs, devcb, list)
00370       devcb->callback(device, state, devcb->data);
00371    AST_RWLIST_UNLOCK(&devstate_cbs);
00372 
00373    ast_hint_state_changed(device);
00374 }

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

Get provider device state.

Definition at line 301 of file devicestate.c.

References AST_DEVICE_INVALID, ast_log(), AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, devstate_prov::callback, devstate_prov::label, LOG_DEBUG, and option_debug.

Referenced by ast_device_state().

00302 {
00303    struct devstate_prov *devprov;
00304    int res = AST_DEVICE_INVALID;
00305 
00306 
00307    AST_RWLIST_RDLOCK(&devstate_provs);
00308    AST_RWLIST_TRAVERSE(&devstate_provs, devprov, list) {
00309       if (option_debug > 4)
00310          ast_log(LOG_DEBUG, "Checking provider %s with %s\n", devprov->label, provider);
00311 
00312       if (!strcasecmp(devprov->label, provider)) {
00313          res = devprov->callback(address);
00314          break;
00315       }
00316    }
00317    AST_RWLIST_UNLOCK(&devstate_provs);
00318    return res;
00319 }


Variable Documentation

ast_cond_t change_pending [static]
 

Flag for the queue.

Definition at line 176 of file devicestate.c.

Referenced by ast_device_state_engine_init().

pthread_t change_thread = AST_PTHREADT_NULL [static]
 

The device state change notification thread.

Definition at line 173 of file devicestate.c.

Referenced by ast_device_state_engine_init().

const char* devstatestring[] [static]
 

Device state strings for printing.

Definition at line 131 of file devicestate.c.


Asterisk is a trademark for Digium, inc.. | Edvina.net | Asterisk.org | This documentation was generated with Doxygen