diff --git a/include/asterisk/http_websocket.h b/include/asterisk/http_websocket.h index 2a55e6006a99e83c97da4d2261e58aeb3a28c19a..ee7f9b8c1ba08391b98b9a3f81b7df3f6d0e652a 100644 --- a/include/asterisk/http_websocket.h +++ b/include/asterisk/http_websocket.h @@ -440,6 +440,55 @@ AST_OPTIONAL_API(struct ast_websocket *, ast_websocket_client_create, struct ast_tls_config *tls_cfg, enum ast_websocket_result *result), { return NULL;}); +/*! + * \brief Options used for a websocket client + */ +struct ast_websocket_client_options { + /*! + * The URI to connect to + * + * Expected uri form: + * \verbatim ws[s]://<address>[:port][/<path>] \endverbatim + * The address (can be a host name) and port are parsed out and used to connect + * to the remote server. If multiple IPs are returned during address + * resolution then the first one is chosen. + */ + const char *uri; + /*! + * A comma separated string of supported protocols + */ + const char *protocols; + /*! + * Optional connection timeout + * + * How long (in milliseconds) to attempt to connect (-1 equals infinite) + */ + int timeout; + /*! + * Secure websocket credentials + */ + struct ast_tls_config *tls_cfg; +}; + +/*! + * \brief Create, and connect, a websocket client using given options. + * + * If the client websocket successfully connects, then the accepted protocol can be + * checked via a call to ast_websocket_client_accept_protocol. + * + * \note While connecting this *will* block until a response is received + * from the remote host, or the connection timeout is reached + * + * \param options Websocket client options + * \param result result code set on client failure + * + * \return a client websocket. + * \retval NULL if object could not be created or connected + */ +AST_OPTIONAL_API(struct ast_websocket *, ast_websocket_client_create_with_options, + (struct ast_websocket_client_options *options, + enum ast_websocket_result *result), { return NULL;}); + /*! * \brief Retrieve the server accepted sub-protocol on the client. * diff --git a/res/res_http_websocket.c b/res/res_http_websocket.c index 879762e556e252443ef2cbf10785d577d2dc8b06..d0a5ea72e2a0260131e11a41bc51807daa272ad5 100644 --- a/res/res_http_websocket.c +++ b/res/res_http_websocket.c @@ -1223,8 +1223,7 @@ static void websocket_client_destroy(void *obj) } static struct ast_websocket * websocket_client_create( - const char *uri, const char *protocols, struct ast_tls_config *tls_cfg, - enum ast_websocket_result *result) + struct ast_websocket_client_options *options, enum ast_websocket_result *result) { struct ast_websocket *ws = ao2_alloc(sizeof(*ws), session_destroy_fn); @@ -1248,18 +1247,18 @@ static struct ast_websocket * websocket_client_create( } if (websocket_client_parse_uri( - uri, &ws->client->host, &ws->client->resource_name)) { + options->uri, &ws->client->host, &ws->client->resource_name)) { ao2_ref(ws, -1); *result = WS_URI_PARSE_ERROR; return NULL; } if (!(ws->client->args = websocket_client_args_create( - ws->client->host, tls_cfg, result))) { + ws->client->host, options->tls_cfg, result))) { ao2_ref(ws, -1); return NULL; } - ws->client->protocols = ast_strdup(protocols); + ws->client->protocols = ast_strdup(options->protocols); ws->client->version = 13; ws->opcode = -1; @@ -1395,13 +1394,13 @@ static enum ast_websocket_result websocket_client_handshake( return websocket_client_handshake_get_response(client); } -static enum ast_websocket_result websocket_client_connect(struct ast_websocket *ws) +static enum ast_websocket_result websocket_client_connect(struct ast_websocket *ws, int timeout) { enum ast_websocket_result res; /* create and connect the client - note client_start releases the session instance on failure */ - if (!(ws->client->ser = ast_tcptls_client_start( - ast_tcptls_client_create(ws->client->args)))) { + if (!(ws->client->ser = ast_tcptls_client_start_timeout( + ast_tcptls_client_create(ws->client->args), timeout))) { return WS_CLIENT_START_ERROR; } @@ -1422,14 +1421,26 @@ 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) { - struct ast_websocket *ws = websocket_client_create( - uri, protocols, tls_cfg, result); + struct ast_websocket_client_options options = { + .uri = uri, + .protocols = protocols, + .timeout = -1, + .tls_cfg = tls_cfg, + }; + + return ast_websocket_client_create_with_options(&options, result); +} + +struct ast_websocket *AST_OPTIONAL_API_NAME(ast_websocket_client_create_with_options) + (struct ast_websocket_client_options *options, enum ast_websocket_result *result) +{ + struct ast_websocket *ws = websocket_client_create(options, result); if (!ws) { return NULL; } - if ((*result = websocket_client_connect(ws)) != WS_OK) { + if ((*result = websocket_client_connect(ws, options->timeout)) != WS_OK) { ao2_ref(ws, -1); return NULL; }