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 curl easy socket backend. #380

Merged
merged 9 commits into from Dec 11, 2023
Merged

Conversation

philljj
Copy link
Contributor

@philljj philljj commented Dec 6, 2023

Description

Added libcurl easy socket backend support for testing purposes.

Built with:

./configure --enable-curl

Prereqs

  • wolfssl has been built with --enable-curl and installed to /usr/local.
  • libcurl has been built with --with-wolfssl and installed to /usr/local.

Testing

Added new curl easy socket example to examples/mqttnet.c, gated behind ENABLE_MQTT_CURL. If using TLS a CAfile can be passed in with -A:

$./examples/mqttclient/mqttclient -p 8883 -A mosquitto.org.crt -t
MQTT Client: QoS 0, Use TLS 1
MQTT Net Init: Success (0)
MQTT Init: Success (0)
*   Trying [2001:41d0:1:925e::1]:8883...
*   Trying 91.121.93.94:8883...
* Connected to test.mosquitto.org (2001:41d0:1:925e::1) port 8883
* successfully set certificate verify locations:
*  CAfile: mosquitto.org.crt
*  CApath: /etc/ssl/certs
* SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384
* using HTTP/1.x
* Connection #0 to host test.mosquitto.org left intact
MQTT Socket Connect: Success (0)
MQTT Connect: Proto (v3.1.1), Success (0)
MQTT Connect Ack: Return Code 0, Session Present 0
MQTT Subscribe: Success (0)
  Topic wolfMQTT/example/testTopic, Qos 0, Return Code 0
MQTT Publish: Topic wolfMQTT/example/testTopic, ID 2, Success (0)
MQTT Waiting for message...
MQTT Message: Topic wolfMQTT/example/testTopic, Qos 0, Len 4
Payload (0 - 4) printing 4 bytes:
test
MQTT Message: Done
$./examples/mqttclient/mqttclient -p 1883
MQTT Client: QoS 0, Use TLS 0
MQTT Net Init: Success (0)
MQTT Init: Success (0)
*   Trying [2001:41d0:1:925e::1]:1883...
* Connected to test.mosquitto.org (2001:41d0:1:925e::1) port 1883
* Connection #0 to host test.mosquitto.org left intact
MQTT Socket Connect: Success (0)
MQTT Connect: Proto (v3.1.1), Success (0)
MQTT Connect Ack: Return Code 0, Session Present 0
MQTT Subscribe: Success (0)
  Topic wolfMQTT/example/testTopic, Qos 0, Return Code 0
MQTT Publish: Topic wolfMQTT/example/testTopic, ID 2, Success (0)
MQTT Waiting for message...
MQTT Message: Topic wolfMQTT/example/testTopic, Qos 0, Len 4
Payload (0 - 4) printing 4 bytes:
test
MQTT Message: Done

Also test with:

./configure --enable-curl && make check
./configure --enable-mt --enable-nonblock CFLAGS="-DWOLFMQTT_TEST_NONBLOCK" --enable-curl  && make check

These tests are enabled and work with --enable-curl:

  • scripts/firmware.test
  • scripts/client.test

These tests work as well if they are enabled:

  • scripts/multithread.test
  • scripts/nbclient.test

@philljj philljj self-assigned this Dec 6, 2023
configure.ac Outdated

if test "x$ENABLED_CURL" = "xyes"; then
if test "x$ENABLED_TLS" = "xyes"; then
AC_MSG_ERROR([--enable-tls and --enable-curl are incompatible])
Copy link
Contributor

Choose a reason for hiding this comment

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

Do these really need to be incompatible? Just seems odd to forcefully have to disable TLS here to get the CURL easy sockets to work.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

In the last update --enable-curl and --enable-tls are allowed now. It disables some examples that aren't expected to work with curl. And when curl is enabled some of the lower level TLS code in src/mqtt_socket.c is gated out.

src/mqtt_curl.c Outdated Show resolved Hide resolved
src/mqtt_curl.c Outdated
#include <errno.h>
#endif

#include "wolfmqtt/mqtt_client.h"
Copy link
Contributor

Choose a reason for hiding this comment

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

We must support building sources directly. This while file needs wrapped with ENABLE_MQTT_CURL

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good catch!

examples/mqttcurl.c Outdated Show resolved Hide resolved

if (ctx->curl == NULL) {
PRINTF("error: curl_easy_init returned NULL");
return MQTT_CODE_ERROR_MEMORY;
Copy link
Contributor

Choose a reason for hiding this comment

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

Please refactor to single return point. Can't you leak handles returning early?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done! Refactored the setopt and curl_easy_perform to a separate function, and the handle is cleaned up if that function fails.

@dgarske dgarske requested a review from embhorn December 6, 2023 18:20
examples/mqttexample.c Outdated Show resolved Hide resolved
src/mqtt_curl.c Outdated Show resolved Hide resolved
src/mqtt_curl.c Outdated
}

return rc;
}
Copy link
Member

Choose a reason for hiding this comment

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

Some compilers complain when there is no blank line at the eof.

src/mqtt_curl.c Outdated Show resolved Hide resolved
configure.ac Show resolved Hide resolved
Copy link
Member

@embhorn embhorn left a comment

Choose a reason for hiding this comment

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

Could you add a section to the readme about using the libcurl option?

@philljj
Copy link
Contributor Author

philljj commented Dec 8, 2023

The client and firmware tests work with --enable-curl now, and the curl support includes TLS and mTLS.

Will add a github action now.

Copy link
Contributor

@dgarske dgarske left a comment

Choose a reason for hiding this comment

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

Great work. Looking forward to the GitHub CI action being in place.


FD_SET(sockfd, &errfd);

if(for_recv) {
Copy link
Contributor

Choose a reason for hiding this comment

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

NIT: Please use if ( ... add space.

return MQTT_CODE_ERROR_BAD_ARG;
}

/* Toggle with option, or put behind debug define? */
Copy link
Contributor

Choose a reason for hiding this comment

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

Please wrap with DEBUG_WOLFMQTT

@philljj
Copy link
Contributor Author

philljj commented Dec 8, 2023

Added the curl ubuntu CI test in a separate workflow
.github/workflows/ubuntu-check-curl.yml
just to avoid potential side-effects between the with and without curl CI tests.

(The --enable-curl in wolfssl pulls in opensslextra and other things).

The new workflow tests these combinations:

  • --enable-curl
  • --enable-curl --disable-tls

@@ -534,6 +544,10 @@ int MqttSocket_Disconnect(MqttClient *client)
rc = client->net->disconnect(client->net->context);
}
MqttClient_Flags(client, MQTT_CLIENT_FLAG_IS_CONNECTED, 0);

#ifdef ENABLE_MQTT_CURL
curl_global_cleanup();
Copy link
Contributor

Choose a reason for hiding this comment

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

Should this now be in mqttnet.c or maybe MqttClient_DeInit?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think mqttnet.c is too low level.

Would want it somewhere higher level where it's among the first/last functions called on init/exit.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

mqtt_socket just seemed natural because that's where we call wolfSSL_Init/cleanup.

@@ -34,6 +34,10 @@
#include <errno.h>
#endif

#ifdef ENABLE_MQTT_CURL
Copy link
Contributor

Choose a reason for hiding this comment

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

Can likely be removed if curl_global_cleanup is moved

mqttcurl_connect(SocketContext * sock, const char* host, word16 port,
int timeout_ms)
{
CURLcode res = 0;
Copy link
Contributor

Choose a reason for hiding this comment

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

examples/mqttnet.c:435:14: error: cannot initialize a variable of type 'CURLcode' with an rvalue of type 'int'
    CURLcode res = 0;
             ^     ~
examples/mqttnet.c:647:21: error: cannot initialize a variable of type 'CURLcode' with an rvalue of type 'int'
    CURLcode        res = 0;
                    ^     ~
examples/mqttnet.c:714:21: error: cannot initialize a variable of type 'CURLcode' with an rvalue of type 'int'
    CURLcode        res = 0;
                    ^     ~

Copy link
Member

@embhorn embhorn left a comment

Choose a reason for hiding this comment

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

./configure --enable-all --enable-curl produces build errors:

examples/mqttnet.c: In function ‘SN_ClientNet_Init’:
examples/mqttnet.c:1442:24: error: ‘SN_NetConnect’ undeclared (first use in this function); did you mean ‘NetConnect’?
 1442 |         net->connect = SN_NetConnect;
      |                        ^~~~~~~~~~~~~
      |                        NetConnect
examples/mqttnet.c:1442:24: note: each undeclared identifier is reported only once for each function it appears in
examples/mqttnet.c:1445:21: error: ‘NetPeek’ undeclared (first use in this function)
 1445 |         net->peek = NetPeek;
      |                     ^~~~~~~

@philljj
Copy link
Contributor Author

philljj commented Dec 8, 2023

I think several of these combinations need to be rejected in configure.ac. Looking at this.

Copy link
Member

@embhorn embhorn left a comment

Choose a reason for hiding this comment

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

In examples/mqttclient/mqttclient, the client gets into the "Read loop" and fails to send messages typed. Also the client never sends a ping, just exits on timeout:

MQTT Waiting for message...
MQTT Message: Topic wolfMQTT/example/testTopic, Qos 0, Len 4
Payload (0 - 4) printing 4 bytes:
test
MQTT Message: Done
test
error: recvd 0 bytes, expected 2
Network Error Callback: Error (libcurl) (error -16)
MQTT Message Wait: Error (libcurl) (-16)
MQTT Disconnect: Success (0)
MQTT Socket Disconnect: Success (0)

@philljj
Copy link
Contributor Author

philljj commented Dec 8, 2023

Also, I'll document more clearly which --enable- options are compatible with --enable-curl.

Copy link
Contributor

@dgarske dgarske left a comment

Choose a reason for hiding this comment

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

@embhorn when you are happy merge please.

Copy link
Member

@embhorn embhorn left a comment

Choose a reason for hiding this comment

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

Fantastic!

@embhorn embhorn merged commit 15ba2f2 into wolfSSL:master Dec 11, 2023
10 checks passed
@philljj philljj deleted the add_curl_easy_sockets branch December 12, 2023 15:28
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.

None yet

3 participants