Wed Jan 8 2020 09:49:46

Asterisk developer's documentation


devicestate.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2008, Digium, Inc.
5  *
6  * Mark Spencer <markster@digium.com>
7  * Russell Bryant <russell@digium.com>
8  *
9  * See http://www.asterisk.org for more information about
10  * the Asterisk project. Please do not directly contact
11  * any of the maintainers of this project for assistance;
12  * the project provides a web site, mailing lists and IRC
13  * channels for your use.
14  *
15  * This program is free software, distributed under the terms of
16  * the GNU General Public License Version 2. See the LICENSE file
17  * at the top of the source tree.
18  */
19 
20 /*! \file
21  *
22  * \brief Device state management
23  *
24  * \author Mark Spencer <markster@digium.com>
25  * \author Russell Bryant <russell@digium.com>
26  *
27  * \arg \ref AstExtState
28  */
29 
30 /*! \page AstExtState Extension and device states in Asterisk
31  *
32  * (Note that these descriptions of device states and extension
33  * states have not been updated to the way things work
34  * in Asterisk 1.6.)
35  *
36  * Asterisk has an internal system that reports states
37  * for an extension. By using the dialplan priority -1,
38  * also called a \b hint, a connection can be made from an
39  * extension to one or many devices. The state of the extension
40  * now depends on the combined state of the devices.
41  *
42  * The device state is basically based on the current calls.
43  * If the devicestate engine can find a call from or to the
44  * device, it's in use.
45  *
46  * Some channel drivers implement a callback function for
47  * a better level of reporting device states. The SIP channel
48  * has a complicated system for this, which is improved
49  * by adding call limits to the configuration.
50  *
51  * Functions that want to check the status of an extension
52  * register themself as a \b watcher.
53  * Watchers in this system can subscribe either to all extensions
54  * or just a specific extensions.
55  *
56  * For non-device related states, there's an API called
57  * devicestate providers. This is an extendible system for
58  * delivering state information from outside sources or
59  * functions within Asterisk. Currently we have providers
60  * for app_meetme.c - the conference bridge - and call
61  * parking (metermaids).
62  *
63  * There are manly three subscribers to extension states
64  * within Asterisk:
65  * - AMI, the manager interface
66  * - app_queue.c - the Queue dialplan application
67  * - SIP subscriptions, a.k.a. "blinking lamps" or
68  * "buddy lists"
69  *
70  * The CLI command "show hints" show last known state
71  *
72  * \note None of these handle user states, like an IM presence
73  * system. res_jabber.c can subscribe and watch such states
74  * in jabber/xmpp based systems.
75  *
76  * \section AstDevStateArch Architecture for devicestates
77  *
78  * When a channel driver or asterisk app changes state for
79  * a watched object, it alerts the core. The core queues
80  * a change. When the change is processed, there's a query
81  * sent to the channel driver/provider if there's a function
82  * to handle that, otherwise a channel walk is issued to find
83  * a channel that involves the object.
84  *
85  * The changes are queued and processed by a separate thread.
86  * This thread calls the watchers subscribing to status
87  * changes for the object. For manager, this results
88  * in events. For SIP, NOTIFY requests.
89  *
90  * - Device states
91  * \arg \ref devicestate.c
92  * \arg \ref devicestate.h
93  *
94  * \section AstExtStateArch Architecture for extension states
95  *
96  * Hints are connected to extension. If an extension changes state
97  * it checks the hint devices. If there is a hint, the callbacks into
98  * device states are checked. The aggregated state is set for the hint
99  * and reported back.
100  *
101  * - Extension states
102  * \arg \ref AstENUM ast_extension_states
103  * \arg \ref pbx.c
104  * \arg \ref pbx.h
105  * - Structures
106  * - \ref ast_state_cb struct. Callbacks for watchers
107  * - Callback ast_state_cb_type
108  * - \ref ast_hint struct.
109  * - Functions
110  * - ast_extension_state_add()
111  * - ast_extension_state_del()
112  * - ast_get_hint()
113  *
114  */
115 
116 /*** MODULEINFO
117  <support_level>core</support_level>
118  ***/
119 
120 #include "asterisk.h"
121 
122 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 413586 $")
123 
124 #include "asterisk/_private.h"
125 #include "asterisk/channel.h"
126 #include "asterisk/utils.h"
127 #include "asterisk/lock.h"
128 #include "asterisk/linkedlists.h"
129 #include "asterisk/devicestate.h"
130 #include "asterisk/pbx.h"
131 #include "asterisk/app.h"
132 #include "asterisk/event.h"
133 
134 /*! \brief Device state strings for printing */
135 static const char * const devstatestring[][2] = {
136  { /* 0 AST_DEVICE_UNKNOWN */ "Unknown", "UNKNOWN" }, /*!< Valid, but unknown state */
137  { /* 1 AST_DEVICE_NOT_INUSE */ "Not in use", "NOT_INUSE" }, /*!< Not used */
138  { /* 2 AST_DEVICE IN USE */ "In use", "INUSE" }, /*!< In use */
139  { /* 3 AST_DEVICE_BUSY */ "Busy", "BUSY" }, /*!< Busy */
140  { /* 4 AST_DEVICE_INVALID */ "Invalid", "INVALID" }, /*!< Invalid - not known to Asterisk */
141  { /* 5 AST_DEVICE_UNAVAILABLE */ "Unavailable", "UNAVAILABLE" }, /*!< Unavailable (not registered) */
142  { /* 6 AST_DEVICE_RINGING */ "Ringing", "RINGING" }, /*!< Ring, ring, ring */
143  { /* 7 AST_DEVICE_RINGINUSE */ "Ring+Inuse", "RINGINUSE" }, /*!< Ring and in use */
144  { /* 8 AST_DEVICE_ONHOLD */ "On Hold", "ONHOLD" }, /*!< On Hold */
145 };
146 
147 /*!\brief Mapping for channel states to device states */
148 static const struct chan2dev {
151 } chan2dev[] = {
162  { -100, -100 },
163 };
164 
165 /*! \brief A device state provider (not a channel) */
167  char label[40];
170 };
171 
172 /*! \brief A list of providers */
174 
175 struct state_change {
176  AST_LIST_ENTRY(state_change) list;
177  enum ast_devstate_cache cachable;
178  char device[1];
179 };
180 
181 /*! \brief The state change queue. State changes are queued
182  for processing by a separate thread */
183 static AST_LIST_HEAD_STATIC(state_changes, state_change);
184 
185 /*! \brief The device state change notification thread */
186 static pthread_t change_thread = AST_PTHREADT_NULL;
187 
188 /*! \brief Flag for the queue */
190 
192  AST_LIST_ENTRY(devstate_change) entry;
193  uint32_t state;
194  struct ast_eid eid;
195  enum ast_devstate_cache cachable;
196  char device[1];
197 };
198 
199 static struct {
200  pthread_t thread;
205  unsigned int enabled:1;
206 } devstate_collector = {
207  .thread = AST_PTHREADT_NULL,
208  .enabled = 0,
209 };
210 
211 /* Forward declarations */
212 static int getproviderstate(const char *provider, const char *address);
213 
214 /*! \brief Find devicestate as text message for output */
215 const char *ast_devstate2str(enum ast_device_state devstate)
216 {
217  return devstatestring[devstate][0];
218 }
219 
220 /* Deprecated interface (not prefixed with ast_) */
221 const char *devstate2str(enum ast_device_state devstate)
222 {
223  return devstatestring[devstate][0];
224 }
225 
227 {
228  int i;
229  chanstate &= 0xFFFF;
230  for (i = 0; chan2dev[i].chan != -100; i++) {
231  if (chan2dev[i].chan == chanstate) {
232  return chan2dev[i].dev;
233  }
234  }
235  return AST_DEVICE_UNKNOWN;
236 }
237 
238 /* Parseable */
239 const char *ast_devstate_str(enum ast_device_state state)
240 {
241  return devstatestring[state][1];
242 }
243 
245 {
246  if (!strcasecmp(val, "NOT_INUSE"))
247  return AST_DEVICE_NOT_INUSE;
248  else if (!strcasecmp(val, "INUSE"))
249  return AST_DEVICE_INUSE;
250  else if (!strcasecmp(val, "BUSY"))
251  return AST_DEVICE_BUSY;
252  else if (!strcasecmp(val, "INVALID"))
253  return AST_DEVICE_INVALID;
254  else if (!strcasecmp(val, "UNAVAILABLE"))
255  return AST_DEVICE_UNAVAILABLE;
256  else if (!strcasecmp(val, "RINGING"))
257  return AST_DEVICE_RINGING;
258  else if (!strcasecmp(val, "RINGINUSE"))
259  return AST_DEVICE_RINGINUSE;
260  else if (!strcasecmp(val, "ONHOLD"))
261  return AST_DEVICE_ONHOLD;
262 
263  return AST_DEVICE_UNKNOWN;
264 }
265 
266 /*! \brief Find out if device is active in a call or not
267  \note find channels with the device's name in it
268  This function is only used for channels that does not implement
269  devicestate natively
270 */
271 enum ast_device_state ast_parse_device_state(const char *device)
272 {
273  struct ast_channel *chan;
274  char match[AST_CHANNEL_NAME];
275  enum ast_device_state res;
276 
277  snprintf(match, sizeof(match), "%s-", device);
278 
279  if (!(chan = ast_channel_get_by_name_prefix(match, strlen(match)))) {
280  return AST_DEVICE_UNKNOWN;
281  }
282 
284 
285  chan = ast_channel_unref(chan);
286 
287  return res;
288 }
289 
290 static enum ast_device_state devstate_cached(const char *device)
291 {
293  struct ast_event *event;
294 
298 
299  if (!event)
300  return res;
301 
303 
304  ast_event_destroy(event);
305 
306  return res;
307 }
308 
309 /*! \brief Check device state through channel specific function or generic function */
310 static enum ast_device_state _ast_device_state(const char *device, int check_cache)
311 {
312  char *buf;
313  char *number;
314  const struct ast_channel_tech *chan_tech;
315  enum ast_device_state res;
316  /*! \brief Channel driver that provides device state */
317  char *tech;
318  /*! \brief Another provider of device state */
319  char *provider = NULL;
320 
321  /* If the last known state is cached, just return that */
322  if (check_cache) {
323  res = devstate_cached(device);
324  if (res != AST_DEVICE_UNKNOWN) {
325  return res;
326  }
327  }
328 
329  buf = ast_strdupa(device);
330  tech = strsep(&buf, "/");
331  if (!(number = buf)) {
332  provider = strsep(&tech, ":");
333  if (!tech) {
334  return AST_DEVICE_INVALID;
335  }
336  /* We have a provider */
337  number = tech;
338  tech = NULL;
339 
340  ast_debug(3, "Checking if I can find provider for \"%s\" - number: %s\n", provider, number);
341  return getproviderstate(provider, number);
342  }
343 
344  ast_debug(4, "No provider found, checking channel drivers for %s - %s\n", tech, number);
345 
346  if (!(chan_tech = ast_get_channel_tech(tech)))
347  return AST_DEVICE_INVALID;
348 
349  if (!(chan_tech->devicestate)) /* Does the channel driver support device state notification? */
350  return ast_parse_device_state(device); /* No, try the generic function */
351 
352  res = chan_tech->devicestate(number);
353 
354  if (res != AST_DEVICE_UNKNOWN)
355  return res;
356 
357  res = ast_parse_device_state(device);
358 
359  return res;
360 }
361 
362 enum ast_device_state ast_device_state(const char *device)
363 {
364  /* This function is called from elsewhere in the code to find out the
365  * current state of a device. Check the cache, first. */
366 
367  return _ast_device_state(device, 1);
368 }
369 
370 /*! \brief Add device state provider */
372 {
373  struct devstate_prov *devprov;
374 
375  if (!callback || !(devprov = ast_calloc(1, sizeof(*devprov))))
376  return -1;
377 
378  devprov->callback = callback;
379  ast_copy_string(devprov->label, label, sizeof(devprov->label));
380 
381  AST_RWLIST_WRLOCK(&devstate_provs);
382  AST_RWLIST_INSERT_HEAD(&devstate_provs, devprov, list);
383  AST_RWLIST_UNLOCK(&devstate_provs);
384 
385  return 0;
386 }
387 
388 /*! \brief Remove device state provider */
389 int ast_devstate_prov_del(const char *label)
390 {
391  struct devstate_prov *devcb;
392  int res = -1;
393 
394  AST_RWLIST_WRLOCK(&devstate_provs);
395  AST_RWLIST_TRAVERSE_SAFE_BEGIN(&devstate_provs, devcb, list) {
396  if (!strcasecmp(devcb->label, label)) {
398  ast_free(devcb);
399  res = 0;
400  break;
401  }
402  }
404  AST_RWLIST_UNLOCK(&devstate_provs);
405 
406  return res;
407 }
408 
409 /*! \brief Get provider device state */
410 static int getproviderstate(const char *provider, const char *address)
411 {
412  struct devstate_prov *devprov;
413  int res = AST_DEVICE_INVALID;
414 
415  AST_RWLIST_RDLOCK(&devstate_provs);
416  AST_RWLIST_TRAVERSE(&devstate_provs, devprov, list) {
417  ast_debug(5, "Checking provider %s with %s\n", devprov->label, provider);
418 
419  if (!strcasecmp(devprov->label, provider)) {
420  res = devprov->callback(address);
421  break;
422  }
423  }
424  AST_RWLIST_UNLOCK(&devstate_provs);
425 
426  return res;
427 }
428 
429 static void devstate_event(const char *device, enum ast_device_state state, int cachable)
430 {
431  struct ast_event *event;
432  enum ast_event_type event_type;
433 
434  if (devstate_collector.enabled) {
435  /* Distributed device state is enabled, so this state change is a change
436  * for a single server, not the real state. */
437  event_type = AST_EVENT_DEVICE_STATE_CHANGE;
438  } else {
439  event_type = AST_EVENT_DEVICE_STATE;
440  }
441 
442  ast_debug(3, "device '%s' state '%u'\n", device, state);
443 
444  if (!(event = ast_event_new(event_type,
448  AST_EVENT_IE_END))) {
449  return;
450  }
451 
452  if (cachable) {
454  } else {
455  ast_event_queue(event);
456  }
457 }
458 
459 /*! Called by the state change thread to find out what the state is, and then
460  * to queue up the state change event */
461 static void do_state_change(const char *device, int cachable)
462 {
463  enum ast_device_state state;
464 
465  state = _ast_device_state(device, 0);
466 
467  ast_debug(3, "Changing state for %s - state %u (%s)\n", device, state, ast_devstate2str(state));
468 
469  devstate_event(device, state, cachable);
470 }
471 
472 int ast_devstate_changed_literal(enum ast_device_state state, enum ast_devstate_cache cachable, const char *device)
473 {
474  struct state_change *change;
475 
476  /*
477  * If we know the state change (how nice of the caller of this function!)
478  * then we can just generate a device state event.
479  *
480  * Otherwise, we do the following:
481  * - Queue an event up to another thread that the state has changed
482  * - In the processing thread, it calls the callback provided by the
483  * device state provider (which may or may not be a channel driver)
484  * to determine the state.
485  * - If the device state provider does not know the state, or this is
486  * for a channel and the channel driver does not implement a device
487  * state callback, then we will look through the channel list to
488  * see if we can determine a state based on active calls.
489  * - Once a state has been determined, a device state event is generated.
490  */
491 
492  if (state != AST_DEVICE_UNKNOWN) {
493  devstate_event(device, state, cachable);
494  } else if (change_thread == AST_PTHREADT_NULL || !(change = ast_calloc(1, sizeof(*change) + strlen(device)))) {
495  /* we could not allocate a change struct, or */
496  /* there is no background thread, so process the change now */
497  do_state_change(device, cachable);
498  } else {
499  /* queue the change */
500  strcpy(change->device, device);
501  change->cachable = cachable;
502  AST_LIST_LOCK(&state_changes);
503  AST_LIST_INSERT_TAIL(&state_changes, change, list);
504  ast_cond_signal(&change_pending);
505  AST_LIST_UNLOCK(&state_changes);
506  }
507 
508  return 0;
509 }
510 
512 {
514 }
515 
516 int ast_devstate_changed(enum ast_device_state state, enum ast_devstate_cache cachable, const char *fmt, ...)
517 {
518  char buf[AST_MAX_EXTENSION];
519  va_list ap;
520 
521  va_start(ap, fmt);
522  vsnprintf(buf, sizeof(buf), fmt, ap);
523  va_end(ap);
524 
525  return ast_devstate_changed_literal(state, cachable, buf);
526 }
527 
528 int ast_device_state_changed(const char *fmt, ...)
529 {
530  char buf[AST_MAX_EXTENSION];
531  va_list ap;
532 
533  va_start(ap, fmt);
534  vsnprintf(buf, sizeof(buf), fmt, ap);
535  va_end(ap);
536 
538 }
539 
540 /*! \brief Go through the dev state change queue and update changes in the dev state thread */
541 static void *do_devstate_changes(void *data)
542 {
543  struct state_change *next, *current;
544 
545  for (;;) {
546  /* This basically pops off any state change entries, resets the list back to NULL, unlocks, and processes each state change */
547  AST_LIST_LOCK(&state_changes);
548  if (AST_LIST_EMPTY(&state_changes))
549  ast_cond_wait(&change_pending, &state_changes.lock);
550  next = AST_LIST_FIRST(&state_changes);
551  AST_LIST_HEAD_INIT_NOLOCK(&state_changes);
552  AST_LIST_UNLOCK(&state_changes);
553 
554  /* Process each state change */
555  while ((current = next)) {
556  next = AST_LIST_NEXT(current, list);
557  do_state_change(current->device, current->cachable);
558  ast_free(current);
559  }
560  }
561 
562  return NULL;
563 }
564 
565 static void destroy_devstate_change(struct devstate_change *sc)
566 {
567  ast_free(sc);
568 }
569 
570 #define MAX_SERVERS 64
572  struct devstate_change states[MAX_SERVERS];
573  size_t num_states;
574 };
575 
576 static void devstate_cache_cb(const struct ast_event *event, void *data)
577 {
578  struct change_collection *collection = data;
579  int i;
580  const struct ast_eid *eid;
581 
582  if (collection->num_states == ARRAY_LEN(collection->states)) {
583  ast_log(LOG_ERROR, "More per-server state values than we have room for (MAX_SERVERS is %d)\n",
584  MAX_SERVERS);
585  return;
586  }
587 
588  if (!(eid = ast_event_get_ie_raw(event, AST_EVENT_IE_EID))) {
589  ast_log(LOG_ERROR, "Device state change event with no EID\n");
590  return;
591  }
592 
593  i = collection->num_states;
594 
595  collection->states[i].state = ast_event_get_ie_uint(event, AST_EVENT_IE_STATE);
596  collection->states[i].eid = *eid;
597 
598  collection->num_states++;
599 }
600 
601 static void process_collection(const char *device, enum ast_devstate_cache cachable, struct change_collection *collection)
602 {
603  int i;
604  struct ast_devstate_aggregate agg;
605  enum ast_device_state state;
606  struct ast_event *event;
607 
609 
610  for (i = 0; i < collection->num_states; i++) {
611  ast_debug(1, "Adding per-server state of '%s' for '%s'\n",
612  ast_devstate2str(collection->states[i].state), device);
613  ast_devstate_aggregate_add(&agg, collection->states[i].state);
614  }
615 
616  state = ast_devstate_aggregate_result(&agg);
617 
618  ast_debug(1, "Aggregate devstate result is '%s' for '%s'\n",
619  ast_devstate2str(state), device);
620 
624 
625  if (event) {
626  enum ast_device_state old_state;
627 
628  old_state = ast_event_get_ie_uint(event, AST_EVENT_IE_STATE);
629 
630  ast_event_destroy(event);
631 
632  if (state == old_state) {
633  /* No change since last reported device state */
634  ast_debug(1, "Aggregate state for device '%s' has not changed from '%s'\n",
635  device, ast_devstate2str(state));
636  return;
637  }
638  }
639 
640  ast_debug(1, "Aggregate state for device '%s' has changed to '%s'\n",
641  device, ast_devstate2str(state));
642 
647 
648  if (!event) {
649  return;
650  }
651 
652  if (cachable) {
654  } else {
655  ast_event_queue(event);
656  }
657 }
658 
659 static void handle_devstate_change(struct devstate_change *sc)
660 {
661  struct ast_event_sub *tmp_sub;
662  struct change_collection collection = {
663  .num_states = 0,
664  };
665 
666  ast_debug(1, "Processing device state change for '%s'\n", sc->device);
667 
669  ast_log(LOG_ERROR, "Failed to create subscription\n");
670  return;
671  }
672 
674  ast_log(LOG_ERROR, "Failed to append device IE\n");
675  ast_event_sub_destroy(tmp_sub);
676  return;
677  }
678 
679  /* Populate the collection of device states from the cache */
680  ast_event_dump_cache(tmp_sub);
681 
682  process_collection(sc->device, sc->cachable, &collection);
683 
684  ast_event_sub_destroy(tmp_sub);
685 }
686 
687 static void *run_devstate_collector(void *data)
688 {
689  for (;;) {
690  struct devstate_change *sc;
691 
693  while (!(sc = AST_LIST_REMOVE_HEAD(&devstate_collector.devstate_change_q, entry)))
696 
698 
700  }
701 
702  return NULL;
703 }
704 
705 static void devstate_change_collector_cb(const struct ast_event *event, void *data)
706 {
707  struct devstate_change *sc;
708  const char *device, *cachable_str;
709  const struct ast_eid *eid;
710  uint32_t state;
712 
713  device = ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE);
716 
717  if (ast_strlen_zero(device) || !eid) {
718  ast_log(LOG_ERROR, "Invalid device state change event received\n");
719  return;
720  }
721 
722  if (!(sc = ast_calloc(1, sizeof(*sc) + strlen(device))))
723  return;
724 
725  strcpy(sc->device, device);
726  sc->eid = *eid;
727  sc->state = state;
728 
729  /* For 'cachable' we cannot use ast_event_get_ie_uint(), it overwrites the default of AST_DEVSTATE_CACHABLE we
730  * have already setup for 'cachable', if for whatever reason the AST_EVENT_IE_CACHABLE wasn't
731  * posted in the event ast_event_get_ie_uint() is going will return 0,
732  * which equates to AST_DEVSTATE_NOT_CACHABLE the first enumeration in 'ast_devstate_cache'.
733  */
734 
735  if ((cachable_str = ast_event_get_ie_str(event, AST_EVENT_IE_CACHABLE))) {
736  sscanf(cachable_str, "%30u", &cachable);
737  }
738  sc->cachable = cachable;
739 
741  AST_LIST_INSERT_TAIL(&devstate_collector.devstate_change_q, sc, entry);
744 }
745 
746 /*! \brief Initialize the device state engine in separate thread */
748 {
749  ast_cond_init(&change_pending, NULL);
751  ast_log(LOG_ERROR, "Unable to start device state change thread.\n");
752  return -1;
753  }
754 
755  return 0;
756 }
757 
759 {
760  memset(agg, 0, sizeof(*agg));
761  agg->state = AST_DEVICE_INVALID;
762 }
763 
765 {
766  static enum ast_device_state state_order[] = {
767  1, /* AST_DEVICE_UNKNOWN */
768  3, /* AST_DEVICE_NOT_INUSE */
769  6, /* AST_DEVICE_INUSE */
770  7, /* AST_DEVICE_BUSY */
771  0, /* AST_DEVICE_INVALID */
772  2, /* AST_DEVICE_UNAVAILABLE */
773  5, /* AST_DEVICE_RINGING */
774  8, /* AST_DEVICE_RINGINUSE */
775  4, /* AST_DEVICE_ONHOLD */
776  };
777 
778  if (state == AST_DEVICE_RINGING) {
779  agg->ringing = 1;
780  } else if (state == AST_DEVICE_INUSE || state == AST_DEVICE_ONHOLD || state == AST_DEVICE_BUSY) {
781  agg->inuse = 1;
782  }
783 
784  if (agg->ringing && agg->inuse) {
786  } else if (state_order[state] > state_order[agg->state]) {
787  agg->state = state;
788  }
789 }
790 
792 {
793  return agg->state;
794 }
795 
797 {
798  if (devstate_collector.enabled) {
799  return 0;
800  }
801 
803  devstate_change_collector_cb, "devicestate_engine_enable_distributed", NULL, AST_EVENT_IE_END);
804 
805  if (!devstate_collector.event_sub) {
806  ast_log(LOG_ERROR, "Failed to create subscription for the device state change collector\n");
807  return -1;
808  }
809 
811  ast_cond_init(&devstate_collector.cond, NULL);
813  ast_log(LOG_ERROR, "Unable to start device state collector thread.\n");
814  return -1;
815  }
816 
817  devstate_collector.enabled = 1;
818 
819  return 0;
820 }
int ast_event_sub_append_ie_str(struct ast_event_sub *sub, enum ast_event_ie_type ie_type, const char *str)
Append a string parameter to a subscription.
Definition: event.c:826
A list of providers.
Definition: devicestate.c:173
enum sip_cc_notify_state state
Definition: chan_sip.c:842
pthread_t thread
Definition: app_meetme.c:962
const char * ast_devstate2str(enum ast_device_state devstate) attribute_pure
Find devicestate as text message for output.
Definition: devicestate.c:215
Main Channel structure associated with a channel.
Definition: channel.h:742
ast_device_state
Device States.
Definition: devicestate.h:51
An event.
Definition: event.c:85
enum ast_device_state dev
Definition: devicestate.c:150
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:39
Asterisk locking-related definitions:
struct state_change * next
Definition: devicestate.c:176
Asterisk main include file. File version handling, generic pbx functions.
#define AST_LIST_FIRST(head)
Returns the first entry contained in a list.
Definition: linkedlists.h:420
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
char * strsep(char **str, const char *delims)
static int getproviderstate(const char *provider, const char *address)
Get provider device state.
Definition: devicestate.c:410
static void devstate_event(const char *device, enum ast_device_state state, int cachable)
Definition: devicestate.c:429
#define AST_RWLIST_HEAD_STATIC(name, type)
Defines a structure to be used to hold a read/write list of specified type, statically initialized...
Definition: linkedlists.h:332
struct ast_channel_tech * ast_get_channel_tech(const char *name)
Get a channel technology structure by name.
Definition: channel.c:960
Definition: ast_expr2.c:325
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:2502
const char * devstate2str(enum ast_device_state devstate) attribute_pure
Convert device state to text string for output.
Definition: devicestate.c:221
Device state management.
A device state provider (not a channel)
Definition: devicestate.c:166
static struct @248 devstate_collector
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
Definition: linkedlists.h:51
struct ast_eid eid
Definition: devicestate.c:194
int ast_event_queue_and_cache(struct ast_event *event)
Queue and cache an event.
Definition: event.c:1465
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:139
struct ast_event_sub * event_sub
Definition: devicestate.c:201
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:150
static enum ast_device_state devstate_cached(const char *device)
Definition: devicestate.c:290
struct devstate_change states[MAX_SERVERS]
Definition: devicestate.c:572
enum ast_device_state ast_parse_device_state(const char *device)
Search the Channels by Name.
Definition: devicestate.c:271
ast_devstate_prov_cb_type callback
Definition: devicestate.c:168
#define AST_LIST_NEXT(elm, field)
Returns the next entry in the list after the given entry.
Definition: linkedlists.h:438
int ast_enable_distributed_devstate(void)
Enable distributed device state processing.
Definition: devicestate.c:796
int ast_devstate_prov_del(const char *label)
Remove device state provider.
Definition: devicestate.c:389
struct ast_event * ast_event_get_cached(enum ast_event_type,...)
Retrieve an event from the cache.
Definition: event.c:1342
ast_channel_state
ast_channel states
Definition: channelstate.h:35
static void devstate_cache_cb(const struct ast_event *event, void *data)
Definition: devicestate.c:576
#define ast_cond_wait(cond, mutex)
Definition: lock.h:171
#define ast_cond_init(cond, attr)
Definition: lock.h:167
int ast_devstate_prov_add(const char *label, ast_devstate_prov_cb_type callback)
Add device state provider.
Definition: devicestate.c:371
#define AST_LIST_EMPTY(head)
Checks whether the specified list contains any entries.
Definition: linkedlists.h:449
#define ast_mutex_lock(a)
Definition: lock.h:155
static void destroy_devstate_change(struct devstate_change *sc)
Definition: devicestate.c:565
static void * run_devstate_collector(void *data)
Definition: devicestate.c:687
void ast_event_sub_destroy(struct ast_event_sub *sub)
Destroy an allocated subscription.
Definition: event.c:971
enum ast_devstate_cache cachable
Definition: devicestate.c:177
struct @248::@251 devstate_change_q
#define ast_cond_signal(cond)
Definition: lock.h:169
An Entity ID is essentially a MAC address, brief and unique.
Definition: utils.h:808
Entity ID Used by All events Payload type: RAW This IE indicates which server the event originated fr...
Definition: event_defs.h:266
enum ast_device_state ast_devstate_aggregate_result(struct ast_devstate_aggregate *agg)
Get the aggregate device state result.
Definition: devicestate.c:791
Utility functions.
struct ast_channel * ast_channel_get_by_name_prefix(const char *name, size_t name_len)
Find a channel by a name prefix.
Definition: channel.c:1808
pthread_cond_t ast_cond_t
Definition: lock.h:144
#define ast_pthread_create_background(a, b, c, d)
Definition: utils.h:426
Number structure.
Definition: app_followme.c:109
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
Definition: linkedlists.h:77
#define AST_RWLIST_INSERT_HEAD
Definition: linkedlists.h:703
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:236
int ast_event_queue(struct ast_event *event)
Queue an event.
Definition: event.c:1517
ast_event_type
Event types.
Definition: event_defs.h:30
int ast_devstate_changed(enum ast_device_state state, enum ast_devstate_cache cachable, const char *fmt,...)
Tells Asterisk the State for Device is changed.
Definition: devicestate.c:516
uint32_t state
Definition: devicestate.c:193
enum ast_device_state ast_devstate_val(const char *val)
Convert device state from text to integer value.
Definition: devicestate.c:244
General Asterisk PBX channel definitions.
static void do_state_change(const char *device, int cachable)
Definition: devicestate.c:461
int ast_device_state_changed(const char *fmt,...)
Tells Asterisk the State for Device is changed. (Accept change notification, add it to change queue...
Definition: devicestate.c:528
unsigned int enabled
Definition: devicestate.c:205
#define AST_PTHREADT_NULL
Definition: lock.h:65
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
ast_mutex_t lock
Definition: app_meetme.c:964
ast_cond_t cond
Definition: app_meetme.c:963
#define AST_MAX_EXTENSION
Definition: channel.h:135
#define AST_RWLIST_TRAVERSE
Definition: linkedlists.h:493
#define AST_RWLIST_REMOVE_CURRENT
Definition: linkedlists.h:565
A set of macros to manage forward-linked lists.
enum ast_device_state ast_state_chan2dev(enum ast_channel_state chanstate)
Convert channel state to devicestate.
Definition: devicestate.c:226
int ast_device_state_changed_literal(const char *device)
Tells Asterisk the State for Device is changed.
Definition: devicestate.c:511
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:818
unsigned int ringing
Definition: devicestate.h:266
Event non-cachability flag Used by: All events Payload type: UINT.
Definition: event_defs.h:291
Structure to describe a channel &quot;technology&quot;, ie a channel driver See for examples: ...
Definition: channel.h:507
Core PBX routines and definitions.
#define AST_RWLIST_TRAVERSE_SAFE_BEGIN
Definition: linkedlists.h:542
const void * ast_event_get_ie_raw(const struct ast_event *event, enum ast_event_ie_type ie_type)
Get the value of an information element that has a raw payload.
Definition: event.c:1111
#define AST_LIST_HEAD_STATIC(name, type)
Defines a structure to be used to hold a list of specified type, statically initialized.
Definition: linkedlists.h:290
void ast_devstate_aggregate_add(struct ast_devstate_aggregate *agg, enum ast_device_state state)
Add a device state to the aggregate device state.
Definition: devicestate.c:764
const char * ast_devstate_str(enum ast_device_state devstate) attribute_pure
Convert device state to text string that is easier to parse.
Definition: devicestate.c:239
static void devstate_change_collector_cb(const struct ast_event *event, void *data)
Definition: devicestate.c:705
enum ast_channel_state chan
Definition: devicestate.c:149
void ast_event_dump_cache(const struct ast_event_sub *event_sub)
Dump the event cache for the subscriber.
Definition: event.c:654
#define AST_LIST_HEAD_NOLOCK(name, type)
Defines a structure to be used to hold a list of specified type (with no lock).
Definition: linkedlists.h:224
unsigned char eid[6]
Definition: utils.h:809
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: utils.h:663
int ast_device_state_engine_init(void)
Initialize the device state engine in separate thread.
Definition: devicestate.c:747
static const char *const devstatestring[][2]
Device state strings for printing.
Definition: devicestate.c:135
#define MAX_SERVERS
Definition: devicestate.c:570
#define LOG_ERROR
Definition: logger.h:155
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:716
static pthread_t change_thread
The device state change notification thread.
Definition: devicestate.c:186
Event subscription.
Definition: event.c:124
enum ast_channel_state _state
Definition: channel.h:839
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
char device[1]
Definition: devicestate.c:178
enum ast_devstate_cache cachable
Definition: devicestate.c:195
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
Definition: linkedlists.h:409
ast_devstate_cache
Device State Cachability.
Definition: devicestate.h:67
static void handle_devstate_change(struct devstate_change *sc)
Definition: devicestate.c:659
enum ast_device_state(* ast_devstate_prov_cb_type)(const char *data)
Devicestate provider call back.
Definition: devicestate.h:73
#define ast_free(a)
Definition: astmm.h:97
void ast_devstate_aggregate_init(struct ast_devstate_aggregate *agg)
Initialize aggregate device state.
Definition: devicestate.c:758
#define AST_CHANNEL_NAME
Definition: channel.h:137
char label[40]
Definition: devicestate.c:167
#define AST_RWLIST_ENTRY
Definition: linkedlists.h:414
uint32_t ast_event_get_ie_uint(const struct ast_event *event, enum ast_event_ie_type ie_type)
Get the value of an information element that has an integer payload.
Definition: event.c:1075
Mapping for channel states to device states.
Definition: devicestate.c:148
static void * do_devstate_changes(void *data)
Go through the dev state change queue and update changes in the dev state thread. ...
Definition: devicestate.c:541
#define AST_LIST_HEAD_INIT_NOLOCK(head)
Initializes a list head structure.
Definition: linkedlists.h:666
int(*const devicestate)(void *data)
Definition: channel.h:521
void ast_event_destroy(struct ast_event *event)
Destroy an event.
Definition: event.c:1314
static ast_cond_t change_pending
Flag for the queue.
Definition: devicestate.c:189
struct ast_event * ast_event_new(enum ast_event_type event_type,...)
Create a new event.
Definition: event.c:1202
#define ast_calloc(a, b)
Definition: astmm.h:82
struct ast_event_sub * ast_event_subscribe(enum ast_event_type event_type, ast_event_cb_t cb, const char *description, void *userdata,...)
Subscribe to events.
Definition: event.c:909
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:223
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
You shouldn&#39;t care about the contents of this struct.
Definition: devicestate.h:265
#define ast_mutex_init(pmutex)
Definition: lock.h:152
int ast_devstate_changed_literal(enum ast_device_state state, enum ast_devstate_cache cachable, const char *device)
Tells Asterisk the State for Device is changed.
Definition: devicestate.c:472
static enum ast_device_state _ast_device_state(const char *device, int check_cache)
Check device state through channel specific function or generic function.
Definition: devicestate.c:310
Generic State IE Used by AST_EVENT_DEVICE_STATE_CHANGE Payload type: UINT The actual state values dep...
Definition: event_defs.h:115
const char * ast_event_get_ie_str(const struct ast_event *event, enum ast_event_ie_type ie_type)
Get the value of an information element that has a string payload.
Definition: event.c:1102
The state change queue. State changes are queued for processing by a separate thread.
Definition: devicestate.c:183
enum ast_device_state state
Definition: devicestate.h:268
Device Name Used by AST_EVENT_DEVICE_STATE_CHANGE Payload type: STR.
Definition: event_defs.h:107
static int match(struct sockaddr_in *sin, unsigned short callno, unsigned short dcallno, const struct chan_iax2_pvt *cur, int check_dcallno)
Definition: chan_iax2.c:2069
struct ast_event_sub * ast_event_subscribe_new(enum ast_event_type type, ast_event_cb_t cb, void *userdata)
Allocate a subscription, but do not activate it.
Definition: event.c:739
static void process_collection(const char *device, enum ast_devstate_cache cachable, struct change_collection *collection)
Definition: devicestate.c:601
#define AST_RWLIST_TRAVERSE_SAFE_END
Definition: linkedlists.h:602
Structure for mutex and tracking information.
Definition: lock.h:121
#define ASTERISK_FILE_VERSION(file, version)
Register/unregister a source code file with the core.
Definition: asterisk.h:180
#define ast_mutex_unlock(a)
Definition: lock.h:156