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