24#if defined(AST_DEVMODE)
42#define ARI_WS_SESSION_NUM_BUCKETS 23
45#define APPS_NUM_BUCKETS 7
48#define MESSAGES_INIT_SIZE 23
66#define VALIDATION_FAILED \
68 " \"error\": \"InvalidMessage\"," \
69 " \"message\": \"Message validation failed\"" \
93 ast_log(
LOG_NOTICE,
"Problem occurred during websocket write to %s, websocket closed\n",
118 if (ast_ws_session ==
NULL) {
128 "ARI web socket failed to set nonblock; closing: %s\n",
135 config->general->write_timeout);
165 uint64_t payload_len;
179 &payload_len, &opcode, &fragmented);
195 "{s:s, s:s, s:s, s:i, s:s, s:s }",
196 "type",
"RESTResponse",
197 "transaction_id",
"",
200 "reason_phrase",
"Failed to parse request message JSON",
207 "WebSocket input failed to parse\n");
249 const char *msg_type, *msg_application, *
msg_timestamp, *msg_ast_id;
257 msg_application =
S_OR(
262 if (strcmp(msg_type,
"ApplicationReplaced") == 0 &&
263 strcmp(msg_application,
app_name) == 0) {
274 "%s: Failed to dispatch '%s' message from Stasis app '%s'; could not update message\n",
275 remote_addr, msg_type, msg_application);
288 "%s: Failed to dispatch '%s' message from Stasis app '%s'; could not update message\n",
289 remote_addr, msg_type, msg_application);
297 "%s: Failed to dispatch '%s' message from Stasis app '%s'; could not update message\n",
298 remote_addr, msg_type, msg_application);
307 "%s: Queued '%s' message for Stasis app '%s'; websocket is not ready\n",
316 ast_verbose(
"<--- Sending ARI event to %s --->\n%s\n",
326 SCOPE_EXIT(
"%s: Dispatched '%s' message from Stasis app '%s'\n",
346 for (i = get_params; i; i = i->
next) {
347 if (strcmp(i->
name,
"app") == 0) {
358 if (strlen(app_parse) == 0) {
364 app_parse,
',', vals,
368 if (
args->app_count == 0) {
376 "Too many values for app");
386 for (j = 0; j <
args->app_count; ++j) {
387 args->app[j] = (vals[j]);
389 }
else if (strcmp(i->
name,
"subscribeAll") == 0) {
394 args->app_parse = app_parse;
491 size =
sizeof(*ari_ws_session) + strlen(
session_id) + 1;
501 "Allocation failed");
512 "Allocation failed");
519 "Allocation failed");
525 if (
args->subscribe_all) {
531 for (i = 0; i <
args->app_count; ++i) {
532 const char *
app =
args->app[i];
536 "Invalid application provided in param [app].");
543 "Allocation failed");
551 "Stasis registration failed");
566 "Allocation failed");
591 ast_http_error(ser, 500,
"Server Error",
"Memory allocation error");
599 if (response->message) {
606 ast_http_error(ser, response->response_code, response->response_text, msg);
611 if (
args.app_count == 0) {
613 "HTTP request is missing param: [app]");
617#if defined(AST_DEVMODE)
619 ser, &
args, session_id);
625 "%s: Failed to create ARI ari_session\n", remote_addr);
655 SCOPE_ENTER(2,
"%s: WebSocket established\n", remote_addr);
658 ast_trace(2,
"%s: Websocket Upgrade Headers:\n", remote_addr);
659 for (v = upgrade_headers; v; v = v->
next) {
667 "%s: Failed to create response\n", remote_addr);
677 "%s: Failed to locate an event session for the websocket session\n",
681 ast_trace(-1,
"%s: Waiting for messages\n", remote_addr);
688 SCOPE_EXIT(
"%s: Websocket closed\n", remote_addr);
729 NULL, ari_ws_session_cmp_fn);
732 "Failed to allocate the local registry for websocket applications\n");
Asterisk RESTful API hooks.
enum ast_json_encoding_format ast_ari_json_format(void)
Configured encoding format for JSON output.
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.
void ast_ari_response_alloc_failed(struct ast_ari_response *response)
Fill in response with a 500 message for allocation failures.
ari_validator ast_ari_validate_message_fn(void)
Function pointer to ast_ari_validate_message().
Generated file - Build validators for ARI model objects.
int ari_websocket_process_request(struct ari_ws_session *ari_ws_session, const char *remote_addr, struct ast_variable *upgrade_headers, const char *app_name, struct ast_json *request_msg)
AO2_STRING_FIELD_CMP_FN(ari_ws_session, session_id)
static int null_validator(struct ast_json *json)
Validator that always succeeds.
static int ari_ws_session_create(int(*validator)(struct ast_json *), struct ast_tcptls_session_instance *ser, struct ast_ari_events_event_websocket_args *args, const char *session_id)
static int ari_ws_session_update(struct ari_ws_session *ari_ws_session, struct ast_websocket *ast_ws_session)
static void ari_ws_session_reset(struct ari_ws_session *ari_ws_session)
static void stasis_app_message_handler(void *data, const char *app_name, struct ast_json *message)
static int websocket_attempted_cb(struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *headers, const char *session_id)
#define MESSAGES_INIT_SIZE
static int parse_app_args(struct ast_variable *get_params, struct ast_ari_response *response, struct ast_ari_events_event_websocket_args *args)
static struct ao2_container * ari_ws_session_registry
Local registry for created event_session objects.
static void ari_ws_session_dtor(void *obj)
void ari_websocket_send_event(struct ari_ws_session *ari_ws_session, const char *app_name, struct ast_json *message, int debug_app)
Callback handler for Stasis application messages.
AO2_STRING_FIELD_HASH_FN(ari_ws_session, session_id)
static void websocket_established_cb(struct ast_websocket *ast_ws_session, struct ast_variable *get_params, struct ast_variable *upgrade_headers)
struct ast_websocket_server * ast_ws_server
static void ari_ws_session_registry_dtor(void)
int ari_websocket_unload_module(void)
void ari_handle_websocket(struct ast_tcptls_session_instance *ser, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers)
Wrapper for invoking the websocket code for an incoming connection.
static int ari_ws_session_shutdown_cb(void *ari_ws_session, void *arg, int flags)
static int ari_ws_session_write(struct ari_ws_session *ari_ws_session, struct ast_json *message)
#define VALIDATION_FAILED
#define ARI_WS_SESSION_NUM_BUCKETS
int ari_websocket_load_module(void)
static void ari_ws_session_cleanup(struct ari_ws_session *ari_ws_session)
static struct ast_json * ari_ws_session_read(struct ari_ws_session *ari_ws_session)
Internal API's for websockets.
Asterisk main include file. File version handling, generic pbx functions.
#define ast_strdup(str)
A wrapper for strdup()
#define ast_calloc(num, len)
A wrapper for calloc()
#define ast_malloc(len)
A wrapper for malloc()
#define ao2_iterator_next(iter)
#define ao2_link(container, obj)
Add an object to a container.
@ AO2_ALLOC_OPT_LOCK_MUTEX
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container,...
#define ao2_unlink(container, obj)
Remove an object from a container.
#define ao2_find(container, arg, flags)
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.
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
@ OBJ_SEARCH_KEY
The arg parameter is a search key, but is not an object.
#define ao2_alloc(data_size, destructor_fn)
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Allocate and initialize a hash container with the desired number of buckets.
static const char config[]
void ast_verbose(const char *fmt,...)
#define TRACE_ATLEAST(level)
#define SCOPE_ENTER(level,...)
#define SCOPE_EXIT_LOG_RTN(__log_level,...)
#define ast_trace(level,...)
ast_http_method
HTTP Request methods known by Asterisk.
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.
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.
int ast_websocket_set_timeout(struct ast_websocket *session, int timeout)
Set the timeout on a non-blocking WebSocket session.
int ast_websocket_set_nonblock(struct ast_websocket *session)
Set the socket of a WebSocket session to be non-blocking.
const char * ast_websocket_session_id(struct ast_websocket *session)
Get the session ID for a WebSocket session.
int ast_websocket_read(struct ast_websocket *session, char **payload, uint64_t *payload_len, enum ast_websocket_opcode *opcode, int *fragmented)
Read a WebSocket frame and handle it.
struct ast_sockaddr * ast_websocket_remote_address(struct ast_websocket *session)
Get the remote address for a WebSocket connected session.
ast_websocket_opcode
WebSocket operation codes.
@ AST_WEBSOCKET_OPCODE_CLOSE
@ AST_WEBSOCKET_OPCODE_TEXT
void ast_websocket_unref(struct ast_websocket *session)
Decrease the reference count for a WebSocket session.
int ast_websocket_uri_cb(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_vars, struct ast_variable *headers)
Callback suitable for use with a ast_http_uri.
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.
int ast_websocket_write_string(struct ast_websocket *ws, const char *buf)
Construct and transmit a WebSocket frame containing string data.
int ast_websocket_fd(struct ast_websocket *session)
Get the file descriptor for a WebSocket session.
struct ast_websocket_server * ast_websocket_server_create(void)
Creates a ast_websocket_server.
Application convenience functions, designed to give consistent look and feel to Asterisk apps.
#define ast_app_separate_args(a, b, c, d)
#define ast_debug(level,...)
Log a DEBUG message.
Internal API's for res_ari.
struct ast_json * ast_json_string_create(const char *value)
Construct a JSON string from value.
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
void ast_json_free(void *p)
Asterisk's custom JSON allocator. Exposed for use by unit tests.
#define ast_json_dump_string(root)
Encode a JSON value to a compact string.
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
struct ast_json * ast_json_timeval(const struct timeval tv, const char *zone)
Construct a timeval as JSON.
struct ast_json * ast_json_ref(struct ast_json *value)
Increase refcount on value.
int ast_json_object_set(struct ast_json *object, const char *key, struct ast_json *value)
Set a field in a JSON object.
struct ast_json * ast_json_load_buf(const char *buffer, size_t buflen, struct ast_json_error *error)
Parse buffer with known length into a JSON object or array.
const char * ast_json_string_get(const struct ast_json *string)
Get the value of a JSON string.
struct ast_json * ast_json_object_get(struct ast_json *object, const char *key)
Get a field from a JSON object.
char * ast_json_dump_string_format(struct ast_json *root, enum ast_json_encoding_format format)
Encode a JSON value to a string.
#define SCOPED_AO2LOCK(varname, obj)
scoped lock specialization for ao2 mutexes.
Asterisk module definitions.
@ AST_MODULE_LOAD_SUCCESS
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
static char * ast_sockaddr_stringify(const struct ast_sockaddr *addr)
Wrapper around ast_sockaddr_stringify_fmt() with default format.
const char * app_name(struct ast_app *app)
struct ast_ari_conf * ast_ari_config_get(void)
Get the current ARI configuration.
static struct timeval msg_timestamp(void *msg, enum smdi_message_type type)
Generated file - declares stubs to be implemented in res/ari/resource_events.c.
Stasis Application API. See Stasis Application API for detailed documentation.
int stasis_app_event_allowed(const char *app_name, struct ast_json *event)
Check if the given event should be filtered.
int stasis_app_register(const char *app_name, stasis_app_cb handler, void *data)
Register a new Stasis application.
void(* stasis_app_cb)(void *data, const char *app_name, struct ast_json *message)
Callback for Stasis application handler.
void stasis_app_unregister(const char *app_name)
Unregister a Stasis application and unsubscribe from all event sources.
int stasis_app_register_all(const char *app_name, stasis_app_cb handler, void *data)
Register a new Stasis application that receives all Asterisk events.
int stasis_app_get_debug_by_name(const char *app_name)
Get debug status of an application.
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one.
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true"....
static force_inline int attribute_pure ast_strlen_zero(const char *s)
#define ast_str_container_alloc(buckets)
Allocates a hash container for bare strings.
int ast_str_container_add(struct ao2_container *str_container, const char *add)
Adds a string to a string container allocated by ast_str_container_alloc.
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
struct ari_ws_session::@424 message_queue
struct ao2_container * websocket_apps
struct ast_websocket * ast_ws_session
int(* validator)(struct ast_json *)
All configuration options for ARI.
Definition of a URI handler.
Abstract JSON element (object, array, string, int, ...).
describes a server instance
struct ast_sockaddr remote_address
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 for a WebSocket server.
Structure definition for session.
static void handler(const char *name, int response_code, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
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.
int ast_wait_for_input(int fd, int ms)
char * ast_eid_to_str(char *s, int maxlen, struct ast_eid *eid)
Convert an EID to a string.
struct ast_eid ast_eid_default
Global EID.
#define AST_VECTOR_RESET(vec, cleanup)
Reset vector.
#define AST_VECTOR_ELEM_CLEANUP_NOOP(elem)
Vector element cleanup that does nothing.
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.