#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_prov |
A device state provider (not a channel). More... | |
struct | state_change |
Functions | |
static int | __ast_device_state_changed_literal (char *buf, int norecurse, char *cid_num, char *cid_name) |
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, const char *cid_num, const char *cid_name) |
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, char *cid_num, char *cid_name) |
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.
static int __ast_device_state_changed_literal | ( | char * | buf, | |
int | norecurse, | |||
char * | cid_num, | |||
char * | cid_name | |||
) | [static] |
Definition at line 299 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, ast_strlen_zero(), do_state_change(), LOG_DEBUG, and option_debug.
Referenced by ast_device_state_changed(), and ast_device_state_changed_literal().
00300 { 00301 char *device; 00302 struct state_change *change; 00303 char *tmp = NULL; 00304 00305 if (option_debug > 2) 00306 ast_log(LOG_DEBUG, "Notification of state change to be queued on device/channel %s\n", buf); 00307 00308 device = buf; 00309 00310 if (change_thread == AST_PTHREADT_NULL || !(change = ast_calloc(1, sizeof(*change) + strlen(device)))) { 00311 /* we could not allocate a change struct, or */ 00312 /* there is no background thread, so process the change now */ 00313 do_state_change(device, cid_num, cid_name); 00314 } else { 00315 /* queue the change */ 00316 strcpy(change->device, device); 00317 if (cid_num && (!ast_strlen_zero(cid_num))) { 00318 strncpy(change->cid_num, cid_num, sizeof(change->cid_num) - 1); 00319 } 00320 if (cid_name && (!ast_strlen_zero(cid_name))) { 00321 strncpy(change->cid_name, cid_name, sizeof(change->cid_name) - 1); 00322 } 00323 AST_LIST_LOCK(&state_changes); 00324 AST_LIST_INSERT_TAIL(&state_changes, change, list); 00325 if (AST_LIST_FIRST(&state_changes) == change) 00326 /* the list was empty, signal the thread */ 00327 ast_cond_signal(&change_pending); 00328 AST_LIST_UNLOCK(&state_changes); 00329 } 00330 00331 /* The problem with this API is that a device may be called with the unique 00332 * identifier appended or not, but it's separated from the channel name 00333 * with a '-', which is also a legitimate character in a channel name. So, 00334 * we have to force both names to get their names checked for state changes 00335 * to ensure that the right one gets notified. Not a huge performance hit, 00336 * but it might could be fixed by an enterprising programmer in trunk. 00337 */ 00338 if (!norecurse && (tmp = strrchr(device, '-'))) { 00339 *tmp = '\0'; 00340 __ast_device_state_changed_literal(device, 1, cid_num, cid_name); 00341 } 00342 00343 return 1; 00344 }
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 134 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(), chanavail_exec(), create_queue_member(), devstate_read(), do_state_change(), reload_queues(), ring_entry(), and transmit_state_notify().
00135 { 00136 char *buf; 00137 char *number; 00138 const struct ast_channel_tech *chan_tech; 00139 int res = 0; 00140 /*! \brief Channel driver that provides device state */ 00141 char *tech; 00142 /*! \brief Another provider of device state */ 00143 char *provider = NULL; 00144 00145 buf = ast_strdupa(device); 00146 tech = strsep(&buf, "/"); 00147 number = buf; 00148 if (!number) { 00149 provider = strsep(&tech, ":"); 00150 if (!provider) 00151 return AST_DEVICE_INVALID; 00152 /* We have a provider */ 00153 number = tech; 00154 tech = NULL; 00155 } 00156 00157 if (provider) { 00158 if(option_debug > 2) 00159 ast_log(LOG_DEBUG, "Checking if I can find provider for \"%s\" - number: %s\n", provider, number); 00160 return getproviderstate(provider, number); 00161 } 00162 if (option_debug > 3) 00163 ast_log(LOG_DEBUG, "No provider found, checking channel drivers for %s - %s\n", tech, number); 00164 00165 chan_tech = ast_get_channel_tech(tech); 00166 if (!chan_tech) 00167 return AST_DEVICE_INVALID; 00168 00169 if (!chan_tech->devicestate) /* Does the channel driver support device state notification? */ 00170 return ast_parse_device_state(device); /* No, try the generic function */ 00171 else { 00172 res = chan_tech->devicestate(number); /* Ask the channel driver for device state */ 00173 if (res == AST_DEVICE_UNKNOWN) { 00174 res = ast_parse_device_state(device); 00175 /* at this point we know the device exists, but the channel driver 00176 could not give us a state; if there is no channel state available, 00177 it must be 'not in use' 00178 */ 00179 if (res == AST_DEVICE_UNKNOWN) 00180 res = AST_DEVICE_NOT_INUSE; 00181 return res; 00182 } else 00183 return res; 00184 } 00185 }
int ast_device_state_changed | ( | const char * | fmt, | |
... | ||||
) |
Accept change notification, add it to change queue.
Definition at line 360 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(), devstate_write(), 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().
00361 { 00362 char buf[AST_MAX_EXTENSION]; 00363 va_list ap; 00364 00365 va_start(ap, fmt); 00366 vsnprintf(buf, sizeof(buf), fmt, ap); 00367 va_end(ap); 00368 return __ast_device_state_changed_literal(buf, 0, NULL, NULL); 00369 }
int ast_device_state_changed_literal | ( | const char * | device, | |
const char * | cid_num, | |||
const char * | cid_name | |||
) |
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 346 of file devicestate.c.
References __ast_device_state_changed_literal(), and ast_strdupa.
Referenced by action_devstate(), ast_channel_free(), ast_setstate_and_callerid(), devstate_cli(), and devstate_exec().
00347 { 00348 char *buf; 00349 char *buf2 = NULL; 00350 char *buf3 = NULL; 00351 buf = ast_strdupa(dev); 00352 if (cid_num) 00353 buf2 = ast_strdupa(cid_num); 00354 if (cid_name) 00355 buf3 = ast_strdupa(cid_name); 00356 return __ast_device_state_changed_literal(buf, 0, buf2, buf3); 00357 }
int ast_device_state_engine_init | ( | void | ) |
Initialize the device state engine in separate thread.
Definition at line 397 of file devicestate.c.
References ast_cond_init(), ast_log(), ast_pthread_create_background, do_devstate_changes(), and LOG_ERROR.
Referenced by main().
00398 { 00399 ast_cond_init(&change_pending, NULL); 00400 if (ast_pthread_create_background(&change_thread, NULL, do_devstate_changes, NULL) < 0) { 00401 ast_log(LOG_ERROR, "Unable to start device state change thread.\n"); 00402 return -1; 00403 } 00404 00405 return 0; 00406 }
int ast_devstate_add | ( | ast_devstate_cb_type | callback, | |
void * | data | |||
) |
Add device state watcher.
Registers a device state change callback.
Definition at line 245 of file devicestate.c.
References ast_calloc, AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_UNLOCK, devstate_cb::callback, and devstate_cb::data.
Referenced by load_module().
00246 { 00247 struct devstate_cb *devcb; 00248 00249 if (!callback || !(devcb = ast_calloc(1, sizeof(*devcb)))) 00250 return -1; 00251 00252 devcb->data = data; 00253 devcb->callback = callback; 00254 00255 AST_LIST_LOCK(&devstate_cbs); 00256 AST_LIST_INSERT_HEAD(&devstate_cbs, devcb, list); 00257 AST_LIST_UNLOCK(&devstate_cbs); 00258 00259 return 0; 00260 }
void ast_devstate_del | ( | ast_devstate_cb_type | callback, | |
void * | data | |||
) |
Remove device state watcher.
Unregisters a device state change callback.
Definition at line 263 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, and free.
Referenced by unload_module().
00264 { 00265 struct devstate_cb *devcb; 00266 00267 AST_LIST_LOCK(&devstate_cbs); 00268 AST_LIST_TRAVERSE_SAFE_BEGIN(&devstate_cbs, devcb, list) { 00269 if ((devcb->callback == callback) && (devcb->data == data)) { 00270 AST_LIST_REMOVE_CURRENT(&devstate_cbs, list); 00271 free(devcb); 00272 break; 00273 } 00274 } 00275 AST_LIST_TRAVERSE_SAFE_END; 00276 AST_LIST_UNLOCK(&devstate_cbs); 00277 }
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 188 of file devicestate.c.
References ast_calloc, AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_UNLOCK, devstate_prov::callback, and devstate_prov::label.
Referenced by load_module().
00189 { 00190 struct devstate_prov *devprov; 00191 00192 if (!callback || !(devprov = ast_calloc(1, sizeof(*devprov)))) 00193 return -1; 00194 00195 devprov->callback = callback; 00196 ast_copy_string(devprov->label, label, sizeof(devprov->label)); 00197 00198 AST_LIST_LOCK(&devstate_provs); 00199 AST_LIST_INSERT_HEAD(&devstate_provs, devprov, list); 00200 AST_LIST_UNLOCK(&devstate_provs); 00201 00202 return 0; 00203 }
void ast_devstate_prov_del | ( | const char * | label | ) |
Remove device state provider.
label | to use in hint, like label:object |
Definition at line 206 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, and devstate_prov::label.
Referenced by unload_module().
00207 { 00208 struct devstate_prov *devcb; 00209 00210 AST_LIST_LOCK(&devstate_provs); 00211 AST_LIST_TRAVERSE_SAFE_BEGIN(&devstate_provs, devcb, list) { 00212 if (!strcasecmp(devcb->label, label)) { 00213 AST_LIST_REMOVE_CURRENT(&devstate_provs, list); 00214 free(devcb); 00215 break; 00216 } 00217 } 00218 AST_LIST_TRAVERSE_SAFE_END; 00219 AST_LIST_UNLOCK(&devstate_provs); 00220 }
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.
Definition at line 110 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().
00111 { 00112 struct ast_channel *chan; 00113 char match[AST_CHANNEL_NAME]; 00114 int res; 00115 00116 ast_copy_string(match, device, sizeof(match)-1); 00117 strcat(match, "-"); 00118 chan = ast_get_channel_by_name_prefix_locked(match, strlen(match)); 00119 00120 if (!chan) 00121 return AST_DEVICE_UNKNOWN; 00122 00123 if (chan->_state == AST_STATE_RINGING) 00124 res = AST_DEVICE_RINGING; 00125 else 00126 res = AST_DEVICE_INUSE; 00127 00128 ast_channel_unlock(chan); 00129 00130 return res; 00131 }
const char* devstate2str | ( | int | devstate | ) |
Find devicestate as text message for output.
Convert device state to text string for output.
Definition at line 100 of file devicestate.c.
Referenced by __queues_show(), do_state_change(), and handle_statechange().
00101 { 00102 return devstatestring[devstate]; 00103 }
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 372 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().
00373 { 00374 struct state_change *cur; 00375 00376 AST_LIST_LOCK(&state_changes); 00377 for(;;) { 00378 /* the list lock will _always_ be held at this point in the loop */ 00379 cur = AST_LIST_REMOVE_HEAD(&state_changes, list); 00380 if (cur) { 00381 /* we got an entry, so unlock the list while we process it */ 00382 AST_LIST_UNLOCK(&state_changes); 00383 do_state_change(cur->device, cur->cid_num, cur->cid_name); 00384 free(cur); 00385 AST_LIST_LOCK(&state_changes); 00386 } else { 00387 /* there was no entry, so atomically unlock the list and wait for 00388 the condition to be signalled (returns with the lock held) */ 00389 ast_cond_wait(&change_pending, &state_changes.lock); 00390 } 00391 } 00392 00393 return NULL; 00394 }
static void do_state_change | ( | const char * | device, | |
char * | cid_num, | |||
char * | cid_name | |||
) | [static] |
Notify callback watchers of change, and notify PBX core for hint updates Normally executed within a separate thread.
Definition at line 282 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().
00283 { 00284 int state; 00285 struct devstate_cb *devcb; 00286 00287 state = ast_device_state(device); 00288 if (option_debug > 2) 00289 ast_log(LOG_DEBUG, "Changing state for %s - state %d (%s)\n", device, state, devstate2str(state)); 00290 00291 AST_LIST_LOCK(&devstate_cbs); 00292 AST_LIST_TRAVERSE(&devstate_cbs, devcb, list) 00293 devcb->callback(device, state, devcb->data, cid_num, cid_name); 00294 AST_LIST_UNLOCK(&devstate_cbs); 00295 00296 ast_hint_state_changed(device, cid_num, cid_name); 00297 }
static int getproviderstate | ( | const char * | provider, | |
const char * | address | |||
) | [static] |
Get provider device state.
Definition at line 223 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().
00224 { 00225 struct devstate_prov *devprov; 00226 int res = AST_DEVICE_INVALID; 00227 00228 00229 AST_LIST_LOCK(&devstate_provs); 00230 AST_LIST_TRAVERSE_SAFE_BEGIN(&devstate_provs, devprov, list) { 00231 if(option_debug > 4) 00232 ast_log(LOG_DEBUG, "Checking provider %s with %s\n", devprov->label, provider); 00233 00234 if (!strcasecmp(devprov->label, provider)) { 00235 res = devprov->callback(address); 00236 break; 00237 } 00238 } 00239 AST_LIST_TRAVERSE_SAFE_END; 00240 AST_LIST_UNLOCK(&devstate_provs); 00241 return res; 00242 }
ast_cond_t change_pending [static] |
pthread_t change_thread = AST_PTHREADT_NULL [static] |
const char* devstatestring[] [static] |