devicestate.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628
  1. /*
  2. * Asterisk -- An open source telephony toolkit.
  3. *
  4. * Copyright (C) 1999 - 2007, Digium, Inc.
  5. *
  6. * Mark Spencer <markster@digium.com>
  7. *
  8. * See http://www.asterisk.org for more information about
  9. * the Asterisk project. Please do not directly contact
  10. * any of the maintainers of this project for assistance;
  11. * the project provides a web site, mailing lists and IRC
  12. * channels for your use.
  13. *
  14. * This program is free software, distributed under the terms of
  15. * the GNU General Public License Version 2. See the LICENSE file
  16. * at the top of the source tree.
  17. */
  18. /*! \file
  19. *
  20. * \brief Device state management
  21. *
  22. *
  23. * \author Mark Spencer <markster@digium.com>
  24. *
  25. * \arg \ref AstExtState
  26. */
  27. /*! \page AstExtState Extension and device states in Asterisk
  28. *
  29. * Asterisk has an internal system that reports states
  30. * for an extension. By using the dialplan priority -1,
  31. * also called a \b hint, a connection can be made from an
  32. * extension to one or many devices. The state of the extension
  33. * now depends on the combined state of the devices.
  34. *
  35. * The device state is basically based on the current calls.
  36. * If the devicestate engine can find a call from or to the
  37. * device, it's in use.
  38. *
  39. * Some channel drivers implement a callback function for
  40. * a better level of reporting device states. The SIP channel
  41. * has a complicated system for this, which is improved
  42. * by adding call limits to the configuration.
  43. *
  44. * Functions that want to check the status of an extension
  45. * register themself as a \b watcher.
  46. * Watchers in this system can subscribe either to all extensions
  47. * or just a specific extensions.
  48. *
  49. * For non-device related states, there's an API called
  50. * devicestate providers. This is an extendible system for
  51. * delivering state information from outside sources or
  52. * functions within Asterisk. Currently we have providers
  53. * for app_meetme.c - the conference bridge - and call
  54. * parking (metermaids).
  55. *
  56. * There are manly three subscribers to extension states
  57. * within Asterisk:
  58. * - AMI, the manager interface
  59. * - app_queue.c - the Queue dialplan application
  60. * - SIP subscriptions, a.k.a. "blinking lamps" or
  61. * "buddy lists"
  62. *
  63. * The CLI command "show hints" show last known state
  64. *
  65. * \note None of these handle user states, like an IM presence
  66. * system. res_jabber.c can subscribe and watch such states
  67. * in jabber/xmpp based systems.
  68. *
  69. * \section AstDevStateArch Architecture for devicestates
  70. *
  71. * When a channel driver or asterisk app changes state for
  72. * a watched object, it alerts the core. The core queues
  73. * a change. When the change is processed, there's a query
  74. * sent to the channel driver/provider if there's a function
  75. * to handle that, otherwise a channel walk is issued to find
  76. * a channel that involves the object.
  77. *
  78. * The changes are queued and processed by a separate thread.
  79. * This thread calls the watchers subscribing to status
  80. * changes for the object. For manager, this results
  81. * in events. For SIP, NOTIFY requests.
  82. *
  83. * - Device states
  84. * \arg \ref devicestate.c
  85. * \arg \ref devicestate.h
  86. *
  87. * \section AstExtStateArch Architecture for extension states
  88. *
  89. * Hints are connected to extension. If an extension changes state
  90. * it checks the hint devices. If there is a hint, the callbacks into
  91. * device states are checked. The aggregated state is set for the hint
  92. * and reported back.
  93. *
  94. * - Extension states
  95. * \arg \ref AstENUM ast_extension_states
  96. * \arg \ref pbx.c
  97. * \arg \ref pbx.h
  98. * - Structures
  99. * - \ref ast_state_cb struct. Callbacks for watchers
  100. * - Callback ast_state_cb_type
  101. * - \ref ast_hint struct.
  102. * - Functions
  103. * - ast_extension_state_add()
  104. * - ast_extension_state_del()
  105. * - ast_get_hint()
  106. *
  107. */
  108. #include "asterisk.h"
  109. ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
  110. #include "asterisk/_private.h"
  111. #include "asterisk/channel.h"
  112. #include "asterisk/utils.h"
  113. #include "asterisk/lock.h"
  114. #include "asterisk/linkedlists.h"
  115. #include "asterisk/devicestate.h"
  116. #include "asterisk/pbx.h"
  117. #include "asterisk/app.h"
  118. #include "asterisk/event.h"
  119. /*! \brief Device state strings for printing */
  120. static const char *devstatestring[] = {
  121. /* 0 AST_DEVICE_UNKNOWN */ "Unknown", /*!< Valid, but unknown state */
  122. /* 1 AST_DEVICE_NOT_INUSE */ "Not in use", /*!< Not used */
  123. /* 2 AST_DEVICE IN USE */ "In use", /*!< In use */
  124. /* 3 AST_DEVICE_BUSY */ "Busy", /*!< Busy */
  125. /* 4 AST_DEVICE_INVALID */ "Invalid", /*!< Invalid - not known to Asterisk */
  126. /* 5 AST_DEVICE_UNAVAILABLE */ "Unavailable", /*!< Unavailable (not registred) */
  127. /* 6 AST_DEVICE_RINGING */ "Ringing", /*!< Ring, ring, ring */
  128. /* 7 AST_DEVICE_RINGINUSE */ "Ring+Inuse", /*!< Ring and in use */
  129. /* 8 AST_DEVICE_ONHOLD */ "On Hold" /*!< On Hold */
  130. };
  131. /*! \brief A device state provider (not a channel) */
  132. struct devstate_prov {
  133. char label[40];
  134. ast_devstate_prov_cb_type callback;
  135. AST_RWLIST_ENTRY(devstate_prov) list;
  136. };
  137. /*! \brief A list of providers */
  138. static AST_RWLIST_HEAD_STATIC(devstate_provs, devstate_prov);
  139. struct state_change {
  140. AST_LIST_ENTRY(state_change) list;
  141. char device[1];
  142. };
  143. /*! \brief The state change queue. State changes are queued
  144. for processing by a separate thread */
  145. static AST_LIST_HEAD_STATIC(state_changes, state_change);
  146. /*! \brief The device state change notification thread */
  147. static pthread_t change_thread = AST_PTHREADT_NULL;
  148. /*! \brief Flag for the queue */
  149. static ast_cond_t change_pending;
  150. /*! \brief Whether or not to cache this device state value */
  151. enum devstate_cache {
  152. /*! Cache this value as it is coming from a device state provider which is
  153. * pushing up state change events to us as they happen */
  154. CACHE_ON,
  155. /*! Don't cache this result, since it was pulled from the device state provider.
  156. * We only want to cache results from device state providers that are being nice
  157. * and pushing state change events up to us as they happen. */
  158. CACHE_OFF,
  159. };
  160. /* Forward declarations */
  161. static int getproviderstate(const char *provider, const char *address);
  162. /*! \brief Find devicestate as text message for output */
  163. const char *devstate2str(enum ast_device_state devstate)
  164. {
  165. return devstatestring[devstate];
  166. }
  167. const char *ast_devstate_str(enum ast_device_state state)
  168. {
  169. const char *res = "UNKNOWN";
  170. switch (state) {
  171. case AST_DEVICE_UNKNOWN:
  172. break;
  173. case AST_DEVICE_NOT_INUSE:
  174. res = "NOT_INUSE";
  175. break;
  176. case AST_DEVICE_INUSE:
  177. res = "INUSE";
  178. break;
  179. case AST_DEVICE_BUSY:
  180. res = "BUSY";
  181. break;
  182. case AST_DEVICE_INVALID:
  183. res = "INVALID";
  184. break;
  185. case AST_DEVICE_UNAVAILABLE:
  186. res = "UNAVAILABLE";
  187. break;
  188. case AST_DEVICE_RINGING:
  189. res = "RINGING";
  190. break;
  191. case AST_DEVICE_RINGINUSE:
  192. res = "RINGINUSE";
  193. break;
  194. case AST_DEVICE_ONHOLD:
  195. res = "ONHOLD";
  196. break;
  197. case AST_DEVICE_TOTAL: /* included only for completeness */
  198. break;
  199. }
  200. return res;
  201. }
  202. enum ast_device_state ast_devstate_val(const char *val)
  203. {
  204. if (!strcasecmp(val, "NOT_INUSE"))
  205. return AST_DEVICE_NOT_INUSE;
  206. else if (!strcasecmp(val, "INUSE"))
  207. return AST_DEVICE_INUSE;
  208. else if (!strcasecmp(val, "BUSY"))
  209. return AST_DEVICE_BUSY;
  210. else if (!strcasecmp(val, "INVALID"))
  211. return AST_DEVICE_INVALID;
  212. else if (!strcasecmp(val, "UNAVAILABLE"))
  213. return AST_DEVICE_UNAVAILABLE;
  214. else if (!strcasecmp(val, "RINGING"))
  215. return AST_DEVICE_RINGING;
  216. else if (!strcasecmp(val, "RINGINUSE"))
  217. return AST_DEVICE_RINGINUSE;
  218. else if (!strcasecmp(val, "ONHOLD"))
  219. return AST_DEVICE_ONHOLD;
  220. return AST_DEVICE_UNKNOWN;
  221. }
  222. /*! \brief Find out if device is active in a call or not
  223. \note find channels with the device's name in it
  224. This function is only used for channels that does not implement
  225. devicestate natively
  226. */
  227. enum ast_device_state ast_parse_device_state(const char *device)
  228. {
  229. struct ast_channel *chan;
  230. char match[AST_CHANNEL_NAME];
  231. enum ast_device_state res;
  232. ast_copy_string(match, device, sizeof(match)-1);
  233. strcat(match, "-");
  234. chan = ast_get_channel_by_name_prefix_locked(match, strlen(match));
  235. if (!chan)
  236. return AST_DEVICE_UNKNOWN;
  237. if (chan->_state == AST_STATE_RINGING)
  238. res = AST_DEVICE_RINGING;
  239. else
  240. res = AST_DEVICE_INUSE;
  241. ast_channel_unlock(chan);
  242. return res;
  243. }
  244. static enum ast_device_state devstate_cached(const char *device)
  245. {
  246. enum ast_device_state res = AST_DEVICE_UNKNOWN;
  247. struct ast_event *event;
  248. event = ast_event_get_cached(AST_EVENT_DEVICE_STATE,
  249. AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, device,
  250. AST_EVENT_IE_END);
  251. if (!event)
  252. return res;
  253. res = ast_event_get_ie_uint(event, AST_EVENT_IE_STATE);
  254. ast_event_destroy(event);
  255. return res;
  256. }
  257. /*! \brief Check device state through channel specific function or generic function */
  258. static enum ast_device_state _ast_device_state(const char *device, int check_cache)
  259. {
  260. char *buf;
  261. char *number;
  262. const struct ast_channel_tech *chan_tech;
  263. enum ast_device_state res;
  264. /*! \brief Channel driver that provides device state */
  265. char *tech;
  266. /*! \brief Another provider of device state */
  267. char *provider = NULL;
  268. /* If the last known state is cached, just return that */
  269. if (check_cache) {
  270. res = devstate_cached(device);
  271. if (res != AST_DEVICE_UNKNOWN) {
  272. return res;
  273. }
  274. }
  275. buf = ast_strdupa(device);
  276. tech = strsep(&buf, "/");
  277. if (!(number = buf)) {
  278. if (!(provider = strsep(&tech, ":")))
  279. return AST_DEVICE_INVALID;
  280. /* We have a provider */
  281. number = tech;
  282. tech = NULL;
  283. }
  284. if (provider) {
  285. ast_debug(3, "Checking if I can find provider for \"%s\" - number: %s\n", provider, number);
  286. return getproviderstate(provider, number);
  287. }
  288. ast_debug(4, "No provider found, checking channel drivers for %s - %s\n", tech, number);
  289. if (!(chan_tech = ast_get_channel_tech(tech)))
  290. return AST_DEVICE_INVALID;
  291. if (!(chan_tech->devicestate)) /* Does the channel driver support device state notification? */
  292. return ast_parse_device_state(device); /* No, try the generic function */
  293. res = chan_tech->devicestate(number);
  294. if (res != AST_DEVICE_UNKNOWN)
  295. return res;
  296. res = ast_parse_device_state(device);
  297. if (res == AST_DEVICE_UNKNOWN)
  298. return AST_DEVICE_NOT_INUSE;
  299. return res;
  300. }
  301. enum ast_device_state ast_device_state(const char *device)
  302. {
  303. /* This function is called from elsewhere in the code to find out the
  304. * current state of a device. Check the cache, first. */
  305. return _ast_device_state(device, 1);
  306. }
  307. /*! \brief Add device state provider */
  308. int ast_devstate_prov_add(const char *label, ast_devstate_prov_cb_type callback)
  309. {
  310. struct devstate_prov *devprov;
  311. if (!callback || !(devprov = ast_calloc(1, sizeof(*devprov))))
  312. return -1;
  313. devprov->callback = callback;
  314. ast_copy_string(devprov->label, label, sizeof(devprov->label));
  315. AST_RWLIST_WRLOCK(&devstate_provs);
  316. AST_RWLIST_INSERT_HEAD(&devstate_provs, devprov, list);
  317. AST_RWLIST_UNLOCK(&devstate_provs);
  318. return 0;
  319. }
  320. /*! \brief Remove device state provider */
  321. int ast_devstate_prov_del(const char *label)
  322. {
  323. struct devstate_prov *devcb;
  324. int res = -1;
  325. AST_RWLIST_WRLOCK(&devstate_provs);
  326. AST_RWLIST_TRAVERSE_SAFE_BEGIN(&devstate_provs, devcb, list) {
  327. if (!strcasecmp(devcb->label, label)) {
  328. AST_RWLIST_REMOVE_CURRENT(list);
  329. ast_free(devcb);
  330. res = 0;
  331. break;
  332. }
  333. }
  334. AST_RWLIST_TRAVERSE_SAFE_END;
  335. AST_RWLIST_UNLOCK(&devstate_provs);
  336. return res;
  337. }
  338. /*! \brief Get provider device state */
  339. static int getproviderstate(const char *provider, const char *address)
  340. {
  341. struct devstate_prov *devprov;
  342. int res = AST_DEVICE_INVALID;
  343. AST_RWLIST_RDLOCK(&devstate_provs);
  344. AST_RWLIST_TRAVERSE(&devstate_provs, devprov, list) {
  345. ast_debug(5, "Checking provider %s with %s\n", devprov->label, provider);
  346. if (!strcasecmp(devprov->label, provider)) {
  347. res = devprov->callback(address);
  348. break;
  349. }
  350. }
  351. AST_RWLIST_UNLOCK(&devstate_provs);
  352. return res;
  353. }
  354. static void devstate_event(const char *device, enum ast_device_state state, enum devstate_cache cache)
  355. {
  356. struct ast_event *event;
  357. if (!(event = ast_event_new(AST_EVENT_DEVICE_STATE,
  358. AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, device,
  359. AST_EVENT_IE_STATE, AST_EVENT_IE_PLTYPE_UINT, state,
  360. AST_EVENT_IE_END))) {
  361. return;
  362. }
  363. if (cache == CACHE_ON) {
  364. /* Cache this event, replacing an event in the cache with the same
  365. * device name if it exists. */
  366. ast_event_queue_and_cache(event,
  367. AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR,
  368. AST_EVENT_IE_END);
  369. } else {
  370. ast_event_queue(event);
  371. }
  372. }
  373. /*! Called by the state change thread to find out what the state is, and then
  374. * to queue up the state change event */
  375. static void do_state_change(const char *device)
  376. {
  377. enum ast_device_state state;
  378. state = _ast_device_state(device, 0);
  379. ast_debug(3, "Changing state for %s - state %d (%s)\n", device, state, devstate2str(state));
  380. devstate_event(device, state, CACHE_OFF);
  381. }
  382. int ast_devstate_changed_literal(enum ast_device_state state, const char *device)
  383. {
  384. struct state_change *change;
  385. ast_debug(3, "Notification of state change to be queued on device/channel %s\n", device);
  386. if (state != AST_DEVICE_UNKNOWN) {
  387. devstate_event(device, state, CACHE_ON);
  388. } else if (change_thread == AST_PTHREADT_NULL || !(change = ast_calloc(1, sizeof(*change) + strlen(device)))) {
  389. /* we could not allocate a change struct, or */
  390. /* there is no background thread, so process the change now */
  391. do_state_change(device);
  392. } else {
  393. /* queue the change */
  394. strcpy(change->device, device);
  395. AST_LIST_LOCK(&state_changes);
  396. AST_LIST_INSERT_TAIL(&state_changes, change, list);
  397. ast_cond_signal(&change_pending);
  398. AST_LIST_UNLOCK(&state_changes);
  399. }
  400. return 1;
  401. }
  402. int ast_device_state_changed_literal(const char *dev)
  403. {
  404. return ast_devstate_changed_literal(AST_DEVICE_UNKNOWN, dev);
  405. }
  406. int ast_devstate_changed(enum ast_device_state state, const char *fmt, ...)
  407. {
  408. char buf[AST_MAX_EXTENSION];
  409. va_list ap;
  410. va_start(ap, fmt);
  411. vsnprintf(buf, sizeof(buf), fmt, ap);
  412. va_end(ap);
  413. return ast_devstate_changed_literal(state, buf);
  414. }
  415. /*! \brief Accept change notification, add it to change queue */
  416. int ast_device_state_changed(const char *fmt, ...)
  417. {
  418. char buf[AST_MAX_EXTENSION];
  419. va_list ap;
  420. va_start(ap, fmt);
  421. vsnprintf(buf, sizeof(buf), fmt, ap);
  422. va_end(ap);
  423. return ast_devstate_changed_literal(AST_DEVICE_UNKNOWN, buf);
  424. }
  425. /*! \brief Go through the dev state change queue and update changes in the dev state thread */
  426. static void *do_devstate_changes(void *data)
  427. {
  428. struct state_change *next, *current;
  429. for (;;) {
  430. /* This basically pops off any state change entries, resets the list back to NULL, unlocks, and processes each state change */
  431. AST_LIST_LOCK(&state_changes);
  432. if (AST_LIST_EMPTY(&state_changes))
  433. ast_cond_wait(&change_pending, &state_changes.lock);
  434. next = AST_LIST_FIRST(&state_changes);
  435. AST_LIST_HEAD_INIT_NOLOCK(&state_changes);
  436. AST_LIST_UNLOCK(&state_changes);
  437. /* Process each state change */
  438. while ((current = next)) {
  439. next = AST_LIST_NEXT(current, list);
  440. do_state_change(current->device);
  441. ast_free(current);
  442. }
  443. }
  444. return NULL;
  445. }
  446. /*! \brief Initialize the device state engine in separate thread */
  447. int ast_device_state_engine_init(void)
  448. {
  449. ast_cond_init(&change_pending, NULL);
  450. if (ast_pthread_create_background(&change_thread, NULL, do_devstate_changes, NULL) < 0) {
  451. ast_log(LOG_ERROR, "Unable to start device state change thread.\n");
  452. return -1;
  453. }
  454. return 0;
  455. }
  456. void ast_devstate_aggregate_init(struct ast_devstate_aggregate *agg)
  457. {
  458. memset(agg, 0, sizeof(*agg));
  459. agg->all_unknown = 1;
  460. agg->all_unavail = 1;
  461. agg->all_busy = 1;
  462. agg->all_free = 1;
  463. }
  464. void ast_devstate_aggregate_add(struct ast_devstate_aggregate *agg, enum ast_device_state state)
  465. {
  466. switch (state) {
  467. case AST_DEVICE_NOT_INUSE:
  468. agg->all_unknown = 0;
  469. agg->all_unavail = 0;
  470. agg->all_busy = 0;
  471. break;
  472. case AST_DEVICE_INUSE:
  473. agg->in_use = 1;
  474. agg->all_unavail = 0;
  475. agg->all_free = 0;
  476. agg->all_unknown = 0;
  477. break;
  478. case AST_DEVICE_RINGING:
  479. agg->ring = 1;
  480. agg->all_unavail = 0;
  481. agg->all_free = 0;
  482. agg->all_unknown = 0;
  483. break;
  484. case AST_DEVICE_RINGINUSE:
  485. agg->in_use = 1;
  486. agg->ring = 1;
  487. agg->all_unavail = 0;
  488. agg->all_free = 0;
  489. agg->all_unknown = 0;
  490. break;
  491. case AST_DEVICE_ONHOLD:
  492. agg->all_unknown = 0;
  493. agg->all_unavail = 0;
  494. agg->all_free = 0;
  495. agg->on_hold = 1;
  496. break;
  497. case AST_DEVICE_BUSY:
  498. agg->all_unknown = 0;
  499. agg->all_unavail = 0;
  500. agg->all_free = 0;
  501. agg->busy = 1;
  502. agg->in_use = 1;
  503. break;
  504. case AST_DEVICE_UNAVAILABLE:
  505. agg->all_unknown = 0;
  506. case AST_DEVICE_INVALID:
  507. agg->all_busy = 0;
  508. agg->all_free = 0;
  509. break;
  510. case AST_DEVICE_UNKNOWN:
  511. agg->all_busy = 0;
  512. agg->all_free = 0;
  513. break;
  514. case AST_DEVICE_TOTAL: /* not a device state, included for completeness. */
  515. break;
  516. }
  517. }
  518. enum ast_device_state ast_devstate_aggregate_result(struct ast_devstate_aggregate *agg)
  519. {
  520. if (agg->all_free)
  521. return AST_DEVICE_NOT_INUSE;
  522. if ((agg->in_use || agg->on_hold) && agg->ring)
  523. return AST_DEVICE_RINGINUSE;
  524. if (agg->ring)
  525. return AST_DEVICE_RINGING;
  526. if (agg->busy)
  527. return AST_DEVICE_BUSY;
  528. if (agg->in_use)
  529. return AST_DEVICE_INUSE;
  530. if (agg->on_hold)
  531. return AST_DEVICE_ONHOLD;
  532. if (agg->all_busy)
  533. return AST_DEVICE_BUSY;
  534. if (agg->all_unknown)
  535. return AST_DEVICE_UNKNOWN;
  536. if (agg->all_unavail)
  537. return AST_DEVICE_UNAVAILABLE;
  538. return AST_DEVICE_NOT_INUSE;
  539. }