summaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
authorKevin Harwell <kharwell@digium.com>2014-06-05 17:22:35 +0000
committerKevin Harwell <kharwell@digium.com>2014-06-05 17:22:35 +0000
commite763d704700674342c8957f82bddeab3e15dfa08 (patch)
tree14ffdb60c71b6e5976783d97778ba485c4954e6b /include
parentfd45b822470264d50d80d419e65655ea01842da7 (diff)
res_http_websocket: Create a websocket client
Added a websocket server client in Asterisk. Asterisk has a websocket server, but not a client. The ability to have Asterisk be able to connect to a websocket server can potentially be useful for future work (for instance this could allow ARI to connect back to some external system, although more work would be needed in order to incorporate that). Also a couple of things to note - proxy connection support has not been implemented and there is limited http response code handling (basically, it is connect or not). Also added an initial new URI handling mechanism to core. Internet type URI's are parsed into a data structure that contains pointers to the various parts of the URI. (closes issue ASTERISK-23742) Reported by: Kevin Harwell Review: https://reviewboard.asterisk.org/r/3541/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@415223 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'include')
-rw-r--r--include/asterisk/http.h59
-rw-r--r--include/asterisk/http_websocket.h90
-rw-r--r--include/asterisk/uri.h181
3 files changed, 329 insertions, 1 deletions
diff --git a/include/asterisk/http.h b/include/asterisk/http.h
index 0642cfa9b..35c8b22bd 100644
--- a/include/asterisk/http.h
+++ b/include/asterisk/http.h
@@ -225,4 +225,63 @@ struct ast_json;
struct ast_json *ast_http_get_json(
struct ast_tcptls_session_instance *ser, struct ast_variable *headers);
+/*!\brief Parse the http response status line.
+ *
+ * \param buf the http response line information
+ * \param version the expected http version (e.g. HTTP/1.1)
+ * \param code the expected status code
+ * \return -1 if version didn't match or status code conversion fails.
+ * \return status code (>0)
+ * \since 13
+ */
+int ast_http_response_status_line(const char *buf, const char *version, int code);
+
+/*!\brief Parse a header into the given name/value strings.
+ *
+ * \note This modifies the given buffer and the out parameters point (not
+ * allocated) to the start of the header name and header value,
+ * respectively.
+ *
+ * \param buf a string containing the name/value to point to
+ * \param name out parameter pointing to the header name
+ * \param value out parameter pointing to header value
+ * \return -1 if buf is empty
+ * \return 0 if buf could be separated into into name and value
+ * \return 1 if name or value portion don't exist
+ * \since 13
+ */
+int ast_http_header_parse(char *buf, char **name, char **value);
+
+/*!\brief Check if the header and value match (case insensitive) their
+ * associated expected values.
+ *
+ * \param name header name to check
+ * \param expected_name the expected name of the header
+ * \param value header value to check
+ * \param expected_value the expected value of the header
+ * \return 0 if the name and expected name do not match
+ * \return -1 if the value and expected value do not match
+ * \return 1 if the both the name and value match their expected value
+ * \since 13
+ */
+int ast_http_header_match(const char *name, const char *expected_name,
+ const char *value, const char *expected_value);
+
+/*!\brief Check if the header name matches the expected header name. If so,
+ * then check to see if the value can be located in the expected value.
+ *
+ * \note Both header and value checks are case insensitive.
+ *
+ * \param name header name to check
+ * \param expected_name the expected name of the header
+ * \param value header value to check if in expected value
+ * \param expected_value the expected value(s)
+ * \return 0 if the name and expected name do not match
+ * \return -1 if the value and is not in the expected value
+ * \return 1 if the name matches expected name and value is in expected value
+ * \since 13
+ */
+int ast_http_header_match_in(const char *name, const char *expected_name,
+ const char *value, const char *expected_value);
+
#endif /* _ASTERISK_SRV_H */
diff --git a/include/asterisk/http_websocket.h b/include/asterisk/http_websocket.h
index 10cb9a023..d95e6068e 100644
--- a/include/asterisk/http_websocket.h
+++ b/include/asterisk/http_websocket.h
@@ -26,7 +26,15 @@
/*!
* \file http_websocket.h
- * \brief Support for WebSocket connections within the Asterisk HTTP server.
+ * \brief Support for WebSocket connections within the Asterisk HTTP server and client
+ * WebSocket connections to a server.
+ *
+ * Supported WebSocket versions in server implementation:
+ * Version 7 defined in specification http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-07
+ * Version 8 defined in specification http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-10
+ * Version 13 defined in specification http://tools.ietf.org/html/rfc6455
+ * Supported WebSocket versions in client implementation:
+ * Version 13 defined in specification http://tools.ietf.org/html/rfc6455
*
* \author Joshua Colp <jcolp@digium.com>
*
@@ -146,6 +154,20 @@ AST_OPTIONAL_API(int, ast_websocket_server_remove_protocol, (struct ast_websocke
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;});
/*!
+ * \brief Read a WebSocket frame containing string data.
+ *
+ * \param ws pointer to the websocket
+ * \param buf string buffer to populate with data read from socket
+ * \retval -1 on error
+ * \retval number of bytes read on success
+ *
+ * \note Once an AST_WEBSOCKET_OPCODE_CLOSE opcode is received the socket will be closed
+ */
+AST_OPTIONAL_API(int, ast_websocket_read_string,
+ (struct ast_websocket *ws, struct ast_str **buf),
+ { errno = ENOSYS; return -1;});
+
+/*!
* \brief Construct and transmit a WebSocket frame
*
* \param session Pointer to the WebSocket session
@@ -159,6 +181,17 @@ AST_OPTIONAL_API(int, ast_websocket_read, (struct ast_websocket *session, char *
AST_OPTIONAL_API(int, ast_websocket_write, (struct ast_websocket *session, enum ast_websocket_opcode opcode, char *payload, uint64_t actual_length), { errno = ENOSYS; return -1;});
/*!
+ * \brief Construct and transmit a WebSocket frame containing string data.
+ *
+ * \param ws pointer to the websocket
+ * \param buf string data to write to socket
+ * \retval 0 if successfully written
+ * \retval -1 if error occurred
+ */
+AST_OPTIONAL_API(int, ast_websocket_write_string,
+ (struct ast_websocket *ws, const struct ast_str *buf),
+ { errno = ENOSYS; return -1;});
+/*!
* \brief Close a WebSocket session by sending a message with the CLOSE opcode and an optional code
*
* \param session Pointer to the WebSocket session
@@ -234,4 +267,59 @@ AST_OPTIONAL_API(int, ast_websocket_is_secure, (struct ast_websocket *session),
*/
AST_OPTIONAL_API(int, ast_websocket_set_nonblock, (struct ast_websocket *session), { errno = ENOSYS; return -1;});
+/*!
+ * \brief Result code for a websocket client.
+ */
+enum ast_websocket_result {
+ WS_OK,
+ WS_ALLOCATE_ERROR,
+ WS_KEY_ERROR,
+ WS_URI_PARSE_ERROR,
+ WS_URI_RESOLVE_ERROR,
+ WS_BAD_STATUS,
+ WS_INVALID_RESPONSE,
+ WS_BAD_REQUEST,
+ WS_URL_NOT_FOUND,
+ WS_HEADER_MISMATCH,
+ WS_HEADER_MISSING,
+ WS_NOT_SUPPORTED,
+ WS_WRITE_ERROR,
+ WS_CLIENT_START_ERROR,
+};
+
+/*!
+ * \brief Create, and connect, a websocket client.
+ *
+ * \detail 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.
+ * \note Expected uri form: ws[s]://<address>[:port][/<path>] 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.
+ *
+ * \param uri uri to connect to
+ * \param protocols a comma separated string of supported protocols
+ * \param tls_cfg secure websocket credentials
+ * \param result result code set on client failure
+ * \retval a client websocket.
+ * \retval NULL if object could not be created or connected
+ * \since 13
+ */
+AST_OPTIONAL_API(struct ast_websocket *, ast_websocket_client_create,
+ (const char *uri, const char *protocols,
+ struct ast_tls_config *tls_cfg,
+ enum ast_websocket_result *result), { return NULL;});
+
+/*!
+ * \brief Retrieve the server accepted sub-protocol on the client.
+ *
+ * \param ws the websocket client
+ * \retval the accepted client sub-protocol.
+ * \since 13
+ */
+AST_OPTIONAL_API(const char *, ast_websocket_client_accept_protocol,
+ (struct ast_websocket *ws), { return NULL;});
#endif
diff --git a/include/asterisk/uri.h b/include/asterisk/uri.h
new file mode 100644
index 000000000..225d8c8d7
--- /dev/null
+++ b/include/asterisk/uri.h
@@ -0,0 +1,181 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2014, Digium, Inc.
+ *
+ * Kevin Harwell <kharwell@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+#ifndef _ASTERISK_URI_H
+#define _ASTERISK_URI_H
+
+/*! \brief Opaque structure that stores uri information. */
+struct ast_uri;
+
+/*!
+ * \brief Create a uri with the given parameters
+ *
+ * \param scheme the uri scheme (ex: http)
+ * \param user_info user credentials (ex: <name>@<pass>)
+ * \param host host name or ip address
+ * \param port the port
+ * \param path the path
+ * \param query query parameters
+ * \return a structure containing parsed uri data.
+ * \return \c NULL on error
+ * \since 13
+ */
+struct ast_uri *ast_uri_create(const char *scheme, const char *user_info,
+ const char *host, const char *port,
+ const char *path, const char *query);
+
+/*!
+ * \brief Copy the given uri replacing any value in the new uri with
+ * any given.
+ *
+ * \param uri the uri object to copy
+ * \param scheme the uri scheme (ex: http)
+ * \param user_info user credentials (ex: <name>@<pass>)
+ * \param host host name or ip address
+ * \param port the port
+ * \param path the path
+ * \param query query parameters
+ * \return a copy of the given uri with specified values replaced.
+ * \return \c NULL on error
+ * \since 13
+ */
+struct ast_uri *ast_uri_copy_replace(const struct ast_uri *uri, const char *scheme,
+ const char *user_info, const char *host,
+ const char *port, const char *path,
+ const char *query);
+/*!
+ * \brief Retrieve the uri scheme.
+ *
+ * \return the uri scheme.
+ * \since 13
+ */
+const char *ast_uri_scheme(const struct ast_uri *uri);
+
+/*!
+ * \brief Retrieve the uri user information.
+ *
+ * \return the uri user information.
+ * \since 13
+ */
+const char *ast_uri_user_info(const struct ast_uri *uri);
+
+/*!
+ * \brief Retrieve the uri host.
+ *
+ * \return the uri host.
+ * \since 13
+ */
+const char *ast_uri_host(const struct ast_uri *uri);
+
+/*!
+ * \brief Retrieve the uri port
+ *
+ * \return the uri port.
+ * \since 13
+ */
+const char *ast_uri_port(const struct ast_uri *uri);
+
+/*!
+ * \brief Retrieve the uri path.
+ *
+ * \return the uri path.
+ * \since 13
+ */
+const char *ast_uri_path(const struct ast_uri *uri);
+
+/*!
+ * \brief Retrieve the uri query parameters.
+ *
+ * \return the uri query parameters.
+ * \since 13
+ */
+const char *ast_uri_query(const struct ast_uri *uri);
+
+/*!
+ * \brief Retrieve if the uri is of a secure type
+ *
+ * \note Secure types are recognized by an 's' at the end
+ * of the scheme.
+ *
+ * \return True if secure, False otherwise.
+ * \since 13
+ */
+const int ast_uri_is_secure(const struct ast_uri *uri);
+
+/*!
+ * \brief Parse the given uri into a structure.
+ *
+ * \note Expects the following form:
+ * <scheme>://[user:pass@]<host>[:port][/<path>]
+ *
+ * \param uri a string uri to parse
+ * \return a structure containing parsed uri data.
+ * \return \c NULL on error
+ * \since 13
+ */
+struct ast_uri *ast_uri_parse(const char *uri);
+
+/*!
+ * \brief Parse the given http uri into a structure.
+ *
+ * \note Expects the following form:
+ * [http[s]://][user:pass@]<host>[:port][/<path>]
+ *
+ * \note If no scheme is given it defaults to 'http' and if
+ * no port is specified it will default to 443 if marked
+ * secure, otherwise to 80.
+ *
+ * \param uri an http string uri to parse
+ * \return a structure containing parsed http uri data.
+ * \return \c NULL on error
+ * \since 13
+ */
+struct ast_uri *ast_uri_parse_http(const char *uri);
+
+/*!
+ * \brief Parse the given websocket uri into a structure.
+ *
+ * \note Expects the following form:
+ * [ws[s]://][user:pass@]<host>[:port][/<path>]
+ *
+ * \note If no scheme is given it defaults to 'ws' and if
+ * no port is specified it will default to 443 if marked
+ * secure, otherwise to 80.
+ *
+ * \param uri a websocket string uri to parse
+ * \return a structure containing parsed http uri data.
+ * \return \c NULL on error
+ * \since 13
+ */
+struct ast_uri *ast_uri_parse_websocket(const char *uri);
+
+/*!
+ * \brief Retrieve a string of the host and port.
+ *
+ * \detail Combine the host and port (<host>:<port>) if the port
+ * is available, otherwise just return the host.
+ *
+ * \note Caller is responsible for release the returned string.
+ *
+ * \param uri the uri object
+ * \return a string value of the host and optional port.
+ * \since 13
+ */
+char *ast_uri_make_host_with_port(const struct ast_uri *uri);
+
+#endif /* _ASTERISK_URI_H */