Asterisk - The Open Source Telephony Project GIT-master-a358458
http_websocket.h
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 2012, Digium, Inc.
5 *
6 * Joshua Colp <jcolp@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#ifndef _ASTERISK_HTTP_WEBSOCKET_H
20#define _ASTERISK_HTTP_WEBSOCKET_H
21
22#include "asterisk/http.h"
24
25#include <errno.h>
26
27/*! \brief Default websocket write timeout, in ms */
28#define AST_DEFAULT_WEBSOCKET_WRITE_TIMEOUT 100
29
30/*! \brief Default websocket write timeout, in ms (as a string) */
31#define AST_DEFAULT_WEBSOCKET_WRITE_TIMEOUT_STR "100"
32
33/*!
34 * \file
35 *
36 * \brief Support for WebSocket connections within the Asterisk HTTP server and client
37 * WebSocket connections to a server.
38 *
39 * Supported WebSocket versions in server implementation:
40 * Version 7 defined in specification http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-07
41 * Version 8 defined in specification http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-10
42 * Version 13 defined in specification http://tools.ietf.org/html/rfc6455
43 * Supported WebSocket versions in client implementation:
44 * Version 13 defined in specification http://tools.ietf.org/html/rfc6455
45 *
46 * \author Joshua Colp <jcolp@digium.com>
47 *
48 */
49
50/*! \brief WebSocket operation codes */
52 AST_WEBSOCKET_OPCODE_TEXT = 0x1, /*!< Text frame */
53 AST_WEBSOCKET_OPCODE_BINARY = 0x2, /*!< Binary frame */
54 AST_WEBSOCKET_OPCODE_PING = 0x9, /*!< Request that the other side respond with a pong */
55 AST_WEBSOCKET_OPCODE_PONG = 0xA, /*!< Response to a ping */
56 AST_WEBSOCKET_OPCODE_CLOSE = 0x8, /*!< Connection is being closed */
57 AST_WEBSOCKET_OPCODE_CONTINUATION = 0x0, /*!< Continuation of a previous frame */
58};
59
60/*!
61 * \brief Opaque structure for WebSocket server.
62 * \since 12
63 */
65
66/*!
67 * \brief Opaque structure for WebSocket sessions.
68 */
69struct ast_websocket;
70
71/*!
72 * \brief Callback from the HTTP request attempting to establish a websocket connection
73 *
74 * This callback occurs when an HTTP request is made to establish a websocket connection.
75 * Implementers of \ref ast_websocket_protocol can use this to deny a request, or to
76 * set up application specific data before invocation of \ref ast_websocket_callback.
77 *
78 * \param ser The TCP/TLS session
79 * \param parameters Parameters extracted from the request URI
80 * \param headers Headers included in the request
81 * \param session_id The id of the current session.
82 *
83 * \retval 0 The session should be accepted
84 * \retval -1 The session should be rejected. Note that the caller must send an error
85 * response using \ref ast_http_error.
86 * \since 13.5.0
87 */
88typedef int (*ast_websocket_pre_callback)(struct ast_tcptls_session_instance *ser, struct ast_variable *parameters, struct ast_variable *headers, const char *session_id);
89
90/*!
91 * \brief Callback for when a new connection for a sub-protocol is established
92 *
93 * \param session A WebSocket session structure
94 * \param parameters Parameters extracted from the request URI
95 * \param headers Headers included in the request
96 *
97 * \note Once called the ownership of the session is transferred to the sub-protocol handler. It
98 * is responsible for closing and cleaning up.
99 *
100 */
101typedef void (*ast_websocket_callback)(struct ast_websocket *session, struct ast_variable *parameters, struct ast_variable *headers);
102
103/*!
104 * \brief A websocket protocol implementation
105 *
106 * Users of the Websocket API can register themselves as a websocket
107 * protocol. See \ref ast_websocket_add_protocol2 and \ref ast_websocket_server_add_protocol2.
108 * Simpler implementations may use only \ref ast_websocket_add_protocol and
109 * \ref ast_websocket_server_add_protocol.
110 *
111 * \since 13.5.0
112 */
114 /*! \brief Name of the protocol */
115 char *name;
116/*!
117 * \brief Protocol version. This prevents dynamically loadable modules from registering
118 * if this struct is changed.
119 */
120#define AST_WEBSOCKET_PROTOCOL_VERSION 1
121 /*! \brief Protocol version. Should be set to /ref AST_WEBSOCKET_PROTOCOL_VERSION */
122 unsigned int version;
123 /*! \brief Callback called when a new session is attempted. Optional. */
125 /*! \brief Callback called when a new session is established. Mandatory. */
127};
128
129/*!
130 * \brief Creates a \ref ast_websocket_server
131 *
132 * \return New \ref ast_websocket_server instance
133 * \retval NULL on error
134 * \since 12
135 */
137
138/*!
139 * \brief Callback suitable for use with a \ref ast_http_uri.
140 *
141 * Set the data field of the ast_http_uri to \ref ast_websocket_server.
142 * \since 12
143 */
144AST_OPTIONAL_API(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), { return -1; });
145
146/*!
147 * \brief Allocate a websocket sub-protocol instance
148 *
149 * \return An instance of \ref ast_websocket_protocol on success
150 * \retval NULL on error
151 * \since 13.5.0
152 */
154
155/*!
156 * \brief Add a sub-protocol handler to the default /ws server
157 *
158 * \param name Name of the sub-protocol to register
159 * \param callback Callback called when a new connection requesting the sub-protocol is established
160 *
161 * \retval 0 success
162 * \retval -1 if sub-protocol handler could not be registered
163 */
164AST_OPTIONAL_API(int, ast_websocket_add_protocol, (const char *name, ast_websocket_callback callback), {return -1;});
165
166/*!
167 * \brief Add a sub-protocol handler to the default /ws server
168 *
169 * \param protocol The sub-protocol to register. Note that this must
170 * be allocated using /ref ast_websocket_sub_protocol_alloc.
171 *
172 * \note This method is reference stealing. It will steal the reference to \p protocol
173 * on success.
174 *
175 * \retval 0 success
176 * \retval -1 if sub-protocol handler could not be registered
177 * \since 13.5.0
178 */
179AST_OPTIONAL_API(int, ast_websocket_add_protocol2, (struct ast_websocket_protocol *protocol), {return -1;});
180
181/*!
182 * \brief Remove a sub-protocol handler from the default /ws server.
183 *
184 * \param name Name of the sub-protocol to unregister
185 * \param callback Session Established callback that was previously registered with the sub-protocol
186 *
187 * \retval 0 success
188 * \retval -1 if sub-protocol was not found or if callback did not match
189 */
190AST_OPTIONAL_API(int, ast_websocket_remove_protocol, (const char *name, ast_websocket_callback callback), {return -1;});
191
192/*!
193 * \brief Add a sub-protocol handler to the given server.
194 *
195 * \param server The server to add the sub-protocol to
196 * \param name Name of the sub-protocol to register
197 * \param callback Callback called when a new connection requesting the sub-protocol is established
198 *
199 * \retval 0 success
200 * \retval -1 if sub-protocol handler could not be registered
201 * \since 12
202 */
203AST_OPTIONAL_API(int, ast_websocket_server_add_protocol, (struct ast_websocket_server *server, const char *name, ast_websocket_callback callback), {return -1;});
204
205/*!
206 * \brief Add a sub-protocol handler to the given server.
207 *
208 * \param server The server to add the sub-protocol to.
209 * \param protocol The sub-protocol to register. Note that this must
210 * be allocated using /ref ast_websocket_sub_protocol_alloc.
211 *
212 * \note This method is reference stealing. It will steal the reference to \p protocol
213 * on success.
214 *
215 * \retval 0 success
216 * \retval -1 if sub-protocol handler could not be registered
217 * \since 13.5.0
218 */
219AST_OPTIONAL_API(int, ast_websocket_server_add_protocol2, (struct ast_websocket_server *server, struct ast_websocket_protocol *protocol), {return -1;});
220
221/*!
222 * \brief Remove a sub-protocol handler from the given server.
223 *
224 * \param server The server to unregister the sub-protocol from
225 * \param name Name of the sub-protocol to unregister
226 * \param callback Callback that was previously registered with the sub-protocol
227 *
228 * \retval 0 success
229 * \retval -1 if sub-protocol was not found or if callback did not match
230 * \since 12
231 */
232AST_OPTIONAL_API(int, ast_websocket_server_remove_protocol, (struct ast_websocket_server *server, const char *name, ast_websocket_callback callback), {return -1;});
233
234/*!
235 * \brief Read a WebSocket frame and handle it
236 *
237 * \param session Pointer to the WebSocket session
238 * \param payload Pointer to a char* which will be populated with a pointer to the payload if present
239 * \param payload_len Pointer to a uint64_t which will be populated with the length of the payload if present
240 * \param opcode Pointer to an enum which will be populated with the opcode of the frame
241 * \param fragmented Pointer to an int which is set to 1 if payload is fragmented and 0 if not
242 *
243 * \retval -1 on error
244 * \retval 0 on success
245 *
246 * \note Once an AST_WEBSOCKET_OPCODE_CLOSE opcode is received the socket will be closed
247 */
248AST_OPTIONAL_API(int, ast_websocket_read, (struct ast_websocket *session, char **payload, uint64_t *payload_len, enum ast_websocket_opcode *opcode, int *fragmented), { errno = ENOSYS; return -1;});
249
250/*!
251 * \brief Read a WebSocket frame containing string data.
252 *
253 * \note The caller is responsible for freeing the output "buf".
254 *
255 * \param ws pointer to the websocket
256 * \param buf string buffer to populate with data read from socket
257 * \retval -1 on error
258 * \return number of bytes read on success
259 *
260 * \note Once an AST_WEBSOCKET_OPCODE_CLOSE opcode is received the socket will be closed
261 */
263 (struct ast_websocket *ws, char **buf),
264 { errno = ENOSYS; return -1;});
265
266/*!
267 * \brief Construct and transmit a WebSocket frame
268 *
269 * \param session Pointer to the WebSocket session
270 * \param opcode WebSocket operation code to place in the frame
271 * \param payload Optional pointer to a payload to add to the frame
272 * \param payload_size Length of the payload (0 if no payload)
273 *
274 * \retval 0 if successfully written
275 * \retval -1 if error occurred
276 */
277AST_OPTIONAL_API(int, ast_websocket_write, (struct ast_websocket *session, enum ast_websocket_opcode opcode, char *payload, uint64_t payload_size), { errno = ENOSYS; return -1;});
278
279/*!
280 * \brief Construct and transmit a WebSocket frame containing string data.
281 *
282 * \param ws pointer to the websocket
283 * \param buf string data to write to socket
284 * \retval 0 if successfully written
285 * \retval -1 if error occurred
286 */
288 (struct ast_websocket *ws, const char *buf),
289 { errno = ENOSYS; return -1;});
290/*!
291 * \brief Close a WebSocket session by sending a message with the CLOSE opcode and an optional code
292 *
293 * \param session Pointer to the WebSocket session
294 * \param reason Reason code for closing the session as defined in the RFC
295 *
296 * \retval 0 if successfully written
297 * \retval -1 if error occurred
298 */
299AST_OPTIONAL_API(int, ast_websocket_close, (struct ast_websocket *session, uint16_t reason), { errno = ENOSYS; return -1;});
300
301/*!
302 * \brief Enable multi-frame reconstruction up to a certain number of bytes
303 *
304 * \param session Pointer to the WebSocket session
305 * \param bytes If a reconstructed payload exceeds the specified number of bytes the payload will be returned
306 * and upon reception of the next multi-frame a new reconstructed payload will begin.
307 */
308AST_OPTIONAL_API(void, ast_websocket_reconstruct_enable, (struct ast_websocket *session, size_t bytes), {return;});
309
310/*!
311 * \brief Disable multi-frame reconstruction
312 *
313 * \param session Pointer to the WebSocket session
314 *
315 * \note If reconstruction is disabled each message that is part of a multi-frame message will be sent up to
316 * the user when ast_websocket_read is called.
317 */
319
320/*!
321 * \brief Increase the reference count for a WebSocket session
322 *
323 * \param session Pointer to the WebSocket session
324 */
325AST_OPTIONAL_API(void, ast_websocket_ref, (struct ast_websocket *session), {return;});
326
327/*!
328 * \brief Decrease the reference count for a WebSocket session
329 *
330 * \param session Pointer to the WebSocket session
331 */
332AST_OPTIONAL_API(void, ast_websocket_unref, (struct ast_websocket *session), {return;});
333
334/*!
335 * \brief Get the file descriptor for a WebSocket session.
336 *
337 * \return file descriptor
338 *
339 * \note You must *not* directly read from or write to this file descriptor. It should only be used for polling.
340 */
341AST_OPTIONAL_API(int, ast_websocket_fd, (struct ast_websocket *session), { errno = ENOSYS; return -1;});
342
343/*!
344 * \brief Wait for the WebSocket session to be ready to be read.
345 * \since 16.8.0
346 * \since 17.2.0
347 *
348 * \param session Pointer to the WebSocket session
349 * \param timeout the number of milliseconds to wait
350 *
351 * \retval -1 if error occurred
352 * \retval 0 if the timeout expired
353 * \retval 1 if the WebSocket session is ready for reading
354 */
355AST_OPTIONAL_API(int, ast_websocket_wait_for_input, (struct ast_websocket *session, int timeout), { errno = ENOSYS; return -1; });
356
357/*!
358 * \brief Get the remote address for a WebSocket connected session.
359 *
360 * \return Remote address
361 */
363
364/*!
365 * \brief Get the local address for a WebSocket connection session.
366 *
367 * \return Local address
368 *
369 * \since 13.19.0
370 */
372
373/*!
374 * \brief Get whether the WebSocket session is using a secure transport or not.
375 *
376 * \retval 0 if unsecure
377 * \retval 1 if secure
378 */
379AST_OPTIONAL_API(int, ast_websocket_is_secure, (struct ast_websocket *session), { errno = ENOSYS; return -1;});
380
381/*!
382 * \brief Set the socket of a WebSocket session to be non-blocking.
383 *
384 * \retval 0 on success
385 * \retval -1 on failure
386 */
387AST_OPTIONAL_API(int, ast_websocket_set_nonblock, (struct ast_websocket *session), { errno = ENOSYS; return -1;});
388
389/*!
390 * \brief Get the session ID for a WebSocket session.
391 *
392 * \return session id
393 */
394AST_OPTIONAL_API(const char *, ast_websocket_session_id, (struct ast_websocket *session), { errno = ENOSYS; return NULL;});
395
396/*!
397 * \brief Result code for a websocket client.
398 */
414};
415
416/*!
417 * \brief Create, and connect, a websocket client.
418 *
419 * If the client websocket successfully connects, then the accepted protocol can be
420 * checked via a call to ast_websocket_client_accept_protocol.
421 *
422 * \note While connecting this *will* block until a response is
423 * received from the remote host.
424 * \note Expected uri form:
425 * \verbatim ws[s]://<address>[:port][/<path>] \endverbatim
426 * The address (can be a host name) and port are parsed out and used to connect
427 * to the remote server. If multiple IPs are returned during address
428 * resolution then the first one is chosen.
429 *
430 * \param uri uri to connect to
431 * \param protocols a comma separated string of supported protocols
432 * \param tls_cfg secure websocket credentials
433 * \param result result code set on client failure
434 * \return a client websocket.
435 * \retval NULL if object could not be created or connected
436 * \since 13
437 */
439 (const char *uri, const char *protocols,
440 struct ast_tls_config *tls_cfg,
441 enum ast_websocket_result *result), { return NULL;});
442
443/*!
444 * \brief Options used for a websocket client
445 */
447 /*!
448 * The URI to connect to
449 *
450 * Expected uri form:
451 * \verbatim ws[s]://<address>[:port][/<path>] \endverbatim
452 * The address (can be a host name) and port are parsed out and used to connect
453 * to the remote server. If multiple IPs are returned during address
454 * resolution then the first one is chosen.
455 */
456 const char *uri;
457 /*!
458 * A comma separated string of supported protocols
459 */
460 const char *protocols;
461 /*!
462 * Optional connection timeout
463 *
464 * How long (in milliseconds) to attempt to connect (-1 equals infinite)
465 */
467 /*!
468 * Secure websocket credentials
469 */
471};
472
473/*!
474 * \brief Create, and connect, a websocket client using given options.
475 *
476 * If the client websocket successfully connects, then the accepted protocol can be
477 * checked via a call to ast_websocket_client_accept_protocol.
478 *
479 * \note While connecting this *will* block until a response is received
480 * from the remote host, or the connection timeout is reached
481 *
482 * \param options Websocket client options
483 * \param result result code set on client failure
484 *
485 * \return a client websocket.
486 * \retval NULL if object could not be created or connected
487 */
490 enum ast_websocket_result *result), { return NULL;});
491
492/*!
493 * \brief Retrieve the server accepted sub-protocol on the client.
494 *
495 * \param ws the websocket client
496 * \return the accepted client sub-protocol.
497 * \since 13
498 */
500 (struct ast_websocket *ws), { return NULL;});
501
502/*!
503 * \brief Set the timeout on a non-blocking WebSocket session.
504 *
505 * \since 11.11.0
506 * \since 12.4.0
507 *
508 * \retval 0 on success
509 * \retval -1 on failure
510 */
511AST_OPTIONAL_API(int, ast_websocket_set_timeout, (struct ast_websocket *session, int timeout), {return -1;});
512
513#endif
static struct ast_mansession session
static PGresult * result
Definition: cel_pgsql.c:84
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
static const char name[]
Definition: format_mp3.c:68
Support for Private Asterisk HTTP Servers.
ast_http_method
HTTP Request methods known by Asterisk.
Definition: http.h:58
struct ast_websocket_protocol * ast_websocket_sub_protocol_alloc(const char *name)
Allocate a websocket sub-protocol instance.
int ast_websocket_read_string(struct ast_websocket *ws, char **buf)
Read a WebSocket frame containing string data.
int ast_websocket_is_secure(struct ast_websocket *session)
Get whether the WebSocket session is using a secure transport or not.
void ast_websocket_reconstruct_disable(struct ast_websocket *session)
Disable multi-frame reconstruction.
int ast_websocket_remove_protocol(const char *name, ast_websocket_callback callback)
Remove a sub-protocol handler from the default /ws server.
int ast_websocket_set_timeout(struct ast_websocket *session, int timeout)
Set the timeout on a non-blocking WebSocket session.
int ast_websocket_close(struct ast_websocket *session, uint16_t reason)
Close a WebSocket session by sending a message with the CLOSE opcode and an optional code.
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.
int ast_websocket_wait_for_input(struct ast_websocket *session, int timeout)
Wait for the WebSocket session to be ready to be read.
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.
int ast_websocket_server_add_protocol(struct ast_websocket_server *server, const char *name, ast_websocket_callback callback)
Add a sub-protocol handler to the given server.
int ast_websocket_server_remove_protocol(struct ast_websocket_server *server, const char *name, ast_websocket_callback callback)
Remove a sub-protocol handler from the given server.
ast_websocket_result
Result code for a websocket client.
@ WS_BAD_REQUEST
@ WS_URL_NOT_FOUND
@ WS_CLIENT_START_ERROR
@ WS_KEY_ERROR
@ WS_NOT_SUPPORTED
@ WS_ALLOCATE_ERROR
@ WS_HEADER_MISMATCH
@ WS_WRITE_ERROR
@ WS_URI_RESOLVE_ERROR
@ WS_OK
@ WS_INVALID_RESPONSE
@ WS_BAD_STATUS
@ WS_URI_PARSE_ERROR
@ WS_HEADER_MISSING
int(* ast_websocket_pre_callback)(struct ast_tcptls_session_instance *ser, struct ast_variable *parameters, struct ast_variable *headers, const char *session_id)
Callback from the HTTP request attempting to establish a websocket connection.
struct ast_sockaddr * ast_websocket_local_address(struct ast_websocket *session)
Get the local address for a WebSocket connection session.
struct ast_websocket * ast_websocket_client_create(const char *uri, const char *protocols, struct ast_tls_config *tls_cfg, enum ast_websocket_result *result)
Create, and connect, a websocket client.
void ast_websocket_ref(struct ast_websocket *session)
Increase the reference count for a WebSocket session.
ast_websocket_opcode
WebSocket operation codes.
@ AST_WEBSOCKET_OPCODE_PING
@ AST_WEBSOCKET_OPCODE_PONG
@ AST_WEBSOCKET_OPCODE_CONTINUATION
@ AST_WEBSOCKET_OPCODE_BINARY
@ AST_WEBSOCKET_OPCODE_CLOSE
@ AST_WEBSOCKET_OPCODE_TEXT
int ast_websocket_add_protocol2(struct ast_websocket_protocol *protocol)
Add a sub-protocol handler to the default /ws server.
void ast_websocket_unref(struct ast_websocket *session)
Decrease the reference count for a WebSocket session.
void ast_websocket_reconstruct_enable(struct ast_websocket *session, size_t bytes)
Enable multi-frame reconstruction up to a certain number of bytes.
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.
const char * ast_websocket_client_accept_protocol(struct ast_websocket *ws)
Retrieve the server accepted sub-protocol on the client.
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.
void(* ast_websocket_callback)(struct ast_websocket *session, struct ast_variable *parameters, struct ast_variable *headers)
Callback for when a new connection for a sub-protocol is established.
struct ast_websocket_server * ast_websocket_server_create(void)
Creates a ast_websocket_server.
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.
int ast_websocket_add_protocol(const char *name, ast_websocket_callback callback)
Add a sub-protocol handler to the default /ws server.
int errno
Optional API function macros.
#define AST_OPTIONAL_API(result, name, proto, stub)
Declare an optional API function.
Definition: optional_api.h:230
const char * method
Definition: res_pjsip.c:1279
#define NULL
Definition: resample.c:96
Definition of a URI handler.
Definition: http.h:102
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.
Options used for a websocket client.
struct ast_tls_config * tls_cfg
A websocket protocol implementation.
ast_websocket_callback session_established
Callback called when a new session is established. Mandatory.
unsigned int version
Protocol version. Should be set to /ref AST_WEBSOCKET_PROTOCOL_VERSION.
char * name
Name of the protocol.
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 struct test_options options