res/res_stasis: Fix accidental subscription to 'all' bridge topic
[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                         if (bridge) {
1298                                 app_subscribe_bridge(app, bridge);
1299                         }
1300                 }
1301
1302                 if (bridge) {
1303                         /* Bridge is handling channel frames */
1304                         control_wait(control);
1305                         control_dispatch_all(control, chan);
1306                         continue;
1307                 }
1308
1309                 r = ast_waitfor(chan, MAX_WAIT_MS);
1310
1311                 if (r < 0) {
1312                         ast_debug(3, "%s: Poll error\n",
1313                                   ast_channel_uniqueid(chan));
1314                         control_mark_done(control);
1315                         break;
1316                 }
1317
1318                 command_count = control_dispatch_all(control, chan);
1319
1320                 if (command_count > 0 && ast_channel_fdno(chan) == -1) {
1321                         /* Command drained the channel; wait for next frame */
1322                         continue;
1323                 }
1324
1325                 if (r == 0) {
1326                         /* Timeout */
1327                         continue;
1328                 }
1329
1330                 f = ast_read(chan);
1331                 if (!f) {
1332                         /* Continue on in the dialplan */
1333                         ast_debug(3, "%s: Hangup (no more frames)\n",
1334                                 ast_channel_uniqueid(chan));
1335                         control_mark_done(control);
1336                         break;
1337                 }
1338
1339                 if (f->frametype == AST_FRAME_CONTROL) {
1340                         if (f->subclass.integer == AST_CONTROL_HANGUP) {
1341                                 /* Continue on in the dialplan */
1342                                 ast_debug(3, "%s: Hangup\n",
1343                                         ast_channel_uniqueid(chan));
1344                                 control_mark_done(control);
1345                                 break;
1346                         }
1347                 }
1348         }
1349
1350         ast_channel_lock(chan);
1351         needs_depart = (ast_channel_internal_bridge_channel(chan) != NULL);
1352         ast_channel_unlock(chan);
1353         if (needs_depart) {
1354                 ast_bridge_depart(chan);
1355         }
1356
1357         app_unsubscribe_bridge(app, stasis_app_get_bridge(control));
1358         ao2_cleanup(bridge);
1359
1360         /* Only publish a stasis_end event if it hasn't already been published */
1361         if (!stasis_app_channel_is_stasis_end_published(chan)) {
1362                 /* A masquerade has occurred and this message will be wrong so it
1363                  * has already been sent elsewhere. */
1364                 res = has_masquerade_store(chan) && app_send_end_msg(app, chan);
1365                 if (res != 0) {
1366                         ast_log(LOG_ERROR,
1367                                 "Error sending end message to %s\n", app_name);
1368                         return res;
1369                 }
1370         } else {
1371                 remove_stasis_end_published(chan);
1372         }
1373
1374         /* There's an off chance that app is ready for cleanup. Go ahead
1375          * and clean up, just in case
1376          */
1377         cleanup();
1378
1379         /* The control needs to be removed from the controls container in
1380          * case a new PBX is started and ends up coming back into Stasis.
1381          */
1382         ao2_cleanup(app);
1383         app = NULL;
1384         control_unlink(control);
1385         control = NULL;
1386
1387         if (!ast_channel_pbx(chan)) {
1388                 int chan_hungup;
1389
1390                 /* The ASYNCGOTO softhangup flag may have broken the channel out of
1391                  * its bridge to run dialplan, so if there's no pbx on the channel
1392                  * let it run dialplan here. Otherwise, it will run when this
1393                  * application exits. */
1394                 ast_channel_lock(chan);
1395                 ast_channel_clear_softhangup(chan, AST_SOFTHANGUP_ASYNCGOTO);
1396                 chan_hungup = ast_check_hangup(chan);
1397                 ast_channel_unlock(chan);
1398
1399                 if (!chan_hungup) {
1400                         struct ast_pbx_args pbx_args;
1401
1402                         memset(&pbx_args, 0, sizeof(pbx_args));
1403                         pbx_args.no_hangup_chan = 1;
1404
1405                         res = ast_pbx_run_args(chan, &pbx_args);
1406                 }
1407         }
1408
1409         return res;
1410 }
1411
1412 int stasis_app_send(const char *app_name, struct ast_json *message)
1413 {
1414         RAII_VAR(struct stasis_app *, app, NULL, ao2_cleanup);
1415
1416         if (!apps_registry) {
1417                 return -1;
1418         }
1419
1420         app = ao2_find(apps_registry, app_name, OBJ_SEARCH_KEY);
1421         if (!app) {
1422                 /* XXX We can do a better job handling late binding, queueing up
1423                  * the call for a few seconds to wait for the app to register.
1424                  */
1425                 ast_log(LOG_WARNING,
1426                         "Stasis app '%s' not registered\n", app_name);
1427                 return -1;
1428         }
1429         app_send(app, message);
1430         return 0;
1431 }
1432
1433 static struct stasis_app *find_app_by_name(const char *app_name)
1434 {
1435         struct stasis_app *res = NULL;
1436
1437         if (!apps_registry) {
1438                 return NULL;
1439         }
1440
1441         if (!ast_strlen_zero(app_name)) {
1442                 res = ao2_find(apps_registry, app_name, OBJ_SEARCH_KEY);
1443         }
1444
1445         if (!res) {
1446                 ast_log(LOG_WARNING, "Could not find app '%s'\n",
1447                         app_name ? : "(null)");
1448         }
1449         return res;
1450 }
1451
1452 static int append_name(void *obj, void *arg, int flags)
1453 {
1454         struct stasis_app *app = obj;
1455         struct ao2_container *apps = arg;
1456
1457         ast_str_container_add(apps, stasis_app_name(app));
1458         return 0;
1459 }
1460
1461 struct ao2_container *stasis_app_get_all(void)
1462 {
1463         RAII_VAR(struct ao2_container *, apps, NULL, ao2_cleanup);
1464
1465         if (!apps_registry) {
1466                 return NULL;
1467         }
1468
1469         apps = ast_str_container_alloc(1);
1470         if (!apps) {
1471                 return NULL;
1472         }
1473
1474         ao2_callback(apps_registry, OBJ_NODATA, append_name, apps);
1475
1476         return ao2_bump(apps);
1477 }
1478
1479 static int __stasis_app_register(const char *app_name, stasis_app_cb handler, void *data, int all_events)
1480 {
1481         RAII_VAR(struct stasis_app *, app, NULL, ao2_cleanup);
1482
1483         if (!apps_registry) {
1484                 return -1;
1485         }
1486
1487         ao2_lock(apps_registry);
1488         app = ao2_find(apps_registry, app_name, OBJ_SEARCH_KEY | OBJ_NOLOCK);
1489         if (app) {
1490                 app_update(app, handler, data);
1491         } else {
1492                 app = app_create(app_name, handler, data, all_events ? STASIS_APP_SUBSCRIBE_ALL : STASIS_APP_SUBSCRIBE_MANUAL);
1493                 if (app) {
1494                         if (all_events) {
1495                                 struct stasis_app_event_source *source;
1496                                 SCOPED_LOCK(lock, &event_sources, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK);
1497
1498                                 AST_LIST_TRAVERSE(&event_sources, source, next) {
1499                                         if (!source->subscribe) {
1500                                                 continue;
1501                                         }
1502
1503                                         source->subscribe(app, NULL);
1504                                 }
1505                         }
1506                         ao2_link_flags(apps_registry, app, OBJ_NOLOCK);
1507                 } else {
1508                         ao2_unlock(apps_registry);
1509                         return -1;
1510                 }
1511         }
1512
1513         /* We lazily clean up the apps_registry, because it's good enough to
1514          * prevent memory leaks, and we're lazy.
1515          */
1516         cleanup();
1517         ao2_unlock(apps_registry);
1518         return 0;
1519 }
1520
1521 int stasis_app_register(const char *app_name, stasis_app_cb handler, void *data)
1522 {
1523         return __stasis_app_register(app_name, handler, data, 0);
1524 }
1525
1526 int stasis_app_register_all(const char *app_name, stasis_app_cb handler, void *data)
1527 {
1528         return __stasis_app_register(app_name, handler, data, 1);
1529 }
1530
1531 void stasis_app_unregister(const char *app_name)
1532 {
1533         RAII_VAR(struct stasis_app *, app, NULL, ao2_cleanup);
1534
1535         if (!app_name) {
1536                 return;
1537         }
1538
1539         if (!apps_registry) {
1540                 return;
1541         }
1542
1543         app = ao2_find(apps_registry, app_name, OBJ_SEARCH_KEY);
1544         if (!app) {
1545                 ast_log(LOG_ERROR,
1546                         "Stasis app '%s' not registered\n", app_name);
1547                 return;
1548         }
1549
1550         app_deactivate(app);
1551
1552         /* There's a decent chance that app is ready for cleanup. Go ahead
1553          * and clean up, just in case
1554          */
1555         cleanup();
1556 }
1557
1558 void stasis_app_register_event_source(struct stasis_app_event_source *obj)
1559 {
1560         SCOPED_LOCK(lock, &event_sources, AST_RWLIST_WRLOCK, AST_RWLIST_UNLOCK);
1561         AST_LIST_INSERT_TAIL(&event_sources, obj, next);
1562         /* only need to bump the module ref on non-core sources because the
1563            core ones are [un]registered by this module. */
1564         if (!stasis_app_is_core_event_source(obj)) {
1565                 ast_module_ref(ast_module_info->self);
1566         }
1567 }
1568
1569 void stasis_app_unregister_event_source(struct stasis_app_event_source *obj)
1570 {
1571         struct stasis_app_event_source *source;
1572         SCOPED_LOCK(lock, &event_sources, AST_RWLIST_WRLOCK, AST_RWLIST_UNLOCK);
1573         AST_RWLIST_TRAVERSE_SAFE_BEGIN(&event_sources, source, next) {
1574                 if (source == obj) {
1575                         AST_RWLIST_REMOVE_CURRENT(next);
1576                         if (!stasis_app_is_core_event_source(obj)) {
1577                                 ast_module_unref(ast_module_info->self);
1578                         }
1579                         break;
1580                 }
1581         }
1582         AST_RWLIST_TRAVERSE_SAFE_END;
1583 }
1584
1585 /*!
1586  * \internal
1587  * \brief Convert event source data to JSON.
1588  *
1589  * Calls each event source that has a "to_json" handler allowing each
1590  * source to add data to the given JSON object.
1591  *
1592  * \param app application associated with the event source
1593  * \param json a json object to "fill"
1594  *
1595  * \retval The given json object.
1596  */
1597 static struct ast_json *app_event_sources_to_json(
1598         const struct stasis_app *app, struct ast_json *json)
1599 {
1600         struct stasis_app_event_source *source;
1601         SCOPED_LOCK(lock, &event_sources, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK);
1602         AST_LIST_TRAVERSE(&event_sources, source, next) {
1603                 if (source->to_json) {
1604                         source->to_json(app, json);
1605                 }
1606         }
1607         return json;
1608 }
1609
1610 static struct ast_json *stasis_app_object_to_json(struct stasis_app *app)
1611 {
1612         if (!app) {
1613                 return NULL;
1614         }
1615
1616         return app_event_sources_to_json(app, app_to_json(app));
1617 }
1618
1619 struct ast_json *stasis_app_to_json(const char *app_name)
1620 {
1621         RAII_VAR(struct stasis_app *, app, find_app_by_name(app_name), ao2_cleanup);
1622
1623         return stasis_app_object_to_json(app);
1624 }
1625
1626 /*!
1627  * \internal
1628  * \brief Finds an event source that matches a uri scheme.
1629  *
1630  * Uri(s) should begin with a particular scheme that can be matched
1631  * against an event source.
1632  *
1633  * \param uri uri containing a scheme to match
1634  *
1635  * \retval an event source if found, NULL otherwise.
1636  */
1637 static struct stasis_app_event_source *app_event_source_find(const char *uri)
1638 {
1639         struct stasis_app_event_source *source;
1640         SCOPED_LOCK(lock, &event_sources, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK);
1641         AST_LIST_TRAVERSE(&event_sources, source, next) {
1642                 if (ast_begins_with(uri, source->scheme)) {
1643                         return source;
1644                 }
1645         }
1646         return NULL;
1647 }
1648
1649 /*!
1650  * \internal
1651  * \brief Callback for subscription handling
1652  *
1653  * \param app [un]subscribing application
1654  * \param uri scheme:id of an event source
1655  * \param event_source being [un]subscribed [from]to
1656  *
1657  * \retval stasis_app_subscribe_res return code.
1658  */
1659 typedef enum stasis_app_subscribe_res (*app_subscription_handler)(
1660         struct stasis_app *app, const char *uri,
1661         struct stasis_app_event_source *event_source);
1662
1663 /*!
1664  * \internal
1665  * \brief Subscriptions handler for application [un]subscribing.
1666  *
1667  * \param app_name Name of the application to subscribe.
1668  * \param event_source_uris URIs for the event sources to subscribe to.
1669  * \param event_sources_count Array size of event_source_uris.
1670  * \param json Optional output pointer for JSON representation of the app
1671  *             after adding the subscription.
1672  * \param handler [un]subscribe handler
1673  *
1674  * \retval stasis_app_subscribe_res return code.
1675  */
1676 static enum stasis_app_subscribe_res app_handle_subscriptions(
1677         const char *app_name, const char **event_source_uris,
1678         int event_sources_count, struct ast_json **json,
1679         app_subscription_handler handler)
1680 {
1681         RAII_VAR(struct stasis_app *, app, find_app_by_name(app_name), ao2_cleanup);
1682         int i;
1683
1684         if (!app) {
1685                 return STASIS_ASR_APP_NOT_FOUND;
1686         }
1687
1688         for (i = 0; i < event_sources_count; ++i) {
1689                 const char *uri = event_source_uris[i];
1690                 enum stasis_app_subscribe_res res = STASIS_ASR_INTERNAL_ERROR;
1691                 struct stasis_app_event_source *event_source;
1692
1693                 if (!(event_source = app_event_source_find(uri))) {
1694                         ast_log(LOG_WARNING, "Invalid scheme: %s\n", uri);
1695                         return STASIS_ASR_EVENT_SOURCE_BAD_SCHEME;
1696                 }
1697
1698                 if (handler &&
1699                     ((res = handler(app, uri, event_source)))) {
1700                         return res;
1701                 }
1702         }
1703
1704         if (json) {
1705                 ast_debug(3, "%s: Successful; setting results\n", app_name);
1706                 *json = stasis_app_object_to_json(app);
1707         }
1708
1709         return STASIS_ASR_OK;
1710 }
1711
1712 enum stasis_app_subscribe_res stasis_app_subscribe_channel(const char *app_name,
1713         struct ast_channel *chan)
1714 {
1715         RAII_VAR(struct stasis_app *, app, find_app_by_name(app_name), ao2_cleanup);
1716         int res;
1717
1718         if (!app) {
1719                 return STASIS_ASR_APP_NOT_FOUND;
1720         }
1721
1722         ast_debug(3, "%s: Subscribing to %s\n", app_name, ast_channel_uniqueid(chan));
1723
1724         res = app_subscribe_channel(app, chan);
1725         if (res != 0) {
1726                 ast_log(LOG_ERROR, "Error subscribing app '%s' to channel '%s'\n",
1727                         app_name, ast_channel_uniqueid(chan));
1728                 return STASIS_ASR_INTERNAL_ERROR;
1729         }
1730
1731         return STASIS_ASR_OK;
1732 }
1733
1734
1735 /*!
1736  * \internal
1737  * \brief Subscribe an app to an event source.
1738  *
1739  * \param app subscribing application
1740  * \param uri scheme:id of an event source
1741  * \param event_source being subscribed to
1742  *
1743  * \retval stasis_app_subscribe_res return code.
1744  */
1745 static enum stasis_app_subscribe_res app_subscribe(
1746         struct stasis_app *app, const char *uri,
1747         struct stasis_app_event_source *event_source)
1748 {
1749         const char *app_name = stasis_app_name(app);
1750         RAII_VAR(void *, obj, NULL, ao2_cleanup);
1751
1752         ast_debug(3, "%s: Checking %s\n", app_name, uri);
1753
1754         if (!ast_strlen_zero(uri + strlen(event_source->scheme)) &&
1755             (!event_source->find || (!(obj = event_source->find(app, uri + strlen(event_source->scheme)))))) {
1756                 ast_log(LOG_WARNING, "Event source not found: %s\n", uri);
1757                 return STASIS_ASR_EVENT_SOURCE_NOT_FOUND;
1758         }
1759
1760         ast_debug(3, "%s: Subscribing to %s\n", app_name, uri);
1761
1762         if (!event_source->subscribe || (event_source->subscribe(app, obj))) {
1763                 ast_log(LOG_WARNING, "Error subscribing app '%s' to '%s'\n",
1764                         app_name, uri);
1765                 return STASIS_ASR_INTERNAL_ERROR;
1766         }
1767
1768         return STASIS_ASR_OK;
1769 }
1770
1771 enum stasis_app_subscribe_res stasis_app_subscribe(const char *app_name,
1772         const char **event_source_uris, int event_sources_count,
1773         struct ast_json **json)
1774 {
1775         return app_handle_subscriptions(
1776                 app_name, event_source_uris, event_sources_count,
1777                 json, app_subscribe);
1778 }
1779
1780 /*!
1781  * \internal
1782  * \brief Unsubscribe an app from an event source.
1783  *
1784  * \param app application to unsubscribe
1785  * \param uri scheme:id of an event source
1786  * \param event_source being unsubscribed from
1787  *
1788  * \retval stasis_app_subscribe_res return code.
1789  */
1790 static enum stasis_app_subscribe_res app_unsubscribe(
1791         struct stasis_app *app, const char *uri,
1792         struct stasis_app_event_source *event_source)
1793 {
1794         const char *app_name = stasis_app_name(app);
1795         const char *id = uri + strlen(event_source->scheme);
1796
1797         if (!event_source->is_subscribed ||
1798             (!event_source->is_subscribed(app, id))) {
1799                 return STASIS_ASR_EVENT_SOURCE_NOT_FOUND;
1800         }
1801
1802         ast_debug(3, "%s: Unsubscribing from %s\n", app_name, uri);
1803
1804         if (!event_source->unsubscribe || (event_source->unsubscribe(app, id))) {
1805                 ast_log(LOG_WARNING, "Error unsubscribing app '%s' to '%s'\n",
1806                         app_name, uri);
1807                 return -1;
1808         }
1809         return 0;
1810 }
1811
1812 enum stasis_app_subscribe_res stasis_app_unsubscribe(const char *app_name,
1813         const char **event_source_uris, int event_sources_count,
1814         struct ast_json **json)
1815 {
1816         return app_handle_subscriptions(
1817                 app_name, event_source_uris, event_sources_count,
1818                 json, app_unsubscribe);
1819 }
1820
1821 enum stasis_app_user_event_res stasis_app_user_event(const char *app_name,
1822         const char *event_name,
1823         const char **source_uris, int sources_count,
1824         struct ast_json *json_variables)
1825 {
1826         RAII_VAR(struct stasis_app *, app, find_app_by_name(app_name), ao2_cleanup);
1827         RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
1828         RAII_VAR(struct ast_multi_object_blob *, multi, NULL, ao2_cleanup);
1829         RAII_VAR(void *, obj, NULL, ao2_cleanup);
1830         RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
1831         enum stasis_app_user_event_res res = STASIS_APP_USER_INTERNAL_ERROR;
1832         struct ast_json *json_value;
1833         int have_channel = 0;
1834         int i;
1835
1836         if (!app) {
1837                 ast_log(LOG_WARNING, "App %s not found\n", app_name);
1838                 return STASIS_APP_USER_APP_NOT_FOUND;
1839         }
1840
1841         if (!ast_multi_user_event_type()) {
1842                 return res;
1843         }
1844
1845         blob = json_variables;
1846         if (!blob) {
1847                 blob = ast_json_pack("{}");
1848         } else {
1849                 ast_json_ref(blob);
1850         }
1851         json_value = ast_json_string_create(event_name);
1852         if (!json_value) {
1853                 ast_log(LOG_ERROR, "unable to create json string\n");
1854                 return res;
1855         }
1856         if (ast_json_object_set(blob, "eventname", json_value)) {
1857                 ast_log(LOG_ERROR, "unable to set eventname to blob\n");
1858                 return res;
1859         }
1860
1861         multi = ast_multi_object_blob_create(blob);
1862
1863         for (i = 0; i < sources_count; ++i) {
1864                 const char *uri = source_uris[i];
1865                 void *snapshot=NULL;
1866                 enum stasis_user_multi_object_snapshot_type type;
1867
1868                 if (ast_begins_with(uri, "channel:")) {
1869                         type = STASIS_UMOS_CHANNEL;
1870                         snapshot = ast_channel_snapshot_get_latest(uri + 8);
1871                         have_channel = 1;
1872                 } else if (ast_begins_with(uri, "bridge:")) {
1873                         type = STASIS_UMOS_BRIDGE;
1874                         snapshot = ast_bridge_snapshot_get_latest(uri + 7);
1875                 } else if (ast_begins_with(uri, "endpoint:")) {
1876                         type = STASIS_UMOS_ENDPOINT;
1877                         snapshot = ast_endpoint_latest_snapshot(uri + 9, NULL);
1878                 } else {
1879                         ast_log(LOG_WARNING, "Invalid scheme: %s\n", uri);
1880                         return STASIS_APP_USER_EVENT_SOURCE_BAD_SCHEME;
1881                 }
1882                 if (!snapshot) {
1883                         ast_log(LOG_ERROR, "Unable to get snapshot for %s\n", uri);
1884                         return STASIS_APP_USER_EVENT_SOURCE_NOT_FOUND;
1885                 }
1886                 ast_multi_object_blob_add(multi, type, snapshot);
1887         }
1888
1889         message = stasis_message_create(ast_multi_user_event_type(), multi);
1890         if (!message) {
1891                 ast_log(LOG_ERROR, "Unable to create stasis user event message\n");
1892                 return res;
1893         }
1894
1895         /*
1896          * Publishing to two different topics is normally to be avoided -- except
1897          * in this case both are final destinations with no forwards (only listeners).
1898          * The message has to be delivered to the application topic for ARI, but a
1899          * copy is also delivered directly to the manager for AMI if there is a channel.
1900          */
1901         stasis_publish(ast_app_get_topic(app), message);
1902
1903         if (have_channel) {
1904                 stasis_publish(ast_manager_get_topic(), message);
1905         }
1906
1907         return STASIS_APP_USER_OK;
1908 }
1909
1910 void stasis_app_ref(void)
1911 {
1912         ast_module_ref(ast_module_info->self);
1913 }
1914
1915 void stasis_app_unref(void)
1916 {
1917         ast_module_unref(ast_module_info->self);
1918 }
1919
1920 static int unload_module(void)
1921 {
1922         stasis_app_unregister_event_sources();
1923
1924         messaging_cleanup();
1925
1926         cleanup();
1927         ao2_cleanup(apps_registry);
1928         apps_registry = NULL;
1929
1930         ao2_cleanup(app_controls);
1931         app_controls = NULL;
1932
1933         ao2_cleanup(app_bridges);
1934         app_bridges = NULL;
1935
1936         ao2_cleanup(app_bridges_moh);
1937         app_bridges_moh = NULL;
1938
1939         ao2_cleanup(app_bridges_playback);
1940         app_bridges_playback = NULL;
1941
1942         STASIS_MESSAGE_TYPE_CLEANUP(end_message_type);
1943         STASIS_MESSAGE_TYPE_CLEANUP(start_message_type);
1944
1945         return 0;
1946 }
1947
1948 /* \brief Sanitization callback for channel snapshots */
1949 static int channel_snapshot_sanitizer(const struct ast_channel_snapshot *snapshot)
1950 {
1951         if (!snapshot || !(snapshot->tech_properties & AST_CHAN_TP_INTERNAL)) {
1952                 return 0;
1953         }
1954         return 1;
1955 }
1956
1957 /* \brief Sanitization callback for channels */
1958 static int channel_sanitizer(const struct ast_channel *chan)
1959 {
1960         if (!chan || !(ast_channel_tech(chan)->properties & AST_CHAN_TP_INTERNAL)) {
1961                 return 0;
1962         }
1963         return 1;
1964 }
1965
1966 /* \brief Sanitization callback for channel unique IDs */
1967 static int channel_id_sanitizer(const char *id)
1968 {
1969         RAII_VAR(struct ast_channel_snapshot *, snapshot, ast_channel_snapshot_get_latest(id), ao2_cleanup);
1970
1971         return channel_snapshot_sanitizer(snapshot);
1972 }
1973
1974 /* \brief Sanitization callbacks for communication to Stasis applications */
1975 struct stasis_message_sanitizer app_sanitizer = {
1976         .channel_id = channel_id_sanitizer,
1977         .channel_snapshot = channel_snapshot_sanitizer,
1978         .channel = channel_sanitizer,
1979 };
1980
1981 struct stasis_message_sanitizer *stasis_app_get_sanitizer(void)
1982 {
1983         return &app_sanitizer;
1984 }
1985
1986 static const struct ast_datastore_info stasis_internal_channel_info = {
1987         .type = "stasis-internal-channel",
1988 };
1989
1990 static int set_internal_datastore(struct ast_channel *chan)
1991 {
1992         struct ast_datastore *datastore;
1993
1994         datastore = ast_channel_datastore_find(chan, &stasis_internal_channel_info, NULL);
1995         if (!datastore) {
1996                 datastore = ast_datastore_alloc(&stasis_internal_channel_info, NULL);
1997                 if (!datastore) {
1998                         return -1;
1999                 }
2000                 ast_channel_datastore_add(chan, datastore);
2001         }
2002         return 0;
2003 }
2004
2005 int stasis_app_channel_unreal_set_internal(struct ast_channel *chan)
2006 {
2007         struct ast_channel *outchan = NULL, *outowner = NULL;
2008         int res = 0;
2009         struct ast_unreal_pvt *unreal_pvt = ast_channel_tech_pvt(chan);
2010
2011         ao2_ref(unreal_pvt, +1);
2012         ast_unreal_lock_all(unreal_pvt, &outowner, &outchan);
2013         if (outowner) {
2014                 res |= set_internal_datastore(outowner);
2015                 ast_channel_unlock(outowner);
2016                 ast_channel_unref(outowner);
2017         }
2018         if (outchan) {
2019                 res |= set_internal_datastore(outchan);
2020                 ast_channel_unlock(outchan);
2021                 ast_channel_unref(outchan);
2022         }
2023         ao2_unlock(unreal_pvt);
2024         ao2_ref(unreal_pvt, -1);
2025         return res;
2026 }
2027
2028 int stasis_app_channel_set_internal(struct ast_channel *chan)
2029 {
2030         int res;
2031
2032         ast_channel_lock(chan);
2033         res = set_internal_datastore(chan);
2034         ast_channel_unlock(chan);
2035
2036         return res;
2037 }
2038
2039 int stasis_app_channel_is_internal(struct ast_channel *chan)
2040 {
2041         struct ast_datastore *datastore;
2042         int res = 0;
2043
2044         ast_channel_lock(chan);
2045         datastore = ast_channel_datastore_find(chan, &stasis_internal_channel_info, NULL);
2046         if (datastore) {
2047                 res = 1;
2048         }
2049         ast_channel_unlock(chan);
2050
2051         return res;
2052 }
2053
2054 static int load_module(void)
2055 {
2056         if (STASIS_MESSAGE_TYPE_INIT(start_message_type) != 0) {
2057                 return AST_MODULE_LOAD_DECLINE;
2058         }
2059         if (STASIS_MESSAGE_TYPE_INIT(end_message_type) != 0) {
2060                 return AST_MODULE_LOAD_DECLINE;
2061         }
2062         apps_registry = ao2_container_alloc(APPS_NUM_BUCKETS, app_hash, app_compare);
2063         app_controls = ao2_container_alloc(CONTROLS_NUM_BUCKETS, control_hash, control_compare);
2064         app_bridges = ao2_container_alloc(BRIDGES_NUM_BUCKETS, bridges_hash, bridges_compare);
2065         app_bridges_moh = ao2_container_alloc_hash(
2066                 AO2_ALLOC_OPT_LOCK_MUTEX, AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT,
2067                 37, bridges_channel_hash_fn, bridges_channel_sort_fn, NULL);
2068         app_bridges_playback = ao2_container_alloc_hash(
2069                 AO2_ALLOC_OPT_LOCK_MUTEX, AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT,
2070                 37, bridges_channel_hash_fn, bridges_channel_sort_fn, NULL);
2071         if (!apps_registry || !app_controls || !app_bridges || !app_bridges_moh || !app_bridges_playback) {
2072                 unload_module();
2073                 return AST_MODULE_LOAD_FAILURE;
2074         }
2075
2076         if (messaging_init()) {
2077                 unload_module();
2078                 return AST_MODULE_LOAD_FAILURE;
2079         }
2080
2081         bridge_stasis_init();
2082
2083         stasis_app_register_event_sources();
2084
2085         return AST_MODULE_LOAD_SUCCESS;
2086 }
2087
2088 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Stasis application support",
2089         .load_pri = AST_MODPRI_APP_DEPEND,
2090         .support_level = AST_MODULE_SUPPORT_CORE,
2091         .load = load_module,
2092         .unload = unload_module,
2093 );