Asterisk - The Open Source Telephony Project GIT-master-6144b6b
Loading...
Searching...
No Matches
resource_channels.c
Go to the documentation of this file.
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#include "asterisk/file.h"
33#include "asterisk/pbx.h"
34#include "asterisk/bridge.h"
35#include "asterisk/callerid.h"
36#include "asterisk/stasis_app.h"
41#include "asterisk/causes.h"
43#include "asterisk/core_local.h"
44#include "asterisk/dial.h"
46#include "asterisk/rtp_engine.h"
48#include "resource_channels.h"
49
50#include <limits.h>
51
52
53/*! \brief Return the corresponded hangup code of the given reason */
54static int convert_reason_to_hangup_code(const char* reason)
55{
56 if (!strcmp(reason, "normal")) {
57 return AST_CAUSE_NORMAL;
58 } else if (!strcmp(reason, "busy")) {
59 return AST_CAUSE_BUSY;
60 } else if (!strcmp(reason, "congestion")) {
62 } else if (!strcmp(reason, "no_answer")) {
63 return AST_CAUSE_NOANSWER;
64 } else if (!strcmp(reason, "timeout")) {
66 } else if (!strcmp(reason, "rejected")) {
68 } else if (!strcmp(reason, "unallocated")) {
70 } else if (!strcmp(reason, "normal_unspecified")) {
72 } else if (!strcmp(reason, "number_incomplete")) {
74 } else if (!strcmp(reason, "codec_mismatch")) {
76 } else if (!strcmp(reason, "interworking")) {
78 } else if (!strcmp(reason, "failure")) {
79 return AST_CAUSE_FAILURE;
80 } else if(!strcmp(reason, "answered_elsewhere")) {
82 }
83
84 return -1;
85}
86
87/*!
88 * \brief Ensure channel is in a state that allows operation to be performed.
89 *
90 * Since Asterisk 14, it has been possible for down channels, as well as unanswered
91 * outbound channels to enter Stasis. While some operations are fine to perform on
92 * such channels, operations that
93 *
94 * - Attempt to manipulate channel state
95 * - Attempt to play media
96 * - Attempt to control the channel's location in the dialplan
97 *
98 * are invalid. This function can be used to determine if the channel is in an
99 * appropriate state.
100 *
101 * \note When this function returns an error, the HTTP response is taken care of.
102 *
103 * \param control The app control
104 * \param response Response to fill in if there is an error
105 *
106 * \retval 0 Channel is in a valid state. Continue on!
107 * \retval non-zero Channel is in an invalid state. Bail!
108 */
109static int channel_state_invalid(struct stasis_app_control *control,
110 struct ast_ari_response *response)
111{
112 struct ast_channel_snapshot *snapshot;
113
114 snapshot = stasis_app_control_get_snapshot(control);
115 if (!snapshot) {
116 ast_ari_response_error(response, 404, "Not Found", "Channel not found");
117 return -1;
118 }
119
120 /* These channel states apply only to outbound channels:
121 * - Down: Channel has been created, and nothing else has been done
122 * - Reserved: For a PRI, an underlying B-channel is reserved,
123 * but the channel is not yet dialed
124 * - Ringing: The channel has been dialed.
125 *
126 * This does not affect inbound channels. Inbound channels, when they
127 * enter the dialplan, are in the "Ring" state. If they have already
128 * been answered, then they are in the "Up" state.
129 */
130 if (snapshot->state == AST_STATE_DOWN
131 || snapshot->state == AST_STATE_RESERVED
132 || snapshot->state == AST_STATE_RINGING) {
133 ast_ari_response_error(response, 412, "Precondition Failed",
134 "Channel in invalid state");
135 ao2_ref(snapshot, -1);
136
137 return -1;
138 }
139
140 ao2_ref(snapshot, -1);
141
142 return 0;
143}
144
145/*!
146 * \brief Finds the control object for a channel, filling the response with an
147 * error, if appropriate.
148 * \param[out] response Response to fill with an error if control is not found.
149 * \param channel_id ID of the channel to lookup.
150 * \return Channel control object.
151 * \retval NULL if control object does not exist.
152 */
154 struct ast_ari_response *response,
155 const char *channel_id)
156{
157 RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
158
159 ast_assert(response != NULL);
160
161 control = stasis_app_control_find_by_channel_id(channel_id);
162 if (control == NULL) {
163 /* Distinguish between 404 and 409 errors */
164 RAII_VAR(struct ast_channel *, chan, NULL, ao2_cleanup);
165 chan = ast_channel_get_by_name(channel_id);
166 if (chan == NULL) {
167 ast_ari_response_error(response, 404, "Not Found",
168 "Channel not found");
169 return NULL;
170 }
171
172 ast_ari_response_error(response, 409, "Conflict",
173 "Channel not in Stasis application");
174 return NULL;
175 }
176
177 ao2_ref(control, +1);
178 return control;
179}
180
182 struct ast_variable *headers,
184 struct ast_ari_response *response)
185{
186 RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
187 RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
188 int ipri;
189 const char *context;
190 const char *exten;
191
192 ast_assert(response != NULL);
193
194 control = find_control(response, args->channel_id);
195 if (control == NULL) {
196 return;
197 }
198
199 if (channel_state_invalid(control, response)) {
200 return;
201 }
202
203 snapshot = stasis_app_control_get_snapshot(control);
204 if (!snapshot) {
205 ast_ari_response_error(response, 404, "Not Found", "Channel not found");
206 return;
207 }
208
209 if (ast_strlen_zero(args->context)) {
210 context = snapshot->dialplan->context;
211 exten = S_OR(args->extension, snapshot->dialplan->exten);
212 } else {
213 context = args->context;
214 exten = S_OR(args->extension, "s");
215 }
216
217 if (!ast_strlen_zero(args->label)) {
218 /* A label was provided in the request, use that */
219
220 if (sscanf(args->label, "%30d", &ipri) != 1) {
221 ipri = ast_findlabel_extension(NULL, context, exten, args->label, NULL);
222 if (ipri == -1) {
223 ast_log(AST_LOG_ERROR, "Requested label: %s can not be found in context: %s\n", args->label, context);
224 ast_ari_response_error(response, 404, "Not Found", "Requested label can not be found");
225 return;
226 }
227 } else {
228 ast_debug(3, "Numeric value provided for label, jumping to that priority\n");
229 }
230
231 if (ipri == 0) {
232 ast_log(AST_LOG_ERROR, "Invalid priority label '%s' specified for extension %s in context: %s\n",
233 args->label, exten, context);
234 ast_ari_response_error(response, 400, "Bad Request", "Requested priority is illegal");
235 return;
236 }
237
238 } else if (args->priority) {
239 /* No label provided, use provided priority */
240 ipri = args->priority;
241 } else if (ast_strlen_zero(args->context) && ast_strlen_zero(args->extension)) {
242 /* Special case. No exten, context, or priority provided, then move on to the next priority */
243 ipri = snapshot->dialplan->priority + 1;
244 } else {
245 ipri = 1;
246 }
247
248
249 if (stasis_app_control_continue(control, context, exten, ipri)) {
251 return;
252 }
253
255}
256
259 struct ast_ari_response *response)
260{
261 RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
262
263 control = find_control(response, args->channel_id);
264 if (!control) {
265 return;
266 }
267
268 if (stasis_app_control_move(control, args->app, args->app_args)) {
269 ast_ari_response_error(response, 500, "Internal Server Error",
270 "Failed to switch Stasis applications");
271 return;
272 }
273
275}
276
279 struct ast_ari_response *response)
280{
281 RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
282 RAII_VAR(struct ast_channel_snapshot *, chan_snapshot, NULL, ao2_cleanup);
283 char *tech;
284 char *resource;
285 int tech_len;
286
287 control = find_control(response, args->channel_id);
288 if (!control) {
289 return;
290 }
291
292 if (channel_state_invalid(control, response)) {
293 return;
294 }
295
296 if (ast_strlen_zero(args->endpoint)) {
297 ast_ari_response_error(response, 400, "Not Found",
298 "Required parameter 'endpoint' not provided.");
299 return;
300 }
301
302 tech = ast_strdupa(args->endpoint);
303 if (!(resource = strchr(tech, '/')) || !(tech_len = resource - tech)) {
304 ast_ari_response_error(response, 422, "Unprocessable Entity",
305 "Endpoint parameter '%s' does not contain tech/resource", args->endpoint);
306 return;
307 }
308
309 *resource++ = '\0';
310 if (ast_strlen_zero(resource)) {
311 ast_ari_response_error(response, 422, "Unprocessable Entity",
312 "No resource provided in endpoint parameter '%s'", args->endpoint);
313 return;
314 }
315
316 chan_snapshot = ast_channel_snapshot_get_latest(args->channel_id);
317 if (!chan_snapshot) {
318 ast_ari_response_error(response, 500, "Internal Server Error",
319 "Unable to find channel snapshot for '%s'", args->channel_id);
320 return;
321 }
322
323 if (strncasecmp(chan_snapshot->base->type, tech, tech_len)) {
324 ast_ari_response_error(response, 422, "Unprocessable Entity",
325 "Endpoint technology '%s' does not match channel technology '%s'",
326 tech, chan_snapshot->base->type);
327 return;
328 }
329
330 if (stasis_app_control_redirect(control, resource)) {
331 ast_ari_response_error(response, 500, "Internal Server Error",
332 "Failed to redirect channel");
333 return;
334 }
335
337}
338
341 struct ast_ari_response *response)
342{
343 RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
344
345 control = find_control(response, args->channel_id);
346 if (control == NULL) {
347 return;
348 }
349
350 if (channel_state_invalid(control, response)) {
351 return;
352 }
353
354 if (stasis_app_control_answer(control) != 0) {
356 response, 500, "Internal Server Error",
357 "Failed to answer channel");
358 return;
359 }
360
362}
363
366 struct ast_ari_response *response)
367{
368 RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
369
370 control = find_control(response, args->channel_id);
371 if (control == NULL) {
372 return;
373 }
374
375 if (channel_state_invalid(control, response)) {
376 return;
377 }
378
380
382}
383
386 struct ast_ari_response *response)
387{
388 RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
389
390 control = find_control(response, args->channel_id);
391 if (control == NULL) {
392 return;
393 }
394
395 if (channel_state_invalid(control, response)) {
396 return;
397 }
398
400
402}
403
406 struct ast_ari_response *response)
407{
408 RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
409
410 control = find_control(response, args->channel_id);
411 if (control == NULL) {
412 return;
413 }
414
415 if (channel_state_invalid(control, response)) {
416 return;
417 }
418
420
422}
423
426 struct ast_ari_response *response)
427{
428 RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
429 unsigned int direction = 0;
430 enum ast_frame_type frametype = AST_FRAME_VOICE;
431
432 control = find_control(response, args->channel_id);
433 if (control == NULL) {
434 return;
435 }
436
437 if (channel_state_invalid(control, response)) {
438 return;
439 }
440
441 if (ast_strlen_zero(args->direction)) {
443 response, 400, "Bad Request",
444 "Direction is required");
445 return;
446 }
447
448 if (!strcmp(args->direction, "in")) {
450 } else if (!strcmp(args->direction, "out")) {
452 } else if (!strcmp(args->direction, "both")) {
454 } else {
456 response, 400, "Bad Request",
457 "Invalid direction specified");
458 return;
459 }
460
461 stasis_app_control_mute(control, direction, frametype);
462
464}
465
468 struct ast_ari_response *response)
469{
470 RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
471 unsigned int direction = 0;
472 enum ast_frame_type frametype = AST_FRAME_VOICE;
473
474 control = find_control(response, args->channel_id);
475 if (control == NULL) {
476 return;
477 }
478
479 if (channel_state_invalid(control, response)) {
480 return;
481 }
482
483 if (ast_strlen_zero(args->direction)) {
485 response, 400, "Bad Request",
486 "Direction is required");
487 return;
488 }
489
490 if (!strcmp(args->direction, "in")) {
492 } else if (!strcmp(args->direction, "out")) {
494 } else if (!strcmp(args->direction, "both")) {
496 } else {
498 response, 400, "Bad Request",
499 "Invalid direction specified");
500 return;
501 }
502
503 stasis_app_control_unmute(control, direction, frametype);
504
506}
507
510 struct ast_ari_response *response)
511{
512 RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
513
514 control = find_control(response, args->channel_id);
515 if (control == NULL) {
516 return;
517 }
518
519 if (channel_state_invalid(control, response)) {
520 return;
521 }
522
523 if (ast_strlen_zero(args->dtmf)) {
525 response, 400, "Bad Request",
526 "DTMF is required");
527 return;
528 }
529
530 stasis_app_control_dtmf(control, args->dtmf, args->before, args->between, args->duration, args->after);
531
533}
534
537 struct ast_ari_response *response)
538{
539 RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
540
541 control = find_control(response, args->channel_id);
542 if (control == NULL) {
543 /* Response filled in by find_control */
544 return;
545 }
546
547 if (channel_state_invalid(control, response)) {
548 return;
549 }
550
552
554}
555
558 struct ast_ari_response *response)
559{
560 RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
561
562 control = find_control(response, args->channel_id);
563 if (control == NULL) {
564 /* Response filled in by find_control */
565 return;
566 }
567
568 if (channel_state_invalid(control, response)) {
569 return;
570 }
571
573
575}
576
579 struct ast_ari_response *response)
580{
581 RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
582
583 control = find_control(response, args->channel_id);
584 if (control == NULL) {
585 /* Response filled in by find_control */
586 return;
587 }
588
589 if (channel_state_invalid(control, response)) {
590 return;
591 }
592
593 stasis_app_control_moh_start(control, args->moh_class);
595}
596
599 struct ast_ari_response *response)
600{
601 RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
602
603 control = find_control(response, args->channel_id);
604 if (control == NULL) {
605 /* Response filled in by find_control */
606 return;
607 }
608
609 if (channel_state_invalid(control, response)) {
610 return;
611 }
612
615}
616
619 struct ast_ari_response *response)
620{
621 RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
622
623 control = find_control(response, args->channel_id);
624 if (control == NULL) {
625 /* Response filled in by find_control */
626 return;
627 }
628
629 if (channel_state_invalid(control, response)) {
630 return;
631 }
632
635}
636
639 struct ast_ari_response *response)
640{
641 RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
642
643 control = find_control(response, args->channel_id);
644 if (control == NULL) {
645 /* Response filled in by find_control */
646 return;
647 }
648
649 if (channel_state_invalid(control, response)) {
650 return;
651 }
652
655}
656
658 const char *args_channel_id,
659 const char **args_media,
660 size_t args_media_count,
661 const char *args_lang,
662 int args_offsetms,
663 int args_skipms,
664 const char *args_playback_id,
665 struct ast_ari_response *response)
666{
667 RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
668 RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
669 RAII_VAR(struct stasis_app_playback *, playback, NULL, ao2_cleanup);
670 RAII_VAR(char *, playback_url, NULL, ast_free);
671 struct ast_json *json;
672 const char *language;
673
674 ast_assert(response != NULL);
675
676 control = find_control(response, args_channel_id);
677 if (control == NULL) {
678 /* Response filled in by find_control */
679 return;
680 }
681
682 if (channel_state_invalid(control, response)) {
683 return;
684 }
685
686 snapshot = stasis_app_control_get_snapshot(control);
687 if (!snapshot) {
689 response, 404, "Not Found",
690 "Channel not found");
691 return;
692 }
693
694 if (args_skipms < 0) {
696 response, 400, "Bad Request",
697 "skipms cannot be negative");
698 return;
699 }
700
701 if (args_offsetms < 0) {
703 response, 400, "Bad Request",
704 "offsetms cannot be negative");
705 return;
706 }
707
708 language = S_OR(args_lang, snapshot->base->language);
709
710 playback = stasis_app_control_play_uri(control, args_media, args_media_count, language,
711 args_channel_id, STASIS_PLAYBACK_TARGET_CHANNEL, args_skipms, args_offsetms, args_playback_id);
712 if (!playback) {
714 response, 500, "Internal Server Error",
715 "Failed to queue media for playback");
716 return;
717 }
718
719 if (ast_asprintf(&playback_url, "/playbacks/%s",
720 stasis_app_playback_get_id(playback)) == -1) {
721 playback_url = NULL;
723 response, 500, "Internal Server Error",
724 "Out of memory");
725 return;
726 }
727
728 json = stasis_app_playback_to_json(playback);
729 if (!json) {
731 response, 500, "Internal Server Error",
732 "Out of memory");
733 return;
734 }
735
736 ast_ari_response_created(response, playback_url, json);
737}
738
741 struct ast_ari_response *response)
742{
744 args->channel_id,
745 args->media,
746 args->media_count,
747 args->lang,
748 args->offsetms,
749 args->skipms,
750 args->playback_id,
751 response);
752}
753
756 struct ast_ari_response *response)
757{
759 args->channel_id,
760 args->media,
761 args->media_count,
762 args->lang,
763 args->offsetms,
764 args->skipms,
765 args->playback_id,
766 response);
767}
768
771 struct ast_ari_response *response)
772{
773 RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
774 RAII_VAR(struct stasis_app_recording *, recording, NULL, ao2_cleanup);
775 RAII_VAR(char *, recording_url, NULL, ast_free);
776 struct ast_json *json;
779 RAII_VAR(char *, uri_encoded_name, NULL, ast_free);
780 size_t uri_name_maxlen;
781
782 ast_assert(response != NULL);
783
784 if (args->max_duration_seconds < 0) {
786 response, 400, "Bad Request",
787 "max_duration_seconds cannot be negative");
788 return;
789 }
790
791 if (args->max_silence_seconds < 0) {
793 response, 400, "Bad Request",
794 "max_silence_seconds cannot be negative");
795 return;
796 }
797
798 control = find_control(response, args->channel_id);
799 if (control == NULL) {
800 /* Response filled in by find_control */
801 return;
802 }
803
805 if (options == NULL) {
807 response, 500, "Internal Server Error",
808 "Out of memory");
809 }
810 ast_string_field_build(options, target, "channel:%s", args->channel_id);
811 options->max_silence_seconds = args->max_silence_seconds;
812 options->max_duration_seconds = args->max_duration_seconds;
813 options->terminate_on =
815 options->if_exists =
817 options->beep = args->beep;
818
819 if (options->terminate_on == STASIS_APP_RECORDING_TERMINATE_INVALID) {
821 response, 400, "Bad Request",
822 "terminateOn invalid");
823 return;
824 }
825
826 if (options->if_exists == AST_RECORD_IF_EXISTS_ERROR) {
828 response, 400, "Bad Request",
829 "ifExists invalid");
830 return;
831 }
832
833 if (!ast_get_format_for_file_ext(options->format)) {
835 response, 422, "Unprocessable Entity",
836 "specified format is unknown on this system");
837 return;
838 }
839
840 recording = stasis_app_control_record(control, options);
841 if (recording == NULL) {
842 switch(errno) {
843 case EINVAL:
844 /* While the arguments are invalid, we should have
845 * caught them prior to calling record.
846 */
848 response, 500, "Internal Server Error",
849 "Error parsing request");
850 break;
851 case EEXIST:
852 ast_ari_response_error(response, 409, "Conflict",
853 "Recording '%s' already exists and can not be overwritten",
854 args->name);
855 break;
856 case ENOMEM:
858 response, 500, "Internal Server Error",
859 "Out of memory");
860 break;
861 case EPERM:
863 response, 400, "Bad Request",
864 "Recording name invalid");
865 break;
866 default:
868 "Unrecognized recording error: %s\n",
869 strerror(errno));
871 response, 500, "Internal Server Error",
872 "Internal Server Error");
873 break;
874 }
875 return;
876 }
877
878 uri_name_maxlen = strlen(args->name) * 3;
879 uri_encoded_name = ast_malloc(uri_name_maxlen);
880 if (!uri_encoded_name) {
882 response, 500, "Internal Server Error",
883 "Out of memory");
884 return;
885 }
886 ast_uri_encode(args->name, uri_encoded_name, uri_name_maxlen,
888
889 if (ast_asprintf(&recording_url, "/recordings/live/%s",
890 uri_encoded_name) == -1) {
891 recording_url = NULL;
893 response, 500, "Internal Server Error",
894 "Out of memory");
895 return;
896 }
897
898 json = stasis_app_recording_to_json(recording);
899 if (!json) {
901 response, 500, "Internal Server Error",
902 "Out of memory");
903 return;
904 }
905
906 ast_ari_response_created(response, recording_url, json);
907}
908
911 struct ast_ari_response *response)
912{
913 struct ast_channel_snapshot *snapshot;
914
915 snapshot = ast_channel_snapshot_get_latest(args->channel_id);
916 if (!snapshot) {
918 response, 404, "Not Found",
919 "Channel not found");
920 return;
921 }
922
923 ast_ari_response_ok(response,
925 ao2_ref(snapshot, -1);
926}
927
930 struct ast_ari_response *response)
931{
932 RAII_VAR(struct ast_channel *, chan, NULL, ao2_cleanup);
933 int cause;
934 struct ast_rtp_glue *glue;
935 struct ast_rtp_instance *rtp = NULL;
936 const struct ast_channel_tech *tech;
937
938 chan = ast_channel_get_by_name(args->channel_id);
939 if (chan == NULL) {
941 response, 404, "Not Found",
942 "Channel not found");
943 return;
944 }
945
946 if (!ast_strlen_zero(args->reason) && !ast_strlen_zero(args->reason_code)) {
947 ast_ari_response_error(response, 400, "Bad Request",
948 "The reason and reason_code can't both be specified");
949 return;
950 }
951
952 if (!ast_strlen_zero(args->reason_code)) {
953 /* reason_code allows any hangup code */
954 if (sscanf(args->reason_code, "%30d", &cause) != 1) {
956 response, 400, "Invalid Reason Code",
957 "Invalid reason for hangup reason code provided");
958 return;
959 }
960 } else if (!ast_strlen_zero(args->reason)) {
961 /* reason allows only listed hangup reason */
962 cause = convert_reason_to_hangup_code(args->reason);
963 if (cause == -1) {
965 response, 400, "Invalid Reason",
966 "Invalid reason for hangup reason provided");
967 return;
968 }
969 } else {
970 /* not specified. set default hangup */
971 cause = AST_CAUSE_NORMAL;
972 }
973
974 ast_channel_hangupcause_set(chan, cause);
975
976 /*
977 * Only hold the channel lock long enough to get the rtp instance.
978 * glue->get_rtp_info() will bump the refcount on it.
979 */
980 ast_channel_lock(chan);
981 tech = ast_channel_tech(chan);
982 glue = ast_rtp_instance_get_glue(tech->type);
983 if (glue) {
984 glue->get_rtp_info(chan, &rtp);
985 }
986 ast_channel_unlock(chan);
987 /*
988 * If this channel is in a bridge, ast_rtp_instance_set_stats_vars() will
989 * attempt to lock the bridge peer as well as this channel. This can cause
990 * a lock inversion if we already have this channel locked and another
991 * thread tries to set bridge variables on the peer because it will have
992 * locked the peer first, then this channel. For this reason, we must
993 * NOT have the channel locked when we call ast_rtp_instance_set_stats_vars().
994 * This should be safe since glue->get_rtp_info() will have bumped the
995 * refcount on the rtp instance so it can't go away while the channel
996 * is unlocked.
997 */
998 if (rtp) {
1000 ao2_ref(rtp, -1);
1001 }
1002
1004
1006}
1007
1010 struct ast_ari_response *response)
1011{
1012 RAII_VAR(struct ao2_container *, snapshots, NULL, ao2_cleanup);
1013 RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
1014 struct ao2_iterator i;
1015 void *obj;
1017
1018 snapshots = ast_channel_cache_all();
1019
1020 json = ast_json_array_create();
1021 if (!json) {
1023 return;
1024 }
1025
1026 i = ao2_iterator_init(snapshots, 0);
1027 while ((obj = ao2_iterator_next(&i))) {
1028 struct ast_channel_snapshot *snapshot = obj;
1029 int r;
1030
1031 if (sanitize && sanitize->channel_snapshot
1032 && sanitize->channel_snapshot(snapshot)) {
1033 ao2_ref(snapshot, -1);
1034 continue;
1035 }
1036
1038 json, ast_channel_snapshot_to_json(snapshot, NULL));
1039 if (r != 0) {
1042 ao2_ref(snapshot, -1);
1043 return;
1044 }
1045 ao2_ref(snapshot, -1);
1046 }
1048
1049 ast_ari_response_ok(response, ast_json_ref(json));
1050}
1051
1052/*! \brief Structure used for origination */
1054 /*! \brief Dialplan context */
1056 /*! \brief Dialplan extension */
1058 /*! \brief Dialplan priority */
1060 /*! \brief Application data to pass to Stasis application */
1061 char appdata[0];
1062};
1063
1064/*! \brief Thread which dials and executes upon answer */
1065static void *ari_originate_dial(void *data)
1066{
1067 struct ast_dial *dial = data;
1068 struct ari_origination *origination = ast_dial_get_user_data(dial);
1069 enum ast_dial_result res;
1070
1071 res = ast_dial_run(dial, NULL, 0);
1072 if (res != AST_DIAL_RESULT_ANSWERED) {
1073 goto end;
1074 }
1075
1076 if (!ast_strlen_zero(origination->appdata)) {
1077 struct ast_app *app = pbx_findapp("Stasis");
1078
1079 if (app) {
1080 ast_verb(4, "Launching Stasis(%s) on %s\n", origination->appdata,
1082 pbx_exec(ast_dial_answered(dial), app, origination->appdata);
1083 } else {
1084 ast_log(LOG_WARNING, "No such application 'Stasis'\n");
1085 }
1086 } else {
1087 struct ast_channel *answered = ast_dial_answered(dial);
1088
1089 if (!ast_strlen_zero(origination->context)) {
1090 ast_channel_context_set(answered, origination->context);
1091 }
1092
1093 if (!ast_strlen_zero(origination->exten)) {
1094 ast_channel_exten_set(answered, origination->exten);
1095 }
1096
1097 if (origination->priority > 0) {
1098 ast_channel_priority_set(answered, origination->priority);
1099 }
1100
1101 if (ast_pbx_run(answered)) {
1102 ast_log(LOG_ERROR, "Failed to start PBX on %s\n", ast_channel_name(answered));
1103 } else {
1104 /* PBX will have taken care of hanging up, so we steal the answered channel so dial doesn't do it */
1106 }
1107 }
1108
1109end:
1110 ast_dial_destroy(dial);
1111 ast_free(origination);
1112 return NULL;
1113}
1114
1115static struct ast_channel *ari_channels_handle_originate_with_id(const char *args_endpoint,
1116 const char *args_extension,
1117 const char *args_context,
1118 long args_priority,
1119 const char *args_label,
1120 const char *args_app,
1121 const char *args_app_args,
1122 const char *args_caller_id,
1123 int args_timeout,
1124 struct ast_variable *variables,
1125 struct ast_variable *report_event_variables,
1126 const char *args_channel_id,
1127 const char *args_other_channel_id,
1128 const char *args_originator,
1129 const char *args_formats,
1130 struct ast_ari_response *response)
1131{
1132 char *dialtech;
1133 char *dialdevice = NULL;
1134 struct ast_dial *dial;
1135 char *caller_id = NULL;
1136 char *cid_num = NULL;
1137 char *cid_name = NULL;
1138 char *stuff;
1139 struct ast_channel *other = NULL;
1140 struct ast_channel *chan = NULL;
1142 struct ast_assigned_ids assignedids = {
1143 .uniqueid = args_channel_id,
1144 .uniqueid2 = args_other_channel_id,
1145 };
1146 struct ari_origination *origination;
1147 pthread_t thread;
1148 struct ast_format_cap *format_cap = NULL;
1149
1150 if ((assignedids.uniqueid && AST_MAX_PUBLIC_UNIQUEID < strlen(assignedids.uniqueid))
1151 || (assignedids.uniqueid2 && AST_MAX_PUBLIC_UNIQUEID < strlen(assignedids.uniqueid2))) {
1152 ast_ari_response_error(response, 400, "Bad Request",
1153 "Uniqueid length exceeds maximum of %d", AST_MAX_PUBLIC_UNIQUEID);
1154 return NULL;
1155 }
1156
1157 if (ast_strlen_zero(args_endpoint)) {
1158 ast_ari_response_error(response, 400, "Bad Request",
1159 "Endpoint must be specified");
1160 return NULL;
1161 }
1162
1163 if (!ast_strlen_zero(args_originator) && !ast_strlen_zero(args_formats)) {
1164 ast_ari_response_error(response, 400, "Bad Request",
1165 "Originator and formats can't both be specified");
1166 return NULL;
1167 }
1168
1169 dialtech = ast_strdupa(args_endpoint);
1170 if ((stuff = strchr(dialtech, '/'))) {
1171 *stuff++ = '\0';
1172 dialdevice = stuff;
1173 }
1174
1175 if (ast_strlen_zero(dialtech) || ast_strlen_zero(dialdevice)) {
1176 ast_ari_response_error(response, 400, "Bad Request",
1177 "Invalid endpoint specified");
1178 return NULL;
1179 }
1180
1181 if (!ast_strlen_zero(args_app)) {
1182 RAII_VAR(struct ast_str *, appdata, ast_str_create(64), ast_free);
1183
1184 if (!appdata) {
1186 return NULL;
1187 }
1188
1189 ast_str_set(&appdata, 0, "%s", args_app);
1190 if (!ast_strlen_zero(args_app_args)) {
1191 ast_str_append(&appdata, 0, ",%s", args_app_args);
1192 }
1193
1194 origination = ast_calloc(1, sizeof(*origination) + ast_str_size(appdata) + 1);
1195 if (!origination) {
1197 return NULL;
1198 }
1199
1200 strcpy(origination->appdata, ast_str_buffer(appdata));
1201 } else if (!ast_strlen_zero(args_extension)) {
1202 origination = ast_calloc(1, sizeof(*origination) + 1);
1203 if (!origination) {
1205 return NULL;
1206 }
1207
1208 ast_copy_string(origination->context, S_OR(args_context, "default"), sizeof(origination->context));
1209 ast_copy_string(origination->exten, args_extension, sizeof(origination->exten));
1210
1211 if (!ast_strlen_zero(args_label)) {
1212 /* A label was provided in the request, use that */
1213 int ipri = 1;
1214 if (sscanf(args_label, "%30d", &ipri) != 1) {
1215 ipri = ast_findlabel_extension(chan, origination->context, origination->exten, args_label, args_caller_id);
1216
1217 if (ipri == -1) {
1218 ast_log(AST_LOG_ERROR, "Requested label: %s can not be found in context: %s\n", args_label, args_context);
1219 ast_ari_response_error(response, 404, "Not Found", "Requested label can not be found");
1220 return NULL;
1221 }
1222 } else {
1223 ast_debug(3, "Numeric value provided for label, jumping to that priority\n");
1224 }
1225
1226 if (ipri == 0) {
1227 ast_log(AST_LOG_ERROR, "Invalid priority label '%s' specified for extension %s in context: %s\n",
1228 args_label, args_extension, args_context);
1229 ast_ari_response_error(response, 400, "Bad Request", "Requested priority is illegal");
1230 return NULL;
1231 }
1232
1233 /* Our priority was provided by a label */
1234 origination->priority = ipri;
1235 } else {
1236 /* No label provided, use provided priority */
1237 origination->priority = args_priority ? args_priority : 1;
1238 }
1239
1240 origination->appdata[0] = '\0';
1241 } else {
1242 ast_ari_response_error(response, 400, "Bad Request",
1243 "Application or extension must be specified");
1244 return NULL;
1245 }
1246
1247 dial = ast_dial_create();
1248 if (!dial) {
1250 ast_free(origination);
1251 return NULL;
1252 }
1253 ast_dial_set_user_data(dial, origination);
1254
1255 if (ast_dial_append(dial, dialtech, dialdevice, &assignedids)) {
1257 ast_dial_destroy(dial);
1258 ast_free(origination);
1259 return NULL;
1260 }
1261
1262 if (args_timeout > 0) {
1263 ast_dial_set_global_timeout(dial, args_timeout * 1000);
1264 } else if (args_timeout == -1) {
1266 } else {
1267 ast_dial_set_global_timeout(dial, 30000);
1268 }
1269
1270 if (!ast_strlen_zero(args_caller_id)) {
1271 caller_id = ast_strdupa(args_caller_id);
1272 ast_callerid_parse(caller_id, &cid_name, &cid_num);
1273
1274 if (ast_is_shrinkable_phonenumber(cid_num)) {
1275 ast_shrink_phone_number(cid_num);
1276 }
1277 }
1278
1279 if (!ast_strlen_zero(args_originator)) {
1280 other = ast_channel_get_by_name(args_originator);
1281 if (!other) {
1283 response, 400, "Bad Request",
1284 "Provided originator channel was not found");
1285 ast_dial_destroy(dial);
1286 ast_free(origination);
1287 return NULL;
1288 }
1289 }
1290
1291 if (!ast_strlen_zero(args_formats)) {
1292 char *format_name;
1293 char *formats_copy = ast_strdupa(args_formats);
1294
1297 ast_dial_destroy(dial);
1298 ast_free(origination);
1299 ast_channel_cleanup(other);
1300 return NULL;
1301 }
1302
1303 while ((format_name = ast_strip(strsep(&formats_copy, ",")))) {
1304 struct ast_format *fmt = ast_format_cache_get(format_name);
1305
1306 if (!fmt || ast_format_cap_append(format_cap, fmt, 0)) {
1307 if (!fmt) {
1309 response, 400, "Bad Request",
1310 "Provided format (%s) was not found", format_name);
1311 } else {
1313 }
1314 ast_dial_destroy(dial);
1315 ast_free(origination);
1316 ast_channel_cleanup(other);
1317 ao2_ref(format_cap, -1);
1318 ao2_cleanup(fmt);
1319 return NULL;
1320 }
1321 ao2_ref(fmt, -1);
1322 }
1323 }
1324
1325 if (ast_dial_prerun(dial, other, format_cap)) {
1327 ast_ari_response_error(response, 409, "Conflict",
1328 "Channel with given unique ID already exists");
1329 } else {
1331 }
1332 ast_dial_destroy(dial);
1333 ast_free(origination);
1334 ast_channel_cleanup(other);
1335 return NULL;
1336 }
1337
1338 ast_channel_cleanup(other);
1339 ao2_cleanup(format_cap);
1340
1341 chan = ast_dial_get_channel(dial, 0);
1342 if (!chan) {
1344 ast_dial_destroy(dial);
1345 ast_free(origination);
1346 return NULL;
1347 }
1348
1349 if (!ast_strlen_zero(cid_num) || !ast_strlen_zero(cid_name)) {
1351
1352 /*
1353 * It seems strange to set the CallerID on an outgoing call leg
1354 * to whom we are calling, but this function's callers are doing
1355 * various Originate methods. This call leg goes to the local
1356 * user. Once the called party answers, the dialplan needs to
1357 * be able to access the CallerID from the CALLERID function as
1358 * if the called party had placed this call.
1359 */
1360 ast_set_callerid(chan, cid_num, cid_name, cid_num);
1361
1363 if (!ast_strlen_zero(cid_num)) {
1364 connected.id.number.valid = 1;
1365 connected.id.number.str = (char *) cid_num;
1367 }
1368 if (!ast_strlen_zero(cid_name)) {
1369 connected.id.name.valid = 1;
1370 connected.id.name.str = (char *) cid_name;
1372 }
1374 }
1375
1376 if (variables) {
1377 ast_set_variables(chan, variables);
1378 }
1380
1381 if (!ast_strlen_zero(args_app)) {
1382 struct ast_channel *local_peer;
1383
1384 stasis_app_subscribe_channel(args_app, chan);
1385
1386 /* Subscribe to the Local channel peer also. */
1387 local_peer = ast_local_get_peer(chan);
1388 if (local_peer) {
1389 stasis_app_subscribe_channel(args_app, local_peer);
1390 ast_channel_unref(local_peer);
1391 }
1392 }
1393
1394 if (report_event_variables) {
1395 struct ast_variable *var;
1396
1397 for (var = report_event_variables; var; var = var->next) {
1398 if (ast_channel_set_ari_var_reportable(chan, var->name, 1)) {
1400 ast_dial_destroy(dial);
1401 ast_free(origination);
1402 return NULL;
1403 }
1404 }
1405 }
1407
1408 /* Before starting the async dial bump the ref in case the dial quickly goes away and takes
1409 * the reference with it
1410 */
1411 ast_channel_ref(chan);
1412
1415 ast_dial_destroy(dial);
1416 ast_free(origination);
1417 } else {
1419 }
1420
1421 return chan;
1422}
1423
1424/*!
1425 * \internal
1426 * \brief Convert a \c ast_json list of key/value pair tuples into a \c ast_variable list
1427 * \since 13.3.0
1428 *
1429 * \param[out] response HTTP response if error
1430 * \param json_variables The JSON blob containing the variable
1431 * \param[out] variables An out reference to the variables to populate.
1432 *
1433 * \retval 0 on success.
1434 * \retval -1 on error.
1435 */
1436static int json_to_ast_variables(struct ast_ari_response *response, struct ast_json *json_variables,
1437 struct ast_variable **variables, struct ast_variable **report_event_variables)
1438{
1439 struct ast_json_iter *it_json_var;
1440 struct ast_variable *var_tail = NULL;
1441 struct ast_variable *report_var_tail = NULL;
1442
1443 *variables = NULL;
1444 *report_event_variables = NULL;
1445
1446 for (it_json_var = ast_json_object_iter(json_variables); it_json_var;
1447 it_json_var = ast_json_object_iter_next(json_variables, it_json_var)) {
1448 struct ast_variable *new_var;
1449 const char *key = ast_json_object_iter_key(it_json_var);
1450 const char *value = NULL;
1451 struct ast_json *json_value = ast_json_object_iter_value(it_json_var);
1452 int report_events = 0;
1453
1454 if (ast_strlen_zero(key)) {
1455 continue;
1456 }
1457
1458 if (ast_json_typeof(json_value) == AST_JSON_STRING) {
1459 value = ast_json_string_get(json_value);
1460 } else if (ast_json_typeof(json_value) == AST_JSON_OBJECT) {
1461 struct ast_json *value_field = ast_json_object_get(json_value, "value");
1462 struct ast_json *report_field = ast_json_object_get(json_value, "report_events");
1463 ast_log(LOG_DEBUG, "Processing variable '%s' with report_events: %s\n", key,
1464 report_field ? (ast_json_is_true(report_field) ? "true" : "false") : "not set");
1465
1466 if (!value_field || ast_json_typeof(value_field) != AST_JSON_STRING) {
1467 ast_ari_response_error(response, 400, "Bad Request",
1468 "Each object value in 'variables' must include string field 'value'");
1469 goto error;
1470 }
1471
1472 value = ast_json_string_get(value_field);
1473 ast_log(LOG_DEBUG, "Variable '%s' has value '%s'\n", key, value);
1474
1475 if (report_field) {
1476 enum ast_json_type report_type = ast_json_typeof(report_field);
1477
1478 if (report_type != AST_JSON_TRUE && report_type != AST_JSON_FALSE) {
1479 ast_ari_response_error(response, 400, "Bad Request",
1480 "Field 'report_events' in 'variables' entries must be boolean");
1481 goto error;
1482 }
1483
1484 report_events = ast_json_is_true(report_field);
1485 }
1486 } else {
1487 ast_ari_response_error(response, 400, "Bad Request",
1488 "Each value in 'variables' must be a string or an object with 'value' and optional 'report_events'");
1489 goto error;
1490 }
1491
1492 if (!value) {
1493 continue;
1494 }
1495
1496 new_var = ast_variable_new(key, value, "");
1497 if (!new_var) {
1499 goto error;
1500 }
1501
1502 var_tail = ast_variable_list_append_hint(variables, var_tail, new_var);
1503
1504 if (report_events) {
1505 struct ast_variable *report_var = ast_variable_new(key, "1", "");
1506
1507 if (!report_var) {
1509 goto error;
1510 }
1511
1512 report_var_tail = ast_variable_list_append_hint(report_event_variables,
1513 report_var_tail, report_var);
1514 }
1515 }
1516
1517 return 0;
1518
1519error:
1520 ast_variables_destroy(*variables);
1521 *variables = NULL;
1522 ast_variables_destroy(*report_event_variables);
1523 *report_event_variables = NULL;
1524 return -1;
1525}
1526
1529 struct ast_ari_response *response)
1530{
1531 struct ast_variable *variables = NULL;
1532 struct ast_variable *report_event_variables = NULL;
1533 struct ast_channel *chan;
1534
1535 /* Parse any query parameters out of the body parameter */
1536 if (args->variables) {
1537 struct ast_json *json_variables;
1538
1540 json_variables = ast_json_object_get(args->variables, "variables");
1541 if (json_variables
1542 && json_to_ast_variables(response, json_variables, &variables,
1543 &report_event_variables)) {
1544 return;
1545 }
1546 }
1547
1549 args->endpoint,
1550 args->extension,
1551 args->context,
1552 args->priority,
1553 args->label,
1554 args->app,
1555 args->app_args,
1556 args->caller_id,
1557 args->timeout,
1558 variables,
1559 report_event_variables,
1560 args->channel_id,
1561 args->other_channel_id,
1562 args->originator,
1563 args->formats,
1564 response);
1565 ast_channel_cleanup(chan);
1566 ast_variables_destroy(report_event_variables);
1567 ast_variables_destroy(variables);
1568}
1569
1572 struct ast_ari_response *response)
1573{
1574 struct ast_variable *variables = NULL;
1575 struct ast_variable *report_event_variables = NULL;
1576 struct ast_channel *chan;
1577
1578 /* Parse any query parameters out of the body parameter */
1579 if (args->variables) {
1580 struct ast_json *json_variables;
1581
1583 json_variables = ast_json_object_get(args->variables, "variables");
1584 if (json_variables
1585 && json_to_ast_variables(response, json_variables, &variables,
1586 &report_event_variables)) {
1587 return;
1588 }
1589 }
1590
1592 args->endpoint,
1593 args->extension,
1594 args->context,
1595 args->priority,
1596 args->label,
1597 args->app,
1598 args->app_args,
1599 args->caller_id,
1600 args->timeout,
1601 variables,
1602 report_event_variables,
1603 args->channel_id,
1604 args->other_channel_id,
1605 args->originator,
1606 args->formats,
1607 response);
1608 ast_channel_cleanup(chan);
1609 ast_variables_destroy(report_event_variables);
1610 ast_variables_destroy(variables);
1611}
1612
1615 struct ast_ari_response *response)
1616{
1617 RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
1618 RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
1619 RAII_VAR(struct ast_str *, value, ast_str_create(32), ast_free);
1620 RAII_VAR(struct ast_channel *, channel, NULL, ast_channel_cleanup);
1621
1622 ast_assert(response != NULL);
1623
1624 if (!value) {
1626 return;
1627 }
1628
1629 if (ast_strlen_zero(args->variable)) {
1631 response, 400, "Bad Request",
1632 "Variable name is required");
1633 return;
1634 }
1635
1636 if (ast_strlen_zero(args->channel_id)) {
1638 response, 400, "Bad Request",
1639 "Channel ID is required");
1640 return;
1641 }
1642
1643 channel = ast_channel_get_by_name(args->channel_id);
1644 if (!channel) {
1646 response, 404, "Channel Not Found",
1647 "Provided channel was not found");
1648 return;
1649 }
1650
1651 /* You may be tempted to lock the channel you're about to read from. You
1652 * would be wrong. Some dialplan functions put the channel into
1653 * autoservice, which deadlocks if the channel is already locked.
1654 * ast_str_retrieve_variable() does its own locking, and the dialplan
1655 * functions need to as well. We should be fine without the lock.
1656 */
1657
1658 if (args->variable[strlen(args->variable) - 1] == ')') {
1659 if (ast_func_read2(channel, args->variable, &value, 0)) {
1661 response, 500, "Error With Function",
1662 "Unable to read provided function");
1663 return;
1664 }
1665 } else {
1666 if (!ast_str_retrieve_variable(&value, 0, channel, NULL, args->variable)) {
1668 response, 404, "Variable Not Found",
1669 "Provided variable was not found");
1670 return;
1671 }
1672 }
1673
1674 if (!(json = ast_json_pack("{s: s}", "value", S_OR(ast_str_buffer(value), "")))) {
1676 return;
1677 }
1678
1679 ast_ari_response_ok(response, ast_json_ref(json));
1680}
1681
1684 struct ast_ari_response *response)
1685{
1686 int res;
1688 RAII_VAR(struct ast_json *, inner_json, ast_json_object_create(), ast_json_unref);
1689 RAII_VAR(struct ast_str *, value, ast_str_create(32), ast_free);
1690 RAII_VAR(struct ast_channel *, channel, NULL, ast_channel_cleanup);
1691
1692 ast_assert(response != NULL);
1693
1694 if (!json || !inner_json || !value) {
1696 return;
1697 }
1698
1699 if (args->variables_count == 0) {
1701 response, 400, "Bad Request",
1702 "At least one variable name is required");
1703 return;
1704 }
1705
1706 if (ast_strlen_zero(args->channel_id)) {
1708 response, 400, "Bad Request",
1709 "Channel ID is required");
1710 return;
1711 }
1712
1713 channel = ast_channel_get_by_name(args->channel_id);
1714 if (!channel) {
1716 response, 404, "Channel Not Found",
1717 "Provided channel was not found");
1718 return;
1719 }
1720
1721 for (int i = 0; i < args->variables_count; i++) {
1722 struct ast_json *json_str;
1723 char buf[strlen(args->variables[i]) + 1];
1724 char *variable;
1725
1726 strcpy(buf, args->variables[i]);
1727 variable = ast_strip(buf);
1728 if (ast_strlen_zero(variable)) {
1730 response, 400, "Bad Request",
1731 "Variable names are required");
1732 return;
1733 }
1734
1735 if (variable[strlen(variable) - 1] == ')') {
1736 if (ast_func_read2(channel, variable, &value, 0)) {
1738 response, 500, "Error With Function",
1739 "Unable to read provided function");
1740 return;
1741 }
1742 } else {
1743 if (!ast_str_retrieve_variable(&value, 0, channel, NULL, variable)) {
1745 response, 404, "Variable Not Found",
1746 "Provided variable was not found");
1747 return;
1748 }
1749 }
1750
1752 if (!json_str) {
1754 return;
1755 }
1756
1757 res = ast_json_object_set(inner_json, variable, json_str);
1758 if (res) {
1760 ast_json_unref(json_str);
1761 return;
1762 }
1763 }
1764
1765 res = ast_json_object_set(json, "variables", ast_json_ref(inner_json));
1766 if (res) {
1768 return;
1769 }
1770
1771 ast_ari_response_ok(response, ast_json_ref(json));
1772}
1773
1776 struct ast_ari_response *response)
1777{
1778 RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
1779
1780 ast_assert(response != NULL);
1781
1782 if (ast_strlen_zero(args->variable)) {
1784 response, 400, "Bad Request",
1785 "Variable name is required");
1786 return;
1787 }
1788
1789 control = find_control(response, args->channel_id);
1790 if (control == NULL) {
1791 /* response filled in by find_control */
1792 return;
1793 }
1794
1795 if (stasis_app_control_set_channel_var_reportable(control, args->variable, args->value,
1796 args->report_events)) {
1798 response, 400, "Bad Request",
1799 "Failed to execute function");
1800 return;
1801 }
1802
1804}
1805
1808 struct ast_ari_response *response)
1809{
1810 struct ast_json *json_variables;
1811 struct ast_variable *var;
1812 RAII_VAR(struct ast_variable *, variables, NULL, ast_variables_destroy);
1813 RAII_VAR(struct ast_variable *, report_event_variables, NULL, ast_variables_destroy);
1814 RAII_VAR(struct ast_channel *, channel, NULL, ast_channel_cleanup);
1815 RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
1816
1817 ast_assert(response != NULL);
1818
1819 if (!args->variables) {
1821 response, 400, "Bad Request",
1822 "The 'variables' field is required");
1823 return;
1824 }
1825
1826 channel = ast_channel_get_by_name(args->channel_id);
1827 if (!channel) {
1829 response, 404, "Channel Not Found",
1830 "Provided channel was not found");
1831 return;
1832 }
1833
1834 control = find_control(response, args->channel_id);
1835 if (control == NULL) {
1836 /* response filled in by find_control */
1837 return;
1838 }
1839
1840 json_variables = ast_json_object_get(args->variables, "variables");
1841 if (!json_variables || ast_json_typeof(json_variables) != AST_JSON_OBJECT) {
1843 response, 400, "Bad Request",
1844 "The 'variables' field must be a JSON object");
1845 return;
1846 }
1847
1848 if (json_to_ast_variables(response, json_variables, &variables,
1849 &report_event_variables)) {
1850 return;
1851 }
1852
1853 for (var = variables; var; var = var->next) {
1854 int report_events = 0;
1855 struct ast_variable *report_var;
1856 char buf[strlen(var->name) + 1];
1857 char *variable;
1858 strcpy(buf, var->name);
1859 /* Strip whitespace from the variable name */
1860 variable = ast_strip(buf);
1861
1862 /* See if the variable is in the report event list */
1863 for (report_var = report_event_variables; report_var;
1864 report_var = report_var->next) {
1865 if (!strcmp(report_var->name, var->name)) {
1866 report_events = 1;
1867 break;
1868 }
1869 }
1870
1872 var->value, report_events)) {
1874 response, 400, "Bad Request",
1875 "Failed to execute function");
1876 return;
1877 }
1878 }
1879
1881}
1882
1884 const char *args_channel_id,
1885 const char *args_spy,
1886 const char *args_whisper,
1887 const char *args_app,
1888 const char *args_app_args,
1889 const char *args_snoop_id,
1890 struct ast_ari_response *response)
1891{
1892 enum stasis_app_snoop_direction spy, whisper;
1893 RAII_VAR(struct ast_channel *, chan, NULL, ast_channel_cleanup);
1894 RAII_VAR(struct ast_channel *, snoop, NULL, ast_channel_cleanup);
1895 RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
1896
1897 ast_assert(response != NULL);
1898
1899 if (ast_strlen_zero(args_spy) || !strcmp(args_spy, "none")) {
1901 } else if (!strcmp(args_spy, "both")) {
1903 } else if (!strcmp(args_spy, "out")) {
1905 } else if (!strcmp(args_spy, "in")) {
1907 } else {
1909 response, 400, "Bad Request",
1910 "Invalid direction specified for spy");
1911 return;
1912 }
1913
1914 if (ast_strlen_zero(args_whisper) || !strcmp(args_whisper, "none")) {
1916 } else if (!strcmp(args_whisper, "both")) {
1918 } else if (!strcmp(args_whisper, "out")) {
1920 } else if (!strcmp(args_whisper, "in")) {
1921 whisper = STASIS_SNOOP_DIRECTION_IN;
1922 } else {
1924 response, 400, "Bad Request",
1925 "Invalid direction specified for whisper");
1926 return;
1927 }
1928
1931 response, 400, "Bad Request",
1932 "Direction must be specified for at least spy or whisper");
1933 return;
1934 } else if (ast_strlen_zero(args_app)) {
1936 response, 400, "Bad Request",
1937 "Application name is required");
1938 return;
1939 }
1940
1941 chan = ast_channel_get_by_name(args_channel_id);
1942 if (chan == NULL) {
1944 response, 404, "Channel Not Found",
1945 "Provided channel was not found");
1946 return;
1947 }
1948
1949 snoop = stasis_app_control_snoop(chan, spy, whisper, args_app, args_app_args,
1950 args_snoop_id);
1951 if (snoop == NULL) {
1953 response, 500, "Internal error",
1954 "Snoop channel could not be created");
1955 return;
1956 }
1957
1960}
1961
1964 struct ast_ari_response *response)
1965{
1967 args->channel_id,
1968 args->spy,
1969 args->whisper,
1970 args->app,
1971 args->app_args,
1972 args->snoop_id,
1973 response);
1974}
1975
1978 struct ast_ari_response *response)
1979{
1981 args->channel_id,
1982 args->spy,
1983 args->whisper,
1984 args->app,
1985 args->app_args,
1986 args->snoop_id,
1987 response);
1988}
1989
1994
1995static void chan_data_destroy(struct ari_channel_thread_data *chan_data)
1996{
1997 ast_free(chan_data->stasis_stuff);
1998 ast_hangup(chan_data->chan);
1999 ast_free(chan_data);
2000}
2001
2002/*!
2003 * \brief Thread that owns stasis-created channel.
2004 *
2005 * The channel enters into a Stasis application immediately upon creation. In this
2006 * way, the channel can be manipulated by the Stasis application. Once the channel
2007 * exits the Stasis application, it is hung up.
2008 */
2009static void *ari_channel_thread(void *data)
2010{
2011 struct ari_channel_thread_data *chan_data = data;
2012 struct ast_app *stasis_app;
2013
2014 stasis_app = pbx_findapp("Stasis");
2015 if (!stasis_app) {
2016 ast_log(LOG_ERROR, "Stasis dialplan application is not registered");
2017 chan_data_destroy(chan_data);
2018 return NULL;
2019 }
2020
2021 pbx_exec(chan_data->chan, stasis_app, ast_str_buffer(chan_data->stasis_stuff));
2022
2023 chan_data_destroy(chan_data);
2024
2025 return NULL;
2026}
2027
2029 .type = "ARI Dialstring",
2030 .destroy = ast_free_ptr,
2031};
2032
2033/*!
2034 * \brief Save dialstring onto a channel datastore
2035 *
2036 * This will later be retrieved when it comes time to actually dial the channel
2037 *
2038 * \param chan The channel on which to save the dialstring
2039 * \param dialstring The dialstring to save
2040 * \retval 0 on success.
2041 * \retval -1 on error.
2042 */
2043static int save_dialstring(struct ast_channel *chan, const char *dialstring)
2044{
2045 struct ast_datastore *datastore;
2046
2048 if (!datastore) {
2049 return -1;
2050 }
2051
2052 datastore->data = ast_strdup(dialstring);
2053 if (!datastore->data) {
2054 ast_datastore_free(datastore);
2055 return -1;
2056 }
2057
2058 ast_channel_lock(chan);
2059 if (ast_channel_datastore_add(chan, datastore)) {
2060 ast_channel_unlock(chan);
2061 ast_datastore_free(datastore);
2062 return -1;
2063 }
2064 ast_channel_unlock(chan);
2065
2066 return 0;
2067}
2068
2069/*!
2070 * \brief Retrieve the dialstring from the channel datastore
2071 *
2072 * \pre chan is locked
2073 * \param chan Channel that was previously created in ARI
2074 * \retval NULL Failed to find datastore
2075 * \retval non-NULL The dialstring
2076 */
2077static char *restore_dialstring(struct ast_channel *chan)
2078{
2079 struct ast_datastore *datastore;
2080
2081 datastore = ast_channel_datastore_find(chan, &dialstring_info, NULL);
2082 if (!datastore) {
2083 return NULL;
2084 }
2085
2086 return datastore->data;
2087}
2088
2091 struct ast_ari_response *response)
2092{
2093 RAII_VAR(struct ast_variable *, variables, NULL, ast_variables_destroy);
2094 RAII_VAR(struct ast_variable *, report_event_variables, NULL, ast_variables_destroy);
2095 struct ast_assigned_ids assignedids;
2096 struct ari_channel_thread_data *chan_data;
2097 struct ast_channel_snapshot *snapshot;
2098 pthread_t thread;
2099 char *dialtech;
2100 char *dialdevice = NULL;
2101 char *stuff;
2102 int cause;
2103 struct ast_format_cap *request_cap;
2104 struct ast_channel *originator = NULL;
2105
2106 /* Parse any query parameters out of the body parameter */
2107 if (args->variables) {
2108 struct ast_json *json_variables;
2109
2111 json_variables = ast_json_object_get(args->variables, "variables");
2112 if (json_variables &&
2113 json_to_ast_variables(response, json_variables, &variables, &report_event_variables)) {
2114 ast_log(LOG_ERROR, "Failed to parse variables from request body for channel creation\n");
2115 return;
2116 }
2117 }
2118
2119 assignedids.uniqueid = args->channel_id;
2120 assignedids.uniqueid2 = args->other_channel_id;
2121
2122 if (!ast_strlen_zero(args->originator) && !ast_strlen_zero(args->formats)) {
2123 ast_ari_response_error(response, 400, "Bad Request",
2124 "Originator and formats can't both be specified");
2125 return;
2126 }
2127
2128 if (ast_strlen_zero(args->endpoint)) {
2129 ast_ari_response_error(response, 400, "Bad Request",
2130 "Endpoint must be specified");
2131 return;
2132 }
2133
2134 chan_data = ast_calloc(1, sizeof(*chan_data));
2135 if (!chan_data) {
2137 return;
2138 }
2139
2140 chan_data->stasis_stuff = ast_str_create(32);
2141 if (!chan_data->stasis_stuff) {
2143 chan_data_destroy(chan_data);
2144 return;
2145 }
2146
2147 ast_str_append(&chan_data->stasis_stuff, 0, "%s", args->app);
2148 if (!ast_strlen_zero(args->app_args)) {
2149 ast_str_append(&chan_data->stasis_stuff, 0, ",%s", args->app_args);
2150 }
2151
2152 dialtech = ast_strdupa(args->endpoint);
2153 if ((stuff = strchr(dialtech, '/'))) {
2154 *stuff++ = '\0';
2155 dialdevice = stuff;
2156 }
2157
2158 if (ast_strlen_zero(dialtech) || ast_strlen_zero(dialdevice)) {
2159 ast_ari_response_error(response, 400, "Bad Request",
2160 "Invalid endpoint specified");
2161 chan_data_destroy(chan_data);
2162 return;
2163 }
2164
2165 if (!ast_strlen_zero(args->originator)) {
2166 originator = ast_channel_get_by_name(args->originator);
2167 }
2168
2169 if (originator) {
2170 request_cap = ao2_bump(ast_channel_nativeformats(originator));
2171 if (!ast_strlen_zero(args->app)) {
2172 stasis_app_subscribe_channel(args->app, originator);
2173 }
2174 } else if (!ast_strlen_zero(args->formats)) {
2175 char *format_name;
2176 char *formats_copy = ast_strdupa(args->formats);
2177
2178 if (!(request_cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
2180 chan_data_destroy(chan_data);
2181 return;
2182 }
2183
2184 while ((format_name = ast_strip(strsep(&formats_copy, ",")))) {
2185 struct ast_format *fmt = ast_format_cache_get(format_name);
2186
2187 if (!fmt || ast_format_cap_append(request_cap, fmt, 0)) {
2188 if (!fmt) {
2190 response, 400, "Bad Request",
2191 "Provided format (%s) was not found", format_name);
2192 } else {
2194 }
2195 ao2_ref(request_cap, -1);
2196 ao2_cleanup(fmt);
2197 chan_data_destroy(chan_data);
2198 return;
2199 }
2200 ao2_ref(fmt, -1);
2201 }
2202 } else {
2203 if (!(request_cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
2205 chan_data_destroy(chan_data);
2206 return;
2207 }
2208
2210 }
2211
2212 chan_data->chan = ast_request(dialtech, request_cap, &assignedids, originator, dialdevice, &cause);
2213 ao2_cleanup(request_cap);
2214
2215 if (!chan_data->chan) {
2217 ast_ari_response_error(response, 409, "Conflict",
2218 "Channel with given unique ID already exists");
2219 } else {
2221 }
2222 ast_channel_cleanup(originator);
2223 chan_data_destroy(chan_data);
2224 return;
2225 }
2226
2227 if (!ast_strlen_zero(args->app)) {
2228 stasis_app_subscribe_channel(args->app, chan_data->chan);
2229 }
2230
2231 if (variables) {
2232 ast_set_variables(chan_data->chan, variables);
2233 }
2234 if (report_event_variables) {
2235 struct ast_variable *var;
2236
2237 for (var = report_event_variables; var; var = var->next) {
2238 if (ast_channel_set_ari_var_reportable(chan_data->chan, var->name, 1)) {
2240 ast_channel_cleanup(originator);
2241 chan_data_destroy(chan_data);
2242 return;
2243 }
2244 }
2245 }
2246
2247 ast_channel_cleanup(originator);
2248
2249 if (save_dialstring(chan_data->chan, stuff)) {
2251 chan_data_destroy(chan_data);
2252 return;
2253 }
2254
2256
2259 chan_data_destroy(chan_data);
2260 } else {
2262 }
2263
2264 ao2_ref(snapshot, -1);
2265}
2266
2269 struct ast_ari_response *response)
2270{
2271 RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
2272 RAII_VAR(struct ast_channel *, caller, NULL, ast_channel_cleanup);
2273 RAII_VAR(struct ast_channel *, callee, NULL, ast_channel_cleanup);
2274 char *dialstring;
2275
2276 control = find_control(response, args->channel_id);
2277 if (control == NULL) {
2278 /* Response filled in by find_control */
2279 return;
2280 }
2281
2282 if (!ast_strlen_zero(args->caller)) {
2283 caller = ast_channel_get_by_name(args->caller);
2284 }
2285
2286 callee = ast_channel_get_by_name(args->channel_id);
2287 if (!callee) {
2288 ast_ari_response_error(response, 404, "Not Found",
2289 "Callee not found");
2290 return;
2291 }
2292
2293 if (ast_channel_state(callee) != AST_STATE_DOWN
2294 && ast_channel_state(callee) != AST_STATE_RESERVED) {
2295 ast_ari_response_error(response, 409, "Conflict",
2296 "Channel is not in the 'Down' state");
2297 return;
2298 }
2299
2300 /* XXX This is straight up copied from main/dial.c. It's probably good
2301 * to separate this to some common method.
2302 */
2303 if (caller) {
2304 ast_channel_lock_both(caller, callee);
2305 } else {
2306 ast_channel_lock(callee);
2307 }
2308
2309 dialstring = restore_dialstring(callee);
2310 if (!dialstring) {
2311 ast_channel_unlock(callee);
2312 if (caller) {
2313 ast_channel_unlock(caller);
2314 }
2315 ast_ari_response_error(response, 409, "Conflict",
2316 "Dialing a channel not created by ARI");
2317 return;
2318 }
2319 /* Make a copy of the dialstring just in case some jerk tries to hang up the
2320 * channel before we can actually dial
2321 */
2322 dialstring = ast_strdupa(dialstring);
2323
2325 if (caller) {
2326 ast_channel_inherit_variables(caller, callee);
2327 ast_channel_datastore_inherit(caller, callee);
2329
2330 /* Copy over callerid information */
2332
2334
2336
2337 ast_channel_language_set(callee, ast_channel_language(caller));
2340 ast_channel_musicclass_set(callee, ast_channel_musicclass(caller));
2341
2344 ast_channel_unlock(caller);
2345 }
2346
2348 ast_channel_unlock(callee);
2349
2350 if (stasis_app_control_dial(control, dialstring, args->timeout)) {
2352 return;
2353 }
2354
2356}
2357
2360 struct ast_ari_response *response)
2361{
2362 RAII_VAR(struct ast_channel *, chan, NULL, ast_channel_cleanup);
2363 RAII_VAR(struct ast_rtp_instance *, rtp, NULL, ao2_cleanup);
2364 struct ast_json *j_res;
2365 const struct ast_channel_tech *tech;
2366 struct ast_rtp_glue *glue;
2367
2368 chan = ast_channel_get_by_name(args->channel_id);
2369 if (!chan) {
2370 ast_ari_response_error(response, 404, "Not Found",
2371 "Channel not found");
2372 return;
2373 }
2374
2375 ast_channel_lock(chan);
2376 tech = ast_channel_tech(chan);
2377 if (!tech) {
2378 ast_channel_unlock(chan);
2379 ast_ari_response_error(response, 404, "Not Found",
2380 "Channel's tech not found");
2381 return;
2382 }
2383
2384 glue = ast_rtp_instance_get_glue(tech->type);
2385 if (!glue) {
2386 ast_channel_unlock(chan);
2387 ast_ari_response_error(response, 403, "Forbidden",
2388 "Unsupported channel type");
2389 return;
2390 }
2391
2392 glue->get_rtp_info(chan, &rtp);
2393 if (!rtp) {
2394 ast_channel_unlock(chan);
2395 ast_ari_response_error(response, 404, "Not Found",
2396 "RTP info not found");
2397 return;
2398 }
2399
2401 if (!j_res) {
2402 ast_channel_unlock(chan);
2403 ast_ari_response_error(response, 404, "Not Found",
2404 "Statistics not found");
2405 return;
2406 }
2407
2408 ast_channel_unlock(chan);
2409 ast_ari_response_ok(response, j_res);
2410
2411 return;
2412}
2413
2415 struct ast_variable *variables,
2416 struct ast_variable *report_event_variables,
2417 struct ast_ari_response *response)
2418{
2419 char *endpoint;
2420 struct ast_channel *chan;
2421 struct varshead *vars;
2422
2423 if (ast_asprintf(&endpoint, "UnicastRTP/%s/c(%s)",
2424 args->external_host,
2425 args->format) == -1) {
2426 return 1;
2427 }
2428
2430 endpoint,
2431 NULL,
2432 NULL,
2433 0,
2434 NULL,
2435 args->app,
2436 args->data,
2437 NULL,
2438 0,
2439 variables,
2440 report_event_variables,
2441 args->channel_id,
2442 NULL,
2443 NULL,
2444 args->format,
2445 response);
2446
2447 ast_free(endpoint);
2448
2449 if (!chan) {
2450 return 1;
2451 }
2452
2453 ast_channel_lock(chan);
2454 vars = ast_channel_varshead(chan);
2455 if (vars && !AST_LIST_EMPTY(vars)) {
2456 ast_json_object_set(response->message, "channelvars", ast_json_channel_vars(vars));
2457 }
2458 ast_channel_unlock(chan);
2459 ast_channel_unref(chan);
2460 return 0;
2461}
2462
2464 struct ast_variable *variables,
2465 struct ast_variable *report_event_variables,
2466 struct ast_ari_response *response)
2467{
2468 char *endpoint;
2469 struct ast_channel *chan;
2470 struct varshead *vars;
2471
2472 if (ast_asprintf(&endpoint, "AudioSocket/%s/%s",
2473 args->external_host, args->data) == -1) {
2474 return 1;
2475 }
2476
2478 endpoint,
2479 NULL,
2480 NULL,
2481 0,
2482 NULL,
2483 args->app,
2484 args->data,
2485 NULL,
2486 0,
2487 variables,
2488 report_event_variables,
2489 args->channel_id,
2490 NULL,
2491 NULL,
2492 args->format,
2493 response);
2494
2495 ast_free(endpoint);
2496
2497 if (!chan) {
2498 return 1;
2499 }
2500
2501 ast_channel_lock(chan);
2502 vars = ast_channel_varshead(chan);
2503 if (vars && !AST_LIST_EMPTY(vars)) {
2504 ast_json_object_set(response->message, "channelvars", ast_json_channel_vars(vars));
2505 }
2506 ast_channel_unlock(chan);
2507 ast_channel_unref(chan);
2508 return 0;
2509}
2510
2512 struct ast_variable *variables,
2513 struct ast_variable *report_event_variables,
2514 struct ast_ari_response *response)
2515{
2516 char *endpoint;
2517 struct ast_channel *chan;
2518 struct varshead *vars;
2519 char direction[16] = "";
2520
2521 /* If direction is set here, it WILL override any m() line in transport data
2522 * since it is appended to the end of the string.
2523 */
2524 if (args->direction) {
2525 snprintf(direction, sizeof(direction), "d(%s)", args->direction);
2526 }
2527
2528 if (ast_asprintf(&endpoint, "WebSocket/%s%s%s%s%s",
2529 args->external_host,
2530 S_COR(args->transport_data, "/", ""),
2531 S_OR(args->transport_data, ""),
2532 S_COR(!args->transport_data && args->direction, "/", ""),
2533 direction) == -1) {
2534 return 1;
2535 }
2536
2538 endpoint,
2539 NULL,
2540 NULL,
2541 0,
2542 NULL,
2543 args->app,
2544 args->data,
2545 NULL,
2546 0,
2547 variables,
2548 report_event_variables,
2549 args->channel_id,
2550 NULL,
2551 NULL,
2552 args->format,
2553 response);
2554
2555 ast_free(endpoint);
2556
2557 if (!chan) {
2558 return 1;
2559 }
2560
2561 ast_channel_lock(chan);
2562 vars = ast_channel_varshead(chan);
2563 if (vars && !AST_LIST_EMPTY(vars)) {
2564 ast_json_object_set(response->message, "channelvars", ast_json_channel_vars(vars));
2565 }
2566 ast_channel_unlock(chan);
2567 ast_channel_unref(chan);
2568 return 0;
2569}
2570
2571#include "asterisk/config.h"
2572#include "asterisk/netsock2.h"
2573
2576{
2577 RAII_VAR(struct ast_variable *, variables, NULL, ast_variables_destroy);
2578 RAII_VAR(struct ast_variable *, report_event_variables, NULL, ast_variables_destroy);
2579 char *external_host;
2580 char *host = NULL;
2581 char *port = NULL;
2582
2583 ast_assert(response != NULL);
2584
2585 /* Parse any query parameters out of the body parameter */
2586 if (args->variables) {
2587 struct ast_json *json_variables;
2588
2590 json_variables = ast_json_object_get(args->variables, "variables");
2591 if (json_variables
2592 && json_to_ast_variables(response, json_variables, &variables,
2593 &report_event_variables)) {
2594 return;
2595 }
2596 }
2597
2598 if (ast_strlen_zero(args->app)) {
2599 ast_ari_response_error(response, 400, "Bad Request", "app cannot be empty");
2600 return;
2601 }
2602
2603 if (ast_strlen_zero(args->transport)) {
2604 args->transport = "udp";
2605 }
2606
2607 if (ast_strlen_zero(args->encapsulation)) {
2608 args->encapsulation = "rtp";
2609 }
2610 if (ast_strings_equal(args->transport, "websocket")) {
2611 if (!ast_strings_equal(args->encapsulation, "none")) {
2612 ast_ari_response_error(response, 400, "Bad Request", "encapsulation must be 'none' for websocket transport");
2613 return;
2614 }
2615 }
2616
2617 if (ast_strings_equal(args->encapsulation, "rtp")) {
2618 if (!ast_strings_equal(args->transport, "udp")) {
2619 ast_ari_response_error(response, 400, "Bad Request", "transport must be 'udp' for rtp encapsulation");
2620 return;
2621 }
2622 }
2623
2624 if (ast_strings_equal(args->encapsulation, "audiosocket")) {
2625 if (!ast_strings_equal(args->transport, "tcp")) {
2626 ast_ari_response_error(response, 400, "Bad Request", "transport must be 'tcp' for audiosocket encapsulation");
2627 return;
2628 }
2629 }
2630
2631 if (ast_strlen_zero(args->connection_type)) {
2632 args->connection_type = "client";
2633 }
2634 if (!ast_strings_equal(args->transport, "websocket")) {
2635 if (ast_strings_equal(args->connection_type, "server")) {
2636 ast_ari_response_error(response, 400, "Bad Request", "'server' connection_type can only be used with the websocket transport");
2637 return;
2638 }
2639 }
2640
2641 if (ast_strlen_zero(args->external_host)) {
2642 if (ast_strings_equal(args->connection_type, "client")) {
2643 ast_ari_response_error(response, 400, "Bad Request", "external_host is required for all but websocket server connections");
2644 return;
2645 } else {
2646 /* server is only valid for websocket, enforced above */
2647 args->external_host = "INCOMING";
2648 }
2649 }
2650
2651 if (ast_strings_equal(args->transport, "websocket")) {
2652 if (ast_strings_equal(args->connection_type, "client")) {
2653 struct ast_websocket_client *ws_client =
2655 ao2_cleanup(ws_client);
2656 if (!ws_client) {
2657 ast_ari_response_error(response, 400, "Bad Request", "external_host must be a valid websocket_client connection id.");
2658 return;
2659 }
2660 }
2661 } else {
2662 external_host = ast_strdupa(args->external_host);
2663 if (!ast_sockaddr_split_hostport(external_host, &host, &port, PARSE_PORT_REQUIRE)) {
2664 ast_ari_response_error(response, 400, "Bad Request", "external_host must be <host>:<port> for all transports other than websocket");
2665 return;
2666 }
2667 }
2668
2669 if (ast_strlen_zero(args->format)) {
2670 ast_ari_response_error(response, 400, "Bad Request", "format cannot be empty");
2671 return;
2672 }
2673
2674 if (!ast_strlen_zero(args->direction)) {
2675 if (strcmp(args->direction, "both") && strcmp(args->direction, "in")
2676 && strcmp(args->direction, "out")) {
2678 response, 400, "Bad Request",
2679 "Invalid direction specified");
2680 return;
2681 }
2682 }
2683
2684 if (strcasecmp(args->encapsulation, "rtp") == 0 && strcasecmp(args->transport, "udp") == 0) {
2685 if (external_media_rtp_udp(args, variables, report_event_variables, response)) {
2687 response, 500, "Internal Server Error",
2688 "An internal error prevented this request from being handled");
2689 }
2690 } else if (strcasecmp(args->encapsulation, "audiosocket") == 0 && strcasecmp(args->transport, "tcp") == 0) {
2691 if (ast_strlen_zero(args->data)) {
2692 ast_ari_response_error(response, 400, "Bad Request", "data can not be empty");
2693 } else if (external_media_audiosocket_tcp(args, variables, report_event_variables, response)) {
2695 response, 500, "Internal Server Error",
2696 "An internal error prevented this request from being handled");
2697 }
2698 } else if (strcasecmp(args->encapsulation, "none") == 0 && strcasecmp(args->transport, "websocket") == 0) {
2699 if (external_media_websocket(args, variables, report_event_variables, response)) {
2701 response, 500, "Internal Server Error",
2702 "An internal error prevented this request from being handled");
2703 }
2704 } else {
2706 response, 501, "Not Implemented",
2707 "The encapsulation and/or transport is not supported");
2708 }
2709}
2710
2712{
2714 RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
2715 RAII_VAR(struct ast_channel *, chan, NULL, ast_channel_cleanup);
2716
2717 control = find_control(response, args->channel_id);
2718 if (control == NULL) {
2719 /* Response filled in by find_control */
2720 return;
2721 }
2722
2723 chan = ast_channel_get_by_name(args->channel_id);
2724 if (!chan) {
2725 ast_ari_response_error(response, 404, "Not Found",
2726 "Callee not found");
2727 return;
2728 }
2729
2730 if (ast_strlen_zero(args->states)) {
2731 ast_ari_response_error(response, 400, "Bad Request", "states must not be empty");
2732 return;
2733 }
2734
2735 if (strcasecmp(args->states, "channel_progress") == 0) {
2737 } else if (strcasecmp(args->states, "channel_answered") == 0) {
2739 } else if (strcasecmp(args->states, "channel_unavailable") == 0) {
2741 } else if (strcasecmp(args->states, "channel_declined") == 0) {
2743 } else {
2744 ast_ari_response_error(response, 400, "Bad Request", "Invalid states value");
2745 return;
2746 }
2747
2750}
static const char app[]
pthread_t thread
Definition app_sla.c:335
void ast_ari_response_created(struct ast_ari_response *response, const char *url, struct ast_json *message)
Fill in a Created (201) ast_ari_response.
Definition res_ari.c:258
void ast_ari_response_error(struct ast_ari_response *response, int response_code, const char *response_text, const char *message_fmt,...)
Fill in an error ast_ari_response.
Definition res_ari.c:212
void ast_ari_response_ok(struct ast_ari_response *response, struct ast_json *message)
Fill in an OK (200) ast_ari_response.
Definition res_ari.c:229
void ast_ari_response_alloc_failed(struct ast_ari_response *response)
Fill in response with a 500 message for allocation failures.
Definition res_ari.c:251
void ast_ari_response_no_content(struct ast_ari_response *response)
Fill in a No Content (204) ast_ari_response.
Definition res_ari.c:237
#define var
Definition ast_expr2f.c:605
char * strsep(char **str, const char *delims)
Asterisk main include file. File version handling, generic pbx functions.
#define ast_free(a)
Definition astmm.h:180
#define ast_strdup(str)
A wrapper for strdup()
Definition astmm.h:241
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition astmm.h:298
void ast_free_ptr(void *ptr)
free() wrapper
Definition astmm.c:1739
#define ast_asprintf(ret, fmt,...)
A wrapper for asprintf()
Definition astmm.h:267
#define ast_calloc(num, len)
A wrapper for calloc()
Definition astmm.h:202
#define ast_malloc(len)
A wrapper for malloc()
Definition astmm.h:191
#define ast_log
Definition astobj2.c:42
#define ao2_iterator_next(iter)
Definition astobj2.h:1911
#define ao2_cleanup(obj)
Definition astobj2.h:1934
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition astobj2.h:459
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
Definition astobj2.h:480
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
Bridging API.
CallerID (and other GR30) management and generation Includes code and algorithms from the Zapata libr...
int ast_callerid_parse(char *instr, char **name, char **location)
Destructively parse inbuf into name and location (or number)
Definition callerid.c:1162
void ast_shrink_phone_number(char *n)
Shrink a phone number in place to just digits (more accurately it just removes ()'s,...
Definition callerid.c:1101
int ast_is_shrinkable_phonenumber(const char *exten)
Check if a string consists only of digits and + # ( ) - . (meaning it can be cleaned with ast_shrink_...
Definition callerid.c:1157
#define AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED
Definition callerid.h:437
Internal Asterisk hangup causes.
#define AST_CAUSE_CONGESTION
Definition causes.h:153
#define AST_CAUSE_UNALLOCATED
Definition causes.h:98
#define AST_CAUSE_INTERWORKING
Definition causes.h:146
#define AST_CAUSE_BEARERCAPABILITY_NOTAVAIL
Definition causes.h:130
#define AST_CAUSE_INVALID_NUMBER_FORMAT
Definition causes.h:116
#define AST_CAUSE_FAILURE
Definition causes.h:150
#define AST_CAUSE_NO_USER_RESPONSE
Definition causes.h:108
#define AST_CAUSE_NORMAL
Definition causes.h:151
#define AST_CAUSE_CALL_REJECTED
Definition causes.h:111
#define AST_CAUSE_ANSWERED_ELSEWHERE
Definition causes.h:114
#define AST_CAUSE_NORMAL_UNSPECIFIED
Definition causes.h:119
#define AST_CAUSE_NOANSWER
Definition causes.h:152
#define AST_CAUSE_BUSY
Definition causes.h:149
static int connected
Definition cdr_pgsql.c:73
static char language[MAX_LANGUAGE]
Definition chan_iax2.c:361
void ast_channel_exten_set(struct ast_channel *chan, const char *value)
const char * ast_channel_name(const struct ast_channel *chan)
#define AST_MAX_PUBLIC_UNIQUEID
Definition channel.h:147
enum ast_channel_error ast_channel_errno(void)
Get error code for latest channel operation.
Definition channel.c:11141
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
Definition channel.c:2376
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition channel.c:2540
struct varshead * ast_channel_varshead(struct ast_channel *chan)
@ AST_CHANNEL_REQUESTOR_BRIDGE_PEER
Definition channel.h:1525
void ast_channel_set_connected_line(struct ast_channel *chan, const struct ast_party_connected_line *connected, const struct ast_set_party_connected_line *update)
Set the connected line information in the Asterisk channel.
Definition channel.c:8484
const char * ast_channel_musicclass(const struct ast_channel *chan)
#define ast_channel_lock(chan)
Definition channel.h:2983
struct ast_format_cap * ast_channel_nativeformats(const struct ast_channel *chan)
@ AST_FLAG_ORIGINATED
Definition channel.h:1059
struct ast_party_redirecting * ast_channel_redirecting(struct ast_channel *chan)
unsigned short ast_channel_transfercapability(const struct ast_channel *chan)
void ast_set_variables(struct ast_channel *chan, struct ast_variable *vars)
adds a list of channel variables to a channel
Definition channel.c:8291
struct ast_flags * ast_channel_flags(struct ast_channel *chan)
@ AST_CHANNEL_ERROR_ID_EXISTS
Definition channel.h:4936
#define ast_channel_ref(c)
Increase channel reference count.
Definition channel.h:3008
#define ast_channel_lock_both(chan1, chan2)
Lock two channels.
Definition channel.h:2990
struct ast_party_connected_line * ast_channel_connected(struct ast_channel *chan)
const char * ast_channel_uniqueid(const struct ast_channel *chan)
int ast_channel_datastore_inherit(struct ast_channel *from, struct ast_channel *to)
Inherit datastores from a parent to a child.
Definition channel.c:2359
void ast_channel_req_accountcodes(struct ast_channel *chan, const struct ast_channel *requestor, enum ast_channel_requestor_relationship relationship)
Setup new channel accountcodes from the requestor channel after ast_request().
Definition channel.c:6453
#define AST_MUTE_DIRECTION_READ
Definition channel.h:4851
ast_channel_adsicpe
Definition channel.h:888
int ast_channel_set_ari_var_reportable(struct ast_channel *chan, const char *variable, int report_events)
Set whether a channel variable should be included in REST events on the channel.
Definition channel.c:7906
void ast_set_callerid(struct ast_channel *chan, const char *cid_num, const char *cid_name, const char *cid_ani)
Set caller ID number, name and ANI and generate AMI event.
Definition channel.c:7370
void ast_channel_inherit_variables(const struct ast_channel *parent, struct ast_channel *child)
Inherits channel variable from parent to child channel.
Definition channel.c:6795
struct ast_channel * ast_channel_get_by_name(const char *search)
Find a channel by name or uniqueid.
Definition channel.c:1417
struct ast_party_dialed * ast_channel_dialed(struct ast_channel *chan)
int ast_indicate_data(struct ast_channel *chan, int condition, const void *data, size_t datalen)
Indicates condition of channel, with payload.
Definition channel.c:4676
int ast_softhangup(struct ast_channel *chan, int cause)
Softly hangup up a channel.
Definition channel.c:2462
#define ast_channel_unref(c)
Decrease channel reference count.
Definition channel.h:3019
#define AST_MAX_CONTEXT
Definition channel.h:135
const char * ast_channel_language(const struct ast_channel *chan)
void ast_channel_context_set(struct ast_channel *chan, const char *value)
@ AST_SOFTHANGUP_EXPLICIT
Definition channel.h:1168
void ast_connected_line_copy_from_caller(struct ast_party_connected_line *dest, const struct ast_party_caller *src)
Copy the caller information to the connected line information.
Definition channel.c:8469
#define AST_MUTE_DIRECTION_WRITE
Definition channel.h:4852
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
void ast_party_connected_line_set_init(struct ast_party_connected_line *init, const struct ast_party_connected_line *guide)
Initialize the given connected line structure using the given guide for a set update operation.
Definition channel.c:2032
void ast_channel_transfercapability_set(struct ast_channel *chan, unsigned short value)
void ast_channel_priority_set(struct ast_channel *chan, int value)
void ast_channel_hangupcause_set(struct ast_channel *chan, int value)
#define ast_channel_cleanup(c)
Cleanup a channel reference.
Definition channel.h:3030
void ast_channel_adsicpe_set(struct ast_channel *chan, enum ast_channel_adsicpe value)
struct ast_channel * ast_request(const char *type, struct ast_format_cap *request_cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *addr, int *cause)
Requests a channel.
Definition channel.c:6373
#define ast_channel_unlock(chan)
Definition channel.h:2984
#define AST_MAX_EXTENSION
Definition channel.h:134
void ast_party_redirecting_copy(struct ast_party_redirecting *dest, const struct ast_party_redirecting *src)
Copy the source redirecting information to the destination redirecting.
Definition channel.c:2122
struct ast_datastore * ast_channel_datastore_find(struct ast_channel *chan, const struct ast_datastore_info *info, const char *uid)
Find a datastore on a channel.
Definition channel.c:2390
ast_channel_state
ast_channel states
@ AST_STATE_RINGING
@ AST_STATE_DOWN
@ AST_STATE_RESERVED
@ AST_MEDIA_TYPE_AUDIO
Definition codec.h:32
Local proxy channel special access.
struct ast_channel * ast_local_get_peer(struct ast_channel *ast)
Get the other local channel in the pair.
Definition core_local.c:288
#define ast_datastore_alloc(info, uid)
Definition datastore.h:85
int ast_datastore_free(struct ast_datastore *datastore)
Free a data store object.
Definition datastore.c:68
Dialing API.
ast_dial_result
List of return codes for dial run API calls.
Definition dial.h:54
@ AST_DIAL_RESULT_ANSWERED
Definition dial.h:61
int ast_dial_append(struct ast_dial *dial, const char *tech, const char *device, const struct ast_assigned_ids *assignedids)
Append a channel.
Definition dial.c:280
struct ast_dial * ast_dial_create(void)
New dialing structure.
Definition dial.c:223
struct ast_channel * ast_dial_answered(struct ast_dial *dial)
Return channel that answered.
Definition dial.c:980
void ast_dial_set_user_data(struct ast_dial *dial, void *user_data)
Set user data on a dial structure.
Definition dial.c:1277
int ast_dial_prerun(struct ast_dial *dial, struct ast_channel *chan, struct ast_format_cap *cap)
Request all appended channels, but do not dial.
Definition dial.c:431
void ast_dial_set_global_timeout(struct ast_dial *dial, int timeout)
Set the maximum time (globally) allowed for trying to ring phones.
Definition dial.c:1287
enum ast_dial_result ast_dial_run(struct ast_dial *dial, struct ast_channel *chan, int async)
Execute dialing synchronously or asynchronously.
Definition dial.c:938
struct ast_channel * ast_dial_answered_steal(struct ast_dial *dial)
Steal the channel that answered.
Definition dial.c:992
void * ast_dial_get_user_data(struct ast_dial *dial)
Return the user data on a dial structure.
Definition dial.c:1282
struct ast_channel * ast_dial_get_channel(struct ast_dial *dial, int num)
Get the dialing channel, if prerun has been executed.
Definition dial.c:1261
int ast_dial_destroy(struct ast_dial *dial)
Destroys a dialing structure.
Definition dial.c:1094
char * end
Definition eagi_proxy.c:73
char buf[BUFSIZE]
Definition eagi_proxy.c:66
Generic File Format Support. Should be included by clients of the file handling routines....
struct ast_format * ast_get_format_for_file_ext(const char *file_ext)
Get the ast_format associated with the given file extension.
Definition file.c:2040
Media Format Cache API.
#define ast_format_cache_get(name)
Retrieve a named format from the cache.
int ast_format_cap_append_by_type(struct ast_format_cap *cap, enum ast_media_type type)
Add all codecs Asterisk knows about for a specific type to the capabilities structure.
Definition format_cap.c:216
@ AST_FORMAT_CAP_FLAG_DEFAULT
Definition format_cap.h:38
#define ast_format_cap_append(cap, format, framing)
Add format capability to capabilities structure.
Definition format_cap.h:99
#define ast_format_cap_alloc(flags)
Allocate a new ast_format_cap structure.
Definition format_cap.h:49
direction
struct ao2_container * ast_channel_cache_all(void)
struct ast_channel_snapshot * ast_channel_snapshot_get_latest(const char *uniqueid)
Obtain the latest ast_channel_snapshot from the Stasis Message Bus API cache. This is an ao2 object,...
void ast_channel_stage_snapshot_done(struct ast_channel *chan)
Clear flag to indicate channel snapshot is being staged, and publish snapshot.
void ast_channel_stage_snapshot(struct ast_channel *chan)
Set flag to indicate channel snapshot is being staged.
@ AST_RECORD_IF_EXISTS_ERROR
Configuration File Parser.
#define ast_variable_new(name, value, filename)
struct ast_variable * ast_variable_list_append_hint(struct ast_variable **head, struct ast_variable *search_hint, struct ast_variable *new_var)
Appends a variable list to the end of another list.
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition extconf.c:1260
@ AST_TRANSFER_FAILED
@ AST_TRANSFER_UNAVAILABLE
@ AST_TRANSFER_SUCCESS
@ AST_TRANSFER_PROGRESS
ast_frame_type
Frame types.
@ AST_CONTROL_TRANSFER
#define AST_LOG_ERROR
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_DEBUG
#define LOG_ERROR
#define ast_verb(level,...)
#define LOG_WARNING
struct ast_json * ast_json_object_iter_value(struct ast_json_iter *iter)
Get the value from an iterator.
Definition json.c:455
struct ast_json * ast_json_string_create(const char *value)
Construct a JSON string from value.
Definition json.c:278
enum ast_json_type ast_json_typeof(const struct ast_json *value)
Get the type of value.
Definition json.c:78
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition json.c:73
struct ast_json_iter * ast_json_object_iter_next(struct ast_json *object, struct ast_json_iter *iter)
Get the next iterator.
Definition json.c:447
int ast_json_array_append(struct ast_json *array, struct ast_json *value)
Append to an array.
Definition json.c:378
struct ast_json * ast_json_object_create(void)
Create a new JSON object.
Definition json.c:399
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
Definition json.c:612
struct ast_json * ast_json_array_create(void)
Create a empty JSON array.
Definition json.c:362
struct ast_json_iter * ast_json_object_iter(struct ast_json *object)
Get an iterator pointing to the first field in a JSON object.
Definition json.c:439
ast_json_type
Valid types of a JSON element.
Definition json.h:163
@ AST_JSON_STRING
Definition json.h:166
@ AST_JSON_OBJECT
Definition json.h:164
@ AST_JSON_FALSE
Definition json.h:170
@ AST_JSON_TRUE
Definition json.h:169
struct ast_json * ast_json_ref(struct ast_json *value)
Increase refcount on value.
Definition json.c:67
int ast_json_object_set(struct ast_json *object, const char *key, struct ast_json *value)
Set a field in a JSON object.
Definition json.c:414
const char * ast_json_string_get(const struct ast_json *string)
Get the value of a JSON string.
Definition json.c:283
const char * ast_json_object_iter_key(struct ast_json_iter *iter)
Get the key from an iterator.
Definition json.c:451
struct ast_json * ast_json_object_get(struct ast_json *object, const char *key)
Get a field from a JSON object.
Definition json.c:407
struct ast_json * ast_json_channel_vars(struct varshead *channelvars)
Construct a JSON object from a ast_var_t list.
Definition json.c:941
int ast_json_is_true(const struct ast_json *value)
Check if value is JSON true.
Definition json.c:263
#define AST_LIST_EMPTY(head)
Checks whether the specified list contains any entries.
int errno
int ast_max_forwards_decrement(struct ast_channel *chan)
Decrement the max forwards count for a particular channel.
Network socket handling.
int ast_sockaddr_split_hostport(char *str, char **host, char **port, int flags)
Splits a string into its host and port components.
Definition netsock2.c:164
Core PBX routines and definitions.
int ast_findlabel_extension(struct ast_channel *c, const char *context, const char *exten, const char *label, const char *callerid)
Find the priority of an extension that has the specified label.
Definition pbx.c:2740
enum ast_pbx_result ast_pbx_run(struct ast_channel *c)
Execute the PBX in the current thread.
Definition pbx.c:3315
int pbx_exec(struct ast_channel *c, struct ast_app *app, const char *data)
Execute an application.
Definition pbx_app.c:483
int ast_func_read2(struct ast_channel *chan, const char *function, struct ast_str **str, ssize_t maxlen)
executes a read operation on a function
const char * ast_str_retrieve_variable(struct ast_str **buf, ssize_t maxlen, struct ast_channel *chan, struct varshead *headp, const char *var)
struct ast_app * pbx_findapp(const char *app)
Look up an application.
Definition ael_main.c:165
static struct @522 args
#define NULL
Definition resample.c:96
void ast_ari_channels_get_channel_vars(struct ast_variable *headers, struct ast_ari_channels_get_channel_vars_args *args, struct ast_ari_response *response)
Get the value of multiple channel variables or functions.
static int save_dialstring(struct ast_channel *chan, const char *dialstring)
Save dialstring onto a channel datastore.
void ast_ari_channels_mute(struct ast_variable *headers, struct ast_ari_channels_mute_args *args, struct ast_ari_response *response)
Mute a channel.
static int external_media_websocket(struct ast_ari_channels_external_media_args *args, struct ast_variable *variables, struct ast_variable *report_event_variables, struct ast_ari_response *response)
void ast_ari_channels_snoop_channel_with_id(struct ast_variable *headers, struct ast_ari_channels_snoop_channel_with_id_args *args, struct ast_ari_response *response)
Start snooping.
void ast_ari_channels_continue_in_dialplan(struct ast_variable *headers, struct ast_ari_channels_continue_in_dialplan_args *args, struct ast_ari_response *response)
Exit application; continue execution in the dialplan.
void ast_ari_channels_start_moh(struct ast_variable *headers, struct ast_ari_channels_start_moh_args *args, struct ast_ari_response *response)
Play music on hold to a channel.
static int channel_state_invalid(struct stasis_app_control *control, struct ast_ari_response *response)
Ensure channel is in a state that allows operation to be performed.
void ast_ari_channels_stop_moh(struct ast_variable *headers, struct ast_ari_channels_stop_moh_args *args, struct ast_ari_response *response)
Stop playing music on hold to a channel.
void ast_ari_channels_move(struct ast_variable *headers, struct ast_ari_channels_move_args *args, struct ast_ari_response *response)
Move the channel from one Stasis application to another.
static char * restore_dialstring(struct ast_channel *chan)
Retrieve the dialstring from the channel datastore.
void ast_ari_channels_send_dtmf(struct ast_variable *headers, struct ast_ari_channels_send_dtmf_args *args, struct ast_ari_response *response)
Send provided DTMF to a given channel.
void ast_ari_channels_unmute(struct ast_variable *headers, struct ast_ari_channels_unmute_args *args, struct ast_ari_response *response)
Unmute a channel.
void ast_ari_channels_dial(struct ast_variable *headers, struct ast_ari_channels_dial_args *args, struct ast_ari_response *response)
Dial a created channel.
static void * ari_originate_dial(void *data)
Thread which dials and executes upon answer.
void ast_ari_channels_create(struct ast_variable *headers, struct ast_ari_channels_create_args *args, struct ast_ari_response *response)
Create channel.
void ast_ari_channels_list(struct ast_variable *headers, struct ast_ari_channels_list_args *args, struct ast_ari_response *response)
List all active channels in Asterisk.
static void ari_channels_handle_snoop_channel(const char *args_channel_id, const char *args_spy, const char *args_whisper, const char *args_app, const char *args_app_args, const char *args_snoop_id, struct ast_ari_response *response)
void ast_ari_channels_get(struct ast_variable *headers, struct ast_ari_channels_get_args *args, struct ast_ari_response *response)
Channel details.
static void * ari_channel_thread(void *data)
Thread that owns stasis-created channel.
void ast_ari_channels_snoop_channel(struct ast_variable *headers, struct ast_ari_channels_snoop_channel_args *args, struct ast_ari_response *response)
Start snooping.
struct ast_datastore_info dialstring_info
static int json_to_ast_variables(struct ast_ari_response *response, struct ast_json *json_variables, struct ast_variable **variables, struct ast_variable **report_event_variables)
void ast_ari_channels_transfer_progress(struct ast_variable *headers, struct ast_ari_channels_transfer_progress_args *args, struct ast_ari_response *response)
Inform the channel about the progress of the attended/blind transfer.
void ast_ari_channels_ring(struct ast_variable *headers, struct ast_ari_channels_ring_args *args, struct ast_ari_response *response)
Indicate ringing to a channel.
void ast_ari_channels_play(struct ast_variable *headers, struct ast_ari_channels_play_args *args, struct ast_ari_response *response)
Start playback of media.
void ast_ari_channels_stop_silence(struct ast_variable *headers, struct ast_ari_channels_stop_silence_args *args, struct ast_ari_response *response)
Stop playing silence to a channel.
void ast_ari_channels_external_media(struct ast_variable *headers, struct ast_ari_channels_external_media_args *args, struct ast_ari_response *response)
Start an External Media session.
static void ari_channels_handle_play(const char *args_channel_id, const char **args_media, size_t args_media_count, const char *args_lang, int args_offsetms, int args_skipms, const char *args_playback_id, struct ast_ari_response *response)
void ast_ari_channels_ring_stop(struct ast_variable *headers, struct ast_ari_channels_ring_stop_args *args, struct ast_ari_response *response)
Stop ringing indication on a channel if locally generated.
void ast_ari_channels_progress(struct ast_variable *headers, struct ast_ari_channels_progress_args *args, struct ast_ari_response *response)
Indicate progress on a channel.
void ast_ari_channels_start_silence(struct ast_variable *headers, struct ast_ari_channels_start_silence_args *args, struct ast_ari_response *response)
Play silence to a channel.
void ast_ari_channels_set_channel_vars(struct ast_variable *headers, struct ast_ari_channels_set_channel_vars_args *args, struct ast_ari_response *response)
Set the values of multiple channel variables or functions.
static int convert_reason_to_hangup_code(const char *reason)
Return the corresponded hangup code of the given reason.
void ast_ari_channels_unhold(struct ast_variable *headers, struct ast_ari_channels_unhold_args *args, struct ast_ari_response *response)
Remove a channel from hold.
void ast_ari_channels_originate(struct ast_variable *headers, struct ast_ari_channels_originate_args *args, struct ast_ari_response *response)
Create a new channel (originate).
void ast_ari_channels_redirect(struct ast_variable *headers, struct ast_ari_channels_redirect_args *args, struct ast_ari_response *response)
Redirect the channel to a different location.
void ast_ari_channels_record(struct ast_variable *headers, struct ast_ari_channels_record_args *args, struct ast_ari_response *response)
Start a recording.
static void chan_data_destroy(struct ari_channel_thread_data *chan_data)
void ast_ari_channels_set_channel_var(struct ast_variable *headers, struct ast_ari_channels_set_channel_var_args *args, struct ast_ari_response *response)
Set the value of a channel variable or function.
void ast_ari_channels_hold(struct ast_variable *headers, struct ast_ari_channels_hold_args *args, struct ast_ari_response *response)
Hold a channel.
static int external_media_rtp_udp(struct ast_ari_channels_external_media_args *args, struct ast_variable *variables, struct ast_variable *report_event_variables, struct ast_ari_response *response)
static struct ast_channel * ari_channels_handle_originate_with_id(const char *args_endpoint, const char *args_extension, const char *args_context, long args_priority, const char *args_label, const char *args_app, const char *args_app_args, const char *args_caller_id, int args_timeout, struct ast_variable *variables, struct ast_variable *report_event_variables, const char *args_channel_id, const char *args_other_channel_id, const char *args_originator, const char *args_formats, struct ast_ari_response *response)
void ast_ari_channels_answer(struct ast_variable *headers, struct ast_ari_channels_answer_args *args, struct ast_ari_response *response)
Answer a channel.
void ast_ari_channels_play_with_id(struct ast_variable *headers, struct ast_ari_channels_play_with_id_args *args, struct ast_ari_response *response)
Start playback of media and specify the playbackId.
void ast_ari_channels_rtpstatistics(struct ast_variable *headers, struct ast_ari_channels_rtpstatistics_args *args, struct ast_ari_response *response)
RTP stats on a channel.
void ast_ari_channels_get_channel_var(struct ast_variable *headers, struct ast_ari_channels_get_channel_var_args *args, struct ast_ari_response *response)
Get the value of a channel variable or function.
static struct stasis_app_control * find_control(struct ast_ari_response *response, const char *channel_id)
Finds the control object for a channel, filling the response with an error, if appropriate.
static int external_media_audiosocket_tcp(struct ast_ari_channels_external_media_args *args, struct ast_variable *variables, struct ast_variable *report_event_variables, struct ast_ari_response *response)
void ast_ari_channels_originate_with_id(struct ast_variable *headers, struct ast_ari_channels_originate_with_id_args *args, struct ast_ari_response *response)
Create a new channel (originate with id).
void ast_ari_channels_hangup(struct ast_variable *headers, struct ast_ari_channels_hangup_args *args, struct ast_ari_response *response)
Delete (i.e. hangup) a channel.
Generated file - declares stubs to be implemented in res/ari/resource_channels.c.
int ast_ari_channels_originate_with_id_parse_body(struct ast_json *body, struct ast_ari_channels_originate_with_id_args *args)
Body parsing function for /channels/{channelId}.
int ast_ari_channels_create_parse_body(struct ast_json *body, struct ast_ari_channels_create_args *args)
Body parsing function for /channels/create.
int ast_ari_channels_external_media_parse_body(struct ast_json *body, struct ast_ari_channels_external_media_args *args)
Body parsing function for /channels/externalMedia.
int ast_ari_channels_originate_parse_body(struct ast_json *body, struct ast_ari_channels_originate_args *args)
Body parsing function for /channels.
Pluggable RTP Architecture.
void ast_rtp_instance_set_stats_vars(struct ast_channel *chan, struct ast_rtp_instance *instance)
Set standard statistics from an RTP instance on a channel.
struct ast_json * ast_rtp_instance_get_stats_all_json(struct ast_rtp_instance *instance)
Retrieve statistics about an RTP instance in json format.
struct ast_rtp_glue * ast_rtp_instance_get_glue(const char *type)
Get the RTP glue that binds a channel to the RTP engine.
Stasis Application API. See Stasis Application API for detailed documentation.
struct stasis_message_sanitizer * stasis_app_get_sanitizer(void)
Get the Stasis message sanitizer for app_stasis applications.
void stasis_app_control_moh_start(struct stasis_app_control *control, const char *moh_class)
Play music on hold to a channel (does not affect hold status)
Definition control.c:832
int stasis_app_control_unmute(struct stasis_app_control *control, unsigned int direction, enum ast_frame_type frametype)
Unmute the channel associated with this control.
Definition control.c:700
void stasis_app_control_unhold(struct stasis_app_control *control)
Remove the channel associated with the control from hold.
Definition control.c:813
void stasis_app_control_silence_start(struct stasis_app_control *control)
Start playing silence to a channel.
Definition control.c:884
void stasis_app_control_silence_stop(struct stasis_app_control *control)
Stop playing silence to a channel.
Definition control.c:907
int stasis_app_control_continue(struct stasis_app_control *control, const char *context, const char *extension, int priority)
Exit res_stasis and continue execution in the dialplan.
Definition control.c:415
int stasis_app_control_redirect(struct stasis_app_control *control, const char *endpoint)
Redirect a channel in res_stasis to a particular endpoint.
Definition control.c:526
void stasis_app_control_moh_stop(struct stasis_app_control *control)
Stop playing music on hold to a channel (does not affect hold status)
Definition control.c:850
int stasis_app_control_move(struct stasis_app_control *control, const char *app_name, const char *app_args)
Exit res_stasis and move to another Stasis application.
Definition control.c:477
int stasis_app_control_mute(struct stasis_app_control *control, unsigned int direction, enum ast_frame_type frametype)
Mute the channel associated with this control.
Definition control.c:672
enum stasis_app_subscribe_res stasis_app_subscribe_channel(const char *app_name, struct ast_channel *chan)
Directly subscribe an application to a channel.
int stasis_app_control_dtmf(struct stasis_app_control *control, const char *dtmf, int before, int between, unsigned int duration, int after)
Send DTMF to the channel associated with this control.
Definition control.c:591
int stasis_app_control_set_channel_var_reportable(struct stasis_app_control *control, const char *variable, const char *value, int report_events)
Set a variable on the channel associated with this control to value with option of including in event...
Definition control.c:763
void stasis_app_control_hold(struct stasis_app_control *control)
Place the channel associated with the control on hold.
Definition control.c:800
struct stasis_app_control * stasis_app_control_find_by_channel_id(const char *channel_id)
Returns the handler for the channel with the given id.
Definition res_stasis.c:349
int stasis_app_control_ring_stop(struct stasis_app_control *control)
Stop locally generated ringing on the channel associated with this control.
Definition control.c:633
int stasis_app_control_dial(struct stasis_app_control *control, const char *dialstring, unsigned int timeout)
Dial a channel.
Definition control.c:1729
struct ast_channel_snapshot * stasis_app_control_get_snapshot(const struct stasis_app_control *control)
Returns the most recent snapshot for the associated channel.
Definition control.c:912
int stasis_app_control_ring(struct stasis_app_control *control)
Indicate ringing to the channel associated with this control.
Definition control.c:618
int stasis_app_control_progress(struct stasis_app_control *control)
Indicate progress to the channel associated with this control.
Definition control.c:648
int stasis_app_control_answer(struct stasis_app_control *control)
Answer the channel associated with this control.
Stasis Application Playback API. See StasisApplication API" for detailed documentation.
@ STASIS_PLAYBACK_TARGET_CHANNEL
struct stasis_app_playback * stasis_app_control_play_uri(struct stasis_app_control *control, const char **media, size_t media_count, const char *language, const char *target_id, enum stasis_app_playback_target_type target_type, int skipms, long offsetms, const char *id)
Play a file to the control's channel.
struct ast_json * stasis_app_playback_to_json(const struct stasis_app_playback *playback)
Convert a playback to its JSON representation.
const char * stasis_app_playback_get_id(struct stasis_app_playback *playback)
Gets the unique id of a playback object.
Stasis Application Recording API. See StasisApplication API" for detailed documentation.
struct stasis_app_recording_options * stasis_app_recording_options_create(const char *name, const char *format)
Allocate a recording options object.
struct ast_json * stasis_app_recording_to_json(const struct stasis_app_recording *recording)
Construct a JSON model of a recording.
struct stasis_app_recording * stasis_app_control_record(struct stasis_app_control *control, struct stasis_app_recording_options *options)
Record media from a channel.
enum ast_record_if_exists stasis_app_recording_if_exists_parse(const char *str)
Parse a string into the if_exists enum.
#define STASIS_APP_RECORDING_TERMINATE_INVALID
char stasis_app_recording_termination_parse(const char *str)
Parse a string into the recording termination enum.
Stasis Application Snoop API. See StasisApplication API" for detailed documentation.
struct ast_channel * stasis_app_control_snoop(struct ast_channel *chan, enum stasis_app_snoop_direction spy, enum stasis_app_snoop_direction whisper, const char *app, const char *app_args, const char *snoop_id)
Create a snoop on the provided channel.
stasis_app_snoop_direction
Directions for audio stream flow.
@ STASIS_SNOOP_DIRECTION_IN
Audio stream in from the channel.
@ STASIS_SNOOP_DIRECTION_OUT
Audio stream out to the channel.
@ STASIS_SNOOP_DIRECTION_NONE
No direction.
@ STASIS_SNOOP_DIRECTION_BOTH
Audio stream to AND from the channel.
struct ast_json * ast_channel_snapshot_to_json(const struct ast_channel_snapshot *snapshot, const struct stasis_message_sanitizer *sanitize)
Build a JSON object from a ast_channel_snapshot.
#define ast_string_field_build(x, field, fmt, args...)
Set a field to a complex (built) value.
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition strings.h:1139
int ast_strings_equal(const char *str1, const char *str2)
Compare strings for equality checking for NULL.
Definition strings.c:238
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one.
Definition strings.h:80
#define S_COR(a, b, c)
returns the equivalent of logic or for strings, with an additional boolean check: second one if not e...
Definition strings.h:87
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition strings.h:65
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition strings.h:659
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition strings.h:1113
char *attribute_pure ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition strings.h:761
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition strings.h:425
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
Definition strings.h:223
size_t attribute_pure ast_str_size(const struct ast_str *buf)
Returns the current maximum length (without reallocation) of the current buffer.
Definition strings.h:742
Generic container type.
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition astobj2.h:1821
struct ast_channel * chan
Structure used for origination.
char appdata[0]
Application data to pass to Stasis application.
char exten[AST_MAX_EXTENSION]
Dialplan extension.
char context[AST_MAX_CONTEXT]
Dialplan context.
int priority
Dialplan priority.
ast_app: A registered application
Definition pbx_app.c:45
struct ast_json * message
Definition ari.h:103
Structure to pass both assignedid values to channel drivers.
Definition channel.h:606
const char * uniqueid2
Definition channel.h:608
const char * uniqueid
Definition channel.h:607
Structure representing a snapshot of channel state.
enum ast_channel_state state
Structure to describe a channel "technology", ie a channel driver See for examples:
Definition channel.h:648
const char *const type
Definition channel.h:649
Main Channel structure associated with a channel.
struct ast_channel_snapshot * snapshot
Structure for a data store type.
Definition datastore.h:31
const char * type
Definition datastore.h:32
Structure for a data store object.
Definition datastore.h:64
void * data
Definition datastore.h:66
Main dialing structure. Contains global options, channels being dialed, and more!
Definition dial.c:48
Format capabilities structure, holds formats + preference order + etc.
Definition format_cap.c:54
Definition of a media format.
Definition format.c:43
Iterator for JSON object key/values.
Abstract JSON element (object, array, string, int, ...).
Connected Line/Party information.
Definition channel.h:458
int transit_network_select
Transit Network Select.
Definition channel.h:399
enum ast_rtp_glue_result(* get_rtp_info)(struct ast_channel *chan, struct ast_rtp_instance **instance)
Callback for retrieving the RTP instance carrying audio.
Definition rtp_engine.h:787
Support for dynamic strings.
Definition strings.h:623
Structure for variables, used for configurations and for channel variables.
char stuff[0]
Contents of file, name, and value in that order stuffed here.
struct ast_variable * next
Structure containing callbacks for Stasis message sanitization.
Definition stasis.h:200
int(* channel_snapshot)(const struct ast_channel_snapshot *snapshot)
Callback which determines whether a channel should be sanitized from a message based on the channel's...
Definition stasis.h:221
int value
Definition syslog.c:37
static struct test_options options
int error(const char *format,...)
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition utils.h:981
#define ast_assert(a)
Definition utils.h:779
char * ast_uri_encode(const char *string, char *outbuf, int buflen, struct ast_flags spec)
Turn text string to URI-encoded XX version.
Definition utils.c:721
const struct ast_flags ast_uri_http
Definition utils.c:717
#define ast_pthread_create_detached(a, b, c, d)
Definition utils.h:628
#define ast_set_flag(p, flag)
Definition utils.h:71
struct ast_websocket_client * ast_websocket_client_retrieve_by_id(const char *id)
Retrieve a websocket client object by ID.