Asterisk - The Open Source Telephony Project GIT-master-7e7a603
app_sla.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 2022, Naveen Albert
5 *
6 * Based on previous MeetMe-based SLA Implementation by:
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 Shared Line Appearances
23 *
24 * \author Naveen Albert <asterisk@phreaknet.org>
25 *
26 * \ingroup applications
27 */
28
29/*! \li \ref app_sla.c uses configuration file \ref sla.conf
30 * \addtogroup configuration_file Configuration Files
31 */
32
33/*!
34 * \page sla.conf sla.conf
35 * \verbinclude sla.conf.sample
36 */
37
38/*** MODULEINFO
39 <depend>app_confbridge</depend>
40 <support_level>extended</support_level>
41 ***/
42
43#include "asterisk.h"
44
45#include "asterisk/lock.h"
46#include "asterisk/file.h"
47#include "asterisk/channel.h"
48#include "asterisk/pbx.h"
49#include "asterisk/module.h"
50#include "asterisk/config.h"
51#include "asterisk/app.h"
52#include "asterisk/cli.h"
53#include "asterisk/utils.h"
54#include "asterisk/astobj2.h"
56#include "asterisk/dial.h"
57#include "asterisk/causes.h"
59
60/*** DOCUMENTATION
61 <application name="SLAStation" language="en_US">
62 <synopsis>
63 Shared Line Appearance Station.
64 </synopsis>
65 <syntax>
66 <parameter name="station" required="true">
67 <para>Station name</para>
68 </parameter>
69 </syntax>
70 <description>
71 <para>This application should be executed by an SLA station. The argument depends
72 on how the call was initiated. If the phone was just taken off hook, then the argument
73 <replaceable>station</replaceable> should be just the station name. If the call was
74 initiated by pressing a line key, then the station name should be preceded by an underscore
75 and the trunk name associated with that line button.</para>
76 <para>For example: <literal>station1_line1</literal></para>
77 <para>On exit, this application will set the variable <variable>SLASTATION_STATUS</variable> to
78 one of the following values:</para>
79 <variablelist>
80 <variable name="SLASTATION_STATUS">
81 <value name="FAILURE" />
82 <value name="CONGESTION" />
83 <value name="SUCCESS" />
84 </variable>
85 </variablelist>
86 </description>
87 </application>
88 <application name="SLATrunk" language="en_US">
89 <synopsis>
90 Shared Line Appearance Trunk.
91 </synopsis>
92 <syntax>
93 <parameter name="trunk" required="true">
94 <para>Trunk name</para>
95 </parameter>
96 <parameter name="options">
97 <optionlist>
98 <option name="M" hasparams="optional">
99 <para>Play back the specified MOH <replaceable>class</replaceable>
100 instead of ringing</para>
101 <argument name="class" required="true" />
102 </option>
103 </optionlist>
104 </parameter>
105 </syntax>
106 <description>
107 <para>This application should be executed by an SLA trunk on an inbound call. The channel calling
108 this application should correspond to the SLA trunk with the name <replaceable>trunk</replaceable>
109 that is being passed as an argument.</para>
110 <para>On exit, this application will set the variable <variable>SLATRUNK_STATUS</variable> to
111 one of the following values:</para>
112 <variablelist>
113 <variable name="SLATRUNK_STATUS">
114 <value name="FAILURE" />
115 <value name="SUCCESS" />
116 <value name="UNANSWERED" />
117 <value name="RINGTIMEOUT" />
118 </variable>
119 </variablelist>
120 </description>
121 </application>
122 ***/
123
124#define SLA_CONFIG_FILE "sla.conf"
125#define MAX_CONFNUM 80
126
127static const char * const slastation_app = "SLAStation";
128static const char * const slatrunk_app = "SLATrunk";
129
130enum {
131 /*! If set there will be no enter or leave sounds */
132 CONFFLAG_QUIET = (1 << 0),
133 /*! Set to have music on hold when user is alone in conference */
134 CONFFLAG_MOH = (1 << 1),
135 /*! If set, the channel will leave the conference if all marked users leave */
137 /*! If set, the user will be marked */
139 /*! Pass DTMF through the conference */
143};
144
145enum {
147};
148
149enum {
152};
153
157
161};
162
169};
170
172 /*! This means that any station can put it on hold, and any station
173 * can retrieve the call from hold. */
175 /*! This means that only the station that put the call on hold may
176 * retrieve it from hold. */
178};
179
180struct sla_trunk_ref;
181
186 AST_STRING_FIELD(device);
187 AST_STRING_FIELD(autocontext);
188 );
190 struct ast_dial *dial;
191 /*! Ring timeout for this station, for any trunk. If a ring timeout
192 * is set for a specific trunk on this station, that will take
193 * priority over this value. */
194 unsigned int ring_timeout;
195 /*! Ring delay for this station, for any trunk. If a ring delay
196 * is set for a specific trunk on this station, that will take
197 * priority over this value. */
198 unsigned int ring_delay;
199 /*! This option uses the values in the sla_hold_access enum and sets the
200 * access control type for hold on this station. */
201 unsigned int hold_access:1;
202 /*! Mark used during reload processing */
203 unsigned int mark:1;
204};
205
206/*!
207 * \brief A reference to a station
208 *
209 * This struct looks near useless at first glance. However, its existence
210 * in the list of stations in sla_trunk means that this station references
211 * that trunk. We use the mark to keep track of whether it needs to be
212 * removed from the sla_trunk's list of stations during a reload.
213 */
217 /*! Mark used during reload processing */
218 unsigned int mark:1;
219};
220
221struct sla_trunk {
226 );
228 /*! Number of stations that use this trunk */
229 unsigned int num_stations;
230 /*! Number of stations currently on a call with this trunk */
231 unsigned int active_stations;
232 /*! Number of stations that have this trunk on hold. */
233 unsigned int hold_stations;
235 unsigned int ring_timeout;
236 /*! If set to 1, no station will be able to join an active call with
237 * this trunk. */
238 unsigned int barge_disabled:1;
239 /*! This option uses the values in the sla_hold_access enum and sets the
240 * access control type for hold on this trunk. */
241 unsigned int hold_access:1;
242 /*! Whether this trunk is currently on hold, meaning that once a station
243 * connects to it, the trunk channel needs to have UNHOLD indicated to it. */
244 unsigned int on_hold:1;
245 /*! Mark used during reload processing */
246 unsigned int mark:1;
247};
248
249/*!
250 * \brief A station's reference to a trunk
251 *
252 * An sla_station keeps a list of trunk_refs. This holds metadata about the
253 * stations usage of the trunk.
254 */
260 /*! Ring timeout to use when this trunk is ringing on this specific
261 * station. This takes higher priority than a ring timeout set at
262 * the station level. */
263 unsigned int ring_timeout;
264 /*! Ring delay to use when this trunk is ringing on this specific
265 * station. This takes higher priority than a ring delay set at
266 * the station level. */
267 unsigned int ring_delay;
268 /*! Mark used during reload processing */
269 unsigned int mark:1;
270};
271
274
275static const char sla_registrar[] = "SLA";
276
277/*! \brief Event types that can be queued up for the SLA thread */
279 /*! A station has put the call on hold */
281 /*! The state of a dial has changed */
283 /*! The state of a ringing trunk has changed */
285};
286
287struct sla_event {
292};
293
294/*! \brief A station that failed to be dialed
295 * \note Only used by the SLA thread. */
298 struct timeval last_try;
300};
301
302/*! \brief A trunk that is ringing */
305 /*! The time that this trunk started ringing */
306 struct timeval ring_begin;
309};
310
314};
315
316/*! \brief A station that is ringing */
319 /*! The time that this station started ringing */
320 struct timeval ring_begin;
322};
323
324/*!
325 * \brief A structure for data used by the sla thread
326 */
327static struct {
328 /*! The SLA thread ID */
329 pthread_t thread;
336 unsigned int stop:1;
337 /*! Attempt to handle CallerID, even though it is known not to work
338 * properly in some situations. */
339 unsigned int attempt_callerid:1;
340} sla = {
341 .thread = AST_PTHREADT_NULL,
343
344static const char *sla_hold_str(unsigned int hold_access)
345{
346 const char *hold = "Unknown";
347
348 switch (hold_access) {
349 case SLA_HOLD_OPEN:
350 hold = "Open";
351 break;
352 case SLA_HOLD_PRIVATE:
353 hold = "Private";
354 default:
355 break;
356 }
357
358 return hold;
359}
360
361static char *sla_show_trunks(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
362{
363 struct ao2_iterator i;
364 struct sla_trunk *trunk;
365
366 switch (cmd) {
367 case CLI_INIT:
368 e->command = "sla show trunks";
369 e->usage =
370 "Usage: sla show trunks\n"
371 " This will list all trunks defined in sla.conf\n";
372 return NULL;
373 case CLI_GENERATE:
374 return NULL;
375 }
376
377 ast_cli(a->fd, "\n"
378 "=============================================================\n"
379 "=== Configured SLA Trunks ===================================\n"
380 "=============================================================\n"
381 "===\n");
383 for (; (trunk = ao2_iterator_next(&i)); ao2_ref(trunk, -1)) {
384 struct sla_station_ref *station_ref;
385 char ring_timeout[23] = "(none)";
386
387 ao2_lock(trunk);
388
389 if (trunk->ring_timeout) {
390 snprintf(ring_timeout, sizeof(ring_timeout), "%u Seconds", trunk->ring_timeout);
391 }
392
393 ast_cli(a->fd, "=== ---------------------------------------------------------\n"
394 "=== Trunk Name: %s\n"
395 "=== ==> Device: %s\n"
396 "=== ==> AutoContext: %s\n"
397 "=== ==> RingTimeout: %s\n"
398 "=== ==> BargeAllowed: %s\n"
399 "=== ==> HoldAccess: %s\n"
400 "=== ==> Stations ...\n",
401 trunk->name, trunk->device,
402 S_OR(trunk->autocontext, "(none)"),
403 ring_timeout,
404 trunk->barge_disabled ? "No" : "Yes",
405 sla_hold_str(trunk->hold_access));
406
407 AST_LIST_TRAVERSE(&trunk->stations, station_ref, entry) {
408 ast_cli(a->fd, "=== ==> Station name: %s\n", station_ref->station->name);
409 }
410
411 ast_cli(a->fd, "=== ---------------------------------------------------------\n===\n");
412
413 ao2_unlock(trunk);
414 }
416 ast_cli(a->fd, "=============================================================\n\n");
417
418 return CLI_SUCCESS;
419}
420
421static const char *trunkstate2str(enum sla_trunk_state state)
422{
423#define S(e) case e: return # e;
424 switch (state) {
430 }
431 return "Uknown State";
432#undef S
433}
434
435static char *sla_show_stations(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
436{
437 struct ao2_iterator i;
438 struct sla_station *station;
439
440 switch (cmd) {
441 case CLI_INIT:
442 e->command = "sla show stations";
443 e->usage =
444 "Usage: sla show stations\n"
445 " This will list all stations defined in sla.conf\n";
446 return NULL;
447 case CLI_GENERATE:
448 return NULL;
449 }
450
451 ast_cli(a->fd, "\n"
452 "=============================================================\n"
453 "=== Configured SLA Stations =================================\n"
454 "=============================================================\n"
455 "===\n");
457 for (; (station = ao2_iterator_next(&i)); ao2_ref(station, -1)) {
458 struct sla_trunk_ref *trunk_ref;
459 char ring_timeout[16] = "(none)";
460 char ring_delay[16] = "(none)";
461
462 ao2_lock(station);
463
464 if (station->ring_timeout) {
465 snprintf(ring_timeout, sizeof(ring_timeout), "%u", station->ring_timeout);
466 }
467 if (station->ring_delay) {
468 snprintf(ring_delay, sizeof(ring_delay), "%u", station->ring_delay);
469 }
470 ast_cli(a->fd, "=== ---------------------------------------------------------\n"
471 "=== Station Name: %s\n"
472 "=== ==> Device: %s\n"
473 "=== ==> AutoContext: %s\n"
474 "=== ==> RingTimeout: %s\n"
475 "=== ==> RingDelay: %s\n"
476 "=== ==> HoldAccess: %s\n"
477 "=== ==> Trunks ...\n",
478 station->name, station->device,
479 S_OR(station->autocontext, "(none)"),
481 sla_hold_str(station->hold_access));
482 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
483 if (trunk_ref->ring_timeout) {
484 snprintf(ring_timeout, sizeof(ring_timeout), "%u", trunk_ref->ring_timeout);
485 } else {
486 strcpy(ring_timeout, "(none)");
487 }
488 if (trunk_ref->ring_delay) {
489 snprintf(ring_delay, sizeof(ring_delay), "%u", trunk_ref->ring_delay);
490 } else {
491 strcpy(ring_delay, "(none)");
492 }
493
494 ast_cli(a->fd, "=== ==> Trunk Name: %s\n"
495 "=== ==> State: %s\n"
496 "=== ==> RingTimeout: %s\n"
497 "=== ==> RingDelay: %s\n",
498 trunk_ref->trunk->name,
499 trunkstate2str(trunk_ref->state),
501 }
502 ast_cli(a->fd, "=== ---------------------------------------------------------\n"
503 "===\n");
504
505 ao2_unlock(station);
506 }
508 ast_cli(a->fd, "============================================================\n"
509 "\n");
510
511 return CLI_SUCCESS;
512}
513
514static struct ast_cli_entry cli_sla[] = {
515 AST_CLI_DEFINE(sla_show_trunks, "Show SLA Trunks"),
516 AST_CLI_DEFINE(sla_show_stations, "Show SLA Stations"),
517};
518
519static void sla_queue_event_full(enum sla_event_type type, struct sla_trunk_ref *trunk_ref, struct sla_station *station, int lock)
520{
521 struct sla_event *event;
522
523 if (sla.thread == AST_PTHREADT_NULL) {
524 ao2_ref(station, -1);
525 ao2_ref(trunk_ref, -1);
526 return;
527 }
528
529 if (!(event = ast_calloc(1, sizeof(*event)))) {
530 ao2_ref(station, -1);
531 ao2_ref(trunk_ref, -1);
532 return;
533 }
534
535 event->type = type;
536 event->trunk_ref = trunk_ref;
537 event->station = station;
538
539 if (!lock) {
541 return;
542 }
543
544 ast_mutex_lock(&sla.lock);
546 ast_cond_signal(&sla.cond);
547 ast_mutex_unlock(&sla.lock);
548}
549
551{
553}
554
556{
558}
559
560/*! \brief Queue a SLA event from the conference */
561static void sla_queue_event_conf(enum sla_event_type type, struct ast_channel *chan, const char *confname)
562{
563 struct sla_station *station;
564 struct sla_trunk_ref *trunk_ref = NULL;
565 char *trunk_name;
566 struct ao2_iterator i;
567
568 trunk_name = ast_strdupa(confname);
569 strsep(&trunk_name, "_");
570 if (ast_strlen_zero(trunk_name)) {
571 ast_log(LOG_ERROR, "Invalid conference name for SLA - '%s'!\n", confname);
572 return;
573 }
574
576 while ((station = ao2_iterator_next(&i))) {
577 ao2_lock(station);
578 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
579 if (trunk_ref->chan == chan && !strcmp(trunk_ref->trunk->name, trunk_name)) {
580 ao2_ref(trunk_ref, 1);
581 break;
582 }
583 }
584 ao2_unlock(station);
585 if (trunk_ref) {
586 /* station reference given to sla_queue_event_full() */
587 break;
588 }
589 ao2_ref(station, -1);
590 }
592
593 if (!trunk_ref) {
594 ast_debug(1, "Trunk not found for event!\n");
595 return;
596 }
597
598 sla_queue_event_full(type, trunk_ref, station, 1);
599}
600
601/*!
602 * \brief Framehook to support HOLD within the conference
603 */
604
607 char *confname;
608};
609
611 .type = "app_sla",
612};
613
614static int remove_framehook(struct ast_channel *chan)
615{
616 struct ast_datastore *datastore = NULL;
617 struct sla_framehook_data *data;
618 SCOPED_CHANNELLOCK(chan_lock, chan);
619
621 if (!datastore) {
622 ast_log(AST_LOG_WARNING, "Cannot remove framehook from %s: HOLD_INTERCEPT not currently enabled\n", ast_channel_name(chan));
623 return -1;
624 }
625 data = datastore->data;
626
627 ast_free(data->confname);
628
629 if (ast_framehook_detach(chan, data->framehook_id)) {
630 ast_log(AST_LOG_WARNING, "Failed to remove framehook from channel %s\n", ast_channel_name(chan));
631 return -1;
632 }
633 if (ast_channel_datastore_remove(chan, datastore)) {
634 ast_log(AST_LOG_WARNING, "Failed to remove datastore from channel %s\n", ast_channel_name(chan));
635 return -1;
636 }
637 ast_datastore_free(datastore);
638
639 return 0;
640}
641
642static struct ast_frame *sla_framehook(struct ast_channel *chan, struct ast_frame *f, enum ast_framehook_event event, void *data)
643{
644 struct sla_framehook_data *sla_data = data;
645 if (!f || (event != AST_FRAMEHOOK_EVENT_WRITE)) {
646 return f;
647 }
650 }
651 return f;
652}
653
654/*! \brief Callback function which informs upstream if we are consuming a frame of a specific type */
655static int sla_framehook_consume(void *data, enum ast_frame_type type)
656{
657 return (type == AST_FRAME_CONTROL ? 1 : 0);
658}
659
660static int attach_framehook(struct ast_channel *chan, const char *confname)
661{
662 struct ast_datastore *datastore;
663 struct sla_framehook_data *data;
664 static struct ast_framehook_interface sla_framehook_interface = {
666 .event_cb = sla_framehook,
667 .consume_cb = sla_framehook_consume,
668 .disable_inheritance = 1,
669 };
670 SCOPED_CHANNELLOCK(chan_lock, chan);
671
673 if (datastore) {
674 ast_log(AST_LOG_WARNING, "SLA framehook already set on '%s'\n", ast_channel_name(chan));
675 return 0;
676 }
677
679 if (!datastore) {
680 return -1;
681 }
682
683 data = ast_calloc(1, sizeof(*data));
684 if (!data) {
685 ast_datastore_free(datastore);
686 return -1;
687 }
688
689 data->framehook_id = ast_framehook_attach(chan, &sla_framehook_interface);
690 data->confname = ast_strdup(confname);
691 if (!data->confname || data->framehook_id < 0) {
692 ast_log(AST_LOG_WARNING, "Failed to attach SLA framehook to '%s'\n", ast_channel_name(chan));
693 ast_datastore_free(datastore);
694 ast_free(data);
695 return -1;
696 }
697 datastore->data = data;
698
699 ast_channel_datastore_add(chan, datastore);
700 return 0;
701}
702
703/*!
704 * \internal
705 * \brief Find an SLA trunk by name
706 */
707static struct sla_trunk *sla_find_trunk(const char *name)
708{
709 struct sla_trunk tmp_trunk = {
710 .name = name,
711 };
712
713 return ao2_find(sla_trunks, &tmp_trunk, OBJ_POINTER);
714}
715
716/*!
717 * \internal
718 * \brief Find an SLA station by name
719 */
720static struct sla_station *sla_find_station(const char *name)
721{
722 struct sla_station tmp_station = {
723 .name = name,
724 };
725
726 return ao2_find(sla_stations, &tmp_station, OBJ_POINTER);
727}
728
729static int sla_check_station_hold_access(const struct sla_trunk *trunk, const struct sla_station *station)
730{
731 struct sla_station_ref *station_ref;
732 struct sla_trunk_ref *trunk_ref;
733
734 /* For each station that has this call on hold, check for private hold. */
735 AST_LIST_TRAVERSE(&trunk->stations, station_ref, entry) {
736 AST_LIST_TRAVERSE(&station_ref->station->trunks, trunk_ref, entry) {
737 if (trunk_ref->trunk != trunk || station_ref->station == station) {
738 continue;
739 }
740 if (trunk_ref->state == SLA_TRUNK_STATE_ONHOLD_BYME && station_ref->station->hold_access == SLA_HOLD_PRIVATE) {
741 return 1;
742 }
743 return 0;
744 }
745 }
746
747 return 0;
748}
749
750/*!
751 * \brief Find a trunk reference on a station by name
752 * \param station the station
753 * \param name the trunk's name
754 * \pre sla_station is locked
755 * \return a pointer to the station's trunk reference. If the trunk
756 * is not found, it is not idle and barge is disabled, or if
757 * it is on hold and private hold is set, then NULL will be returned.
758 */
759static struct sla_trunk_ref *sla_find_trunk_ref_byname(const struct sla_station *station, const char *name)
760{
761 struct sla_trunk_ref *trunk_ref = NULL;
762
763 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
764 if (strcasecmp(trunk_ref->trunk->name, name)) {
765 continue;
766 }
767
768 if (trunk_ref->trunk->barge_disabled && trunk_ref->state == SLA_TRUNK_STATE_UP) {
769 ast_debug(2, "Barge disabled, trunk not available\n");
770 trunk_ref = NULL;
771 } else if (trunk_ref->trunk->hold_stations && trunk_ref->trunk->hold_access == SLA_HOLD_PRIVATE && trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) {
772 ast_debug(2, "Private hold by another station\n");
773 trunk_ref = NULL;
774 } else if (sla_check_station_hold_access(trunk_ref->trunk, station)) {
775 ast_debug(2, "No hold access\n");
776 trunk_ref = NULL;
777 }
778
779 break;
780 }
781
782 if (trunk_ref) {
783 ao2_ref(trunk_ref, 1);
784 }
785
786 return trunk_ref;
787}
788
789static void sla_station_ref_destructor(void *obj)
790{
791 struct sla_station_ref *station_ref = obj;
792
793 if (station_ref->station) {
794 ao2_ref(station_ref->station, -1);
795 station_ref->station = NULL;
796 }
797}
798
800{
801 struct sla_station_ref *station_ref;
802
803 if (!(station_ref = ao2_alloc(sizeof(*station_ref), sla_station_ref_destructor))) {
804 return NULL;
805 }
806
807 ao2_ref(station, 1);
808 station_ref->station = station;
809
810 return station_ref;
811}
812
814{
815 struct sla_ringing_station *ringing_station;
816
817 if (!(ringing_station = ast_calloc(1, sizeof(*ringing_station)))) {
818 return NULL;
819 }
820
821 ao2_ref(station, 1);
822 ringing_station->station = station;
823 ringing_station->ring_begin = ast_tvnow();
824
825 return ringing_station;
826}
827
828static void sla_ringing_station_destroy(struct sla_ringing_station *ringing_station)
829{
830 if (ringing_station->station) {
831 ao2_ref(ringing_station->station, -1);
832 ringing_station->station = NULL;
833 }
834
835 ast_free(ringing_station);
836}
837
839{
840 struct sla_failed_station *failed_station;
841
842 if (!(failed_station = ast_calloc(1, sizeof(*failed_station)))) {
843 return NULL;
844 }
845
846 ao2_ref(station, 1);
847 failed_station->station = station;
848 failed_station->last_try = ast_tvnow();
849
850 return failed_station;
851}
852
853static void sla_failed_station_destroy(struct sla_failed_station *failed_station)
854{
855 if (failed_station->station) {
856 ao2_ref(failed_station->station, -1);
857 failed_station->station = NULL;
858 }
859
860 ast_free(failed_station);
861}
862
864{
865 switch (state) {
869 return AST_DEVICE_RINGING;
871 return AST_DEVICE_INUSE;
874 return AST_DEVICE_ONHOLD;
875 }
876
877 return AST_DEVICE_UNKNOWN;
878}
879
880static void sla_change_trunk_state(const struct sla_trunk *trunk, enum sla_trunk_state state,
881 enum sla_which_trunk_refs inactive_only, const struct sla_trunk_ref *exclude)
882{
883 struct sla_station *station;
884 struct sla_trunk_ref *trunk_ref;
885 struct ao2_iterator i;
886
888 while ((station = ao2_iterator_next(&i))) {
889 ao2_lock(station);
890 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
891 if (trunk_ref->trunk != trunk || (inactive_only ? trunk_ref->chan : 0) || trunk_ref == exclude) {
892 continue;
893 }
894 trunk_ref->state = state;
895 ast_devstate_changed(sla_state_to_devstate(state), AST_DEVSTATE_CACHABLE, "SLA:%s_%s", station->name, trunk->name);
896 break;
897 }
898 ao2_unlock(station);
899 ao2_ref(station, -1);
900 }
902}
903
909};
910
912{
913 ast_raw_answer(chan); /* Do NOT use ast_answer since that waits for media using ast_waitfor_nandfds. */
914 ast_indicate(chan, -1);
915}
916
917static int conf_run(struct ast_channel *chan, const char *confname, struct ast_flags *confflags, char *optargs[])
918{
919 char confbridge_args[256];
920 int res = 0;
921
922 snprintf(confbridge_args, sizeof(confbridge_args), "%s", confname);
923
924 res |= ast_func_write(chan, "CONFBRIDGE(user,quiet)", ast_test_flag(confflags, CONFFLAG_QUIET) ? "1" : "0");
925 res |= ast_func_write(chan, "CONFBRIDGE(user,dtmf_passthrough)", ast_test_flag(confflags, CONFFLAG_PASS_DTMF) ? "1" : "0");
926 res |= ast_func_write(chan, "CONFBRIDGE(user,marked)", ast_test_flag(confflags, CONFFLAG_MARKEDUSER) ? "1" : "0");
927 res |= ast_func_write(chan, "CONFBRIDGE(user,end_marked)", ast_test_flag(confflags, CONFFLAG_MARKEDEXIT) ? "1" : "0");
928 res |= ast_func_write(chan, "CONFBRIDGE(user,music_on_hold_when_empty)", ast_test_flag(confflags, CONFFLAG_MOH) ? "1" : "0");
930 res |= ast_func_write(chan, "CONFBRIDGE(user,music_on_hold_class)", optargs[SLA_TRUNK_OPT_ARG_MOH_CLASS]);
931 }
932
933 if (res) {
934 ast_log(LOG_ERROR, "Failed to set up conference, aborting\n");
935 return -1;
936 }
937
938 /* Attach a framehook that we'll use to process HOLD from stations. */
939 if (ast_test_flag(confflags, CONFFLAG_SLA_STATION) && attach_framehook(chan, confname)) {
940 return -1;
941 }
942
943 ast_debug(2, "Channel %s is running ConfBridge(%s)\n", ast_channel_name(chan), confbridge_args);
944 res = ast_pbx_exec_application(chan, "ConfBridge", confbridge_args);
945
946 if (ast_test_flag(confflags, CONFFLAG_SLA_STATION)) {
948 }
949 return res;
950}
951
952static int conf_kick_all(struct ast_channel *chan, const char *confname)
953{
954 char confkick_args[256];
955
956 snprintf(confkick_args, sizeof(confkick_args), "%s,all", confname);
957 ast_debug(2, "Kicking all participants from conference %s\n", confname);
958
959 if (chan) {
960 return ast_pbx_exec_application(chan, "ConfKick", confkick_args);
961 } else {
962 /* We might not have a channel available to us, use a dummy channel in that case. */
964 if (!chan) {
965 ast_log(LOG_WARNING, "Failed to allocate dummy channel\n");
966 return -1;
967 } else {
968 int res = ast_pbx_exec_application(chan, "ConfKick", confkick_args);
970 return res;
971 }
972 }
973}
974
975static void *run_station(void *data)
976{
977 RAII_VAR(struct sla_station *, station, NULL, ao2_cleanup);
978 RAII_VAR(struct sla_trunk_ref *, trunk_ref, NULL, ao2_cleanup);
979 struct ast_str *conf_name = ast_str_create(16);
980 struct ast_flags conf_flags = { 0 };
981
982 {
983 struct run_station_args *args = data;
984 station = args->station;
985 trunk_ref = args->trunk_ref;
986 ast_mutex_lock(args->cond_lock);
987 ast_cond_signal(args->cond);
988 ast_mutex_unlock(args->cond_lock);
989 /* args is no longer valid here. */
990 }
991
993 ast_str_set(&conf_name, 0, "SLA_%s", trunk_ref->trunk->name);
996
997 ast_debug(2, "Station %s joining conference %s\n", station->name, ast_str_buffer(conf_name));
998 conf_run(trunk_ref->chan, ast_str_buffer(conf_name), &conf_flags, NULL);
999
1000 trunk_ref->chan = NULL;
1003 conf_kick_all(NULL, ast_str_buffer(conf_name));
1006 }
1007
1010 station->dial = NULL;
1011 ast_free(conf_name);
1012
1013 return NULL;
1014}
1015
1016static void sla_ringing_trunk_destroy(struct sla_ringing_trunk *ringing_trunk);
1017
1018static void sla_stop_ringing_trunk(struct sla_ringing_trunk *ringing_trunk)
1019{
1020 struct sla_station_ref *station_ref;
1021
1022 conf_kick_all(ringing_trunk->trunk->chan, ringing_trunk->trunk->name);
1024
1025 while ((station_ref = AST_LIST_REMOVE_HEAD(&ringing_trunk->timed_out_stations, entry))) {
1026 ao2_ref(station_ref, -1);
1027 }
1028
1029 sla_ringing_trunk_destroy(ringing_trunk);
1030}
1031
1033{
1034 struct sla_ringing_trunk *ringing_trunk;
1035 struct sla_trunk_ref *trunk_ref;
1036 struct sla_station_ref *station_ref;
1037
1038 ast_dial_join(ringing_station->station->dial);
1039 ast_dial_destroy(ringing_station->station->dial);
1040 ringing_station->station->dial = NULL;
1041
1043 goto done;
1044 }
1045
1046 /* If the station is being hung up because of a timeout, then add it to the
1047 * list of timed out stations on each of the ringing trunks. This is so
1048 * that when doing further processing to figure out which stations should be
1049 * ringing, which trunk to answer, determining timeouts, etc., we know which
1050 * ringing trunks we should ignore. */
1051 AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
1052 AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
1053 if (ringing_trunk->trunk == trunk_ref->trunk) {
1054 break;
1055 }
1056 }
1057 if (!trunk_ref) {
1058 continue;
1059 }
1060 if (!(station_ref = sla_create_station_ref(ringing_station->station))) {
1061 continue;
1062 }
1063 AST_LIST_INSERT_TAIL(&ringing_trunk->timed_out_stations, station_ref, entry);
1064 }
1065
1066done:
1067 sla_ringing_station_destroy(ringing_station);
1068}
1069
1070static void sla_dial_state_callback(struct ast_dial *dial)
1071{
1073}
1074
1075/*! \brief Check to see if dialing this station already timed out for this ringing trunk
1076 * \note Assumes sla.lock is locked
1077 */
1078static int sla_check_timed_out_station(const struct sla_ringing_trunk *ringing_trunk, const struct sla_station *station)
1079{
1080 struct sla_station_ref *timed_out_station;
1081
1082 AST_LIST_TRAVERSE(&ringing_trunk->timed_out_stations, timed_out_station, entry) {
1083 if (station == timed_out_station->station) {
1084 return 1;
1085 }
1086 }
1087
1088 return 0;
1089}
1090
1091/*! \brief Choose the highest priority ringing trunk for a station
1092 * \param station the station
1093 * \param rm remove the ringing trunk once selected
1094 * \param trunk_ref a place to store the pointer to this stations reference to
1095 * the selected trunk
1096 * \return a pointer to the selected ringing trunk, or NULL if none found
1097 * \note Assumes that sla.lock is locked
1098 */
1099static struct sla_ringing_trunk *sla_choose_ringing_trunk(struct sla_station *station, struct sla_trunk_ref **trunk_ref, int rm)
1100{
1101 struct sla_trunk_ref *s_trunk_ref;
1102 struct sla_ringing_trunk *ringing_trunk = NULL;
1103
1104 AST_LIST_TRAVERSE(&station->trunks, s_trunk_ref, entry) {
1105 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
1106 /* Make sure this is the trunk we're looking for */
1107 if (s_trunk_ref->trunk != ringing_trunk->trunk) {
1108 continue;
1109 }
1110
1111 /* This trunk on the station is ringing. But, make sure this station
1112 * didn't already time out while this trunk was ringing. */
1113 if (sla_check_timed_out_station(ringing_trunk, station)) {
1114 continue;
1115 }
1116
1117 if (rm) {
1119 }
1120
1121 if (trunk_ref) {
1122 ao2_ref(s_trunk_ref, 1);
1123 *trunk_ref = s_trunk_ref;
1124 }
1125
1126 break;
1127 }
1129
1130 if (ringing_trunk) {
1131 break;
1132 }
1133 }
1134
1135 return ringing_trunk;
1136}
1137
1139{
1140 struct sla_ringing_station *ringing_station;
1141
1142 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
1143 RAII_VAR(struct sla_trunk_ref *, s_trunk_ref, NULL, ao2_cleanup);
1144 struct sla_ringing_trunk *ringing_trunk = NULL;
1145 struct run_station_args args;
1146 enum ast_dial_result dial_res;
1147 pthread_t dont_care;
1150
1151 switch ((dial_res = ast_dial_state(ringing_station->station->dial))) {
1159 break;
1162 /* Find the appropriate trunk to answer. */
1163 ast_mutex_lock(&sla.lock);
1164 ringing_trunk = sla_choose_ringing_trunk(ringing_station->station, &s_trunk_ref, 1);
1165 ast_mutex_unlock(&sla.lock);
1166 if (!ringing_trunk) {
1167 /* This case happens in a bit of a race condition. If two stations answer
1168 * the outbound call at the same time, the first one will get connected to
1169 * the trunk. When the second one gets here, it will not see any trunks
1170 * ringing so we have no idea what to conect it to. So, we just hang up
1171 * on it. */
1172 ast_debug(1, "Found no ringing trunk for station '%s' to answer!\n", ringing_station->station->name);
1173 ast_dial_join(ringing_station->station->dial);
1174 ast_dial_destroy(ringing_station->station->dial);
1175 ringing_station->station->dial = NULL;
1176 sla_ringing_station_destroy(ringing_station);
1177 break;
1178 }
1179 /* Track the channel that answered this trunk */
1180 s_trunk_ref->chan = ast_dial_answered(ringing_station->station->dial);
1181 /* Actually answer the trunk */
1182 answer_trunk_chan(ringing_trunk->trunk->chan);
1184 /* Now, start a thread that will connect this station to the trunk. The rest of
1185 * the code here sets up the thread and ensures that it is able to save the arguments
1186 * before they are no longer valid since they are allocated on the stack. */
1187 ao2_ref(s_trunk_ref, 1);
1188 args.trunk_ref = s_trunk_ref;
1189 ao2_ref(ringing_station->station, 1);
1190 args.station = ringing_station->station;
1191 args.cond = &cond;
1192 args.cond_lock = &cond_lock;
1193 sla_ringing_trunk_destroy(ringing_trunk);
1194 sla_ringing_station_destroy(ringing_station);
1203 break;
1208 break;
1209 }
1210 if (dial_res == AST_DIAL_RESULT_ANSWERED) {
1211 /* Queue up reprocessing ringing trunks, and then ringing stations again */
1214 break;
1215 }
1216 }
1218}
1219
1220/*! \brief Check to see if this station is already ringing
1221 * \note Assumes sla.lock is locked
1222 */
1224{
1225 struct sla_ringing_station *ringing_station;
1226
1227 AST_LIST_TRAVERSE(&sla.ringing_stations, ringing_station, entry) {
1228 if (station == ringing_station->station) {
1229 return 1;
1230 }
1231 }
1232
1233 return 0;
1234}
1235
1236/*! \brief Check to see if this station has failed to be dialed in the past minute
1237 * \note assumes sla.lock is locked
1238 */
1240{
1241 struct sla_failed_station *failed_station;
1242 int res = 0;
1243
1244 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.failed_stations, failed_station, entry) {
1245 if (station != failed_station->station) {
1246 continue;
1247 }
1248 if (ast_tvdiff_ms(ast_tvnow(), failed_station->last_try) > 1000) {
1250 sla_failed_station_destroy(failed_station);
1251 break;
1252 }
1253 res = 1;
1254 }
1256
1257 return res;
1258}
1259
1260/*! \brief Ring a station
1261 * \note Assumes sla.lock is locked
1262 */
1263static int sla_ring_station(struct sla_ringing_trunk *ringing_trunk, struct sla_station *station)
1264{
1265 char *tech, *tech_data;
1266 struct ast_dial *dial;
1267 struct sla_ringing_station *ringing_station;
1268 enum ast_dial_result res;
1269 int caller_is_saved;
1270 struct ast_party_caller caller;
1271
1272 if (!(dial = ast_dial_create())) {
1273 return -1;
1274 }
1275
1277 tech_data = ast_strdupa(station->device);
1278 tech = strsep(&tech_data, "/");
1279
1280 if (ast_dial_append(dial, tech, tech_data, NULL) == -1) {
1281 ast_dial_destroy(dial);
1282 return -1;
1283 }
1284
1285 /* Do we need to save off the caller ID data? */
1286 caller_is_saved = 0;
1287 if (!sla.attempt_callerid) {
1288 caller_is_saved = 1;
1289 caller = *ast_channel_caller(ringing_trunk->trunk->chan);
1291 }
1292
1293 res = ast_dial_run(dial, ringing_trunk->trunk->chan, 1);
1294
1295 /* Restore saved caller ID */
1296 if (caller_is_saved) {
1298 ast_channel_caller_set(ringing_trunk->trunk->chan, &caller);
1299 }
1300
1301 if (res != AST_DIAL_RESULT_TRYING) {
1302 struct sla_failed_station *failed_station;
1303 ast_dial_destroy(dial);
1304 if ((failed_station = sla_create_failed_station(station))) {
1305 AST_LIST_INSERT_HEAD(&sla.failed_stations, failed_station, entry);
1306 }
1307 return -1;
1308 }
1309 if (!(ringing_station = sla_create_ringing_station(station))) {
1310 ast_dial_join(dial);
1311 ast_dial_destroy(dial);
1312 return -1;
1313 }
1314
1315 station->dial = dial;
1316
1317 AST_LIST_INSERT_HEAD(&sla.ringing_stations, ringing_station, entry);
1318
1319 return 0;
1320}
1321
1322/*! \brief Check to see if a station is in use
1323 */
1325{
1326 struct sla_trunk_ref *trunk_ref;
1327
1328 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
1329 if (trunk_ref->chan) {
1330 return 1;
1331 }
1332 }
1333
1334 return 0;
1335}
1336
1337static struct sla_trunk_ref *sla_find_trunk_ref(const struct sla_station *station, const struct sla_trunk *trunk)
1338{
1339 struct sla_trunk_ref *trunk_ref = NULL;
1340
1341 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
1342 if (trunk_ref->trunk == trunk) {
1343 break;
1344 }
1345 }
1346
1347 ao2_ref(trunk_ref, 1);
1348
1349 return trunk_ref;
1350}
1351
1352/*! \brief Calculate the ring delay for a given ringing trunk on a station
1353 * \param station the station
1354 * \param ringing_trunk the trunk. If NULL, the highest priority ringing trunk will be used
1355 * \return the number of ms left before the delay is complete, or INT_MAX if there is no delay
1356 */
1357static int sla_check_station_delay(struct sla_station *station, struct sla_ringing_trunk *ringing_trunk)
1358{
1359 RAII_VAR(struct sla_trunk_ref *, trunk_ref, NULL, ao2_cleanup);
1360 unsigned int delay = UINT_MAX;
1361 int time_left, time_elapsed;
1362
1363 if (!ringing_trunk) {
1364 ringing_trunk = sla_choose_ringing_trunk(station, &trunk_ref, 0);
1365 } else {
1366 trunk_ref = sla_find_trunk_ref(station, ringing_trunk->trunk);
1367 }
1368
1369 if (!ringing_trunk || !trunk_ref) {
1370 return delay;
1371 }
1372
1373 /* If this station has a ring delay specific to the highest priority
1374 * ringing trunk, use that. Otherwise, use the ring delay specified
1375 * globally for the station. */
1376 delay = trunk_ref->ring_delay;
1377 if (!delay) {
1378 delay = station->ring_delay;
1379 }
1380 if (!delay) {
1381 return INT_MAX;
1382 }
1383
1384 time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
1385 time_left = (delay * 1000) - time_elapsed;
1386
1387 return time_left;
1388}
1389
1390/*! \brief Ring stations based on current set of ringing trunks
1391 * \note Assumes that sla.lock is locked
1392 */
1393static void sla_ring_stations(void)
1394{
1395 struct sla_station_ref *station_ref;
1396 struct sla_ringing_trunk *ringing_trunk;
1397
1398 /* Make sure that every station that uses at least one of the ringing
1399 * trunks, is ringing. */
1400 AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
1401 AST_LIST_TRAVERSE(&ringing_trunk->trunk->stations, station_ref, entry) {
1402 int time_left;
1403
1404 /* Is this station already ringing? */
1405 if (sla_check_ringing_station(station_ref->station)) {
1406 continue;
1407 }
1408
1409 /* Is this station already in a call? */
1410 if (sla_check_inuse_station(station_ref->station)) {
1411 continue;
1412 }
1413
1414 /* Did we fail to dial this station earlier? If so, has it been
1415 * a minute since we tried? */
1416 if (sla_check_failed_station(station_ref->station)) {
1417 continue;
1418 }
1419
1420 /* If this station already timed out while this trunk was ringing,
1421 * do not dial it again for this ringing trunk. */
1422 if (sla_check_timed_out_station(ringing_trunk, station_ref->station)) {
1423 continue;
1424 }
1425
1426 /* Check for a ring delay in progress */
1427 time_left = sla_check_station_delay(station_ref->station, ringing_trunk);
1428 if (time_left != INT_MAX && time_left > 0) {
1429 continue;
1430 }
1431
1432 /* It is time to make this station begin to ring. Do it! */
1433 sla_ring_station(ringing_trunk, station_ref->station);
1434 }
1435 }
1436 /* Now, all of the stations that should be ringing, are ringing. */
1437}
1438
1439static void sla_hangup_stations(void)
1440{
1441 struct sla_trunk_ref *trunk_ref;
1442 struct sla_ringing_station *ringing_station;
1443
1444 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
1445 AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
1446 struct sla_ringing_trunk *ringing_trunk;
1447 ast_mutex_lock(&sla.lock);
1448 AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
1449 if (trunk_ref->trunk == ringing_trunk->trunk) {
1450 break;
1451 }
1452 }
1453 ast_mutex_unlock(&sla.lock);
1454 if (ringing_trunk) {
1455 break;
1456 }
1457 }
1458 if (!trunk_ref) {
1460 ast_dial_join(ringing_station->station->dial);
1461 ast_dial_destroy(ringing_station->station->dial);
1462 ringing_station->station->dial = NULL;
1463 sla_ringing_station_destroy(ringing_station);
1464 }
1465 }
1467}
1468
1470{
1471 ast_mutex_lock(&sla.lock);
1473 ast_mutex_unlock(&sla.lock);
1474
1475 /* Find stations that shouldn't be ringing anymore. */
1477}
1478
1480{
1481 ast_atomic_fetchadd_int((int *) &event->trunk_ref->trunk->hold_stations, 1);
1482 event->trunk_ref->state = SLA_TRUNK_STATE_ONHOLD_BYME;
1483 ast_devstate_changed(AST_DEVICE_ONHOLD, AST_DEVSTATE_CACHABLE, "SLA:%s_%s", event->station->name, event->trunk_ref->trunk->name);
1485
1486 if (event->trunk_ref->trunk->active_stations == 1) {
1487 /* The station putting it on hold is the only one on the call, so start
1488 * Music on hold to the trunk. */
1489 event->trunk_ref->trunk->on_hold = 1;
1490 ast_indicate(event->trunk_ref->trunk->chan, AST_CONTROL_HOLD);
1491 }
1492
1493 ast_softhangup(event->trunk_ref->chan, AST_SOFTHANGUP_DEV);
1494 event->trunk_ref->chan = NULL;
1495}
1496
1497/*! \brief Process trunk ring timeouts
1498 * \note Called with sla.lock locked
1499 * \return non-zero if a change to the ringing trunks was made
1500 */
1501static int sla_calc_trunk_timeouts(unsigned int *timeout)
1502{
1503 struct sla_ringing_trunk *ringing_trunk;
1504 int res = 0;
1505
1506 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
1507 int time_left, time_elapsed;
1508 if (!ringing_trunk->trunk->ring_timeout) {
1509 continue;
1510 }
1511 time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
1512 time_left = (ringing_trunk->trunk->ring_timeout * 1000) - time_elapsed;
1513 if (time_left <= 0) {
1514 pbx_builtin_setvar_helper(ringing_trunk->trunk->chan, "SLATRUNK_STATUS", "RINGTIMEOUT");
1516 sla_stop_ringing_trunk(ringing_trunk);
1517 res = 1;
1518 continue;
1519 }
1520 if (time_left < *timeout) {
1521 *timeout = time_left;
1522 }
1523 }
1525
1526 return res;
1527}
1528
1529/*! \brief Process station ring timeouts
1530 * \note Called with sla.lock locked
1531 * \return non-zero if a change to the ringing stations was made
1532 */
1533static int sla_calc_station_timeouts(unsigned int *timeout)
1534{
1535 struct sla_ringing_trunk *ringing_trunk;
1536 struct sla_ringing_station *ringing_station;
1537 int res = 0;
1538
1539 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
1540 unsigned int ring_timeout = 0;
1541 int time_elapsed, time_left = INT_MAX, final_trunk_time_left = INT_MIN;
1542 struct sla_trunk_ref *trunk_ref;
1543
1544 /* If there are any ring timeouts specified for a specific trunk
1545 * on the station, then use the highest per-trunk ring timeout.
1546 * Otherwise, use the ring timeout set for the entire station. */
1547 AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
1548 struct sla_station_ref *station_ref;
1549 int trunk_time_elapsed, trunk_time_left;
1550
1551 AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
1552 if (ringing_trunk->trunk == trunk_ref->trunk) {
1553 break;
1554 }
1555 }
1556 if (!ringing_trunk) {
1557 continue;
1558 }
1559
1560 /* If there is a trunk that is ringing without a timeout, then the
1561 * only timeout that could matter is a global station ring timeout. */
1562 if (!trunk_ref->ring_timeout) {
1563 break;
1564 }
1565
1566 /* This trunk on this station is ringing and has a timeout.
1567 * However, make sure this trunk isn't still ringing from a
1568 * previous timeout. If so, don't consider it. */
1569 AST_LIST_TRAVERSE(&ringing_trunk->timed_out_stations, station_ref, entry) {
1570 if (station_ref->station == ringing_station->station) {
1571 break;
1572 }
1573 }
1574 if (station_ref) {
1575 continue;
1576 }
1577
1578 trunk_time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
1579 trunk_time_left = (trunk_ref->ring_timeout * 1000) - trunk_time_elapsed;
1580 if (trunk_time_left > final_trunk_time_left) {
1581 final_trunk_time_left = trunk_time_left;
1582 }
1583 }
1584
1585 /* No timeout was found for ringing trunks, and no timeout for the entire station */
1586 if (final_trunk_time_left == INT_MIN && !ringing_station->station->ring_timeout) {
1587 continue;
1588 }
1589
1590 /* Compute how much time is left for a global station timeout */
1591 if (ringing_station->station->ring_timeout) {
1592 ring_timeout = ringing_station->station->ring_timeout;
1593 time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_station->ring_begin);
1594 time_left = (ring_timeout * 1000) - time_elapsed;
1595 }
1596
1597 /* If the time left based on the per-trunk timeouts is smaller than the
1598 * global station ring timeout, use that. */
1599 if (final_trunk_time_left > INT_MIN && final_trunk_time_left < time_left) {
1600 time_left = final_trunk_time_left;
1601 }
1602
1603 /* If there is no time left, the station needs to stop ringing */
1604 if (time_left <= 0) {
1607 res = 1;
1608 continue;
1609 }
1610
1611 /* There is still some time left for this station to ring, so save that
1612 * timeout if it is the first event scheduled to occur */
1613 if (time_left < *timeout) {
1614 *timeout = time_left;
1615 }
1616 }
1618
1619 return res;
1620}
1621
1622/*! \brief Calculate the ring delay for a station
1623 * \note Assumes sla.lock is locked
1624 */
1625static int sla_calc_station_delays(unsigned int *timeout)
1626{
1627 struct sla_station *station;
1628 int res = 0;
1629 struct ao2_iterator i;
1630
1632 for (; (station = ao2_iterator_next(&i)); ao2_ref(station, -1)) {
1633 struct sla_ringing_trunk *ringing_trunk;
1634 int time_left;
1635
1636 /* Ignore stations already ringing */
1637 if (sla_check_ringing_station(station)) {
1638 continue;
1639 }
1640
1641 /* Ignore stations already on a call */
1642 if (sla_check_inuse_station(station)) {
1643 continue;
1644 }
1645
1646 /* Ignore stations that don't have one of their trunks ringing */
1647 if (!(ringing_trunk = sla_choose_ringing_trunk(station, NULL, 0))) {
1648 continue;
1649 }
1650
1651 if ((time_left = sla_check_station_delay(station, ringing_trunk)) == INT_MAX) {
1652 continue;
1653 }
1654
1655 /* If there is no time left, then the station needs to start ringing.
1656 * Return non-zero so that an event will be queued up an event to
1657 * make that happen. */
1658 if (time_left <= 0) {
1659 res = 1;
1660 continue;
1661 }
1662
1663 if (time_left < *timeout) {
1664 *timeout = time_left;
1665 }
1666 }
1668
1669 return res;
1670}
1671
1672/*! \brief Calculate the time until the next known event
1673 * \note Called with sla.lock locked */
1674static int sla_process_timers(struct timespec *ts)
1675{
1676 unsigned int timeout = UINT_MAX;
1677 struct timeval wait;
1678 unsigned int change_made = 0;
1679
1680 /* Check for ring timeouts on ringing trunks */
1681 if (sla_calc_trunk_timeouts(&timeout)) {
1682 change_made = 1;
1683 }
1684
1685 /* Check for ring timeouts on ringing stations */
1686 if (sla_calc_station_timeouts(&timeout)) {
1687 change_made = 1;
1688 }
1689
1690 /* Check for station ring delays */
1691 if (sla_calc_station_delays(&timeout)) {
1692 change_made = 1;
1693 }
1694
1695 /* queue reprocessing of ringing trunks */
1696 if (change_made) {
1698 }
1699
1700 /* No timeout */
1701 if (timeout == UINT_MAX) {
1702 return 0;
1703 }
1704
1705 if (ts) {
1706 wait = ast_tvadd(ast_tvnow(), ast_samp2tv(timeout, 1000));
1707 ts->tv_sec = wait.tv_sec;
1708 ts->tv_nsec = wait.tv_usec * 1000;
1709 }
1710
1711 return 1;
1712}
1713
1715{
1716 if (event->trunk_ref) {
1717 ao2_ref(event->trunk_ref, -1);
1718 event->trunk_ref = NULL;
1719 }
1720
1721 if (event->station) {
1722 ao2_ref(event->station, -1);
1723 event->station = NULL;
1724 }
1725
1726 ast_free(event);
1727}
1728
1729static void *sla_thread(void *data)
1730{
1731 struct sla_failed_station *failed_station;
1732 struct sla_ringing_station *ringing_station;
1733
1734 ast_mutex_lock(&sla.lock);
1735
1736 while (!sla.stop) {
1737 struct sla_event *event;
1738 struct timespec ts = { 0, };
1739 unsigned int have_timeout = 0;
1740
1741 if (AST_LIST_EMPTY(&sla.event_q)) {
1742 if ((have_timeout = sla_process_timers(&ts))) {
1743 ast_cond_timedwait(&sla.cond, &sla.lock, &ts);
1744 } else {
1745 ast_cond_wait(&sla.cond, &sla.lock);
1746 }
1747 if (sla.stop) {
1748 break;
1749 }
1750 }
1751
1752 if (have_timeout) {
1754 }
1755
1756 while ((event = AST_LIST_REMOVE_HEAD(&sla.event_q, entry))) {
1757 ast_mutex_unlock(&sla.lock);
1758 switch (event->type) {
1759 case SLA_EVENT_HOLD:
1761 break;
1764 break;
1767 break;
1768 }
1770 ast_mutex_lock(&sla.lock);
1771 }
1772 }
1773
1774 ast_mutex_unlock(&sla.lock);
1775
1776 while ((ringing_station = AST_LIST_REMOVE_HEAD(&sla.ringing_stations, entry))) {
1777 sla_ringing_station_destroy(ringing_station);
1778 }
1779
1780 while ((failed_station = AST_LIST_REMOVE_HEAD(&sla.failed_stations, entry))) {
1781 sla_failed_station_destroy(failed_station);
1782 }
1783
1784 return NULL;
1785}
1786
1792};
1793
1794static void *dial_trunk(void *data)
1795{
1796 struct dial_trunk_args *args = data;
1797 struct ast_dial *dial;
1798 char *tech, *tech_data;
1799 enum ast_dial_result dial_res;
1800 char conf_name[MAX_CONFNUM];
1801 struct ast_flags conf_flags = { 0 };
1802 RAII_VAR(struct sla_trunk_ref *, trunk_ref, args->trunk_ref, ao2_cleanup);
1803 RAII_VAR(struct sla_station *, station, args->station, ao2_cleanup);
1804 int caller_is_saved;
1805 struct ast_party_caller caller;
1806 int last_state = 0;
1807 int current_state = 0;
1808
1809 if (!(dial = ast_dial_create())) {
1810 ast_mutex_lock(args->cond_lock);
1811 ast_cond_signal(args->cond);
1812 ast_mutex_unlock(args->cond_lock);
1813 return NULL;
1814 }
1815
1816 tech_data = ast_strdupa(trunk_ref->trunk->device);
1817 tech = strsep(&tech_data, "/");
1818 if (ast_dial_append(dial, tech, tech_data, NULL) == -1) {
1819 ast_mutex_lock(args->cond_lock);
1820 ast_cond_signal(args->cond);
1821 ast_mutex_unlock(args->cond_lock);
1822 ast_dial_destroy(dial);
1823 return NULL;
1824 }
1825
1826 /* Do we need to save of the caller ID data? */
1827 caller_is_saved = 0;
1828 if (!sla.attempt_callerid) {
1829 caller_is_saved = 1;
1830 caller = *ast_channel_caller(trunk_ref->chan);
1831 ast_party_caller_init(ast_channel_caller(trunk_ref->chan));
1832 }
1833
1834 dial_res = ast_dial_run(dial, trunk_ref->chan, 1);
1835
1836 /* Restore saved caller ID */
1837 if (caller_is_saved) {
1838 ast_party_caller_free(ast_channel_caller(trunk_ref->chan));
1839 ast_channel_caller_set(trunk_ref->chan, &caller);
1840 }
1841
1842 if (dial_res != AST_DIAL_RESULT_TRYING) {
1843 ast_mutex_lock(args->cond_lock);
1844 ast_cond_signal(args->cond);
1845 ast_mutex_unlock(args->cond_lock);
1846 ast_dial_destroy(dial);
1847 return NULL;
1848 }
1849
1850 /* Wait for dial to end, while servicing the channel */
1851 while (ast_waitfor(trunk_ref->chan, 100)) {
1852 unsigned int done = 0;
1853 struct ast_frame *fr = ast_read(trunk_ref->chan);
1854
1855 if (!fr) {
1856 ast_debug(1, "Channel %s did not return a frame, must have hung up\n", ast_channel_name(trunk_ref->chan));
1857 done = 1;
1858 break;
1859 }
1860 ast_frfree(fr); /* Ignore while dialing */
1861
1862 switch ((dial_res = ast_dial_state(dial))) {
1864 trunk_ref->trunk->chan = ast_dial_answered(dial);
1870 done = 1;
1871 break;
1873 current_state = AST_CONTROL_PROGRESS;
1874 break;
1878 current_state = AST_CONTROL_RINGING;
1879 break;
1880 }
1881 if (done) {
1882 break;
1883 }
1884
1885 /* check that SLA station that originated trunk call is still alive */
1886 if (station && ast_device_state(station->device) == AST_DEVICE_NOT_INUSE) {
1887 ast_debug(3, "Originating station device %s no longer active\n", station->device);
1888 trunk_ref->trunk->chan = NULL;
1889 break;
1890 }
1891
1892 /* If trunk line state changed, send indication back to originating SLA Station channel */
1893 if (current_state != last_state) {
1894 ast_debug(3, "Indicating State Change %d to channel %s\n", current_state, ast_channel_name(trunk_ref->chan));
1895 ast_indicate(trunk_ref->chan, current_state);
1896 last_state = current_state;
1897 }
1898 }
1899
1900 if (!trunk_ref->trunk->chan) {
1901 ast_mutex_lock(args->cond_lock);
1902 ast_cond_signal(args->cond);
1903 ast_mutex_unlock(args->cond_lock);
1904 ast_dial_join(dial);
1905 ast_dial_destroy(dial);
1906 return NULL;
1907 }
1908
1909 snprintf(conf_name, sizeof(conf_name), "SLA_%s", trunk_ref->trunk->name);
1911
1912 ast_mutex_lock(args->cond_lock);
1913 ast_cond_signal(args->cond);
1914 ast_mutex_unlock(args->cond_lock);
1915
1916 ast_debug(2, "Trunk dial %s joining conference %s\n", trunk_ref->trunk->name, conf_name);
1917 conf_run(trunk_ref->trunk->chan, conf_name, &conf_flags, NULL);
1918
1919 /* If the trunk is going away, it is definitely now IDLE. */
1921
1922 trunk_ref->trunk->chan = NULL;
1923 trunk_ref->trunk->on_hold = 0;
1924
1925 ast_dial_join(dial);
1926 ast_dial_destroy(dial);
1927
1928 return NULL;
1929}
1930
1931/*!
1932 * \brief For a given station, choose the highest priority idle trunk
1933 * \pre sla_station is locked
1934 */
1935static struct sla_trunk_ref *sla_choose_idle_trunk(const struct sla_station *station)
1936{
1937 struct sla_trunk_ref *trunk_ref = NULL;
1938
1939 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
1940 if (trunk_ref->state == SLA_TRUNK_STATE_IDLE) {
1941 ao2_ref(trunk_ref, 1);
1942 break;
1943 }
1944 }
1945
1946 return trunk_ref;
1947}
1948
1949static int sla_station_exec(struct ast_channel *chan, const char *data)
1950{
1951 char *station_name, *trunk_name;
1952 RAII_VAR(struct sla_station *, station, NULL, ao2_cleanup);
1953 RAII_VAR(struct sla_trunk_ref *, trunk_ref, NULL, ao2_cleanup);
1954 char conf_name[MAX_CONFNUM];
1955 struct ast_flags conf_flags = { 0 };
1956
1957 if (ast_strlen_zero(data)) {
1958 ast_log(LOG_WARNING, "Invalid Arguments to SLAStation!\n");
1959 pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
1960 return 0;
1961 }
1962
1963 trunk_name = ast_strdupa(data);
1964 station_name = strsep(&trunk_name, "_");
1965
1966 if (ast_strlen_zero(station_name)) {
1967 ast_log(LOG_WARNING, "Invalid Arguments to SLAStation!\n");
1968 pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
1969 return 0;
1970 }
1971
1972 station = sla_find_station(station_name);
1973
1974 if (!station) {
1975 ast_log(LOG_WARNING, "Station '%s' not found!\n", station_name);
1976 pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
1977 return 0;
1978 }
1979
1980 ao2_lock(station);
1981 if (!ast_strlen_zero(trunk_name)) {
1982 trunk_ref = sla_find_trunk_ref_byname(station, trunk_name);
1983 } else {
1984 trunk_ref = sla_choose_idle_trunk(station);
1985 }
1986 ao2_unlock(station);
1987
1988 if (!trunk_ref) {
1989 if (ast_strlen_zero(trunk_name)) {
1990 ast_log(LOG_NOTICE, "No trunks available for call.\n");
1991 } else {
1992 ast_log(LOG_NOTICE, "Can't join existing call on trunk '%s' due to access controls.\n", trunk_name);
1993 }
1994 pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "CONGESTION");
1995 return 0;
1996 }
1997
1998 if (trunk_ref->state == SLA_TRUNK_STATE_ONHOLD_BYME) {
1999 if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->hold_stations) == 1) {
2001 } else {
2002 trunk_ref->state = SLA_TRUNK_STATE_UP;
2003 ast_devstate_changed(AST_DEVICE_INUSE, AST_DEVSTATE_CACHABLE, "SLA:%s_%s", station->name, trunk_ref->trunk->name);
2004 }
2005 } else if (trunk_ref->state == SLA_TRUNK_STATE_RINGING) {
2006 struct sla_ringing_trunk *ringing_trunk;
2007
2008 ast_mutex_lock(&sla.lock);
2009 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
2010 if (ringing_trunk->trunk == trunk_ref->trunk) {
2012 break;
2013 }
2014 }
2016 ast_mutex_unlock(&sla.lock);
2017
2018 if (ringing_trunk) {
2019 answer_trunk_chan(ringing_trunk->trunk->chan);
2021
2022 sla_ringing_trunk_destroy(ringing_trunk);
2023
2024 /* Queue up reprocessing ringing trunks, and then ringing stations again */
2027 }
2028 }
2029
2030 trunk_ref->chan = chan;
2031
2032 if (!trunk_ref->trunk->chan) {
2033 ast_mutex_t cond_lock;
2035 pthread_t dont_care;
2036 struct dial_trunk_args args = {
2037 .trunk_ref = trunk_ref,
2038 .station = station,
2039 .cond_lock = &cond_lock,
2040 .cond = &cond,
2041 };
2042 ao2_ref(trunk_ref, 1);
2043 ao2_ref(station, 1);
2045 /* Create a thread to dial the trunk and dump it into the conference.
2046 * However, we want to wait until the trunk has been dialed and the
2047 * conference is created before continuing on here.
2048 * Don't autoservice the channel or we'll have multiple threads
2049 * handling it. dial_trunk services the channel.
2050 */
2059
2060 if (!trunk_ref->trunk->chan) {
2061 ast_debug(1, "Trunk didn't get created. chan: %lx\n", (unsigned long) trunk_ref->trunk->chan);
2062 pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "CONGESTION");
2064 trunk_ref->chan = NULL;
2065 return 0;
2066 }
2067 }
2068
2069 if (ast_atomic_fetchadd_int((int *) &trunk_ref->trunk->active_stations, 1) == 0 &&
2071 trunk_ref->trunk->on_hold = 0;
2074 }
2075
2076 snprintf(conf_name, sizeof(conf_name), "SLA_%s", trunk_ref->trunk->name);
2078 ast_answer(chan);
2079
2080 ast_debug(2, "Station %s joining conference %s\n", station->name, conf_name);
2081 conf_run(chan, conf_name, &conf_flags, NULL);
2082
2083 trunk_ref->chan = NULL;
2086 conf_kick_all(chan, conf_name);
2089 }
2090
2091 pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "SUCCESS");
2092
2093 return 0;
2094}
2095
2096static void sla_trunk_ref_destructor(void *obj)
2097{
2098 struct sla_trunk_ref *trunk_ref = obj;
2099
2100 if (trunk_ref->trunk) {
2101 ao2_ref(trunk_ref->trunk, -1);
2102 trunk_ref->trunk = NULL;
2103 }
2104}
2105
2107{
2108 struct sla_trunk_ref *trunk_ref;
2109
2110 if (!(trunk_ref = ao2_alloc(sizeof(*trunk_ref), sla_trunk_ref_destructor))) {
2111 return NULL;
2112 }
2113
2114 ao2_ref(trunk, 1);
2115 trunk_ref->trunk = trunk;
2116
2117 return trunk_ref;
2118}
2119
2121{
2122 struct sla_ringing_trunk *ringing_trunk;
2123
2124 if (!(ringing_trunk = ast_calloc(1, sizeof(*ringing_trunk)))) {
2125 return NULL;
2126 }
2127
2128 ao2_ref(trunk, 1);
2129 ringing_trunk->trunk = trunk;
2130 ringing_trunk->ring_begin = ast_tvnow();
2131
2133
2134 ast_mutex_lock(&sla.lock);
2135 AST_LIST_INSERT_HEAD(&sla.ringing_trunks, ringing_trunk, entry);
2136 ast_mutex_unlock(&sla.lock);
2137
2139
2140 return ringing_trunk;
2141}
2142
2143static void sla_ringing_trunk_destroy(struct sla_ringing_trunk *ringing_trunk)
2144{
2145 if (ringing_trunk->trunk) {
2146 ao2_ref(ringing_trunk->trunk, -1);
2147 ringing_trunk->trunk = NULL;
2148 }
2149
2150 ast_free(ringing_trunk);
2151}
2152
2153static int sla_trunk_exec(struct ast_channel *chan, const char *data)
2154{
2155 char conf_name[MAX_CONFNUM];
2156 struct ast_flags conf_flags = { 0 };
2157 RAII_VAR(struct sla_trunk *, trunk, NULL, ao2_cleanup);
2158 struct sla_ringing_trunk *ringing_trunk;
2160 AST_APP_ARG(trunk_name);
2162 );
2163 char *opts[SLA_TRUNK_OPT_ARG_ARRAY_SIZE] = { NULL, };
2164 struct ast_flags opt_flags = { 0 };
2165 char *parse;
2166
2167 if (ast_strlen_zero(data)) {
2168 ast_log(LOG_ERROR, "The SLATrunk application requires an argument, the trunk name\n");
2169 return -1;
2170 }
2171
2172 parse = ast_strdupa(data);
2174 if (args.argc == 2) {
2175 if (ast_app_parse_options(sla_trunk_opts, &opt_flags, opts, args.options)) {
2176 ast_log(LOG_ERROR, "Error parsing options for SLATrunk\n");
2177 return -1;
2178 }
2179 }
2180
2181 trunk = sla_find_trunk(args.trunk_name);
2182
2183 if (!trunk) {
2184 ast_log(LOG_ERROR, "SLA Trunk '%s' not found!\n", args.trunk_name);
2185 pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
2186 return 0;
2187 }
2188
2189 if (trunk->chan) {
2190 ast_log(LOG_ERROR, "Call came in on %s, but the trunk is already in use!\n", args.trunk_name);
2191 pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
2192 return 0;
2193 }
2194
2195 trunk->chan = chan;
2196
2197 if (!(ringing_trunk = queue_ringing_trunk(trunk))) {
2198 pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
2199 return 0;
2200 }
2201
2202 snprintf(conf_name, sizeof(conf_name), "SLA_%s", args.trunk_name);
2204
2205 if (ast_test_flag(&opt_flags, SLA_TRUNK_OPT_MOH)) {
2206 ast_indicate(chan, -1);
2207 ast_set_flag(&conf_flags, CONFFLAG_MOH);
2208 } else {
2210 }
2211
2212 ast_debug(2, "Trunk %s joining conference %s\n", args.trunk_name, conf_name);
2213 conf_run(chan, conf_name, &conf_flags, opts);
2214 trunk->chan = NULL;
2215 trunk->on_hold = 0;
2216
2218
2219 if (!pbx_builtin_getvar_helper(chan, "SLATRUNK_STATUS")) {
2220 pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "SUCCESS");
2221 }
2222
2223 /* Remove the entry from the list of ringing trunks if it is still there. */
2224 ast_mutex_lock(&sla.lock);
2225 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
2226 if (ringing_trunk->trunk == trunk) {
2228 break;
2229 }
2230 }
2232 ast_mutex_unlock(&sla.lock);
2233 if (ringing_trunk) {
2234 sla_ringing_trunk_destroy(ringing_trunk);
2235 pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "UNANSWERED");
2236 /* Queue reprocessing of ringing trunks to make stations stop ringing
2237 * that shouldn't be ringing after this trunk stopped. */
2239 }
2240
2241 return 0;
2242}
2243
2244static enum ast_device_state sla_state(const char *data)
2245{
2246 char *buf, *station_name, *trunk_name;
2247 RAII_VAR(struct sla_station *, station, NULL, ao2_cleanup);
2248 struct sla_trunk_ref *trunk_ref;
2250
2251 trunk_name = buf = ast_strdupa(data);
2252 station_name = strsep(&trunk_name, "_");
2253
2254 station = sla_find_station(station_name);
2255 if (station) {
2256 ao2_lock(station);
2257 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
2258 if (!strcasecmp(trunk_name, trunk_ref->trunk->name)) {
2259 res = sla_state_to_devstate(trunk_ref->state);
2260 break;
2261 }
2262 }
2263 ao2_unlock(station);
2264 }
2265
2266 if (res == AST_DEVICE_INVALID) {
2267 ast_log(LOG_ERROR, "Could not determine state for trunk %s on station %s!\n", trunk_name, station_name);
2268 }
2269
2270 return res;
2271}
2272
2273static int sla_trunk_release_refs(void *obj, void *arg, int flags)
2274{
2275 struct sla_trunk *trunk = obj;
2276 struct sla_station_ref *station_ref;
2277
2278 while ((station_ref = AST_LIST_REMOVE_HEAD(&trunk->stations, entry))) {
2279 ao2_ref(station_ref, -1);
2280 }
2281
2282 return 0;
2283}
2284
2285static int sla_station_release_refs(void *obj, void *arg, int flags)
2286{
2287 struct sla_station *station = obj;
2288 struct sla_trunk_ref *trunk_ref;
2289
2290 while ((trunk_ref = AST_LIST_REMOVE_HEAD(&station->trunks, entry))) {
2291 ao2_ref(trunk_ref, -1);
2292 }
2293
2294 return 0;
2295}
2296
2297static void sla_station_destructor(void *obj)
2298{
2299 struct sla_station *station = obj;
2300
2301 ast_debug(1, "sla_station destructor for '%s'\n", station->name);
2302
2303 if (!ast_strlen_zero(station->autocontext)) {
2304 struct sla_trunk_ref *trunk_ref;
2305
2306 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
2307 char exten[AST_MAX_EXTENSION];
2308 char hint[AST_MAX_EXTENSION + 5];
2309 snprintf(exten, sizeof(exten), "%s_%s", station->name, trunk_ref->trunk->name);
2310 snprintf(hint, sizeof(hint), "SLA:%s", exten);
2311 ast_context_remove_extension(station->autocontext, exten, 1, sla_registrar);
2312 ast_context_remove_extension(station->autocontext, hint, PRIORITY_HINT, sla_registrar);
2313 }
2314 }
2315
2316 sla_station_release_refs(station, NULL, 0);
2317
2319}
2320
2321static int sla_trunk_cmp(void *obj, void *arg, int flags)
2322{
2323 struct sla_trunk *trunk = obj, *trunk2 = arg;
2324
2325 return !strcasecmp(trunk->name, trunk2->name) ? CMP_MATCH | CMP_STOP : 0;
2326}
2327
2328static int sla_station_cmp(void *obj, void *arg, int flags)
2329{
2330 struct sla_station *station = obj, *station2 = arg;
2331
2332 return !strcasecmp(station->name, station2->name) ? CMP_MATCH | CMP_STOP : 0;
2333}
2334
2335static void sla_destroy(void)
2336{
2337 if (sla.thread != AST_PTHREADT_NULL) {
2338 ast_mutex_lock(&sla.lock);
2339 sla.stop = 1;
2340 ast_cond_signal(&sla.cond);
2341 ast_mutex_unlock(&sla.lock);
2342 pthread_join(sla.thread, NULL);
2343 }
2344
2345 /* Drop any created contexts from the dialplan */
2347
2348 ast_mutex_destroy(&sla.lock);
2349 ast_cond_destroy(&sla.cond);
2350
2353
2354 ao2_ref(sla_trunks, -1);
2355 sla_trunks = NULL;
2356
2357 ao2_ref(sla_stations, -1);
2359}
2360
2361static int sla_check_device(const char *device)
2362{
2363 char *tech, *tech_data;
2364
2365 tech_data = ast_strdupa(device);
2366 tech = strsep(&tech_data, "/");
2367
2368 if (ast_strlen_zero(tech) || ast_strlen_zero(tech_data)) {
2369 return -1;
2370 }
2371
2372 return 0;
2373}
2374
2375static void sla_trunk_destructor(void *obj)
2376{
2377 struct sla_trunk *trunk = obj;
2378
2379 ast_debug(1, "sla_trunk destructor for '%s'\n", trunk->name);
2380
2381 if (!ast_strlen_zero(trunk->autocontext)) {
2383 }
2384
2385 sla_trunk_release_refs(trunk, NULL, 0);
2386
2388}
2389
2390static int sla_build_trunk(struct ast_config *cfg, const char *cat)
2391{
2392 RAII_VAR(struct sla_trunk *, trunk, NULL, ao2_cleanup);
2393 struct ast_variable *var;
2394 const char *dev;
2395 int existing_trunk = 0;
2396
2397 if (!(dev = ast_variable_retrieve(cfg, cat, "device"))) {
2398 ast_log(LOG_ERROR, "SLA Trunk '%s' defined with no device!\n", cat);
2399 return -1;
2400 }
2401
2402 if (sla_check_device(dev)) {
2403 ast_log(LOG_ERROR, "SLA Trunk '%s' defined with invalid device '%s'!\n", cat, dev);
2404 return -1;
2405 }
2406
2407 if ((trunk = sla_find_trunk(cat))) {
2408 trunk->mark = 0;
2409 existing_trunk = 1;
2410 } else if ((trunk = ao2_alloc(sizeof(*trunk), sla_trunk_destructor))) {
2411 if (ast_string_field_init(trunk, 32)) {
2412 return -1;
2413 }
2414 ast_string_field_set(trunk, name, cat);
2415 } else {
2416 return -1;
2417 }
2418
2419 ao2_lock(trunk);
2420
2421 ast_string_field_set(trunk, device, dev);
2422
2423 for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
2424 if (!strcasecmp(var->name, "autocontext")) {
2425 ast_string_field_set(trunk, autocontext, var->value);
2426 } else if (!strcasecmp(var->name, "ringtimeout")) {
2427 if (sscanf(var->value, "%30u", &trunk->ring_timeout) != 1) {
2428 ast_log(LOG_WARNING, "Invalid ringtimeout '%s' specified for trunk '%s'\n", var->value, trunk->name);
2429 trunk->ring_timeout = 0;
2430 }
2431 } else if (!strcasecmp(var->name, "barge")) {
2432 trunk->barge_disabled = ast_false(var->value);
2433 } else if (!strcasecmp(var->name, "hold")) {
2434 if (!strcasecmp(var->value, "private")) {
2435 trunk->hold_access = SLA_HOLD_PRIVATE;
2436 } else if (!strcasecmp(var->value, "open")) {
2437 trunk->hold_access = SLA_HOLD_OPEN;
2438 } else {
2439 ast_log(LOG_WARNING, "Invalid value '%s' for hold on trunk %s\n", var->value, trunk->name);
2440 }
2441 } else if (strcasecmp(var->name, "type") && strcasecmp(var->name, "device")) {
2442 ast_log(LOG_ERROR, "Invalid option '%s' specified at line %d of %s!\n", var->name, var->lineno, SLA_CONFIG_FILE);
2443 }
2444 }
2445
2446 ao2_unlock(trunk);
2447
2448 if (!ast_strlen_zero(trunk->autocontext)) {
2449 if (!ast_context_find_or_create(NULL, NULL, trunk->autocontext, sla_registrar)) {
2450 ast_log(LOG_ERROR, "Failed to automatically find or create context '%s' for SLA!\n", trunk->autocontext);
2451 return -1;
2452 }
2453
2454 if (ast_add_extension(trunk->autocontext, 0 /* don't replace */, "s", 1,
2456 ast_log(LOG_ERROR, "Failed to automatically create extension for trunk '%s'!\n", trunk->name);
2457 return -1;
2458 }
2459 }
2460
2461 if (!existing_trunk) {
2462 ao2_link(sla_trunks, trunk);
2463 }
2464
2465 return 0;
2466}
2467
2468/*!
2469 * \internal
2470 * \pre station is not locked
2471 */
2472static void sla_add_trunk_to_station(struct sla_station *station, struct ast_variable *var)
2473{
2474 RAII_VAR(struct sla_trunk *, trunk, NULL, ao2_cleanup);
2475 struct sla_trunk_ref *trunk_ref = NULL;
2476 struct sla_station_ref *station_ref;
2477 char *trunk_name, *options, *cur;
2478 int existing_trunk_ref = 0;
2479 int existing_station_ref = 0;
2480
2481 options = ast_strdupa(var->value);
2482 trunk_name = strsep(&options, ",");
2483
2484 trunk = sla_find_trunk(trunk_name);
2485 if (!trunk) {
2486 ast_log(LOG_ERROR, "Trunk '%s' not found!\n", var->value);
2487 return;
2488 }
2489
2490 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
2491 if (trunk_ref->trunk == trunk) {
2492 trunk_ref->mark = 0;
2493 existing_trunk_ref = 1;
2494 break;
2495 }
2496 }
2497
2498 if (!trunk_ref && !(trunk_ref = create_trunk_ref(trunk))) {
2499 return;
2500 }
2501
2502 trunk_ref->state = SLA_TRUNK_STATE_IDLE;
2503
2504 while ((cur = strsep(&options, ","))) {
2505 char *name, *value = cur;
2506 name = strsep(&value, "=");
2507 if (!strcasecmp(name, "ringtimeout")) {
2508 if (sscanf(value, "%30u", &trunk_ref->ring_timeout) != 1) {
2509 ast_log(LOG_WARNING, "Invalid ringtimeout value '%s' for trunk '%s' on station '%s'\n", value, trunk->name, station->name);
2510 trunk_ref->ring_timeout = 0;
2511 }
2512 } else if (!strcasecmp(name, "ringdelay")) {
2513 if (sscanf(value, "%30u", &trunk_ref->ring_delay) != 1) {
2514 ast_log(LOG_WARNING, "Invalid ringdelay value '%s' for trunk '%s' on station '%s'\n", value, trunk->name, station->name);
2515 trunk_ref->ring_delay = 0;
2516 }
2517 } else {
2518 ast_log(LOG_WARNING, "Invalid option '%s' for trunk '%s' on station '%s'\n", name, trunk->name, station->name);
2519 }
2520 }
2521
2522 AST_LIST_TRAVERSE(&trunk->stations, station_ref, entry) {
2523 if (station_ref->station == station) {
2524 station_ref->mark = 0;
2525 existing_station_ref = 1;
2526 break;
2527 }
2528 }
2529
2530 if (!station_ref && !(station_ref = sla_create_station_ref(station))) {
2531 if (!existing_trunk_ref) {
2532 ao2_ref(trunk_ref, -1);
2533 } else {
2534 trunk_ref->mark = 1;
2535 }
2536 return;
2537 }
2538
2539 if (!existing_station_ref) {
2540 ao2_lock(trunk);
2541 AST_LIST_INSERT_TAIL(&trunk->stations, station_ref, entry);
2542 ast_atomic_fetchadd_int((int *) &trunk->num_stations, 1);
2543 ao2_unlock(trunk);
2544 }
2545
2546 if (!existing_trunk_ref) {
2550 }
2551}
2552
2553static int sla_build_station(struct ast_config *cfg, const char *cat)
2554{
2556 struct ast_variable *var;
2557 const char *dev;
2558 int existing_station = 0;
2559
2560 if (!(dev = ast_variable_retrieve(cfg, cat, "device"))) {
2561 ast_log(LOG_ERROR, "SLA Station '%s' defined with no device!\n", cat);
2562 return -1;
2563 }
2564
2565 if ((station = sla_find_station(cat))) {
2566 station->mark = 0;
2567 existing_station = 1;
2568 } else if ((station = ao2_alloc(sizeof(*station), sla_station_destructor))) {
2569 if (ast_string_field_init(station, 32)) {
2570 return -1;
2571 }
2572 ast_string_field_set(station, name, cat);
2573 } else {
2574 return -1;
2575 }
2576
2577 ao2_lock(station);
2578
2579 ast_string_field_set(station, device, dev);
2580
2581 for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
2582 if (!strcasecmp(var->name, "trunk")) {
2583 ao2_unlock(station);
2584 sla_add_trunk_to_station(station, var);
2585 ao2_lock(station);
2586 } else if (!strcasecmp(var->name, "autocontext")) {
2587 ast_string_field_set(station, autocontext, var->value);
2588 } else if (!strcasecmp(var->name, "ringtimeout")) {
2589 if (sscanf(var->value, "%30u", &station->ring_timeout) != 1) {
2590 ast_log(LOG_WARNING, "Invalid ringtimeout '%s' specified for station '%s'\n", var->value, station->name);
2591 station->ring_timeout = 0;
2592 }
2593 } else if (!strcasecmp(var->name, "ringdelay")) {
2594 if (sscanf(var->value, "%30u", &station->ring_delay) != 1) {
2595 ast_log(LOG_WARNING, "Invalid ringdelay '%s' specified for station '%s'\n", var->value, station->name);
2596 station->ring_delay = 0;
2597 }
2598 } else if (!strcasecmp(var->name, "hold")) {
2599 if (!strcasecmp(var->value, "private")) {
2600 station->hold_access = SLA_HOLD_PRIVATE;
2601 } else if (!strcasecmp(var->value, "open")) {
2602 station->hold_access = SLA_HOLD_OPEN;
2603 } else {
2604 ast_log(LOG_WARNING, "Invalid value '%s' for hold on station %s\n", var->value, station->name);
2605 }
2606 } else if (strcasecmp(var->name, "type") && strcasecmp(var->name, "device")) {
2607 ast_log(LOG_ERROR, "Invalid option '%s' specified at line %d of %s!\n", var->name, var->lineno, SLA_CONFIG_FILE);
2608 }
2609 }
2610
2611 ao2_unlock(station);
2612
2613 if (!ast_strlen_zero(station->autocontext)) {
2614 struct sla_trunk_ref *trunk_ref;
2615
2616 if (!ast_context_find_or_create(NULL, NULL, station->autocontext, sla_registrar)) {
2617 ast_log(LOG_ERROR, "Failed to automatically find or create context '%s' for SLA!\n", station->autocontext);
2618 return -1;
2619 }
2620 /* The extension for when the handset goes off-hook.
2621 * exten => station1,1,SLAStation(station1) */
2622 if (ast_add_extension(station->autocontext, 0 /* don't replace */, station->name, 1,
2624 ast_log(LOG_ERROR, "Failed to automatically create extension for trunk '%s'!\n", station->name);
2625 return -1;
2626 }
2627 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
2628 char exten[AST_MAX_EXTENSION];
2629 char hint[AST_MAX_EXTENSION + 5];
2630 snprintf(exten, sizeof(exten), "%s_%s", station->name, trunk_ref->trunk->name);
2631 snprintf(hint, sizeof(hint), "SLA:%s", exten);
2632 /* Extension for this line button
2633 * exten => station1_line1,1,SLAStation(station1_line1) */
2634 if (ast_add_extension(station->autocontext, 0 /* don't replace */, exten, 1,
2636 ast_log(LOG_ERROR, "Failed to automatically create extension for trunk '%s'!\n", station->name);
2637 return -1;
2638 }
2639 /* Hint for this line button
2640 * exten => station1_line1,hint,SLA:station1_line1 */
2641 if (ast_add_extension(station->autocontext, 0 /* don't replace */, exten, PRIORITY_HINT,
2642 NULL, NULL, hint, NULL, NULL, sla_registrar)) {
2643 ast_log(LOG_ERROR, "Failed to automatically create hint for trunk '%s'!\n", station->name);
2644 return -1;
2645 }
2646 }
2647 }
2648
2649 if (!existing_station) {
2650 ao2_link(sla_stations, station);
2651 }
2652
2653 return 0;
2654}
2655
2656static int sla_trunk_mark(void *obj, void *arg, int flags)
2657{
2658 struct sla_trunk *trunk = obj;
2659 struct sla_station_ref *station_ref;
2660
2661 ao2_lock(trunk);
2662
2663 trunk->mark = 1;
2664
2665 AST_LIST_TRAVERSE(&trunk->stations, station_ref, entry) {
2666 station_ref->mark = 1;
2667 }
2668
2669 ao2_unlock(trunk);
2670
2671 return 0;
2672}
2673
2674static int sla_station_mark(void *obj, void *arg, int flags)
2675{
2676 struct sla_station *station = obj;
2677 struct sla_trunk_ref *trunk_ref;
2678
2679 ao2_lock(station);
2680
2681 station->mark = 1;
2682
2683 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
2684 trunk_ref->mark = 1;
2685 }
2686
2687 ao2_unlock(station);
2688
2689 return 0;
2690}
2691
2692static int sla_trunk_is_marked(void *obj, void *arg, int flags)
2693{
2694 struct sla_trunk *trunk = obj;
2695
2696 ao2_lock(trunk);
2697
2698 if (trunk->mark) {
2699 /* Only remove all of the station references if the trunk itself is going away */
2700 sla_trunk_release_refs(trunk, NULL, 0);
2701 } else {
2702 struct sla_station_ref *station_ref;
2703
2704 /* Otherwise only remove references to stations no longer in the config */
2705 AST_LIST_TRAVERSE_SAFE_BEGIN(&trunk->stations, station_ref, entry) {
2706 if (!station_ref->mark) {
2707 continue;
2708 }
2710 ao2_ref(station_ref, -1);
2711 }
2713 }
2714
2715 ao2_unlock(trunk);
2716
2717 return trunk->mark ? CMP_MATCH : 0;
2718}
2719
2720static int sla_station_is_marked(void *obj, void *arg, int flags)
2721{
2722 struct sla_station *station = obj;
2723
2724 ao2_lock(station);
2725
2726 if (station->mark) {
2727 /* Only remove all of the trunk references if the station itself is going away */
2728 sla_station_release_refs(station, NULL, 0);
2729 } else {
2730 struct sla_trunk_ref *trunk_ref;
2731
2732 /* Otherwise only remove references to trunks no longer in the config */
2733 AST_LIST_TRAVERSE_SAFE_BEGIN(&station->trunks, trunk_ref, entry) {
2734 if (!trunk_ref->mark) {
2735 continue;
2736 }
2738 ao2_ref(trunk_ref, -1);
2739 }
2741 }
2742
2743 ao2_unlock(station);
2744
2745 return station->mark ? CMP_MATCH : 0;
2746}
2747
2748static int sla_in_use(void)
2749{
2751}
2752
2754{
2755 struct ast_config *cfg;
2756 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
2757 const char *cat = NULL;
2758 int res = 0;
2759 const char *val;
2760
2761 if (!reload) {
2762 ast_mutex_init(&sla.lock);
2763 ast_cond_init(&sla.cond, NULL);
2766 }
2767
2768 if (!(cfg = ast_config_load(SLA_CONFIG_FILE, config_flags))) {
2769 return 0; /* Treat no config as normal */
2770 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
2771 return 0;
2772 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
2773 ast_log(LOG_ERROR, "Config file " SLA_CONFIG_FILE " is in an invalid format. Aborting.\n");
2774 return 0;
2775 }
2776
2777 if (reload) {
2780 }
2781
2782 if ((val = ast_variable_retrieve(cfg, "general", "attemptcallerid"))) {
2783 sla.attempt_callerid = ast_true(val);
2784 }
2785
2786 while ((cat = ast_category_browse(cfg, cat)) && !res) {
2787 const char *type;
2788 if (!strcasecmp(cat, "general")) {
2789 continue;
2790 }
2791 if (!(type = ast_variable_retrieve(cfg, cat, "type"))) {
2792 ast_log(LOG_WARNING, "Invalid entry in %s defined with no type!\n", SLA_CONFIG_FILE);
2793 continue;
2794 }
2795 if (!strcasecmp(type, "trunk")) {
2796 res = sla_build_trunk(cfg, cat);
2797 } else if (!strcasecmp(type, "station")) {
2798 res = sla_build_station(cfg, cat);
2799 } else {
2800 ast_log(LOG_WARNING, "Entry in %s defined with invalid type '%s'!\n", SLA_CONFIG_FILE, type);
2801 }
2802 }
2803
2804 ast_config_destroy(cfg);
2805
2806 if (reload) {
2809 }
2810
2811 /* Start SLA event processing thread once SLA has been configured. */
2812 if (sla.thread == AST_PTHREADT_NULL && sla_in_use()) {
2814 }
2815
2816 return res;
2817}
2818
2819static int load_config(int reload)
2820{
2821 return sla_load_config(reload);
2822}
2823
2824static int unload_module(void)
2825{
2826 int res = 0;
2827
2831
2832 ast_devstate_prov_del("SLA");
2833
2834 sla_destroy();
2835
2836 return res;
2837}
2838
2839/*!
2840 * \brief Load the module
2841 *
2842 * Module loading including tests for configuration or dependencies.
2843 * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
2844 * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
2845 * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the
2846 * configuration file or other non-critical problem return
2847 * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
2848 */
2849static int load_module(void)
2850{
2851 int res = 0;
2852
2853 res |= load_config(0);
2854
2858
2859 res |= ast_devstate_prov_add("SLA", sla_state);
2860
2861 return res;
2862}
2863
2864static int reload(void)
2865{
2866 return load_config(1);
2867}
2868
2869AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Shared Line Appearances",
2870 .support_level = AST_MODULE_SUPPORT_EXTENDED,
2871 .load = load_module,
2872 .unload = unload_module,
2873 .reload = reload,
2874 .load_pri = AST_MODPRI_DEVSTATE_PROVIDER,
sla_trunk_state
Definition: app_sla.c:163
@ SLA_TRUNK_STATE_ONHOLD
Definition: app_sla.c:167
@ SLA_TRUNK_STATE_RINGING
Definition: app_sla.c:165
@ SLA_TRUNK_STATE_UP
Definition: app_sla.c:166
@ SLA_TRUNK_STATE_ONHOLD_BYME
Definition: app_sla.c:168
@ SLA_TRUNK_STATE_IDLE
Definition: app_sla.c:164
pthread_t thread
Definition: app_sla.c:329
static int sla_load_config(int reload)
Definition: app_sla.c:2753
static int sla_build_station(struct ast_config *cfg, const char *cat)
Definition: app_sla.c:2553
struct @66::@78 event_q
unsigned int stop
Definition: app_sla.c:336
static int sla_trunk_is_marked(void *obj, void *arg, int flags)
Definition: app_sla.c:2692
static const char *const slatrunk_app
Definition: app_sla.c:128
ast_cond_t cond
Definition: app_sla.c:330
static struct ast_cli_entry cli_sla[]
Definition: app_sla.c:514
sla_which_trunk_refs
Definition: app_sla.c:158
@ INACTIVE_TRUNK_REFS
Definition: app_sla.c:160
@ ALL_TRUNK_REFS
Definition: app_sla.c:159
static int sla_build_trunk(struct ast_config *cfg, const char *cat)
Definition: app_sla.c:2390
static int sla_calc_station_delays(unsigned int *timeout)
Calculate the ring delay for a station.
Definition: app_sla.c:1625
static int sla_station_mark(void *obj, void *arg, int flags)
Definition: app_sla.c:2674
static int sla_check_failed_station(const struct sla_station *station)
Check to see if this station has failed to be dialed in the past minute.
Definition: app_sla.c:1239
static int sla_framehook_consume(void *data, enum ast_frame_type type)
Callback function which informs upstream if we are consuming a frame of a specific type.
Definition: app_sla.c:655
static struct sla_trunk_ref * sla_choose_idle_trunk(const struct sla_station *station)
For a given station, choose the highest priority idle trunk.
Definition: app_sla.c:1935
static int sla_check_device(const char *device)
Definition: app_sla.c:2361
static int sla_ring_station(struct sla_ringing_trunk *ringing_trunk, struct sla_station *station)
Ring a station.
Definition: app_sla.c:1263
static void sla_trunk_ref_destructor(void *obj)
Definition: app_sla.c:2096
static int sla_station_is_marked(void *obj, void *arg, int flags)
Definition: app_sla.c:2720
static int sla_check_inuse_station(const struct sla_station *station)
Check to see if a station is in use.
Definition: app_sla.c:1324
static int sla_trunk_release_refs(void *obj, void *arg, int flags)
Definition: app_sla.c:2273
static struct sla_ringing_trunk * sla_choose_ringing_trunk(struct sla_station *station, struct sla_trunk_ref **trunk_ref, int rm)
Choose the highest priority ringing trunk for a station.
Definition: app_sla.c:1099
static struct sla_ringing_trunk * queue_ringing_trunk(struct sla_trunk *trunk)
Definition: app_sla.c:2120
static void sla_queue_event_full(enum sla_event_type type, struct sla_trunk_ref *trunk_ref, struct sla_station *station, int lock)
Definition: app_sla.c:519
static void sla_queue_event_nolock(enum sla_event_type type)
Definition: app_sla.c:550
static void sla_dial_state_callback(struct ast_dial *dial)
Definition: app_sla.c:1070
@ CONFFLAG_QUIET
Definition: app_sla.c:132
@ CONFFLAG_MARKEDUSER
Definition: app_sla.c:138
@ CONFFLAG_MARKEDEXIT
Definition: app_sla.c:136
@ CONFFLAG_PASS_DTMF
Definition: app_sla.c:140
@ CONFFLAG_MOH
Definition: app_sla.c:134
@ CONFFLAG_SLA_TRUNK
Definition: app_sla.c:142
@ CONFFLAG_SLA_STATION
Definition: app_sla.c:141
static const struct ast_app_option sla_trunk_opts[128]
Definition: app_sla.c:156
static void sla_stop_ringing_trunk(struct sla_ringing_trunk *ringing_trunk)
Definition: app_sla.c:1018
static struct ao2_container * sla_stations
Definition: app_sla.c:272
static struct @66 sla
A structure for data used by the sla thread.
static void sla_failed_station_destroy(struct sla_failed_station *failed_station)
Definition: app_sla.c:853
static struct sla_ringing_station * sla_create_ringing_station(struct sla_station *station)
Definition: app_sla.c:813
static const char *const slastation_app
Definition: app_sla.c:127
static void sla_station_ref_destructor(void *obj)
Definition: app_sla.c:789
sla_event_type
Event types that can be queued up for the SLA thread.
Definition: app_sla.c:278
@ SLA_EVENT_RINGING_TRUNK
Definition: app_sla.c:284
@ SLA_EVENT_HOLD
Definition: app_sla.c:280
@ SLA_EVENT_DIAL_STATE
Definition: app_sla.c:282
static void sla_change_trunk_state(const struct sla_trunk *trunk, enum sla_trunk_state state, enum sla_which_trunk_refs inactive_only, const struct sla_trunk_ref *exclude)
Definition: app_sla.c:880
static void sla_add_trunk_to_station(struct sla_station *station, struct ast_variable *var)
Definition: app_sla.c:2472
static int sla_trunk_cmp(void *obj, void *arg, int flags)
Definition: app_sla.c:2321
static void sla_handle_ringing_trunk_event(void)
Definition: app_sla.c:1469
static struct sla_station_ref * sla_create_station_ref(struct sla_station *station)
Definition: app_sla.c:799
static int conf_kick_all(struct ast_channel *chan, const char *confname)
Definition: app_sla.c:952
static struct ast_frame * sla_framehook(struct ast_channel *chan, struct ast_frame *f, enum ast_framehook_event event, void *data)
Definition: app_sla.c:642
static void answer_trunk_chan(struct ast_channel *chan)
Definition: app_sla.c:911
static void sla_handle_dial_state_event(void)
Definition: app_sla.c:1138
static struct sla_trunk_ref * sla_find_trunk_ref_byname(const struct sla_station *station, const char *name)
Find a trunk reference on a station by name.
Definition: app_sla.c:759
#define SLA_CONFIG_FILE
Definition: app_sla.c:124
static void sla_stop_ringing_station(struct sla_ringing_station *ringing_station, enum sla_station_hangup hangup)
Definition: app_sla.c:1032
static void * run_station(void *data)
Definition: app_sla.c:975
static int sla_station_release_refs(void *obj, void *arg, int flags)
Definition: app_sla.c:2285
static int remove_framehook(struct ast_channel *chan)
Definition: app_sla.c:614
@ SLA_TRUNK_OPT_ARG_MOH_CLASS
Definition: app_sla.c:150
@ SLA_TRUNK_OPT_ARG_ARRAY_SIZE
Definition: app_sla.c:151
static struct sla_trunk_ref * create_trunk_ref(struct sla_trunk *trunk)
Definition: app_sla.c:2106
@ SLA_TRUNK_OPT_MOH
Definition: app_sla.c:146
static struct sla_trunk * sla_find_trunk(const char *name)
Definition: app_sla.c:707
struct @66::@75 ringing_trunks
static int sla_trunk_exec(struct ast_channel *chan, const char *data)
Definition: app_sla.c:2153
struct @66::@76 ringing_stations
#define MAX_CONFNUM
Definition: app_sla.c:125
unsigned int attempt_callerid
Definition: app_sla.c:339
static void sla_ringing_trunk_destroy(struct sla_ringing_trunk *ringing_trunk)
Definition: app_sla.c:2143
static void sla_trunk_destructor(void *obj)
Definition: app_sla.c:2375
static const char * sla_hold_str(unsigned int hold_access)
Definition: app_sla.c:344
static void sla_ring_stations(void)
Ring stations based on current set of ringing trunks.
Definition: app_sla.c:1393
static void sla_queue_event(enum sla_event_type type)
Definition: app_sla.c:555
static enum ast_device_state sla_state(const char *data)
Definition: app_sla.c:2244
static void * dial_trunk(void *data)
Definition: app_sla.c:1794
static char * sla_show_stations(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: app_sla.c:435
static enum ast_device_state sla_state_to_devstate(enum sla_trunk_state state)
Definition: app_sla.c:863
static void sla_event_destroy(struct sla_event *event)
Definition: app_sla.c:1714
static struct sla_trunk_ref * sla_find_trunk_ref(const struct sla_station *station, const struct sla_trunk *trunk)
Definition: app_sla.c:1337
static void sla_destroy(void)
Definition: app_sla.c:2335
static int conf_run(struct ast_channel *chan, const char *confname, struct ast_flags *confflags, char *optargs[])
Definition: app_sla.c:917
#define S(e)
static int sla_station_exec(struct ast_channel *chan, const char *data)
Definition: app_sla.c:1949
static int sla_check_station_delay(struct sla_station *station, struct sla_ringing_trunk *ringing_trunk)
Calculate the ring delay for a given ringing trunk on a station.
Definition: app_sla.c:1357
static void sla_handle_hold_event(struct sla_event *event)
Definition: app_sla.c:1479
static int load_module(void)
Load the module.
Definition: app_sla.c:2849
static int attach_framehook(struct ast_channel *chan, const char *confname)
Definition: app_sla.c:660
static void sla_ringing_station_destroy(struct sla_ringing_station *ringing_station)
Definition: app_sla.c:828
static int sla_trunk_mark(void *obj, void *arg, int flags)
Definition: app_sla.c:2656
static int sla_calc_trunk_timeouts(unsigned int *timeout)
Process trunk ring timeouts.
Definition: app_sla.c:1501
sla_hold_access
Definition: app_sla.c:171
@ SLA_HOLD_OPEN
Definition: app_sla.c:174
@ SLA_HOLD_PRIVATE
Definition: app_sla.c:177
static int unload_module(void)
Definition: app_sla.c:2824
static int load_config(int reload)
Definition: app_sla.c:2819
static int sla_check_station_hold_access(const struct sla_trunk *trunk, const struct sla_station *station)
Definition: app_sla.c:729
static int reload(void)
Definition: app_sla.c:2864
static int sla_in_use(void)
Definition: app_sla.c:2748
static struct sla_station * sla_find_station(const char *name)
Definition: app_sla.c:720
static void sla_hangup_stations(void)
Definition: app_sla.c:1439
ast_mutex_t lock
Definition: app_sla.c:331
static struct ao2_container * sla_trunks
Definition: app_sla.c:273
static void sla_queue_event_conf(enum sla_event_type type, struct ast_channel *chan, const char *confname)
Queue a SLA event from the conference.
Definition: app_sla.c:561
static int sla_check_timed_out_station(const struct sla_ringing_trunk *ringing_trunk, const struct sla_station *station)
Check to see if dialing this station already timed out for this ringing trunk.
Definition: app_sla.c:1078
static int sla_check_ringing_station(const struct sla_station *station)
Check to see if this station is already ringing.
Definition: app_sla.c:1223
static int sla_process_timers(struct timespec *ts)
Calculate the time until the next known event.
Definition: app_sla.c:1674
static const char * trunkstate2str(enum sla_trunk_state state)
Definition: app_sla.c:421
static void sla_station_destructor(void *obj)
Definition: app_sla.c:2297
static int sla_station_cmp(void *obj, void *arg, int flags)
Definition: app_sla.c:2328
sla_station_hangup
Definition: app_sla.c:311
@ SLA_STATION_HANGUP_NORMAL
Definition: app_sla.c:312
@ SLA_STATION_HANGUP_TIMEOUT
Definition: app_sla.c:313
static const char sla_registrar[]
Definition: app_sla.c:275
static const struct ast_datastore_info sla_framehook_datastore
Definition: app_sla.c:610
struct @66::@77 failed_stations
static void * sla_thread(void *data)
Definition: app_sla.c:1729
static int sla_calc_station_timeouts(unsigned int *timeout)
Process station ring timeouts.
Definition: app_sla.c:1533
static char * sla_show_trunks(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: app_sla.c:361
static struct sla_failed_station * sla_create_failed_station(struct sla_station *station)
Definition: app_sla.c:838
#define var
Definition: ast_expr2f.c:605
Asterisk main include file. File version handling, generic pbx functions.
#define ast_free(a)
Definition: astmm.h:180
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:241
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
void ast_free_ptr(void *ptr)
free() wrapper
Definition: astmm.c:1739
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
#define ast_log
Definition: astobj2.c:42
#define ao2_iterator_next(iter)
Definition: astobj2.h:1911
#define ao2_link(container, obj)
Add an object to a container.
Definition: astobj2.h:1532
@ CMP_MATCH
Definition: astobj2.h:1027
@ CMP_STOP
Definition: astobj2.h:1028
#define OBJ_POINTER
Definition: astobj2.h:1150
@ AO2_ALLOC_OPT_LOCK_MUTEX
Definition: astobj2.h:363
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container,...
Definition: astobj2.h:1693
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1736
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
#define ao2_unlock(a)
Definition: astobj2.h:729
#define ao2_lock(a)
Definition: astobj2.h:717
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
@ OBJ_NODATA
Definition: astobj2.h:1044
@ OBJ_MULTIPLE
Definition: astobj2.h:1049
@ OBJ_UNLINK
Definition: astobj2.h:1039
#define ao2_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn)
Allocate and initialize a list container.
Definition: astobj2.h:1327
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:409
static void hold(struct ast_channel *chan)
Helper method to place a channel in a bridge on hold.
Internal Asterisk hangup causes.
enum cc_state state
Definition: ccss.c:393
static const char type[]
Definition: chan_ooh323.c:109
static int hangup(void *data)
Definition: chan_pjsip.c:2516
General Asterisk PBX channel definitions.
const char * ast_channel_name(const struct ast_channel *chan)
void ast_channel_caller_set(struct ast_channel *chan, struct ast_party_caller *value)
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
Definition: channel.c:2385
int ast_channel_datastore_remove(struct ast_channel *chan, struct ast_datastore *datastore)
Remove a datastore from a channel.
Definition: channel.c:2394
int ast_waitfor(struct ast_channel *chan, int ms)
Wait for input on a channel.
Definition: channel.c:3162
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition: channel.c:4257
void ast_party_caller_free(struct ast_party_caller *doomed)
Destroy the caller party contents.
Definition: channel.c:2015
int ast_softhangup(struct ast_channel *chan, int cause)
Softly hangup up a channel.
Definition: channel.c:2471
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:2958
@ AST_SOFTHANGUP_DEV
Definition: channel.h:1121
#define ast_dummy_channel_alloc()
Create a fake channel structure.
Definition: channel.h:1282
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
int ast_answer(struct ast_channel *chan)
Answer a channel.
Definition: channel.c:2805
int ast_indicate(struct ast_channel *chan, int condition)
Indicates condition of channel.
Definition: channel.c:4277
#define AST_MAX_EXTENSION
Definition: channel.h:134
int ast_raw_answer(struct ast_channel *chan)
Answer a channel.
Definition: channel.c:2690
struct ast_datastore * ast_channel_datastore_find(struct ast_channel *chan, const struct ast_datastore_info *info, const char *uid)
Find a datastore on a channel.
Definition: channel.c:2399
void ast_party_caller_init(struct ast_party_caller *init)
Initialize the given caller structure.
Definition: channel.c:1978
Standard Command Line Interface.
#define CLI_SUCCESS
Definition: cli.h:44
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
#define AST_CLI_DEFINE(fn, txt,...)
Definition: cli.h:197
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
@ CLI_INIT
Definition: cli.h:152
@ CLI_GENERATE
Definition: cli.h:153
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
#define ast_datastore_alloc(info, uid)
Definition: datastore.h:85
int ast_datastore_free(struct ast_datastore *datastore)
Free a data store object.
Definition: datastore.c:68
Device state management.
int ast_devstate_prov_del(const char *label)
Remove device state provider.
Definition: devicestate.c:418
@ AST_DEVSTATE_CACHABLE
Definition: devicestate.h:70
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:510
int ast_devstate_prov_add(const char *label, ast_devstate_prov_cb_type callback)
Add device state provider.
Definition: devicestate.c:391
ast_device_state
Device States.
Definition: devicestate.h:52
@ AST_DEVICE_INUSE
Definition: devicestate.h:55
@ AST_DEVICE_UNKNOWN
Definition: devicestate.h:53
@ AST_DEVICE_ONHOLD
Definition: devicestate.h:61
@ AST_DEVICE_RINGING
Definition: devicestate.h:59
@ AST_DEVICE_INVALID
Definition: devicestate.h:57
@ AST_DEVICE_NOT_INUSE
Definition: devicestate.h:54
Dialing API.
enum ast_dial_result ast_dial_state(struct ast_dial *dial)
Return state of dial.
Definition: dial.c:1008
ast_dial_result
List of return codes for dial run API calls.
Definition: dial.h:54
@ AST_DIAL_RESULT_FAILED
Definition: dial.h:56
@ AST_DIAL_RESULT_HANGUP
Definition: dial.h:63
@ AST_DIAL_RESULT_INVALID
Definition: dial.h:55
@ AST_DIAL_RESULT_ANSWERED
Definition: dial.h:61
@ AST_DIAL_RESULT_TIMEOUT
Definition: dial.h:62
@ AST_DIAL_RESULT_TRYING
Definition: dial.h:57
@ AST_DIAL_RESULT_PROGRESS
Definition: dial.h:59
@ AST_DIAL_RESULT_RINGING
Definition: dial.h:58
@ AST_DIAL_RESULT_PROCEEDING
Definition: dial.h:60
@ AST_DIAL_RESULT_UNANSWERED
Definition: dial.h:64
void ast_dial_set_state_callback(struct ast_dial *dial, ast_dial_state_callback callback)
Set a callback for state changes.
Definition: dial.c:1269
int ast_dial_append(struct ast_dial *dial, const char *tech, const char *device, const struct ast_assigned_ids *assignedids)
Append a channel.
Definition: dial.c:280
struct ast_dial * ast_dial_create(void)
New dialing structure.
Definition: dial.c:223
struct ast_channel * ast_dial_answered(struct ast_dial *dial)
Return channel that answered.
Definition: dial.c:977
enum ast_dial_result ast_dial_run(struct ast_dial *dial, struct ast_channel *chan, int async)
Execute dialing synchronously or asynchronously.
Definition: dial.c:935
enum ast_dial_result ast_dial_join(struct ast_dial *dial)
Cancel async thread.
Definition: dial.c:1017
int ast_dial_destroy(struct ast_dial *dial)
Destroys a dialing structure.
Definition: dial.c:1091
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
Generic File Format Support. Should be included by clients of the file handling routines....
static const char name[]
Definition: format_mp3.c:68
int ast_framehook_attach(struct ast_channel *chan, struct ast_framehook_interface *i)
Attach an framehook onto a channel for frame interception.
Definition: framehook.c:132
ast_framehook_event
These are the types of events that the framehook's event callback can receive.
Definition: framehook.h:151
@ AST_FRAMEHOOK_EVENT_WRITE
Definition: framehook.h:153
int ast_framehook_detach(struct ast_channel *chan, int framehook_id)
Detach an framehook from a channel.
Definition: framehook.c:177
#define AST_FRAMEHOOK_INTERFACE_VERSION
Definition: framehook.h:227
Application convenience functions, designed to give consistent look and feel to Asterisk apps.
#define AST_APP_ARG(name)
Define an application argument.
#define END_OPTIONS
#define AST_APP_OPTIONS(holder, options...)
Declares an array of options for an application.
#define AST_APP_OPTION_ARG(option, flagno, argno)
Declares an application option that accepts an argument.
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
#define BEGIN_OPTIONS
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
int ast_app_parse_options(const struct ast_app_option *options, struct ast_flags *flags, char **args, char *optstr)
Parses a string containing application options and sets flags/arguments.
Definition: main/app.c:3056
char * strsep(char **str, const char *delims)
Configuration File Parser.
#define ast_config_load(filename, flags)
Load a config file.
char * ast_category_browse(struct ast_config *config, const char *prev_name)
Browse categories.
Definition: extconf.c:3326
#define CONFIG_STATUS_FILEUNCHANGED
#define CONFIG_STATUS_FILEINVALID
void ast_config_destroy(struct ast_config *cfg)
Destroys a config.
Definition: extconf.c:1289
const char * ast_variable_retrieve(struct ast_config *config, const char *category, const char *variable)
Definition: main/config.c:783
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category_name)
Definition: extconf.c:1215
@ CONFIG_FLAG_FILEUNCHANGED
Media Format Bitfield Compatibility API.
#define ast_frfree(fr)
ast_frame_type
Frame types.
@ AST_FRAME_CONTROL
@ AST_CONTROL_PROGRESS
@ AST_CONTROL_UNHOLD
@ AST_CONTROL_RINGING
@ AST_CONTROL_HOLD
#define AST_LOG_WARNING
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_ERROR
#define LOG_NOTICE
#define LOG_WARNING
#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:225
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:491
#define AST_LIST_EMPTY(head)
Checks whether the specified list contains any entries.
Definition: linkedlists.h:450
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:731
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
Definition: linkedlists.h:410
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:615
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
Definition: linkedlists.h:711
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: linkedlists.h:529
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
Definition: linkedlists.h:557
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:833
#define AST_RWLIST_ENTRY
Definition: linkedlists.h:415
Asterisk locking-related definitions:
#define ast_cond_destroy(cond)
Definition: lock.h:202
#define ast_cond_wait(cond, mutex)
Definition: lock.h:205
#define AST_PTHREADT_NULL
Definition: lock.h:66
#define ast_cond_init(cond, attr)
Definition: lock.h:201
#define ast_cond_timedwait(cond, mutex, time)
Definition: lock.h:206
#define ast_mutex_init(pmutex)
Definition: lock.h:186
#define ast_mutex_unlock(a)
Definition: lock.h:190
int ast_atomic_fetchadd_int(volatile int *p, int v)
Atomically add v to *p and return the previous value of *p.
Definition: lock.h:757
#define SCOPED_CHANNELLOCK(varname, chan)
scoped lock specialization for channels.
Definition: lock.h:619
pthread_cond_t ast_cond_t
Definition: lock.h:178
#define ast_mutex_destroy(a)
Definition: lock.h:188
#define ast_mutex_lock(a)
Definition: lock.h:189
int ast_atomic_dec_and_test(volatile int *p)
decrement *p by 1 and return true if the variable has reached 0.
Definition: lock.h:767
#define ast_cond_signal(cond)
Definition: lock.h:203
Asterisk module definitions.
@ AST_MODFLAG_LOAD_ORDER
Definition: module.h:317
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
Definition: module.h:543
@ AST_MODPRI_DEVSTATE_PROVIDER
Definition: module.h:329
@ AST_MODULE_SUPPORT_EXTENDED
Definition: module.h:122
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx_app.c:392
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:626
Core PBX routines and definitions.
int ast_add_extension(const char *context, int replace, const char *extension, int priority, const char *label, const char *callerid, const char *application, void *data, void(*datad)(void *), const char *registrar)
Add and extension to an extension context.
Definition: pbx.c:6928
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
struct ast_context * ast_context_find_or_create(struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *name, const char *registrar)
Register a new context or find an existing one.
Definition: pbx.c:6149
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name.
int ast_context_remove_extension(const char *context, const char *extension, int priority, const char *registrar)
Simply remove extension from context.
Definition: pbx.c:4948
int ast_pbx_exec_application(struct ast_channel *chan, const char *app_name, const char *app_args)
Execute an application.
Definition: pbx_app.c:501
void ast_context_destroy(struct ast_context *con, const char *registrar)
Destroy a context (matches the specified context or ANY context if NULL)
Definition: pbx.c:8221
#define PRIORITY_HINT
Definition: pbx.h:54
int ast_func_write(struct ast_channel *chan, const char *function, const char *value)
executes a write operation on a function
#define NULL
Definition: resample.c:96
#define AST_DECLARE_STRING_FIELDS(field_list)
Declare the fields needed in a structure.
Definition: stringfields.h:341
#define AST_STRING_FIELD(name)
Declare a string field.
Definition: stringfields.h:303
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:521
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Definition: stringfields.h:359
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:374
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one.
Definition: strings.h:80
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true"....
Definition: utils.c:2199
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
int attribute_pure ast_false(const char *val)
Make sure something is false. Determine if a string containing a boolean value is "false"....
Definition: utils.c:2216
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition: strings.h:659
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition: strings.h:1113
Generic container type.
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1821
Main Channel structure associated with a channel.
descriptor for a cli entry.
Definition: cli.h:171
char * command
Definition: cli.h:186
const char * usage
Definition: cli.h:177
Structure for a data store type.
Definition: datastore.h:31
const char * type
Definition: datastore.h:32
Structure for a data store object.
Definition: datastore.h:64
void * data
Definition: datastore.h:66
Main dialing structure. Contains global options, channels being dialed, and more!
Definition: dial.c:48
Structure used to handle boolean flags.
Definition: utils.h:199
Data structure associated with a single frame of data.
struct ast_frame_subclass subclass
union ast_frame::@226 data
enum ast_frame_type frametype
Structure for mutex and tracking information.
Definition: lock.h:135
Caller Party information.
Definition: channel.h:418
Support for dynamic strings.
Definition: strings.h:623
Structure for variables, used for configurations and for channel variables.
struct sla_station * station
Definition: app_sla.c:1789
ast_cond_t * cond
Definition: app_sla.c:1791
ast_mutex_t * cond_lock
Definition: app_sla.c:1790
struct sla_trunk_ref * trunk_ref
Definition: app_sla.c:1788
Definition: search.h:40
Definition: astman.c:222
struct sla_station * station
Definition: app_sla.c:905
ast_cond_t * cond
Definition: app_sla.c:908
ast_mutex_t * cond_lock
Definition: app_sla.c:907
struct sla_trunk_ref * trunk_ref
Definition: app_sla.c:906
struct sla_station * station
Definition: app_sla.c:289
enum sla_event_type type
Definition: app_sla.c:288
struct sla_event::@70 entry
struct sla_trunk_ref * trunk_ref
Definition: app_sla.c:290
A station that failed to be dialed.
Definition: app_sla.c:296
struct sla_station * station
Definition: app_sla.c:297
struct sla_failed_station::@71 entry
struct timeval last_try
Definition: app_sla.c:298
Framehook to support HOLD within the conference.
Definition: app_sla.c:605
A station that is ringing.
Definition: app_sla.c:317
struct sla_station * station
Definition: app_sla.c:318
struct timeval ring_begin
Definition: app_sla.c:320
struct sla_ringing_station::@74 entry
A trunk that is ringing.
Definition: app_sla.c:303
struct sla_ringing_trunk::@72 timed_out_stations
struct timeval ring_begin
Definition: app_sla.c:306
struct sla_ringing_trunk::@73 entry
struct sla_trunk * trunk
Definition: app_sla.c:304
A reference to a station.
Definition: app_sla.c:214
struct sla_station * station
Definition: app_sla.c:216
struct sla_station_ref::@67 entry
unsigned int mark
Definition: app_sla.c:218
unsigned int ring_timeout
Definition: app_sla.c:194
struct ast_dial * dial
Definition: app_sla.c:190
unsigned int ring_delay
Definition: app_sla.c:198
unsigned int hold_access
Definition: app_sla.c:201
unsigned int mark
Definition: app_sla.c:203
A station's reference to a trunk.
Definition: app_sla.c:255
unsigned int ring_timeout
Definition: app_sla.c:263
enum sla_trunk_state state
Definition: app_sla.c:258
struct ast_channel * chan
Definition: app_sla.c:259
unsigned int ring_delay
Definition: app_sla.c:267
unsigned int mark
Definition: app_sla.c:269
struct sla_trunk_ref::@69 entry
struct sla_trunk * trunk
Definition: app_sla.c:257
unsigned int num_stations
Definition: app_sla.c:229
unsigned int ring_timeout
Definition: app_sla.c:235
const ast_string_field autocontext
Definition: app_sla.c:226
unsigned int hold_stations
Definition: app_sla.c:233
unsigned int barge_disabled
Definition: app_sla.c:238
struct ast_channel * chan
Definition: app_sla.c:234
unsigned int hold_access
Definition: app_sla.c:241
unsigned int mark
Definition: app_sla.c:246
unsigned int active_stations
Definition: app_sla.c:231
const ast_string_field device
Definition: app_sla.c:226
struct sla_trunk::@68 stations
const ast_string_field name
Definition: app_sla.c:226
unsigned int on_hold
Definition: app_sla.c:244
Definition: ast_expr2.c:325
int value
Definition: syslog.c:37
int done
Definition: test_amihooks.c:48
const char * args
static struct test_options options
static struct test_val a
struct timeval ast_samp2tv(unsigned int _nsamp, unsigned int _rate)
Returns a timeval corresponding to the duration of n samples at rate r. Useful to convert samples to ...
Definition: time.h:282
struct timeval ast_tvadd(struct timeval a, struct timeval b)
Returns the sum of two timevals a + b.
Definition: extconf.c:2282
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
Definition: time.h:107
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:159
Utility functions.
#define ast_test_flag(p, flag)
Definition: utils.h:63
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:941
#define ast_pthread_create(a, b, c, d)
Definition: utils.h:584
#define ast_pthread_create_detached_background(a, b, c, d)
Definition: utils.h:597
#define ast_set_flag(p, flag)
Definition: utils.h:70
#define ARRAY_LEN(a)
Definition: utils.h:666