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