Asterisk - The Open Source Telephony Project  21.4.1
Data Structures | Macros | Enumerations | Functions | Variables
resource_events.c File Reference

/api-docs/events.{format} implementation- WebSocket resource More...

#include "asterisk.h"
#include "resource_events.h"
#include "asterisk/astobj2.h"
#include "asterisk/http_websocket.h"
#include "asterisk/stasis_app.h"
#include "asterisk/vector.h"

Go to the source code of this file.

Data Structures

struct  event_session
 A wrapper for the /ref ast_ari_websocket_session. More...
 

Macros

#define APPS_NUM_BUCKETS   7
 
#define EVENT_SESSION_NUM_BUCKETS   23
 
#define MESSAGES_INIT_SIZE   23
 

Enumerations

enum  event_session_error_type { ERROR_TYPE_STASIS_REGISTRATION = 1, ERROR_TYPE_OOM = 2, ERROR_TYPE_MISSING_APP_PARAM = 3, ERROR_TYPE_INVALID_APP_PARAM = 4 }
 event_session error types. More...
 

Functions

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. More...
 
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. More...
 
void ast_ari_websocket_events_event_websocket_dtor (void)
 WebSocket connection for events.
 
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. More...
 
int ast_ari_websocket_events_event_websocket_init (void)
 WebSocket connection for events. More...
 
static int event_session_alloc (struct ast_tcptls_session_instance *ser, struct ast_ari_events_event_websocket_args *args, const char *session_id)
 Creates an event_session object and registers its apps with Stasis.
 
static int event_session_allocation_error_handler (struct event_session *session, enum event_session_error_type error, struct ast_tcptls_session_instance *ser)
 Handles event_session error processing.
 
static void event_session_cleanup (struct event_session *session)
 Processes cleanup actions for a event_session object.
 
static int event_session_compare (void *obj, void *arg, int flags)
 AO2 comparison function for event_session objects.
 
static void event_session_dtor (void *obj)
 Event session object destructor (event_session).
 
static int event_session_hash (const void *obj, const int flags)
 AO2 hash function for event_session objects. More...
 
static void event_session_shutdown (struct event_session *session)
 Explicitly shutdown a session. More...
 
static int event_session_shutdown_cb (void *session, void *arg, int flags)
 
static void event_session_update_websocket (struct event_session *session, struct ast_ari_websocket_session *ws_session)
 Updates the websocket session for an event_session. More...
 
static void stasis_app_message_handler (void *data, const char *app_name, struct ast_json *message)
 Callback handler for Stasis application messages.
 

Variables

static struct ao2_containerevent_session_registry
 Local registry for created event_session objects.
 

Detailed Description

/api-docs/events.{format} implementation- WebSocket resource

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

Definition in file resource_events.c.

Macro Definition Documentation

#define APPS_NUM_BUCKETS   7

Number of buckets for a websocket apps container. Remember to keep it a prime number!

Definition at line 42 of file resource_events.c.

Referenced by event_session_alloc().

#define EVENT_SESSION_NUM_BUCKETS   23

Number of buckets for the event session registry. Remember to keep it a prime number!

Definition at line 39 of file resource_events.c.

Referenced by ast_ari_websocket_events_event_websocket_init().

#define MESSAGES_INIT_SIZE   23

Initial size of a message queue.

Definition at line 45 of file resource_events.c.

Referenced by event_session_alloc().

Enumeration Type Documentation

event_session error types.

Enumerator
ERROR_TYPE_STASIS_REGISTRATION 

Stasis failed to register the application.

ERROR_TYPE_OOM 

Insufficient memory to create the event session.

ERROR_TYPE_MISSING_APP_PARAM 

HTTP request was missing an [app] parameter.

ERROR_TYPE_INVALID_APP_PARAM 

HTTP request contained an invalid [app] parameter.

Definition at line 58 of file resource_events.c.

58  {
59  ERROR_TYPE_STASIS_REGISTRATION = 1, /*!< Stasis failed to register the application. */
60  ERROR_TYPE_OOM = 2, /*!< Insufficient memory to create the event
61  session. */
62  ERROR_TYPE_MISSING_APP_PARAM = 3, /*!< HTTP request was missing an [app] parameter. */
63  ERROR_TYPE_INVALID_APP_PARAM = 4, /*!< HTTP request contained an invalid [app]
64  parameter. */
65 };

Function Documentation

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.

Parameters
headersHTTP headers
argsSwagger parameters
[out]responseHTTP response

Definition at line 532 of file resource_events.c.

References ast_ari_events_user_event_args::application, ast_ari_events_user_event_parse_body(), ast_ari_response_error(), ast_ari_response_no_content(), ast_json_object_get(), ast_ari_events_user_event_args::event_name, ast_ari_events_user_event_args::source, ast_ari_events_user_event_args::source_count, stasis_app_user_event(), and ast_ari_events_user_event_args::variables.

Referenced by ast_ari_events_user_event_cb().

535 {
536  enum stasis_app_user_event_res res;
537  struct ast_json *json_variables = NULL;
538 
539  if (args->variables) {
541  json_variables = ast_json_object_get(args->variables, "variables");
542  }
543 
544  if (ast_strlen_zero(args->application)) {
545  ast_ari_response_error(response, 400, "Bad Request",
546  "Missing parameter application");
547  return;
548  }
549 
551  args->event_name,
552  args->source, args->source_count,
553  json_variables);
554 
555  switch (res) {
556  case STASIS_APP_USER_OK:
557  ast_ari_response_no_content(response);
558  break;
559 
560  case STASIS_APP_USER_APP_NOT_FOUND:
561  ast_ari_response_error(response, 404, "Not Found",
562  "Application not found");
563  break;
564 
565  case STASIS_APP_USER_EVENT_SOURCE_NOT_FOUND:
566  ast_ari_response_error(response, 422, "Unprocessable Entity",
567  "Event source was not found");
568  break;
569 
570  case STASIS_APP_USER_EVENT_SOURCE_BAD_SCHEME:
571  ast_ari_response_error(response, 400, "Bad Request",
572  "Invalid event source URI scheme");
573  break;
574 
575  case STASIS_APP_USER_USEREVENT_INVALID:
576  ast_ari_response_error(response, 400, "Bad Request",
577  "Invalid userevent data");
578  break;
579 
580  case STASIS_APP_USER_INTERNAL_ERROR:
581  default:
582  ast_ari_response_error(response, 500, "Internal Server Error",
583  "Error processing request");
584  }
585 }
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}.
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_no_content(struct ast_ari_response *response)
Fill in a No Content (204) ast_ari_response.
Definition: res_ari.c:284
stasis_app_user_event_res
Return code for stasis_app_user_event.
Definition: stasis_app.h:255
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
Abstract JSON element (object, array, string, int, ...).
enum stasis_app_user_event_res stasis_app_user_event(const char *app_name, const char *event_name, const char **source_uris, int sources_count, struct ast_json *json_variables)
Generate a Userevent for stasis app (echo to AMI)
Definition: res_stasis.c:2102
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.

Parameters
serHTTP TCP/TLS Server Session
headersHTTP headers
argsSwagger parameters
session_idThe id of the current session.
Return values
0success
non-zeroerror

Definition at line 488 of file resource_events.c.

References ast_debug, and event_session_alloc().

491 {
492  ast_debug(3, "/events WebSocket attempted\n");
493 
494  /* Create the event session */
495  return event_session_alloc(ser, args, session_id);
496 }
static int event_session_alloc(struct ast_tcptls_session_instance *ser, struct ast_ari_events_event_websocket_args *args, const char *session_id)
Creates an event_session object and registers its apps with Stasis.
#define ast_debug(level,...)
Log a DEBUG message.
void ast_ari_websocket_events_event_websocket_established ( struct ast_ari_websocket_session session,
struct ast_variable headers,
struct ast_ari_events_event_websocket_args args 
)

WebSocket connection for events.

Parameters
sessionARI WebSocket.
headersHTTP headers.
argsSwagger parameters.

Definition at line 498 of file resource_events.c.

References ao2_ref, ao2_unlink, ast_ari_websocket_session_id(), ast_ari_websocket_session_read(), ast_debug, ast_json_unref(), event_session_cleanup(), event_session_update_websocket(), OBJ_SEARCH_KEY, and event_session::session_id.

501 {
502  struct event_session *session;
503 
504  struct ast_json *msg;
505  const char *session_id;
506 
507  ast_debug(3, "/events WebSocket established\n");
508 
509  ast_assert(ws_session != NULL);
510 
511  session_id = ast_ari_websocket_session_id(ws_session);
512 
513  /* Find the event_session and update its websocket */
514  session = ao2_find(event_session_registry, session_id, OBJ_SEARCH_KEY);
515  if (session) {
517  event_session_update_websocket(session, ws_session);
518  } else {
519  ast_log(LOG_WARNING,
520  "Failed to locate an event session for the provided websocket session\n");
521  }
522 
523  /* We don't process any input, but we'll consume it waiting for EOF */
524  while ((msg = ast_ari_websocket_session_read(ws_session))) {
525  ast_json_unref(msg);
526  }
527 
528  event_session_cleanup(session);
529  ao2_ref(session, -1);
530 }
const char * ast_ari_websocket_session_id(const struct ast_ari_websocket_session *session)
Get the Session ID for an ARI WebSocket.
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1101
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 * ast_ari_websocket_session_read(struct ast_ari_websocket_session *session)
Read a message from an ARI WebSocket.
static void event_session_cleanup(struct event_session *session)
Processes cleanup actions for a event_session object.
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
static void event_session_update_websocket(struct event_session *session, struct ast_ari_websocket_session *ws_session)
Updates the websocket session for an event_session.
A wrapper for the /ref ast_ari_websocket_session.
#define ast_debug(level,...)
Log a DEBUG message.
#define ao2_unlink(container, obj)
Remove an object from a container.
Definition: astobj2.h:1578
Abstract JSON element (object, array, string, int, ...).
static struct ao2_container * event_session_registry
Local registry for created event_session objects.
int ast_ari_websocket_events_event_websocket_init ( void  )

WebSocket connection for events.

Return values
0success
-1error

Definition at line 473 of file resource_events.c.

References AO2_ALLOC_OPT_LOCK_MUTEX, ao2_container_alloc_hash, event_session_compare(), event_session_hash(), and EVENT_SESSION_NUM_BUCKETS.

474 {
475  /* Try to instantiate the registry */
478  if (!event_session_registry) {
479  /* This is bad, bad. */
480  ast_log(LOG_WARNING,
481  "Failed to allocate the local registry for websocket applications\n");
482  return -1;
483  }
484 
485  return 0;
486 }
#define EVENT_SESSION_NUM_BUCKETS
#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.
Definition: astobj2.h:1303
static int event_session_hash(const void *obj, const int flags)
AO2 hash function for event_session objects.
static int event_session_compare(void *obj, void *arg, int flags)
AO2 comparison function for event_session objects.
static struct ao2_container * event_session_registry
Local registry for created event_session objects.
static int event_session_hash ( const void *  obj,
const int  flags 
)
static

AO2 hash function for event_session objects.

Computes hash value for the given event_session, with respect to the provided search flags.

Definition at line 191 of file resource_events.c.

References ast_str_hash(), OBJ_SEARCH_KEY, OBJ_SEARCH_MASK, OBJ_SEARCH_OBJECT, and event_session::session_id.

Referenced by ast_ari_websocket_events_event_websocket_init().

192 {
193  const struct event_session *session;
194  const char *key;
195 
196  switch (flags & OBJ_SEARCH_MASK) {
197  case OBJ_SEARCH_KEY:
198  key = obj;
199  break;
200  case OBJ_SEARCH_OBJECT:
201  session = obj;
202  key = session->session_id;
203  break;
204  default:
205  /* Hash can only work on something with a full key. */
206  ast_assert(0);
207  return 0;
208  }
209  return ast_str_hash(key);
210 }
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1101
A wrapper for the /ref ast_ari_websocket_session.
The arg parameter is an object of the same type.
Definition: astobj2.h:1087
Search option field mask.
Definition: astobj2.h:1072
static force_inline int attribute_pure ast_str_hash(const char *str)
Compute a hash value on a string.
Definition: strings.h:1259
static void event_session_shutdown ( struct event_session session)
static

Explicitly shutdown a session.

An explicit shutdown is necessary, since the stasis_app has a reference to this session. We also need to be sure to null out the ws_session field, since the websocket is about to go away.

Definition at line 223 of file resource_events.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ast_json_unref(), AST_VECTOR_FREE, AST_VECTOR_GET, AST_VECTOR_SIZE, lock, event_session::message_queue, SCOPED_AO2LOCK, stasis_app_unregister(), event_session::websocket_apps, and event_session::ws_session.

Referenced by event_session_cleanup().

224 {
225  struct ao2_iterator i;
226  char *app;
227  int j;
228  SCOPED_AO2LOCK(lock, session);
229 
230  /* Clean up the websocket_apps container */
231  if (session->websocket_apps) {
232  i = ao2_iterator_init(session->websocket_apps, 0);
233  while ((app = ao2_iterator_next(&i))) {
235  ao2_cleanup(app);
236  }
238  ao2_cleanup(session->websocket_apps);
239  session->websocket_apps = NULL;
240  }
241 
242  /* Clean up the message_queue container */
243  for (j = 0; j < AST_VECTOR_SIZE(&session->message_queue); j++) {
244  struct ast_json *msg = AST_VECTOR_GET(&session->message_queue, j);
245  ast_json_unref(msg);
246  }
247  AST_VECTOR_FREE(&session->message_queue);
248 
249  /* Remove the handle to the underlying websocket session */
250  session->ws_session = NULL;
251 }
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
Definition: vector.h:174
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition: json.c:73
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
void stasis_app_unregister(const char *app_name)
Unregister a Stasis application.
Definition: res_stasis.c:1794
ast_mutex_t lock
struct ao2_container * websocket_apps
struct event_session::@427 message_queue
struct ast_ari_websocket_session * ws_session
#define SCOPED_AO2LOCK(varname, obj)
scoped lock specialization for ao2 mutexes.
Definition: lock.h:604
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:680
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1821
Abstract JSON element (object, array, string, int, ...).
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:609
static void event_session_update_websocket ( struct event_session session,
struct ast_ari_websocket_session ws_session 
)
static

Updates the websocket session for an event_session.

The websocket for the given event_session will be updated to the value of the ws_session argument.

If the value of the ws_session is not NULL and there are messages in the event session's message_queue, the messages are dispatched and removed from the queue.

Definition at line 269 of file resource_events.c.

References ast_ari_websocket_session_write(), ast_json_unref(), AST_VECTOR_ELEM_CLEANUP_NOOP, AST_VECTOR_GET, AST_VECTOR_RESET, AST_VECTOR_SIZE, event_session::message_queue, and event_session::ws_session.

Referenced by ast_ari_websocket_events_event_websocket_established().

271 {
272  int i;
273 
274  ast_assert(session != NULL);
275 
276  ao2_lock(session);
277 
278  session->ws_session = ws_session;
279 
280  for (i = 0; i < AST_VECTOR_SIZE(&session->message_queue); i++) {
281  struct ast_json *msg = AST_VECTOR_GET(&session->message_queue, i);
283  ast_json_unref(msg);
284  }
285 
287  ao2_unlock(session);
288 }
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition: json.c:73
#define AST_VECTOR_ELEM_CLEANUP_NOOP(elem)
Vector element cleanup that does nothing.
Definition: vector.h:571
struct event_session::@427 message_queue
struct ast_ari_websocket_session * ws_session
#define AST_VECTOR_RESET(vec, cleanup)
Reset vector.
Definition: vector.h:625
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:680
Abstract JSON element (object, array, string, int, ...).
int ast_ari_websocket_session_write(struct ast_ari_websocket_session *session, struct ast_json *message)
Send a message to an ARI WebSocket.
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:609