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