Asterisk - The Open Source Telephony Project GIT-master-c753fe4
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros Modules Pages
Data Structures | Macros | Functions
ari_websockets.h File Reference

Internal API's for websockets. More...

#include "asterisk/http.h"
#include "asterisk/json.h"
#include "asterisk/vector.h"
#include "asterisk/websocket_client.h"
Include dependency graph for ari_websockets.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  ari_ws_session
 

Macros

#define ARI_MAX_APP_NAME_LEN   (AST_MAX_CONTEXT - STASIS_CONTEXT_PREFIX_LEN)
 
#define STASIS_CONTEXT_PREFIX   "stasis-"
 
#define STASIS_CONTEXT_PREFIX_LEN   (sizeof(STASIS_CONTEXT_PREFIX) - 1)
 

Functions

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. More...
 
int ari_outbound_websocket_start (struct ari_conf_outbound_websocket *owc)
 
struct ari_ws_sessionari_websocket_get_session (const char *session_id)
 
struct ari_ws_sessionari_websocket_get_session_by_app (const char *app_name)
 
struct ao2_containerari_websocket_get_sessions (void)
 
int ari_websocket_load_module (int is_enabled)
 
int ari_websocket_process_request (struct ari_ws_session *ast_ws_session, const char *remote_addr, struct ast_variable *upgrade_headers, const char *app_name, struct ast_json *msg)
 
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. More...
 
void ari_websocket_shutdown (struct ari_ws_session *session)
 
void ari_websocket_shutdown_all (void)
 
const char * ari_websocket_type_to_str (enum ast_websocket_type type)
 
int ari_websocket_unload_module (void)
 

Detailed Description

Internal API's for websockets.

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

Definition in file ari_websockets.h.

Macro Definition Documentation

◆ ARI_MAX_APP_NAME_LEN

#define ARI_MAX_APP_NAME_LEN   (AST_MAX_CONTEXT - STASIS_CONTEXT_PREFIX_LEN)

Definition at line 48 of file ari_websockets.h.

◆ STASIS_CONTEXT_PREFIX

#define STASIS_CONTEXT_PREFIX   "stasis-"

Definition at line 46 of file ari_websockets.h.

◆ STASIS_CONTEXT_PREFIX_LEN

#define STASIS_CONTEXT_PREFIX_LEN   (sizeof(STASIS_CONTEXT_PREFIX) - 1)

Definition at line 47 of file ari_websockets.h.

Function Documentation

◆ ari_handle_websocket()

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.

Parameters
ws_serverWebSocket server to invoke.
serHTTP session.
uriRequested URI.
methodRequested HTTP method.
get_paramsParsed query parameters.
headersParsed HTTP headers.

Definition at line 267 of file ari_websockets.c.

271{
272 struct ast_http_uri fake_urih = {
274 };
275
276 ast_websocket_uri_cb(ser, &fake_urih, uri, method, get_params,
277 headers);
278}
struct ast_websocket_server * ast_ws_server
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.
const char * method
Definition: res_pjsip.c:1279
Definition of a URI handler.
Definition: http.h:102
const char * uri
Definition: http.h:105
void * data
Definition: http.h:116

References ast_websocket_uri_cb(), ast_ws_server, ast_http_uri::data, method, and ast_http_uri::uri.

Referenced by ast_ari_invoke().

◆ ari_outbound_websocket_start()

int ari_outbound_websocket_start ( struct ari_conf_outbound_websocket owc)

Definition at line 1479 of file ari_websockets.c.

1480{
1481 if (owc) {
1482 return outbound_session_create(owc, NULL, 0);
1483 }
1484 return -1;
1485}
static int outbound_session_create(void *obj, void *args, int flags)
#define NULL
Definition: resample.c:96

References NULL, and outbound_session_create().

Referenced by ari_start_owc().

◆ ari_websocket_get_session()

struct ari_ws_session * ari_websocket_get_session ( const char *  session_id)

Definition at line 887 of file ari_websockets.c.

888{
889 return ao2_find(session_registry, session_id, OBJ_SEARCH_KEY);
890}
static struct ao2_container * session_registry
Local registry for created ari_ws_session objects.
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1736
@ OBJ_SEARCH_KEY
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1101

References ao2_find, OBJ_SEARCH_KEY, ari_ws_session::session_id, and session_registry.

Referenced by ari_shut_session(), and outbound_session_create().

◆ ari_websocket_get_session_by_app()

struct ari_ws_session * ari_websocket_get_session_by_app ( const char *  app_name)

◆ ari_websocket_get_sessions()

struct ao2_container * ari_websocket_get_sessions ( void  )

Definition at line 1360 of file ari_websockets.c.

1361{
1362 return ao2_bump(session_registry);
1363}
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
Definition: astobj2.h:480

References ao2_bump, and session_registry.

Referenced by ari_show_sessions(), and ari_shut_session().

◆ ari_websocket_load_module()

int ari_websocket_load_module ( int  is_enabled)

Definition at line 1528 of file ari_websockets.c.

1529{
1530 int res = 0;
1531 struct ast_websocket_protocol *protocol;
1532
1533 ast_debug(2, "Initializing ARI websockets. Enabled: %s\n", is_enabled ? "yes" : "no");
1534
1537 ari_ws_session_sort_fn, ari_ws_session_cmp_fn);
1538 if (!session_registry) {
1540 "Failed to allocate the local registry for websocket applications\n");
1542 }
1543
1544 res = ari_sorcery_observer_add("outbound_websocket", &observer_callbacks);
1545 if (res < 0) {
1546 ast_log(LOG_WARNING, "Failed to register ARI websocket observer\n");
1549 }
1550
1551 /*
1552 * The global "enabled" flag only controls whether the REST and
1553 * inbound websockets are enabled. The outbound websocket
1554 * configs are always enabled.
1555 if (!is_enabled) {
1556 return AST_MODULE_LOAD_SUCCESS;
1557 }
1558 */
1559
1561 if (!ast_ws_server) {
1564 }
1565
1566 protocol = ast_websocket_sub_protocol_alloc("ari");
1567 if (!protocol) {
1570 }
1574
1576}
static struct ast_sorcery_observer observer_callbacks
static int websocket_attempted_cb(struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *headers, const char *session_id)
static void websocket_established_cb(struct ast_websocket *ast_ws_session, struct ast_variable *get_params, struct ast_variable *upgrade_headers)
int ari_websocket_unload_module(void)
#define ast_log
Definition: astobj2.c:42
@ AO2_ALLOC_OPT_LOCK_MUTEX
Definition: astobj2.h:363
#define ao2_container_alloc_rbtree(ao2_options, container_options, sort_fn, cmp_fn)
Allocate and initialize a red-black tree container.
Definition: astobj2.h:1349
@ AO2_CONTAINER_ALLOC_OPT_DUPS_REPLACE
Replace objects with duplicate keys in container.
Definition: astobj2.h:1211
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.
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_WARNING
@ 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 ari_sorcery_observer_add(const char *object_type, const struct ast_sorcery_observer *callbacks)
static int is_enabled(void)
Helper function to check if module is enabled.
Definition: res_ari.c:96
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.

References AO2_ALLOC_OPT_LOCK_MUTEX, AO2_CONTAINER_ALLOC_OPT_DUPS_REPLACE, ao2_container_alloc_rbtree, ari_sorcery_observer_add(), ari_websocket_unload_module(), ast_debug, ast_log, AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, ast_websocket_server_add_protocol2(), ast_websocket_server_create(), ast_websocket_sub_protocol_alloc(), ast_ws_server, is_enabled(), LOG_WARNING, observer_callbacks, ast_websocket_protocol::session_attempted, ast_websocket_protocol::session_established, session_registry, websocket_attempted_cb(), and websocket_established_cb().

Referenced by load_module().

◆ ari_websocket_process_request()

int ari_websocket_process_request ( struct ari_ws_session ast_ws_session,
const char *  remote_addr,
struct ast_variable upgrade_headers,
const char *  app_name,
struct ast_json msg 
)

Definition at line 261 of file ari_websocket_requests.c.

264{
265 int debug_app = stasis_app_get_debug_by_name(app_name);
267 struct ast_ari_response response = { .fd = -1, 0 };
268
269 SCOPE_ENTER(3, "%s: New WebSocket Msg\n", remote_addr);
270
271 if (TRACE_ATLEAST(3) || debug_app) {
272 char *str = ast_json_dump_string_format(request_msg, AST_JSON_PRETTY);
273 /* If we can't allocate a string, we can't respond to the client either. */
274 if (!str) {
275 SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_ERROR, "%s: Failed to dump JSON request\n",
276 remote_addr);
277 }
278 ast_verbose("<--- Received ARI message from %s --->\n%s\n",
279 remote_addr, str);
281 }
282
284 parse_rest_request_msg, remote_addr, request_msg, &response, debug_app);
285
286 if (!request || response.response_code != 200) {
288 remote_addr, app_name, request, &response, debug_app);
289 SCOPE_EXIT_RTN_VALUE(0, "%s: Done with message\n", remote_addr);
290 }
291
292 /*
293 * We don't actually use the headers in the response
294 * but we have to allocate it because ast_ari_invoke
295 * and the resource handlers expect it.
296 */
297 response.headers = ast_str_create(80);
298 if (!response.headers) {
299 /* If we can't allocate a string, we can't respond to the client either. */
300 SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_ERROR, "%s: Failed allocate headers string\n",
301 remote_addr);
302 }
303
305 NULL, request->uri, request->method, request->query_strings,
306 upgrade_headers, request->body, &response);
307
308 ast_free(response.headers);
309
310 if (response.no_response) {
311 SCOPE_EXIT_RTN_VALUE(0, "No response needed\n");
312 }
313
315 remote_addr, app_name, request, &response, debug_app);
316
317 SCOPE_EXIT_RTN_VALUE(0, "%s: Done with message\n", remote_addr);
318}
const char * str
Definition: app_jack.c:150
@ ARI_INVOKE_SOURCE_WEBSOCKET
Definition: ari.h:149
enum ast_ari_invoke_result ast_ari_invoke(struct ast_tcptls_session_instance *ser, enum ast_ari_invoke_source source, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
Definition: res_ari.c:528
static struct rest_request_msg * parse_rest_request_msg(const char *remote_addr, struct ast_json *request_msg, struct ast_ari_response *response, int debug_app)
static void request_destroy(struct rest_request_msg *request)
static void send_rest_response(struct ari_ws_session *ari_ws_session, const char *remote_addr, const char *app_name, struct rest_request_msg *request, struct ast_ari_response *response, int debug_app)
#define ast_free(a)
Definition: astmm.h:180
static int request(void *obj)
Definition: chan_pjsip.c:2611
void ast_verbose(const char *fmt,...)
Definition: extconf.c:2206
#define TRACE_ATLEAST(level)
#define SCOPE_EXIT_RTN_VALUE(__return_value,...)
#define SCOPE_EXIT_LOG_RTN_VALUE(__value, __log_level,...)
#define SCOPE_CALL_WITH_RESULT(level, __var, __funcname,...)
#define SCOPE_ENTER(level,...)
#define SCOPE_CALL(level, __funcname,...)
#define LOG_ERROR
void ast_json_free(void *p)
Asterisk's custom JSON allocator. Exposed for use by unit tests.
Definition: json.c:52
@ AST_JSON_PRETTY
Definition: json.h:795
char * ast_json_dump_string_format(struct ast_json *root, enum ast_json_encoding_format format)
Encode a JSON value to a string.
Definition: json.c:484
const char * app_name(struct ast_app *app)
Definition: pbx_app.c:463
int stasis_app_get_debug_by_name(const char *app_name)
Get debug status of an application.
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition: strings.h:659
struct ast_str * headers
Definition: ari.h:105
int response_code
Definition: ari.h:108
unsigned int no_response
Definition: ari.h:114
#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

References app_name(), ARI_INVOKE_SOURCE_WEBSOCKET, ast_ari_invoke(), ast_free, ast_json_dump_string_format(), ast_json_free(), AST_JSON_PRETTY, ast_str_create, ast_verbose(), ast_ari_response::fd, ast_ari_response::headers, LOG_ERROR, ast_ari_response::no_response, NULL, parse_rest_request_msg(), RAII_VAR, request(), request_destroy(), ast_ari_response::response_code, SCOPE_CALL, SCOPE_CALL_WITH_RESULT, SCOPE_ENTER, SCOPE_EXIT_LOG_RTN_VALUE, SCOPE_EXIT_RTN_VALUE, send_rest_response(), stasis_app_get_debug_by_name(), str, and TRACE_ATLEAST.

Referenced by outbound_session_handler_thread(), and websocket_established_cb().

◆ ari_websocket_send_event()

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.

Definition at line 290 of file ari_websockets.c.

292{
293 char *remote_addr = session->ast_ws_session ? ast_sockaddr_stringify(
294 ast_websocket_remote_address(session->ast_ws_session)) : "";
295 const char *msg_type, *msg_application;
296 SCOPE_ENTER(4, "%s: Dispatching message from Stasis app '%s'\n", remote_addr, app_name);
297
299
301
302 msg_type = S_OR(ast_json_string_get(ast_json_object_get(message, "type")), "");
303 msg_application = S_OR(
305
306 /* If we've been replaced, remove the application from our local
307 websocket_apps container */
308 if (session->type == AST_WS_TYPE_INBOUND
309 && strcmp(msg_type, "ApplicationReplaced") == 0 &&
310 strcmp(msg_application, app_name) == 0) {
311 AST_VECTOR_REMOVE_CMP_ORDERED(&session->websocket_apps,
313 }
314
315 /* Now, we need to determine our state to see how we will handle the message */
319 "%s: Failed to dispatch '%s' message from Stasis app '%s'; could not update message\n",
320 remote_addr, msg_type, msg_application);
321 }
322
325 app_name, debug_app);
326 }
327
329 && !ast_strlen_zero(session->channel_id)
330 && ast_strings_equal(msg_type, "StasisEnd")) {
331 struct ast_json *chan = ast_json_object_get(message, "channel");
332 struct ast_json *id_obj = ast_json_object_get(chan, "id");
333 const char *id = ast_json_string_get(id_obj);
334 if (!ast_strlen_zero(id)
335 && ast_strings_equal(id, session->channel_id)) {
336 ast_debug(3, "%s: StasisEnd message sent for channel '%s'\n",
337 remote_addr, id);
338 session->stasis_end_sent = 1;
339 }
340 }
342 SCOPE_EXIT("%s: Dispatched '%s' message from Stasis app '%s'\n",
343 remote_addr, msg_type, app_name);
344}
static void session_send_or_queue(struct ari_ws_session *session, struct ast_json *message, const char *msg_type, const char *app_name, int debug_app)
static struct ast_mansession session
void ast_free_ptr(void *ptr)
free() wrapper
Definition: astmm.c:1739
#define ao2_unlock(a)
Definition: astobj2.h:729
#define ao2_lock(a)
Definition: astobj2.h:717
#define SCOPE_EXIT(...)
#define SCOPE_EXIT_LOG_RTN(__log_level,...)
struct ast_sockaddr * ast_websocket_remote_address(struct ast_websocket *session)
Get the remote address for a WebSocket connected session.
@ AST_WS_TYPE_INBOUND
@ AST_WS_TYPE_CLIENT_PER_CALL
struct ast_json * ast_json_string_create(const char *value)
Construct a JSON string from value.
Definition: json.c:278
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
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
static char * ast_sockaddr_stringify(const struct ast_sockaddr *addr)
Wrapper around ast_sockaddr_stringify_fmt() with default format.
Definition: netsock2.h:256
int stasis_app_event_allowed(const char *app_name, struct ast_json *event)
Check if the given event should be filtered.
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
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
Abstract JSON element (object, array, string, int, ...).
#define ast_assert(a)
Definition: utils.h:739
#define AST_VECTOR_REMOVE_CMP_ORDERED(vec, value, cmp, cleanup)
Remove an element from a vector that matches the given comparison while maintaining order.
Definition: vector.h:551

References ao2_lock, ao2_unlock, app_name(), ast_assert, ast_debug, ast_free_ptr(), ast_json_object_get(), ast_json_object_set(), ast_json_string_create(), ast_json_string_get(), ast_sockaddr_stringify(), ast_strings_equal(), ast_strlen_zero(), AST_VECTOR_REMOVE_CMP_ORDERED, ast_websocket_remote_address(), AST_WS_TYPE_CLIENT_PER_CALL, AST_WS_TYPE_INBOUND, LOG_WARNING, NULL, S_OR, SCOPE_ENTER, SCOPE_EXIT, SCOPE_EXIT_LOG_RTN, session, session_send_or_queue(), and stasis_app_event_allowed().

Referenced by send_rest_response(), session_read(), and stasis_app_message_handler().

◆ ari_websocket_shutdown()

void ari_websocket_shutdown ( struct ari_ws_session session)

Definition at line 1487 of file ari_websockets.c.

1488{
1489 if (session) {
1491 }
1492}
static int session_shutdown_cb(void *obj, void *arg, int flags)

References NULL, session, and session_shutdown_cb().

Referenced by ari_shut_session().

◆ ari_websocket_shutdown_all()

void ari_websocket_shutdown_all ( void  )

Definition at line 1494 of file ari_websockets.c.

1495{
1496 if (session_registry) {
1499 }
1500}
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container,...
Definition: astobj2.h:1693
@ OBJ_NODATA
Definition: astobj2.h:1044
@ OBJ_MULTIPLE
Definition: astobj2.h:1049

References ao2_callback, NULL, OBJ_MULTIPLE, OBJ_NODATA, session_registry, and session_shutdown_cb().

Referenced by ari_shut_sessions().

◆ ari_websocket_type_to_str()

const char * ari_websocket_type_to_str ( enum ast_websocket_type  type)

Definition at line 359 of file res/ari/config.c.

360{
361 switch (type) {
363 return "persistent";
365 return "per_call";
367 return "per_call_config";
369 return "inbound";
370 case AST_WS_TYPE_ANY:
371 return "any";
372 default:
373 return "unknown";
374 }
375}
static const char type[]
Definition: chan_ooh323.c:109
@ AST_WS_TYPE_ANY
@ AST_WS_TYPE_CLIENT_PER_CALL_CONFIG
@ AST_WS_TYPE_CLIENT_PERSISTENT

References AST_WS_TYPE_ANY, AST_WS_TYPE_CLIENT_PER_CALL, AST_WS_TYPE_CLIENT_PER_CALL_CONFIG, AST_WS_TYPE_CLIENT_PERSISTENT, AST_WS_TYPE_INBOUND, and type.

Referenced by ari_show_owc(), session_shutdown_cb(), show_owc_cb(), and show_sessions_cb().

◆ ari_websocket_unload_module()

int ari_websocket_unload_module ( void  )

Definition at line 1516 of file ari_websockets.c.

1517{
1518 ari_sorcery_observer_remove("outbound_websocket", &observer_callbacks);
1522 return 0;
1523}
static void session_registry_dtor(void)
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
int ari_sorcery_observer_remove(const char *object_type, const struct ast_sorcery_observer *callbacks)

References ao2_cleanup, ari_sorcery_observer_remove(), ast_ws_server, NULL, observer_callbacks, and session_registry_dtor().

Referenced by ari_websocket_load_module(), and unload_module().