ARI: Add the ability to subscribe to all events
[asterisk/asterisk.git] / res / res_stasis.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2012 - 2013, Digium, Inc.
5  *
6  * David M. Lee, II <dlee@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*! \file
20  *
21  * \brief Stasis application support.
22  *
23  * \author David M. Lee, II <dlee@digium.com>
24  *
25  * <code>res_stasis.so</code> brings together the various components of the
26  * Stasis application infrastructure.
27  *
28  * First, there's the Stasis application handler, stasis_app_exec(). This is
29  * called by <code>app_stasis.so</code> to give control of a channel to the
30  * Stasis application code from the dialplan.
31  *
32  * While a channel is in stasis_app_exec(), it has a \ref stasis_app_control
33  * object, which may be used to control the channel.
34  *
35  * To control the channel, commands may be sent to channel using
36  * stasis_app_send_command() and stasis_app_send_async_command().
37  *
38  * Alongside this, applications may be registered/unregistered using
39  * stasis_app_register()/stasis_app_unregister(). While a channel is in Stasis,
40  * events received on the channel's topic are converted to JSON and forwarded to
41  * the \ref stasis_app_cb. The application may also subscribe to the channel to
42  * continue to receive messages even after the channel has left Stasis, but it
43  * will not be able to control it.
44  *
45  * Given all the stuff that comes together in this module, it's been broken up
46  * into several pieces that are in <code>res/stasis/</code> and compiled into
47  * <code>res_stasis.so</code>.
48  */
49
50 /*** MODULEINFO
51         <support_level>core</support_level>
52  ***/
53
54 #include "asterisk.h"
55
56 ASTERISK_REGISTER_FILE()
57
58 #include "asterisk/astobj2.h"
59 #include "asterisk/callerid.h"
60 #include "asterisk/module.h"
61 #include "asterisk/stasis_app_impl.h"
62 #include "asterisk/stasis_channels.h"
63 #include "asterisk/stasis_bridges.h"
64 #include "asterisk/stasis_endpoints.h"
65 #include "asterisk/stasis_message_router.h"
66 #include "asterisk/strings.h"
67 #include "stasis/app.h"
68 #include "stasis/control.h"
69 #include "stasis/messaging.h"
70 #include "stasis/stasis_bridge.h"
71 #include "asterisk/core_unreal.h"
72 #include "asterisk/musiconhold.h"
73 #include "asterisk/causes.h"
74 #include "asterisk/stringfields.h"
75 #include "asterisk/bridge_after.h"
76 #include "asterisk/format_cache.h"
77
78 /*! Time to wait for a frame in the application */
79 #define MAX_WAIT_MS 200
80
81 /*!
82  * \brief Number of buckets for the Stasis application hash table.  Remember to
83  * keep it a prime number!
84  */
85 #define APPS_NUM_BUCKETS 127
86
87 /*!
88  * \brief Number of buckets for the Stasis application hash table.  Remember to
89  * keep it a prime number!
90  */
91 #define CONTROLS_NUM_BUCKETS 127
92
93 /*!
94  * \brief Number of buckets for the Stasis bridges hash table.  Remember to
95  * keep it a prime number!
96  */
97 #define BRIDGES_NUM_BUCKETS 127
98
99 /*!
100  * \brief Stasis application container.
101  */
102 struct ao2_container *apps_registry;
103
104 struct ao2_container *app_controls;
105
106 struct ao2_container *app_bridges;
107
108 struct ao2_container *app_bridges_moh;
109
110 struct ao2_container *app_bridges_playback;
111
112 /*!
113  * \internal \brief List of registered event sources.
114  */
115 AST_RWLIST_HEAD_STATIC(event_sources, stasis_app_event_source);
116
117 static struct ast_json *stasis_end_to_json(struct stasis_message *message,
118                 const struct stasis_message_sanitizer *sanitize)
119 {
120         struct ast_channel_blob *payload = stasis_message_data(message);
121
122         if (sanitize && sanitize->channel_snapshot &&
123                         sanitize->channel_snapshot(payload->snapshot)) {
124                 return NULL;
125         }
126
127         return ast_json_pack("{s: s, s: o, s: o}",
128                 "type", "StasisEnd",
129                 "timestamp", ast_json_timeval(ast_tvnow(), NULL),
130                 "channel", ast_channel_snapshot_to_json(payload->snapshot, sanitize));
131 }
132
133 STASIS_MESSAGE_TYPE_DEFN_LOCAL(end_message_type,
134         .to_json = stasis_end_to_json);
135
136 struct start_message_blob {
137         struct ast_channel_snapshot *channel;           /*!< Channel that is entering Stasis() */
138         struct ast_channel_snapshot *replace_channel;   /*!< Channel that is being replaced (optional) */
139         struct ast_json *blob;                          /*!< JSON blob containing timestamp and args */
140 };
141
142 static struct ast_json *stasis_start_to_json(struct stasis_message *message,
143                 const struct stasis_message_sanitizer *sanitize)
144 {
145         struct start_message_blob *payload = stasis_message_data(message);
146         struct ast_json *msg;
147
148         if (sanitize && sanitize->channel_snapshot &&
149                         sanitize->channel_snapshot(payload->channel)) {
150                 return NULL;
151         }
152
153         msg = ast_json_pack("{s: s, s: O, s: O, s: o}",
154                 "type", "StasisStart",
155                 "timestamp", ast_json_object_get(payload->blob, "timestamp"),
156                 "args", ast_json_object_get(payload->blob, "args"),
157                 "channel", ast_channel_snapshot_to_json(payload->channel, NULL));
158         if (!msg) {
159                 ast_log(LOG_ERROR, "Failed to pack JSON for StasisStart message\n");
160                 return NULL;
161         }
162
163         if (payload->replace_channel) {
164                 int res = ast_json_object_set(msg, "replace_channel",
165                         ast_channel_snapshot_to_json(payload->replace_channel, NULL));
166
167                 if (res) {
168                         ast_json_unref(msg);
169                         ast_log(LOG_ERROR, "Failed to append JSON for StasisStart message\n");
170                         return NULL;
171                 }
172         }
173
174         return msg;
175 }
176
177 STASIS_MESSAGE_TYPE_DEFN_LOCAL(start_message_type,
178         .to_json = stasis_start_to_json);
179
180 const char *stasis_app_name(const struct stasis_app *app)
181 {
182         return app_name(app);
183 }
184
185 /*! AO2 hash function for \ref app */
186 static int app_hash(const void *obj, const int flags)
187 {
188         const struct stasis_app *app;
189         const char *key;
190
191         switch (flags & OBJ_SEARCH_MASK) {
192         case OBJ_SEARCH_KEY:
193                 key = obj;
194                 break;
195         case OBJ_SEARCH_OBJECT:
196                 app = obj;
197                 key = stasis_app_name(app);
198                 break;
199         default:
200                 /* Hash can only work on something with a full key. */
201                 ast_assert(0);
202                 return 0;
203         }
204         return ast_str_hash(key);
205 }
206
207 /*! AO2 comparison function for \ref app */
208 static int app_compare(void *obj, void *arg, int flags)
209 {
210         const struct stasis_app *object_left = obj;
211         const struct stasis_app *object_right = arg;
212         const char *right_key = arg;
213         int cmp;
214
215         switch (flags & OBJ_SEARCH_MASK) {
216         case OBJ_SEARCH_OBJECT:
217                 right_key = stasis_app_name(object_right);
218                 /* Fall through */
219         case OBJ_SEARCH_KEY:
220                 cmp = strcmp(stasis_app_name(object_left), right_key);
221                 break;
222         case OBJ_SEARCH_PARTIAL_KEY:
223                 /*
224                  * We could also use a partial key struct containing a length
225                  * so strlen() does not get called for every comparison instead.
226                  */
227                 cmp = strncmp(stasis_app_name(object_left), right_key, strlen(right_key));
228                 break;
229         default:
230                 /*
231                  * What arg points to is specific to this traversal callback
232                  * and has no special meaning to astobj2.
233                  */
234                 cmp = 0;
235                 break;
236         }
237         if (cmp) {
238                 return 0;
239         }
240         /*
241          * At this point the traversal callback is identical to a sorted
242          * container.
243          */
244         return CMP_MATCH;
245 }
246
247 /*! AO2 hash function for \ref stasis_app_control */
248 static int control_hash(const void *obj, const int flags)
249 {
250         const struct stasis_app_control *control;
251         const char *key;
252
253         switch (flags & OBJ_SEARCH_MASK) {
254         case OBJ_SEARCH_KEY:
255                 key = obj;
256                 break;
257         case OBJ_SEARCH_OBJECT:
258                 control = obj;
259                 key = stasis_app_control_get_channel_id(control);
260                 break;
261         default:
262                 /* Hash can only work on something with a full key. */
263                 ast_assert(0);
264                 return 0;
265         }
266         return ast_str_hash(key);
267 }
268
269 /*! AO2 comparison function for \ref stasis_app_control */
270 static int control_compare(void *obj, void *arg, int flags)
271 {
272         const struct stasis_app_control *object_left = obj;
273         const struct stasis_app_control *object_right = arg;
274         const char *right_key = arg;
275         int cmp;
276
277         switch (flags & OBJ_SEARCH_MASK) {
278         case OBJ_SEARCH_OBJECT:
279                 right_key = stasis_app_control_get_channel_id(object_right);
280                 /* Fall through */
281         case OBJ_SEARCH_KEY:
282                 cmp = strcmp(stasis_app_control_get_channel_id(object_left), right_key);
283                 break;
284         case OBJ_SEARCH_PARTIAL_KEY:
285                 /*
286                  * We could also use a partial key struct containing a length
287                  * so strlen() does not get called for every comparison instead.
288                  */
289                 cmp = strncmp(stasis_app_control_get_channel_id(object_left), right_key, strlen(right_key));
290                 break;
291         default:
292                 /*
293                  * What arg points to is specific to this traversal callback
294                  * and has no special meaning to astobj2.
295                  */
296                 cmp = 0;
297                 break;
298         }
299         if (cmp) {
300                 return 0;
301         }
302         /*
303          * At this point the traversal callback is identical to a sorted
304          * container.
305          */
306         return CMP_MATCH;
307 }
308
309 static int cleanup_cb(void *obj, void *arg, int flags)
310 {
311         struct stasis_app *app = obj;
312
313         if (!app_is_finished(app)) {
314                 return 0;
315         }
316
317         ast_verb(1, "Shutting down application '%s'\n", stasis_app_name(app));
318         app_shutdown(app);
319
320         return CMP_MATCH;
321
322 }
323
324 /*!
325  * \brief Clean up any old apps that we don't need any more.
326  */
327 static void cleanup(void)
328 {
329         ao2_callback(apps_registry, OBJ_MULTIPLE | OBJ_NODATA | OBJ_UNLINK,
330                 cleanup_cb, NULL);
331 }
332
333 struct stasis_app_control *stasis_app_control_create(struct ast_channel *chan)
334 {
335         return control_create(chan, NULL);
336 }
337
338 struct stasis_app_control *stasis_app_control_find_by_channel(
339         const struct ast_channel *chan)
340 {
341         if (chan == NULL) {
342                 return NULL;
343         }
344
345         return stasis_app_control_find_by_channel_id(
346                 ast_channel_uniqueid(chan));
347 }
348
349 struct stasis_app_control *stasis_app_control_find_by_channel_id(
350         const char *channel_id)
351 {
352         return ao2_find(app_controls, channel_id, OBJ_SEARCH_KEY);
353 }
354
355 /*! AO2 hash function for bridges container  */
356 static int bridges_hash(const void *obj, const int flags)
357 {
358         const struct ast_bridge *bridge;
359         const char *key;
360
361         switch (flags & OBJ_SEARCH_MASK) {
362         case OBJ_SEARCH_KEY:
363                 key = obj;
364                 break;
365         case OBJ_SEARCH_OBJECT:
366                 bridge = obj;
367                 key = bridge->uniqueid;
368                 break;
369         default:
370                 /* Hash can only work on something with a full key. */
371                 ast_assert(0);
372                 return 0;
373         }
374         return ast_str_hash(key);
375 }
376
377 /*! AO2 comparison function for bridges container */
378 static int bridges_compare(void *obj, void *arg, int flags)
379 {
380         const struct ast_bridge *object_left = obj;
381         const struct ast_bridge *object_right = arg;
382         const char *right_key = arg;
383         int cmp;
384
385         switch (flags & OBJ_SEARCH_MASK) {
386         case OBJ_SEARCH_OBJECT:
387                 right_key = object_right->uniqueid;
388                 /* Fall through */
389         case OBJ_SEARCH_KEY:
390                 cmp = strcmp(object_left->uniqueid, right_key);
391                 break;
392         case OBJ_SEARCH_PARTIAL_KEY:
393                 /*
394                  * We could also use a partial key struct containing a length
395                  * so strlen() does not get called for every comparison instead.
396                  */
397                 cmp = strncmp(object_left->uniqueid, right_key, strlen(right_key));
398                 break;
399         default:
400                 /*
401                  * What arg points to is specific to this traversal callback
402                  * and has no special meaning to astobj2.
403                  */
404                 cmp = 0;
405                 break;
406         }
407         if (cmp) {
408                 return 0;
409         }
410         /*
411          * At this point the traversal callback is identical to a sorted
412          * container.
413          */
414         return CMP_MATCH;
415 }
416
417 /*!
418  *  Used with app_bridges_moh and app_bridge_control, they provide links
419  *  between bridges and channels used for ARI application purposes
420  */
421 struct stasis_app_bridge_channel_wrapper {
422         AST_DECLARE_STRING_FIELDS(
423                 AST_STRING_FIELD(channel_id);
424                 AST_STRING_FIELD(bridge_id);
425         );
426 };
427
428 static void stasis_app_bridge_channel_wrapper_destructor(void *obj)
429 {
430         struct stasis_app_bridge_channel_wrapper *wrapper = obj;
431         ast_string_field_free_memory(wrapper);
432 }
433
434 /*! AO2 hash function for the bridges moh container */
435 static int bridges_channel_hash_fn(const void *obj, const int flags)
436 {
437         const struct stasis_app_bridge_channel_wrapper *wrapper;
438         const char *key;
439
440         switch (flags & OBJ_SEARCH_MASK) {
441         case OBJ_SEARCH_KEY:
442                 key = obj;
443                 break;
444         case OBJ_SEARCH_OBJECT:
445                 wrapper = obj;
446                 key = wrapper->bridge_id;
447                 break;
448         default:
449                 /* Hash can only work on something with a full key. */
450                 ast_assert(0);
451                 return 0;
452         }
453         return ast_str_hash(key);
454 }
455
456 static int bridges_channel_sort_fn(const void *obj_left, const void *obj_right, const int flags)
457 {
458         const struct stasis_app_bridge_channel_wrapper *left = obj_left;
459         const struct stasis_app_bridge_channel_wrapper *right = obj_right;
460         const char *right_key = obj_right;
461         int cmp;
462
463         switch (flags & OBJ_SEARCH_MASK) {
464         case OBJ_SEARCH_OBJECT:
465                 right_key = right->bridge_id;
466                 /* Fall through */
467         case OBJ_SEARCH_KEY:
468                 cmp = strcmp(left->bridge_id, right_key);
469                 break;
470         case OBJ_SEARCH_PARTIAL_KEY:
471                 cmp = strncmp(left->bridge_id, right_key, strlen(right_key));
472                 break;
473         default:
474                 /* Sort can only work on something with a full or partial key. */
475                 ast_assert(0);
476                 cmp = 0;
477                 break;
478         }
479         return cmp;
480 }
481
482 /*! Removes the bridge to music on hold channel link */
483 static void remove_bridge_moh(char *bridge_id)
484 {
485         ao2_find(app_bridges_moh, bridge_id, OBJ_SEARCH_KEY | OBJ_UNLINK | OBJ_NODATA);
486         ast_free(bridge_id);
487 }
488
489 /*! After bridge failure callback for moh channels */
490 static void moh_after_bridge_cb_failed(enum ast_bridge_after_cb_reason reason, void *data)
491 {
492         char *bridge_id = data;
493
494         remove_bridge_moh(bridge_id);
495 }
496
497 /*! After bridge callback for moh channels */
498 static void moh_after_bridge_cb(struct ast_channel *chan, void *data)
499 {
500         char *bridge_id = data;
501
502         remove_bridge_moh(bridge_id);
503 }
504
505 /*! Request a bridge MOH channel */
506 static struct ast_channel *prepare_bridge_moh_channel(void)
507 {
508         RAII_VAR(struct ast_format_cap *, cap, NULL, ao2_cleanup);
509
510         cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
511         if (!cap) {
512                 return NULL;
513         }
514
515         ast_format_cap_append(cap, ast_format_slin, 0);
516
517         return ast_request("Announcer", cap, NULL, NULL, "ARI_MOH", NULL);
518 }
519
520 /*! Provides the moh channel with a thread so it can actually play its music */
521 static void *moh_channel_thread(void *data)
522 {
523         struct ast_channel *moh_channel = data;
524
525         while (!ast_safe_sleep(moh_channel, 1000)) {
526         }
527
528         ast_moh_stop(moh_channel);
529         ast_hangup(moh_channel);
530
531         return NULL;
532 }
533
534 /*!
535  * \internal
536  * \brief Creates, pushes, and links a channel for playing music on hold to bridge
537  *
538  * \param bridge Which bridge this moh channel exists for
539  *
540  * \retval NULL if the channel could not be created, pushed, or linked
541  * \retval Reference to the channel on success
542  */
543 static struct ast_channel *bridge_moh_create(struct ast_bridge *bridge)
544 {
545         RAII_VAR(struct stasis_app_bridge_channel_wrapper *, new_wrapper, NULL, ao2_cleanup);
546         RAII_VAR(char *, bridge_id, ast_strdup(bridge->uniqueid), ast_free);
547         struct ast_channel *chan;
548         pthread_t threadid;
549
550         if (!bridge_id) {
551                 return NULL;
552         }
553
554         chan = prepare_bridge_moh_channel();
555         if (!chan) {
556                 return NULL;
557         }
558
559         if (stasis_app_channel_unreal_set_internal(chan)) {
560                 ast_hangup(chan);
561                 return NULL;
562         }
563
564         /* The after bridge callback assumes responsibility of the bridge_id. */
565         if (ast_bridge_set_after_callback(chan,
566                 moh_after_bridge_cb, moh_after_bridge_cb_failed, bridge_id)) {
567                 ast_hangup(chan);
568                 return NULL;
569         }
570         bridge_id = NULL;
571
572         if (ast_unreal_channel_push_to_bridge(chan, bridge,
573                 AST_BRIDGE_CHANNEL_FLAG_IMMOVABLE | AST_BRIDGE_CHANNEL_FLAG_LONELY)) {
574                 ast_hangup(chan);
575                 return NULL;
576         }
577
578         new_wrapper = ao2_alloc_options(sizeof(*new_wrapper),
579                 stasis_app_bridge_channel_wrapper_destructor, AO2_ALLOC_OPT_LOCK_NOLOCK);
580         if (!new_wrapper) {
581                 ast_hangup(chan);
582                 return NULL;
583         }
584
585         if (ast_string_field_init(new_wrapper, 32)) {
586                 ast_hangup(chan);
587                 return NULL;
588         }
589         ast_string_field_set(new_wrapper, bridge_id, bridge->uniqueid);
590         ast_string_field_set(new_wrapper, channel_id, ast_channel_uniqueid(chan));
591
592         if (!ao2_link_flags(app_bridges_moh, new_wrapper, OBJ_NOLOCK)) {
593                 ast_hangup(chan);
594                 return NULL;
595         }
596
597         if (ast_pthread_create_detached(&threadid, NULL, moh_channel_thread, chan)) {
598                 ast_log(LOG_ERROR, "Failed to create channel thread. Abandoning MOH channel creation.\n");
599                 ao2_unlink_flags(app_bridges_moh, new_wrapper, OBJ_NOLOCK);
600                 ast_hangup(chan);
601                 return NULL;
602         }
603
604         return chan;
605 }
606
607 struct ast_channel *stasis_app_bridge_moh_channel(struct ast_bridge *bridge)
608 {
609         RAII_VAR(struct stasis_app_bridge_channel_wrapper *, moh_wrapper, NULL, ao2_cleanup);
610
611         {
612                 SCOPED_AO2LOCK(lock, app_bridges_moh);
613
614                 moh_wrapper = ao2_find(app_bridges_moh, bridge->uniqueid, OBJ_SEARCH_KEY | OBJ_NOLOCK);
615                 if (!moh_wrapper) {
616                         return bridge_moh_create(bridge);
617                 }
618         }
619
620         return ast_channel_get_by_name(moh_wrapper->channel_id);
621 }
622
623 int stasis_app_bridge_moh_stop(struct ast_bridge *bridge)
624 {
625         RAII_VAR(struct stasis_app_bridge_channel_wrapper *, moh_wrapper, NULL, ao2_cleanup);
626         struct ast_channel *chan;
627
628         moh_wrapper = ao2_find(app_bridges_moh, bridge->uniqueid, OBJ_SEARCH_KEY | OBJ_UNLINK);
629         if (!moh_wrapper) {
630                 return -1;
631         }
632
633         chan = ast_channel_get_by_name(moh_wrapper->channel_id);
634         if (!chan) {
635                 return -1;
636         }
637
638         ast_moh_stop(chan);
639         ast_softhangup(chan, AST_CAUSE_NORMAL_CLEARING);
640         ao2_cleanup(chan);
641
642         return 0;
643 }
644
645 /*! Removes the bridge to playback channel link */
646 static void remove_bridge_playback(char *bridge_id)
647 {
648         struct stasis_app_bridge_channel_wrapper *wrapper;
649         struct stasis_app_control *control;
650
651         wrapper = ao2_find(app_bridges_playback, bridge_id, OBJ_SEARCH_KEY | OBJ_UNLINK);
652
653         if (wrapper) {
654                 control = stasis_app_control_find_by_channel_id(wrapper->channel_id);
655                 if (control) {
656                         ao2_unlink(app_controls, control);
657                         ao2_ref(control, -1);
658                 }
659                 ao2_ref(wrapper, -1);
660         }
661         ast_free(bridge_id);
662 }
663
664 static void playback_after_bridge_cb_failed(enum ast_bridge_after_cb_reason reason, void *data)
665 {
666         char *bridge_id = data;
667
668         remove_bridge_playback(bridge_id);
669 }
670
671 static void playback_after_bridge_cb(struct ast_channel *chan, void *data)
672 {
673         char *bridge_id = data;
674
675         remove_bridge_playback(bridge_id);
676 }
677
678 int stasis_app_bridge_playback_channel_add(struct ast_bridge *bridge,
679         struct ast_channel *chan,
680         struct stasis_app_control *control)
681 {
682         RAII_VAR(struct stasis_app_bridge_channel_wrapper *, new_wrapper, NULL, ao2_cleanup);
683         char *bridge_id = ast_strdup(bridge->uniqueid);
684
685         if (!bridge_id) {
686                 return -1;
687         }
688
689         if (ast_bridge_set_after_callback(chan,
690                 playback_after_bridge_cb, playback_after_bridge_cb_failed, bridge_id)) {
691                 ast_free(bridge_id);
692                 return -1;
693         }
694
695         new_wrapper = ao2_alloc_options(sizeof(*new_wrapper),
696                 stasis_app_bridge_channel_wrapper_destructor, AO2_ALLOC_OPT_LOCK_NOLOCK);
697         if (!new_wrapper) {
698                 return -1;
699         }
700
701         if (ast_string_field_init(new_wrapper, 32)) {
702                 return -1;
703         }
704
705         ast_string_field_set(new_wrapper, bridge_id, bridge->uniqueid);
706         ast_string_field_set(new_wrapper, channel_id, ast_channel_uniqueid(chan));
707
708         if (!ao2_link(app_bridges_playback, new_wrapper)) {
709                 return -1;
710         }
711
712         ao2_link(app_controls, control);
713         return 0;
714 }
715
716 struct ast_channel *stasis_app_bridge_playback_channel_find(struct ast_bridge *bridge)
717 {
718         struct stasis_app_bridge_channel_wrapper *playback_wrapper;
719         struct ast_channel *chan;
720
721         playback_wrapper = ao2_find(app_bridges_playback, bridge->uniqueid, OBJ_SEARCH_KEY);
722         if (!playback_wrapper) {
723                 return NULL;
724         }
725
726         chan = ast_channel_get_by_name(playback_wrapper->channel_id);
727         ao2_ref(playback_wrapper, -1);
728         return chan;
729 }
730
731 struct ast_bridge *stasis_app_bridge_find_by_id(
732         const char *bridge_id)
733 {
734         return ao2_find(app_bridges, bridge_id, OBJ_SEARCH_KEY);
735 }
736
737
738 /*!
739  * \brief In addition to running ao2_cleanup(), this function also removes the
740  * object from the app_controls container.
741  */
742 static void control_unlink(struct stasis_app_control *control)
743 {
744         if (!control) {
745                 return;
746         }
747
748         ao2_unlink(app_controls, control);
749         ao2_cleanup(control);
750 }
751
752 struct ast_bridge *stasis_app_bridge_create(const char *type, const char *name, const char *id)
753 {
754         struct ast_bridge *bridge;
755         char *requested_type, *requested_types = ast_strdupa(S_OR(type, "mixing"));
756         int capabilities = 0;
757         int flags = AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM | AST_BRIDGE_FLAG_MERGE_INHIBIT_TO
758                 | AST_BRIDGE_FLAG_SWAP_INHIBIT_FROM | AST_BRIDGE_FLAG_SWAP_INHIBIT_TO
759                 | AST_BRIDGE_FLAG_TRANSFER_BRIDGE_ONLY;
760
761         while ((requested_type = strsep(&requested_types, ","))) {
762                 requested_type = ast_strip(requested_type);
763
764                 if (!strcmp(requested_type, "mixing")) {
765                         capabilities |= STASIS_BRIDGE_MIXING_CAPABILITIES;
766                         flags |= AST_BRIDGE_FLAG_SMART;
767                 } else if (!strcmp(requested_type, "holding")) {
768                         capabilities |= AST_BRIDGE_CAPABILITY_HOLDING;
769                 } else if (!strcmp(requested_type, "dtmf_events") ||
770                         !strcmp(requested_type, "proxy_media")) {
771                         capabilities &= ~AST_BRIDGE_CAPABILITY_NATIVE;
772                 }
773         }
774
775         if (!capabilities
776                 /* Holding and mixing capabilities don't mix. */
777                 || ((capabilities & AST_BRIDGE_CAPABILITY_HOLDING)
778                         && (capabilities & (STASIS_BRIDGE_MIXING_CAPABILITIES)))) {
779                 return NULL;
780         }
781
782         bridge = bridge_stasis_new(capabilities, flags, name, id);
783         if (bridge) {
784                 if (!ao2_link(app_bridges, bridge)) {
785                         ast_bridge_destroy(bridge, 0);
786                         bridge = NULL;
787                 }
788         }
789         return bridge;
790 }
791
792 void stasis_app_bridge_destroy(const char *bridge_id)
793 {
794         struct ast_bridge *bridge = stasis_app_bridge_find_by_id(bridge_id);
795         if (!bridge) {
796                 return;
797         }
798         ao2_unlink(app_bridges, bridge);
799         ast_bridge_destroy(bridge, 0);
800 }
801
802 struct replace_channel_store {
803         struct ast_channel_snapshot *snapshot;
804         char *app;
805 };
806
807 static void replace_channel_destroy(void *obj)
808 {
809         struct replace_channel_store *replace = obj;
810
811         ao2_cleanup(replace->snapshot);
812         ast_free(replace->app);
813         ast_free(replace);
814 }
815
816 static const struct ast_datastore_info replace_channel_store_info = {
817         .type = "replace-channel-store",
818         .destroy = replace_channel_destroy,
819 };
820
821 static struct replace_channel_store *get_replace_channel_store(struct ast_channel *chan, int no_create)
822 {
823         struct ast_datastore *datastore;
824
825         SCOPED_CHANNELLOCK(lock, chan);
826         datastore = ast_channel_datastore_find(chan, &replace_channel_store_info, NULL);
827         if (!datastore) {
828                 if (no_create) {
829                         return NULL;
830                 }
831
832                 datastore = ast_datastore_alloc(&replace_channel_store_info, NULL);
833                 if (!datastore) {
834                         return NULL;
835                 }
836                 ast_channel_datastore_add(chan, datastore);
837         }
838
839         if (!datastore->data) {
840                 datastore->data = ast_calloc(1, sizeof(struct replace_channel_store));
841         }
842         return datastore->data;
843 }
844
845 int app_set_replace_channel_snapshot(struct ast_channel *chan, struct ast_channel_snapshot *replace_snapshot)
846 {
847         struct replace_channel_store *replace = get_replace_channel_store(chan, 0);
848
849         if (!replace) {
850                 return -1;
851         }
852
853         ao2_replace(replace->snapshot, replace_snapshot);
854         return 0;
855 }
856
857 int app_set_replace_channel_app(struct ast_channel *chan, const char *replace_app)
858 {
859         struct replace_channel_store *replace = get_replace_channel_store(chan, 0);
860
861         if (!replace) {
862                 return -1;
863         }
864
865         ast_free(replace->app);
866         replace->app = NULL;
867
868         if (replace_app) {
869                 replace->app = ast_strdup(replace_app);
870                 if (!replace->app) {
871                         return -1;
872                 }
873         }
874
875         return 0;
876 }
877
878 static struct ast_channel_snapshot *get_replace_channel_snapshot(struct ast_channel *chan)
879 {
880         struct replace_channel_store *replace = get_replace_channel_store(chan, 1);
881         struct ast_channel_snapshot *replace_channel_snapshot;
882
883         if (!replace) {
884                 return NULL;
885         }
886
887         replace_channel_snapshot = replace->snapshot;
888         replace->snapshot = NULL;
889
890         return replace_channel_snapshot;
891 }
892
893 char *app_get_replace_channel_app(struct ast_channel *chan)
894 {
895         struct replace_channel_store *replace = get_replace_channel_store(chan, 1);
896         char *replace_channel_app;
897
898         if (!replace) {
899                 return NULL;
900         }
901
902         replace_channel_app = replace->app;
903         replace->app = NULL;
904
905         return replace_channel_app;
906 }
907
908 static void start_message_blob_dtor(void *obj)
909 {
910         struct start_message_blob *payload = obj;
911
912         ao2_cleanup(payload->channel);
913         ao2_cleanup(payload->replace_channel);
914         ast_json_unref(payload->blob);
915 }
916
917 static int send_start_msg_snapshots(struct ast_channel *chan, struct stasis_app *app,
918         int argc, char *argv[], struct ast_channel_snapshot *snapshot,
919         struct ast_channel_snapshot *replace_channel_snapshot)
920 {
921         RAII_VAR(struct ast_json *, json_blob, NULL, ast_json_unref);
922         struct ast_json *json_args;
923         RAII_VAR(struct start_message_blob *, payload, NULL, ao2_cleanup);
924         struct stasis_message *msg;
925         int i;
926
927         if (app_subscribe_channel(app, chan)) {
928                 ast_log(LOG_ERROR, "Error subscribing app '%s' to channel '%s'\n",
929                         app_name(app), ast_channel_name(chan));
930                 return -1;
931         }
932
933         payload = ao2_alloc(sizeof(*payload), start_message_blob_dtor);
934         if (!payload) {
935                 ast_log(LOG_ERROR, "Error packing JSON for StasisStart message\n");
936                 return -1;
937         }
938
939         payload->channel = ao2_bump(snapshot);
940         payload->replace_channel = ao2_bump(replace_channel_snapshot);
941
942         json_blob = ast_json_pack("{s: s, s: o, s: []}",
943                 "app", app_name(app),
944                 "timestamp", ast_json_timeval(ast_tvnow(), NULL),
945                 "args");
946         if (!json_blob) {
947                 ast_log(LOG_ERROR, "Error packing JSON for StasisStart message\n");
948                 return -1;
949         }
950
951         /* Append arguments to args array */
952         json_args = ast_json_object_get(json_blob, "args");
953         ast_assert(json_args != NULL);
954         for (i = 0; i < argc; ++i) {
955                 int r = ast_json_array_append(json_args,
956                                               ast_json_string_create(argv[i]));
957                 if (r != 0) {
958                         ast_log(LOG_ERROR, "Error appending to StasisStart message\n");
959                         return -1;
960                 }
961         }
962
963         payload->blob = ast_json_ref(json_blob);
964
965         msg = stasis_message_create(start_message_type(), payload);
966         if (!msg) {
967                 ast_log(LOG_ERROR, "Error sending StasisStart message\n");
968                 return -1;
969         }
970
971         if (replace_channel_snapshot) {
972                 app_unsubscribe_channel_id(app, replace_channel_snapshot->uniqueid);
973         }
974         stasis_publish(ast_app_get_topic(app), msg);
975         ao2_ref(msg, -1);
976         return 0;
977 }
978
979 static int send_start_msg(struct stasis_app *app, struct ast_channel *chan,
980         int argc, char *argv[])
981 {
982         RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
983         RAII_VAR(struct ast_channel_snapshot *, replace_channel_snapshot,
984                 NULL, ao2_cleanup);
985
986         ast_assert(chan != NULL);
987
988         replace_channel_snapshot = get_replace_channel_snapshot(chan);
989
990         /* Set channel info */
991         ast_channel_lock(chan);
992         snapshot = ast_channel_snapshot_create(chan);
993         ast_channel_unlock(chan);
994         if (!snapshot) {
995                 return -1;
996         }
997         return send_start_msg_snapshots(chan, app, argc, argv, snapshot, replace_channel_snapshot);
998 }
999
1000 static void remove_masquerade_store(struct ast_channel *chan);
1001
1002 int app_send_end_msg(struct stasis_app *app, struct ast_channel *chan)
1003 {
1004         struct stasis_message_sanitizer *sanitize = stasis_app_get_sanitizer();
1005         struct ast_json *blob;
1006         struct stasis_message *msg;
1007
1008         if (sanitize && sanitize->channel
1009                 && sanitize->channel(chan)) {
1010                 return 0;
1011         }
1012
1013         blob = ast_json_pack("{s: s}", "app", app_name(app));
1014         if (!blob) {
1015                 ast_log(LOG_ERROR, "Error packing JSON for StasisEnd message\n");
1016                 return -1;
1017         }
1018
1019         remove_masquerade_store(chan);
1020         app_unsubscribe_channel(app, chan);
1021         msg = ast_channel_blob_create(chan, end_message_type(), blob);
1022         if (msg) {
1023                 stasis_publish(ast_app_get_topic(app), msg);
1024         }
1025         ao2_cleanup(msg);
1026         ast_json_unref(blob);
1027
1028         return 0;
1029 }
1030
1031 static int masq_match_cb(void *obj, void *data, int flags)
1032 {
1033         struct stasis_app_control *control = obj;
1034         struct ast_channel *chan = data;
1035
1036         if (!strcmp(ast_channel_uniqueid(chan),
1037                 stasis_app_control_get_channel_id(control))) {
1038                 return CMP_MATCH;
1039         }
1040
1041         return 0;
1042 }
1043
1044 static void channel_stolen_cb(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
1045 {
1046         struct stasis_app_control *control;
1047
1048         /* find control */
1049         control = ao2_callback(app_controls, 0, masq_match_cb, old_chan);
1050         if (!control) {
1051                 ast_log(LOG_ERROR, "Could not find control for masqueraded channel\n");
1052                 return;
1053         }
1054
1055         /* send the StasisEnd message to the app */
1056         stasis_app_channel_set_stasis_end_published(new_chan);
1057         app_send_end_msg(control_app(control), new_chan);
1058
1059         /* remove the datastore */
1060         remove_masquerade_store(old_chan);
1061
1062         ao2_cleanup(control);
1063 }
1064
1065 static void channel_replaced_cb(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
1066 {
1067         RAII_VAR(struct ast_channel_snapshot *, new_snapshot, NULL, ao2_cleanup);
1068         RAII_VAR(struct ast_channel_snapshot *, old_snapshot, NULL, ao2_cleanup);
1069         struct stasis_app_control *control;
1070
1071         /* At this point, new_chan is the channel pointer that is in Stasis() and
1072          * has the unknown channel's name in it while old_chan is the channel pointer
1073          * that is not in Stasis(), but has the guts of the channel that Stasis() knows
1074          * about */
1075
1076         /* grab a snapshot for the channel that is jumping into Stasis() */
1077         new_snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(new_chan));
1078         if (!new_snapshot) {
1079                 ast_log(LOG_ERROR, "Could not get snapshot for masquerading channel\n");
1080                 return;
1081         }
1082
1083         /* grab a snapshot for the channel that has been kicked out of Stasis() */
1084         old_snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(old_chan));
1085         if (!old_snapshot) {
1086                 ast_log(LOG_ERROR, "Could not get snapshot for masqueraded channel\n");
1087                 return;
1088         }
1089
1090         /* find, unlink, and relink control since the channel has a new name and
1091          * its hash has likely changed */
1092         control = ao2_callback(app_controls, OBJ_UNLINK, masq_match_cb, new_chan);
1093         if (!control) {
1094                 ast_log(LOG_ERROR, "Could not find control for masquerading channel\n");
1095                 return;
1096         }
1097         ao2_link(app_controls, control);
1098
1099
1100         /* send the StasisStart with replace_channel to the app */
1101         send_start_msg_snapshots(new_chan, control_app(control), 0, NULL, new_snapshot,
1102                 old_snapshot);
1103         /* send the StasisEnd message to the app */
1104         app_send_end_msg(control_app(control), old_chan);
1105
1106         ao2_cleanup(control);
1107 }
1108
1109 static const struct ast_datastore_info masquerade_store_info = {
1110         .type = "stasis-masqerade",
1111         .chan_fixup = channel_stolen_cb,
1112         .chan_breakdown = channel_replaced_cb,
1113 };
1114
1115 static int has_masquerade_store(struct ast_channel *chan)
1116 {
1117         SCOPED_CHANNELLOCK(lock, chan);
1118         return !!ast_channel_datastore_find(chan, &masquerade_store_info, NULL);
1119 }
1120
1121 static int add_masquerade_store(struct ast_channel *chan)
1122 {
1123         struct ast_datastore *datastore;
1124
1125         SCOPED_CHANNELLOCK(lock, chan);
1126         if (ast_channel_datastore_find(chan, &masquerade_store_info, NULL)) {
1127                 return 0;
1128         }
1129
1130         datastore = ast_datastore_alloc(&masquerade_store_info, NULL);
1131         if (!datastore) {
1132                 return -1;
1133         }
1134
1135         ast_channel_datastore_add(chan, datastore);
1136
1137         return 0;
1138 }
1139
1140 static void remove_masquerade_store(struct ast_channel *chan)
1141 {
1142         struct ast_datastore *datastore;
1143
1144         SCOPED_CHANNELLOCK(lock, chan);
1145         datastore = ast_channel_datastore_find(chan, &masquerade_store_info, NULL);
1146         if (!datastore) {
1147                 return;
1148         }
1149
1150         ast_channel_datastore_remove(chan, datastore);
1151         ast_datastore_free(datastore);
1152 }
1153
1154 void stasis_app_control_execute_until_exhausted(struct ast_channel *chan, struct stasis_app_control *control)
1155 {
1156         while (!control_is_done(control)) {
1157                 int command_count;
1158                 command_count = control_dispatch_all(control, chan);
1159
1160                 ao2_lock(control);
1161
1162                 if (control_command_count(control)) {
1163                         /* If the command queue isn't empty, something added to the queue before it was locked. */
1164                         ao2_unlock(control);
1165                         continue;
1166                 }
1167
1168                 if (command_count == 0 || ast_channel_fdno(chan) == -1) {
1169                         control_mark_done(control);
1170                         ao2_unlock(control);
1171                         break;
1172                 }
1173                 ao2_unlock(control);
1174         }
1175 }
1176
1177 int stasis_app_control_is_done(struct stasis_app_control *control)
1178 {
1179         return control_is_done(control);
1180 }
1181
1182 struct ast_datastore_info set_end_published_info = {
1183         .type = "stasis_end_published",
1184 };
1185
1186 void stasis_app_channel_set_stasis_end_published(struct ast_channel *chan)
1187 {
1188         struct ast_datastore *datastore;
1189
1190         datastore = ast_datastore_alloc(&set_end_published_info, NULL);
1191
1192         ast_channel_lock(chan);
1193         ast_channel_datastore_add(chan, datastore);
1194         ast_channel_unlock(chan);
1195 }
1196
1197 int stasis_app_channel_is_stasis_end_published(struct ast_channel *chan)
1198 {
1199         struct ast_datastore *datastore;
1200
1201         ast_channel_lock(chan);
1202         datastore = ast_channel_datastore_find(chan, &set_end_published_info, NULL);
1203         ast_channel_unlock(chan);
1204
1205         return datastore ? 1 : 0;
1206 }
1207
1208 static void remove_stasis_end_published(struct ast_channel *chan)
1209 {
1210         struct ast_datastore *datastore;
1211
1212         ast_channel_lock(chan);
1213         datastore = ast_channel_datastore_find(chan, &set_end_published_info, NULL);
1214         ast_channel_unlock(chan);
1215
1216         if (datastore) {
1217                 ast_channel_datastore_remove(chan, datastore);
1218                 ast_datastore_free(datastore);
1219         }
1220 }
1221
1222 /*! /brief Stasis dialplan application callback */
1223 int stasis_app_exec(struct ast_channel *chan, const char *app_name, int argc,
1224                     char *argv[])
1225 {
1226         SCOPED_MODULE_USE(ast_module_info->self);
1227
1228         RAII_VAR(struct stasis_app *, app, NULL, ao2_cleanup);
1229         RAII_VAR(struct stasis_app_control *, control, NULL, control_unlink);
1230         struct ast_bridge *bridge = NULL;
1231         int res = 0;
1232         int needs_depart;
1233
1234         ast_assert(chan != NULL);
1235
1236         /* Just in case there's a lingering indication that the channel has had a stasis
1237          * end published on it, remove that now.
1238          */
1239         remove_stasis_end_published(chan);
1240
1241         if (!apps_registry) {
1242                 return -1;
1243         }
1244
1245         app = ao2_find(apps_registry, app_name, OBJ_SEARCH_KEY);
1246         if (!app) {
1247                 ast_log(LOG_ERROR,
1248                         "Stasis app '%s' not registered\n", app_name);
1249                 return -1;
1250         }
1251         if (!app_is_active(app)) {
1252                 ast_log(LOG_ERROR,
1253                         "Stasis app '%s' not active\n", app_name);
1254                 return -1;
1255         }
1256
1257         control = control_create(chan, app);
1258         if (!control) {
1259                 ast_log(LOG_ERROR, "Allocated failed\n");
1260                 return -1;
1261         }
1262         ao2_link(app_controls, control);
1263
1264         if (add_masquerade_store(chan)) {
1265                 ast_log(LOG_ERROR, "Failed to attach masquerade detector\n");
1266                 return -1;
1267         }
1268
1269         res = send_start_msg(app, chan, argc, argv);
1270         if (res != 0) {
1271                 ast_log(LOG_ERROR,
1272                         "Error sending start message to '%s'\n", app_name);
1273                 remove_masquerade_store(chan);
1274                 return -1;
1275         }
1276
1277         /* Pull queued prestart commands and execute */
1278         control_prestart_dispatch_all(control, chan);
1279
1280         while (!control_is_done(control)) {
1281                 RAII_VAR(struct ast_frame *, f, NULL, ast_frame_dtor);
1282                 int r;
1283                 int command_count;
1284                 RAII_VAR(struct ast_bridge *, last_bridge, NULL, ao2_cleanup);
1285
1286                 /* Check to see if a bridge absorbed our hangup frame */
1287                 if (ast_check_hangup_locked(chan)) {
1288                         control_mark_done(control);
1289                         break;
1290                 }
1291
1292                 last_bridge = bridge;
1293                 bridge = ao2_bump(stasis_app_get_bridge(control));
1294
1295                 if (bridge != last_bridge) {
1296                         app_unsubscribe_bridge(app, last_bridge);
1297                         app_subscribe_bridge(app, bridge);
1298                 }
1299
1300                 if (bridge) {
1301                         /* Bridge is handling channel frames */
1302                         control_wait(control);
1303                         control_dispatch_all(control, chan);
1304                         continue;
1305                 }
1306
1307                 r = ast_waitfor(chan, MAX_WAIT_MS);
1308
1309                 if (r < 0) {
1310                         ast_debug(3, "%s: Poll error\n",
1311                                   ast_channel_uniqueid(chan));
1312                         control_mark_done(control);
1313                         break;
1314                 }
1315
1316                 command_count = control_dispatch_all(control, chan);
1317
1318                 if (command_count > 0 && ast_channel_fdno(chan) == -1) {
1319                         /* Command drained the channel; wait for next frame */
1320                         continue;
1321                 }
1322
1323                 if (r == 0) {
1324                         /* Timeout */
1325                         continue;
1326                 }
1327
1328                 f = ast_read(chan);
1329                 if (!f) {
1330                         /* Continue on in the dialplan */
1331                         ast_debug(3, "%s: Hangup (no more frames)\n",
1332                                 ast_channel_uniqueid(chan));
1333                         control_mark_done(control);
1334                         break;
1335                 }
1336
1337                 if (f->frametype == AST_FRAME_CONTROL) {
1338                         if (f->subclass.integer == AST_CONTROL_HANGUP) {
1339                                 /* Continue on in the dialplan */
1340                                 ast_debug(3, "%s: Hangup\n",
1341                                         ast_channel_uniqueid(chan));
1342                                 control_mark_done(control);
1343                                 break;
1344                         }
1345                 }
1346         }
1347
1348         ast_channel_lock(chan);
1349         needs_depart = (ast_channel_internal_bridge_channel(chan) != NULL);
1350         ast_channel_unlock(chan);
1351         if (needs_depart) {
1352                 ast_bridge_depart(chan);
1353         }
1354
1355         app_unsubscribe_bridge(app, stasis_app_get_bridge(control));
1356         ao2_cleanup(bridge);
1357
1358         /* Only publish a stasis_end event if it hasn't already been published */
1359         if (!stasis_app_channel_is_stasis_end_published(chan)) {
1360                 /* A masquerade has occurred and this message will be wrong so it
1361                  * has already been sent elsewhere. */
1362                 res = has_masquerade_store(chan) && app_send_end_msg(app, chan);
1363                 if (res != 0) {
1364                         ast_log(LOG_ERROR,
1365                                 "Error sending end message to %s\n", app_name);
1366                         return res;
1367                 }
1368         } else {
1369                 remove_stasis_end_published(chan);
1370         }
1371
1372         /* There's an off chance that app is ready for cleanup. Go ahead
1373          * and clean up, just in case
1374          */
1375         cleanup();
1376
1377         /* The control needs to be removed from the controls container in
1378          * case a new PBX is started and ends up coming back into Stasis.
1379          */
1380         ao2_cleanup(app);
1381         app = NULL;
1382         control_unlink(control);
1383         control = NULL;
1384
1385         if (!ast_channel_pbx(chan)) {
1386                 int chan_hungup;
1387
1388                 /* The ASYNCGOTO softhangup flag may have broken the channel out of
1389                  * its bridge to run dialplan, so if there's no pbx on the channel
1390                  * let it run dialplan here. Otherwise, it will run when this
1391                  * application exits. */
1392                 ast_channel_lock(chan);
1393                 ast_channel_clear_softhangup(chan, AST_SOFTHANGUP_ASYNCGOTO);
1394                 chan_hungup = ast_check_hangup(chan);
1395                 ast_channel_unlock(chan);
1396
1397                 if (!chan_hungup) {
1398                         struct ast_pbx_args pbx_args;
1399
1400                         memset(&pbx_args, 0, sizeof(pbx_args));
1401                         pbx_args.no_hangup_chan = 1;
1402
1403                         res = ast_pbx_run_args(chan, &pbx_args);
1404                 }
1405         }
1406
1407         return res;
1408 }
1409
1410 int stasis_app_send(const char *app_name, struct ast_json *message)
1411 {
1412         RAII_VAR(struct stasis_app *, app, NULL, ao2_cleanup);
1413
1414         if (!apps_registry) {
1415                 return -1;
1416         }
1417
1418         app = ao2_find(apps_registry, app_name, OBJ_SEARCH_KEY);
1419         if (!app) {
1420                 /* XXX We can do a better job handling late binding, queueing up
1421                  * the call for a few seconds to wait for the app to register.
1422                  */
1423                 ast_log(LOG_WARNING,
1424                         "Stasis app '%s' not registered\n", app_name);
1425                 return -1;
1426         }
1427         app_send(app, message);
1428         return 0;
1429 }
1430
1431 static struct stasis_app *find_app_by_name(const char *app_name)
1432 {
1433         struct stasis_app *res = NULL;
1434
1435         if (!apps_registry) {
1436                 return NULL;
1437         }
1438
1439         if (!ast_strlen_zero(app_name)) {
1440                 res = ao2_find(apps_registry, app_name, OBJ_SEARCH_KEY);
1441         }
1442
1443         if (!res) {
1444                 ast_log(LOG_WARNING, "Could not find app '%s'\n",
1445                         app_name ? : "(null)");
1446         }
1447         return res;
1448 }
1449
1450 static int append_name(void *obj, void *arg, int flags)
1451 {
1452         struct stasis_app *app = obj;
1453         struct ao2_container *apps = arg;
1454
1455         ast_str_container_add(apps, stasis_app_name(app));
1456         return 0;
1457 }
1458
1459 struct ao2_container *stasis_app_get_all(void)
1460 {
1461         RAII_VAR(struct ao2_container *, apps, NULL, ao2_cleanup);
1462
1463         if (!apps_registry) {
1464                 return NULL;
1465         }
1466
1467         apps = ast_str_container_alloc(1);
1468         if (!apps) {
1469                 return NULL;
1470         }
1471
1472         ao2_callback(apps_registry, OBJ_NODATA, append_name, apps);
1473
1474         return ao2_bump(apps);
1475 }
1476
1477 static int __stasis_app_register(const char *app_name, stasis_app_cb handler, void *data, int all_events)
1478 {
1479         RAII_VAR(struct stasis_app *, app, NULL, ao2_cleanup);
1480
1481         if (!apps_registry) {
1482                 return -1;
1483         }
1484
1485         ao2_lock(apps_registry);
1486         app = ao2_find(apps_registry, app_name, OBJ_SEARCH_KEY | OBJ_NOLOCK);
1487         if (app) {
1488                 app_update(app, handler, data);
1489         } else {
1490                 app = app_create(app_name, handler, data, all_events ? STASIS_APP_SUBSCRIBE_ALL : STASIS_APP_SUBSCRIBE_MANUAL);
1491                 if (app) {
1492                         if (all_events) {
1493                                 struct stasis_app_event_source *source;
1494                                 SCOPED_LOCK(lock, &event_sources, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK);
1495
1496                                 AST_LIST_TRAVERSE(&event_sources, source, next) {
1497                                         if (!source->subscribe) {
1498                                                 continue;
1499                                         }
1500
1501                                         source->subscribe(app, NULL);
1502                                 }
1503                         }
1504                         ao2_link_flags(apps_registry, app, OBJ_NOLOCK);
1505                 } else {
1506                         ao2_unlock(apps_registry);
1507                         return -1;
1508                 }
1509         }
1510
1511         /* We lazily clean up the apps_registry, because it's good enough to
1512          * prevent memory leaks, and we're lazy.
1513          */
1514         cleanup();
1515         ao2_unlock(apps_registry);
1516         return 0;
1517 }
1518
1519 int stasis_app_register(const char *app_name, stasis_app_cb handler, void *data)
1520 {
1521         return __stasis_app_register(app_name, handler, data, 0);
1522 }
1523
1524 int stasis_app_register_all(const char *app_name, stasis_app_cb handler, void *data)
1525 {
1526         return __stasis_app_register(app_name, handler, data, 1);
1527 }
1528
1529 void stasis_app_unregister(const char *app_name)
1530 {
1531         RAII_VAR(struct stasis_app *, app, NULL, ao2_cleanup);
1532
1533         if (!app_name) {
1534                 return;
1535         }
1536
1537         if (!apps_registry) {
1538                 return;
1539         }
1540
1541         app = ao2_find(apps_registry, app_name, OBJ_SEARCH_KEY);
1542         if (!app) {
1543                 ast_log(LOG_ERROR,
1544                         "Stasis app '%s' not registered\n", app_name);
1545                 return;
1546         }
1547
1548         app_deactivate(app);
1549
1550         /* There's a decent chance that app is ready for cleanup. Go ahead
1551          * and clean up, just in case
1552          */
1553         cleanup();
1554 }
1555
1556 void stasis_app_register_event_source(struct stasis_app_event_source *obj)
1557 {
1558         SCOPED_LOCK(lock, &event_sources, AST_RWLIST_WRLOCK, AST_RWLIST_UNLOCK);
1559         AST_LIST_INSERT_TAIL(&event_sources, obj, next);
1560         /* only need to bump the module ref on non-core sources because the
1561            core ones are [un]registered by this module. */
1562         if (!stasis_app_is_core_event_source(obj)) {
1563                 ast_module_ref(ast_module_info->self);
1564         }
1565 }
1566
1567 void stasis_app_unregister_event_source(struct stasis_app_event_source *obj)
1568 {
1569         struct stasis_app_event_source *source;
1570         SCOPED_LOCK(lock, &event_sources, AST_RWLIST_WRLOCK, AST_RWLIST_UNLOCK);
1571         AST_RWLIST_TRAVERSE_SAFE_BEGIN(&event_sources, source, next) {
1572                 if (source == obj) {
1573                         AST_RWLIST_REMOVE_CURRENT(next);
1574                         if (!stasis_app_is_core_event_source(obj)) {
1575                                 ast_module_unref(ast_module_info->self);
1576                         }
1577                         break;
1578                 }
1579         }
1580         AST_RWLIST_TRAVERSE_SAFE_END;
1581 }
1582
1583 /*!
1584  * \internal
1585  * \brief Convert event source data to JSON.
1586  *
1587  * Calls each event source that has a "to_json" handler allowing each
1588  * source to add data to the given JSON object.
1589  *
1590  * \param app application associated with the event source
1591  * \param json a json object to "fill"
1592  *
1593  * \retval The given json object.
1594  */
1595 static struct ast_json *app_event_sources_to_json(
1596         const struct stasis_app *app, struct ast_json *json)
1597 {
1598         struct stasis_app_event_source *source;
1599         SCOPED_LOCK(lock, &event_sources, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK);
1600         AST_LIST_TRAVERSE(&event_sources, source, next) {
1601                 if (source->to_json) {
1602                         source->to_json(app, json);
1603                 }
1604         }
1605         return json;
1606 }
1607
1608 static struct ast_json *stasis_app_object_to_json(struct stasis_app *app)
1609 {
1610         if (!app) {
1611                 return NULL;
1612         }
1613
1614         return app_event_sources_to_json(app, app_to_json(app));
1615 }
1616
1617 struct ast_json *stasis_app_to_json(const char *app_name)
1618 {
1619         RAII_VAR(struct stasis_app *, app, find_app_by_name(app_name), ao2_cleanup);
1620
1621         return stasis_app_object_to_json(app);
1622 }
1623
1624 /*!
1625  * \internal
1626  * \brief Finds an event source that matches a uri scheme.
1627  *
1628  * Uri(s) should begin with a particular scheme that can be matched
1629  * against an event source.
1630  *
1631  * \param uri uri containing a scheme to match
1632  *
1633  * \retval an event source if found, NULL otherwise.
1634  */
1635 static struct stasis_app_event_source *app_event_source_find(const char *uri)
1636 {
1637         struct stasis_app_event_source *source;
1638         SCOPED_LOCK(lock, &event_sources, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK);
1639         AST_LIST_TRAVERSE(&event_sources, source, next) {
1640                 if (ast_begins_with(uri, source->scheme)) {
1641                         return source;
1642                 }
1643         }
1644         return NULL;
1645 }
1646
1647 /*!
1648  * \internal
1649  * \brief Callback for subscription handling
1650  *
1651  * \param app [un]subscribing application
1652  * \param uri scheme:id of an event source
1653  * \param event_source being [un]subscribed [from]to
1654  *
1655  * \retval stasis_app_subscribe_res return code.
1656  */
1657 typedef enum stasis_app_subscribe_res (*app_subscription_handler)(
1658         struct stasis_app *app, const char *uri,
1659         struct stasis_app_event_source *event_source);
1660
1661 /*!
1662  * \internal
1663  * \brief Subscriptions handler for application [un]subscribing.
1664  *
1665  * \param app_name Name of the application to subscribe.
1666  * \param event_source_uris URIs for the event sources to subscribe to.
1667  * \param event_sources_count Array size of event_source_uris.
1668  * \param json Optional output pointer for JSON representation of the app
1669  *             after adding the subscription.
1670  * \param handler [un]subscribe handler
1671  *
1672  * \retval stasis_app_subscribe_res return code.
1673  */
1674 static enum stasis_app_subscribe_res app_handle_subscriptions(
1675         const char *app_name, const char **event_source_uris,
1676         int event_sources_count, struct ast_json **json,
1677         app_subscription_handler handler)
1678 {
1679         RAII_VAR(struct stasis_app *, app, find_app_by_name(app_name), ao2_cleanup);
1680         int i;
1681
1682         if (!app) {
1683                 return STASIS_ASR_APP_NOT_FOUND;
1684         }
1685
1686         for (i = 0; i < event_sources_count; ++i) {
1687                 const char *uri = event_source_uris[i];
1688                 enum stasis_app_subscribe_res res = STASIS_ASR_INTERNAL_ERROR;
1689                 struct stasis_app_event_source *event_source;
1690
1691                 if (!(event_source = app_event_source_find(uri))) {
1692                         ast_log(LOG_WARNING, "Invalid scheme: %s\n", uri);
1693                         return STASIS_ASR_EVENT_SOURCE_BAD_SCHEME;
1694                 }
1695
1696                 if (handler &&
1697                     ((res = handler(app, uri, event_source)))) {
1698                         return res;
1699                 }
1700         }
1701
1702         if (json) {
1703                 ast_debug(3, "%s: Successful; setting results\n", app_name);
1704                 *json = stasis_app_object_to_json(app);
1705         }
1706
1707         return STASIS_ASR_OK;
1708 }
1709
1710 enum stasis_app_subscribe_res stasis_app_subscribe_channel(const char *app_name,
1711         struct ast_channel *chan)
1712 {
1713         RAII_VAR(struct stasis_app *, app, find_app_by_name(app_name), ao2_cleanup);
1714         int res;
1715
1716         if (!app) {
1717                 return STASIS_ASR_APP_NOT_FOUND;
1718         }
1719
1720         ast_debug(3, "%s: Subscribing to %s\n", app_name, ast_channel_uniqueid(chan));
1721
1722         res = app_subscribe_channel(app, chan);
1723         if (res != 0) {
1724                 ast_log(LOG_ERROR, "Error subscribing app '%s' to channel '%s'\n",
1725                         app_name, ast_channel_uniqueid(chan));
1726                 return STASIS_ASR_INTERNAL_ERROR;
1727         }
1728
1729         return STASIS_ASR_OK;
1730 }
1731
1732
1733 /*!
1734  * \internal
1735  * \brief Subscribe an app to an event source.
1736  *
1737  * \param app subscribing application
1738  * \param uri scheme:id of an event source
1739  * \param event_source being subscribed to
1740  *
1741  * \retval stasis_app_subscribe_res return code.
1742  */
1743 static enum stasis_app_subscribe_res app_subscribe(
1744         struct stasis_app *app, const char *uri,
1745         struct stasis_app_event_source *event_source)
1746 {
1747         const char *app_name = stasis_app_name(app);
1748         RAII_VAR(void *, obj, NULL, ao2_cleanup);
1749
1750         ast_debug(3, "%s: Checking %s\n", app_name, uri);
1751
1752         if (!ast_strlen_zero(uri + strlen(event_source->scheme)) &&
1753             (!event_source->find || (!(obj = event_source->find(app, uri + strlen(event_source->scheme)))))) {
1754                 ast_log(LOG_WARNING, "Event source not found: %s\n", uri);
1755                 return STASIS_ASR_EVENT_SOURCE_NOT_FOUND;
1756         }
1757
1758         ast_debug(3, "%s: Subscribing to %s\n", app_name, uri);
1759
1760         if (!event_source->subscribe || (event_source->subscribe(app, obj))) {
1761                 ast_log(LOG_WARNING, "Error subscribing app '%s' to '%s'\n",
1762                         app_name, uri);
1763                 return STASIS_ASR_INTERNAL_ERROR;
1764         }
1765
1766         return STASIS_ASR_OK;
1767 }
1768
1769 enum stasis_app_subscribe_res stasis_app_subscribe(const char *app_name,
1770         const char **event_source_uris, int event_sources_count,
1771         struct ast_json **json)
1772 {
1773         return app_handle_subscriptions(
1774                 app_name, event_source_uris, event_sources_count,
1775                 json, app_subscribe);
1776 }
1777
1778 /*!
1779  * \internal
1780  * \brief Unsubscribe an app from an event source.
1781  *
1782  * \param app application to unsubscribe
1783  * \param uri scheme:id of an event source
1784  * \param event_source being unsubscribed from
1785  *
1786  * \retval stasis_app_subscribe_res return code.
1787  */
1788 static enum stasis_app_subscribe_res app_unsubscribe(
1789         struct stasis_app *app, const char *uri,
1790         struct stasis_app_event_source *event_source)
1791 {
1792         const char *app_name = stasis_app_name(app);
1793         const char *id = uri + strlen(event_source->scheme);
1794
1795         if (!event_source->is_subscribed ||
1796             (!event_source->is_subscribed(app, id))) {
1797                 return STASIS_ASR_EVENT_SOURCE_NOT_FOUND;
1798         }
1799
1800         ast_debug(3, "%s: Unsubscribing from %s\n", app_name, uri);
1801
1802         if (!event_source->unsubscribe || (event_source->unsubscribe(app, id))) {
1803                 ast_log(LOG_WARNING, "Error unsubscribing app '%s' to '%s'\n",
1804                         app_name, uri);
1805                 return -1;
1806         }
1807         return 0;
1808 }
1809
1810 enum stasis_app_subscribe_res stasis_app_unsubscribe(const char *app_name,
1811         const char **event_source_uris, int event_sources_count,
1812         struct ast_json **json)
1813 {
1814         return app_handle_subscriptions(
1815                 app_name, event_source_uris, event_sources_count,
1816                 json, app_unsubscribe);
1817 }
1818
1819 enum stasis_app_user_event_res stasis_app_user_event(const char *app_name,
1820         const char *event_name,
1821         const char **source_uris, int sources_count,
1822         struct ast_json *json_variables)
1823 {
1824         RAII_VAR(struct stasis_app *, app, find_app_by_name(app_name), ao2_cleanup);
1825         RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
1826         RAII_VAR(struct ast_multi_object_blob *, multi, NULL, ao2_cleanup);
1827         RAII_VAR(void *, obj, NULL, ao2_cleanup);
1828         RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
1829         enum stasis_app_user_event_res res = STASIS_APP_USER_INTERNAL_ERROR;
1830         struct ast_json *json_value;
1831         int have_channel = 0;
1832         int i;
1833
1834         if (!app) {
1835                 ast_log(LOG_WARNING, "App %s not found\n", app_name);
1836                 return STASIS_APP_USER_APP_NOT_FOUND;
1837         }
1838
1839         if (!ast_multi_user_event_type()) {
1840                 return res;
1841         }
1842
1843         blob = json_variables;
1844         if (!blob) {
1845                 blob = ast_json_pack("{}");
1846         } else {
1847                 ast_json_ref(blob);
1848         }
1849         json_value = ast_json_string_create(event_name);
1850         if (!json_value) {
1851                 ast_log(LOG_ERROR, "unable to create json string\n");
1852                 return res;
1853         }
1854         if (ast_json_object_set(blob, "eventname", json_value)) {
1855                 ast_log(LOG_ERROR, "unable to set eventname to blob\n");
1856                 return res;
1857         }
1858
1859         multi = ast_multi_object_blob_create(blob);
1860
1861         for (i = 0; i < sources_count; ++i) {
1862                 const char *uri = source_uris[i];
1863                 void *snapshot=NULL;
1864                 enum stasis_user_multi_object_snapshot_type type;
1865
1866                 if (ast_begins_with(uri, "channel:")) {
1867                         type = STASIS_UMOS_CHANNEL;
1868                         snapshot = ast_channel_snapshot_get_latest(uri + 8);
1869                         have_channel = 1;
1870                 } else if (ast_begins_with(uri, "bridge:")) {
1871                         type = STASIS_UMOS_BRIDGE;
1872                         snapshot = ast_bridge_snapshot_get_latest(uri + 7);
1873                 } else if (ast_begins_with(uri, "endpoint:")) {
1874                         type = STASIS_UMOS_ENDPOINT;
1875                         snapshot = ast_endpoint_latest_snapshot(uri + 9, NULL);
1876                 } else {
1877                         ast_log(LOG_WARNING, "Invalid scheme: %s\n", uri);
1878                         return STASIS_APP_USER_EVENT_SOURCE_BAD_SCHEME;
1879                 }
1880                 if (!snapshot) {
1881                         ast_log(LOG_ERROR, "Unable to get snapshot for %s\n", uri);
1882                         return STASIS_APP_USER_EVENT_SOURCE_NOT_FOUND;
1883                 }
1884                 ast_multi_object_blob_add(multi, type, snapshot);
1885         }
1886
1887         message = stasis_message_create(ast_multi_user_event_type(), multi);
1888         if (!message) {
1889                 ast_log(LOG_ERROR, "Unable to create stasis user event message\n");
1890                 return res;
1891         }
1892
1893         /*
1894          * Publishing to two different topics is normally to be avoided -- except
1895          * in this case both are final destinations with no forwards (only listeners).
1896          * The message has to be delivered to the application topic for ARI, but a
1897          * copy is also delivered directly to the manager for AMI if there is a channel.
1898          */
1899         stasis_publish(ast_app_get_topic(app), message);
1900
1901         if (have_channel) {
1902                 stasis_publish(ast_manager_get_topic(), message);
1903         }
1904
1905         return STASIS_APP_USER_OK;
1906 }
1907
1908 void stasis_app_ref(void)
1909 {
1910         ast_module_ref(ast_module_info->self);
1911 }
1912
1913 void stasis_app_unref(void)
1914 {
1915         ast_module_unref(ast_module_info->self);
1916 }
1917
1918 static int unload_module(void)
1919 {
1920         stasis_app_unregister_event_sources();
1921
1922         messaging_cleanup();
1923
1924         cleanup();
1925         ao2_cleanup(apps_registry);
1926         apps_registry = NULL;
1927
1928         ao2_cleanup(app_controls);
1929         app_controls = NULL;
1930
1931         ao2_cleanup(app_bridges);
1932         app_bridges = NULL;
1933
1934         ao2_cleanup(app_bridges_moh);
1935         app_bridges_moh = NULL;
1936
1937         ao2_cleanup(app_bridges_playback);
1938         app_bridges_playback = NULL;
1939
1940         STASIS_MESSAGE_TYPE_CLEANUP(end_message_type);
1941         STASIS_MESSAGE_TYPE_CLEANUP(start_message_type);
1942
1943         return 0;
1944 }
1945
1946 /* \brief Sanitization callback for channel snapshots */
1947 static int channel_snapshot_sanitizer(const struct ast_channel_snapshot *snapshot)
1948 {
1949         if (!snapshot || !(snapshot->tech_properties & AST_CHAN_TP_INTERNAL)) {
1950                 return 0;
1951         }
1952         return 1;
1953 }
1954
1955 /* \brief Sanitization callback for channels */
1956 static int channel_sanitizer(const struct ast_channel *chan)
1957 {
1958         if (!chan || !(ast_channel_tech(chan)->properties & AST_CHAN_TP_INTERNAL)) {
1959                 return 0;
1960         }
1961         return 1;
1962 }
1963
1964 /* \brief Sanitization callback for channel unique IDs */
1965 static int channel_id_sanitizer(const char *id)
1966 {
1967         RAII_VAR(struct ast_channel_snapshot *, snapshot, ast_channel_snapshot_get_latest(id), ao2_cleanup);
1968
1969         return channel_snapshot_sanitizer(snapshot);
1970 }
1971
1972 /* \brief Sanitization callbacks for communication to Stasis applications */
1973 struct stasis_message_sanitizer app_sanitizer = {
1974         .channel_id = channel_id_sanitizer,
1975         .channel_snapshot = channel_snapshot_sanitizer,
1976         .channel = channel_sanitizer,
1977 };
1978
1979 struct stasis_message_sanitizer *stasis_app_get_sanitizer(void)
1980 {
1981         return &app_sanitizer;
1982 }
1983
1984 static const struct ast_datastore_info stasis_internal_channel_info = {
1985         .type = "stasis-internal-channel",
1986 };
1987
1988 static int set_internal_datastore(struct ast_channel *chan)
1989 {
1990         struct ast_datastore *datastore;
1991
1992         datastore = ast_channel_datastore_find(chan, &stasis_internal_channel_info, NULL);
1993         if (!datastore) {
1994                 datastore = ast_datastore_alloc(&stasis_internal_channel_info, NULL);
1995                 if (!datastore) {
1996                         return -1;
1997                 }
1998                 ast_channel_datastore_add(chan, datastore);
1999         }
2000         return 0;
2001 }
2002
2003 int stasis_app_channel_unreal_set_internal(struct ast_channel *chan)
2004 {
2005         struct ast_channel *outchan = NULL, *outowner = NULL;
2006         int res = 0;
2007         struct ast_unreal_pvt *unreal_pvt = ast_channel_tech_pvt(chan);
2008
2009         ao2_ref(unreal_pvt, +1);
2010         ast_unreal_lock_all(unreal_pvt, &outowner, &outchan);
2011         if (outowner) {
2012                 res |= set_internal_datastore(outowner);
2013                 ast_channel_unlock(outowner);
2014                 ast_channel_unref(outowner);
2015         }
2016         if (outchan) {
2017                 res |= set_internal_datastore(outchan);
2018                 ast_channel_unlock(outchan);
2019                 ast_channel_unref(outchan);
2020         }
2021         ao2_unlock(unreal_pvt);
2022         ao2_ref(unreal_pvt, -1);
2023         return res;
2024 }
2025
2026 int stasis_app_channel_set_internal(struct ast_channel *chan)
2027 {
2028         int res;
2029
2030         ast_channel_lock(chan);
2031         res = set_internal_datastore(chan);
2032         ast_channel_unlock(chan);
2033
2034         return res;
2035 }
2036
2037 int stasis_app_channel_is_internal(struct ast_channel *chan)
2038 {
2039         struct ast_datastore *datastore;
2040         int res = 0;
2041
2042         ast_channel_lock(chan);
2043         datastore = ast_channel_datastore_find(chan, &stasis_internal_channel_info, NULL);
2044         if (datastore) {
2045                 res = 1;
2046         }
2047         ast_channel_unlock(chan);
2048
2049         return res;
2050 }
2051
2052 static int load_module(void)
2053 {
2054         if (STASIS_MESSAGE_TYPE_INIT(start_message_type) != 0) {
2055                 return AST_MODULE_LOAD_DECLINE;
2056         }
2057         if (STASIS_MESSAGE_TYPE_INIT(end_message_type) != 0) {
2058                 return AST_MODULE_LOAD_DECLINE;
2059         }
2060         apps_registry = ao2_container_alloc(APPS_NUM_BUCKETS, app_hash, app_compare);
2061         app_controls = ao2_container_alloc(CONTROLS_NUM_BUCKETS, control_hash, control_compare);
2062         app_bridges = ao2_container_alloc(BRIDGES_NUM_BUCKETS, bridges_hash, bridges_compare);
2063         app_bridges_moh = ao2_container_alloc_hash(
2064                 AO2_ALLOC_OPT_LOCK_MUTEX, AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT,
2065                 37, bridges_channel_hash_fn, bridges_channel_sort_fn, NULL);
2066         app_bridges_playback = ao2_container_alloc_hash(
2067                 AO2_ALLOC_OPT_LOCK_MUTEX, AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT,
2068                 37, bridges_channel_hash_fn, bridges_channel_sort_fn, NULL);
2069         if (!apps_registry || !app_controls || !app_bridges || !app_bridges_moh || !app_bridges_playback) {
2070                 unload_module();
2071                 return AST_MODULE_LOAD_FAILURE;
2072         }
2073
2074         if (messaging_init()) {
2075                 unload_module();
2076                 return AST_MODULE_LOAD_FAILURE;
2077         }
2078
2079         bridge_stasis_init();
2080
2081         stasis_app_register_event_sources();
2082
2083         return AST_MODULE_LOAD_SUCCESS;
2084 }
2085
2086 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Stasis application support",
2087         .load_pri = AST_MODPRI_APP_DEPEND,
2088         .support_level = AST_MODULE_SUPPORT_CORE,
2089         .load = load_module,
2090         .unload = unload_module,
2091 );