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;
154 if (!server->protocols) {
182 ast_verb(2,
"WebSocket connection %s '%s' closed\n", session->
client ?
"to" :
"from",
201 if (!protocol->
name) {
242 "expected version '%u', got version '%u'\n",
260 ast_verb(2,
"WebSocket registered sub-protocol '%s'\n", protocol->name);
282 ast_verb(2,
"WebSocket unregistered sub-protocol '%s'\n",
name);
293 uint8_t mask_key_idx;
295 uint8_t length = frame[1] & 0x7f;
298 mask_key_idx = length == 126 ? 4 : length == 127 ? 10 : 2;
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;
346 ast_verb(2,
"WebSocket connection %s '%s' forcefully closed due to fatal write error\n",
351 return res ==
sizeof(frame);
376 size_t header_size = 2;
381 ast_debug(3,
"Writing websocket %s frame, length %" PRIu64
"\n",
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);
412 }
else if (length == 127) {
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");
551 errno = ECONNABORTED;
566 if (rlen < 0 &&
errno != EAGAIN) {
605 int mask_present = 0;
606 char *mask =
NULL, *new_payload =
NULL;
623 fin = (session->
buf[0] >> 7) & 1;
624 mask_present = (session->
buf[1] >> 7) & 1;
627 options_len += mask_present ? 4 : 0;
640 mask = &session->
buf[4];
644 mask = &session->
buf[10];
647 mask = &session->
buf[2];
670 (*payload)[pos] ^= mask[pos % 4];
692 if (*payload_len >= 2) {
709 session->
payload = new_payload;
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");
794 char *requested_protocols =
NULL, *protocol =
NULL;
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",
840 if (!protocol_handler) {
842 ast_log(
LOG_WARNING,
"WebSocket connection from '%s' could not be accepted - no protocols requested\n",
847 }
else if (key1 && key2) {
850 ast_log(
LOG_WARNING,
"WebSocket connection from '%s' could not be accepted - unsupported version '00/76' chosen\n",
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",
873 if (version == 7 || version == 8 || version == 13) {
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",
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",
936 "HTTP/1.1 101 Switching Protocols\r\n" 938 "Connection: Upgrade\r\n" 939 "Sec-WebSocket-Accept: %s\r\n\r\n",
946 ast_log(
LOG_WARNING,
"WebSocket connection from '%s' could not be accepted - unsupported version '%d' chosen\n",
955 ast_log(
LOG_WARNING,
"WebSocket connection from '%s' could not be accepted - failed to enable keepalive\n",
965 ast_log(
LOG_WARNING,
"WebSocket connection from '%s' could not be accepted - failed to get local address\n",
999 .description =
"Asterisk HTTP WebSocket",
1011 ast_debug(1,
"Entering WebSocket echo loop\n");
1034 ast_debug(1,
"Ignored WebSocket opcode %u\n", opcode);
1039 ast_debug(1,
"Exiting WebSocket echo loop\n");
1154 args->
name =
"websocket client";
1183 memcpy(key + i, &num,
sizeof(
long));
1225 const char *uri,
const char *protocols,
struct ast_tls_config *tls_cfg,
1272 return ws->client->accept_protocol;
1278 if (response_code <= 0) {
1282 switch (response_code) {
1287 "- from %s\n", client->
host);
1291 "found - from %s\n", client->
host);
1296 response_code, client->
host);
1306 int has_upgrade = 0;
1307 int has_connection = 0;
1309 int has_protocol = 0;
1318 buf,
"HTTP/1.1", 101))) !=
WS_OK) {
1338 name,
"upgrade", value,
"websocket")) < 0) {
1340 }
else if (!has_connection &&
1342 name,
"connection", value,
"upgrade")) < 0) {
1344 }
else if (!has_accept &&
1346 name,
"sec-websocket-accept", value,
1348 client->
key, base64,
sizeof(base64)))) < 0) {
1350 }
else if (!has_protocol &&
1352 name,
"sec-websocket-protocol", value, client->
protocols))) {
1353 if (has_protocol < 0) {
1357 }
else if (!strcasecmp(name,
"sec-websocket-extensions")) {
1359 "supported by client\n");
1363 return has_upgrade && has_connection && has_accept ?
1370 char protocols[100] =
"";
1373 sprintf(protocols,
"Sec-WebSocket-Protocol: %s\r\n",
1378 "GET /%s HTTP/1.1\r\n" 1379 "Sec-WebSocket-Version: %d\r\n" 1380 "Upgrade: websocket\r\n" 1381 "Connection: Upgrade\r\n" 1383 "Sec-WebSocket-Key: %s\r\n" 1425 uri, protocols, tls_cfg,
result);
1447 while (fragmented) {
1449 &opcode, &fragmented)) {
1451 "error reading string data\n");
1471 "non string data received\n");
1480 return payload_len + 1;
1486 uint64_t
len = strlen(
buf);
1488 ast_debug(3,
"Writing websocket string of length %" PRIu64
"\n", len);
1504 if (!websocketuri.
data) {
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.
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)
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.
ast_http_callback callback
String manipulation functions.
A websocket protocol implementation.
void ast_ssl_teardown(struct ast_tls_config *cfg)
free resources used by an SSL server
int AST_OPTIONAL_API_NAME() ast_websocket_is_secure(struct ast_websocket *session)
static enum ast_websocket_result websocket_client_handshake_get_response(struct websocket_client *client)
#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.
const char * ast_uri_path(const struct ast_uri *uri)
Retrieve the uri path.
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.
static const char * websocket_opcode2str(enum ast_websocket_opcode opcode)
struct ast_tcptls_session_instance * ser
static int load_module(void)
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.
struct ast_sockaddr *AST_OPTIONAL_API_NAME() ast_websocket_local_address(struct ast_websocket *session)
#define ao2_callback(c, flags, cb_fn, arg)
Stores parsed uri information.
Structure for variables, used for configurations and for channel variables.
static void put_unaligned_uint16(void *p, unsigned short datum)
static enum ast_websocket_result websocket_client_handshake(struct websocket_client *client)
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.
static void put_unaligned_uint32(void *p, unsigned int datum)
void ast_http_uri_unlink(struct ast_http_uri *urihandler)
Unregister a URI handler.
Assume that the ao2_container is already locked.
int AST_OPTIONAL_API_NAME() ast_websocket_write_string(struct ast_websocket *ws, const char *buf)
static void websocket_client_args_destroy(void *obj)
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_OPTIONAL_API_NAME() ast_websocket_read_string(struct ast_websocket *ws, char **buf)
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)
void AST_OPTIONAL_API_NAME() ast_websocket_reconstruct_disable(struct ast_websocket *session)
#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.
static struct ast_websocket_server * websocket_server_create_impl(void)
const char * ast_uri_query(const struct ast_uri *uri)
Retrieve the uri query parameters.
static char * websocket_client_create_key(void)
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.
static enum ast_websocket_result websocket_client_connect(struct ast_websocket *ws)
Socket address structure.
const char *AST_OPTIONAL_API_NAME() ast_websocket_client_accept_protocol(struct ast_websocket *ws)
#define ast_verb(level,...)
static void websocket_server_dtor(void *obj)
struct ast_websocket_server *AST_OPTIONAL_API_NAME() ast_websocket_server_create(void)
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.
#define ast_strlen_zero(foo)
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)
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.
#define ast_debug(level,...)
Log a DEBUG message.
Handle unaligned data access.
const char *AST_OPTIONAL_API_NAME() ast_websocket_session_id(struct ast_websocket *session)
enum ast_websocket_opcode opcode
static int unload_module(void)
char * name
Name of the protocol.
static int ws_safe_read(struct ast_websocket *session, char *buf, size_t len, enum ast_websocket_opcode *opcode)
int ast_iostream_close(struct ast_iostream *stream)
Close an iostream.
#define MAX_PROTOCOL_BUCKETS
Number of buckets for registered protocols.
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
int ast_http_header_parse(char *buf, char **name, char **value)
Parse a header into the given name/value strings.
static struct ast_mansession session
uint64_t htonll(uint64_t host64)
static struct ast_websocket * websocket_client_create(const char *uri, const char *protocols, struct ast_tls_config *tls_cfg, enum ast_websocket_result *result)
void AST_OPTIONAL_API_NAME() ast_websocket_ref(struct ast_websocket *session)
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
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 remote_address
#define ao2_ref(o, delta)
struct ast_sockaddr *AST_OPTIONAL_API_NAME() ast_websocket_remote_address(struct ast_websocket *session)
long int ast_random(void)
#define ast_strdupa(s)
duplicate a string in memory from the stack
struct websocket_client * client
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()
struct ast_sockaddr local_address
static int websocket_remove_protocol_internal(const char *name, ast_websocket_callback callback)
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...
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
void ast_sha1_hash_uint(uint8_t *digest, const char *input)
Produces SHA1 hash based on input string, stored in uint8_t array.
static unsigned short get_unaligned_uint16(const void *p)
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
static struct ast_http_uri websocketuri
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)
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.
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
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)
int AST_OPTIONAL_API_NAME() ast_websocket_add_protocol2(struct ast_websocket_protocol *protocol)
static int protocol_cmp_fn(void *obj, void *arg, int flags)
Comparison function for protocols.
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
int AST_OPTIONAL_API_NAME() ast_websocket_server_add_protocol2(struct ast_websocket_server *server, struct ast_websocket_protocol *protocol)
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()
char * ast_uri_make_host_with_port(const struct ast_uri *uri)
Retrieve a string of the host and port.
#define ao2_alloc(data_size, destructor_fn)
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)
#define MAXIMUM_FRAME_SIZE
Size of the pre-determined buffer for WebSocket frames.
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)
static char version[AST_MAX_EXTENSION]
static int websocket_add_protocol_internal(const char *name, ast_websocket_callback callback)
uint64_t ntohll(uint64_t net64)
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.
static enum ast_websocket_result websocket_client_handle_response_code(struct websocket_client *client, int response_code)
Structure definition for session.
static void put_unaligned_uint64(void *p, uint64_t datum)
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 ao2_find(container, arg, flags)
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)
#define SCOPED_MODULE_USE(module)
struct ast_iostream * stream
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS|AST_MODFLAG_LOAD_ORDER, "HTTP Phone Provisioning",.support_level=AST_MODULE_SUPPORT_EXTENDED,.load=load_module,.unload=unload_module,.reload=reload,.load_pri=AST_MODPRI_CHANNEL_DEPEND,.requires="http",)
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
int AST_OPTIONAL_API_NAME() ast_websocket_wait_for_input(struct ast_websocket *session, int timeout)
char * strsep(char **str, const char *delims)
static void websocket_bad_request(struct ast_tcptls_session_instance *ser)
struct ast_tcptls_session_instance * ast_tcptls_client_create(struct ast_tcptls_session_args *desc)
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.
struct ast_tcptls_session_instance * ast_tcptls_client_start(struct ast_tcptls_session_instance *tcptls_session)
attempts to connect and start tcptls session, on error the tcptls_session's ref count is decremented...
#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
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.
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)
#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.
struct ast_websocket_protocol *AST_OPTIONAL_API_NAME() ast_websocket_sub_protocol_alloc(const char *name)
void ast_http_request_close_on_completion(struct ast_tcptls_session_instance *ser)
Request the HTTP connection be closed after this HTTP request.
static const char * opcode_map[]
struct ast_uri * ast_uri_parse_websocket(const char *uri)
Parse the given websocket uri into a structure.
static char * websocket_combine_key(const char *key, char *res, int res_size)
static void websocket_client_destroy(void *obj)
static uint64_t get_unaligned_uint64(const void *p)
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.
int AST_OPTIONAL_API_NAME() ast_websocket_server_remove_protocol(struct ast_websocket_server *server, const char *name, ast_websocket_callback callback)
static struct ast_websocket_server * websocket_server_internal_create(void)
#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]
static struct ast_tcptls_session_args * websocket_client_args_create(const char *host, struct ast_tls_config *tls_cfg, enum ast_websocket_result *result)
struct ast_sockaddr remote_address
unsigned int version
Protocol version. Should be set to /ref AST_WEBSOCKET_PROTOCOL_VERSION.