Asterisk - The Open Source Telephony Project GIT-master-f36a736
ari_websockets.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 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#include "asterisk.h"
20
21#include "asterisk/ari.h"
22#include "asterisk/astobj2.h"
24#include "asterisk/stasis_app.h"
25#include "internal.h"
26
27/*! \file
28 *
29 * \brief WebSocket support for RESTful API's.
30 * \author David M. Lee, II <dlee@digium.com>
31 */
32
35 int (*validator)(struct ast_json *);
36};
37
38static void websocket_session_dtor(void *obj)
39{
41
42 ast_websocket_unref(session->ws_session);
43 session->ws_session = NULL;
44}
45
46/*!
47 * \brief Validator that always succeeds.
48 */
49static int null_validator(struct ast_json *json)
50{
51 return 1;
52}
53
55 struct ast_websocket *ws_session, int (*validator)(struct ast_json *))
56{
59
60 if (ws_session == NULL) {
61 return NULL;
62 }
63
64 if (config == NULL || config->general == NULL) {
65 return NULL;
66 }
67
68 if (validator == NULL) {
70 }
71
74 "ARI web socket failed to set nonblock; closing: %s\n",
75 strerror(errno));
76 return NULL;
77 }
78
79 if (ast_websocket_set_timeout(ws_session, config->general->write_timeout)) {
80 ast_log(LOG_WARNING, "Failed to set write timeout %d on ARI web socket\n",
81 config->general->write_timeout);
82 }
83
85 if (!session) {
86 return NULL;
87 }
88
90 session->ws_session = ws_session;
91 session->validator = validator;
92
93 ao2_ref(session, +1);
94 return session;
95}
96
99{
101
102 if (ast_websocket_fd(session->ws_session) < 0) {
103 return NULL;
104 }
105
106 while (!message) {
107 int res;
108 char *payload;
109 uint64_t payload_len;
110 enum ast_websocket_opcode opcode;
111 int fragmented;
112
113 res = ast_wait_for_input(
114 ast_websocket_fd(session->ws_session), -1);
115
116 if (res <= 0) {
117 ast_log(LOG_WARNING, "WebSocket poll error: %s\n",
118 strerror(errno));
119 return NULL;
120 }
121
122 res = ast_websocket_read(session->ws_session, &payload,
123 &payload_len, &opcode, &fragmented);
124
125 if (res != 0) {
126 ast_log(LOG_WARNING, "WebSocket read error: %s\n",
127 strerror(errno));
128 return NULL;
129 }
130
131 switch (opcode) {
133 ast_debug(1, "WebSocket closed\n");
134 return NULL;
136 message = ast_json_load_buf(payload, payload_len, NULL);
137 if (message == NULL) {
139 "WebSocket input failed to parse\n");
140 }
141
142 break;
143 default:
144 /* Ignore all other message types */
145 break;
146 }
147 }
148
149 return ast_json_ref(message);
150}
151
152#define VALIDATION_FAILED \
153 "{" \
154 " \"error\": \"InvalidMessage\"," \
155 " \"message\": \"Message validation failed\"" \
156 "}"
157
159 struct ast_json *message)
160{
161 RAII_VAR(char *, str, NULL, ast_json_free);
162
163#ifdef AST_DEVMODE
164 if (!session->validator(message)) {
165 ast_log(LOG_ERROR, "Outgoing message failed validation\n");
167 }
168#endif
169
171
172 if (str == NULL) {
173 ast_log(LOG_ERROR, "Failed to encode JSON object\n");
174 return -1;
175 }
176
177 if (ast_websocket_write_string(session->ws_session, str)) {
178 ast_log(LOG_NOTICE, "Problem occurred during websocket write to %s, websocket closed\n",
180 return -1;
181 }
182 return 0;
183}
184
187{
188 return ast_websocket_remote_address(session->ws_session);
189}
190
192 struct ast_tcptls_session_instance *ser, const char *uri,
193 enum ast_http_method method, struct ast_variable *get_params,
194 struct ast_variable *headers)
195{
196 struct ast_http_uri fake_urih = {
197 .data = ws_server,
198 };
199 ast_websocket_uri_cb(ser, &fake_urih, uri, method, get_params,
200 headers);
201}
202
205{
206 return ast_websocket_session_id(session->ws_session);
207}
const char * str
Definition: app_jack.c:147
Asterisk RESTful API hooks.
enum ast_json_encoding_format ast_ari_json_format(void)
Configured encoding format for JSON output.
Definition: res_ari.c:806
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.
static int null_validator(struct ast_json *json)
Validator that always succeeds.
struct ast_json * ast_ari_websocket_session_read(struct ast_ari_websocket_session *session)
Read a message from an ARI WebSocket.
static void websocket_session_dtor(void *obj)
void ari_handle_websocket(struct ast_websocket_server *ws_server, 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.
const char * ast_ari_websocket_session_id(const struct ast_ari_websocket_session *session)
Get the Session ID for an ARI WebSocket.
struct ast_sockaddr * ast_ari_websocket_session_get_remote_addr(struct ast_ari_websocket_session *session)
Get the remote address from an ARI WebSocket.
int ast_ari_websocket_session_write(struct ast_ari_websocket_session *session, struct ast_json *message)
Send a message to an ARI WebSocket.
#define VALIDATION_FAILED
Asterisk main include file. File version handling, generic pbx functions.
static struct ast_mansession session
#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
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:409
static const char config[]
Definition: chan_ooh323.c:111
ast_http_method
HTTP Request methods known by Asterisk.
Definition: http.h:58
Support for WebSocket connections within the Asterisk HTTP server and client WebSocket connections to...
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_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.
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_ERROR
#define LOG_NOTICE
#define LOG_WARNING
Internal API's for res_ari.
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition: json.c:73
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_ref(struct ast_json *value)
Increase refcount on value.
Definition: json.c:67
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.
Definition: json.c:585
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
int errno
static char * ast_sockaddr_stringify(const struct ast_sockaddr *addr)
Wrapper around ast_sockaddr_stringify_fmt() with default format.
Definition: netsock2.h:256
struct ast_ari_conf * ast_ari_config_get(void)
Get the current ARI configuration.
const char * method
Definition: res_pjsip.c:1279
#define NULL
Definition: resample.c:96
Stasis Application API. See Stasis Application API for detailed documentation.
All configuration options for ARI.
Definition: internal.h:54
struct ast_websocket * ws_session
int(* validator)(struct ast_json *)
Definition of a URI handler.
Definition: http.h:102
const char * uri
Definition: http.h:105
void * data
Definition: http.h:116
Abstract JSON element (object, array, string, int, ...).
Socket address structure.
Definition: netsock2.h:97
describes a server instance
Definition: tcptls.h:150
Structure for variables, used for configurations and for channel variables.
Structure for a WebSocket server.
Structure definition for session.
#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
int ast_wait_for_input(int fd, int ms)
Definition: utils.c:1698