summaryrefslogtreecommitdiff
path: root/res
diff options
context:
space:
mode:
Diffstat (limited to 'res')
-rw-r--r--res/ari/ari_websockets.c10
-rw-r--r--res/ari/config.c4
-rw-r--r--res/ari/internal.h2
-rw-r--r--res/res_ari.c8
-rw-r--r--res/res_http_websocket.c22
-rw-r--r--res/res_pjsip.c8
-rw-r--r--res/res_pjsip/config_transport.c2
-rw-r--r--res/res_pjsip_transport_websocket.c36
8 files changed, 86 insertions, 6 deletions
diff --git a/res/ari/ari_websockets.c b/res/ari/ari_websockets.c
index 90d6f0fdb..ff0a53c4f 100644
--- a/res/ari/ari_websockets.c
+++ b/res/ari/ari_websockets.c
@@ -56,11 +56,16 @@ struct ast_ari_websocket_session *ast_ari_websocket_session_create(
struct ast_websocket *ws_session, int (*validator)(struct ast_json *))
{
RAII_VAR(struct ast_ari_websocket_session *, session, NULL, ao2_cleanup);
+ RAII_VAR(struct ast_ari_conf *, config, ast_ari_config_get(), ao2_cleanup);
if (ws_session == NULL) {
return NULL;
}
+ if (config == NULL || config->general == NULL) {
+ return NULL;
+ }
+
if (validator == NULL) {
validator = null_validator;
}
@@ -72,6 +77,11 @@ struct ast_ari_websocket_session *ast_ari_websocket_session_create(
return NULL;
}
+ if (ast_websocket_set_timeout(ws_session, config->general->write_timeout)) {
+ ast_log(LOG_WARNING, "Failed to set write timeout %d on ARI web socket\n",
+ config->general->write_timeout);
+ }
+
session = ao2_alloc(sizeof(*session), websocket_session_dtor);
if (!session) {
return NULL;
diff --git a/res/ari/config.c b/res/ari/config.c
index 59c4d7d94..667d91ac0 100644
--- a/res/ari/config.c
+++ b/res/ari/config.c
@@ -27,6 +27,7 @@
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/config_options.h"
+#include "asterisk/http_websocket.h"
#include "internal.h"
/*! \brief Locking container for safe configuration access. */
@@ -320,6 +321,9 @@ int ast_ari_config_init(void)
aco_option_register(&cfg_info, "allowed_origins", ACO_EXACT, general_options,
"", OPT_STRINGFIELD_T, 0,
STRFLDSET(struct ast_ari_conf_general, allowed_origins));
+ aco_option_register(&cfg_info, "websocket_write_timeout", ACO_EXACT, general_options,
+ AST_DEFAULT_WEBSOCKET_WRITE_TIMEOUT_STR, OPT_INT_T, PARSE_IN_RANGE,
+ FLDSET(struct ast_ari_conf_general, write_timeout), 1, INT_MAX);
aco_option_register(&cfg_info, "type", ACO_EXACT, user, NULL,
OPT_NOOP_T, 0, 0);
diff --git a/res/ari/internal.h b/res/ari/internal.h
index 8453747f1..93ea0b773 100644
--- a/res/ari/internal.h
+++ b/res/ari/internal.h
@@ -65,6 +65,8 @@ struct ast_ari_conf {
struct ast_ari_conf_general {
/*! Enabled by default, disabled if false. */
int enabled;
+ /*! Write timeout for websocket connections */
+ int write_timeout;
/*! Encoding format used during output (default compact). */
enum ast_json_encoding_format format;
/*! Authentication realm */
diff --git a/res/res_ari.c b/res/res_ari.c
index ce7027e44..acdbbfe9a 100644
--- a/res/res_ari.c
+++ b/res/res_ari.c
@@ -95,6 +95,14 @@
<ref type="link">https://wiki.asterisk.org/wiki/display/AST/Asterisk+Builtin+mini-HTTP+Server</ref>
</see-also>
</configOption>
+ <configOption name="websocket_write_timeout">
+ <synopsis>The timeout (in milliseconds) to set on WebSocket connections.</synopsis>
+ <description>
+ <para>If a websocket connection accepts input slowly, the timeout
+ for writes to it can be increased to keep it from being disconnected.
+ Value is in milliseconds; default is 100 ms.</para>
+ </description>
+ </configOption>
<configOption name="pretty">
<synopsis>Responses from ARI are formatted to be human readable</synopsis>
</configOption>
diff --git a/res/res_http_websocket.c b/res/res_http_websocket.c
index 07fcd9e2e..90744a1b3 100644
--- a/res/res_http_websocket.c
+++ b/res/res_http_websocket.c
@@ -81,6 +81,7 @@ struct ast_websocket {
size_t payload_len; /*!< Length of the payload */
char *payload; /*!< Pointer to the payload */
size_t reconstruct; /*!< Number of bytes before a reconstructed payload will be returned and a new one started */
+ int timeout; /*!< The timeout for operations on the socket */
unsigned int secure:1; /*!< Bit to indicate that the transport is secure */
unsigned int closing:1; /*!< Bit to indicate that the session is in the process of being closed */
unsigned int close_sent:1; /*!< Bit to indicate that the session close opcode has been sent and no further data will be sent */
@@ -260,7 +261,7 @@ int AST_OPTIONAL_API_NAME(ast_websocket_close)(struct ast_websocket *session, ui
session->close_sent = 1;
ao2_lock(session);
- res = (fwrite(frame, 1, 4, session->f) == 4) ? 0 : -1;
+ res = ast_careful_fwrite(session->f, session->fd, frame, 4, session->timeout);
ao2_unlock(session);
return res;
}
@@ -303,13 +304,12 @@ int AST_OPTIONAL_API_NAME(ast_websocket_write)(struct ast_websocket *session, en
ao2_unlock(session);
return -1;
}
-
- if (fwrite(frame, 1, header_size, session->f) != header_size) {
+ if (ast_careful_fwrite(session->f, session->fd, frame, header_size, session->timeout)) {
ao2_unlock(session);
return -1;
}
- if (fwrite(payload, 1, actual_length, session->f) != actual_length) {
+ if (ast_careful_fwrite(session->f, session->fd, payload, actual_length, session->timeout)) {
ao2_unlock(session);
return -1;
}
@@ -371,6 +371,13 @@ int AST_OPTIONAL_API_NAME(ast_websocket_set_nonblock)(struct ast_websocket *sess
return 0;
}
+int AST_OPTIONAL_API_NAME(ast_websocket_set_timeout)(struct ast_websocket *session, int timeout)
+{
+ session->timeout = timeout;
+
+ return 0;
+}
+
/* MAINTENANCE WARNING on ast_websocket_read()!
*
* We have to keep in mind during this function that the fact that session->fd seems ready
@@ -514,8 +521,10 @@ int AST_OPTIONAL_API_NAME(ast_websocket_read)(struct ast_websocket *session, cha
}
/* Per the RFC for PING we need to send back an opcode with the application data as received */
- if (*opcode == AST_WEBSOCKET_OPCODE_PING) {
- ast_websocket_write(session, AST_WEBSOCKET_OPCODE_PONG, *payload, *payload_len);
+ if ((*opcode == AST_WEBSOCKET_OPCODE_PING) && (ast_websocket_write(session, AST_WEBSOCKET_OPCODE_PONG, *payload, *payload_len))) {
+ *payload_len = 0;
+ ast_websocket_close(session, 1009);
+ return 0;
}
session->payload = new_payload;
@@ -696,6 +705,7 @@ int AST_OPTIONAL_API_NAME(ast_websocket_uri_cb)(struct ast_tcptls_session_instan
ao2_ref(protocol_handler, -1);
return 0;
}
+ session->timeout = AST_DEFAULT_WEBSOCKET_WRITE_TIMEOUT;
fprintf(ser->f, "HTTP/1.1 101 Switching Protocols\r\n"
"Upgrade: %s\r\n"
diff --git a/res/res_pjsip.c b/res/res_pjsip.c
index 2602660ee..45b8e7e02 100644
--- a/res/res_pjsip.c
+++ b/res/res_pjsip.c
@@ -869,6 +869,14 @@
or the <replaceable>wss</replaceable> protocols.</para></note>
</description>
</configOption>
+ <configOption name="websocket_write_timeout">
+ <synopsis>The timeout (in milliseconds) to set on WebSocket connections.</synopsis>
+ <description>
+ <para>If a websocket connection accepts input slowly, the timeout
+ for writes to it can be increased to keep it from being disconnected.
+ Value is in milliseconds; default is 100 ms.</para>
+ </description>
+ </configOption>
</configObject>
<configObject name="contact">
<synopsis>A way of creating an aliased name to a SIP URI</synopsis>
diff --git a/res/res_pjsip/config_transport.c b/res/res_pjsip/config_transport.c
index 22581ca52..785fcc5ac 100644
--- a/res/res_pjsip/config_transport.c
+++ b/res/res_pjsip/config_transport.c
@@ -28,6 +28,7 @@
#include "asterisk/sorcery.h"
#include "asterisk/acl.h"
#include "include/res_pjsip_private.h"
+#include "asterisk/http_websocket.h"
static int sip_transport_to_ami(const struct ast_sip_transport *transport,
struct ast_str **buf)
@@ -668,6 +669,7 @@ int ast_sip_initialize_sorcery_transport(void)
ast_sorcery_object_field_register_custom(sorcery, "transport", "local_net", "", transport_localnet_handler, localnet_to_str, localnet_to_vl, 0, 0);
ast_sorcery_object_field_register_custom(sorcery, "transport", "tos", "0", transport_tos_handler, tos_to_str, NULL, 0, 0);
ast_sorcery_object_field_register(sorcery, "transport", "cos", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_transport, cos));
+ ast_sorcery_object_field_register(sorcery, "transport", "websocket_write_timeout", AST_DEFAULT_WEBSOCKET_WRITE_TIMEOUT_STR, OPT_INT_T, PARSE_IN_RANGE, FLDSET(struct ast_sip_transport, write_timeout), 1, INT_MAX);
ast_sip_register_endpoint_formatter(&endpoint_transport_formatter);
diff --git a/res/res_pjsip_transport_websocket.c b/res/res_pjsip_transport_websocket.c
index 22962dab0..bae120a19 100644
--- a/res/res_pjsip_transport_websocket.c
+++ b/res/res_pjsip_transport_websocket.c
@@ -207,6 +207,37 @@ static int transport_read(void *data)
return (read_data->payload_len == recvd) ? 0 : -1;
}
+static int get_write_timeout(void)
+{
+ int write_timeout = -1;
+ struct ao2_container *transports;
+
+ transports = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "transport", AST_RETRIEVE_FLAG_ALL, NULL);
+
+ if (transports) {
+ struct ao2_iterator it_transports = ao2_iterator_init(transports, 0);
+ struct ast_sip_transport *transport;
+
+ for (; (transport = ao2_iterator_next(&it_transports)); ao2_cleanup(transport)) {
+ if (transport->type != AST_TRANSPORT_WS && transport->type != AST_TRANSPORT_WSS) {
+ continue;
+ }
+ ast_debug(5, "Found %s transport with write timeout: %d\n",
+ transport->type == AST_TRANSPORT_WS ? "WS" : "WSS",
+ transport->write_timeout);
+ write_timeout = MAX(write_timeout, transport->write_timeout);
+ }
+ ao2_cleanup(transports);
+ }
+
+ if (write_timeout < 0) {
+ write_timeout = AST_DEFAULT_WEBSOCKET_WRITE_TIMEOUT;
+ }
+
+ ast_debug(1, "Write timeout for WS/WSS transports: %d\n", write_timeout);
+ return write_timeout;
+}
+
/*!
\brief WebSocket connection handler.
*/
@@ -222,6 +253,11 @@ static void websocket_cb(struct ast_websocket *session, struct ast_variable *par
return;
}
+ if (ast_websocket_set_timeout(session, get_write_timeout())) {
+ ast_websocket_unref(session);
+ return;
+ }
+
if (!(serializer = ast_sip_create_serializer())) {
ast_websocket_unref(session);
return;