10a5046d9442b454599c1b096e7ed09d14259c33
[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                 <responses>
104                         <list-elements>
105                                 <managerEvent language="en_US" name="BridgeInfoChannel">
106                                         <managerEventInstance class="EVENT_FLAG_COMMAND">
107                                                 <synopsis>Information about a channel in a bridge.</synopsis>
108                                                 <syntax>
109                                                         <channel_snapshot/>
110                                                 </syntax>
111                                         </managerEventInstance>
112                                 </managerEvent>
113                         </list-elements>
114                         <managerEvent language="en_US" name="BridgeInfoComplete">
115                                 <managerEventInstance class="EVENT_FLAG_COMMAND">
116                                         <synopsis>Information about a bridge.</synopsis>
117                                         <syntax>
118                                                 <bridge_snapshot/>
119                                         </syntax>
120                                 </managerEventInstance>
121                         </managerEvent>
122                 </responses>
123         </manager>
124         <manager name="BridgeDestroy" language="en_US">
125                 <synopsis>
126                         Destroy a bridge.
127                 </synopsis>
128                 <syntax>
129                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
130                         <parameter name="BridgeUniqueid" required="true">
131                                 <para>The unique ID of the bridge to destroy.</para>
132                         </parameter>
133                 </syntax>
134                 <description>
135                         <para>Deletes the bridge, causing channels to continue or hang up.</para>
136                 </description>
137         </manager>
138         <manager name="BridgeKick" language="en_US">
139                 <synopsis>
140                         Kick a channel from a bridge.
141                 </synopsis>
142                 <syntax>
143                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
144                         <parameter name="BridgeUniqueid" required="false">
145                                 <para>The unique ID of the bridge containing the channel to
146                                 destroy.  This parameter can be omitted, or supplied to insure
147                                 that the channel is not removed from the wrong bridge.</para>
148                         </parameter>
149                         <parameter name="Channel" required="true">
150                                 <para>The channel to kick out of a bridge.</para>
151                         </parameter>
152                 </syntax>
153                 <description>
154                         <para>The channel is removed from the bridge.</para>
155                 </description>
156         </manager>
157  ***/
158
159 /*! \brief The \ref stasis subscription returned by the forwarding of the channel topic
160  * to the manager topic
161  */
162 static struct stasis_forward *topic_forwarder;
163
164 struct ast_str *ast_manager_build_bridge_state_string_prefix(
165         const struct ast_bridge_snapshot *snapshot,
166         const char *prefix)
167 {
168         struct ast_str *out = ast_str_create(128);
169         int res;
170
171         if (!out) {
172                 return NULL;
173         }
174
175         res = ast_str_set(&out, 0,
176                 "%sBridgeUniqueid: %s\r\n"
177                 "%sBridgeType: %s\r\n"
178                 "%sBridgeTechnology: %s\r\n"
179                 "%sBridgeCreator: %s\r\n"
180                 "%sBridgeName: %s\r\n"
181                 "%sBridgeNumChannels: %u\r\n",
182                 prefix, snapshot->uniqueid,
183                 prefix, snapshot->subclass,
184                 prefix, snapshot->technology,
185                 prefix, ast_strlen_zero(snapshot->creator) ? "<unknown>": snapshot->creator,
186                 prefix, ast_strlen_zero(snapshot->name) ? "<unknown>": snapshot->name,
187                 prefix, snapshot->num_channels);
188         if (!res) {
189                 ast_free(out);
190                 return NULL;
191         }
192
193         return out;
194 }
195
196 struct ast_str *ast_manager_build_bridge_state_string(
197         const struct ast_bridge_snapshot *snapshot)
198 {
199         return ast_manager_build_bridge_state_string_prefix(snapshot, "");
200 }
201
202 /*! \brief Typedef for callbacks that get called on channel snapshot updates */
203 typedef struct ast_manager_event_blob *(*bridge_snapshot_monitor)(
204         struct ast_bridge_snapshot *old_snapshot,
205         struct ast_bridge_snapshot *new_snapshot);
206
207 /*! \brief Handle bridge creation */
208 static struct ast_manager_event_blob *bridge_create(
209         struct ast_bridge_snapshot *old_snapshot,
210         struct ast_bridge_snapshot *new_snapshot)
211 {
212         if (!new_snapshot || old_snapshot) {
213                 return NULL;
214         }
215
216         return ast_manager_event_blob_create(
217                 EVENT_FLAG_CALL, "BridgeCreate", NO_EXTRA_FIELDS);
218 }
219
220 /*! \brief Handle bridge destruction */
221 static struct ast_manager_event_blob *bridge_destroy(
222         struct ast_bridge_snapshot *old_snapshot,
223         struct ast_bridge_snapshot *new_snapshot)
224 {
225         if (new_snapshot || !old_snapshot) {
226                 return NULL;
227         }
228
229         return ast_manager_event_blob_create(
230                 EVENT_FLAG_CALL, "BridgeDestroy", NO_EXTRA_FIELDS);
231 }
232
233
234 bridge_snapshot_monitor bridge_monitors[] = {
235         bridge_create,
236         bridge_destroy,
237 };
238
239 static void bridge_snapshot_update(void *data, struct stasis_subscription *sub,
240                                     struct stasis_message *message)
241 {
242         RAII_VAR(struct ast_str *, bridge_event_string, NULL, ast_free);
243         struct stasis_cache_update *update;
244         struct ast_bridge_snapshot *old_snapshot;
245         struct ast_bridge_snapshot *new_snapshot;
246         size_t i;
247
248         update = stasis_message_data(message);
249
250         ast_assert(ast_bridge_snapshot_type() == update->type);
251
252         old_snapshot = stasis_message_data(update->old_snapshot);
253         new_snapshot = stasis_message_data(update->new_snapshot);
254
255         for (i = 0; i < ARRAY_LEN(bridge_monitors); ++i) {
256                 RAII_VAR(struct ast_manager_event_blob *, event, NULL, ao2_cleanup);
257
258                 event = bridge_monitors[i](old_snapshot, new_snapshot);
259                 if (!event) {
260                         continue;
261                 }
262
263                 /* If we haven't already, build the channel event string */
264                 if (!bridge_event_string) {
265                         bridge_event_string =
266                                 ast_manager_build_bridge_state_string(
267                                         new_snapshot ? new_snapshot : old_snapshot);
268                         if (!bridge_event_string) {
269                                 return;
270                         }
271                 }
272
273                 manager_event(event->event_flags, event->manager_event, "%s%s",
274                         ast_str_buffer(bridge_event_string),
275                         event->extra_fields);
276         }
277 }
278
279 static void bridge_merge_cb(void *data, struct stasis_subscription *sub,
280                                     struct stasis_message *message)
281 {
282         struct ast_bridge_merge_message *merge_msg = stasis_message_data(message);
283         RAII_VAR(struct ast_str *, to_text, NULL, ast_free);
284         RAII_VAR(struct ast_str *, from_text, NULL, ast_free);
285
286         ast_assert(merge_msg->to != NULL);
287         ast_assert(merge_msg->from != NULL);
288
289         to_text = ast_manager_build_bridge_state_string_prefix(merge_msg->to, "To");
290         from_text = ast_manager_build_bridge_state_string_prefix(merge_msg->from, "From");
291         if (!to_text || !from_text) {
292                 return;
293         }
294
295         /*** DOCUMENTATION
296                 <managerEventInstance>
297                         <synopsis>Raised when two bridges are merged.</synopsis>
298                         <syntax>
299                                 <bridge_snapshot prefix="To"/>
300                                 <bridge_snapshot prefix="From"/>
301                         </syntax>
302                 </managerEventInstance>
303         ***/
304         manager_event(EVENT_FLAG_CALL, "BridgeMerge",
305                 "%s"
306                 "%s",
307                 ast_str_buffer(to_text),
308                 ast_str_buffer(from_text));
309 }
310
311 static void channel_enter_cb(void *data, struct stasis_subscription *sub,
312                                     struct stasis_message *message)
313 {
314         static const char *swap_name = "SwapUniqueid: ";
315         struct ast_bridge_blob *blob = stasis_message_data(message);
316         RAII_VAR(struct ast_str *, bridge_text, NULL, ast_free);
317         RAII_VAR(struct ast_str *, channel_text, NULL, ast_free);
318         const char *swap_id;
319
320         bridge_text = ast_manager_build_bridge_state_string(blob->bridge);
321         channel_text = ast_manager_build_channel_state_string(blob->channel);
322         if (!bridge_text || !channel_text) {
323                 return;
324         }
325
326         swap_id = ast_json_string_get(ast_json_object_get(blob->blob, "swap"));
327
328         manager_event(EVENT_FLAG_CALL, "BridgeEnter",
329                 "%s"
330                 "%s"
331                 "%s%s%s",
332                 ast_str_buffer(bridge_text),
333                 ast_str_buffer(channel_text),
334                 swap_id ? swap_name : "",
335                 S_OR(swap_id, ""),
336                 swap_id ? "\r\n" : "");
337 }
338
339 static void channel_leave_cb(void *data, struct stasis_subscription *sub,
340                                     struct stasis_message *message)
341 {
342         struct ast_bridge_blob *blob = stasis_message_data(message);
343         RAII_VAR(struct ast_str *, bridge_text, NULL, ast_free);
344         RAII_VAR(struct ast_str *, channel_text, NULL, ast_free);
345
346         bridge_text = ast_manager_build_bridge_state_string(blob->bridge);
347         channel_text = ast_manager_build_channel_state_string(blob->channel);
348         if (!bridge_text || !channel_text) {
349                 return;
350         }
351
352         manager_event(EVENT_FLAG_CALL, "BridgeLeave",
353                 "%s"
354                 "%s",
355                 ast_str_buffer(bridge_text),
356                 ast_str_buffer(channel_text));
357 }
358
359 static int filter_bridge_type_cb(void *obj, void *arg, int flags)
360 {
361         char *bridge_type = arg;
362         struct ast_bridge_snapshot *snapshot = stasis_message_data(obj);
363         /* unlink all the snapshots that do not match the bridge type */
364         return strcmp(bridge_type, snapshot->technology) ? CMP_MATCH : 0;
365 }
366
367 struct bridge_list_data {
368         const char *id_text;
369         int count;
370 };
371
372 static int send_bridge_list_item_cb(void *obj, void *arg, void *data, int flags)
373 {
374         struct ast_bridge_snapshot *snapshot = stasis_message_data(obj);
375         struct mansession *s = arg;
376         struct bridge_list_data *list_data = data;
377         RAII_VAR(struct ast_str *, bridge_info, ast_manager_build_bridge_state_string(snapshot), ast_free);
378
379         if (!bridge_info) {
380                 return 0;
381         }
382
383         astman_append(s,
384                 "Event: BridgeListItem\r\n"
385                 "%s"
386                 "%s"
387                 "\r\n",
388                 list_data->id_text,
389                 ast_str_buffer(bridge_info));
390         ++list_data->count;
391         return 0;
392 }
393
394 static int manager_bridges_list(struct mansession *s, const struct message *m)
395 {
396         const char *id = astman_get_header(m, "ActionID");
397         const char *type_filter = astman_get_header(m, "BridgeType");
398         RAII_VAR(struct ast_str *, id_text, ast_str_create(128), ast_free);
399         RAII_VAR(struct ao2_container *, bridges, NULL, ao2_cleanup);
400         struct bridge_list_data list_data;
401
402         if (!id_text) {
403                 astman_send_error(s, m, "Internal error");
404                 return -1;
405         }
406
407         if (!ast_strlen_zero(id)) {
408                 ast_str_set(&id_text, 0, "ActionID: %s\r\n", id);
409         }
410
411         bridges = stasis_cache_dump(ast_bridge_cache(), ast_bridge_snapshot_type());
412         if (!bridges) {
413                 astman_send_error(s, m, "Internal error");
414                 return -1;
415         }
416
417         astman_send_listack(s, m, "Bridge listing will follow", "start");
418
419         if (!ast_strlen_zero(type_filter)) {
420                 char *type_filter_dup = ast_strdupa(type_filter);
421
422                 ao2_callback(bridges, OBJ_MULTIPLE | OBJ_NODATA | OBJ_UNLINK,
423                         filter_bridge_type_cb, type_filter_dup);
424         }
425
426         list_data.id_text = ast_str_buffer(id_text);
427         list_data.count = 0;
428         ao2_callback_data(bridges, OBJ_NODATA, send_bridge_list_item_cb, s, &list_data);
429
430         astman_send_list_complete_start(s, m, "BridgeListComplete", list_data.count);
431         astman_send_list_complete_end(s);
432
433         return 0;
434 }
435
436 static int send_bridge_info_item_cb(void *obj, void *arg, void *data, int flags)
437 {
438         char *uniqueid = obj;
439         struct mansession *s = arg;
440         struct bridge_list_data *list_data = data;
441         RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
442         struct ast_channel_snapshot *snapshot;
443         RAII_VAR(struct ast_str *, channel_text, NULL, ast_free);
444
445         msg = stasis_cache_get(ast_channel_cache(),
446                 ast_channel_snapshot_type(), uniqueid);
447         if (!msg) {
448                 return 0;
449         }
450
451         snapshot = stasis_message_data(msg);
452         if (snapshot->tech_properties & AST_CHAN_TP_INTERNAL) {
453                 return 0;
454         }
455
456         channel_text = ast_manager_build_channel_state_string(snapshot);
457         if (!channel_text) {
458                 return 0;
459         }
460
461         astman_append(s,
462                 "Event: BridgeInfoChannel\r\n"
463                 "%s"
464                 "%s"
465                 "\r\n",
466                 list_data->id_text,
467                 ast_str_buffer(channel_text));
468         ++list_data->count;
469         return 0;
470 }
471
472 static int manager_bridge_info(struct mansession *s, const struct message *m)
473 {
474         const char *id = astman_get_header(m, "ActionID");
475         const char *bridge_uniqueid = astman_get_header(m, "BridgeUniqueid");
476         RAII_VAR(struct ast_str *, id_text, ast_str_create(128), ast_free);
477         RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
478         RAII_VAR(struct ast_str *, bridge_info, NULL, ast_free);
479         struct ast_bridge_snapshot *snapshot;
480         struct bridge_list_data list_data;
481
482         if (!id_text) {
483                 astman_send_error(s, m, "Internal error");
484                 return -1;
485         }
486
487         if (ast_strlen_zero(bridge_uniqueid)) {
488                 astman_send_error(s, m, "BridgeUniqueid must be provided");
489                 return 0;
490         }
491
492         if (!ast_strlen_zero(id)) {
493                 ast_str_set(&id_text, 0, "ActionID: %s\r\n", id);
494         }
495
496         msg = stasis_cache_get(ast_bridge_cache(), ast_bridge_snapshot_type(), bridge_uniqueid);
497         if (!msg) {
498                 astman_send_error(s, m, "Specified BridgeUniqueid not found");
499                 return 0;
500         }
501
502         snapshot = stasis_message_data(msg);
503         bridge_info = ast_manager_build_bridge_state_string(snapshot);
504         if (!bridge_info) {
505                 astman_send_error(s, m, "Internal error");
506                 return -1;
507         }
508
509         astman_send_listack(s, m, "Bridge channel listing will follow", "start");
510
511         list_data.id_text = ast_str_buffer(id_text);
512         list_data.count = 0;
513         ao2_callback_data(snapshot->channels, OBJ_NODATA, send_bridge_info_item_cb, s, &list_data);
514
515         astman_send_list_complete_start(s, m, "BridgeInfoComplete", list_data.count);
516         if (!ast_strlen_zero(ast_str_buffer(bridge_info))) {
517                 astman_append(s, "%s", ast_str_buffer(bridge_info));
518         }
519         astman_send_list_complete_end(s);
520
521         return 0;
522 }
523
524 static int manager_bridge_destroy(struct mansession *s, const struct message *m)
525 {
526         const char *bridge_uniqueid = astman_get_header(m, "BridgeUniqueid");
527         struct ast_bridge *bridge;
528
529         if (ast_strlen_zero(bridge_uniqueid)) {
530                 astman_send_error(s, m, "BridgeUniqueid must be provided");
531                 return 0;
532         }
533
534         bridge = ast_bridge_find_by_id(bridge_uniqueid);
535         if (!bridge) {
536                 astman_send_error(s, m, "Specified BridgeUniqueid not found");
537                 return 0;
538         }
539         ast_bridge_destroy(bridge, 0);
540
541         astman_send_ack(s, m, "Bridge has been destroyed");
542
543         return 0;
544 }
545
546 static int manager_bridge_kick(struct mansession *s, const struct message *m)
547 {
548         const char *bridge_uniqueid = astman_get_header(m, "BridgeUniqueid");
549         const char *channel_name = astman_get_header(m, "Channel");
550         RAII_VAR(struct ast_bridge *, bridge, NULL, ao2_cleanup);
551         RAII_VAR(struct ast_channel *, channel, NULL, ao2_cleanup);
552
553         if (ast_strlen_zero(channel_name)) {
554                 astman_send_error(s, m, "Channel must be provided");
555                 return 0;
556         }
557
558         channel = ast_channel_get_by_name(channel_name);
559         if (!channel) {
560                 astman_send_error(s, m, "Channel does not exist");
561                 return 0;
562         }
563
564         if (ast_strlen_zero(bridge_uniqueid)) {
565                 /* get the bridge from the channel */
566                 ast_channel_lock(channel);
567                 bridge = ast_channel_get_bridge(channel);
568                 ast_channel_unlock(channel);
569                 if (!bridge) {
570                         astman_send_error(s, m, "Channel is not in a bridge");
571                         return 0;
572                 }
573         } else {
574                 bridge = ast_bridge_find_by_id(bridge_uniqueid);
575                 if (!bridge) {
576                         astman_send_error(s, m, "Bridge not found");
577                         return 0;
578                 }
579         }
580
581         if (ast_bridge_kick(bridge, channel)) {
582                 astman_send_error(s, m, "Channel kick from bridge failed");
583                 return 0;
584         }
585
586         astman_send_ack(s, m, "Channel has been kicked");
587         return 0;
588 }
589
590 static void manager_bridging_cleanup(void)
591 {
592         stasis_forward_cancel(topic_forwarder);
593         topic_forwarder = NULL;
594 }
595
596 static void manager_bridging_shutdown(void)
597 {
598         ast_manager_unregister("BridgeList");
599         ast_manager_unregister("BridgeInfo");
600         ast_manager_unregister("BridgeDestroy");
601         ast_manager_unregister("BridgeKick");
602 }
603
604 int manager_bridging_init(void)
605 {
606         int ret = 0;
607         struct stasis_topic *manager_topic;
608         struct stasis_topic *bridge_topic;
609
610         if (bridge_state_router) {
611                 /* Already initialized */
612                 return 0;
613         }
614
615         ast_register_atexit(manager_bridging_shutdown);
616         ast_register_cleanup(manager_bridging_cleanup);
617
618         manager_topic = ast_manager_get_topic();
619         if (!manager_topic) {
620                 return -1;
621         }
622
623         bridge_topic = ast_bridge_topic_all_cached();
624         if (!bridge_topic) {
625                 return -1;
626         }
627
628         topic_forwarder = stasis_forward_all(bridge_topic, manager_topic);
629         if (!topic_forwarder) {
630                 return -1;
631         }
632
633         bridge_state_router = ast_manager_get_message_router();
634         if (!bridge_state_router) {
635                 return -1;
636         }
637
638         ret |= stasis_message_router_add_cache_update(bridge_state_router,
639                 ast_bridge_snapshot_type(), bridge_snapshot_update, NULL);
640
641         ret |= stasis_message_router_add(bridge_state_router,
642                 ast_bridge_merge_message_type(), bridge_merge_cb, NULL);
643
644         ret |= stasis_message_router_add(bridge_state_router,
645                 ast_channel_entered_bridge_type(), channel_enter_cb, NULL);
646
647         ret |= stasis_message_router_add(bridge_state_router,
648                 ast_channel_left_bridge_type(), channel_leave_cb, NULL);
649
650         ret |= ast_manager_register_xml_core("BridgeList", 0, manager_bridges_list);
651         ret |= ast_manager_register_xml_core("BridgeInfo", 0, manager_bridge_info);
652         ret |= ast_manager_register_xml_core("BridgeDestroy", 0, manager_bridge_destroy);
653         ret |= ast_manager_register_xml_core("BridgeKick", 0, manager_bridge_kick);
654
655         /* If somehow we failed to add any routes, just shut down the whole
656          * thing and fail it.
657          */
658         if (ret) {
659                 manager_bridging_shutdown();
660                 return -1;
661         }
662
663         return 0;
664 }