#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. |
Definition in file devicestate.c.
int ast_device_state | ( | const char * | device | ) |
Asks a channel for device state.
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.
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.
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.
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.
[in] | agg | the state object |
[in] | state | the state to add |
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.
[in] | agg | the state object |
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.
[in] | agg | the state object |
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.
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.
label | to use in hint, like label:object | |
callback | Callback |
-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.
label | to use in hint, like label:object |
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.
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.
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 }
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] |