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