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