Asterisk - The Open Source Telephony Project GIT-master-a358458
res_ari_events.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/*
20 * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
21 * !!!!! DO NOT EDIT !!!!!
22 * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
23 * This file is generated by a mustache template. Please see the original
24 * template in rest-api-templates/res_ari_resource.c.mustache
25 */
26
27/*! \file
28 *
29 * \brief WebSocket resource
30 *
31 * \author David M. Lee, II <dlee@digium.com>
32 */
33
34/*** MODULEINFO
35 <depend type="module">res_ari</depend>
36 <depend type="module">res_ari_model</depend>
37 <depend type="module">res_stasis</depend>
38 <depend type="module">res_http_websocket</depend>
39 <support_level>core</support_level>
40 ***/
41
42#include "asterisk.h"
43
44#include "asterisk/app.h"
45#include "asterisk/module.h"
46#include "asterisk/stasis_app.h"
47#include "ari/resource_events.h"
48#if defined(AST_DEVMODE)
50#endif
52
53#define MAX_VALS 128
54
56 struct ast_variable *get_params, struct ast_variable *headers, const char *session_id)
57{
59 int res = 0;
60 RAII_VAR(struct ast_ari_response *, response, NULL, ast_free);
61 struct ast_variable *i;
62
63 response = ast_calloc(1, sizeof(*response));
64 if (!response) {
65 ast_log(LOG_ERROR, "Failed to create response.\n");
66 goto fin;
67 }
68
69 for (i = get_params; i; i = i->next) {
70 if (strcmp(i->name, "app") == 0) {
71 /* Parse comma separated list */
72 char *vals[MAX_VALS];
73 size_t j;
74
75 args.app_parse = ast_strdup(i->value);
76 if (!args.app_parse) {
78 goto fin;
79 }
80
81 if (strlen(args.app_parse) == 0) {
82 /* ast_app_separate_args can't handle "" */
83 args.app_count = 1;
84 vals[0] = args.app_parse;
85 } else {
86 args.app_count = ast_app_separate_args(
87 args.app_parse, ',', vals,
88 ARRAY_LEN(vals));
89 }
90
91 if (args.app_count == 0) {
93 goto fin;
94 }
95
96 if (args.app_count >= MAX_VALS) {
97 ast_ari_response_error(response, 400,
98 "Bad Request",
99 "Too many values for app");
100 goto fin;
101 }
102
103 args.app = ast_malloc(sizeof(*args.app) * args.app_count);
104 if (!args.app) {
106 goto fin;
107 }
108
109 for (j = 0; j < args.app_count; ++j) {
110 args.app[j] = (vals[j]);
111 }
112 } else
113 if (strcmp(i->name, "subscribeAll") == 0) {
114 args.subscribe_all = ast_true(i->value);
115 } else
116 {}
117 }
118
119 res = ast_ari_websocket_events_event_websocket_attempted(ser, headers, &args, session_id);
120
121fin: __attribute__((unused))
122 if (!response) {
123 ast_http_error(ser, 500, "Server Error", "Memory allocation error");
124 res = -1;
125 } else if (response->response_code != 0) {
126 /* Param parsing failure */
127 RAII_VAR(char *, msg, NULL, ast_json_free);
128 if (response->message) {
129 msg = ast_json_dump_string(response->message);
130 } else {
131 ast_log(LOG_ERROR, "Missing response message\n");
132 }
133
134 if (msg) {
135 ast_http_error(ser, response->response_code, response->response_text, msg);
136 }
137 res = -1;
138 }
139 ast_free(args.app_parse);
140 ast_free(args.app);
141 return res;
142}
143
145 struct ast_variable *get_params, struct ast_variable *headers)
146{
148 RAII_VAR(struct ast_ari_response *, response, NULL, ast_free);
149 struct ast_variable *i;
150 RAII_VAR(struct ast_websocket *, s, ws_session, ast_websocket_unref);
152
154
155 response = ast_calloc(1, sizeof(*response));
156 if (!response) {
157 ast_log(LOG_ERROR, "Failed to create response.\n");
158 goto fin;
159 }
160
161#if defined(AST_DEVMODE)
164#else
166#endif
167 if (!session) {
168 ast_log(LOG_ERROR, "Failed to create ARI session\n");
169 goto fin;
170 }
171
172 for (i = get_params; i; i = i->next) {
173 if (strcmp(i->name, "app") == 0) {
174 /* Parse comma separated list */
175 char *vals[MAX_VALS];
176 size_t j;
177
178 args.app_parse = ast_strdup(i->value);
179 if (!args.app_parse) {
181 goto fin;
182 }
183
184 if (strlen(args.app_parse) == 0) {
185 /* ast_app_separate_args can't handle "" */
186 args.app_count = 1;
187 vals[0] = args.app_parse;
188 } else {
189 args.app_count = ast_app_separate_args(
190 args.app_parse, ',', vals,
191 ARRAY_LEN(vals));
192 }
193
194 if (args.app_count == 0) {
196 goto fin;
197 }
198
199 if (args.app_count >= MAX_VALS) {
200 ast_ari_response_error(response, 400,
201 "Bad Request",
202 "Too many values for app");
203 goto fin;
204 }
205
206 args.app = ast_malloc(sizeof(*args.app) * args.app_count);
207 if (!args.app) {
209 goto fin;
210 }
211
212 for (j = 0; j < args.app_count; ++j) {
213 args.app[j] = (vals[j]);
214 }
215 } else
216 if (strcmp(i->name, "subscribeAll") == 0) {
217 args.subscribe_all = ast_true(i->value);
218 } else
219 {}
220 }
221
223
224fin: __attribute__((unused))
225 if (response && response->response_code != 0) {
226 /* Param parsing failure */
227 RAII_VAR(char *, msg, NULL, ast_json_free);
228 if (response->message) {
229 msg = ast_json_dump_string(response->message);
230 } else {
231 ast_log(LOG_ERROR, "Missing response message\n");
232 }
233 if (msg) {
234 ast_websocket_write(ws_session,
235 AST_WEBSOCKET_OPCODE_TEXT, msg, strlen(msg));
236 }
237 }
238 ast_free(args.app_parse);
239 ast_free(args.app);
240}
242 struct ast_json *body,
244{
245 struct ast_json *field;
246 /* Parse query parameters out of it */
247 field = ast_json_object_get(body, "application");
248 if (field) {
249 args->application = ast_json_string_get(field);
250 }
251 field = ast_json_object_get(body, "source");
252 if (field) {
253 /* If they were silly enough to both pass in a query param and a
254 * JSON body, free up the query value.
255 */
256 ast_free(args->source);
257 if (ast_json_typeof(field) == AST_JSON_ARRAY) {
258 /* Multiple param passed as array */
259 size_t i;
260 args->source_count = ast_json_array_size(field);
261 args->source = ast_malloc(sizeof(*args->source) * args->source_count);
262
263 if (!args->source) {
264 return -1;
265 }
266
267 for (i = 0; i < args->source_count; ++i) {
268 args->source[i] = ast_json_string_get(ast_json_array_get(field, i));
269 }
270 } else {
271 /* Multiple param passed as single value */
272 args->source_count = 1;
273 args->source = ast_malloc(sizeof(*args->source) * args->source_count);
274 if (!args->source) {
275 return -1;
276 }
277 args->source[0] = ast_json_string_get(field);
278 }
279 }
280 return 0;
281}
282
283/*!
284 * \brief Parameter parsing callback for /events/user/{eventName}.
285 * \param ser TCP/TLS session object
286 * \param get_params GET parameters in the HTTP request.
287 * \param path_vars Path variables extracted from the request.
288 * \param headers HTTP headers.
289 * \param body
290 * \param[out] response Response to the HTTP request.
291 */
293 struct ast_tcptls_session_instance *ser,
294 struct ast_variable *get_params, struct ast_variable *path_vars,
295 struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
296{
298 struct ast_variable *i;
299#if defined(AST_DEVMODE)
300 int is_valid;
301 int code;
302#endif /* AST_DEVMODE */
303
304 for (i = get_params; i; i = i->next) {
305 if (strcmp(i->name, "application") == 0) {
306 args.application = (i->value);
307 } else
308 if (strcmp(i->name, "source") == 0) {
309 /* Parse comma separated list */
310 char *vals[MAX_VALS];
311 size_t j;
312
313 args.source_parse = ast_strdup(i->value);
314 if (!args.source_parse) {
316 goto fin;
317 }
318
319 if (strlen(args.source_parse) == 0) {
320 /* ast_app_separate_args can't handle "" */
321 args.source_count = 1;
322 vals[0] = args.source_parse;
323 } else {
324 args.source_count = ast_app_separate_args(
325 args.source_parse, ',', vals,
326 ARRAY_LEN(vals));
327 }
328
329 if (args.source_count == 0) {
331 goto fin;
332 }
333
334 if (args.source_count >= MAX_VALS) {
335 ast_ari_response_error(response, 400,
336 "Bad Request",
337 "Too many values for source");
338 goto fin;
339 }
340
341 args.source = ast_malloc(sizeof(*args.source) * args.source_count);
342 if (!args.source) {
344 goto fin;
345 }
346
347 for (j = 0; j < args.source_count; ++j) {
348 args.source[j] = (vals[j]);
349 }
350 } else
351 {}
352 }
353 for (i = path_vars; i; i = i->next) {
354 if (strcmp(i->name, "eventName") == 0) {
355 args.event_name = (i->value);
356 } else
357 {}
358 }
359 args.variables = body;
360 ast_ari_events_user_event(headers, &args, response);
361#if defined(AST_DEVMODE)
362 code = response->response_code;
363
364 switch (code) {
365 case 0: /* Implementation is still a stub, or the code wasn't set */
366 is_valid = response->message == NULL;
367 break;
368 case 500: /* Internal Server Error */
369 case 501: /* Not Implemented */
370 case 404: /* Application does not exist. */
371 case 422: /* Event source not found. */
372 case 400: /* Invalid even tsource URI or userevent data. */
373 is_valid = 1;
374 break;
375 default:
376 if (200 <= code && code <= 299) {
377 is_valid = ast_ari_validate_void(
378 response->message);
379 } else {
380 ast_log(LOG_ERROR, "Invalid error response %d for /events/user/{eventName}\n", code);
381 is_valid = 0;
382 }
383 }
384
385 if (!is_valid) {
386 ast_log(LOG_ERROR, "Response validation failed for /events/user/{eventName}\n");
387 ast_ari_response_error(response, 500,
388 "Internal Server Error", "Response validation failed");
389 }
390#endif /* AST_DEVMODE */
391
392fin: __attribute__((unused))
393 ast_free(args.source_parse);
394 ast_free(args.source);
395 return;
396}
397
398/*! \brief REST handler for /api-docs/events.json */
400 .path_segment = "eventName",
401 .is_wildcard = 1,
402 .callbacks = {
404 },
405 .num_children = 0,
406 .children = { }
407};
408/*! \brief REST handler for /api-docs/events.json */
410 .path_segment = "user",
411 .callbacks = {
412 },
413 .num_children = 1,
414 .children = { &events_user_eventName, }
415};
416/*! \brief REST handler for /api-docs/events.json */
418 .path_segment = "events",
419 .callbacks = {
420 },
421 .num_children = 1,
422 .children = { &events_user, }
423};
424
425static int unload_module(void)
426{
431 return 0;
432}
433
434static int load_module(void)
435{
436 int res = 0;
437
438 struct ast_websocket_protocol *protocol;
439
442 }
443
445 if (!events.ws_server) {
448 }
449
450 protocol = ast_websocket_sub_protocol_alloc("ari");
451 if (!protocol) {
456 }
460
462 if (res) {
465 }
466
468}
469
470AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "RESTful API module - WebSocket resource",
471 .support_level = AST_MODULE_SUPPORT_CORE,
472 .load = load_module,
473 .unload = unload_module,
474 .requires = "res_ari,res_ari_model,res_stasis,res_http_websocket",
struct ast_ari_websocket_session * ast_ari_websocket_session_create(struct ast_websocket *ws_session, int(*validator)(struct ast_json *))
Create an ARI WebSocket session.
int ast_ari_remove_handler(struct stasis_rest_handlers *handler)
Definition: res_ari.c:202
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:259
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:298
int ast_ari_add_handler(struct stasis_rest_handlers *handler)
Definition: res_ari.c:179
ari_validator ast_ari_validate_message_fn(void)
Function pointer to ast_ari_validate_message().
Generated file - Build validators for ARI model objects.
int ast_ari_validate_void(struct ast_json *json)
Validator for native Swagger void.
Definition: res_ari_model.c:91
Asterisk main include file. File version handling, generic pbx functions.
static struct ast_mansession session
#define ast_free(a)
Definition: astmm.h:180
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:241
#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_cleanup(obj)
Definition: astobj2.h:1934
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
@ AST_HTTP_POST
Definition: http.h:61
void ast_http_error(struct ast_tcptls_session_instance *ser, int status, const char *title, const char *text)
Send HTTP error message and close socket.
Definition: http.c:651
Support for WebSocket connections within the Asterisk HTTP server and client WebSocket connections to...
struct ast_websocket_protocol * ast_websocket_sub_protocol_alloc(const char *name)
Allocate a websocket sub-protocol instance.
@ AST_WEBSOCKET_OPCODE_TEXT
void ast_websocket_unref(struct ast_websocket *session)
Decrease the reference count for a WebSocket session.
int ast_websocket_server_add_protocol2(struct ast_websocket_server *server, struct ast_websocket_protocol *protocol)
Add a sub-protocol handler to the given server.
struct ast_websocket_server * ast_websocket_server_create(void)
Creates a ast_websocket_server.
int ast_websocket_write(struct ast_websocket *session, enum ast_websocket_opcode opcode, char *payload, uint64_t payload_size)
Construct and transmit a WebSocket frame.
Application convenience functions, designed to give consistent look and feel to Asterisk apps.
#define ast_app_separate_args(a, b, c, d)
#define LOG_ERROR
enum ast_json_type ast_json_typeof(const struct ast_json *value)
Get the type of value.
Definition: json.c:78
void ast_json_free(void *p)
Asterisk's custom JSON allocator. Exposed for use by unit tests.
Definition: json.c:52
struct ast_json * ast_json_array_get(const struct ast_json *array, size_t index)
Get an element from an array.
Definition: json.c:370
#define ast_json_dump_string(root)
Encode a JSON value to a compact string.
Definition: json.h:810
@ AST_JSON_ARRAY
Definition: json.h:165
const char * ast_json_string_get(const struct ast_json *string)
Get the value of a JSON string.
Definition: json.c:283
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
size_t ast_json_array_size(const struct ast_json *array)
Get the size of a JSON array.
Definition: json.c:366
Asterisk module definitions.
#define SCOPED_MODULE_USE(module)
Definition: module.h:665
@ AST_MODFLAG_DEFAULT
Definition: module.h:315
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
Definition: module.h:543
@ AST_MODULE_SUPPORT_CORE
Definition: module.h:121
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
@ AST_MODULE_LOAD_SUCCESS
Definition: module.h:70
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
int ast_ari_events_user_event_parse_body(struct ast_json *body, struct ast_ari_events_user_event_args *args)
Body parsing function for /events/user/{eventName}.
static void ast_ari_events_event_websocket_ws_established_cb(struct ast_websocket *ws_session, struct ast_variable *get_params, struct ast_variable *headers)
static struct stasis_rest_handlers events
REST handler for /api-docs/events.json.
static struct stasis_rest_handlers events_user_eventName
REST handler for /api-docs/events.json.
#define MAX_VALS
static int ast_ari_events_event_websocket_ws_attempted_cb(struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *headers, const char *session_id)
static struct stasis_rest_handlers events_user
REST handler for /api-docs/events.json.
static void ast_ari_events_user_event_cb(struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
Parameter parsing callback for /events/user/{eventName}.
static int load_module(void)
static int unload_module(void)
#define NULL
Definition: resample.c:96
void ast_ari_websocket_events_event_websocket_established(struct ast_ari_websocket_session *ws_session, struct ast_variable *headers, struct ast_ari_events_event_websocket_args *args)
WebSocket connection for events.
void ast_ari_events_user_event(struct ast_variable *headers, struct ast_ari_events_user_event_args *args, struct ast_ari_response *response)
Generate a user event.
int ast_ari_websocket_events_event_websocket_attempted(struct ast_tcptls_session_instance *ser, struct ast_variable *headers, struct ast_ari_events_event_websocket_args *args, const char *session_id)
WebSocket connection for events.
int ast_ari_websocket_events_event_websocket_init(void)
WebSocket connection for events.
void ast_ari_websocket_events_event_websocket_dtor(void)
WebSocket connection for events.
Generated file - declares stubs to be implemented in res/ari/resource_events.c.
Stasis Application API. See Stasis Application API for detailed documentation.
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true"....
Definition: utils.c:2199
struct ast_json * message
Definition: ari.h:94
int response_code
Definition: ari.h:99
Abstract JSON element (object, array, string, int, ...).
struct ast_module * self
Definition: module.h:342
describes a server instance
Definition: tcptls.h:150
Structure for variables, used for configurations and for channel variables.
struct ast_variable * next
A websocket protocol implementation.
ast_websocket_callback session_established
Callback called when a new session is established. Mandatory.
ast_websocket_pre_callback session_attempted
Callback called when a new session is attempted. Optional.
Structure definition for session.
Handler for a single RESTful path segment.
Definition: ari.h:69
const char * path_segment
Definition: ari.h:71
struct ast_websocket_server * ws_server
Definition: ari.h:82
const char * args
#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:941
#define ARRAY_LEN(a)
Definition: utils.h:666