summaryrefslogtreecommitdiffstats
path: root/mqtt_websockets/src/include
diff options
context:
space:
mode:
Diffstat (limited to 'mqtt_websockets/src/include')
-rw-r--r--mqtt_websockets/src/include/common_internal.h37
-rw-r--r--mqtt_websockets/src/include/common_public.h33
-rw-r--r--mqtt_websockets/src/include/endian_compat.h41
-rw-r--r--mqtt_websockets/src/include/mqtt_constants.h101
-rw-r--r--mqtt_websockets/src/include/mqtt_ng.h97
-rw-r--r--mqtt_websockets/src/include/mqtt_wss_client.h172
-rw-r--r--mqtt_websockets/src/include/mqtt_wss_log.h37
-rw-r--r--mqtt_websockets/src/include/ws_client.h130
8 files changed, 648 insertions, 0 deletions
diff --git a/mqtt_websockets/src/include/common_internal.h b/mqtt_websockets/src/include/common_internal.h
new file mode 100644
index 00000000..2e656355
--- /dev/null
+++ b/mqtt_websockets/src/include/common_internal.h
@@ -0,0 +1,37 @@
+// SPDX-License-Identifier: GPL-3.0-only
+//
+// This program is free software: you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free Software Foundation, version 3.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+// See the GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along with this program.
+// If not, see <https://www.gnu.org/licenses/>.
+
+#ifndef COMMON_INTERNAL_H
+#define COMMON_INTERNAL_H
+
+#include "endian_compat.h"
+
+#ifdef MQTT_WSS_CUSTOM_ALLOC
+#include "mqtt_wss_pal.h"
+#else
+#define mw_malloc(...) malloc(__VA_ARGS__)
+#define mw_calloc(...) calloc(__VA_ARGS__)
+#define mw_free(...) free(__VA_ARGS__)
+#define mw_strdup(...) strdup(__VA_ARGS__)
+#define mw_realloc(...) realloc(__VA_ARGS__)
+#endif
+
+#ifndef MQTT_WSS_FRAG_MEMALIGN
+#define MQTT_WSS_FRAG_MEMALIGN (8)
+#endif
+
+#define OPENSSL_VERSION_095 0x00905100L
+#define OPENSSL_VERSION_097 0x00907000L
+#define OPENSSL_VERSION_110 0x10100000L
+#define OPENSSL_VERSION_111 0x10101000L
+
+#endif /* COMMON_INTERNAL_H */
diff --git a/mqtt_websockets/src/include/common_public.h b/mqtt_websockets/src/include/common_public.h
new file mode 100644
index 00000000..a855737f
--- /dev/null
+++ b/mqtt_websockets/src/include/common_public.h
@@ -0,0 +1,33 @@
+#ifndef MQTT_WEBSOCKETS_COMMON_PUBLIC_H
+#define MQTT_WEBSOCKETS_COMMON_PUBLIC_H
+
+#include <stddef.h>
+
+/* free_fnc_t in general (in whatever function or struct it is used)
+ * decides how the related data will be handled.
+ * - If NULL the data are copied internally (causing malloc and later free)
+ * - If pointer provided the free function pointed will be called when data are no longer needed
+ * to free associated memory. This is effectively transfering ownership of that pointer to the library.
+ * This also allows caller to provide custom free function other than system one.
+ * - If == CALLER_RESPONSIBILITY the library will not copy the data pointed to and will not call free
+ * at the end. This is usefull to avoid copying memory (and associated malloc/free) when data are for
+ * example static. In this case caller has to guarantee the memory pointed to will be valid for entire duration
+ * it is needed. For example by freeing the data after PUBACK is received or by data being static.
+ */
+typedef void (*free_fnc_t)(void *ptr);
+void _caller_responsibility(void *ptr);
+#define CALLER_RESPONSIBILITY ((free_fnc_t)&_caller_responsibility)
+
+struct mqtt_ng_stats {
+ size_t tx_bytes_queued;
+ int tx_messages_queued;
+ int tx_messages_sent;
+ int rx_messages_rcvd;
+ size_t tx_buffer_used;
+ size_t tx_buffer_free;
+ size_t tx_buffer_size;
+ // part of transaction buffer that containes mesages we can free alredy during the garbage colleciton step
+ size_t tx_buffer_reclaimable;
+};
+
+#endif /* MQTT_WEBSOCKETS_COMMON_PUBLIC_H */
diff --git a/mqtt_websockets/src/include/endian_compat.h b/mqtt_websockets/src/include/endian_compat.h
new file mode 100644
index 00000000..076ccbe8
--- /dev/null
+++ b/mqtt_websockets/src/include/endian_compat.h
@@ -0,0 +1,41 @@
+// SPDX-License-Identifier: GPL-3.0-only
+//
+// This program is free software: you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free Software Foundation, version 3.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+// See the GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along with this program.
+// If not, see <https://www.gnu.org/licenses/>.
+
+#ifndef MQTT_WSS_ENDIAN_COMPAT_H
+#define MQTT_WSS_ENDIAN_COMPAT_H
+
+#ifdef __APPLE__
+ #include <libkern/OSByteOrder.h>
+
+ #define htobe16(x) OSSwapHostToBigInt16(x)
+ #define htole16(x) OSSwapHostToLittleInt16(x)
+ #define be16toh(x) OSSwapBigToHostInt16(x)
+ #define le16toh(x) OSSwapLittleToHostInt16(x)
+
+ #define htobe32(x) OSSwapHostToBigInt32(x)
+ #define htole32(x) OSSwapHostToLittleInt32(x)
+ #define be32toh(x) OSSwapBigToHostInt32(x)
+ #define le32toh(x) OSSwapLittleToHostInt32(x)
+
+ #define htobe64(x) OSSwapHostToBigInt64(x)
+ #define htole64(x) OSSwapHostToLittleInt64(x)
+ #define be64toh(x) OSSwapBigToHostInt64(x)
+ #define le64toh(x) OSSwapLittleToHostInt64(x)
+#else
+#ifdef __FreeBSD__
+ #include <sys/endian.h>
+#else
+ #include <endian.h>
+#endif
+#endif
+
+#endif /* MQTT_WSS_ENDIAN_COMPAT_H */
diff --git a/mqtt_websockets/src/include/mqtt_constants.h b/mqtt_websockets/src/include/mqtt_constants.h
new file mode 100644
index 00000000..1db49897
--- /dev/null
+++ b/mqtt_websockets/src/include/mqtt_constants.h
@@ -0,0 +1,101 @@
+#ifndef MQTT_CONSTANTS_H
+#define MQTT_CONSTANTS_H
+
+#define MQTT_MAX_QOS 0x02
+
+#define MQTT_VERSION_5_0 0x5
+
+/* [MQTT-1.5.5] most significant bit
+ of MQTT Variable Byte Integer signifies
+ there are more bytes following */
+#define MQTT_VBI_CONTINUATION_FLAG 0x80
+#define MQTT_VBI_DATA_MASK 0x7F
+#define MQTT_VBI_MAXBYTES 4
+
+/* MQTT control packet types as defined in
+ 2.1.2 MQTT Control Packet type */
+#define MQTT_CPT_CONNECT 0x1
+#define MQTT_CPT_CONNACK 0x2
+#define MQTT_CPT_PUBLISH 0x3
+#define MQTT_CPT_PUBACK 0x4
+#define MQTT_CPT_PUBREC 0x5
+#define MQTT_CPT_PUBREL 0x6
+#define MQTT_CPT_PUBCOMP 0x7
+#define MQTT_CPT_SUBSCRIBE 0x8
+#define MQTT_CPT_SUBACK 0x9
+#define MQTT_CPT_UNSUBSCRIBE 0xA
+#define MQTT_CPT_UNSUBACK 0xB
+#define MQTT_CPT_PINGREQ 0xC
+#define MQTT_CPT_PINGRESP 0xD
+#define MQTT_CPT_DISCONNECT 0xE
+#define MQTT_CPT_AUTH 0xF
+
+// MQTT CONNECT FLAGS (spec:3.1.2.3)
+#define MQTT_CONNECT_FLAG_USERNAME 0x80
+#define MQTT_CONNECT_FLAG_PASSWORD 0x40
+#define MQTT_CONNECT_FLAG_LWT_RETAIN 0x20
+#define MQTT_CONNECT_FLAG_LWT 0x04
+#define MQTT_CONNECT_FLAG_CLEAN_START 0x02
+
+#define MQTT_CONNECT_FLAG_QOS_MASK 0x18
+#define MQTT_CONNECT_FLAG_QOS_BITSHIFT 3
+
+#define MQTT_MAX_CLIENT_ID 23 /* [MQTT-3.1.3-5] */
+
+// MQTT Property identifiers [MQTT-2.2.2.2]
+#define MQTT_PROP_PAYLOAD_FMT_INDICATOR 0x01
+#define MQTT_PROP_PAYLOAD_FMT_INDICATOR_NAME "Payload Format Indicator"
+#define MQTT_PROP_MSG_EXPIRY_INTERVAL 0x02
+#define MQTT_PROP_MSG_EXPIRY_INTERVAL_NAME "Message Expiry Interval"
+#define MQTT_PROP_CONTENT_TYPE 0x03
+#define MQTT_PROP_CONTENT_TYPE_NAME "Content Type"
+#define MQTT_PROP_RESPONSE_TOPIC 0x08
+#define MQTT_PROP_RESPONSE_TOPIC_NAME "Response Topic"
+#define MQTT_PROP_CORRELATION_DATA 0x09
+#define MQTT_PROP_CORRELATION_DATA_NAME "Correlation Data"
+#define MQTT_PROP_SUB_IDENTIFIER 0x0B
+#define MQTT_PROP_SUB_IDENTIFIER_NAME "Subscription Identifier"
+#define MQTT_PROP_SESSION_EXPIRY_INTERVAL 0x11
+#define MQTT_PROP_SESSION_EXPIRY_INTERVAL_NAME "Session Expiry Interval"
+#define MQTT_PROP_ASSIGNED_CLIENT_ID 0x12
+#define MQTT_PROP_ASSIGNED_CLIENT_ID_NAME "Assigned Client Identifier"
+#define MQTT_PROP_SERVER_KEEP_ALIVE 0x13
+#define MQTT_PROP_SERVER_KEEP_ALIVE_NAME "Server Keep Alive"
+#define MQTT_PROP_AUTH_METHOD 0x15
+#define MQTT_PROP_AUTH_METHOD_NAME "Authentication Method"
+#define MQTT_PROP_AUTH_DATA 0x16
+#define MQTT_PROP_AUTH_DATA_NAME "Authentication Data"
+#define MQTT_PROP_REQ_PROBLEM_INFO 0x17
+#define MQTT_PROP_REQ_PROBLEM_INFO_NAME "Request Problem Information"
+#define MQTT_PROP_WILL_DELAY_INTERVAL 0x18
+#define MQTT_PROP_WIIL_DELAY_INTERVAL_NAME "Will Delay Interval"
+#define MQTT_PROP_REQ_RESP_INFORMATION 0x19
+#define MQTT_PROP_REQ_RESP_INFORMATION_NAME "Request Response Information"
+#define MQTT_PROP_RESP_INFORMATION 0x1A
+#define MQTT_PROP_RESP_INFORMATION_NAME "Response Information"
+#define MQTT_PROP_SERVER_REF 0x1C
+#define MQTT_PROP_SERVER_REF_NAME "Server Reference"
+#define MQTT_PROP_REASON_STR 0x1F
+#define MQTT_PROP_REASON_STR_NAME "Reason String"
+#define MQTT_PROP_RECEIVE_MAX 0x21
+#define MQTT_PROP_RECEIVE_MAX_NAME "Receive Maximum"
+#define MQTT_PROP_TOPIC_ALIAS_MAX 0x22
+#define MQTT_PROP_TOPIC_ALIAS_MAX_NAME "Topic Alias Maximum"
+#define MQTT_PROP_TOPIC_ALIAS 0x23
+#define MQTT_PROP_TOPIC_ALIAS_NAME "Topic Alias"
+#define MQTT_PROP_MAX_QOS 0x24
+#define MQTT_PROP_MAX_QOS_NAME "Maximum QoS"
+#define MQTT_PROP_RETAIN_AVAIL 0x25
+#define MQTT_PROP_RETAIN_AVAIL_NAME "Retain Available"
+#define MQTT_PROP_USR 0x26
+#define MQTT_PROP_USR_NAME "User Property"
+#define MQTT_PROP_MAX_PKT_SIZE 0x27
+#define MQTT_PROP_MAX_PKT_SIZE_NAME "Maximum Packet Size"
+#define MQTT_PROP_WILDCARD_SUB_AVAIL 0x28
+#define MQTT_PROP_WILDCARD_SUB_AVAIL_NAME "Wildcard Subscription Available"
+#define MQTT_PROP_SUB_ID_AVAIL 0x29
+#define MQTT_PROP_SUB_ID_AVAIL_NAME "Subscription Identifier Available"
+#define MQTT_PROP_SHARED_SUB_AVAIL 0x2A
+#define MQTT_PROP_SHARED_SUB_AVAIL_NAME "Shared Subscription Available"
+
+#endif /* MQTT_CONSTANTS_H */
diff --git a/mqtt_websockets/src/include/mqtt_ng.h b/mqtt_websockets/src/include/mqtt_ng.h
new file mode 100644
index 00000000..09668d09
--- /dev/null
+++ b/mqtt_websockets/src/include/mqtt_ng.h
@@ -0,0 +1,97 @@
+#include <stdint.h>
+#include <sys/types.h>
+#include <time.h>
+
+#include "ringbuffer.h"
+#include "common_public.h"
+
+#define MQTT_NG_MSGGEN_OK 0
+// MQTT_NG_MSGGEN_USER_ERROR means parameters given to this function
+// do not make sense or are out of MQTT specs
+#define MQTT_NG_MSGGEN_USER_ERROR 1
+#define MQTT_NG_MSGGEN_BUFFER_OOM 2
+#define MQTT_NG_MSGGEN_MSG_TOO_BIG 3
+
+struct mqtt_ng_client;
+
+/* Converts integer to MQTT Variable Byte Integer as per 1.5.5 of MQTT 5 specs
+ * @param input value to be converted
+ * @param output pointer to memory where output will be written to. Must allow up to 4 bytes to be written.
+ * @return number of bytes written to output or <= 0 if error in which case contents of output are undefined
+ */
+int uint32_to_mqtt_vbi(uint32_t input, char *output);
+
+struct mqtt_lwt_properties {
+ char *will_topic;
+ free_fnc_t will_topic_free;
+
+ void *will_message;
+ free_fnc_t will_message_free;
+ size_t will_message_size;
+
+ int will_qos;
+ int will_retain;
+};
+
+struct mqtt_auth_properties {
+ char *client_id;
+ free_fnc_t client_id_free;
+ char *username;
+ free_fnc_t username_free;
+ char *password;
+ free_fnc_t password_free;
+};
+
+int mqtt_ng_connect(struct mqtt_ng_client *client,
+ struct mqtt_auth_properties *auth,
+ struct mqtt_lwt_properties *lwt,
+ uint8_t clean_start,
+ uint16_t keep_alive);
+
+int mqtt_ng_publish(struct mqtt_ng_client *client,
+ char *topic,
+ free_fnc_t topic_free,
+ void *msg,
+ free_fnc_t msg_free,
+ size_t msg_len,
+ uint8_t publish_flags,
+ uint16_t *packet_id);
+
+struct mqtt_sub {
+ char *topic;
+ free_fnc_t topic_free;
+ uint8_t options;
+};
+
+int mqtt_ng_subscribe(struct mqtt_ng_client *client, struct mqtt_sub *subscriptions, size_t subscription_count);
+
+int mqtt_ng_ping(struct mqtt_ng_client *client);
+
+typedef ssize_t (*mqtt_ng_send_fnc_t)(void *user_ctx, const void* buf, size_t len);
+
+struct mqtt_ng_init {
+ mqtt_wss_log_ctx_t log;
+ rbuf_t data_in;
+ mqtt_ng_send_fnc_t data_out_fnc;
+ void *user_ctx;
+
+ void (*puback_callback)(uint16_t packet_id);
+ void (*connack_callback)(void* user_ctx, int connack_reply);
+ void (*msg_callback)(const char *topic, const void *msg, size_t msglen, int qos);
+};
+
+struct mqtt_ng_client *mqtt_ng_init(struct mqtt_ng_init *settings);
+
+void mqtt_ng_destroy(struct mqtt_ng_client *client);
+
+int mqtt_ng_disconnect(struct mqtt_ng_client *client, uint8_t reason_code);
+
+int mqtt_ng_sync(struct mqtt_ng_client *client);
+
+time_t mqtt_ng_last_send_time(struct mqtt_ng_client *client);
+
+void mqtt_ng_set_max_mem(struct mqtt_ng_client *client, size_t bytes);
+
+void mqtt_ng_get_stats(struct mqtt_ng_client *client, struct mqtt_ng_stats *stats);
+
+int mqtt_ng_set_topic_alias(struct mqtt_ng_client *client, const char *topic);
diff --git a/mqtt_websockets/src/include/mqtt_wss_client.h b/mqtt_websockets/src/include/mqtt_wss_client.h
new file mode 100644
index 00000000..e325961b
--- /dev/null
+++ b/mqtt_websockets/src/include/mqtt_wss_client.h
@@ -0,0 +1,172 @@
+// Copyright (C) 2020 Timotej Šiškovič
+// SPDX-License-Identifier: GPL-3.0-only
+//
+// This program is free software: you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free Software Foundation, version 3.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+// See the GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along with this program.
+// If not, see <https://www.gnu.org/licenses/>.
+
+#ifndef MQTT_WSS_CLIENT_H
+#define MQTT_WSS_CLIENT_H
+
+#include <stdint.h>
+#include <stddef.h> //size_t
+
+#include "mqtt_wss_log.h"
+#include "common_public.h"
+
+// All OK call me at your earliest convinience
+#define MQTT_WSS_OK 0
+/* All OK, poll timeout you requested when calling mqtt_wss_service expired - you might want to know if timeout
+ * happened or we got some data or handle same as MQTT_WSS_OK
+ */
+#define MQTT_WSS_OK_TO 1
+// Connection was closed by remote
+#define MQTT_WSS_ERR_CONN_DROP -1
+// Error in MQTT protocol (e.g. malformed packet)
+#define MQTT_WSS_ERR_PROTO_MQTT -2
+// Error in WebSocket protocol (e.g. malformed packet)
+#define MQTT_WSS_ERR_PROTO_WS -3
+
+#define MQTT_WSS_ERR_TX_BUF_TOO_SMALL -4
+#define MQTT_WSS_ERR_RX_BUF_TOO_SMALL -5
+
+#define MQTT_WSS_ERR_TOO_BIG_FOR_SERVER -6
+// if client was initialized with MQTT 3 but MQTT 5 feature
+// was requested by user of library
+#define MQTT_WSS_ERR_CANT_DO -8
+
+typedef struct mqtt_wss_client_struct *mqtt_wss_client;
+
+typedef void (*msg_callback_fnc_t)(const char *topic, const void *msg, size_t msglen, int qos);
+/* Creates new instance of MQTT over WSS. Doesn't start connection.
+ * @param log_prefix this is prefix to be used when logging to discern between multiple
+ * mqtt_wss instances. Can be NULL.
+ * @param log_callback is function pointer to fnc to be called when mqtt_wss wants
+ * to log. This allows plugging this library into your own logging system/solution.
+ * If NULL STDOUT/STDERR will be used.
+ * @param msg_callback is function pointer to function which will be called
+ * when application level message arrives from broker (for subscribed topics).
+ * Can be NULL if you are not interested about incoming messages.
+ * @param puback_callback is function pointer to function to be called when QOS1 Publish
+ * is acknowledged by server
+ */
+mqtt_wss_client mqtt_wss_new(const char *log_prefix,
+ mqtt_wss_log_callback_t log_callback,
+ msg_callback_fnc_t msg_callback,
+ void (*puback_callback)(uint16_t packet_id));
+
+void mqtt_wss_set_max_buf_size(mqtt_wss_client client, size_t size);
+
+void mqtt_wss_destroy(mqtt_wss_client client);
+
+struct mqtt_connect_params;
+struct mqtt_wss_proxy;
+
+#define MQTT_WSS_SSL_CERT_CHECK_FULL 0x00
+#define MQTT_WSS_SSL_ALLOW_SELF_SIGNED 0x01
+#define MQTT_WSS_SSL_DONT_CHECK_CERTS 0x08
+
+/* Will block until the MQTT over WSS connection is established or return error
+ * @param client mqtt_wss_client which should connect
+ * @param host to connect to (where MQTT over WSS server is listening)
+ * @param port to connect to (where MQTT over WSS server is listening)
+ * @param mqtt_params pointer to mqtt_connect_params structure which contains MQTT credentials and settings
+ * @param ssl_flags parameters for OpenSSL, 0=MQTT_WSS_SSL_CERT_CHECK_FULL
+ */
+int mqtt_wss_connect(mqtt_wss_client client, char *host, int port, struct mqtt_connect_params *mqtt_params, int ssl_flags, struct mqtt_wss_proxy *proxy);
+int mqtt_wss_service(mqtt_wss_client client, int timeout_ms);
+void mqtt_wss_disconnect(mqtt_wss_client client, int timeout_ms);
+
+// we redefine this instead of using MQTT-C flags as in future
+// we want to support different MQTT implementations if needed
+enum mqtt_wss_publish_flags {
+ MQTT_WSS_PUB_QOS0 = 0x0,
+ MQTT_WSS_PUB_QOS1 = 0x1,
+ MQTT_WSS_PUB_QOS2 = 0x2,
+ MQTT_WSS_PUB_QOSMASK = 0x3,
+ MQTT_WSS_PUB_RETAIN = 0x4
+};
+
+struct mqtt_connect_params {
+ const char *clientid;
+ const char *username;
+ const char *password;
+ const char *will_topic;
+ const void *will_msg;
+ enum mqtt_wss_publish_flags will_flags;
+ size_t will_msg_len;
+ int keep_alive;
+ int drop_on_publish_fail;
+};
+
+enum mqtt_wss_proxy_type {
+ MQTT_WSS_DIRECT = 0,
+ MQTT_WSS_PROXY_HTTP
+};
+
+struct mqtt_wss_proxy {
+ enum mqtt_wss_proxy_type type;
+ const char *host;
+ int port;
+ const char *username;
+ const char *password;
+};
+
+/* TODO!!! update the description
+ * Publishes MQTT message and gets message id
+ * @param client mqtt_wss_client which should transfer the message
+ * @param topic MQTT topic to publish message to (0 terminated C string)
+ * @param msg Message to be published (no need for 0 termination)
+ * @param msg_len Length of the message to be published
+ * @param publish_flags see enum mqtt_wss_publish_flags e.g. (MQTT_WSS_PUB_QOS1 | MQTT_WSS_PUB_RETAIN)
+ * @param packet_id is 16 bit unsigned int representing ID that can be used to pair with PUBACK callback
+ * for usages where application layer wants to know which messages are delivered when
+ * @return Returns 0 on success
+ */
+int mqtt_wss_publish5(mqtt_wss_client client,
+ char *topic,
+ free_fnc_t topic_free,
+ void *msg,
+ free_fnc_t msg_free,
+ size_t msg_len,
+ uint8_t publish_flags,
+ uint16_t *packet_id);
+
+int mqtt_wss_set_topic_alias(mqtt_wss_client client, const char *topic);
+
+/* Subscribes to MQTT topic
+ * @param client mqtt_wss_client which should do the subscription
+ * @param topic MQTT topic to subscribe to
+ * @param max_qos_level maximum QOS level that broker can send to us on this subscription
+ * @return Returns 0 on success
+ */
+int mqtt_wss_subscribe(mqtt_wss_client client, char *topic, int max_qos_level);
+
+
+struct mqtt_wss_stats {
+ uint64_t bytes_tx;
+ uint64_t bytes_rx;
+#ifdef MQTT_WSS_CPUSTATS
+ uint64_t time_keepalive;
+ uint64_t time_read_socket;
+ uint64_t time_write_socket;
+ uint64_t time_process_websocket;
+ uint64_t time_process_mqtt;
+#endif
+ struct mqtt_ng_stats mqtt;
+};
+
+struct mqtt_wss_stats mqtt_wss_get_stats(mqtt_wss_client client);
+
+#ifdef MQTT_WSS_DEBUG
+#include <openssl/ssl.h>
+void mqtt_wss_set_SSL_CTX_keylog_cb(mqtt_wss_client client, void (*ssl_ctx_keylog_cb)(const SSL *ssl, const char *line));
+#endif
+
+#endif /* MQTT_WSS_CLIENT_H */
diff --git a/mqtt_websockets/src/include/mqtt_wss_log.h b/mqtt_websockets/src/include/mqtt_wss_log.h
new file mode 100644
index 00000000..a33c460c
--- /dev/null
+++ b/mqtt_websockets/src/include/mqtt_wss_log.h
@@ -0,0 +1,37 @@
+#ifndef MQTT_WSS_LOG_H
+#define MQTT_WSS_LOG_H
+
+typedef enum mqtt_wss_log_type {
+ MQTT_WSS_LOG_DEBUG = 0x01,
+ MQTT_WSS_LOG_INFO = 0x02,
+ MQTT_WSS_LOG_WARN = 0x03,
+ MQTT_WSS_LOG_ERROR = 0x81,
+ MQTT_WSS_LOG_FATAL = 0x88
+} mqtt_wss_log_type_t;
+
+typedef void (*mqtt_wss_log_callback_t)(mqtt_wss_log_type_t, const char*);
+
+typedef struct mqtt_wss_log_ctx *mqtt_wss_log_ctx_t;
+
+/** Creates logging context with optional prefix and optional callback
+ * @param ctx_prefix String to be prefixed to every log message.
+ * This is useful if multiple clients are instantiated to be able to
+ * know which one this message belongs to. Can be `NULL` for no prefix.
+ * @param log_callback Callback to be called instead of logging to
+ * `STDOUT` or `STDERR` (if debug enabled otherwise silent). Callback has to be
+ * pointer to function of `void function(mqtt_wss_log_type_t, const char*)` type.
+ * If `NULL` default will be used (silent or STDERR/STDOUT).
+ * @return mqtt_wss_log_ctx_t or `NULL` on error */
+mqtt_wss_log_ctx_t mqtt_wss_log_ctx_create(const char *ctx_prefix, mqtt_wss_log_callback_t log_callback);
+
+/** Destroys logging context and cleans up the memory
+ * @param ctx Context to destroy */
+void mqtt_wss_log_ctx_destroy(mqtt_wss_log_ctx_t ctx);
+
+void mws_fatal(mqtt_wss_log_ctx_t ctx, const char *fmt, ...);
+void mws_error(mqtt_wss_log_ctx_t ctx, const char *fmt, ...);
+void mws_warn (mqtt_wss_log_ctx_t ctx, const char *fmt, ...);
+void mws_info (mqtt_wss_log_ctx_t ctx, const char *fmt, ...);
+void mws_debug(mqtt_wss_log_ctx_t ctx, const char *fmt, ...);
+
+#endif /* MQTT_WSS_LOG_H */
diff --git a/mqtt_websockets/src/include/ws_client.h b/mqtt_websockets/src/include/ws_client.h
new file mode 100644
index 00000000..de4fac40
--- /dev/null
+++ b/mqtt_websockets/src/include/ws_client.h
@@ -0,0 +1,130 @@
+// Copyright (C) 2020 Timotej Šiškovič
+// SPDX-License-Identifier: GPL-3.0-only
+//
+// This program is free software: you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free Software Foundation, version 3.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+// See the GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along with this program.
+// If not, see <https://www.gnu.org/licenses/>.
+
+#ifndef WS_CLIENT_H
+#define WS_CLIENT_H
+
+#include "ringbuffer.h"
+#include "mqtt_wss_log.h"
+
+#include <stdint.h>
+
+#define WS_CLIENT_NEED_MORE_BYTES 0x10
+#define WS_CLIENT_PARSING_DONE 0x11
+#define WS_CLIENT_CONNECTION_CLOSED 0x12
+#define WS_CLIENT_PROTOCOL_ERROR -0x10
+#define WS_CLIENT_BUFFER_FULL -0x11
+#define WS_CLIENT_INTERNAL_ERROR -0x12
+
+enum websocket_client_conn_state {
+ WS_RAW = 0,
+ WS_HANDSHAKE,
+ WS_ESTABLISHED,
+ WS_ERROR, // connection has to be restarted if this is reached
+ WS_CONN_CLOSED_GRACEFUL
+};
+
+enum websocket_client_hdr_parse_state {
+ WS_HDR_HTTP = 0, // need to check HTTP/1.1
+ WS_HDR_RC, // need to read HTTP code
+ WS_HDR_ENDLINE, // need to read rest of the first line
+ WS_HDR_PARSE_HEADERS, // rest of the header until CRLF CRLF
+ WS_HDR_PARSE_DONE,
+ WS_HDR_ALL_DONE
+};
+
+enum websocket_client_rx_ws_parse_state {
+ WS_FIRST_2BYTES = 0,
+ WS_PAYLOAD_EXTENDED_16,
+ WS_PAYLOAD_EXTENDED_64,
+ WS_PAYLOAD_DATA, // BINARY payload to be passed to MQTT
+ WS_PAYLOAD_CONNECTION_CLOSE,
+ WS_PAYLOAD_CONNECTION_CLOSE_EC,
+ WS_PAYLOAD_CONNECTION_CLOSE_MSG,
+ WS_PAYLOAD_SKIP_UNKNOWN_PAYLOAD,
+ WS_PAYLOAD_PING_REQ_PAYLOAD, // PING payload to be sent back as PONG
+ WS_PACKET_DONE
+};
+
+enum websocket_opcode {
+ WS_OP_CONTINUATION_FRAME = 0x0,
+ WS_OP_TEXT_FRAME = 0x1,
+ WS_OP_BINARY_FRAME = 0x2,
+ WS_OP_CONNECTION_CLOSE = 0x8,
+ WS_OP_PING = 0x9,
+ WS_OP_PONG = 0xA
+};
+
+struct ws_op_close_payload {
+ uint16_t ec;
+ char *reason;
+};
+
+struct http_header {
+ char *key;
+ char *value;
+ struct http_header *next;
+};
+
+typedef struct websocket_client {
+ enum websocket_client_conn_state state;
+
+ struct ws_handshake {
+ enum websocket_client_hdr_parse_state hdr_state;
+ char *nonce_reply;
+ int nonce_matched;
+ int http_code;
+ char *http_reply_msg;
+ struct http_header *headers;
+ struct http_header *headers_tail;
+ int hdr_count;
+ } hs;
+
+ struct ws_rx {
+ enum websocket_client_rx_ws_parse_state parse_state;
+ enum websocket_opcode opcode;
+ uint64_t payload_length;
+ uint64_t payload_processed;
+ union {
+ struct ws_op_close_payload op_close;
+ char *ping_msg;
+ } specific_data;
+ } rx;
+
+ rbuf_t buf_read; // from SSL
+ rbuf_t buf_write; // to SSL and then to socket
+ // TODO if ringbuffer gets multiple tail support
+ // we can work without buf_to_mqtt and thus reduce
+ // memory usage and remove one more memcpy buf_read->buf_to_mqtt
+ rbuf_t buf_to_mqtt; // RAW data for MQTT lib
+
+ int entropy_fd;
+
+ // careful host is borrowed, don't free
+ char **host;
+ mqtt_wss_log_ctx_t log;
+} ws_client;
+
+ws_client *ws_client_new(size_t buf_size, char **host, mqtt_wss_log_ctx_t log);
+void ws_client_destroy(ws_client *client);
+void ws_client_reset(ws_client *client);
+
+int ws_client_start_handshake(ws_client *client);
+
+int ws_client_want_write(ws_client *client);
+
+int ws_client_process(ws_client *client);
+
+int ws_client_send(ws_client *client, enum websocket_opcode frame_type, const char *data, size_t size);
+
+#endif /* WS_CLIENT_H */