ARI - implement allowMultiple for parameters
[asterisk/asterisk.git] / res / ari / resource_bridges.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2012 - 2013, Digium, Inc.
5  *
6  * David M. Lee, II <dlee@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 Implementation for ARI stubs.
22  *
23  * \author David M. Lee, II <dlee@digium.com>
24  */
25
26 /*** MODULEINFO
27         <support_level>core</support_level>
28  ***/
29
30 #include "asterisk.h"
31
32 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
33
34 #include "resource_bridges.h"
35 #include "asterisk/stasis.h"
36 #include "asterisk/stasis_bridges.h"
37 #include "asterisk/stasis_app.h"
38 #include "asterisk/stasis_app_playback.h"
39 #include "asterisk/stasis_app_recording.h"
40 #include "asterisk/stasis_channels.h"
41 #include "asterisk/core_unreal.h"
42 #include "asterisk/channel.h"
43 #include "asterisk/bridge.h"
44 #include "asterisk/format_cap.h"
45 #include "asterisk/file.h"
46
47 /*!
48  * \brief Finds a bridge, filling the response with an error, if appropriate.
49  *
50  * \param[out] response Response to fill with an error if control is not found.
51  * \param bridge_id ID of the bridge to lookup.
52  *
53  * \return Bridget.
54  * \return \c NULL if bridge does not exist.
55  */
56 static struct ast_bridge *find_bridge(
57         struct ast_ari_response *response,
58         const char *bridge_id)
59 {
60         RAII_VAR(struct ast_bridge *, bridge, NULL, ao2_cleanup);
61
62         ast_assert(response != NULL);
63
64         bridge = stasis_app_bridge_find_by_id(bridge_id);
65         if (bridge == NULL) {
66                 RAII_VAR(struct ast_bridge_snapshot *, snapshot,
67                         ast_bridge_snapshot_get_latest(bridge_id), ao2_cleanup);
68                 if (!snapshot) {
69                         ast_ari_response_error(response, 404, "Not found",
70                                 "Bridge not found");
71                         return NULL;
72                 }
73
74                 ast_ari_response_error(response, 409, "Conflict",
75                         "Bridge not in Stasis application");
76                 return NULL;
77         }
78
79         ao2_ref(bridge, +1);
80         return bridge;
81 }
82
83 /*!
84  * \brief Finds the control object for a channel, filling the response with an
85  * error, if appropriate.
86  * \param[out] response Response to fill with an error if control is not found.
87  * \param channel_id ID of the channel to lookup.
88  * \return Channel control object.
89  * \return \c NULL if control object does not exist.
90  */
91 static struct stasis_app_control *find_channel_control(
92         struct ast_ari_response *response,
93         const char *channel_id)
94 {
95         RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
96
97         ast_assert(response != NULL);
98
99         control = stasis_app_control_find_by_channel_id(channel_id);
100         if (control == NULL) {
101                 ast_ari_response_error(response, 422, "Unprocessable Entity",
102                         "Channel not in Stasis application");
103                 return NULL;
104         }
105
106         ao2_ref(control, +1);
107         return control;
108 }
109
110 struct control_list {
111         size_t count;
112         struct stasis_app_control *controls[];
113 };
114
115 static void control_list_dtor(void *obj) {
116         struct control_list *list = obj;
117         size_t i;
118
119         for (i = 0; i < list->count; ++i) {
120                 ao2_cleanup(list->controls[i]);
121                 list->controls[i] = NULL;
122         }
123 }
124
125 static struct control_list *control_list_create(struct ast_ari_response *response, size_t count, const char **channels) {
126         RAII_VAR(struct control_list *, list, NULL, ao2_cleanup);
127         size_t i;
128
129         if (count == 0 || !channels) {
130                 ast_ari_response_error(response, 400, "Bad Request", "Missing parameter channel");
131                 return NULL;
132         }
133
134         list = ao2_alloc(sizeof(*list) + count * sizeof(list->controls[0]), control_list_dtor);
135         if (!list) {
136                 ast_ari_response_alloc_failed(response);
137                 return NULL;
138         }
139
140         for (i = 0; i < count; ++i) {
141                 if (ast_strlen_zero(channels[i])) {
142                         continue;
143                 }
144                 list->controls[list->count] =
145                         find_channel_control(response, channels[i]);
146                 if (!list->controls[list->count]) {
147                         return NULL;
148                 }
149                 ++list->count;
150         }
151
152         if (list->count == 0) {
153                 ast_ari_response_error(response, 400, "Bad Request", "Missing parameter channel");
154                 return NULL;
155         }
156
157         ao2_ref(list, +1);
158         return list;
159 }
160
161 void ast_ari_add_channel_to_bridge(struct ast_variable *headers, struct ast_add_channel_to_bridge_args *args, struct ast_ari_response *response)
162 {
163         RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args->bridge_id), ao2_cleanup);
164         RAII_VAR(struct control_list *, list, NULL, ao2_cleanup);
165         size_t i;
166
167         if (!bridge) {
168                 /* Response filled in by find_bridge */
169                 return;
170         }
171
172         list = control_list_create(response, args->channel_count, args->channel);
173         if (!list) {
174                 /* Response filled in by control_list_create() */
175                 return;
176         }
177
178         for (i = 0; i < list->count; ++i) {
179                 stasis_app_control_add_channel_to_bridge(list->controls[i], bridge);
180         }
181
182         ast_ari_response_no_content(response);
183 }
184
185 void ast_ari_remove_channel_from_bridge(struct ast_variable *headers, struct ast_remove_channel_from_bridge_args *args, struct ast_ari_response *response)
186 {
187         RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args->bridge_id), ao2_cleanup);
188         RAII_VAR(struct control_list *, list, NULL, ao2_cleanup);
189         size_t i;
190
191         if (!bridge) {
192                 /* Response filled in by find_bridge */
193                 return;
194         }
195
196         list = control_list_create(response, args->channel_count, args->channel);
197         if (!list) {
198                 /* Response filled in by control_list_create() */
199                 return;
200         }
201
202         /* BUGBUG this should make sure the bridge requested for removal is actually
203          * the bridge the channel is in. This will be possible once the bridge uniqueid
204          * is added to the channel snapshot. A 409 response should be issued if the bridge
205          * uniqueids don't match */
206         for (i = 0; i < list->count; ++i) {
207                 if (stasis_app_control_remove_channel_from_bridge(list->controls[i], bridge)) {
208                         ast_ari_response_error(response, 500, "Internal Error",
209                                 "Could not remove channel from bridge");
210                 }
211         }
212
213         if (response->response_code) {
214                 return;
215         }
216
217         ast_ari_response_no_content(response);
218 }
219
220 struct bridge_channel_control_thread_data {
221         struct ast_channel *bridge_channel;
222         struct stasis_app_control *control;
223 };
224
225 static void *bridge_channel_control_thread(void *data)
226 {
227         struct bridge_channel_control_thread_data *thread_data = data;
228         struct ast_channel *bridge_channel = thread_data->bridge_channel;
229         struct stasis_app_control *control = thread_data->control;
230
231         RAII_VAR(struct ast_callid *, callid, ast_channel_callid(bridge_channel), ast_callid_cleanup);
232
233         if (callid) {
234                 ast_callid_threadassoc_add(callid);
235         }
236
237         ast_free(thread_data);
238         thread_data = NULL;
239
240         stasis_app_control_execute_until_exhausted(bridge_channel, control);
241
242         ast_hangup(bridge_channel);
243         ao2_cleanup(control);
244         return NULL;
245 }
246
247 static struct ast_channel *prepare_bridge_media_channel(const char *type)
248 {
249         RAII_VAR(struct ast_format_cap *, cap, NULL, ast_format_cap_destroy);
250         struct ast_format format;
251
252         cap = ast_format_cap_alloc_nolock();
253         if (!cap) {
254                 return NULL;
255         }
256
257         ast_format_cap_add(cap, ast_format_set(&format, AST_FORMAT_SLINEAR, 0));
258
259         if (!cap) {
260                 return NULL;
261         }
262
263         return ast_request(type, cap, NULL, "ARI", NULL);
264 }
265
266 void ast_ari_play_on_bridge(struct ast_variable *headers, struct ast_play_on_bridge_args *args, struct ast_ari_response *response)
267 {
268         RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args->bridge_id), ao2_cleanup);
269         RAII_VAR(struct ast_channel *, play_channel, NULL, ast_hangup);
270         RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
271         RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
272         RAII_VAR(struct stasis_app_playback *, playback, NULL, ao2_cleanup);
273         RAII_VAR(char *, playback_url, NULL, ast_free);
274         RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
275
276         struct bridge_channel_control_thread_data *thread_data;
277         const char *language;
278         pthread_t threadid;
279
280         ast_assert(response != NULL);
281
282         if (!bridge) {
283                 return;
284         }
285
286         if (!(play_channel = prepare_bridge_media_channel("Announcer"))) {
287                 ast_ari_response_error(
288                         response, 500, "Internal Error", "Could not create playback channel");
289                 return;
290         }
291         ast_debug(1, "Created announcer channel '%s'\n", ast_channel_name(play_channel));
292
293         if (ast_unreal_channel_push_to_bridge(play_channel, bridge)) {
294                 ast_ari_response_error(
295                         response, 500, "Internal Error", "Failed to put playback channel into the bridge");
296                 return;
297         }
298
299         control = stasis_app_control_create(play_channel);
300         if (control == NULL) {
301                 ast_ari_response_alloc_failed(response);
302                 return;
303         }
304
305         snapshot = stasis_app_control_get_snapshot(control);
306         if (!snapshot) {
307                 ast_ari_response_error(
308                         response, 500, "Internal Error", "Failed to get control snapshot");
309                 return;
310         }
311
312         language = S_OR(args->lang, snapshot->language);
313
314         playback = stasis_app_control_play_uri(control, args->media, language,
315                 args->bridge_id, STASIS_PLAYBACK_TARGET_BRIDGE, args->skipms,
316                 args->offsetms);
317
318         if (!playback) {
319                 ast_ari_response_alloc_failed(response);
320                 return;
321         }
322
323         ast_asprintf(&playback_url, "/playback/%s",
324                 stasis_app_playback_get_id(playback));
325
326         if (!playback_url) {
327                 ast_ari_response_alloc_failed(response);
328                 return;
329         }
330
331         json = stasis_app_playback_to_json(playback);
332         if (!json) {
333                 ast_ari_response_alloc_failed(response);
334                 return;
335         }
336
337         /* Give play_channel and control reference to the thread data */
338         thread_data = ast_calloc(1, sizeof(*thread_data));
339         if (!thread_data) {
340                 ast_ari_response_alloc_failed(response);
341                 return;
342         }
343
344         thread_data->bridge_channel = play_channel;
345         thread_data->control = control;
346
347         if (ast_pthread_create_detached(&threadid, NULL, bridge_channel_control_thread, thread_data)) {
348                 ast_ari_response_alloc_failed(response);
349                 ast_free(thread_data);
350                 return;
351         }
352
353         /* These are owned by the other thread now, so we don't want RAII_VAR disposing of them. */
354         play_channel = NULL;
355         control = NULL;
356
357         ast_ari_response_created(response, playback_url, json);
358 }
359
360 void ast_ari_record_bridge(struct ast_variable *headers, struct ast_record_bridge_args *args, struct ast_ari_response *response)
361 {
362         RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args->bridge_id), ao2_cleanup);
363         RAII_VAR(struct ast_channel *, record_channel, NULL, ast_hangup);
364         RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
365         RAII_VAR(struct stasis_app_recording *, recording, NULL, ao2_cleanup);
366         RAII_VAR(char *, recording_url, NULL, ast_free);
367         RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
368         RAII_VAR(struct stasis_app_recording_options *, options, NULL, ao2_cleanup);
369         RAII_VAR(char *, uri_encoded_name, NULL, ast_free);
370
371         size_t uri_name_maxlen;
372         struct bridge_channel_control_thread_data *thread_data;
373         pthread_t threadid;
374
375         ast_assert(response != NULL);
376
377         if (bridge == NULL) {
378                 return;
379         }
380
381         if (!(record_channel = prepare_bridge_media_channel("Recorder"))) {
382                 ast_ari_response_error(
383                         response, 500, "Internal Server Error", "Failed to create recording channel");
384                 return;
385         }
386
387         if (ast_unreal_channel_push_to_bridge(record_channel, bridge)) {
388                 ast_ari_response_error(
389                         response, 500, "Internal Error", "Failed to put recording channel into the bridge");
390                 return;
391         }
392
393         control = stasis_app_control_create(record_channel);
394         if (control == NULL) {
395                 ast_ari_response_alloc_failed(response);
396                 return;
397         }
398
399         options = stasis_app_recording_options_create(args->name, args->format);
400         if (options == NULL) {
401                 ast_ari_response_alloc_failed(response);
402                 return;
403         }
404
405         options->max_silence_seconds = args->max_silence_seconds;
406         options->max_duration_seconds = args->max_duration_seconds;
407         options->terminate_on =
408                 stasis_app_recording_termination_parse(args->terminate_on);
409         options->if_exists =
410                 stasis_app_recording_if_exists_parse(args->if_exists);
411         options->beep = args->beep;
412
413         recording = stasis_app_control_record(control, options);
414         if (recording == NULL) {
415                 switch(errno) {
416                 case EINVAL:
417                         /* While the arguments are invalid, we should have
418                          * caught them prior to calling record.
419                          */
420                         ast_ari_response_error(
421                                 response, 500, "Internal Server Error",
422                                 "Error parsing request");
423                         break;
424                 case EEXIST:
425                         ast_ari_response_error(response, 409, "Conflict",
426                                 "Recording '%s' already in progress",
427                                 args->name);
428                         break;
429                 case ENOMEM:
430                         ast_ari_response_alloc_failed(response);
431                         break;
432                 case EPERM:
433                         ast_ari_response_error(
434                                 response, 400, "Bad Request",
435                                 "Recording name invalid");
436                         break;
437                 default:
438                         ast_log(LOG_WARNING,
439                                 "Unrecognized recording error: %s\n",
440                                 strerror(errno));
441                         ast_ari_response_error(
442                                 response, 500, "Internal Server Error",
443                                 "Internal Server Error");
444                         break;
445                 }
446                 return;
447         }
448
449         uri_name_maxlen = strlen(args->name) * 3;
450         uri_encoded_name = ast_malloc(uri_name_maxlen);
451         if (!uri_encoded_name) {
452                 ast_ari_response_alloc_failed(response);
453                 return;
454         }
455         ast_uri_encode(args->name, uri_encoded_name, uri_name_maxlen, ast_uri_http);
456
457         ast_asprintf(&recording_url, "/recordings/live/%s", uri_encoded_name);
458         if (!recording_url) {
459                 ast_ari_response_alloc_failed(response);
460                 return;
461         }
462
463         json = stasis_app_recording_to_json(recording);
464         if (!json) {
465                 ast_ari_response_alloc_failed(response);
466                 return;
467         }
468
469         thread_data = ast_calloc(1, sizeof(*thread_data));
470         if (!thread_data) {
471                 ast_ari_response_alloc_failed(response);
472                 return;
473         }
474
475         thread_data->bridge_channel = record_channel;
476         thread_data->control = control;
477
478         if (ast_pthread_create_detached(&threadid, NULL, bridge_channel_control_thread, thread_data)) {
479                 ast_ari_response_alloc_failed(response);
480                 ast_free(thread_data);
481                 return;
482         }
483
484         /* These are owned by the other thread now, so we don't want RAII_VAR disposing of them. */
485         record_channel = NULL;
486         control = NULL;
487
488         ast_ari_response_created(response, recording_url, json);
489 }
490
491 void ast_ari_get_bridge(struct ast_variable *headers, struct ast_get_bridge_args *args, struct ast_ari_response *response)
492 {
493         RAII_VAR(struct ast_bridge_snapshot *, snapshot, ast_bridge_snapshot_get_latest(args->bridge_id), ao2_cleanup);
494         if (!snapshot) {
495                 ast_ari_response_error(
496                         response, 404, "Not Found",
497                         "Bridge not found");
498                 return;
499         }
500
501         ast_ari_response_ok(response,
502                 ast_bridge_snapshot_to_json(snapshot));
503 }
504
505 void ast_ari_delete_bridge(struct ast_variable *headers, struct ast_delete_bridge_args *args, struct ast_ari_response *response)
506 {
507         RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args->bridge_id), ao2_cleanup);
508         if (!bridge) {
509                 return;
510         }
511
512         stasis_app_bridge_destroy(args->bridge_id);
513         ast_ari_response_no_content(response);
514 }
515
516 void ast_ari_get_bridges(struct ast_variable *headers, struct ast_get_bridges_args *args, struct ast_ari_response *response)
517 {
518         RAII_VAR(struct stasis_cache *, cache, NULL, ao2_cleanup);
519         RAII_VAR(struct ao2_container *, snapshots, NULL, ao2_cleanup);
520         RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
521         struct ao2_iterator i;
522         void *obj;
523
524         cache = ast_bridge_cache();
525         if (!cache) {
526                 ast_ari_response_error(
527                         response, 500, "Internal Server Error",
528                         "Message bus not initialized");
529                 return;
530         }
531         ao2_ref(cache, +1);
532
533         snapshots = stasis_cache_dump(cache, ast_bridge_snapshot_type());
534         if (!snapshots) {
535                 ast_ari_response_alloc_failed(response);
536                 return;
537         }
538
539         json = ast_json_array_create();
540         if (!json) {
541                 ast_ari_response_alloc_failed(response);
542                 return;
543         }
544
545         i = ao2_iterator_init(snapshots, 0);
546         while ((obj = ao2_iterator_next(&i))) {
547                 RAII_VAR(struct stasis_message *, msg, obj, ao2_cleanup);
548                 struct ast_bridge_snapshot *snapshot = stasis_message_data(msg);
549                 if (ast_json_array_append(json, ast_bridge_snapshot_to_json(snapshot))) {
550                         ast_ari_response_alloc_failed(response);
551                         return;
552                 }
553         }
554         ao2_iterator_destroy(&i);
555
556         ast_ari_response_ok(response, ast_json_ref(json));
557 }
558
559 void ast_ari_new_bridge(struct ast_variable *headers, struct ast_new_bridge_args *args, struct ast_ari_response *response)
560 {
561         RAII_VAR(struct ast_bridge *, bridge, stasis_app_bridge_create(args->type), ao2_cleanup);
562         RAII_VAR(struct ast_bridge_snapshot *, snapshot, NULL, ao2_cleanup);
563
564         if (!bridge) {
565                 ast_ari_response_error(
566                         response, 500, "Internal Error",
567                         "Unable to create bridge");
568                 return;
569         }
570
571         snapshot = ast_bridge_snapshot_create(bridge);
572         if (!snapshot) {
573                 ast_ari_response_error(
574                         response, 500, "Internal Error",
575                         "Unable to create snapshot for new bridge");
576                 return;
577         }
578
579         ast_ari_response_ok(response,
580                 ast_bridge_snapshot_to_json(snapshot));
581 }