Fix shutdown crash caused by modules being left open.
[asterisk/asterisk.git] / bridges / bridge_builtin_features.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2009, Digium, Inc.
5  *
6  * Joshua Colp <jcolp@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 Built in bridging features
22  *
23  * \author Joshua Colp <jcolp@digium.com>
24  *
25  * \ingroup bridges
26  */
27
28 /*** MODULEINFO
29         <support_level>core</support_level>
30  ***/
31
32 #include "asterisk.h"
33
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <sys/types.h>
38 #include <sys/stat.h>
39
40 #include "asterisk/module.h"
41 #include "asterisk/channel.h"
42 #include "asterisk/bridge.h"
43 #include "asterisk/bridge_technology.h"
44 #include "asterisk/frame.h"
45 #include "asterisk/file.h"
46 #include "asterisk/app.h"
47 #include "asterisk/astobj2.h"
48 #include "asterisk/pbx.h"
49 #include "asterisk/parking.h"
50 #include "asterisk/features_config.h"
51 #include "asterisk/monitor.h"
52 #include "asterisk/mixmonitor.h"
53 #include "asterisk/audiohook.h"
54 #include "asterisk/causes.h"
55
56 enum set_touch_variables_res {
57         SET_TOUCH_SUCCESS,
58         SET_TOUCH_UNSET,
59         SET_TOUCH_ALLOC_FAILURE,
60 };
61
62 static void set_touch_variable(enum set_touch_variables_res *res, struct ast_channel *chan, const char *var_name, char **touch)
63 {
64         const char *c_touch;
65
66         if (*res == SET_TOUCH_ALLOC_FAILURE) {
67                 return;
68         }
69         c_touch = pbx_builtin_getvar_helper(chan, var_name);
70         if (!ast_strlen_zero(c_touch)) {
71                 *touch = ast_strdup(c_touch);
72                 if (!*touch) {
73                         *res = SET_TOUCH_ALLOC_FAILURE;
74                 } else {
75                         *res = SET_TOUCH_SUCCESS;
76                 }
77         }
78 }
79
80 static enum set_touch_variables_res set_touch_variables(struct ast_channel *chan, int is_mixmonitor, char **touch_format, char **touch_monitor, char **touch_monitor_prefix)
81 {
82         enum set_touch_variables_res res = SET_TOUCH_UNSET;
83         const char *var_format;
84         const char *var_monitor;
85         const char *var_prefix;
86
87         SCOPED_CHANNELLOCK(lock, chan);
88
89         if (is_mixmonitor) {
90                 var_format = "TOUCH_MIXMONITOR_FORMAT";
91                 var_monitor = "TOUCH_MIXMONITOR";
92                 var_prefix = "TOUCH_MIXMONITOR_PREFIX";
93         } else {
94                 var_format = "TOUCH_MONITOR_FORMAT";
95                 var_monitor = "TOUCH_MONITOR";
96                 var_prefix = "TOUCH_MONITOR_PREFIX";
97         }
98         set_touch_variable(&res, chan, var_format, touch_format);
99         set_touch_variable(&res, chan, var_monitor, touch_monitor);
100         set_touch_variable(&res, chan, var_prefix, touch_monitor_prefix);
101
102         return res;
103 }
104
105 static void stop_automonitor(struct ast_bridge_channel *bridge_channel, struct ast_channel *peer_chan, struct ast_features_general_config *features_cfg, const char *stop_message)
106 {
107         ast_verb(4, "AutoMonitor used to stop recording call.\n");
108
109         ast_channel_lock(peer_chan);
110         if (ast_channel_monitor(peer_chan)) {
111                 if (ast_channel_monitor(peer_chan)->stop(peer_chan, 1)) {
112                         ast_verb(4, "Cannot stop AutoMonitor for %s\n", ast_channel_name(bridge_channel->chan));
113                         if (features_cfg && !(ast_strlen_zero(features_cfg->recordingfailsound))) {
114                                 ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->recordingfailsound, NULL);
115                         }
116                         ast_channel_unlock(peer_chan);
117                         return;
118                 }
119         } else {
120                 /* Something else removed the Monitor before we got to it. */
121                 ast_channel_unlock(peer_chan);
122                 return;
123         }
124
125         ast_channel_unlock(peer_chan);
126
127         if (features_cfg && !(ast_strlen_zero(features_cfg->courtesytone))) {
128                 ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL);
129                 ast_bridge_channel_write_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL);
130         }
131
132         if (!ast_strlen_zero(stop_message)) {
133                 ast_bridge_channel_queue_playfile(bridge_channel, NULL, stop_message, NULL);
134                 ast_bridge_channel_write_playfile(bridge_channel, NULL, stop_message, NULL);
135         }
136 }
137
138 static void start_automonitor(struct ast_bridge_channel *bridge_channel, struct ast_channel *peer_chan, struct ast_features_general_config *features_cfg, const char *start_message)
139 {
140         char *touch_filename;
141         size_t len;
142         int x;
143         enum set_touch_variables_res set_touch_res;
144
145         RAII_VAR(char *, touch_format, NULL, ast_free);
146         RAII_VAR(char *, touch_monitor, NULL, ast_free);
147         RAII_VAR(char *, touch_monitor_prefix, NULL, ast_free);
148
149         set_touch_res = set_touch_variables(bridge_channel->chan, 0, &touch_format,
150                 &touch_monitor, &touch_monitor_prefix);
151         switch (set_touch_res) {
152         case SET_TOUCH_SUCCESS:
153                 break;
154         case SET_TOUCH_UNSET:
155                 set_touch_res = set_touch_variables(peer_chan, 0, &touch_format, &touch_monitor,
156                         &touch_monitor_prefix);
157                 if (set_touch_res == SET_TOUCH_ALLOC_FAILURE) {
158                         return;
159                 }
160                 break;
161         case SET_TOUCH_ALLOC_FAILURE:
162                 return;
163         }
164
165         if (!ast_strlen_zero(touch_monitor)) {
166                 len = strlen(touch_monitor) + 50;
167                 touch_filename = ast_alloca(len);
168                 snprintf(touch_filename, len, "%s-%ld-%s",
169                         S_OR(touch_monitor_prefix, "auto"),
170                         (long) time(NULL),
171                         touch_monitor);
172         } else {
173                 char *caller_chan_id;
174                 char *peer_chan_id;
175
176                 caller_chan_id = ast_strdupa(S_COR(ast_channel_caller(bridge_channel->chan)->id.number.valid,
177                         ast_channel_caller(bridge_channel->chan)->id.number.str, ast_channel_name(bridge_channel->chan)));
178                 peer_chan_id = ast_strdupa(S_COR(ast_channel_caller(peer_chan)->id.number.valid,
179                         ast_channel_caller(peer_chan)->id.number.str, ast_channel_name(peer_chan)));
180                 len = strlen(caller_chan_id) + strlen(peer_chan_id) + 50;
181                 touch_filename = ast_alloca(len);
182                 snprintf(touch_filename, len, "%s-%ld-%s-%s",
183                         S_OR(touch_monitor_prefix, "auto"),
184                         (long) time(NULL),
185                         caller_chan_id,
186                         peer_chan_id);
187         }
188
189         for (x = 0; x < strlen(touch_filename); x++) {
190                 if (touch_filename[x] == '/') {
191                         touch_filename[x] = '-';
192                 }
193         }
194
195         ast_verb(4, "AutoMonitor used to record call. Filename: %s\n", touch_filename);
196
197         if (ast_monitor_start(peer_chan, touch_format, touch_filename, 1, X_REC_IN | X_REC_OUT, NULL)) {
198                 ast_verb(4, "AutoMonitor feature was tried by '%s' but monitor failed to start.\n",
199                         ast_channel_name(bridge_channel->chan));
200                 return;
201         }
202
203         if (features_cfg && !ast_strlen_zero(features_cfg->courtesytone)) {
204                 ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL);
205                 ast_bridge_channel_write_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL);
206         }
207
208         if (!ast_strlen_zero(start_message)) {
209                 ast_bridge_channel_queue_playfile(bridge_channel, NULL, start_message, NULL);
210                 ast_bridge_channel_write_playfile(bridge_channel, NULL, start_message, NULL);
211         }
212
213         pbx_builtin_setvar_helper(peer_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
214 }
215
216 static int feature_automonitor(struct ast_bridge_channel *bridge_channel, void *hook_pvt)
217 {
218         const char *start_message;
219         const char *stop_message;
220         struct ast_bridge_features_automonitor *options = hook_pvt;
221         enum ast_bridge_features_monitor start_stop = options ? options->start_stop : AUTO_MONITOR_TOGGLE;
222         int is_monitoring;
223
224         RAII_VAR(struct ast_channel *, peer_chan, NULL, ast_channel_cleanup);
225         RAII_VAR(struct ast_features_general_config *, features_cfg, NULL, ao2_cleanup);
226
227         ast_channel_lock(bridge_channel->chan);
228         features_cfg = ast_get_chan_features_general_config(bridge_channel->chan);
229         ast_channel_unlock(bridge_channel->chan);
230         ast_bridge_channel_lock_bridge(bridge_channel);
231         peer_chan = ast_bridge_peer_nolock(bridge_channel->bridge, bridge_channel->chan);
232         ast_bridge_unlock(bridge_channel->bridge);
233
234         if (!peer_chan) {
235                 ast_verb(4, "Cannot start AutoMonitor for %s - can not determine peer in bridge.\n",
236                         ast_channel_name(bridge_channel->chan));
237                 if (features_cfg && !ast_strlen_zero(features_cfg->recordingfailsound)) {
238                         ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->recordingfailsound, NULL);
239                 }
240                 return 0;
241         }
242
243         ast_channel_lock(bridge_channel->chan);
244         start_message = pbx_builtin_getvar_helper(bridge_channel->chan,
245                 "TOUCH_MONITOR_MESSAGE_START");
246         start_message = ast_strdupa(S_OR(start_message, ""));
247         stop_message = pbx_builtin_getvar_helper(bridge_channel->chan,
248                 "TOUCH_MONITOR_MESSAGE_STOP");
249         stop_message = ast_strdupa(S_OR(stop_message, ""));
250         ast_channel_unlock(bridge_channel->chan);
251
252         is_monitoring = ast_channel_monitor(peer_chan) != NULL;
253         switch (start_stop) {
254         case AUTO_MONITOR_TOGGLE:
255                 if (is_monitoring) {
256                         stop_automonitor(bridge_channel, peer_chan, features_cfg, stop_message);
257                 } else {
258                         start_automonitor(bridge_channel, peer_chan, features_cfg, start_message);
259                 }
260                 return 0;
261         case AUTO_MONITOR_START:
262                 if (!is_monitoring) {
263                         start_automonitor(bridge_channel, peer_chan, features_cfg, start_message);
264                         return 0;
265                 }
266                 ast_verb(4, "AutoMonitor already recording call.\n");
267                 break;
268         case AUTO_MONITOR_STOP:
269                 if (is_monitoring) {
270                         stop_automonitor(bridge_channel, peer_chan, features_cfg, stop_message);
271                         return 0;
272                 }
273                 ast_verb(4, "AutoMonitor already stopped on call.\n");
274                 break;
275         }
276
277         /*
278          * Fake start/stop to invoker so will think it did something but
279          * was already in that mode.
280          */
281         if (features_cfg && !ast_strlen_zero(features_cfg->courtesytone)) {
282                 ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL);
283         }
284         if (is_monitoring) {
285                 if (!ast_strlen_zero(start_message)) {
286                         ast_bridge_channel_queue_playfile(bridge_channel, NULL, start_message, NULL);
287                 }
288         } else {
289                 if (!ast_strlen_zero(stop_message)) {
290                         ast_bridge_channel_queue_playfile(bridge_channel, NULL, stop_message, NULL);
291                 }
292         }
293         return 0;
294 }
295
296 static void stop_automixmonitor(struct ast_bridge_channel *bridge_channel, struct ast_channel *peer_chan, struct ast_features_general_config *features_cfg, const char *stop_message)
297 {
298         ast_verb(4, "AutoMixMonitor used to stop recording call.\n");
299
300         if (ast_stop_mixmonitor(peer_chan, NULL)) {
301                 ast_verb(4, "Failed to stop AutoMixMonitor for %s.\n", ast_channel_name(bridge_channel->chan));
302                 if (features_cfg && !(ast_strlen_zero(features_cfg->recordingfailsound))) {
303                         ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->recordingfailsound, NULL);
304                 }
305                 return;
306         }
307
308         if (features_cfg && !ast_strlen_zero(features_cfg->courtesytone)) {
309                 ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL);
310                 ast_bridge_channel_write_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL);
311         }
312
313         if (!ast_strlen_zero(stop_message)) {
314                 ast_bridge_channel_queue_playfile(bridge_channel, NULL, stop_message, NULL);
315                 ast_bridge_channel_write_playfile(bridge_channel, NULL, stop_message, NULL);
316         }
317 }
318
319 static void start_automixmonitor(struct ast_bridge_channel *bridge_channel, struct ast_channel *peer_chan, struct ast_features_general_config *features_cfg, const char *start_message)
320 {
321         char *touch_filename;
322         size_t len;
323         int x;
324         enum set_touch_variables_res set_touch_res;
325
326         RAII_VAR(char *, touch_format, NULL, ast_free);
327         RAII_VAR(char *, touch_monitor, NULL, ast_free);
328         RAII_VAR(char *, touch_monitor_prefix, NULL, ast_free);
329
330         set_touch_res = set_touch_variables(bridge_channel->chan, 1, &touch_format,
331                 &touch_monitor, &touch_monitor_prefix);
332         switch (set_touch_res) {
333         case SET_TOUCH_SUCCESS:
334                 break;
335         case SET_TOUCH_UNSET:
336                 set_touch_res = set_touch_variables(peer_chan, 1, &touch_format, &touch_monitor,
337                         &touch_monitor_prefix);
338                 if (set_touch_res == SET_TOUCH_ALLOC_FAILURE) {
339                         return;
340                 }
341                 break;
342         case SET_TOUCH_ALLOC_FAILURE:
343                 return;
344         }
345
346         if (!ast_strlen_zero(touch_monitor)) {
347                 len = strlen(touch_monitor) + 50;
348                 touch_filename = ast_alloca(len);
349                 snprintf(touch_filename, len, "%s-%ld-%s.%s",
350                         S_OR(touch_monitor_prefix, "auto"),
351                         (long) time(NULL),
352                         touch_monitor,
353                         S_OR(touch_format, "wav"));
354         } else {
355                 char *caller_chan_id;
356                 char *peer_chan_id;
357
358                 caller_chan_id = ast_strdupa(S_COR(ast_channel_caller(bridge_channel->chan)->id.number.valid,
359                         ast_channel_caller(bridge_channel->chan)->id.number.str, ast_channel_name(bridge_channel->chan)));
360                 peer_chan_id = ast_strdupa(S_COR(ast_channel_caller(peer_chan)->id.number.valid,
361                         ast_channel_caller(peer_chan)->id.number.str, ast_channel_name(peer_chan)));
362                 len = strlen(caller_chan_id) + strlen(peer_chan_id) + 50;
363                 touch_filename = ast_alloca(len);
364                 snprintf(touch_filename, len, "%s-%ld-%s-%s.%s",
365                         S_OR(touch_monitor_prefix, "auto"),
366                         (long) time(NULL),
367                         caller_chan_id,
368                         peer_chan_id,
369                         S_OR(touch_format, "wav"));
370         }
371
372         for (x = 0; x < strlen(touch_filename); x++) {
373                 if (touch_filename[x] == '/') {
374                         touch_filename[x] = '-';
375                 }
376         }
377
378         ast_verb(4, "AutoMixMonitor used to record call. Filename: %s\n", touch_filename);
379
380         if (ast_start_mixmonitor(peer_chan, touch_filename, "b")) {
381                 ast_verb(4, "AutoMixMonitor feature was tried by '%s' but MixMonitor failed to start.\n",
382                         ast_channel_name(bridge_channel->chan));
383
384                 if (features_cfg && !ast_strlen_zero(features_cfg->recordingfailsound)) {
385                         ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->recordingfailsound, NULL);
386                 }
387                 return;
388         }
389
390         if (features_cfg && !ast_strlen_zero(features_cfg->courtesytone)) {
391                 ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL);
392                 ast_bridge_channel_write_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL);
393         }
394
395         if (!ast_strlen_zero(start_message)) {
396                 ast_bridge_channel_queue_playfile(bridge_channel, NULL, start_message, NULL);
397                 ast_bridge_channel_write_playfile(bridge_channel, NULL, start_message, NULL);
398         }
399
400         pbx_builtin_setvar_helper(peer_chan, "TOUCH_MIXMONITOR_OUTPUT", touch_filename);
401 }
402
403 static int feature_automixmonitor(struct ast_bridge_channel *bridge_channel, void *hook_pvt)
404 {
405         static const char *mixmonitor_spy_type = "MixMonitor";
406         const char *stop_message;
407         const char *start_message;
408         struct ast_bridge_features_automixmonitor *options = hook_pvt;
409         enum ast_bridge_features_monitor start_stop = options ? options->start_stop : AUTO_MONITOR_TOGGLE;
410         int is_monitoring;
411
412         RAII_VAR(struct ast_channel *, peer_chan, NULL, ast_channel_cleanup);
413         RAII_VAR(struct ast_features_general_config *, features_cfg, NULL, ao2_cleanup);
414
415         ast_channel_lock(bridge_channel->chan);
416         features_cfg = ast_get_chan_features_general_config(bridge_channel->chan);
417         ast_channel_unlock(bridge_channel->chan);
418         ast_bridge_channel_lock_bridge(bridge_channel);
419         peer_chan = ast_bridge_peer_nolock(bridge_channel->bridge, bridge_channel->chan);
420         ast_bridge_unlock(bridge_channel->bridge);
421
422         if (!peer_chan) {
423                 ast_verb(4, "Cannot start AutoMixMonitor for %s - cannot determine peer in bridge.\n",
424                         ast_channel_name(bridge_channel->chan));
425                 if (features_cfg && !ast_strlen_zero(features_cfg->recordingfailsound)) {
426                         ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->recordingfailsound, NULL);
427                 }
428                 return 0;
429         }
430
431         ast_channel_lock(bridge_channel->chan);
432         start_message = pbx_builtin_getvar_helper(bridge_channel->chan,
433                 "TOUCH_MIXMONITOR_MESSAGE_START");
434         start_message = ast_strdupa(S_OR(start_message, ""));
435         stop_message = pbx_builtin_getvar_helper(bridge_channel->chan,
436                 "TOUCH_MIXMONITOR_MESSAGE_STOP");
437         stop_message = ast_strdupa(S_OR(stop_message, ""));
438         ast_channel_unlock(bridge_channel->chan);
439
440         is_monitoring =
441                 0 < ast_channel_audiohook_count_by_source(peer_chan, mixmonitor_spy_type, AST_AUDIOHOOK_TYPE_SPY);
442         switch (start_stop) {
443         case AUTO_MONITOR_TOGGLE:
444                 if (is_monitoring) {
445                         stop_automixmonitor(bridge_channel, peer_chan, features_cfg, stop_message);
446                 } else {
447                         start_automixmonitor(bridge_channel, peer_chan, features_cfg, start_message);
448                 }
449                 return 0;
450         case AUTO_MONITOR_START:
451                 if (!is_monitoring) {
452                         start_automixmonitor(bridge_channel, peer_chan, features_cfg, start_message);
453                         return 0;
454                 }
455                 ast_verb(4, "AutoMixMonitor already recording call.\n");
456                 break;
457         case AUTO_MONITOR_STOP:
458                 if (is_monitoring) {
459                         stop_automixmonitor(bridge_channel, peer_chan, features_cfg, stop_message);
460                         return 0;
461                 }
462                 ast_verb(4, "AutoMixMonitor already stopped on call.\n");
463                 break;
464         }
465
466         /*
467          * Fake start/stop to invoker so will think it did something but
468          * was already in that mode.
469          */
470         if (features_cfg && !ast_strlen_zero(features_cfg->courtesytone)) {
471                 ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL);
472         }
473         if (is_monitoring) {
474                 if (!ast_strlen_zero(start_message)) {
475                         ast_bridge_channel_queue_playfile(bridge_channel, NULL, start_message, NULL);
476                 }
477         } else {
478                 if (!ast_strlen_zero(stop_message)) {
479                         ast_bridge_channel_queue_playfile(bridge_channel, NULL, stop_message, NULL);
480                 }
481         }
482         return 0;
483 }
484
485 /*! \brief Internal built in feature for hangup */
486 static int feature_hangup(struct ast_bridge_channel *bridge_channel, void *hook_pvt)
487 {
488         /*
489          * This is very simple, we simply change the state on the
490          * bridge_channel to force the channel out of the bridge and the
491          * core takes care of the rest.
492          */
493         ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END,
494                 AST_CAUSE_NORMAL_CLEARING);
495         return 0;
496 }
497
498 static int unload_module(void)
499 {
500         ast_bridge_features_unregister(AST_BRIDGE_BUILTIN_HANGUP);
501         ast_bridge_features_unregister(AST_BRIDGE_BUILTIN_AUTOMON);
502         ast_bridge_features_unregister(AST_BRIDGE_BUILTIN_AUTOMIXMON);
503
504         return 0;
505 }
506
507 static int load_module(void)
508 {
509         ast_bridge_features_register(AST_BRIDGE_BUILTIN_HANGUP, feature_hangup, NULL);
510         ast_bridge_features_register(AST_BRIDGE_BUILTIN_AUTOMON, feature_automonitor, NULL);
511         ast_bridge_features_register(AST_BRIDGE_BUILTIN_AUTOMIXMON, feature_automixmonitor, NULL);
512
513         /* This module cannot be unloaded until shutdown */
514         ast_module_shutdown_ref(ast_module_info->self);
515
516         return AST_MODULE_LOAD_SUCCESS;
517 }
518
519 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Built in bridging features");