Asterisk - The Open Source Telephony Project GIT-master-f3e88d3
Data Structures | Macros | Functions
transport_websocket.c File Reference
#include "asterisk.h"
#include "asterisk/http_websocket.h"
#include "asterisk/utils.h"
#include "logger.h"
#include "transport.h"
#include "transport_websocket.h"
Include dependency graph for transport_websocket.c:

Go to the source code of this file.

Data Structures

struct  aeap_transport_websocket
 

Macros

#define log_error(obj, fmt, ...)   aeap_error(obj, "websocket", fmt, ##__VA_ARGS__)
 

Functions

struct aeap_transport_websocketaeap_transport_websocket_create (void)
 Creates (heap allocated), and initializes a transport websocket. More...
 
static int transport_websocket_init (struct aeap_transport_websocket *transport)
 Initialize a transport websocket object, and set its virtual table. More...
 
static struct aeap_transport_vtabletransport_websocket_vtable (void)
 
static int websocket_connect (struct aeap_transport *self, const char *url, const char *protocol, int timeout)
 
static void websocket_destroy (struct aeap_transport *self)
 
static int websocket_disconnect (struct aeap_transport *self)
 
static intmax_t websocket_read (struct aeap_transport *self, void *buf, intmax_t size, enum AST_AEAP_DATA_TYPE *rtype)
 
static intmax_t websocket_write (struct aeap_transport *self, const void *buf, intmax_t size, enum AST_AEAP_DATA_TYPE wtype)
 

Macro Definition Documentation

◆ log_error

#define log_error (   obj,
  fmt,
  ... 
)    aeap_error(obj, "websocket", fmt, ##__VA_ARGS__)

Definition at line 28 of file transport_websocket.c.

Function Documentation

◆ aeap_transport_websocket_create()

struct aeap_transport_websocket * aeap_transport_websocket_create ( void  )

Creates (heap allocated), and initializes a transport websocket.

Returns
A transport websocket object, or NULL on error

Definition at line 238 of file transport_websocket.c.

239{
240 struct aeap_transport_websocket *transport;
241
242 transport = ast_calloc(1, sizeof(*transport));
243 if (!transport) {
244 ast_log(LOG_ERROR, "AEAP websocket: unable to create transport websocket");
245 return NULL;
246 }
247
248 if (transport_websocket_init(transport)) {
249 ast_free(transport);
250 return NULL;
251 }
252
253 return transport;
254}
#define ast_free(a)
Definition: astmm.h:180
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
#define ast_log
Definition: astobj2.c:42
#define LOG_ERROR
#define NULL
Definition: resample.c:96
static int transport_websocket_init(struct aeap_transport_websocket *transport)
Initialize a transport websocket object, and set its virtual table.

References ast_calloc, ast_free, ast_log, LOG_ERROR, NULL, and transport_websocket_init().

Referenced by aeap_transport_create().

◆ transport_websocket_init()

static int transport_websocket_init ( struct aeap_transport_websocket transport)
static

Initialize a transport websocket object, and set its virtual table.

Parameters
transportThe transport to initialize
Returns
0 on success, -1 on error

Definition at line 229 of file transport_websocket.c.

230{
231 transport->ws = NULL;
232
233 ((struct aeap_transport *)transport)->vtable = transport_websocket_vtable();
234
235 return 0;
236}
struct ast_websocket * ws
Asterisk external application transport structure to be "derived" by specific transport implementatio...
Definition: transport.h:98
static struct aeap_transport_vtable * transport_websocket_vtable(void)

References NULL, transport_websocket_vtable(), and aeap_transport_websocket::ws.

Referenced by aeap_transport_websocket_create().

◆ transport_websocket_vtable()

static struct aeap_transport_vtable * transport_websocket_vtable ( void  )
static

Definition at line 209 of file transport_websocket.c.

210{
211 static struct aeap_transport_vtable websocket_vtable = {
213 .disconnect = websocket_disconnect,
214 .destroy = websocket_destroy,
215 .read = websocket_read,
216 .write = websocket_write,
217 };
218
219 return &websocket_vtable;
220}
Asterisk external application transport virtual table.
Definition: transport.h:33
int(* connect)(struct aeap_transport *self, const char *url, const char *protocol, int timeout)
Connect a transport.
Definition: transport.h:44
static void websocket_destroy(struct aeap_transport *self)
static int websocket_disconnect(struct aeap_transport *self)
static intmax_t websocket_read(struct aeap_transport *self, void *buf, intmax_t size, enum AST_AEAP_DATA_TYPE *rtype)
static intmax_t websocket_write(struct aeap_transport *self, const void *buf, intmax_t size, enum AST_AEAP_DATA_TYPE wtype)
static int websocket_connect(struct aeap_transport *self, const char *url, const char *protocol, int timeout)

References aeap_transport_vtable::connect, websocket_connect(), websocket_destroy(), websocket_disconnect(), websocket_read(), and websocket_write().

Referenced by transport_websocket_init().

◆ websocket_connect()

static int websocket_connect ( struct aeap_transport self,
const char *  url,
const char *  protocol,
int  timeout 
)
static

Definition at line 37 of file transport_websocket.c.

39{
40 struct aeap_transport_websocket *transport = (struct aeap_transport_websocket *)self;
41 enum ast_websocket_result ws_result;
42 struct ast_websocket_client_options ws_options = {
43 .uri = url,
44 .protocols = protocol,
45 .timeout = timeout,
46 .tls_cfg = NULL,
47 };
48
49 transport->ws = ast_websocket_client_create_with_options(&ws_options, &ws_result);
50 if (ws_result != WS_OK) {
51 log_error(self, "connect failure (%d)", (int)ws_result);
52 return -1;
53 }
54
55 return 0;
56}
struct ast_websocket * ast_websocket_client_create_with_options(struct ast_websocket_client_options *options, enum ast_websocket_result *result)
Create, and connect, a websocket client using given options.
ast_websocket_result
Result code for a websocket client.
@ WS_OK
static char url[512]
Options used for a websocket client.
#define log_error(obj, fmt,...)

References ast_websocket_client_create_with_options(), log_error, NULL, ast_websocket_client_options::timeout, ast_websocket_client_options::uri, url, aeap_transport_websocket::ws, and WS_OK.

Referenced by transport_websocket_vtable().

◆ websocket_destroy()

static void websocket_destroy ( struct aeap_transport self)
static

Definition at line 70 of file transport_websocket.c.

71{
72 /*
73 * Disconnect takes care of cleaning up the websocket. Note, disconnect
74 * was called by the base/dispatch interface prior to calling this
75 * function so nothing to do here.
76 */
77}

Referenced by transport_websocket_vtable().

◆ websocket_disconnect()

static int websocket_disconnect ( struct aeap_transport self)
static

Definition at line 58 of file transport_websocket.c.

59{
60 struct aeap_transport_websocket *transport = (struct aeap_transport_websocket *)self;
61
62 if (transport->ws) {
63 ast_websocket_unref(transport->ws);
64 transport->ws = NULL;
65 }
66
67 return 0;
68}
void ast_websocket_unref(struct ast_websocket *session)
Decrease the reference count for a WebSocket session.

References ast_websocket_unref(), NULL, and aeap_transport_websocket::ws.

Referenced by transport_websocket_vtable().

◆ websocket_read()

static intmax_t websocket_read ( struct aeap_transport self,
void *  buf,
intmax_t  size,
enum AST_AEAP_DATA_TYPE rtype 
)
static

Definition at line 79 of file transport_websocket.c.

81{
82 struct aeap_transport_websocket *transport = (struct aeap_transport_websocket *)self;
83
84 char *payload;
85 uint64_t bytes_read = 0;
86 uint64_t total_bytes_read = 0;
87 enum ast_websocket_opcode opcode;
88 int fragmented = 0;
89
91
92 if (ast_websocket_fd(transport->ws) < 0) {
93 log_error(self, "unavailable for reading");
94 /* Ensure this transport is in a disconnected state */
96 return -1;
97 }
98
99 /*
100 * This function is called with the read_lock locked. However, the lock needs to be
101 * unlocked while waiting for input otherwise a deadlock can occur during disconnect
102 * (disconnect attempts to grab the lock but can't because read holds it here). So
103 * unlock it prior to waiting.
104 */
105 ast_mutex_unlock(&transport->base.read_lock);
106 while (ast_websocket_wait_for_input(transport->ws, -1) <= 0) {
107 /* If this was poll getting interrupted just go back to waiting */
108 if (errno == EINTR || errno == EAGAIN) {
109 continue;
110 }
111
112 ast_mutex_lock(&transport->base.read_lock);
113 log_error(self, "poll failure: %s", strerror(errno));
114 /* Ensure this transport is in a disconnected state */
116 return -1;
117 }
118 ast_mutex_lock(&transport->base.read_lock);
119
120 if (!transport->ws) {
121 /*
122 * It's possible the transport was told to disconnect while waiting for input.
123 * If so then the websocket will be NULL, so we don't want to continue.
124 */
125 return 0;
126 }
127
128 do {
129 if (ast_websocket_read(transport->ws, &payload, &bytes_read, &opcode,
130 &fragmented) != 0) {
131 log_error(self, "read failure (%d): %s", opcode, strerror(errno));
132 return -1;
133 }
134
135 if (!bytes_read) {
136 continue;
137 }
138
139 if (total_bytes_read + bytes_read > size) {
140 log_error(self, "attempted to read too many bytes into (%jd) sized buffer", size);
141 return -1;
142 }
143
144 memcpy(buf + total_bytes_read, payload, bytes_read);
145 total_bytes_read += bytes_read;
146
147 } while (opcode == AST_WEBSOCKET_OPCODE_CONTINUATION);
148
149 switch (opcode) {
151 log_error(self, "closed");
152 return -1;
155 break;
158
159 /* Append terminator, but check for overflow first */
160 if (total_bytes_read == size) {
161 log_error(self, "unable to write string terminator");
162 return -1;
163 }
164
165 *((char *)(buf + total_bytes_read)) = '\0';
166 break;
167 default:
168 /* Ignore all other message types */
169 return 0;
170 }
171
172 return total_bytes_read;
173}
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
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.
int ast_websocket_wait_for_input(struct ast_websocket *session, int timeout)
Wait for the WebSocket session to be ready to be read.
ast_websocket_opcode
WebSocket operation codes.
@ AST_WEBSOCKET_OPCODE_CONTINUATION
@ AST_WEBSOCKET_OPCODE_BINARY
@ AST_WEBSOCKET_OPCODE_CLOSE
@ AST_WEBSOCKET_OPCODE_TEXT
int ast_websocket_fd(struct ast_websocket *session)
Get the file descriptor for a WebSocket session.
#define ast_mutex_unlock(a)
Definition: lock.h:190
#define ast_mutex_lock(a)
Definition: lock.h:189
int errno
@ AST_AEAP_DATA_TYPE_NONE
Definition: res_aeap.h:136
@ AST_AEAP_DATA_TYPE_BINARY
Definition: res_aeap.h:137
@ AST_AEAP_DATA_TYPE_STRING
Definition: res_aeap.h:138
struct aeap_transport base
ast_mutex_t read_lock
Definition: transport.h:104
int aeap_transport_disconnect(struct aeap_transport *transport)
Disconnect a transport.
Definition: transport.c:94

References aeap_transport_disconnect(), AST_AEAP_DATA_TYPE_BINARY, AST_AEAP_DATA_TYPE_NONE, AST_AEAP_DATA_TYPE_STRING, ast_mutex_lock, ast_mutex_unlock, ast_websocket_fd(), AST_WEBSOCKET_OPCODE_BINARY, AST_WEBSOCKET_OPCODE_CLOSE, AST_WEBSOCKET_OPCODE_CONTINUATION, AST_WEBSOCKET_OPCODE_TEXT, ast_websocket_read(), ast_websocket_wait_for_input(), aeap_transport_websocket::base, buf, errno, log_error, aeap_transport::read_lock, and aeap_transport_websocket::ws.

Referenced by transport_websocket_vtable().

◆ websocket_write()

static intmax_t websocket_write ( struct aeap_transport self,
const void *  buf,
intmax_t  size,
enum AST_AEAP_DATA_TYPE  wtype 
)
static

Definition at line 175 of file transport_websocket.c.

177{
178 struct aeap_transport_websocket *transport = (struct aeap_transport_websocket *)self;
179 intmax_t res = 0;
180
181 switch (wtype) {
184 (char *)buf, size);
185 break;
188 (char *)buf, size);
189 break;
190 default:
191 break;
192 }
193
194 if (res < 0) {
195 log_error(self, "problem writing to websocket (closed)");
196
197 /*
198 * If the underlying socket is closed then ensure the
199 * transport is in a disconnected state as well.
200 */
202
203 return res;
204 }
205
206 return size;
207}
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.

References aeap_transport_disconnect(), AST_AEAP_DATA_TYPE_BINARY, AST_AEAP_DATA_TYPE_STRING, AST_WEBSOCKET_OPCODE_BINARY, AST_WEBSOCKET_OPCODE_TEXT, ast_websocket_write(), buf, log_error, and aeap_transport_websocket::ws.

Referenced by transport_websocket_vtable().