38 #include "asterisk/uri.h"
41 #define AST_API_MODULE
45 #define WEBSOCKET_GUID "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
48 #define CLIENT_KEY_SIZE 16
51 #define MAX_PROTOCOL_BUCKETS 7
55 #define MAXIMUM_FRAME_SIZE 8192
60 #define DEFAULT_RECONSTRUCTION_CEILING 8192
63 #define MAXIMUM_RECONSTRUCTION_CEILING 8192
66 #define MAXIMUM_FRAME_SIZE 65535
71 #define DEFAULT_RECONSTRUCTION_CEILING MAXIMUM_FRAME_SIZE
74 #define MAXIMUM_RECONSTRUCTION_CEILING MAXIMUM_FRAME_SIZE
84 #define MAX_WS_HDR_SZ 14
85 #define MIN_WS_HDR_SZ 2
110 const char *
name = obj;
119 const char *protocol = arg;
128 ast_free(protocol->
name);
136 static void websocket_server_dtor(
void *obj)
147 server = ao2_alloc(
sizeof(*server), websocket_server_dtor);
154 if (!server->protocols) {
164 return websocket_server_create_impl();
169 return websocket_server_create_impl();
182 ast_verb(2,
"WebSocket connection %s '%s' closed\n", session->
client ?
"to" :
"from",
187 ao2_cleanup(session->
client);
201 if (!protocol->
name) {
218 protocol = ast_websocket_sub_protocol_alloc(name);
224 if (ast_websocket_server_add_protocol2(server, protocol)) {
241 ast_log(LOG_WARNING,
"WebSocket could not register sub-protocol '%s': "
242 "expected version '%u', got version '%u'\n",
260 ast_verb(5,
"WebSocket registered sub-protocol '%s'\n", protocol->
name);
282 ast_verb(5,
"WebSocket unregistered sub-protocol '%s'\n", name);
293 uint8_t mask_key_idx;
294 uint32_t mask_key = ast_random();
295 uint8_t length = frame[1] & 0x7f;
298 mask_key_idx = length == 126 ? 4 : length == 127 ? 10 : 2;
299 put_unaligned_uint32(&frame[mask_key_idx], mask_key);
300 for (i = 0; i < payload_size; i++) {
301 payload[i] ^= ((
char *)&mask_key)[i % 4];
313 char frame[8] = { 0, };
314 int header_size, fsize, res;
321 header_size = session->
client ? 6 : 2;
322 fsize = header_size + 2;
324 frame[0] = opcode | 0x80;
328 put_unaligned_uint16(&frame[header_size], htons(reason ? reason : 1000));
346 ast_verb(2,
"WebSocket connection %s '%s' forcefully closed due to fatal write error\n",
351 return res ==
sizeof(frame);
354 static const char *opcode_map[] = {
369 return opcode_map[
opcode];
376 size_t header_size = 2;
381 ast_debug(3,
"Writing websocket %s frame, length %" PRIu64
"\n",
382 websocket_opcode2str(opcode), payload_size);
384 if (payload_size < 126) {
385 length = payload_size;
386 }
else if (payload_size < (1 << 16)) {
401 frame_size = header_size + payload_size;
404 memset(frame, 0, frame_size + 1);
406 frame[0] = opcode | 0x80;
411 put_unaligned_uint16(&frame[2], htons(payload_size));
412 }
else if (length == 127) {
413 put_unaligned_uint64(&frame[2], htonll(payload_size));
416 memcpy(&frame[header_size], payload, payload_size);
430 ast_debug(1,
"Closing WS with 1011 because we can't fulfill a write request\n");
458 ao2_cleanup(session);
551 errno = ECONNABORTED;
559 ast_log(LOG_WARNING,
"Web socket closed abruptly\n");
566 if (rlen < 0 && errno != EAGAIN) {
567 ast_log(LOG_ERROR,
"Error reading from web socket: %s\n", strerror(errno));
575 ast_log(LOG_WARNING,
"Websocket seems unresponsive, disconnecting ...\n");
590 ast_log(LOG_ERROR,
"ast_iostream_wait_for_input returned err: %s\n", strerror(errno));
605 int mask_present = 0;
606 char *mask = NULL, *new_payload = NULL;
607 size_t options_len = 0, frame_size = 0;
613 if (ws_safe_read(session, &session->
buf[0], MIN_WS_HDR_SZ, opcode)) {
616 frame_size += MIN_WS_HDR_SZ;
619 *opcode = session->
buf[0] & 0xf;
620 *payload_len = session->
buf[1] & 0x7f;
623 fin = (session->
buf[0] >> 7) & 1;
624 mask_present = (session->
buf[1] >> 7) & 1;
627 options_len += mask_present ? 4 : 0;
628 options_len += (*payload_len == 126) ? 2 : (*payload_len == 127) ? 8 : 0;
631 if (ws_safe_read(session, &session->
buf[frame_size], options_len, opcode)) {
634 frame_size += options_len;
637 if (*payload_len == 126) {
639 *payload_len = ntohs(get_unaligned_uint16(&session->
buf[2]));
640 mask = &session->
buf[4];
641 }
else if (*payload_len == 127) {
643 *payload_len = ntohll(get_unaligned_uint64(&session->
buf[2]));
644 mask = &session->
buf[10];
647 mask = &session->
buf[2];
651 *payload = &session->
buf[frame_size];
652 frame_size = frame_size + (*payload_len);
654 ast_log(LOG_WARNING,
"Cannot fit huge websocket frame of %zu bytes\n", frame_size);
661 if (ws_safe_read(session, *payload, *payload_len, opcode)) {
670 (*payload)[pos] ^= mask[pos % 4];
692 if (*payload_len >= 2) {
702 ast_log(LOG_WARNING,
"Failed allocation: %p, %zu, %"PRIu64
"\n",
709 session->
payload = new_payload;
732 *opcode = session->
opcode;
740 ast_log(LOG_WARNING,
"WebSocket unknown opcode %u\n", *opcode);
764 static char *websocket_combine_key(
const char *key,
char *res,
int res_size)
767 unsigned combined_length = strlen(key) + strlen(
WEBSOCKET_GUID) + 1;
786 ast_str_set(&http_header, 0,
"Sec-WebSocket-Version: 7, 8, 13\r\n");
793 const char *upgrade = NULL, *key = NULL, *key1 = NULL, *key2 = NULL, *protos = NULL;
794 char *requested_protocols = NULL, *protocol = NULL;
795 int version = 0, flags = 1;
803 if (method != AST_HTTP_GET) {
804 ast_http_error(ser, 501,
"Not Implemented",
"Attempt to use unimplemented / unsupported method");
811 for (v = headers; v; v = v->
next) {
812 if (!strcasecmp(v->
name,
"Upgrade")) {
814 }
else if (!strcasecmp(v->
name,
"Sec-WebSocket-Key")) {
816 }
else if (!strcasecmp(v->
name,
"Sec-WebSocket-Key1")) {
818 }
else if (!strcasecmp(v->
name,
"Sec-WebSocket-Key2")) {
820 }
else if (!strcasecmp(v->
name,
"Sec-WebSocket-Protocol")) {
822 }
else if (!strcasecmp(v->
name,
"Sec-WebSocket-Version")) {
823 if (sscanf(v->
value,
"%30d", &version) != 1) {
830 if (!upgrade || strcasecmp(upgrade,
"websocket")) {
831 ast_log(LOG_WARNING,
"WebSocket connection from '%s' could not be accepted - did not request WebSocket\n",
835 }
else if (ast_strlen_zero(protos)) {
840 if (!protocol_handler) {
842 ast_log(LOG_WARNING,
"WebSocket connection from '%s' could not be accepted - no protocols requested\n",
844 websocket_bad_request(ser);
847 }
else if (key1 && key2) {
850 ast_log(LOG_WARNING,
"WebSocket connection from '%s' could not be accepted - unsupported version '00/76' chosen\n",
852 websocket_bad_request(ser);
856 if (!protocol_handler && protos) {
859 while (!protocol_handler && (protocol = strsep(&requested_protocols,
","))) {
865 if (!protocol_handler) {
866 ast_log(LOG_WARNING,
"WebSocket connection from '%s' could not be accepted - no protocols out of '%s' supported\n",
868 websocket_bad_request(ser);
873 if (version == 7 || version == 8 || version == 13) {
877 websocket_bad_request(ser);
883 websocket_bad_request(ser);
888 if (!(session = ao2_alloc(
sizeof(*session) + AST_UUID_STR_LEN + 1,
session_destroy_fn))) {
889 ast_log(LOG_WARNING,
"WebSocket connection from '%s' could not be accepted\n",
891 websocket_bad_request(ser);
899 ast_log(LOG_WARNING,
"WebSocket connection from '%s' could not be accepted - failed to generate a session id\n",
901 ast_http_error(ser, 500,
"Internal Server Error",
"Allocation failed");
908 ast_debug(3,
"WebSocket connection from '%s' rejected by protocol handler '%s'\n",
910 websocket_bad_request(ser);
926 "HTTP/1.1 101 Switching Protocols\r\n"
928 "Connection: Upgrade\r\n"
929 "Sec-WebSocket-Accept: %s\r\n"
930 "Sec-WebSocket-Protocol: %s\r\n\r\n",
932 websocket_combine_key(key, base64,
sizeof(base64)),
936 "HTTP/1.1 101 Switching Protocols\r\n"
938 "Connection: Upgrade\r\n"
939 "Sec-WebSocket-Accept: %s\r\n\r\n",
941 websocket_combine_key(key, base64,
sizeof(base64)));
946 ast_log(LOG_WARNING,
"WebSocket connection from '%s' could not be accepted - unsupported version '%d' chosen\n",
948 websocket_bad_request(ser);
955 ast_log(LOG_WARNING,
"WebSocket connection from '%s' could not be accepted - failed to enable keepalive\n",
957 websocket_bad_request(ser);
965 ast_log(LOG_WARNING,
"WebSocket connection from '%s' could not be accepted - failed to get local address\n",
967 websocket_bad_request(ser);
973 ast_verb(2,
"WebSocket connection from '%s' for protocol '%s' accepted using version '%d'\n",
ast_sockaddr_stringify(&ser->remote_address), protocol ? :
"", version);
999 .description =
"Asterisk HTTP WebSocket",
1011 ast_debug(1,
"Entering WebSocket echo loop\n");
1017 while ((res = ast_websocket_wait_for_input(session, -1)) > 0) {
1019 uint64_t payload_len;
1023 if (ast_websocket_read(session, &payload, &payload_len, &opcode, &fragmented)) {
1025 ast_log(LOG_WARNING,
"Read failure during WebSocket echo loop\n");
1034 ast_debug(1,
"Ignored WebSocket opcode %u\n", opcode);
1039 ast_debug(1,
"Exiting WebSocket echo loop\n");
1040 ast_websocket_unref(session);
1049 return ast_websocket_server_add_protocol(ws_server, name, callback);
1054 return websocket_add_protocol_internal(name, callback);
1065 if (ast_websocket_server_add_protocol2(ws_server, protocol)) {
1078 return ast_websocket_server_remove_protocol(ws_server, name, callback);
1083 return websocket_remove_protocol_internal(name, callback);
1096 struct ast_uri *parsed_uri = ast_uri_parse_websocket(uri);
1102 *host = ast_uri_make_host_with_port(parsed_uri);
1104 if (ast_uri_path(parsed_uri) || ast_uri_query(parsed_uri)) {
1111 if (ast_uri_path(parsed_uri)) {
1112 ast_str_set(path, 0,
"%s", ast_uri_path(parsed_uri));
1115 if (ast_uri_query(parsed_uri)) {
1124 static void websocket_client_args_destroy(
void *obj)
1129 ast_free(args->
tls_cfg->certfile);
1130 ast_free(args->
tls_cfg->pvtfile);
1131 ast_free(args->
tls_cfg->cipher);
1132 ast_free(args->
tls_cfg->cafile);
1133 ast_free(args->
tls_cfg->capath);
1146 sizeof(*args), websocket_client_args_destroy);
1149 *result = WS_ALLOCATE_ERROR;
1153 args->accept_fd = -1;
1155 args->name =
"websocket client";
1158 ast_log(LOG_ERROR,
"Unable to resolve address %s\n",
1161 *result = WS_URI_RESOLVE_ERROR;
1170 (
int) strcspn(host,
":"), host);
1175 static char *websocket_client_create_key(
void)
1184 ast_log(LOG_ERROR,
"Unable to allocate client websocket key\n");
1189 long num = ast_random();
1190 memcpy(key + i, &num,
sizeof(
long));
1217 static void websocket_client_destroy(
void *obj)
1221 ao2_cleanup(client->
ser);
1222 ao2_cleanup(client->
args);
1226 ast_free(client->
key);
1228 ast_free(client->
host);
1237 ast_log(LOG_ERROR,
"Unable to allocate websocket\n");
1238 *result = WS_ALLOCATE_ERROR;
1242 if (!(ws->
client = ao2_alloc(
1243 sizeof(*ws->
client), websocket_client_destroy))) {
1244 ast_log(LOG_ERROR,
"Unable to allocate websocket client\n");
1245 *result = WS_ALLOCATE_ERROR;
1249 if (!(ws->
client->
key = websocket_client_create_key())) {
1251 *result = WS_KEY_ERROR;
1258 *result = WS_URI_PARSE_ERROR;
1262 if (!(ws->
client->
args = websocket_client_args_create(
1276 ast_websocket_client_accept_protocol)(
struct ast_websocket *ws)
1284 if (response_code <= 0) {
1285 return WS_INVALID_RESPONSE;
1288 switch (response_code) {
1292 ast_log(LOG_ERROR,
"Received response 400 - Bad Request "
1293 "- from %s\n", client->
host);
1294 return WS_BAD_REQUEST;
1296 ast_log(LOG_ERROR,
"Received response 404 - Request URL not "
1297 "found - from %s\n", client->
host);
1298 return WS_URL_NOT_FOUND;
1301 ast_log(LOG_ERROR,
"Invalid HTTP response code %d from %s\n",
1302 response_code, client->
host);
1303 return WS_INVALID_RESPONSE;
1312 int has_upgrade = 0;
1313 int has_connection = 0;
1315 int has_protocol = 0;
1318 if (errno == EINTR || errno == EAGAIN) {
1322 ast_log(LOG_ERROR,
"Unable to retrieve HTTP status line.");
1323 return WS_BAD_STATUS;
1326 if ((res = websocket_client_handle_response_code(client,
1328 buf,
"HTTP/1.1", 101))) != WS_OK) {
1340 if (errno == EINTR || errno == EAGAIN) {
1357 name,
"upgrade", value,
"websocket")) < 0) {
1358 return WS_HEADER_MISMATCH;
1359 }
else if (!has_connection &&
1361 name,
"connection", value,
"upgrade")) < 0) {
1362 return WS_HEADER_MISMATCH;
1363 }
else if (!has_accept &&
1365 name,
"sec-websocket-accept", value,
1366 websocket_combine_key(
1367 client->
key, base64,
sizeof(base64)))) < 0) {
1368 return WS_HEADER_MISMATCH;
1369 }
else if (!has_protocol &&
1371 name,
"sec-websocket-protocol", value, client->
protocols))) {
1372 if (has_protocol < 0) {
1373 return WS_HEADER_MISMATCH;
1376 }
else if (!strcasecmp(name,
"sec-websocket-extensions")) {
1377 ast_log(LOG_ERROR,
"Extensions received, but not "
1378 "supported by client\n");
1379 return WS_NOT_SUPPORTED;
1383 return has_upgrade && has_connection && has_accept ?
1384 WS_OK : WS_HEADER_MISSING;
1390 char protocols[100] =
"";
1392 if (!ast_strlen_zero(client->
protocols)) {
1393 sprintf(protocols,
"Sec-WebSocket-Protocol: %s\r\n",
1398 "GET /%s HTTP/1.1\r\n"
1399 "Sec-WebSocket-Version: %d\r\n"
1400 "Upgrade: websocket\r\n"
1401 "Connection: Upgrade\r\n"
1403 "Sec-WebSocket-Key: %s\r\n"
1410 ast_log(LOG_ERROR,
"Failed to send handshake.\n");
1411 return WS_WRITE_ERROR;
1414 return websocket_client_handshake_get_response(client);
1424 return WS_CLIENT_START_ERROR;
1427 if ((res = websocket_client_handshake(ws->
client)) != WS_OK) {
1441 (
const char *uri,
const char *protocols,
struct ast_tls_config *tls_cfg,
1451 return ast_websocket_client_create_with_options(&options, result);
1457 struct ast_websocket *ws = websocket_client_create(options, result);
1463 if ((*result = websocket_client_connect(ws, options->
timeout)) != WS_OK) {
1479 while (fragmented) {
1480 if (ast_websocket_read(ws, &payload, &payload_len,
1481 &opcode, &fragmented)) {
1482 ast_log(LOG_ERROR,
"Client WebSocket string read - "
1483 "error reading string data\n");
1502 ast_log(LOG_ERROR,
"Client WebSocket string read - "
1503 "non string data received\n");
1508 if (!(*buf =
ast_strndup(payload, payload_len))) {
1512 return payload_len + 1;
1518 uint64_t len = strlen(buf);
1520 ast_debug(3,
"Writing websocket string of length %" PRIu64
"\n", len);
1533 static int load_module(
void)
1535 websocketuri.
data = websocket_server_internal_create();
1536 if (!websocketuri.
data) {
1545 static int unload_module(
void)
1550 websocketuri.
data = NULL;
1555 AST_MODULE_INFO(
ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER,
"HTTP WebSocket Support",
1556 .support_level = AST_MODULE_SUPPORT_CORE,
1557 .load = load_module,
1558 .unload = unload_module,
void ast_iostream_set_exclusive_input(struct ast_iostream *stream, int exclusive_input)
Set the iostream if it can exclusively depend upon the set timeouts.
struct ast_variable * next
static struct ast_websocket_protocol * one_protocol(struct ast_websocket_server *server)
If the server has exactly one configured protocol, return it.
int ast_iostream_wait_for_input(struct ast_iostream *stream, int timeout)
Wait for input on the iostream's file descriptor.
Asterisk main include file. File version handling, generic pbx functions.
#define ast_realloc(p, len)
A wrapper for realloc()
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
void ast_http_error(struct ast_tcptls_session_instance *ser, int status, const char *title, const char *text)
Send HTTP error message and close socket.
String manipulation functions.
A websocket protocol implementation.
void ast_ssl_teardown(struct ast_tls_config *cfg)
free resources used by an SSL server
#define WEBSOCKET_GUID
GUID used to compute the accept key, defined in the specifications.
int ast_http_body_discard(struct ast_tcptls_session_instance *ser)
Read and discard any unread HTTP request body.
static void ast_sockaddr_copy(struct ast_sockaddr *dst, const struct ast_sockaddr *src)
Copies the data from one ast_sockaddr to another.
ssize_t ast_iostream_write(struct ast_iostream *stream, const void *buffer, size_t count)
Write data to an iostream.
ast_websocket_result
Result code for a websocket client.
static int websocket_client_parse_uri(const char *uri, char **host, struct ast_str **path)
Parse the given uri into a path and remote address.
struct ast_tcptls_session_instance * ser
Structure for a WebSocket server.
ast_websocket_pre_callback session_attempted
Callback called when a new session is attempted. Optional.
int ast_http_uri_link(struct ast_http_uri *urihandler)
Register a URI handler.
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container, as described below.
Stores parsed uri information.
Structure for variables, used for configurations and for channel variables.
struct ast_tcptls_session_args * args
Universally unique identifier support.
void ast_iostream_set_timeout_inactivity(struct ast_iostream *stream, int timeout)
Set the iostream inactivity timeout timer.
void ast_http_uri_unlink(struct ast_http_uri *urihandler)
Unregister a URI handler.
Assume that the ao2_container is already locked.
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
int AST_OPTIONAL_API_NAME() ast_websocket_close(struct ast_websocket *session, uint16_t reason)
Close function for websocket session.
int ast_iostream_get_fd(struct ast_iostream *stream)
Get an iostream's file descriptor.
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
arguments for the accepting thread
#define DEFAULT_RECONSTRUCTION_CEILING
Default reconstruction size for multi-frame payload reconstruction. If exceeded the next frame will s...
struct ao2_container * protocols
#define ao2_link_flags(container, obj, flags)
Add an object to a container.
#define ast_strdup(str)
A wrapper for strdup()
Generic File Format Support. Should be included by clients of the file handling routines. File service providers should instead include mod_format.h.
struct ast_str * resource_name
void ast_http_send(struct ast_tcptls_session_instance *ser, enum ast_http_method method, int status_code, const char *status_title, struct ast_str *http_header, struct ast_str *out, int fd, unsigned int static_content)
Generic function for sending HTTP/1.1 response.
Socket address structure.
static void websocket_echo_callback(struct ast_websocket *session, struct ast_variable *parameters, struct ast_variable *headers)
Simple echo implementation which echoes received text and binary frames.
static int protocol_hash_fn(const void *obj, const int flags)
Hashing function for protocols.
ssize_t ast_iostream_read(struct ast_iostream *stream, void *buffer, size_t count)
Read data from an iostream.
SSL * ast_iostream_get_ssl(struct ast_iostream *stream)
Get a pointer to an iostream's OpenSSL SSL structure.
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Support for Private Asterisk HTTP Servers.
#define ast_fd_set_flags(fd, flags)
Set flags on the given file descriptor.
Handle unaligned data access.
enum ast_websocket_opcode opcode
char * name
Name of the protocol.
int ast_iostream_close(struct ast_iostream *stream)
Close an iostream.
#define MAX_PROTOCOL_BUCKETS
Number of buckets for registered protocols.
int ast_http_header_parse(char *buf, char **name, char **value)
Parse a header into the given name/value strings.
#define ast_strdupa(s)
duplicate a string in memory from the stack
Options used for a websocket client.
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
struct websocket_client * client
struct ast_tls_config * tls_cfg
ssize_t ast_iostream_printf(struct ast_iostream *stream, const char *format,...)
Write a formatted string to an iostream.
#define ast_malloc(len)
A wrapper for malloc()
#define ast_debug(level,...)
Log a DEBUG message.
struct ast_sockaddr local_address
int ast_http_header_match_in(const char *name, const char *expected_name, const char *value, const char *expected_value)
Check if the header name matches the expected header name. If so, then check to see if the value can ...
Support for WebSocket connections within the Asterisk HTTP server and client WebSocket connections to...
describes a server instance
void ast_sha1_hash_uint(uint8_t *digest, const char *input)
Produces SHA1 hash based on input string, stored in uint8_t array.
static void websocket_mask_payload(struct ast_websocket *session, char *frame, char *payload, uint64_t payload_size)
Perform payload masking for client sessions.
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
void ast_iostream_set_timeout_disable(struct ast_iostream *stream)
Disable the iostream timeout timer.
char session_id[AST_UUID_STR_LEN]
uint16_t close_status_code
#define AST_DEFAULT_WEBSOCKET_WRITE_TIMEOUT
Default websocket write timeout, in ms.
#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.
int ast_http_header_match(const char *name, const char *expected_name, const char *value, const char *expected_value)
Check if the header and value match (case insensitive) their associated expected values.
Support for dynamic strings.
void ast_iostream_set_timeout_sequence(struct ast_iostream *stream, struct timeval start, int timeout)
Set the iostream I/O sequence timeout timer.
int ast_base64encode(char *dst, const unsigned char *src, int srclen, int max)
Encode data in base64.
#define ao2_unlink(container, obj)
Remove an object from a container.
static int protocol_cmp_fn(void *obj, void *arg, int flags)
Comparison function for protocols.
static char * ast_sockaddr_stringify(const struct ast_sockaddr *addr)
Wrapper around ast_sockaddr_stringify_fmt() with default format.
static void session_destroy_fn(void *obj)
Destructor function for sessions.
#define ast_strndup(str, len)
A wrapper for strndup()
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.
#define MAXIMUM_FRAME_SIZE
Size of the pre-determined buffer for WebSocket frames.
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.
#define SCOPED_AO2LOCK(varname, obj)
scoped lock specialization for ao2 mutexes.
Structure definition for session.
char * ast_uuid_generate_str(char *buf, size_t size)
Generate a UUID string.
Module has failed to load, may be in an inconsistent state.
#define SCOPED_MODULE_USE(module)
struct ast_iostream * stream
struct ast_tcptls_session_instance * ast_tcptls_client_start_timeout(struct ast_tcptls_session_instance *tcptls_session, int timeout)
Attempt to connect and start a tcptls session within the given timeout.
ssize_t ast_iostream_gets(struct ast_iostream *stream, char *buffer, size_t size)
Read a LF-terminated string from an iostream.
struct ast_sockaddr remote_address
struct ast_tcptls_session_instance * ast_tcptls_client_create(struct ast_tcptls_session_args *desc)
Creates a client connection's ast_tcptls_session_instance.
struct ast_iostream * stream
Definition of a URI handler.
void ast_iostream_nonblock(struct ast_iostream *stream)
Make an iostream non-blocking.
#define MAXIMUM_RECONSTRUCTION_CEILING
Maximum reconstruction size for multi-frame payload reconstruction.
static void protocol_destroy_fn(void *obj)
Destructor function for protocols.
#define CLIENT_KEY_SIZE
Length of a websocket's client key.
#define AST_OPTIONAL_API_NAME(name)
Expands to the name of the implementation function.
struct ast_tls_config * tls_cfg
ast_websocket_callback session_established
Callback called when a new session is established. Mandatory.
ast_http_method
HTTP Request methods known by Asterisk.
int ast_getsockname(int sockfd, struct ast_sockaddr *addr)
Wrapper around getsockname(2) that uses struct ast_sockaddr.
#define ASTERISK_GPL_KEY
The text the key() function should return.
#define AST_WEBSOCKET_PROTOCOL_VERSION
Protocol version. This prevents dynamically loadable modules from registering if this struct is chang...
Asterisk module definitions.
ast_websocket_opcode
WebSocket operation codes.
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
void ast_http_request_close_on_completion(struct ast_tcptls_session_instance *ser)
Request the HTTP connection be closed after this HTTP request.
char hostname[MAXHOSTNAMELEN]
static force_inline int attribute_pure ast_str_case_hash(const char *str)
Compute a hash value on a case-insensitive string.
int ast_http_response_status_line(const char *buf, const char *version, int code)
Parse the http response status line.
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
int ast_sockaddr_resolve(struct ast_sockaddr **addrs, const char *str, int flags, int family)
Parses a string with an IPv4 or IPv6 address and place results into an array.
char buf[MAXIMUM_FRAME_SIZE]
unsigned int version
Protocol version. Should be set to /ref AST_WEBSOCKET_PROTOCOL_VERSION.