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