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