Asterisk - The Open Source Telephony Project GIT-master-a358458
Macros | Functions | Variables
res_ari_events.c File Reference

WebSocket resource. More...

#include "asterisk.h"
#include "asterisk/app.h"
#include "asterisk/module.h"
#include "asterisk/stasis_app.h"
#include "ari/resource_events.h"
#include "asterisk/http_websocket.h"
Include dependency graph for res_ari_events.c:

Go to the source code of this file.

Macros

#define MAX_VALS   128
 

Functions

static void __reg_module (void)
 
static void __unreg_module (void)
 
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 void ast_ari_events_event_websocket_ws_established_cb (struct ast_websocket *ws_session, struct ast_variable *get_params, struct ast_variable *headers)
 
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}. More...
 
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}. More...
 
struct ast_moduleAST_MODULE_SELF_SYM (void)
 
static int load_module (void)
 
static int unload_module (void)
 

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "RESTful API module - WebSocket resource" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .requires = "res_ari,res_ari_model,res_stasis,res_http_websocket", }
 
static const struct ast_module_infoast_module_info = &__mod_info
 
static struct stasis_rest_handlers events
 REST handler for /api-docs/events.json. More...
 
static struct stasis_rest_handlers events_user
 REST handler for /api-docs/events.json. More...
 
static struct stasis_rest_handlers events_user_eventName
 REST handler for /api-docs/events.json. More...
 

Detailed Description

WebSocket resource.

Author
David M. Lee, II dlee@.nosp@m.digi.nosp@m.um.co.nosp@m.m

Definition in file res_ari_events.c.

Macro Definition Documentation

◆ MAX_VALS

#define MAX_VALS   128

Definition at line 53 of file res_ari_events.c.

Function Documentation

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 475 of file res_ari_events.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 475 of file res_ari_events.c.

◆ ast_ari_events_event_websocket_ws_attempted_cb()

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

Definition at line 55 of file res_ari_events.c.

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}
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
#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
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
#define ast_app_separate_args(a, b, c, d)
#define LOG_ERROR
void ast_json_free(void *p)
Asterisk's custom JSON allocator. Exposed for use by unit tests.
Definition: json.c:52
#define ast_json_dump_string(root)
Encode a JSON value to a compact string.
Definition: json.h:810
#define MAX_VALS
#define NULL
Definition: resample.c:96
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 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
Structure for variables, used for configurations and for channel variables.
struct ast_variable * next
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

References args, ARRAY_LEN, ast_app_separate_args, ast_ari_response_alloc_failed(), ast_ari_response_error(), ast_ari_websocket_events_event_websocket_attempted(), ast_calloc, ast_free, ast_http_error(), ast_json_dump_string, ast_json_free(), ast_log, ast_malloc, ast_strdup, ast_true(), LOG_ERROR, MAX_VALS, ast_variable::name, ast_variable::next, NULL, RAII_VAR, and ast_variable::value.

Referenced by load_module().

◆ ast_ari_events_event_websocket_ws_established_cb()

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

Definition at line 144 of file res_ari_events.c.

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}
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.
ari_validator ast_ari_validate_message_fn(void)
Function pointer to ast_ari_validate_message().
static struct ast_mansession session
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
@ AST_WEBSOCKET_OPCODE_TEXT
void ast_websocket_unref(struct ast_websocket *session)
Decrease the reference count for a WebSocket session.
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.
#define SCOPED_MODULE_USE(module)
Definition: module.h:665
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.
struct ast_module * self
Definition: module.h:342
Structure definition for session.

References ao2_cleanup, args, ARRAY_LEN, ast_app_separate_args, ast_ari_response_alloc_failed(), ast_ari_response_error(), ast_ari_validate_message_fn(), ast_ari_websocket_events_event_websocket_established(), ast_ari_websocket_session_create(), ast_calloc, ast_free, ast_json_dump_string, ast_json_free(), ast_log, ast_malloc, ast_strdup, ast_true(), AST_WEBSOCKET_OPCODE_TEXT, ast_websocket_unref(), ast_websocket_write(), LOG_ERROR, MAX_VALS, ast_variable::name, ast_variable::next, NULL, RAII_VAR, SCOPED_MODULE_USE, ast_module_info::self, session, and ast_variable::value.

Referenced by load_module().

◆ ast_ari_events_user_event_cb()

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 
)
static

Parameter parsing callback for /events/user/{eventName}.

Parameters
serTCP/TLS session object
get_paramsGET parameters in the HTTP request.
path_varsPath variables extracted from the request.
headersHTTP headers.
body
[out]responseResponse to the HTTP request.

Definition at line 292 of file res_ari_events.c.

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}
int ast_ari_validate_void(struct ast_json *json)
Validator for native Swagger void.
Definition: res_ari_model.c:91
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.
struct ast_json * message
Definition: ari.h:94
int response_code
Definition: ari.h:99

References args, ARRAY_LEN, ast_app_separate_args, ast_ari_events_user_event(), ast_ari_response_alloc_failed(), ast_ari_response_error(), ast_ari_validate_void(), ast_free, ast_log, ast_malloc, ast_strdup, LOG_ERROR, MAX_VALS, ast_ari_response::message, ast_variable::name, ast_variable::next, NULL, ast_ari_response::response_code, and ast_variable::value.

◆ ast_ari_events_user_event_parse_body()

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}.

Parameters
bodyThe JSON body from which to parse parameters.
[out]argsThe args structure to parse into.
Return values
zeroon success
non-zeroon failure

Definition at line 241 of file res_ari_events.c.

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}
enum ast_json_type ast_json_typeof(const struct ast_json *value)
Get the type of value.
Definition: json.c:78
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
@ 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
Abstract JSON element (object, array, string, int, ...).

References args, ast_free, AST_JSON_ARRAY, ast_json_array_get(), ast_json_array_size(), ast_json_object_get(), ast_json_string_get(), ast_json_typeof(), and ast_malloc.

Referenced by ast_ari_events_user_event().

◆ AST_MODULE_SELF_SYM()

struct ast_module * AST_MODULE_SELF_SYM ( void  )

Definition at line 475 of file res_ari_events.c.

◆ load_module()

static int load_module ( void  )
static

Definition at line 434 of file res_ari_events.c.

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}
int ast_ari_add_handler(struct stasis_rest_handlers *handler)
Definition: res_ari.c:179
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
struct ast_websocket_protocol * ast_websocket_sub_protocol_alloc(const char *name)
Allocate a websocket sub-protocol instance.
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.
@ 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
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 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 int unload_module(void)
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.
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.
struct ast_websocket_server * ws_server
Definition: ari.h:82

References ao2_ref, ast_ari_add_handler(), ast_ari_events_event_websocket_ws_attempted_cb(), ast_ari_events_event_websocket_ws_established_cb(), ast_ari_websocket_events_event_websocket_dtor(), ast_ari_websocket_events_event_websocket_init(), AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, ast_websocket_server_add_protocol2(), ast_websocket_server_create(), ast_websocket_sub_protocol_alloc(), events, NULL, ast_websocket_protocol::session_attempted, ast_websocket_protocol::session_established, unload_module(), and stasis_rest_handlers::ws_server.

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 425 of file res_ari_events.c.

426{
431 return 0;
432}
int ast_ari_remove_handler(struct stasis_rest_handlers *handler)
Definition: res_ari.c:202

References ao2_cleanup, ast_ari_remove_handler(), ast_ari_websocket_events_event_websocket_dtor(), events, NULL, and stasis_rest_handlers::ws_server.

Referenced by load_module().

Variable Documentation

◆ __mod_info

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "RESTful API module - WebSocket resource" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .requires = "res_ari,res_ari_model,res_stasis,res_http_websocket", }
static

Definition at line 475 of file res_ari_events.c.

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 475 of file res_ari_events.c.

◆ events

struct stasis_rest_handlers events
static

REST handler for /api-docs/events.json.

Definition at line 417 of file res_ari_events.c.

Referenced by load_module(), and unload_module().

◆ events_user

struct stasis_rest_handlers events_user
static

REST handler for /api-docs/events.json.

Definition at line 409 of file res_ari_events.c.

◆ events_user_eventName

struct stasis_rest_handlers events_user_eventName
static

REST handler for /api-docs/events.json.

Definition at line 399 of file res_ari_events.c.