Fix DEBUG_THREADS when lock is acquired in __constructor__
[asterisk/asterisk.git] / main / manager_bridges.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2013, Digium, Inc.
5  *
6  * Kinsey Moore <kmoore@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 The Asterisk Management Interface - AMI (bridge event handling)
22  *
23  * \author Kinsey Moore <kmoore@digium.com>
24  */
25
26 #include "asterisk.h"
27
28 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
29
30 #include "asterisk/stasis_bridges.h"
31 #include "asterisk/stasis_channels.h"
32 #include "asterisk/manager.h"
33 #include "asterisk/stasis_message_router.h"
34
35 /*! \brief Message router for cached bridge state snapshot updates */
36 static struct stasis_message_router *bridge_state_router;
37
38 /*** DOCUMENTATION
39         <managerEvent language="en_US" name="BridgeCreate">
40                 <managerEventInstance class="EVENT_FLAG_CALL">
41                         <synopsis>Raised when a bridge is created.</synopsis>
42                         <syntax>
43                                 <bridge_snapshot/>
44                         </syntax>
45                 </managerEventInstance>
46         </managerEvent>
47         <managerEvent language="en_US" name="BridgeDestroy">
48                 <managerEventInstance class="EVENT_FLAG_CALL">
49                         <synopsis>Raised when a bridge is destroyed.</synopsis>
50                         <syntax>
51                                 <bridge_snapshot/>
52                         </syntax>
53                 </managerEventInstance>
54         </managerEvent>
55         <managerEvent language="en_US" name="BridgeEnter">
56                 <managerEventInstance class="EVENT_FLAG_CALL">
57                         <synopsis>Raised when a channel enters a bridge.</synopsis>
58                         <syntax>
59                                 <bridge_snapshot/>
60                                 <channel_snapshot/>
61                                 <parameter name="SwapUniqueid">
62                                         <para>The uniqueid of the channel being swapped out of the bridge</para>
63                                 </parameter>
64                         </syntax>
65                 </managerEventInstance>
66         </managerEvent>
67         <managerEvent language="en_US" name="BridgeLeave">
68                 <managerEventInstance class="EVENT_FLAG_CALL">
69                         <synopsis>Raised when a channel leaves a bridge.</synopsis>
70                         <syntax>
71                                 <bridge_snapshot/>
72                                 <channel_snapshot/>
73                         </syntax>
74                 </managerEventInstance>
75         </managerEvent>
76         <manager name="BridgeList" language="en_US">
77                 <synopsis>
78                         Get a list of bridges in the system.
79                 </synopsis>
80                 <syntax>
81                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
82                         <parameter name="BridgeType">
83                                 <para>Optional type for filtering the resulting list of bridges.</para>
84                         </parameter>
85                 </syntax>
86                 <description>
87                         <para>Returns a list of bridges, optionally filtering on a bridge type.</para>
88                 </description>
89         </manager>
90         <manager name="BridgeInfo" language="en_US">
91                 <synopsis>
92                         Get information about a bridge.
93                 </synopsis>
94                 <syntax>
95                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
96                         <parameter name="BridgeUniqueid" required="true">
97                                 <para>The unique ID of the bridge about which to retreive information.</para>
98                         </parameter>
99                 </syntax>
100                 <description>
101                         <para>Returns detailed information about a bridge and the channels in it.</para>
102                 </description>
103         </manager>
104  ***/
105
106 /*! \brief The \ref stasis subscription returned by the forwarding of the channel topic
107  * to the manager topic
108  */
109 static struct stasis_subscription *topic_forwarder;
110
111 struct ast_str *ast_manager_build_bridge_state_string_prefix(
112         const struct ast_bridge_snapshot *snapshot,
113         const char *prefix)
114 {
115         struct ast_str *out = ast_str_create(128);
116         int res;
117
118         if (!out) {
119                 return NULL;
120         }
121
122         res = ast_str_set(&out, 0,
123                 "%sBridgeUniqueid: %s\r\n"
124                 "%sBridgeType: %s\r\n"
125                 "%sBridgeTechnology: %s\r\n"
126                 "%sBridgeNumChannels: %d\r\n",
127                 prefix, snapshot->uniqueid,
128                 prefix, snapshot->subclass,
129                 prefix, snapshot->technology,
130                 prefix, snapshot->num_channels);
131         if (!res) {
132                 ast_free(out);
133                 return NULL;
134         }
135
136         return out;
137 }
138
139 struct ast_str *ast_manager_build_bridge_state_string(
140         const struct ast_bridge_snapshot *snapshot)
141 {
142         return ast_manager_build_bridge_state_string_prefix(snapshot, "");
143 }
144
145 /*! \brief Typedef for callbacks that get called on channel snapshot updates */
146 typedef struct ast_manager_event_blob *(*bridge_snapshot_monitor)(
147         struct ast_bridge_snapshot *old_snapshot,
148         struct ast_bridge_snapshot *new_snapshot);
149
150 /*! \brief Handle bridge creation */
151 static struct ast_manager_event_blob *bridge_create(
152         struct ast_bridge_snapshot *old_snapshot,
153         struct ast_bridge_snapshot *new_snapshot)
154 {
155         if (!new_snapshot || old_snapshot) {
156                 return NULL;
157         }
158
159         return ast_manager_event_blob_create(
160                 EVENT_FLAG_CALL, "BridgeCreate", NO_EXTRA_FIELDS);
161 }
162
163 /*! \brief Handle bridge destruction */
164 static struct ast_manager_event_blob *bridge_destroy(
165         struct ast_bridge_snapshot *old_snapshot,
166         struct ast_bridge_snapshot *new_snapshot)
167 {
168         if (new_snapshot || !old_snapshot) {
169                 return NULL;
170         }
171
172         return ast_manager_event_blob_create(
173                 EVENT_FLAG_CALL, "BridgeDestroy", NO_EXTRA_FIELDS);
174 }
175
176
177 bridge_snapshot_monitor bridge_monitors[] = {
178         bridge_create,
179         bridge_destroy,
180 };
181
182 static void bridge_snapshot_update(void *data, struct stasis_subscription *sub,
183                                     struct stasis_topic *topic,
184                                     struct stasis_message *message)
185 {
186         RAII_VAR(struct ast_str *, bridge_event_string, NULL, ast_free);
187         struct stasis_cache_update *update;
188         struct ast_bridge_snapshot *old_snapshot;
189         struct ast_bridge_snapshot *new_snapshot;
190         size_t i;
191
192         update = stasis_message_data(message);
193
194         ast_assert(ast_bridge_snapshot_type() == update->type);
195
196         old_snapshot = stasis_message_data(update->old_snapshot);
197         new_snapshot = stasis_message_data(update->new_snapshot);
198
199         for (i = 0; i < ARRAY_LEN(bridge_monitors); ++i) {
200                 RAII_VAR(struct ast_manager_event_blob *, event, NULL, ao2_cleanup);
201
202                 event = bridge_monitors[i](old_snapshot, new_snapshot);
203                 if (!event) {
204                         continue;
205                 }
206
207                 /* If we haven't already, build the channel event string */
208                 if (!bridge_event_string) {
209                         bridge_event_string =
210                                 ast_manager_build_bridge_state_string(
211                                         new_snapshot ? new_snapshot : old_snapshot);
212                         if (!bridge_event_string) {
213                                 return;
214                         }
215                 }
216
217                 manager_event(event->event_flags, event->manager_event, "%s%s",
218                         ast_str_buffer(bridge_event_string),
219                         event->extra_fields);
220         }
221 }
222
223 static void bridge_merge_cb(void *data, struct stasis_subscription *sub,
224                                     struct stasis_topic *topic,
225                                     struct stasis_message *message)
226 {
227         struct ast_bridge_merge_message *merge_msg = stasis_message_data(message);
228         RAII_VAR(struct ast_str *, to_text, NULL, ast_free);
229         RAII_VAR(struct ast_str *, from_text, NULL, ast_free);
230
231         ast_assert(merge_msg->to != NULL);
232         ast_assert(merge_msg->from != NULL);
233
234         to_text = ast_manager_build_bridge_state_string_prefix(merge_msg->to, "To");
235         from_text = ast_manager_build_bridge_state_string_prefix(merge_msg->from, "From");
236         if (!to_text || !from_text) {
237                 return;
238         }
239
240         /*** DOCUMENTATION
241                 <managerEventInstance>
242                         <synopsis>Raised when two bridges are merged.</synopsis>
243                         <syntax>
244                                 <bridge_snapshot prefix="To"/>
245                                 <bridge_snapshot prefix="From"/>
246                         </syntax>
247                 </managerEventInstance>
248         ***/
249         manager_event(EVENT_FLAG_CALL, "BridgeMerge",
250                 "%s"
251                 "%s",
252                 ast_str_buffer(to_text),
253                 ast_str_buffer(from_text));
254 }
255
256 static void channel_enter_cb(void *data, struct stasis_subscription *sub,
257                                     struct stasis_topic *topic,
258                                     struct stasis_message *message)
259 {
260         static const char *swap_name = "SwapUniqueid: ";
261         struct ast_bridge_blob *blob = stasis_message_data(message);
262         RAII_VAR(struct ast_str *, bridge_text, NULL, ast_free);
263         RAII_VAR(struct ast_str *, channel_text, NULL, ast_free);
264         const char *swap_id;
265
266         bridge_text = ast_manager_build_bridge_state_string(blob->bridge);
267         channel_text = ast_manager_build_channel_state_string(blob->channel);
268         if (!bridge_text || !channel_text) {
269                 return;
270         }
271
272         swap_id = ast_json_string_get(ast_json_object_get(blob->blob, "swap"));
273
274         manager_event(EVENT_FLAG_CALL, "BridgeEnter",
275                 "%s"
276                 "%s"
277                 "%s%s%s",
278                 ast_str_buffer(bridge_text),
279                 ast_str_buffer(channel_text),
280                 swap_id ? swap_name : "",
281                 S_OR(swap_id, ""),
282                 swap_id ? "\r\n" : "");
283 }
284
285 static void channel_leave_cb(void *data, struct stasis_subscription *sub,
286                                     struct stasis_topic *topic,
287                                     struct stasis_message *message)
288 {
289         struct ast_bridge_blob *blob = stasis_message_data(message);
290         RAII_VAR(struct ast_str *, bridge_text, NULL, ast_free);
291         RAII_VAR(struct ast_str *, channel_text, NULL, ast_free);
292
293         bridge_text = ast_manager_build_bridge_state_string(blob->bridge);
294         channel_text = ast_manager_build_channel_state_string(blob->channel);
295         if (!bridge_text || !channel_text) {
296                 return;
297         }
298
299         manager_event(EVENT_FLAG_CALL, "BridgeLeave",
300                 "%s"
301                 "%s",
302                 ast_str_buffer(bridge_text),
303                 ast_str_buffer(channel_text));
304 }
305
306 static int filter_bridge_type_cb(void *obj, void *arg, int flags)
307 {
308         char *bridge_type = arg;
309         struct ast_bridge_snapshot *snapshot = stasis_message_data(obj);
310         /* unlink all the snapshots that do not match the bridge type */
311         return strcmp(bridge_type, snapshot->technology) ? CMP_MATCH : 0;
312 }
313
314 static int send_bridge_list_item_cb(void *obj, void *arg, void *data, int flags)
315 {
316         struct ast_bridge_snapshot *snapshot = stasis_message_data(obj);
317         struct mansession *s = arg;
318         char *id_text = data;
319         RAII_VAR(struct ast_str *, bridge_info, ast_manager_build_bridge_state_string(snapshot), ast_free_ptr);
320
321         if (!bridge_info) {
322                 return 0;
323         }
324
325         astman_append(s,
326                 "Event: BridgeListItem\r\n"
327                 "%s"
328                 "%s"
329                 "\r\n",
330                 ast_str_buffer(bridge_info),
331                 id_text);
332         return 0;
333 }
334
335 static int manager_bridges_list(struct mansession *s, const struct message *m)
336 {
337         const char *id = astman_get_header(m, "ActionID");
338         const char *type_filter = astman_get_header(m, "BridgeType");
339         RAII_VAR(struct ast_str *, id_text, ast_str_create(128), ast_free);
340         RAII_VAR(struct ao2_container *, bridges, NULL, ao2_cleanup);
341
342         if (!id_text) {
343                 astman_send_error(s, m, "Internal error");
344                 return -1;
345         }
346
347         if (!ast_strlen_zero(id)) {
348                 ast_str_set(&id_text, 0, "ActionID: %s\r\n", id);
349         }
350
351         bridges = stasis_cache_dump(ast_bridge_cache(), ast_bridge_snapshot_type());
352         if (!bridges) {
353                 astman_send_error(s, m, "Internal error");
354                 return -1;
355         }
356
357         astman_send_ack(s, m, "Bridge listing will follow");
358
359         if (!ast_strlen_zero(type_filter)) {
360                 char *type_filter_dup = ast_strdupa(type_filter);
361                 ao2_callback(bridges, OBJ_MULTIPLE | OBJ_NODATA | OBJ_UNLINK, filter_bridge_type_cb, type_filter_dup);
362         }
363
364         ao2_callback_data(bridges, OBJ_NODATA, send_bridge_list_item_cb, s, ast_str_buffer(id_text));
365
366         astman_append(s,
367                 "Event: BridgeListComplete\r\n"
368                 "%s"
369                 "\r\n",
370                 ast_str_buffer(id_text));
371
372         return 0;
373 }
374
375 static int send_bridge_info_item_cb(void *obj, void *arg, void *data, int flags)
376 {
377         char *uniqueid = obj;
378         struct mansession *s = arg;
379         char *id_text = data;
380         RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
381         struct ast_channel_snapshot *snapshot;
382         RAII_VAR(struct ast_str *, channel_text, NULL, ast_free);
383         msg = stasis_cache_get(ast_channel_cache(),
384                 ast_channel_snapshot_type(), uniqueid);
385
386         if (!msg) {
387                 return 0;
388         }
389
390         snapshot = stasis_message_data(msg);
391         if (snapshot->tech_properties & AST_CHAN_TP_INTERNAL) {
392                 return 0;
393         }
394
395         channel_text = ast_manager_build_channel_state_string(snapshot);
396         if (!channel_text) {
397                 return 0;
398         }
399
400         astman_append(s,
401                 "Event: BridgeInfoChannel\r\n"
402                 "%s"
403                 "%s"
404                 "\r\n",
405                 ast_str_buffer(channel_text),
406                 id_text);
407         return 0;
408 }
409
410 static int manager_bridge_info(struct mansession *s, const struct message *m)
411 {
412         const char *id = astman_get_header(m, "ActionID");
413         const char *bridge_uniqueid = astman_get_header(m, "BridgeUniqueid");
414         RAII_VAR(struct ast_str *, id_text, ast_str_create(128), ast_free);
415         RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
416         RAII_VAR(struct ast_str *, bridge_info, NULL, ast_free);
417         struct ast_bridge_snapshot *snapshot;
418
419         if (!id_text) {
420                 astman_send_error(s, m, "Internal error");
421                 return -1;
422         }
423
424         if (ast_strlen_zero(bridge_uniqueid)) {
425                 astman_send_error(s, m, "BridgeUniqueid must be provided");
426                 return -1;
427         }
428
429         if (!ast_strlen_zero(id)) {
430                 ast_str_set(&id_text, 0, "ActionID: %s\r\n", id);
431         }
432
433         msg = stasis_cache_get(ast_bridge_cache(), ast_bridge_snapshot_type(), bridge_uniqueid);
434         if (!msg) {
435                 astman_send_error(s, m, "Specified BridgeUniqueid not found");
436                 return -1;
437         }
438
439         astman_send_ack(s, m, "Bridge channel listing will follow");
440
441         snapshot = stasis_message_data(msg);
442         bridge_info = ast_manager_build_bridge_state_string(snapshot);
443
444         ao2_callback_data(snapshot->channels, OBJ_NODATA, send_bridge_info_item_cb, s, ast_str_buffer(id_text));
445
446         astman_append(s,
447                 "Event: BridgeInfoComplete\r\n"
448                 "%s"
449                 "%s"
450                 "\r\n",
451                 S_COR(bridge_info, ast_str_buffer(bridge_info), ""),
452                 ast_str_buffer(id_text));
453
454         return 0;
455 }
456
457 static void manager_bridging_cleanup(void)
458 {
459         stasis_unsubscribe(topic_forwarder);
460         topic_forwarder = NULL;
461 }
462
463 static void manager_bridging_shutdown(void)
464 {
465         ast_manager_unregister("BridgeList");
466         ast_manager_unregister("BridgeInfo");
467 }
468
469 int manager_bridging_init(void)
470 {
471         int ret = 0;
472         struct stasis_topic *manager_topic;
473         struct stasis_topic *bridge_topic;
474
475         if (bridge_state_router) {
476                 /* Already initialized */
477                 return 0;
478         }
479
480         ast_register_atexit(manager_bridging_shutdown);
481         ast_register_cleanup(manager_bridging_cleanup);
482
483         manager_topic = ast_manager_get_topic();
484         if (!manager_topic) {
485                 return -1;
486         }
487
488         bridge_topic = ast_bridge_topic_all_cached();
489         if (!bridge_topic) {
490                 return -1;
491         }
492
493         topic_forwarder = stasis_forward_all(bridge_topic, manager_topic);
494         if (!topic_forwarder) {
495                 return -1;
496         }
497
498         bridge_state_router = ast_manager_get_message_router();
499         if (!bridge_state_router) {
500                 return -1;
501         }
502
503         ret |= stasis_message_router_add_cache_update(bridge_state_router,
504                 ast_bridge_snapshot_type(), bridge_snapshot_update, NULL);
505
506         ret |= stasis_message_router_add(bridge_state_router,
507                 ast_bridge_merge_message_type(), bridge_merge_cb, NULL);
508
509         ret |= stasis_message_router_add(bridge_state_router,
510                 ast_channel_entered_bridge_type(), channel_enter_cb, NULL);
511
512         ret |= stasis_message_router_add(bridge_state_router,
513                 ast_channel_left_bridge_type(), channel_leave_cb, NULL);
514
515         ret |= ast_manager_register_xml_core("BridgeList", 0, manager_bridges_list);
516         ret |= ast_manager_register_xml_core("BridgeInfo", 0, manager_bridge_info);
517
518         /* If somehow we failed to add any routes, just shut down the whole
519          * thing and fail it.
520          */
521         if (ret) {
522                 manager_bridging_shutdown();
523                 return -1;
524         }
525
526         return 0;
527 }