Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for websocket #418

Open
wants to merge 8 commits into
base: master
Choose a base branch
from

Conversation

embhorn
Copy link
Member

@embhorn embhorn commented Feb 28, 2025

WebSocket Support

wolfMQTT supports MQTT over WebSockets, allowing clients to connect to MQTT brokers through WebSocket endpoints. This is useful for environments where traditional MQTT ports might be blocked or when integrating with web applications.

Building with WebSocket Support

To build wolfMQTT with WebSocket support:

  1. Install the libwebsockets development library:

    # On Debian/Ubuntu
    sudo apt-get install libwebsockets-dev
    
    # On macOS with Homebrew
    brew install libwebsockets
    
  2. Configure wolfMQTT with WebSocket support:

    ./configure --enable-websocket
    
  3. Build as usual:

    make
    

WebSocket Example

The WebSocket client example is located in /examples/websocket/. This example demonstrates how to connect to an MQTT broker using WebSockets. The example subscribes to the topic "test/topic" and waits for incoming messages.

To run the example:

./examples/websocket/websocket_client [host] [port]

By default, it connects to localhost on port 9001.

Broker Configuration

To use the WebSocket example, your MQTT broker must be configured to support WebSockets. For Mosquitto, add the following to your mosquitto.conf:

# WebSocket settings
listener 9001
protocol websockets

Then restart Mosquitto with this configuration:

mosquitto -c mosquitto.conf

Implementation Details

The WebSocket implementation uses libwebsockets as the backend and provides custom network callbacks for the MQTT client:

  • NetWebsocket_Connect: Establishes a WebSocket connection to the broker
  • NetWebsocket_Read: Reads data from the WebSocket connection
  • NetWebsocket_Write: Writes data to the WebSocket connection
  • NetWebsocket_Disconnect: Closes the WebSocket connection

The example also implements a ping mechanism to keep the WebSocket connection alive, sending a ping to the broker every 30 seconds.

@embhorn embhorn force-pushed the cursor_lws_project branch 3 times, most recently from 2121689 to e177fa6 Compare March 4, 2025 16:34
@embhorn embhorn force-pushed the cursor_lws_project branch from e177fa6 to a74025a Compare March 4, 2025 16:37
@embhorn embhorn marked this pull request as ready for review March 4, 2025 17:47
@embhorn embhorn self-assigned this Mar 4, 2025
@embhorn embhorn requested a review from philljj March 4, 2025 17:50
@philljj
Copy link
Contributor

philljj commented Mar 4, 2025

Testing through this on fedora linux:

sudo dnf install libwebsockets
sudo dnf install libwebsockets-devel

I may have missed something, but wolfssl with default configure gives wolfmqtt libwebsocket build error:

In file included from /usr/local/include/wolfssl/wolfcrypt/random.h:109,
                 from /usr/local/include/wolfssl/wolfcrypt/asn_public.h:36,
                 from /usr/local/include/wolfssl/ssl.h:36,
                 from ./wolfmqtt/mqtt_types.h:78,
                 from ./wolfmqtt/mqtt_client.h:41,
                 from examples/net_libwebsockets.c:27:
/usr/include/openssl/sha.h:81:16: error: ‘WC_SHA224’ redeclared as different kind of symbol
   81 | unsigned char *SHA224(const unsigned char *d, size_t n, unsigned char *md);

Building wolfssl with ./configure --enable-opensslcoexist resolves it.

@embhorn
Copy link
Member Author

embhorn commented Mar 4, 2025

On my local system, I have libsockets built with wolfSSL support installed. I did run into issues with the workflow, and I just built wolfMQTT with --disable-tls

The next effort for this will be to enable secure websocket support

Copy link
Contributor

@philljj philljj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good so far, just light feedback suggestions.

@embhorn embhorn requested a review from philljj March 5, 2025 18:26
configure.ac Outdated
@@ -380,6 +384,24 @@ if test "x$ENABLED_STRESS" != "xno"; then
AM_CFLAGS="$AM_CFLAGS -DNUM_PUB_PER_TASK=$NUM_PUBS"
fi

# WebSocket
if test "x$enable_websocket" = "xyes"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just noticed this configure warning:

./configure --enable-websocket
configure: WARNING: unrecognized options: --enable-websocket
checking build system type... x86_64-pc-linux-gnu
...
   * Multi-thread:              no
   * Stress:                    no
   * WebSocket:                 yes

Adding a missing AC_ARG_ENABLE([websocket] fixes it:

diff --git a/configure.ac b/configure.ac
index 234a127..c24eaec 100644
--- a/configure.ac
+++ b/configure.ac
@@ -384,8 +384,14 @@ if test "x$ENABLED_STRESS" != "xno"; then
     AM_CFLAGS="$AM_CFLAGS -DNUM_PUB_PER_TASK=$NUM_PUBS"
 fi
 
+AC_ARG_ENABLE([websocket],
+    [AS_HELP_STRING([--enable-websocket],[Enable websocket example (default: disabled)])],
+    [ ENABLED_WEBSOCKET=$enableval ],
+    [ ENABLED_WEBSOCKET=no ]
+    )
+
 # WebSocket
-if test "x$enable_websocket" = "xyes"
+if test "x$ENABLED_WEBSOCKET" = "xyes"
 then
     AM_CFLAGS="$AM_CFLAGS -DENABLE_MQTT_WEBSOCKET"
     ENABLED_WEBSOCKET=yes


/* Try to write with timeout */
ret = 0;
while (ret <= 0) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I try to connect while broker is down, it segfaults:

./examples/websocket/websocket_client localhost 19001
Connecting to localhost:19001
[2025/03/05 14:10:55:6780] N: lws_create_context: LWS: 4.3.3-no_hash, NET CLI SRV H1 H2 WS ConMon IPV6-on
[2025/03/05 14:10:55:6781] N: __lws_lc_tag:  ++ [wsi|0|pipe] (1)
[2025/03/05 14:10:55:6781] N: __lws_lc_tag:  ++ [vh|0|netlink] (1)
[2025/03/05 14:10:55:6782] N: __lws_lc_tag:  ++ [vh|1|default||-1] (2)
[2025/03/05 14:10:55:6782] N: __lws_lc_tag:  ++ [wsicli|0|WS/h1/default/localhost] (1)
[2025/03/05 14:10:55:6786] N: [wsicli|0|WS/h1/default/localhost]: lws_client_connect_check: getsockopt fd 6 says e 111
[2025/03/05 14:10:55:6787] N: [wsicli|0|WS/h1/default/localhost]: lws_client_connect_check: getsockopt fd 6 says e 111
[2025/03/05 14:10:55:6787] N: __lws_lc_untag:  -- [wsicli|0|WS/h1/default/localhost] (0) 473μs
MqttClient_NetConnect failed: -8
[2025/03/05 14:10:55:6787] E: [wsicli|0|WS/h1/default/localhost]: lws_issue_raw: invalid sock
Segmentation fault (core dumped)

With this small change it errors gracefully:

-    while (ret <= 0) {
+    while (ret <= 0 && net->status > 0) {

After:

./examples/websocket/websocket_client localhost 19001
Connecting to localhost:19001
[2025/03/05 14:10:30:3210] N: lws_create_context: LWS: 4.3.3-no_hash, NET CLI SRV H1 H2 WS ConMon IPV6-on
[2025/03/05 14:10:30:3211] N: __lws_lc_tag:  ++ [wsi|0|pipe] (1)
[2025/03/05 14:10:30:3211] N: __lws_lc_tag:  ++ [vh|0|netlink] (1)
[2025/03/05 14:10:30:3212] N: __lws_lc_tag:  ++ [vh|1|default||-1] (2)
[2025/03/05 14:10:30:3212] N: __lws_lc_tag:  ++ [wsicli|0|WS/h1/default/localhost] (1)
[2025/03/05 14:10:30:3215] N: [wsicli|0|WS/h1/default/localhost]: lws_client_connect_check: getsockopt fd 6 says e 111
[2025/03/05 14:10:30:3217] N: [wsicli|0|WS/h1/default/localhost]: lws_client_connect_check: getsockopt fd 6 says e 111
[2025/03/05 14:10:30:3217] N: __lws_lc_untag:  -- [wsicli|0|WS/h1/default/localhost] (0) 482μs
MqttClient_NetConnect failed: -8

@embhorn embhorn force-pushed the cursor_lws_project branch from 684697b to a428995 Compare March 5, 2025 21:06
@embhorn embhorn requested a review from philljj March 5, 2025 21:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants