From 2bae880b0934629b41a7fca7fdf0d7f914688d94 Mon Sep 17 00:00:00 2001 From: Sven Gambel Date: Wed, 17 Mar 2021 11:46:05 +0100 Subject: [PATCH 01/93] Add generic proxy support. Moved WebSocket proxy support to generic proxy support. Signed-off-by: Sven Gambel --- src/CMakeLists.txt | 1 + src/Clients.h | 4 +- src/MQTTAsync.h | 4 +- src/MQTTAsyncUtils.c | 19 ++--- src/MQTTClient.c | 35 +++++---- src/MQTTClient.h | 4 +- src/MQTTProtocolOut.c | 22 +++--- src/MQTTProtocolOut.h | 2 + src/Proxy.c | 150 ++++++++++++++++++++++++++++++++++++++ src/Proxy.h | 25 +++++++ src/WebSocket.c | 122 +------------------------------ src/WebSocket.h | 4 +- src/samples/pubsub_opts.h | 2 +- 13 files changed, 229 insertions(+), 165 deletions(-) create mode 100644 src/Proxy.c create mode 100644 src/Proxy.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7354056d5..9985c7159 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -47,6 +47,7 @@ SET(common_src Base64.c SHA1.c WebSocket.c + Proxy.c ) IF (NOT PAHO_HIGH_PERFORMANCE) diff --git a/src/Clients.h b/src/Clients.h index a3ddb1fb8..1a9d9aa0c 100644 --- a/src/Clients.h +++ b/src/Clients.h @@ -145,8 +145,8 @@ typedef struct void* context; /**< calling context - used when calling disconnect_internal */ int MQTTVersion; /**< the version of MQTT being used, 3, 4 or 5 */ int sessionExpiry; /**< MQTT 5 session expiry */ - char* httpProxy; /**< HTTP proxy for websockets */ - char* httpsProxy; /**< HTTPS proxy for websockets */ + char* httpProxy; /**< HTTP proxy */ + char* httpsProxy; /**< HTTPS proxy */ #if defined(OPENSSL) MQTTClient_SSLOptions *sslopts; /**< the SSL/TLS connect options */ SSL_SESSION* session; /**< SSL session pointer for fast handhake */ diff --git a/src/MQTTAsync.h b/src/MQTTAsync.h index c05b68656..d7914166d 100644 --- a/src/MQTTAsync.h +++ b/src/MQTTAsync.h @@ -1341,11 +1341,11 @@ typedef struct */ const MQTTAsync_nameValue* httpHeaders; /** - * HTTP proxy for websockets + * HTTP proxy */ const char* httpProxy; /** - * HTTPS proxy for websockets + * HTTPS proxy */ const char* httpsProxy; } MQTTAsync_connectOptions; diff --git a/src/MQTTAsyncUtils.c b/src/MQTTAsyncUtils.c index 86b9d2862..48b8fe782 100644 --- a/src/MQTTAsyncUtils.c +++ b/src/MQTTAsyncUtils.c @@ -12,7 +12,7 @@ * * Contributors: * Ian Craggs - initial implementation and documentation - * + * Sven Gambel - add generic proxy support *******************************************************************************/ #include @@ -35,6 +35,7 @@ #include "Heap.h" #include "OsWrapper.h" #include "WebSocket.h" +#include "Proxy.h" static int clientSockCompare(void* a, void* b); static int MQTTAsync_checkConn(MQTTAsync_command* command, MQTTAsyncs* client); @@ -2698,9 +2699,9 @@ static int MQTTAsync_connecting(MQTTAsyncs* m) size_t hostname_len; int setSocketForSSLrc = 0; - if (m->websocket && m->c->net.https_proxy) { + if (m->c->net.https_proxy) { m->c->connect_state = PROXY_CONNECT_IN_PROGRESS; - if ((rc = WebSocket_proxy_connect( &m->c->net, 1, serverURI)) == SOCKET_ERROR ) + if ((rc = Proxy_connect( &m->c->net, 1, serverURI)) == SOCKET_ERROR ) goto exit; } @@ -2760,14 +2761,14 @@ static int MQTTAsync_connecting(MQTTAsyncs* m) else { #endif + if (m->c->net.http_proxy) { + m->c->connect_state = PROXY_CONNECT_IN_PROGRESS; + if ((rc = Proxy_connect( &m->c->net, 0, serverURI)) == SOCKET_ERROR ) + goto exit; + } + if ( m->websocket ) { - if (m->c->net.http_proxy) { - m->c->connect_state = PROXY_CONNECT_IN_PROGRESS; - if ((rc = WebSocket_proxy_connect( &m->c->net, 0, serverURI)) == SOCKET_ERROR ) - goto exit; - } - m->c->connect_state = WEBSOCKET_IN_PROGRESS; if ((rc = WebSocket_connect(&m->c->net, serverURI)) == SOCKET_ERROR ) goto exit; diff --git a/src/MQTTClient.c b/src/MQTTClient.c index 710ee87f0..2fc03d3bf 100644 --- a/src/MQTTClient.c +++ b/src/MQTTClient.c @@ -35,6 +35,7 @@ * Ian Craggs - check for NULL SSL options #334 * Ian Craggs - allocate username/password buffers #431 * Ian Craggs - MQTT 5.0 support + * Sven Gambel - add generic proxy support *******************************************************************************/ /** @@ -80,6 +81,7 @@ #include "VersionInfo.h" #include "WebSocket.h" +#include "Proxy.h" const char *client_timestamp_eye = "MQTTClientV3_Timestamp " BUILD_TIMESTAMP; const char *client_version_eye = "MQTTClientV3_Version " CLIENT_VERSION; @@ -1231,9 +1233,9 @@ static MQTTResponse MQTTClient_connectURIVersion(MQTTClient handle, MQTTClient_c const char *topic; int setSocketForSSLrc = 0; - if (m->websocket && m->c->net.https_proxy) { + if (m->c->net.https_proxy) { m->c->connect_state = PROXY_CONNECT_IN_PROGRESS; - if ((rc = WebSocket_proxy_connect( &m->c->net, 1, serverURI)) == SOCKET_ERROR ) + if ((rc = Proxy_connect( &m->c->net, 1, serverURI)) == SOCKET_ERROR ) goto exit; } @@ -1288,28 +1290,31 @@ static MQTTResponse MQTTClient_connectURIVersion(MQTTClient handle, MQTTClient_c } } #endif - else if (m->websocket) + else { if (m->c->net.http_proxy) { m->c->connect_state = PROXY_CONNECT_IN_PROGRESS; - if ((rc = WebSocket_proxy_connect( &m->c->net, 0, serverURI)) == SOCKET_ERROR ) + if ((rc = Proxy_connect( &m->c->net, 0, serverURI)) == SOCKET_ERROR ) goto exit; } - m->c->connect_state = WEBSOCKET_IN_PROGRESS; - if ( WebSocket_connect(&m->c->net, serverURI) == SOCKET_ERROR ) + if (m->websocket) { - rc = SOCKET_ERROR; - goto exit; + m->c->connect_state = WEBSOCKET_IN_PROGRESS; + if ( WebSocket_connect(&m->c->net, serverURI) == SOCKET_ERROR ) + { + rc = SOCKET_ERROR; + goto exit; + } } - } - else - { - m->c->connect_state = WAIT_FOR_CONNACK; /* TCP connect completed, in which case send the MQTT connect packet */ - if (MQTTPacket_send_connect(m->c, MQTTVersion, connectProperties, willProperties) == SOCKET_ERROR) + else { - rc = SOCKET_ERROR; - goto exit; + m->c->connect_state = WAIT_FOR_CONNACK; /* TCP connect completed, in which case send the MQTT connect packet */ + if (MQTTPacket_send_connect(m->c, MQTTVersion, connectProperties, willProperties) == SOCKET_ERROR) + { + rc = SOCKET_ERROR; + goto exit; + } } } } diff --git a/src/MQTTClient.h b/src/MQTTClient.h index 59da61789..7e4c55ad2 100644 --- a/src/MQTTClient.h +++ b/src/MQTTClient.h @@ -951,11 +951,11 @@ typedef struct */ const MQTTClient_nameValue* httpHeaders; /** - * HTTP proxy for websockets + * HTTP proxy */ const char* httpProxy; /** - * HTTPS proxy for websockets + * HTTPS proxy */ const char* httpsProxy; } MQTTClient_connectOptions; diff --git a/src/MQTTProtocolOut.c b/src/MQTTProtocolOut.c index 06c277dfb..a3dc787a0 100644 --- a/src/MQTTProtocolOut.c +++ b/src/MQTTProtocolOut.c @@ -21,6 +21,7 @@ * Ian Craggs - fix for issue #164 * Ian Craggs - fix for issue #179 * Ian Craggs - MQTT 5.0 support + * Sven Gambel - add generic proxy support *******************************************************************************/ /** @@ -38,6 +39,7 @@ #include "StackTrace.h" #include "Heap.h" #include "WebSocket.h" +#include "Proxy.h" #include "Base64.h" extern ClientStates* bstate; @@ -247,11 +249,11 @@ int MQTTProtocol_connect(const char* ip_address, Clients* aClient, int websocket Log(TRACE_PROTOCOL, -1, "Setting https proxy auth to %s", aClient->net.https_proxy_auth); } - if (!ssl && websocket && aClient->net.http_proxy) { + if (!ssl && aClient->net.http_proxy) { #else - if (websocket && aClient->net.http_proxy) { + if (aClient->net.http_proxy) { #endif - addr_len = MQTTProtocol_addressPort(aClient->net.http_proxy, &port, NULL, WS_DEFAULT_PORT); + addr_len = MQTTProtocol_addressPort(aClient->net.http_proxy, &port, NULL, PROXY_DEFAULT_PORT); #if defined(__GNUC__) && defined(__linux__) if (timeout < 0) rc = -1; @@ -262,8 +264,8 @@ int MQTTProtocol_connect(const char* ip_address, Clients* aClient, int websocket #endif } #if defined(OPENSSL) - else if (ssl && websocket && aClient->net.https_proxy) { - addr_len = MQTTProtocol_addressPort(aClient->net.https_proxy, &port, NULL, WS_DEFAULT_PORT); + else if (ssl && aClient->net.https_proxy) { + addr_len = MQTTProtocol_addressPort(aClient->net.https_proxy, &port, NULL, PROXY_DEFAULT_PORT); #if defined(__GNUC__) && defined(__linux__) if (timeout < 0) rc = -1; @@ -296,9 +298,9 @@ int MQTTProtocol_connect(const char* ip_address, Clients* aClient, int websocket #if defined(OPENSSL) if (ssl) { - if (websocket && aClient->net.https_proxy) { + if (aClient->net.https_proxy) { aClient->connect_state = PROXY_CONNECT_IN_PROGRESS; - rc = WebSocket_proxy_connect( &aClient->net, 1, ip_address); + rc = Proxy_connect( &aClient->net, 1, ip_address); } if (rc == 0 && SSLSocket_setSocketForSSL(&aClient->net, aClient->sslopts, ip_address, addr_len) == 1) { @@ -313,12 +315,12 @@ int MQTTProtocol_connect(const char* ip_address, Clients* aClient, int websocket else rc = SOCKET_ERROR; } - else if (websocket && aClient->net.http_proxy) { + else if (aClient->net.http_proxy) { #else - if (websocket && aClient->net.http_proxy) { + if (aClient->net.http_proxy) { #endif aClient->connect_state = PROXY_CONNECT_IN_PROGRESS; - rc = WebSocket_proxy_connect( &aClient->net, 0, ip_address); + rc = Proxy_connect( &aClient->net, 0, ip_address); } if ( websocket ) { diff --git a/src/MQTTProtocolOut.h b/src/MQTTProtocolOut.h index 6a5015574..a31e2e572 100644 --- a/src/MQTTProtocolOut.h +++ b/src/MQTTProtocolOut.h @@ -16,6 +16,7 @@ * Ian Craggs - MQTT 3.1.1 support * Ian Craggs - SNI support * Ian Craggs - MQTT 5.0 support + * Sven Gambel - add generic proxy support *******************************************************************************/ #if !defined(MQTTPROTOCOLOUT_H) @@ -32,6 +33,7 @@ #define MQTT_DEFAULT_PORT 1883 #define SECURE_MQTT_DEFAULT_PORT 8883 #define WS_DEFAULT_PORT 80 +#define PROXY_DEFAULT_PORT 8080 size_t MQTTProtocol_addressPort(const char* uri, int* port, const char **topic, int default_port); void MQTTProtocol_reconnect(const char* ip_address, Clients* client); diff --git a/src/Proxy.c b/src/Proxy.c new file mode 100644 index 000000000..16399ad7c --- /dev/null +++ b/src/Proxy.c @@ -0,0 +1,150 @@ +/******************************************************************************* + * Copyright (c) 2009, 2021 Diehl Metering. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v2.0 + * and Eclipse Distribution License v1.0 which accompany this distribution. + * + * The Eclipse Public License is available at + * https://www.eclipse.org/legal/epl-2.0/ + * and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * Contributors: + * Sven Gambel - move WebSocket proxy support to generic proxy support + *******************************************************************************/ + +#include +#include +// for timeout process in Proxy_connect() +#include +#if defined(_WIN32) || defined(_WIN64) +#include +#else +#include +#endif + +#include "Log.h" +#include "MQTTProtocolOut.h" +#include "StackTrace.h" +#include "Heap.h" + +#if defined(OPENSSL) +#include "SSLSocket.h" +#include +#endif /* defined(OPENSSL) */ +#include "Socket.h" + +/** + * Notify the IP address and port of the endpoint to proxy, and wait connection to endpoint. + * + * @param[in] net network connection to proxy. + * @param[in] ssl enable ssl. + * @param[in] hostname hostname of endpoint. + * + * @retval SOCKET_ERROR failed to network connection + * @retval 0 connection to endpoint + * + */ +int Proxy_connect(networkHandles *net, int ssl, const char *hostname) +{ + int port, i, rc = 0, buf_len=0; + char *buf = NULL; + size_t hostname_len, actual_len = 0; + time_t current, timeout; + PacketBuffers nulbufs = {0, NULL, NULL, NULL, {0, 0, 0, 0}}; + + FUNC_ENTRY; + hostname_len = MQTTProtocol_addressPort(hostname, &port, NULL, PROXY_DEFAULT_PORT); + for ( i = 0; i < 2; ++i ) { +#if defined(OPENSSL) + if(ssl) { + if (net->https_proxy_auth) { + buf_len = snprintf( buf, (size_t)buf_len, "CONNECT %.*s:%d HTTP/1.1\r\n" + "Host: %.*s\r\n" + "Proxy-authorization: Basic %s\r\n" + "\r\n", + (int)hostname_len, hostname, port, + (int)hostname_len, hostname, net->https_proxy_auth); + } + else { + buf_len = snprintf( buf, (size_t)buf_len, "CONNECT %.*s:%d HTTP/1.1\r\n" + "Host: %.*s\r\n" + "\r\n", + (int)hostname_len, hostname, port, + (int)hostname_len, hostname); + } + } + else { +#endif + if (net->http_proxy_auth) { + buf_len = snprintf( buf, (size_t)buf_len, "CONNECT %.*s:%d HTTP/1.1\r\n" + "Host: %.*s\r\n" + "Proxy-authorization: Basic %s\r\n" + "\r\n", + (int)hostname_len, hostname, port, + (int)hostname_len, hostname, net->http_proxy_auth); + } + else { + buf_len = snprintf( buf, (size_t)buf_len, "CONNECT %.*s:%d HTTP/1.1\r\n" + "Host: %.*s\r\n" + "\r\n", + (int)hostname_len, hostname, port, + (int)hostname_len, hostname); + } +#if defined(OPENSSL) + } +#endif + if ( i==0 && buf_len > 0 ) { + ++buf_len; + if ((buf = malloc( buf_len )) == NULL) + { + rc = PAHO_MEMORY_ERROR; + goto exit; + } + + } + } + Log(TRACE_PROTOCOL, -1, "Proxy_connect: \"%s\"", buf); + + Socket_putdatas(net->socket, buf, buf_len, nulbufs); + free(buf); + buf = NULL; + + time(&timeout); + timeout += (time_t)10; + + while(1) { + buf = Socket_getdata(net->socket, (size_t)12, &actual_len, &rc); + if(actual_len) { + if ( (strncmp( buf, "HTTP/1.0 200", 12 ) != 0) && (strncmp( buf, "HTTP/1.1 200", 12 ) != 0) ) + rc = SOCKET_ERROR; + break; + } + else { + time(¤t); + if(current > timeout) { + rc = SOCKET_ERROR; + break; + } +#if defined(_WIN32) || defined(_WIN64) + Sleep(250); +#else + usleep(250000); +#endif + } + } + + /* flush the SocketBuffer */ + actual_len = 1; + while (actual_len) + { + int rc1; + + buf = Socket_getdata(net->socket, (size_t)1, &actual_len, &rc1); + } + +exit: + FUNC_EXIT_RC(rc); + return rc; +} diff --git a/src/Proxy.h b/src/Proxy.h new file mode 100644 index 000000000..67cf5df16 --- /dev/null +++ b/src/Proxy.h @@ -0,0 +1,25 @@ +/******************************************************************************* + * Copyright (c) 2009, 2021 Diehl Metering. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v2.0 + * and Eclipse Distribution License v1.0 which accompany this distribution. + * + * The Eclipse Public License is available at + * https://www.eclipse.org/legal/epl-2.0/ + * and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * Contributors: + * Sven Gambel - move WebSocket proxy support to generic proxy support + *******************************************************************************/ + +#if !defined(PROXY_H) +#define PROXY_H + +#include "Clients.h" + +/* Notify the IP address and port of the endpoint to proxy, and wait connection to endpoint */ +int Proxy_connect(networkHandles *net, int ssl, const char *hostname ); + +#endif /* PROXY_H */ diff --git a/src/WebSocket.c b/src/WebSocket.c index b26b4bf89..dfb94cdab 100644 --- a/src/WebSocket.c +++ b/src/WebSocket.c @@ -14,18 +14,12 @@ * Keith Holman - initial implementation and documentation * Ian Craggs - use memory tracking * Ian Craggs - fix for one MQTT packet spread over >1 ws frame + * Sven Gambel - move WebSocket proxy support to generic proxy support *******************************************************************************/ #include #include #include -// for timeout process in WebSocket_proxy_connect() -#include -#if defined(_WIN32) || defined(_WIN64) -#include -#else -#include -#endif #include "WebSocket.h" @@ -1431,117 +1425,3 @@ int WebSocket_upgrade( networkHandles *net ) FUNC_EXIT_RC(rc); return rc; } - -/** - * Notify the IP address and port of the endpoint to proxy, and wait connection to endpoint. - * - * @param[in] net network connection to proxy. - * @param[in] ssl enable ssl. - * @param[in] hostname hostname of endpoint. - * - * @retval SOCKET_ERROR failed to network connection - * @retval 0 connection to endpoint - * - */ -int WebSocket_proxy_connect( networkHandles *net, int ssl, const char *hostname) -{ - int port, i, rc = 0, buf_len=0; - char *buf = NULL; - size_t hostname_len, actual_len = 0; - time_t current, timeout; - PacketBuffers nulbufs = {0, NULL, NULL, NULL, {0, 0, 0, 0}}; - - FUNC_ENTRY; - hostname_len = MQTTProtocol_addressPort(hostname, &port, NULL, WS_DEFAULT_PORT); - for ( i = 0; i < 2; ++i ) { -#if defined(OPENSSL) - if(ssl) { - if (net->https_proxy_auth) { - buf_len = snprintf( buf, (size_t)buf_len, "CONNECT %.*s:%d HTTP/1.1\r\n" - "Host: %.*s\r\n" - "Proxy-authorization: Basic %s\r\n" - "\r\n", - (int)hostname_len, hostname, port, - (int)hostname_len, hostname, net->https_proxy_auth); - } - else { - buf_len = snprintf( buf, (size_t)buf_len, "CONNECT %.*s:%d HTTP/1.1\r\n" - "Host: %.*s\r\n" - "\r\n", - (int)hostname_len, hostname, port, - (int)hostname_len, hostname); - } - } - else { -#endif - if (net->http_proxy_auth) { - buf_len = snprintf( buf, (size_t)buf_len, "CONNECT %.*s:%d HTTP/1.1\r\n" - "Host: %.*s\r\n" - "Proxy-authorization: Basic %s\r\n" - "\r\n", - (int)hostname_len, hostname, port, - (int)hostname_len, hostname, net->http_proxy_auth); - } - else { - buf_len = snprintf( buf, (size_t)buf_len, "CONNECT %.*s:%d HTTP/1.1\r\n" - "Host: %.*s\r\n" - "\r\n", - (int)hostname_len, hostname, port, - (int)hostname_len, hostname); - } -#if defined(OPENSSL) - } -#endif - if ( i==0 && buf_len > 0 ) { - ++buf_len; - if ((buf = malloc( buf_len )) == NULL) - { - rc = PAHO_MEMORY_ERROR; - goto exit; - } - - } - } - Log(TRACE_PROTOCOL, -1, "WebSocket_proxy_connect: \"%s\"", buf); - - Socket_putdatas(net->socket, buf, buf_len, nulbufs); - free(buf); - buf = NULL; - - time(&timeout); - timeout += (time_t)10; - - while(1) { - buf = Socket_getdata(net->socket, (size_t)12, &actual_len, &rc); - if(actual_len) { - if ( (strncmp( buf, "HTTP/1.0 200", 12 ) != 0) && (strncmp( buf, "HTTP/1.1 200", 12 ) != 0) ) - rc = SOCKET_ERROR; - break; - } - else { - time(¤t); - if(current > timeout) { - rc = SOCKET_ERROR; - break; - } -#if defined(_WIN32) || defined(_WIN64) - Sleep(250); -#else - usleep(250000); -#endif - } - } - - /* flush the SocketBuffer */ - actual_len = 1; - while (actual_len) - { - int rc1; - - buf = Socket_getdata(net->socket, (size_t)1, &actual_len, &rc1); - } - -exit: - FUNC_EXIT_RC(rc); - return rc; -} diff --git a/src/WebSocket.h b/src/WebSocket.h index e9f576536..1183c9691 100644 --- a/src/WebSocket.h +++ b/src/WebSocket.h @@ -12,6 +12,7 @@ * * Contributors: * Keith Holman - initial implementation and documentation + * Sven Gambel - move WebSocket proxy support to generic proxy support *******************************************************************************/ #if !defined(WEBSOCKET_H) @@ -71,7 +72,4 @@ void WebSocket_terminate(void); /* handles websocket upgrade request */ int WebSocket_upgrade(networkHandles *net); -/* Notify the IP address and port of the endpoint to proxy, and wait connection to endpoint */ -int WebSocket_proxy_connect( networkHandles *net, int ssl, const char *hostname); - #endif /* WEBSOCKET_H */ diff --git a/src/samples/pubsub_opts.h b/src/samples/pubsub_opts.h index 0f2268272..73bb09764 100644 --- a/src/samples/pubsub_opts.h +++ b/src/samples/pubsub_opts.h @@ -69,7 +69,7 @@ struct pubsub_opts char *name; char *value; } user_property; - /* websocket HTTP proxies */ + /* HTTP proxies */ char* http_proxy; char* https_proxy; }; From ee364a61a0f82fc5be939c05a0757bb34c2a17ae Mon Sep 17 00:00:00 2001 From: Victor Rosca Date: Thu, 8 Jul 2021 07:57:58 +0300 Subject: [PATCH 02/93] Fix MQTTAsync_terminate(), to re-check the number of handles after re-acquisition of mqttasync_mutex, and refrain from deleting the global variables if the number of handles is no longer zero. Signed-off-by: Victor Rosca --- src/MQTTAsync.c | 3 +-- src/MQTTAsyncUtils.c | 6 ++++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/MQTTAsync.c b/src/MQTTAsync.c index 6f6caa6d9..4c92eee63 100644 --- a/src/MQTTAsync.c +++ b/src/MQTTAsync.c @@ -627,8 +627,6 @@ int MQTTAsync_connect(MQTTAsync handle, const MQTTAsync_connectOptions* options) m->connect.context = options->context; m->connectTimeout = options->connectTimeout; - MQTTAsync_tostop = 0; - /* don't lock async mutex if we are being called from a callback */ thread_id = Thread_getid(); if (thread_id != sendThread_id && thread_id != receiveThread_id) @@ -636,6 +634,7 @@ int MQTTAsync_connect(MQTTAsync handle, const MQTTAsync_connectOptions* options) MQTTAsync_lock_mutex(mqttasync_mutex); locked = 1; } + MQTTAsync_tostop = 0; if (sendThread_state != STARTING && sendThread_state != RUNNING) { sendThread_state = STARTING; diff --git a/src/MQTTAsyncUtils.c b/src/MQTTAsyncUtils.c index 8c4554ec6..7126f4360 100644 --- a/src/MQTTAsyncUtils.c +++ b/src/MQTTAsyncUtils.c @@ -198,7 +198,9 @@ void MQTTAsync_terminate(void) { FUNC_ENTRY; MQTTAsync_stop(); - if (global_initialized) + + /* don't destroy global data if a new client was created while waiting for background threads to terminate */ + if (global_initialized && bstate->clients->count == 0) { ListElement* elem = NULL; ListFree(bstate->clients); @@ -2309,7 +2311,7 @@ static void MQTTAsync_stop(void) { int count = 0; MQTTAsync_tostop = 1; - while ((sendThread_state != STOPPED || receiveThread_state != STOPPED) && ++count < 100) + while ((sendThread_state != STOPPED || receiveThread_state != STOPPED) && MQTTAsync_tostop != 0 && ++count < 100) { MQTTAsync_unlock_mutex(mqttasync_mutex); Log(TRACE_MIN, -1, "sleeping"); From fadf34d1e57ca4e4c1cf310991a766233de5ce9b Mon Sep 17 00:00:00 2001 From: vm-vloz Date: Mon, 26 Jul 2021 18:51:32 -0700 Subject: [PATCH 03/93] Fix disconnect when there are pending writes Signed-off-by: vm-vloz <73361520+vm-vloz@users.noreply.github.com> --- src/Clients.h | 1 + src/MQTTAsync.c | 4 +- src/MQTTClient.c | 2 + src/MQTTProtocolClient.c | 125 ++++++++++++++++++++++++++++++++++----- src/MQTTProtocolClient.h | 2 + src/Socket.c | 8 +++ src/Socket.h | 3 + 7 files changed, 129 insertions(+), 16 deletions(-) diff --git a/src/Clients.h b/src/Clients.h index b0cacf082..23a715ef6 100644 --- a/src/Clients.h +++ b/src/Clients.h @@ -137,6 +137,7 @@ typedef struct List* inboundMsgs; /**< inbound in flight messages */ List* outboundMsgs; /**< outbound in flight messages */ List* messageQueue; /**< inbound complete but undelivered messages */ + List* outboundQueue; /**< outbound queued messages */ unsigned int qentry_seqno; void* phandle; /**< the persistence handle */ MQTTClient_persistence* persistence; /**< a persistence implementation */ diff --git a/src/MQTTAsync.c b/src/MQTTAsync.c index 6f6caa6d9..c5516a633 100644 --- a/src/MQTTAsync.c +++ b/src/MQTTAsync.c @@ -356,6 +356,7 @@ int MQTTAsync_createWithOptions(MQTTAsync* handle, const char* serverURI, const bstate->clients = ListInitialize(); Socket_outInitialize(); Socket_setWriteCompleteCallback(MQTTAsync_writeComplete); + Socket_setWriteAvailableCallback(MQTTProtocol_writeAvailable); MQTTAsync_handles = ListInitialize(); MQTTAsync_commands = ListInitialize(); #if defined(OPENSSL) @@ -408,9 +409,10 @@ int MQTTAsync_createWithOptions(MQTTAsync* handle, const char* serverURI, const m->c->outboundMsgs = ListInitialize(); m->c->inboundMsgs = ListInitialize(); m->c->messageQueue = ListInitialize(); + m->c->outboundQueue = ListInitialize(); m->c->clientID = MQTTStrdup(clientId); if (m->c->context == NULL || m->c->outboundMsgs == NULL || m->c->inboundMsgs == NULL || - m->c->messageQueue == NULL || m->c->clientID == NULL) + m->c->messageQueue == NULL || m->c->outboundQueue == NULL || m->c->clientID == NULL) { rc = PAHO_MEMORY_ERROR; goto exit; diff --git a/src/MQTTClient.c b/src/MQTTClient.c index b32a35ed3..79f9be706 100644 --- a/src/MQTTClient.c +++ b/src/MQTTClient.c @@ -428,6 +428,7 @@ int MQTTClient_createWithOptions(MQTTClient* handle, const char* serverURI, cons bstate->clients = ListInitialize(); Socket_outInitialize(); Socket_setWriteCompleteCallback(MQTTClient_writeComplete); + Socket_setWriteAvailableCallback(MQTTProtocol_writeAvailable); handles = ListInitialize(); #if defined(OPENSSL) SSLSocket_initialize(); @@ -486,6 +487,7 @@ int MQTTClient_createWithOptions(MQTTClient* handle, const char* serverURI, cons m->c->outboundMsgs = ListInitialize(); m->c->inboundMsgs = ListInitialize(); m->c->messageQueue = ListInitialize(); + m->c->outboundQueue = ListInitialize(); m->c->clientID = MQTTStrdup(clientId); m->connect_sem = Thread_create_sem(&rc); m->connack_sem = Thread_create_sem(&rc); diff --git a/src/MQTTProtocolClient.c b/src/MQTTProtocolClient.c index 78f4d7f21..6ca7d71ea 100644 --- a/src/MQTTProtocolClient.c +++ b/src/MQTTProtocolClient.c @@ -36,6 +36,7 @@ #if !defined(NO_PERSISTENCE) #include "MQTTPersistence.h" #endif +#include "Socket.h" #include "SocketBuffer.h" #include "StackTrace.h" #include "Heap.h" @@ -55,6 +56,13 @@ static int MQTTProtocol_startPublishCommon( int retained); static void MQTTProtocol_retries(START_TIME_TYPE now, Clients* client, int regardless); +static int MQTTProtocol_queueAck(Clients* client, int ackType, int msgId); + +typedef struct { + int messageId; + int ackType; +} AckRequest; + /** * List callback function for comparing Message structures by message id @@ -312,6 +320,7 @@ int MQTTProtocol_handlePublishes(void* pack, int sock) Clients* client = NULL; char* clientid = NULL; int rc = TCPSOCKET_COMPLETE; + int socketHasPendingWrites = 0; FUNC_ENTRY; client = (Clients*)(ListFindItem(bstate->clients, &sock, clientSocketCompare)->content); @@ -320,15 +329,23 @@ int MQTTProtocol_handlePublishes(void* pack, int sock) publish->header.bits.retain, publish->payloadlen, min(20, publish->payloadlen), publish->payload); if (publish->header.bits.qos == 0) + { Protocol_processPublication(publish, client, 1); - else if (!Socket_noPendingWrites(sock)) - rc = SOCKET_ERROR; /* queue acks? */ - else if (publish->header.bits.qos == 1) + goto exit; + } + + socketHasPendingWrites = !Socket_noPendingWrites(sock); + + if (publish->header.bits.qos == 1) { - /* send puback before processing the publications because a lot of return publications could fill up the socket buffer */ - rc = MQTTPacket_send_puback(publish->MQTTVersion, publish->msgId, &client->net, client->clientID); - /* if we get a socket error from sending the puback, should we ignore the publication? */ - Protocol_processPublication(publish, client, 1); + if (socketHasPendingWrites) + rc = MQTTProtocol_queueAck(client, PUBACK, publish->msgId); + else + /* send puback before processing the publications because a lot of return publications could fill up the socket buffer */ + rc = MQTTPacket_send_puback(publish->MQTTVersion, publish->msgId, &client->net, client->clientID); + + /* if we get a socket error from sending the puback, should we ignore the publication? */ + Protocol_processPublication(publish, client, 1); } else if (publish->header.bits.qos == 2) { @@ -364,7 +381,12 @@ int MQTTProtocol_handlePublishes(void* pack, int sock) already_received = 1; } else ListAppend(client->inboundMsgs, m, sizeof(Messages) + len); - rc = MQTTPacket_send_pubrec(publish->MQTTVersion, publish->msgId, &client->net, client->clientID); + + if (socketHasPendingWrites) + rc = MQTTProtocol_queueAck(client, PUBREC, publish->msgId); + else + rc = MQTTPacket_send_pubrec(publish->MQTTVersion, publish->msgId, &client->net, client->clientID); + if (m->MQTTVersion >= MQTTVERSION_5 && already_received == 0) { Publish publish1; @@ -539,7 +561,7 @@ int MQTTProtocol_handlePubrels(void* pack, int sock) if (pubrel->header.bits.dup == 0) Log(TRACE_MIN, 3, NULL, "PUBREL", client->clientID, pubrel->msgId); else if (!Socket_noPendingWrites(sock)) - rc = SOCKET_ERROR; /* queue acks? */ + rc = MQTTProtocol_queueAck(client, PUBCOMP, pubrel->msgId); else /* Apparently this is "normal" behaviour, so we don't need to issue a warning */ rc = MQTTPacket_send_pubcomp(pubrel->MQTTVersion, pubrel->msgId, &client->net, client->clientID); @@ -551,15 +573,16 @@ int MQTTProtocol_handlePubrels(void* pack, int sock) Log(TRACE_MIN, 4, NULL, "PUBREL", client->clientID, pubrel->msgId, m->qos); else if (m->nextMessageType != PUBREL) Log(TRACE_MIN, 5, NULL, "PUBREL", client->clientID, pubrel->msgId); - else if (!Socket_noPendingWrites(sock)) - rc = SOCKET_ERROR; /* queue acks? */ else { Publish publish; memset(&publish, '\0', sizeof(publish)); /* send pubcomp before processing the publications because a lot of return publications could fill up the socket buffer */ - rc = MQTTPacket_send_pubcomp(pubrel->MQTTVersion, pubrel->msgId, &client->net, client->clientID); + if (!Socket_noPendingWrites(sock)) + rc = MQTTProtocol_queueAck(client, PUBCOMP, pubrel->msgId); + else + rc = MQTTPacket_send_pubcomp(pubrel->MQTTVersion, pubrel->msgId, &client->net, client->clientID); publish.header.bits.qos = m->qos; publish.header.bits.retain = m->retain; publish.msgId = m->msgid; @@ -576,9 +599,9 @@ int MQTTProtocol_handlePubrels(void* pack, int sock) else Protocol_processPublication(&publish, client, 0); /* only for 3.1.1 and lower */ #if !defined(NO_PERSISTENCE) - rc += MQTTPersistence_remove(client, - (m->MQTTVersion >= MQTTVERSION_5) ? PERSISTENCE_V5_PUBLISH_RECEIVED : PERSISTENCE_PUBLISH_RECEIVED, - m->qos, pubrel->msgId); + rc += MQTTPersistence_remove(client, + (m->MQTTVersion >= MQTTVERSION_5) ? PERSISTENCE_V5_PUBLISH_RECEIVED : PERSISTENCE_PUBLISH_RECEIVED, + m->qos, pubrel->msgId); #endif if (m->MQTTVersion >= MQTTVERSION_5) MQTTProperties_free(&m->properties); @@ -791,6 +814,35 @@ static void MQTTProtocol_retries(START_TIME_TYPE now, Clients* client, int regar } +/** + * Queue an ack message. This is used when the socket is full (e.g. SSL_ERROR_WANT_WRITE). + * To be completed/cleared when the socket is no longer full + * @param client the client that received the published message + * @param ackType the type of ack to send + * @param msgId the msg id of the message we are acknowledging + * @return the completion code + */ +int MQTTProtocol_queueAck(Clients* client, int ackType, int msgId) +{ + int rc = 0; + AckRequest* ackReq = NULL; + + FUNC_ENTRY; + ackReq = malloc(sizeof(AckRequest)); + if (!ackReq) + rc = PAHO_MEMORY_ERROR; + else + { + ackReq->messageId = msgId; + ackReq->ackType = ackType; + ListAppend(client->outboundQueue, ackReq, sizeof(AckRequest)); + } + + FUNC_EXIT_RC(rc); + return rc; +} + + /** * MQTT retry protocol and socket pending writes processing. * @param now current time @@ -835,6 +887,7 @@ void MQTTProtocol_freeClient(Clients* client) MQTTProtocol_freeMessageList(client->outboundMsgs); MQTTProtocol_freeMessageList(client->inboundMsgs); ListFree(client->messageQueue); + ListFree(client->outboundQueue); free(client->clientID); client->clientID = NULL; if (client->will) @@ -917,6 +970,48 @@ void MQTTProtocol_freeMessageList(List* msgList) } +/** + * Callback that is invoked when the socket is available for writing. + * This is the last attempt made to acknowledge a message. Failures that + * occur here are ignored. + * @param socket the socket that is available for writing + */ +void MQTTProtocol_writeAvailable(int socket) +{ + Clients* client = NULL; + ListElement* current = NULL; + int rc = 0; + + FUNC_ENTRY; + + client = (Clients*)(ListFindItem(bstate->clients, &socket, clientSocketCompare)->content); + + current = NULL; + while (ListNextElement(client->outboundQueue, ¤t) && rc == 0) + { + AckRequest* ackReq = (AckRequest*)(current->content); + + switch (ackReq->ackType) + { + case PUBACK: + rc = MQTTPacket_send_puback(client->MQTTVersion, ackReq->messageId, &client->net, client->clientID); + break; + case PUBREC: + rc = MQTTPacket_send_pubrec(client->MQTTVersion, ackReq->messageId, &client->net, client->clientID); + break; + case PUBCOMP: + rc = MQTTPacket_send_pubcomp(client->MQTTVersion, ackReq->messageId, &client->net, client->clientID); + break; + default: + Log(LOG_ERROR, -1, "unknown ACK type %d, dropping msg", ackReq->ackType); + break; + } + } + + ListEmpty(client->outboundQueue); + FUNC_EXIT_RC(rc); +} + /** * Copy no more than dest_size -1 characters from the string pointed to by src to the array pointed to by dest. * The destination string will always be null-terminated. diff --git a/src/MQTTProtocolClient.h b/src/MQTTProtocolClient.h index 2d077afa6..093711dff 100644 --- a/src/MQTTProtocolClient.h +++ b/src/MQTTProtocolClient.h @@ -55,6 +55,8 @@ void MQTTProtocol_freeMessageList(List* msgList); char* MQTTStrncpy(char *dest, const char* src, size_t num); char* MQTTStrdup(const char* src); +void MQTTProtocol_writeAvailable(int socket); + //#define MQTTStrdup(src) MQTTStrncpy(malloc(strlen(src)+1), src, strlen(src)+1) #endif diff --git a/src/Socket.c b/src/Socket.c index 6566883de..43bbd237b 100644 --- a/src/Socket.c +++ b/src/Socket.c @@ -861,7 +861,12 @@ void Socket_setWriteCompleteCallback(Socket_writeComplete* mywritecomplete) writecomplete = mywritecomplete; } +static Socket_writeAvailable* writeAvailable = NULL; +void Socket_setWriteAvailableCallback(Socket_writeAvailable* mywriteavailable) +{ + writeAvailable = mywriteavailable; +} /** * Continue an outstanding write for a particular socket @@ -1010,6 +1015,9 @@ int Socket_continueWrites(fd_set* pwset, int* sock) } curpending = mod_s.write_pending->current; + if (writeAvailable && rc > 0) + (*writeAvailable)(socket); + if (writecomplete) (*writecomplete)(socket, rc); } diff --git a/src/Socket.h b/src/Socket.h index 39a8158e7..e9e61e08a 100644 --- a/src/Socket.h +++ b/src/Socket.h @@ -142,4 +142,7 @@ void Socket_clearPendingWrite(int socket); typedef void Socket_writeComplete(int socket, int rc); void Socket_setWriteCompleteCallback(Socket_writeComplete*); +typedef void Socket_writeAvailable(int socket); +void Socket_setWriteAvailableCallback(Socket_writeAvailable*); + #endif /* SOCKET_H */ From 31c44e79f342bd91cc7f11517ce3382df9ceee53 Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Wed, 28 Jul 2021 17:38:35 +0100 Subject: [PATCH 04/93] Change ordering of acks to after processing incoming message --- src/MQTTProtocolClient.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/MQTTProtocolClient.c b/src/MQTTProtocolClient.c index 78f4d7f21..8ed220ed3 100644 --- a/src/MQTTProtocolClient.c +++ b/src/MQTTProtocolClient.c @@ -325,10 +325,8 @@ int MQTTProtocol_handlePublishes(void* pack, int sock) rc = SOCKET_ERROR; /* queue acks? */ else if (publish->header.bits.qos == 1) { - /* send puback before processing the publications because a lot of return publications could fill up the socket buffer */ - rc = MQTTPacket_send_puback(publish->MQTTVersion, publish->msgId, &client->net, client->clientID); - /* if we get a socket error from sending the puback, should we ignore the publication? */ Protocol_processPublication(publish, client, 1); + rc = MQTTPacket_send_puback(publish->MQTTVersion, publish->msgId, &client->net, client->clientID); } else if (publish->header.bits.qos == 2) { @@ -364,7 +362,6 @@ int MQTTProtocol_handlePublishes(void* pack, int sock) already_received = 1; } else ListAppend(client->inboundMsgs, m, sizeof(Messages) + len); - rc = MQTTPacket_send_pubrec(publish->MQTTVersion, publish->msgId, &client->net, client->clientID); if (m->MQTTVersion >= MQTTVERSION_5 && already_received == 0) { Publish publish1; @@ -394,6 +391,7 @@ int MQTTProtocol_handlePublishes(void* pack, int sock) } memcpy(m->publish->payload, temp, m->publish->payloadlen); } + rc = MQTTPacket_send_pubrec(publish->MQTTVersion, publish->msgId, &client->net, client->clientID); publish->topic = NULL; } exit: @@ -558,8 +556,6 @@ int MQTTProtocol_handlePubrels(void* pack, int sock) Publish publish; memset(&publish, '\0', sizeof(publish)); - /* send pubcomp before processing the publications because a lot of return publications could fill up the socket buffer */ - rc = MQTTPacket_send_pubcomp(pubrel->MQTTVersion, pubrel->msgId, &client->net, client->clientID); publish.header.bits.qos = m->qos; publish.header.bits.retain = m->retain; publish.msgId = m->msgid; @@ -586,6 +582,7 @@ int MQTTProtocol_handlePubrels(void* pack, int sock) ListRemove(&(state.publications), m->publish); ListRemove(client->inboundMsgs, m); ++(state.msgs_received); + rc = MQTTPacket_send_pubcomp(pubrel->MQTTVersion, pubrel->msgId, &client->net, client->clientID); } } if (pubrel->MQTTVersion >= MQTTVERSION_5) From eccdb8412218bcaba0c1c60c13b6163da23efd1e Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Thu, 5 Aug 2021 18:39:41 +0100 Subject: [PATCH 05/93] Try building with Github actions --- .github/workflows/build_linux.yml | 41 +++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 .github/workflows/build_linux.yml diff --git a/.github/workflows/build_linux.yml b/.github/workflows/build_linux.yml new file mode 100644 index 000000000..d03d40b49 --- /dev/null +++ b/.github/workflows/build_linux.yml @@ -0,0 +1,41 @@ +name: "Builds for Linux" +on: push + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Check out code + uses: actions/checkout@v2 + - name: Install dependencies + run: | + apt-get install doxygen + - name: Build + run: | + rm -rf build.paho + mkdir build.paho + cd build.paho + echo "travis build dir $TRAVIS_BUILD_DIR pwd $PWD with OpenSSL root $OPENSSL_ROOT_DIR" + cmake -DPAHO_BUILD_STATIC=TRUE -DPAHO_BUILD_SHARED=TRUE -DCMAKE_BUILD_TYPE=Debug -DPAHO_WITH_SSL=TRUE -DOPENSSL_ROOT_DIR= -DPAHO_BUILD_DOCUMENTATION=FALSE -DPAHO_BUILD_SAMPLES=TRUE -DPAHO_HIGH_PERFORMANCE=TRUE .. + cmake --build . + - name: Start test broker + run: | + git clone https://github.com/eclipse/paho.mqtt.testing.git + cd paho.mqtt.testing/interoperability + python3 startbroker.py -c localhost_testing.conf & + cd ../.. + - name: Start test proxy + run: | + python3 test/mqttsas.py & + - name: run tests + run: | + ctest -VV --timeout 600 + - name: clean up + run: | + killall python3 || true + sleep 3 # allow broker time to terminate and report + - name: package + run: | + cpack --verbose + + From 378f64d5827a66c9402f5de3fe9fa2df820481f8 Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Thu, 5 Aug 2021 18:47:45 +0100 Subject: [PATCH 06/93] Fix yaml --- .github/workflows/build_linux.yml | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build_linux.yml b/.github/workflows/build_linux.yml index d03d40b49..0be976e47 100644 --- a/.github/workflows/build_linux.yml +++ b/.github/workflows/build_linux.yml @@ -1,7 +1,7 @@ name: "Builds for Linux" on: push -jobs: +jobs: build: runs-on: ubuntu-latest steps: @@ -21,9 +21,9 @@ jobs: - name: Start test broker run: | git clone https://github.com/eclipse/paho.mqtt.testing.git - cd paho.mqtt.testing/interoperability - python3 startbroker.py -c localhost_testing.conf & - cd ../.. + cd paho.mqtt.testing/interoperability + python3 startbroker.py -c localhost_testing.conf & + cd ../.. - name: Start test proxy run: | python3 test/mqttsas.py & @@ -37,5 +37,3 @@ jobs: - name: package run: | cpack --verbose - - From 469c278ab7fd857252d88a353e1c75bc53b299c2 Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Thu, 5 Aug 2021 18:57:53 +0100 Subject: [PATCH 07/93] Use sudo to install doxygen --- .github/workflows/build_linux.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build_linux.yml b/.github/workflows/build_linux.yml index 0be976e47..f6ccd7e8e 100644 --- a/.github/workflows/build_linux.yml +++ b/.github/workflows/build_linux.yml @@ -9,7 +9,8 @@ jobs: uses: actions/checkout@v2 - name: Install dependencies run: | - apt-get install doxygen + sudo apt-get update + sudo apt-get install doxygen - name: Build run: | rm -rf build.paho From a72ea3ae485f281103d46b6b88f6b14842884ef5 Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Thu, 5 Aug 2021 19:03:06 +0100 Subject: [PATCH 08/93] Run tests from the right place --- .github/workflows/build_linux.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build_linux.yml b/.github/workflows/build_linux.yml index f6ccd7e8e..bfaa8a652 100644 --- a/.github/workflows/build_linux.yml +++ b/.github/workflows/build_linux.yml @@ -16,9 +16,10 @@ jobs: rm -rf build.paho mkdir build.paho cd build.paho - echo "travis build dir $TRAVIS_BUILD_DIR pwd $PWD with OpenSSL root $OPENSSL_ROOT_DIR" + echo "pwd $PWD" cmake -DPAHO_BUILD_STATIC=TRUE -DPAHO_BUILD_SHARED=TRUE -DCMAKE_BUILD_TYPE=Debug -DPAHO_WITH_SSL=TRUE -DOPENSSL_ROOT_DIR= -DPAHO_BUILD_DOCUMENTATION=FALSE -DPAHO_BUILD_SAMPLES=TRUE -DPAHO_HIGH_PERFORMANCE=TRUE .. cmake --build . + cd .. - name: Start test broker run: | git clone https://github.com/eclipse/paho.mqtt.testing.git @@ -30,6 +31,7 @@ jobs: python3 test/mqttsas.py & - name: run tests run: | + cd build.paho ctest -VV --timeout 600 - name: clean up run: | From 0245be75ab0df4a72a5a13c08206da19a9bdd531 Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Mon, 9 Aug 2021 11:09:51 +0100 Subject: [PATCH 09/93] Run on ubuntu 18.04 instead --- .github/workflows/build_linux.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build_linux.yml b/.github/workflows/build_linux.yml index bfaa8a652..deec28aab 100644 --- a/.github/workflows/build_linux.yml +++ b/.github/workflows/build_linux.yml @@ -3,7 +3,7 @@ on: push jobs: build: - runs-on: ubuntu-latest + runs-on: ubuntu-18.04 steps: - name: Check out code uses: actions/checkout@v2 @@ -17,7 +17,7 @@ jobs: mkdir build.paho cd build.paho echo "pwd $PWD" - cmake -DPAHO_BUILD_STATIC=TRUE -DPAHO_BUILD_SHARED=TRUE -DCMAKE_BUILD_TYPE=Debug -DPAHO_WITH_SSL=TRUE -DOPENSSL_ROOT_DIR= -DPAHO_BUILD_DOCUMENTATION=FALSE -DPAHO_BUILD_SAMPLES=TRUE -DPAHO_HIGH_PERFORMANCE=TRUE .. + cmake -DPAHO_BUILD_STATIC=FALSE -DPAHO_BUILD_SHARED=TRUE -DCMAKE_BUILD_TYPE=Debug -DPAHO_WITH_SSL=TRUE -DOPENSSL_ROOT_DIR= -DPAHO_BUILD_DOCUMENTATION=FALSE -DPAHO_BUILD_SAMPLES=TRUE -DPAHO_HIGH_PERFORMANCE=TRUE .. cmake --build . cd .. - name: Start test broker From 08d7757dea96ff2d66533255d3275d99f5be74f9 Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Mon, 9 Aug 2021 11:42:15 +0100 Subject: [PATCH 10/93] Set directory for build packaging --- .github/workflows/build_linux.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/build_linux.yml b/.github/workflows/build_linux.yml index deec28aab..62ce1ca06 100644 --- a/.github/workflows/build_linux.yml +++ b/.github/workflows/build_linux.yml @@ -19,13 +19,11 @@ jobs: echo "pwd $PWD" cmake -DPAHO_BUILD_STATIC=FALSE -DPAHO_BUILD_SHARED=TRUE -DCMAKE_BUILD_TYPE=Debug -DPAHO_WITH_SSL=TRUE -DOPENSSL_ROOT_DIR= -DPAHO_BUILD_DOCUMENTATION=FALSE -DPAHO_BUILD_SAMPLES=TRUE -DPAHO_HIGH_PERFORMANCE=TRUE .. cmake --build . - cd .. - name: Start test broker run: | git clone https://github.com/eclipse/paho.mqtt.testing.git cd paho.mqtt.testing/interoperability python3 startbroker.py -c localhost_testing.conf & - cd ../.. - name: Start test proxy run: | python3 test/mqttsas.py & @@ -39,4 +37,5 @@ jobs: sleep 3 # allow broker time to terminate and report - name: package run: | + cd build.paho cpack --verbose From 424215f4bd35425822605d8f4f83f58aaadc52d6 Mon Sep 17 00:00:00 2001 From: ajit bansal Date: Thu, 12 Aug 2021 16:26:28 +0530 Subject: [PATCH 11/93] Issue:With MQTTCLIENT_PERSISTENCE_DEFAULT the paho code crashes for MQTTVERSION_5 #1108 For MQTTVERSION_5 for SUBSCRIBE command qoss details was not added in persistent folder. Also at time of retrieving for SUBSCRIBE & UNSUBSCRIBE command ptr value was not update properly for MQTTProperties value in the buffer. Because of which MQTTProperties_read() would not return 1 and qcommand ends being free and later down the call stack crash would happen. This fix covers above two issue. --- src/MQTTAsyncUtils.c | 51 +++++++++++++++++++++----------------------- 1 file changed, 24 insertions(+), 27 deletions(-) diff --git a/src/MQTTAsyncUtils.c b/src/MQTTAsyncUtils.c index 8c4554ec6..41ad44c52 100644 --- a/src/MQTTAsyncUtils.c +++ b/src/MQTTAsyncUtils.c @@ -254,13 +254,15 @@ static int MQTTAsync_persistCommand(MQTTAsync_queuedCommand* qcmd) int chars = 0; /* number of chars from snprintf */ int props_allocated = 0; int process = 1; + int multiplier = 2; /* default value 2 for MQTTVERSION < 5 */ FUNC_ENTRY; switch (command->type) { case SUBSCRIBE: + multiplier = (aclient->c->MQTTVersion >= MQTTVERSION_5) ? 3 : 2; nbufs = ((aclient->c->MQTTVersion >= MQTTVERSION_5) ? 4 : 3) + - (command->details.sub.count * 2); + (command->details.sub.count * multiplier); if (((lens = (int*)malloc(nbufs * sizeof(int))) == NULL) || ((bufs = malloc(nbufs * sizeof(char *))) == NULL)) @@ -282,12 +284,9 @@ static int MQTTAsync_persistCommand(MQTTAsync_queuedCommand* qcmd) bufs[bufindex] = command->details.sub.topics[i]; lens[bufindex++] = (int)strlen(command->details.sub.topics[i]) + 1; - if (aclient->c->MQTTVersion < MQTTVERSION_5) - { - bufs[bufindex] = &command->details.sub.qoss[i]; - lens[bufindex++] = sizeof(command->details.sub.qoss[i]); - } - else + bufs[bufindex] = &command->details.sub.qoss[i]; + lens[bufindex++] = sizeof(command->details.sub.qoss[i]); + if (aclient->c->MQTTVersion >= MQTTVERSION_5) { if (command->details.sub.count == 1) { @@ -456,7 +455,7 @@ static MQTTAsync_queuedCommand* MQTTAsync_restoreCommand(char* buffer, int bufle switch (command->type) { case SUBSCRIBE: - if (qcommand->not_restored == 0) + if (qcommand->not_restored == 1) break; if (&ptr[sizeof(int)] > endpos) goto error_exit; @@ -467,16 +466,17 @@ static MQTTAsync_queuedCommand* MQTTAsync_restoreCommand(char* buffer, int bufle { if ((command->details.sub.topics = (char **)malloc(sizeof(char *) * command->details.sub.count)) == NULL) goto error_exit; - if (MQTTVersion < MQTTVERSION_5) - { - if ((command->details.sub.qoss = (int *)malloc(sizeof(int) * command->details.sub.count)) == NULL) - goto error_exit; - } - else if (command->details.sub.count > 1) + if ((command->details.sub.qoss = (int *)malloc(sizeof(int) * command->details.sub.count)) == NULL) + goto error_exit; + + if ((MQTTVersion >= MQTTVERSION_5)) { - command->details.sub.optlist = (MQTTSubscribe_options*)malloc(sizeof(MQTTSubscribe_options) * command->details.sub.count); - if (command->details.sub.optlist == NULL) - goto error_exit; + if (command->details.sub.count > 1) + { + command->details.sub.optlist = (MQTTSubscribe_options*)malloc(sizeof(MQTTSubscribe_options) * command->details.sub.count); + if (command->details.sub.optlist == NULL) + goto error_exit; + } } } @@ -488,18 +488,15 @@ static MQTTAsync_queuedCommand* MQTTAsync_restoreCommand(char* buffer, int bufle if ((command->details.sub.topics[i] = malloc(data_size)) == NULL) goto error_exit; - strcpy(command->details.sub.topics[i], ptr); ptr += data_size; - if (MQTTVersion < MQTTVERSION_5) - { - if (&ptr[sizeof(int)] > endpos) - goto error_exit; - command->details.sub.qoss[i] = *(int*)ptr; - ptr += sizeof(int); - } - else + if (&ptr[sizeof(int)] > endpos) + goto error_exit; + command->details.sub.qoss[i] = *(int*)ptr; + ptr += sizeof(int); + + if (MQTTVersion >= MQTTVERSION_5) { if (&ptr[sizeof(MQTTSubscribe_options)] > endpos) goto error_exit; @@ -518,7 +515,7 @@ static MQTTAsync_queuedCommand* MQTTAsync_restoreCommand(char* buffer, int bufle break; case UNSUBSCRIBE: - if (qcommand->not_restored == 0) + if (qcommand->not_restored == 1) break; if (&ptr[sizeof(int)] > endpos) From c26338da7a80eac527d8eddf5c8f8313435f1acf Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Thu, 9 Sep 2021 12:14:28 +0100 Subject: [PATCH 12/93] Add MacOS builds --- .github/workflows/build_linux.yml | 2 +- .github/workflows/build_macos.yml | 41 +++++++++++++++++++++++++++++++ .github/workflows/covsync.yml | 1 + 3 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/build_macos.yml diff --git a/.github/workflows/build_linux.yml b/.github/workflows/build_linux.yml index 62ce1ca06..5bd1d200f 100644 --- a/.github/workflows/build_linux.yml +++ b/.github/workflows/build_linux.yml @@ -1,5 +1,5 @@ name: "Builds for Linux" -on: push +on: [push, pull_request] jobs: build: diff --git a/.github/workflows/build_macos.yml b/.github/workflows/build_macos.yml new file mode 100644 index 000000000..210441d19 --- /dev/null +++ b/.github/workflows/build_macos.yml @@ -0,0 +1,41 @@ +name: "Builds for MacOS" +on: [push, pull_request] + +jobs: + build: + runs-on: macos-latest + steps: + - name: Check out code + uses: actions/checkout@v2 + - name: Install dependencies + run: | + brew update + brew install doxygen + - name: Build + run: | + rm -rf build.paho + mkdir build.paho + cd build.paho + echo "pwd $PWD" + cmake -DPAHO_BUILD_STATIC=FALSE -DPAHO_BUILD_SHARED=TRUE -DCMAKE_BUILD_TYPE=Debug -DPAHO_WITH_SSL=TRUE -DOPENSSL_ROOT_DIR= -DPAHO_BUILD_DOCUMENTATION=FALSE -DPAHO_BUILD_SAMPLES=TRUE -DPAHO_HIGH_PERFORMANCE=TRUE .. + cmake --build . + - name: Start test broker + run: | + git clone https://github.com/eclipse/paho.mqtt.testing.git + cd paho.mqtt.testing/interoperability + python3 startbroker.py -c localhost_testing.conf & + - name: Start test proxy + run: | + python3 test/mqttsas.py & + - name: run tests + run: | + cd build.paho + ctest -VV --timeout 600 + - name: clean up + run: | + killall python3 || true + sleep 3 # allow broker time to terminate and report + - name: package + run: | + cd build.paho + cpack --verbose diff --git a/.github/workflows/covsync.yml b/.github/workflows/covsync.yml index 02578c57a..72e411381 100644 --- a/.github/workflows/covsync.yml +++ b/.github/workflows/covsync.yml @@ -14,4 +14,5 @@ jobs: fetch-depth: 0 - run: | git checkout -b coverity-develop origin/develop + git pull origin coverity-develop git push origin coverity-develop From 8038d446f3f92d1da5388eac91add5ea4ec70454 Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Thu, 9 Sep 2021 12:23:39 +0100 Subject: [PATCH 13/93] Correct MacOS OpenSSL location --- .github/workflows/build_macos.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_macos.yml b/.github/workflows/build_macos.yml index 210441d19..79ec23ea8 100644 --- a/.github/workflows/build_macos.yml +++ b/.github/workflows/build_macos.yml @@ -17,7 +17,7 @@ jobs: mkdir build.paho cd build.paho echo "pwd $PWD" - cmake -DPAHO_BUILD_STATIC=FALSE -DPAHO_BUILD_SHARED=TRUE -DCMAKE_BUILD_TYPE=Debug -DPAHO_WITH_SSL=TRUE -DOPENSSL_ROOT_DIR= -DPAHO_BUILD_DOCUMENTATION=FALSE -DPAHO_BUILD_SAMPLES=TRUE -DPAHO_HIGH_PERFORMANCE=TRUE .. + cmake -DPAHO_BUILD_STATIC=FALSE -DPAHO_BUILD_SHARED=TRUE -DCMAKE_BUILD_TYPE=Debug -DPAHO_WITH_SSL=TRUE -DOPENSSL_ROOT_DIR=/usr/local/opt/openssl -DPAHO_BUILD_DOCUMENTATION=FALSE -DPAHO_BUILD_SAMPLES=TRUE -DPAHO_HIGH_PERFORMANCE=TRUE .. cmake --build . - name: Start test broker run: | From c0df8e7c224ca629318b2ad68229ed78ed7966d2 Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Mon, 13 Sep 2021 12:39:20 +0100 Subject: [PATCH 14/93] Add test for blocked acks --- src/MQTTAsyncUtils.c | 10 +- src/Socket.c | 12 ++- test/CMakeLists.txt | 12 +++ test/test8.c | 224 ++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 244 insertions(+), 14 deletions(-) diff --git a/src/MQTTAsyncUtils.c b/src/MQTTAsyncUtils.c index 8c4554ec6..11f4785d4 100644 --- a/src/MQTTAsyncUtils.c +++ b/src/MQTTAsyncUtils.c @@ -979,9 +979,9 @@ void MQTTAsync_checkDisconnect(MQTTAsync handle, MQTTAsync_command* command) static int MQTTAsync_Socket_noPendingWrites(int socket) { int rc; - Thread_lock_mutex(socket_mutex); + MQTTAsync_lock_mutex(socket_mutex); rc = Socket_noPendingWrites(socket); - Thread_unlock_mutex(socket_mutex); + MQTTAsync_unlock_mutex(socket_mutex); return rc; } @@ -2337,7 +2337,7 @@ static void MQTTAsync_closeOnly(Clients* client, enum MQTTReasonCodes reasonCode MQTTProtocol_checkPendingWrites(); if (client->connected && Socket_noPendingWrites(client->net.socket)) MQTTPacket_send_disconnect(client, reasonCode, props); - Thread_lock_mutex(socket_mutex); + MQTTAsync_lock_mutex(socket_mutex); WebSocket_close(&client->net, WebSocket_CLOSE_NORMAL, NULL); #if defined(OPENSSL) SSL_SESSION_free(client->session); /* is a no-op if session is NULL */ @@ -2349,7 +2349,7 @@ static void MQTTAsync_closeOnly(Clients* client, enum MQTTReasonCodes reasonCode #if defined(OPENSSL) client->net.ssl = NULL; #endif - Thread_unlock_mutex(socket_mutex); + MQTTAsync_unlock_mutex(socket_mutex); } client->connected = 0; client->connect_state = NOT_IN_PROGRESS; @@ -2886,7 +2886,7 @@ static MQTTPacket* MQTTAsync_cycle(int* sock, unsigned long timeout, int* rc) { #endif /* 0 from getReadySocket indicates no work to do, rc -1 == error */ - *sock = Socket_getReadySocket(0, &tp,socket_mutex, &rc1); + *sock = Socket_getReadySocket(0, &tp, socket_mutex, &rc1); *rc = rc1; if (!MQTTAsync_tostop && *sock == 0 && (tp.tv_sec > 0L || tp.tv_usec > 0L)) MQTTAsync_sleep(100L); diff --git a/src/Socket.c b/src/Socket.c index 43bbd237b..cc7aac871 100644 --- a/src/Socket.c +++ b/src/Socket.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009, 2020 IBM Corp. and others + * Copyright (c) 2009, 2021 IBM Corp., Ian Craggs and others * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 @@ -51,7 +51,7 @@ int isReady(int socket, fd_set* read_set, fd_set* write_set); int Socket_writev(int socket, iobuf* iovecs, int count, unsigned long* bytes); int Socket_close_only(int socket); int Socket_continueWrite(int socket); -int Socket_continueWrites(fd_set* pwset, int* socket); +int Socket_continueWrites(fd_set* pwset, int* socket, mutex_type mutex); char* Socket_getaddrname(struct sockaddr* sa, int sock); int Socket_abortWrite(int socket); @@ -284,7 +284,7 @@ int Socket_getReadySocket(int more_work, struct timeval *tp, mutex_type mutex, i } Log(TRACE_MAX, -1, "Return code %d from read select", *rc); - if (Socket_continueWrites(&pwset, &sock) == SOCKET_ERROR) + if (Socket_continueWrites(&pwset, &sock, mutex) == SOCKET_ERROR) { *rc = SOCKET_ERROR; goto exit; @@ -992,7 +992,7 @@ int Socket_abortWrite(int socket) * @param sock in case of a socket error contains the affected socket * @return completion code, 0 or SOCKET_ERROR */ -int Socket_continueWrites(fd_set* pwset, int* sock) +int Socket_continueWrites(fd_set* pwset, int* sock, mutex_type mutex) { int rc1 = 0; ListElement* curpending = mod_s.write_pending->first; @@ -1019,7 +1019,11 @@ int Socket_continueWrites(fd_set* pwset, int* sock) (*writeAvailable)(socket); if (writecomplete) + { + Thread_unlock_mutex(mutex); (*writecomplete)(socket, rc); + Thread_lock_mutex(mutex); + } } else ListNextElement(mod_s.write_pending, &curpending); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 0e4c6a8ee..a3900d75b 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1397,6 +1397,11 @@ IF (PAHO_BUILD_STATIC) COMMAND test8-static "--test_no" "7" "--connection" ${MQTT_TEST_BROKER} ) + ADD_TEST( + NAME test8-6-blocked-acks-static + COMMAND test8-static "--test_no" "8" "--connection" ${MQTT_TEST_BROKER} + ) + SET_TESTS_PROPERTIES( test8-1-basic-connect-subscribe-receive-static test8-2-connect-timeout-static @@ -1405,6 +1410,7 @@ IF (PAHO_BUILD_STATIC) test8-5a-all-ha-connections-out-of-service-static test8-5b-all-ha-connections-out-of-service-except-the-last-one-static test8-5c-all-ha-connections-out-of-service-except-the-first-one-static + test8-6-blocked-acks-static PROPERTIES TIMEOUT 540 ) ENDIF() @@ -1455,6 +1461,11 @@ IF (PAHO_BUILD_SHARED) COMMAND test8 "--test_no" "7" "--connection" ${MQTT_TEST_BROKER} ) + ADD_TEST( + NAME test8-6-blocked-acks + COMMAND test8 "--test_no" "8" "--connection" ${MQTT_TEST_BROKER} + ) + SET_TESTS_PROPERTIES( test8-1-basic-connect-subscribe-receive test8-2-connect-timeout @@ -1463,6 +1474,7 @@ IF (PAHO_BUILD_SHARED) test8-5a-all-ha-connections-out-of-service test8-5b-all-ha-connections-out-of-service-except-the-last-one test8-5c-all-ha-connections-out-of-service-except-the-first-one + test8-6-blocked-acks PROPERTIES TIMEOUT 540 ) ENDIF() diff --git a/test/test8.c b/test/test8.c index 6514d24ce..8f35df7d6 100644 --- a/test/test8.c +++ b/test/test8.c @@ -21,14 +21,16 @@ #include "MQTTAsync.h" +#include "Thread.h" #include #include #if !defined(_WINDOWS) #include - #include + #include #include - #include + #include + #define WINAPI #else #include #endif @@ -45,7 +47,7 @@ struct Options { char* connection; /**< connection to system under test. */ int verbose; - int test_no; + int test_no; int size; /**< size of big message */ } options = { @@ -1092,6 +1094,218 @@ int test5c(struct Options options) } +/********************************************************************* + +Test6: Acks blocked due to sending messages + +*********************************************************************/ +char* test6_topic = "test6_topic"; +char* test6_payload = NULL; +int test6_connected = 0; +int test6_payloadlen = 0; + +int test6_messageArrived(void* context, char* topicName, int topicLen, MQTTAsync_message* message) +{ + MQTTAsync c = (MQTTAsync)context; + static int message_count = 0; + + MyLog(LOGA_DEBUG, "In messageArrived callback %p", c); + + assert("Message size correct", message->payloadlen == test6_payloadlen, + "message size was %d", message->payloadlen); + return 1; +} + + +void test6_onPublish(void* context, MQTTAsync_successData* response) +{ + MQTTAsync c = (MQTTAsync)context; + MQTTAsync_message pubmsg = MQTTAsync_message_initializer; + MQTTAsync_responseOptions opts = MQTTAsync_responseOptions_initializer; + int rc; + static int publish_count = 0; + + if (++publish_count > 100) + { + test_finished = 1; + goto exit; + } + + if (test6_payload == NULL) { + test6_payload = malloc(options.size); + } + + MyLog(LOGA_DEBUG, "In publish onSuccess callback, context %p", context); + pubmsg.payload = test6_payload; + pubmsg.payloadlen = options.size; + pubmsg.qos = 0; + pubmsg.retained = 0; + + opts.onSuccess = test6_onPublish; + opts.context = c; + + rc = MQTTAsync_sendMessage(c, "test6_big_messages", &pubmsg, &opts); + assert("Good rc from publish", rc == MQTTASYNC_SUCCESS, "rc was %d", rc); +exit: + MyLog(LOGA_DEBUG, "Leaving publish onSuccess callback, context %p", context); +} + + +void test6_onSubscribe(void* context, MQTTAsync_successData* response) +{ + MQTTAsync c = (MQTTAsync)context; + MQTTAsync_message pubmsg = MQTTAsync_message_initializer; + MQTTAsync_responseOptions opts = MQTTAsync_responseOptions_initializer; + int rc; + + if (test6_payload == NULL) { + test6_payload = malloc(options.size); + } + + MyLog(LOGA_DEBUG, "In subscribe onSuccess callback, context %p", context); + pubmsg.payload = test6_payload; + pubmsg.payloadlen = options.size; + pubmsg.qos = 0; + pubmsg.retained = 0; + + opts.onSuccess = test6_onPublish; + opts.context = c; + + rc = MQTTAsync_sendMessage(c, "test6_big_messages", &pubmsg, &opts); + assert("Good rc from publish", rc == MQTTASYNC_SUCCESS, "rc was %d", rc); +} + + +void test6_onConnect(void* context, MQTTAsync_successData* response) +{ + MQTTAsync c = (MQTTAsync)context; + MQTTAsync_responseOptions opts = MQTTAsync_responseOptions_initializer; + int rc; + + MyLog(LOGA_DEBUG, "In connect onSuccess callback, context %p", context); + opts.onSuccess = test6_onSubscribe; + opts.context = c; + + rc = MQTTAsync_subscribe(c, test6_topic, 2, &opts); + assert("Good rc from subscribe", rc == MQTTASYNC_SUCCESS, "rc was %d", rc); + if (rc != MQTTASYNC_SUCCESS) + test_finished = 1; +} + + +void test6_onConnected(void* context, MQTTAsync_successData* response) +{ + MQTTAsync d = (MQTTAsync)context; + + MyLog(LOGA_DEBUG, "In connect onSuccess callback, context %p", context); + test6_connected = 1; +} + + +void test6_connectionLost(void* context, char* cause) { + MyLog(LOGA_INFO, "Connection lost"); + test_finished = 1; +} + + +int test6(struct Options options) +{ + MQTTAsync c, d; + MQTTAsync_connectOptions opts = MQTTAsync_connectOptions_initializer; + MQTTAsync_message pubmsg = MQTTAsync_message_initializer; + int rc = 0; + char* test_topic = "C client test8 - test6"; + + failures = 0; + test_finished = 0; + MyLog(LOGA_INFO, "Starting test 6 - acks blocked due to sending messages"); + global_start_time = start_clock(); + + rc = MQTTAsync_create(&c, options.connection, "acks blocked", + MQTTCLIENT_PERSISTENCE_DEFAULT, NULL); + assert("good rc from create", rc == MQTTASYNC_SUCCESS, "rc was %d\n", rc); + if (rc != MQTTASYNC_SUCCESS) + { + MQTTAsync_destroy(&c); + goto exit; + } + + rc = MQTTAsync_setCallbacks(c, c, test6_connectionLost, test6_messageArrived, NULL); + assert("Good rc from setCallbacks", rc == MQTTASYNC_SUCCESS, "rc was %d", rc); + + opts.keepAliveInterval = 20; + opts.cleansession = 1; + opts.username = "testuser"; + opts.password = "testpassword"; + + opts.onSuccess = test6_onConnect; + opts.onFailure = NULL; + opts.context = c; + + MyLog(LOGA_DEBUG, "Connecting"); + rc = MQTTAsync_connect(c, &opts); + assert("Good rc from connect", rc == MQTTASYNC_SUCCESS, "rc was %d", rc); + if (rc != MQTTASYNC_SUCCESS) + goto exit; + + rc = MQTTAsync_create(&d, options.connection, "acks blocked - send loop", + MQTTCLIENT_PERSISTENCE_NONE, NULL); + assert("good rc from create", rc == MQTTASYNC_SUCCESS, "rc was %d\n", rc); + if (rc != MQTTASYNC_SUCCESS) + { + MQTTAsync_destroy(&d); + goto exit; + } + + opts.onSuccess = test6_onConnected; + opts.context = d; + + MyLog(LOGA_DEBUG, "Connecting"); + rc = MQTTAsync_connect(d, &opts); + assert("Good rc from connect", rc == MQTTASYNC_SUCCESS, "rc was %d", rc); + if (rc != MQTTASYNC_SUCCESS) + goto exit; + + while (!test6_connected) + { + #if defined(_WIN32) + Sleep(100); + #else + usleep(10000L); + #endif + } + + pubmsg.payload = "small payload in loop"; + pubmsg.payloadlen = test6_payloadlen = strlen(pubmsg.payload)+1; + pubmsg.qos = 1; + pubmsg.retained = 0; + while (test_finished == 0 && failures == 0) + { + rc = MQTTAsync_sendMessage(d, test6_topic, &pubmsg, NULL); + assert("Good rc from publish", rc == MQTTASYNC_SUCCESS, "rc was %d", rc); + if (rc != MQTTASYNC_SUCCESS) + break; + + #if defined(_WIN32) + Sleep(1000); + #else + usleep(100000L); + #endif + } + + MQTTAsync_destroy(&c); + MQTTAsync_destroy(&d); + +exit: + if (test6_payload) + free(test6_payload); + MyLog(LOGA_INFO, "TEST6: test %s. %d tests run, %d failures.", + (failures == 0) ? "passed" : "failed", tests, failures); + return failures; +} + + + void trace_callback(enum MQTTASYNC_TRACE_LEVELS level, char* message) { if (strstr(message, "onnect") && !strstr(message, "isconnect")) @@ -1102,7 +1316,7 @@ void trace_callback(enum MQTTASYNC_TRACE_LEVELS level, char* message) int main(int argc, char** argv) { int rc = 0; - int (*tests[])() = {NULL, test1, test2, test3, test4, test5a, test5b, test5c}; /* indexed starting from 1 */ + int (*tests[])() = {NULL, test1, test2, test3, test4, test5a, test5b, test5c, test6}; /* indexed starting from 1 */ MQTTAsync_nameValue* info; getopts(argc, argv); @@ -1128,7 +1342,7 @@ int main(int argc, char** argv) } else { - MQTTAsync_setTraceLevel(MQTTASYNC_TRACE_ERROR); + MQTTAsync_setTraceLevel(MQTTASYNC_TRACE_PROTOCOL); rc = tests[options.test_no](options); /* run just the selected test */ } From 8f649286ebcd80023a7466f0a804b6a818eb4d6a Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Mon, 13 Sep 2021 13:45:35 +0100 Subject: [PATCH 15/93] Debug test --- test/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index a3900d75b..14c44bca5 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1463,7 +1463,7 @@ IF (PAHO_BUILD_SHARED) ADD_TEST( NAME test8-6-blocked-acks - COMMAND test8 "--test_no" "8" "--connection" ${MQTT_TEST_BROKER} + COMMAND test8 "--test_no" "8" "--connection" ${MQTT_TEST_BROKER} --verbose ) SET_TESTS_PROPERTIES( From 3d62381aad3b0c59339bfca627fab23ea43e34d9 Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Mon, 13 Sep 2021 14:22:25 +0100 Subject: [PATCH 16/93] Better test debug --- test/CMakeLists.txt | 2 +- test/test8.c | 35 +++++++++++++++++++++++++++++++---- 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 14c44bca5..a3900d75b 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1463,7 +1463,7 @@ IF (PAHO_BUILD_SHARED) ADD_TEST( NAME test8-6-blocked-acks - COMMAND test8 "--test_no" "8" "--connection" ${MQTT_TEST_BROKER} --verbose + COMMAND test8 "--test_no" "8" "--connection" ${MQTT_TEST_BROKER} ) SET_TESTS_PROPERTIES( diff --git a/test/test8.c b/test/test8.c index 8f35df7d6..4c2cc4356 100644 --- a/test/test8.c +++ b/test/test8.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2012, 2020 IBM Corp. and others + * Copyright (c) 2012, 2021 IBM Corp., Ian Craggs and others * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 @@ -1117,6 +1117,14 @@ int test6_messageArrived(void* context, char* topicName, int topicLen, MQTTAsync } +void test6_onPublishFailure(void* context, MQTTAsync_failureData* response) +{ + MyLog(LOGA_INFO, "In publish onFailure callback, context %p", context); + failures++; + test_finished = 1; +} + + void test6_onPublish(void* context, MQTTAsync_successData* response) { MQTTAsync c = (MQTTAsync)context; @@ -1142,6 +1150,7 @@ void test6_onPublish(void* context, MQTTAsync_successData* response) pubmsg.retained = 0; opts.onSuccess = test6_onPublish; + opts.onFailure = test6_onPublishFailure; opts.context = c; rc = MQTTAsync_sendMessage(c, "test6_big_messages", &pubmsg, &opts); @@ -1151,6 +1160,14 @@ void test6_onPublish(void* context, MQTTAsync_successData* response) } +void test6_onSubscribeFailure(void* context, MQTTAsync_failureData* response) +{ + MyLog(LOGA_INFO, "In subscribe onFailure callback, context %p", context); + failures++; + test_finished = 1; +} + + void test6_onSubscribe(void* context, MQTTAsync_successData* response) { MQTTAsync c = (MQTTAsync)context; @@ -1169,6 +1186,7 @@ void test6_onSubscribe(void* context, MQTTAsync_successData* response) pubmsg.retained = 0; opts.onSuccess = test6_onPublish; + opts.onFailure = test6_onPublishFailure; opts.context = c; rc = MQTTAsync_sendMessage(c, "test6_big_messages", &pubmsg, &opts); @@ -1176,6 +1194,14 @@ void test6_onSubscribe(void* context, MQTTAsync_successData* response) } +void test6_onConnectFailure(void* context, MQTTAsync_failureData* response) +{ + MyLog(LOGA_INFO, "In connect onFailure callback, context %p", context); + failures++; + test_finished = 1; +} + + void test6_onConnect(void* context, MQTTAsync_successData* response) { MQTTAsync c = (MQTTAsync)context; @@ -1184,6 +1210,7 @@ void test6_onConnect(void* context, MQTTAsync_successData* response) MyLog(LOGA_DEBUG, "In connect onSuccess callback, context %p", context); opts.onSuccess = test6_onSubscribe; + opts.onFailure = test6_onSubscribeFailure; opts.context = c; rc = MQTTAsync_subscribe(c, test6_topic, 2, &opts); @@ -1239,7 +1266,7 @@ int test6(struct Options options) opts.password = "testpassword"; opts.onSuccess = test6_onConnect; - opts.onFailure = NULL; + opts.onFailure = test6_onConnectFailure; opts.context = c; MyLog(LOGA_DEBUG, "Connecting"); @@ -1266,7 +1293,7 @@ int test6(struct Options options) if (rc != MQTTASYNC_SUCCESS) goto exit; - while (!test6_connected) + while (test6_connected == 0 && test_finished == 0 && failures == 0) { #if defined(_WIN32) Sleep(100); @@ -1342,7 +1369,7 @@ int main(int argc, char** argv) } else { - MQTTAsync_setTraceLevel(MQTTASYNC_TRACE_PROTOCOL); + MQTTAsync_setTraceLevel(MQTTASYNC_TRACE_ERROR); rc = tests[options.test_no](options); /* run just the selected test */ } From 490873f22996768c4c694cf1e96cb86eccad6213 Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Mon, 13 Sep 2021 14:57:13 +0100 Subject: [PATCH 17/93] Test8 debug --- test/test8.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/test8.c b/test/test8.c index 4c2cc4356..e5140cc89 100644 --- a/test/test8.c +++ b/test/test8.c @@ -1139,6 +1139,8 @@ void test6_onPublish(void* context, MQTTAsync_successData* response) goto exit; } + MyLog(LOGA_INFO, "In publish onSuccess callback, count %d", publish_count); + if (test6_payload == NULL) { test6_payload = malloc(options.size); } @@ -1179,7 +1181,7 @@ void test6_onSubscribe(void* context, MQTTAsync_successData* response) test6_payload = malloc(options.size); } - MyLog(LOGA_DEBUG, "In subscribe onSuccess callback, context %p", context); + MyLog(LOGA_INFO, "In subscribe onSuccess callback, context %p", context); pubmsg.payload = test6_payload; pubmsg.payloadlen = options.size; pubmsg.qos = 0; @@ -1208,7 +1210,7 @@ void test6_onConnect(void* context, MQTTAsync_successData* response) MQTTAsync_responseOptions opts = MQTTAsync_responseOptions_initializer; int rc; - MyLog(LOGA_DEBUG, "In connect onSuccess callback, context %p", context); + MyLog(LOGA_INFO, "In connect onSuccess callback, context %p", context); opts.onSuccess = test6_onSubscribe; opts.onFailure = test6_onSubscribeFailure; opts.context = c; From d1744cca8e34c54deeb31bed159eb1caa36961e6 Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Mon, 13 Sep 2021 15:22:03 +0100 Subject: [PATCH 18/93] Shorten message size for test8/test8 --- test/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index a3900d75b..fe4c97af8 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1399,7 +1399,7 @@ IF (PAHO_BUILD_STATIC) ADD_TEST( NAME test8-6-blocked-acks-static - COMMAND test8-static "--test_no" "8" "--connection" ${MQTT_TEST_BROKER} + COMMAND test8-static "--test_no" "8" "--connection" ${MQTT_TEST_BROKER} "--size" "500000" ) SET_TESTS_PROPERTIES( @@ -1463,7 +1463,7 @@ IF (PAHO_BUILD_SHARED) ADD_TEST( NAME test8-6-blocked-acks - COMMAND test8 "--test_no" "8" "--connection" ${MQTT_TEST_BROKER} + COMMAND test8 "--test_no" "8" "--connection" ${MQTT_TEST_BROKER} "--size" "500000" ) SET_TESTS_PROPERTIES( From 9396d4e4e11c6a7c8a7ad4296c9e0f7a031b39ae Mon Sep 17 00:00:00 2001 From: Sven Gambel Date: Sun, 19 Sep 2021 15:59:13 +0200 Subject: [PATCH 19/93] Update Proxy.c Fix Visual Studio 2013 build Signed-off-by: Sven Gambel --- src/Proxy.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Proxy.c b/src/Proxy.c index 16399ad7c..056fca30c 100644 --- a/src/Proxy.c +++ b/src/Proxy.c @@ -19,9 +19,12 @@ // for timeout process in Proxy_connect() #include #if defined(_WIN32) || defined(_WIN64) -#include + #include + #if defined(_MSC_VER) && _MSC_VER < 1900 + #define snprintf _snprintf + #endif #else -#include + #include #endif #include "Log.h" From 83211070d631b1b219106ef7e68464fef45f2a76 Mon Sep 17 00:00:00 2001 From: Sven Gambel Date: Sun, 19 Sep 2021 16:40:26 +0200 Subject: [PATCH 20/93] Credit author of the original implementation Signed-off-by: Sven Gambel --- src/Proxy.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Proxy.c b/src/Proxy.c index 056fca30c..728cb8fcd 100644 --- a/src/Proxy.c +++ b/src/Proxy.c @@ -11,6 +11,7 @@ * http://www.eclipse.org/org/documents/edl-v10.php. * * Contributors: + * Keith Holman - initial implementation and documentation * Sven Gambel - move WebSocket proxy support to generic proxy support *******************************************************************************/ From ea026c43d28d4c5e91a868cae6cd9c2f755188d8 Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Thu, 30 Sep 2021 17:05:36 +0100 Subject: [PATCH 21/93] Switch to MacOS 11 for Github actions --- .github/workflows/build_macos.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_macos.yml b/.github/workflows/build_macos.yml index 79ec23ea8..1d5ee055d 100644 --- a/.github/workflows/build_macos.yml +++ b/.github/workflows/build_macos.yml @@ -3,7 +3,7 @@ on: [push, pull_request] jobs: build: - runs-on: macos-latest + runs-on: macos-11 steps: - name: Check out code uses: actions/checkout@v2 From 26de689a3c4bb1df944dfeffa1f85114bfcdad4f Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Thu, 30 Sep 2021 17:56:16 +0100 Subject: [PATCH 22/93] Revert to macos-latest --- .github/workflows/build_macos.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build_macos.yml b/.github/workflows/build_macos.yml index 1d5ee055d..b45d18c99 100644 --- a/.github/workflows/build_macos.yml +++ b/.github/workflows/build_macos.yml @@ -3,7 +3,7 @@ on: [push, pull_request] jobs: build: - runs-on: macos-11 + runs-on: macos-latest steps: - name: Check out code uses: actions/checkout@v2 @@ -17,7 +17,7 @@ jobs: mkdir build.paho cd build.paho echo "pwd $PWD" - cmake -DPAHO_BUILD_STATIC=FALSE -DPAHO_BUILD_SHARED=TRUE -DCMAKE_BUILD_TYPE=Debug -DPAHO_WITH_SSL=TRUE -DOPENSSL_ROOT_DIR=/usr/local/opt/openssl -DPAHO_BUILD_DOCUMENTATION=FALSE -DPAHO_BUILD_SAMPLES=TRUE -DPAHO_HIGH_PERFORMANCE=TRUE .. + cmake -DPAHO_BUILD_STATIC=FALSE -DPAHO_BUILD_SHARED=TRUE -DCMAKE_BUILD_TYPE=Debug -DPAHO_WITH_SSL=TRUE -DOPENSSL_ROOT_DIR=/usr/local/opt/openssl@1.1 -DPAHO_BUILD_DOCUMENTATION=FALSE -DPAHO_BUILD_SAMPLES=TRUE -DPAHO_HIGH_PERFORMANCE=TRUE .. cmake --build . - name: Start test broker run: | From 354cec7dbb502e8aacfb43b2fc51e5fb8fc4d53e Mon Sep 17 00:00:00 2001 From: Vince Chan Date: Thu, 30 Sep 2021 19:52:19 +0100 Subject: [PATCH 23/93] Fix spelling error in environment variable for osx job --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index befd03c5e..39ee01379 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,7 +11,7 @@ jobs: env: OPENSSL_ROOT_DIR= PAHO_BUILD_STATIC=TRUE PAHO_BUILD_SHARED=TRUE PAHO_HIGH_PERFORMANCE=TRUE - os: osx compiler: clang - env: OPENSSL_ROOT_DIR=/usr/local/opt/openssl PAHO_BUILD_STATIC=FALSE PAHO_BUILD_SHARED=TRUE PAHO_HIGH_PERFORMANC=FALSE + env: OPENSSL_ROOT_DIR=/usr/local/opt/openssl PAHO_BUILD_STATIC=FALSE PAHO_BUILD_SHARED=TRUE PAHO_HIGH_PERFORMANCE=FALSE - os: linux compiler: gcc dist: trusty From 9db81de275037fc97dbcac2b8db6b03fe58fb99e Mon Sep 17 00:00:00 2001 From: Yurii Nakonechnyi Date: Fri, 11 Jun 2021 14:57:47 +0300 Subject: [PATCH 24/93] Updated README.md - added description for CMake option PAHO_ENABLE_TESTING Signed-off-by: Yurii Nakonechnyi --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index b00780f81..7031ab627 100644 --- a/README.md +++ b/README.md @@ -151,6 +151,7 @@ PAHO_WITH_SSL | FALSE | Flag that defines whether to build ssl-enabled binaries OPENSSL_ROOT_DIR | "" (system default) | Directory containing your OpenSSL installation (i.e. `/usr/local` when headers are in `/usr/local/include` and libraries are in `/usr/local/lib`) PAHO_BUILD_DOCUMENTATION | FALSE | Create and install the HTML based API documentation (requires Doxygen) PAHO_BUILD_SAMPLES | FALSE | Build sample programs +PAHO_ENABLE_TESTING | TRUE | Build test and run MQTT_TEST_BROKER | tcp://localhost:1883 | MQTT connection URL for a broker to use during test execution MQTT_TEST_PROXY | tcp://localhost:1883 | Hostname of the test proxy to use MQTT_SSL_HOSTNAME | localhost | Hostname of a test SSL MQTT broker to use From 3ae3d6a9abb2642bfd2f1f67ea5760952c9304c8 Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Mon, 11 Oct 2021 17:41:38 +0100 Subject: [PATCH 25/93] Update to MQTTAsync_subscribe sample #1104 --- src/samples/MQTTAsync_subscribe.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/samples/MQTTAsync_subscribe.c b/src/samples/MQTTAsync_subscribe.c index e2680de48..6d5b8a716 100644 --- a/src/samples/MQTTAsync_subscribe.c +++ b/src/samples/MQTTAsync_subscribe.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2012, 2020 IBM Corp. + * Copyright (c) 2012, 2021 IBM Corp., Ian Craggs * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 @@ -40,6 +40,9 @@ int disc_finished = 0; int subscribed = 0; int finished = 0; +void onConnect(void* context, MQTTAsync_successData* response); +void onConnectFailure(void* context, MQTTAsync_failureData* response); + void connlost(void *context, char *cause) { MQTTAsync client = (MQTTAsync)context; @@ -53,6 +56,8 @@ void connlost(void *context, char *cause) printf("Reconnecting\n"); conn_opts.keepAliveInterval = 20; conn_opts.cleansession = 1; + conn_opts.onSuccess = onConnect; + conn_opts.onFailure = onConnectFailure; if ((rc = MQTTAsync_connect(client, &conn_opts)) != MQTTASYNC_SUCCESS) { printf("Failed to start connect, return code %d\n", rc); From 511e0f658964b92948c8c3fbd6bd12267e7fd668 Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Mon, 18 Oct 2021 14:17:54 +0100 Subject: [PATCH 26/93] Correct .PHONY targets in Makefile #1159 --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index e1a7eab6a..79982d000 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ #******************************************************************************* -# Copyright (c) 2009, 2020 IBM Corp. +# Copyright (c) 2009, 2021 IBM Corp. # # All rights reserved. This program and the accompanying materials # are made available under the terms of the Eclipse Public License v2.0 @@ -21,7 +21,7 @@ # Note: on OS X you should install XCode and the associated command-line tools SHELL = /bin/sh -.PHONY: clean, mkdir, install, uninstall, html +.PHONY: clean mkdir install install-strip uninstall html strip-options MAJOR_VERSION := $(shell cat version.major) MINOR_VERSION := $(shell cat version.minor) From c8944bbe8edc97c1fb67f094e69f12249dff147d Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Mon, 18 Oct 2021 14:26:45 +0100 Subject: [PATCH 27/93] Change -lpthread to -pthread #1160 --- Makefile | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Makefile b/Makefile index 79982d000..2c0fc2b72 100644 --- a/Makefile +++ b/Makefile @@ -155,18 +155,18 @@ PAHO_CS_PUB_TARGET = ${blddir}/samples/${PAHO_CS_PUB_NAME} PAHO_CS_SUB_TARGET = ${blddir}/samples/${PAHO_CS_SUB_NAME} #CCFLAGS_SO = -g -fPIC $(CFLAGS) -Os -Wall -fvisibility=hidden -I$(blddir_work) -#FLAGS_EXE = $(LDFLAGS) -I ${srcdir} -lpthread -L ${blddir} -#FLAGS_EXES = $(LDFLAGS) -I ${srcdir} ${START_GROUP} -lpthread -lssl -lcrypto ${END_GROUP} -L ${blddir} +#FLAGS_EXE = $(LDFLAGS) -I ${srcdir} -pthread -L ${blddir} +#FLAGS_EXES = $(LDFLAGS) -I ${srcdir} ${START_GROUP} -pthread -lssl -lcrypto ${END_GROUP} -L ${blddir} CCFLAGS_SO = -g -fPIC $(CFLAGS) -D_GNU_SOURCE -Os -Wall -fvisibility=hidden -I$(blddir_work) -DPAHO_MQTT_EXPORTS=1 -FLAGS_EXE = $(LDFLAGS) -I ${srcdir} ${START_GROUP} -lpthread ${GAI_LIB} ${END_GROUP} -L ${blddir} -FLAGS_EXES = $(LDFLAGS) -I ${srcdir} ${START_GROUP} -lpthread ${GAI_LIB} -lssl -lcrypto ${END_GROUP} -L ${blddir} +FLAGS_EXE = $(LDFLAGS) -I ${srcdir} ${START_GROUP} -pthread ${GAI_LIB} ${END_GROUP} -L ${blddir} +FLAGS_EXES = $(LDFLAGS) -I ${srcdir} ${START_GROUP} -pthread ${GAI_LIB} -lssl -lcrypto ${END_GROUP} -L ${blddir} LDCONFIG ?= /sbin/ldconfig -LDFLAGS_C = $(LDFLAGS) -shared -Wl,-init,$(MQTTCLIENT_INIT) $(START_GROUP) -lpthread $(GAI_LIB) $(END_GROUP) -LDFLAGS_CS = $(LDFLAGS) -shared $(START_GROUP) -lpthread $(GAI_LIB) $(EXTRA_LIB) -lssl -lcrypto $(END_GROUP) -Wl,-init,$(MQTTCLIENT_INIT) -LDFLAGS_A = $(LDFLAGS) -shared -Wl,-init,$(MQTTASYNC_INIT) $(START_GROUP) -lpthread $(GAI_LIB) $(END_GROUP) -LDFLAGS_AS = $(LDFLAGS) -shared $(START_GROUP) -lpthread $(GAI_LIB) $(EXTRA_LIB) -lssl -lcrypto $(END_GROUP) -Wl,-init,$(MQTTASYNC_INIT) +LDFLAGS_C = $(LDFLAGS) -shared -Wl,-init,$(MQTTCLIENT_INIT) $(START_GROUP) -pthread $(GAI_LIB) $(END_GROUP) +LDFLAGS_CS = $(LDFLAGS) -shared $(START_GROUP) -pthread $(GAI_LIB) $(EXTRA_LIB) -lssl -lcrypto $(END_GROUP) -Wl,-init,$(MQTTCLIENT_INIT) +LDFLAGS_A = $(LDFLAGS) -shared -Wl,-init,$(MQTTASYNC_INIT) $(START_GROUP) -pthread $(GAI_LIB) $(END_GROUP) +LDFLAGS_AS = $(LDFLAGS) -shared $(START_GROUP) -pthread $(GAI_LIB) $(EXTRA_LIB) -lssl -lcrypto $(END_GROUP) -Wl,-init,$(MQTTASYNC_INIT) SED_COMMAND = sed \ -e "s/@CLIENT_VERSION@/${release.version}/g" \ From baa58602c7062214390c695461b6baa7b33595ea Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Mon, 8 Nov 2021 09:53:06 +0000 Subject: [PATCH 28/93] Allow waitfor timeout parameter to be negative #1170 --- src/MQTTClient.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/MQTTClient.c b/src/MQTTClient.c index cda2cf235..275e075e0 100644 --- a/src/MQTTClient.c +++ b/src/MQTTClient.c @@ -362,7 +362,7 @@ static int MQTTClient_disconnect1(MQTTClient handle, int timeout, int internal, static int MQTTClient_disconnect_internal(MQTTClient handle, int timeout); static void MQTTClient_retry(void); static MQTTPacket* MQTTClient_cycle(int* sock, ELAPSED_TIME_TYPE timeout, int* rc); -static MQTTPacket* MQTTClient_waitfor(MQTTClient handle, int packet_type, int* rc, ELAPSED_TIME_TYPE timeout); +static MQTTPacket* MQTTClient_waitfor(MQTTClient handle, int packet_type, int* rc, int64_t timeout); /*static int pubCompare(void* a, void* b); */ static void MQTTProtocol_checkPendingWrites(void); static void MQTTClient_writeComplete(int socket, int rc); @@ -2583,7 +2583,7 @@ static MQTTPacket* MQTTClient_cycle(int* sock, ELAPSED_TIME_TYPE timeout, int* r } -static MQTTPacket* MQTTClient_waitfor(MQTTClient handle, int packet_type, int* rc, ELAPSED_TIME_TYPE timeout) +static MQTTPacket* MQTTClient_waitfor(MQTTClient handle, int packet_type, int* rc, int64_t timeout) { MQTTPacket* pack = NULL; MQTTClients* m = handle; @@ -2678,7 +2678,7 @@ static MQTTPacket* MQTTClient_waitfor(MQTTClient handle, int packet_type, int* r } } } - if (MQTTTime_elapsed(start) > (ELAPSED_TIME_TYPE)timeout) + if (MQTTTime_elapsed(start) > (int64_t)timeout) { pack = NULL; break; From 2e57b65ca08e9b8a91f99c677944a2e86d1fb7f8 Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Tue, 9 Nov 2021 12:47:02 +0000 Subject: [PATCH 29/93] Add handling for incoming MQTT V5 disconnect #1163 --- src/MQTTAsyncUtils.c | 6 +++++- src/MQTTPacket.c | 5 +++-- src/MQTTProtocolOut.c | 23 ++++++++++++++++++++++- src/MQTTProtocolOut.h | 3 ++- src/Messages.c | 3 ++- 5 files changed, 34 insertions(+), 6 deletions(-) diff --git a/src/MQTTAsyncUtils.c b/src/MQTTAsyncUtils.c index 56826aee1..f7ffc0947 100644 --- a/src/MQTTAsyncUtils.c +++ b/src/MQTTAsyncUtils.c @@ -2255,13 +2255,17 @@ thread_return_type WINAPI MQTTAsync_receiveThread(void* n) else if (pack->header.bits.type == DISCONNECT) { Ack* disc = (Ack*)pack; + int discrc = 0; + discrc = disc->rc; if (m->disconnected) { Log(TRACE_MIN, -1, "Calling disconnected for client %s", m->c->clientID); (*(m->disconnected))(m->disconnected_context, &disc->properties, disc->rc); } - MQTTPacket_freeAck(disc); + rc = MQTTProtocol_handleDisconnects(pack, m->c->net.socket); + m->c->connected = 0; /* don't send disconnect packet back */ + nextOrClose(m, discrc, "Received disconnect"); } } } diff --git a/src/MQTTPacket.c b/src/MQTTPacket.c index 296bf31b7..6c9a6c5fe 100644 --- a/src/MQTTPacket.c +++ b/src/MQTTPacket.c @@ -816,10 +816,11 @@ void* MQTTPacket_ack(int MQTTVersion, unsigned char aHeader, char* data, size_t pack->rc = MQTTREASONCODE_SUCCESS; pack->properties = props; - if (datalen > 2) + /* disconnect has no msgid */ + if (datalen > 2 || (pack->header.bits.type == DISCONNECT && datalen > 0)) pack->rc = readChar(&curdata); /* reason code */ - if (datalen > 3) + if (datalen > 3 || (pack->header.bits.type == DISCONNECT && datalen > 1)) { if (MQTTProperties_read(&pack->properties, &curdata, enddata) != 1) { diff --git a/src/MQTTProtocolOut.c b/src/MQTTProtocolOut.c index a3dc787a0..733a3392a 100644 --- a/src/MQTTProtocolOut.c +++ b/src/MQTTProtocolOut.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009, 2020 IBM Corp. + * Copyright (c) 2009, 2021 IBM Corp., Ian Craggs * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 @@ -443,3 +443,24 @@ int MQTTProtocol_handleUnsubacks(void* pack, int sock) return rc; } + +/** + * Process an incoming disconnect packet for a socket + * @param pack pointer to the disconnect packet + * @param sock the socket on which the packet was received + * @return completion code + */ +int MQTTProtocol_handleDisconnects(void* pack, int sock) +{ + Ack* disconnect = (Ack*)pack; + Clients* client = NULL; + int rc = TCPSOCKET_COMPLETE; + + FUNC_ENTRY; + client = (Clients*)(ListFindItem(bstate->clients, &sock, clientSocketCompare)->content); + Log(LOG_PROTOCOL, 30, NULL, sock, client->clientID, disconnect->rc); + MQTTPacket_freeAck(disconnect); + FUNC_EXIT_RC(rc); + return rc; +} + diff --git a/src/MQTTProtocolOut.h b/src/MQTTProtocolOut.h index a31e2e572..d8f43d73a 100644 --- a/src/MQTTProtocolOut.h +++ b/src/MQTTProtocolOut.h @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009, 2020 IBM Corp. + * Copyright (c) 2009, 2021 IBM Corp., Ian Craggs * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 @@ -60,5 +60,6 @@ int MQTTProtocol_subscribe(Clients* client, List* topics, List* qoss, int msgID, int MQTTProtocol_handleSubacks(void* pack, int sock); int MQTTProtocol_unsubscribe(Clients* client, List* topics, int msgID, MQTTProperties* props); int MQTTProtocol_handleUnsubacks(void* pack, int sock); +int MQTTProtocol_handleDisconnects(void* pack, int sock); #endif diff --git a/src/Messages.c b/src/Messages.c index 299612d90..1b47fadf9 100644 --- a/src/Messages.c +++ b/src/Messages.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009, 2020 IBM Corp. + * Copyright (c) 2009, 2021 IBM Corp., Ian Craggs * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 @@ -66,6 +66,7 @@ static const char *protocol_message_list[] = "%d %s -> PUBLISH qos: 0 retained: %d rc: %d payload len(%d): %.*s", /* 27 */ "%d %s -> DISCONNECT (%d)", /* 28 */ "Socket error for client identifier %s, socket %d, peer address %s; ending connection", /* 29 */ + "%d %s <- DISCONNECT (%d)", /* 30 */ }; static const char *trace_message_list[] = From ed2a680b9ac485f0bb90e5cbf2ee811b67adb045 Mon Sep 17 00:00:00 2001 From: Andrey Starodubtsev Date: Thu, 11 Nov 2021 00:00:23 +0300 Subject: [PATCH 30/93] Prevent calling `SSL_read` with `num == 0` If whole packet was read from socket buffer, then `*actual_len == bytes`. But this means that `SSL_read` will be called with `num == 0`; in this case `ssl3_read_bytes` from OpenSSL, for example, return 0 and MQTT library treats connection as closed by remote peer. Signed-off-by: Andrey Starodubtsev --- src/SSLSocket.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/SSLSocket.c b/src/SSLSocket.c index a303d370a..7e96c0f51 100644 --- a/src/SSLSocket.c +++ b/src/SSLSocket.c @@ -884,23 +884,26 @@ char *SSLSocket_getdata(SSL* ssl, int socket, size_t bytes, size_t* actual_len, buf = SocketBuffer_getQueuedData(socket, bytes, actual_len); - ERR_clear_error(); - if ((*rc = SSL_read(ssl, buf + (*actual_len), (int)(bytes - (*actual_len)))) < 0) + if (*actual_len != bytes) { - *rc = SSLSocket_error("SSL_read - getdata", ssl, socket, *rc, NULL, NULL); - if (*rc != SSL_ERROR_WANT_READ && *rc != SSL_ERROR_WANT_WRITE) + ERR_clear_error(); + if ((*rc = SSL_read(ssl, buf + (*actual_len), (int)(bytes - (*actual_len)))) < 0) + { + *rc = SSLSocket_error("SSL_read - getdata", ssl, socket, *rc, NULL, NULL); + if (*rc != SSL_ERROR_WANT_READ && *rc != SSL_ERROR_WANT_WRITE) + { + buf = NULL; + goto exit; + } + } + else if (*rc == 0) /* rc 0 means the other end closed the socket */ { buf = NULL; goto exit; } + else + *actual_len += *rc; } - else if (*rc == 0) /* rc 0 means the other end closed the socket */ - { - buf = NULL; - goto exit; - } - else - *actual_len += *rc; if (*actual_len == bytes) { From 0372393c3f7af00026b626ab6b5a5a27c69c9bfc Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Tue, 16 Nov 2021 19:40:46 +0000 Subject: [PATCH 31/93] Fix some potential locking issues #1169 --- src/MQTTAsync.c | 6 ++++-- src/MQTTAsync.h | 2 +- src/MQTTAsyncUtils.c | 16 ++++++++++++++-- src/Socket.c | 5 +++-- 4 files changed, 22 insertions(+), 7 deletions(-) diff --git a/src/MQTTAsync.c b/src/MQTTAsync.c index 50940e02e..d6fb2181b 100644 --- a/src/MQTTAsync.c +++ b/src/MQTTAsync.c @@ -1426,6 +1426,7 @@ int MQTTAsync_getPendingTokens(MQTTAsync handle, MQTTAsync_token **tokens) FUNC_ENTRY; MQTTAsync_lock_mutex(mqttasync_mutex); + MQTTAsync_lock_mutex(mqttcommand_mutex); *tokens = NULL; if (m == NULL) @@ -1439,7 +1440,7 @@ int MQTTAsync_getPendingTokens(MQTTAsync handle, MQTTAsync_token **tokens) { MQTTAsync_queuedCommand* cmd = (MQTTAsync_queuedCommand*)(current->content); - if (cmd->client == m) + if (cmd->client == m && cmd->command.type == PUBLISH) count++; } if (m->c) @@ -1460,7 +1461,7 @@ int MQTTAsync_getPendingTokens(MQTTAsync handle, MQTTAsync_token **tokens) { MQTTAsync_queuedCommand* cmd = (MQTTAsync_queuedCommand*)(current->content); - if (cmd->client == m) + if (cmd->client == m && cmd->command.type == PUBLISH) (*tokens)[count++] = cmd->command.token; } @@ -1477,6 +1478,7 @@ int MQTTAsync_getPendingTokens(MQTTAsync handle, MQTTAsync_token **tokens) (*tokens)[count] = -1; /* indicate end of list */ exit: + MQTTAsync_unlock_mutex(mqttcommand_mutex); MQTTAsync_unlock_mutex(mqttasync_mutex); FUNC_EXIT_RC(rc); return rc; diff --git a/src/MQTTAsync.h b/src/MQTTAsync.h index 360798a26..3d7783fa1 100644 --- a/src/MQTTAsync.h +++ b/src/MQTTAsync.h @@ -421,7 +421,7 @@ typedef void MQTTAsync_connected(void* context, char* cause); /** * This is a callback function, which will be called when the client - * library receives a disconnect packet. + * library receives a disconnect packet from the server. This applies to MQTT V5 and above only. * * Note: Neither MQTTAsync_create() nor MQTTAsync_destroy() should be * called within this callback. diff --git a/src/MQTTAsyncUtils.c b/src/MQTTAsyncUtils.c index 56826aee1..98507bdfe 100644 --- a/src/MQTTAsyncUtils.c +++ b/src/MQTTAsyncUtils.c @@ -1761,11 +1761,18 @@ thread_return_type WINAPI MQTTAsync_sendThread(void* n) while (!MQTTAsync_tostop) { int rc; + int command_count = 0; - while (MQTTAsync_commands->count > 0) + MQTTAsync_lock_mutex(mqttcommand_mutex); + command_count = MQTTAsync_commands->count; + MQTTAsync_unlock_mutex(mqttcommand_mutex); + while (command_count > 0) { if (MQTTAsync_processCommand() == 0) break; /* no commands were processed, so go into a wait */ + MQTTAsync_lock_mutex(mqttcommand_mutex); + command_count = MQTTAsync_commands->count; + MQTTAsync_unlock_mutex(mqttcommand_mutex); } #if !defined(_WIN32) && !defined(_WIN64) if ((rc = Thread_wait_cond(send_cond, 1)) != 0 && rc != ETIMEDOUT) @@ -2888,10 +2895,15 @@ static MQTTPacket* MQTTAsync_cycle(int* sock, unsigned long timeout, int* rc) if ((*sock = SSLSocket_getPendingRead()) == -1) { #endif + int should_stop = 0; + /* 0 from getReadySocket indicates no work to do, rc -1 == error */ *sock = Socket_getReadySocket(0, &tp, socket_mutex, &rc1); *rc = rc1; - if (!MQTTAsync_tostop && *sock == 0 && (tp.tv_sec > 0L || tp.tv_usec > 0L)) + MQTTAsync_lock_mutex(mqttasync_mutex); + should_stop = MQTTAsync_tostop; + MQTTAsync_unlock_mutex(mqttasync_mutex); + if (!should_stop && *sock == 0 && (tp.tv_sec > 0L || tp.tv_usec > 0L)) MQTTAsync_sleep(100L); #if defined(OPENSSL) } diff --git a/src/Socket.c b/src/Socket.c index cc7aac871..189a84125 100644 --- a/src/Socket.c +++ b/src/Socket.c @@ -268,14 +268,15 @@ int Socket_getReadySocket(int more_work, struct timeval *tp, mutex_type mutex, i if (mod_s.cur_clientsds == NULL) { - int rc1; + int rc1, maxfdp1_saved; fd_set pwset; memcpy((void*)&(mod_s.rset), (void*)&(mod_s.rset_saved), sizeof(mod_s.rset)); memcpy((void*)&(pwset), (void*)&(mod_s.pending_wset), sizeof(pwset)); /* Prevent performance issue by unlocking the socket_mutex while waiting for a ready socket. */ + maxfdp1_saved = mod_s.maxfdp1; Thread_unlock_mutex(mutex); - *rc = select(mod_s.maxfdp1, &(mod_s.rset), &pwset, NULL, &timeout); + *rc = select(maxfdp1_saved, &(mod_s.rset), &pwset, NULL, &timeout); Thread_lock_mutex(mutex); if (*rc == SOCKET_ERROR) { From 70e08692b9f214a8726a685927db3d8909590c0f Mon Sep 17 00:00:00 2001 From: Locez Date: Wed, 26 Jan 2022 19:52:01 +0800 Subject: [PATCH 32/93] bugfix: fix double free for qos0 publish Signed-off-by: Locez --- src/MQTTAsyncUtils.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/MQTTAsyncUtils.c b/src/MQTTAsyncUtils.c index f57ad051d..6ceb895c6 100644 --- a/src/MQTTAsyncUtils.c +++ b/src/MQTTAsyncUtils.c @@ -1438,7 +1438,10 @@ static int MQTTAsync_processCommand(void) else { if (rc != SOCKET_ERROR) - command->command.details.pub.destinationName = NULL; /* this will be freed by the protocol code */ + { + command->command.details.pub.payload = NULL; /* this will be freed by the protocol code */ + command->command.details.pub.destinationName = NULL; /* this will be freed by the protocol code */ + } command->client->pending_write = &command->command; } } From b79bcf0d402cd62e06e269ed5a4a5b3d83f81af6 Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Thu, 27 Jan 2022 16:41:46 +0000 Subject: [PATCH 33/93] Update out of date mqtt server hostnames --- src/MQTTAsync.h | 8 ++++---- src/MQTTClient.h | 10 +++++----- src/samples/MQTTAsync_publish.c | 4 ++-- src/samples/MQTTAsync_subscribe.c | 4 ++-- src/samples/MQTTClient_publish.c | 4 ++-- src/samples/MQTTClient_publish_async.c | 4 ++-- src/samples/MQTTClient_subscribe.c | 4 ++-- test/test1.c | 6 +++--- test/test2.c | 4 ++-- test/test3.c | 14 +++++++------- test/test4.c | 4 ++-- test/test5.c | 14 +++++++------- test/test9.c | 4 ++-- test/test95.c | 4 ++-- test/test_mqtt4async.c | 4 ++-- test/test_mqtt4sync.c | 4 ++-- test/test_persistence.c | 4 ++-- test/test_sync_session_present.c | 4 ++-- 18 files changed, 52 insertions(+), 52 deletions(-) diff --git a/src/MQTTAsync.h b/src/MQTTAsync.h index 3d7783fa1..7777e50a0 100644 --- a/src/MQTTAsync.h +++ b/src/MQTTAsync.h @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009, 2021 IBM Corp., Ian Craggs and others + * Copyright (c) 2009, 2022 IBM Corp., Ian Craggs and others * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 @@ -29,7 +29,7 @@ * @cond MQTTAsync_main * @mainpage Asynchronous MQTT client library for C * - * © Copyright 2009, 2021 IBM Corp., Ian Craggs and others + * © Copyright 2009, 2022 IBM Corp., Ian Craggs and others * * @brief An Asynchronous MQTT client library for C. * @@ -1888,7 +1888,7 @@ LIBMQTT_API const char* MQTTAsync_strerror(int code); #include #endif -#define ADDRESS "tcp://mqtt.eclipse.org:1883" +#define ADDRESS "tcp://mqtt.eclipseprojects.io:1883" #define CLIENTID "ExampleClientPub" #define TOPIC "MQTT Examples" #define PAYLOAD "Hello World!" @@ -2059,7 +2059,7 @@ int main(int argc, char* argv[]) #include #endif -#define ADDRESS "tcp://mqtt.eclipse.org:1883" +#define ADDRESS "tcp://mqtt.eclipseprojects.io:1883" #define CLIENTID "ExampleClientSub" #define TOPIC "MQTT Examples" #define PAYLOAD "Hello World!" diff --git a/src/MQTTClient.h b/src/MQTTClient.h index c41c0cf51..ebc64be57 100644 --- a/src/MQTTClient.h +++ b/src/MQTTClient.h @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009, 2021 IBM Corp., Ian Craggs and others + * Copyright (c) 2009, 2022 IBM Corp., Ian Craggs and others * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 @@ -41,7 +41,7 @@ * @endcond * @cond MQTTClient_main * @mainpage MQTT Client library for C - * © Copyright 2009, 2021 IBM Corp., Ian Craggs and others + * © Copyright 2009, 2022 IBM Corp., Ian Craggs and others * * @brief An MQTT client library in C. * @@ -1581,7 +1581,7 @@ LIBMQTT_API const char* MQTTClient_strerror(int code); #include #include "MQTTClient.h" -#define ADDRESS "tcp://mqtt.eclipse.org:1883" +#define ADDRESS "tcp://mqtt.eclipseprojects.io:1883" #define CLIENTID "ExampleClientPub" #define TOPIC "MQTT Examples" #define PAYLOAD "Hello World!" @@ -1648,7 +1648,7 @@ int main(int argc, char* argv[]) #include #endif -#define ADDRESS "tcp://mqtt.eclipse.org:1883" +#define ADDRESS "tcp://mqtt.eclipseprojects.io:1883" #define CLIENTID "ExampleClientPub" #define TOPIC "MQTT Examples" #define PAYLOAD "Hello World!" @@ -1757,7 +1757,7 @@ int main(int argc, char* argv[]) #include #include "MQTTClient.h" -#define ADDRESS "tcp://mqtt.eclipse.org:1883" +#define ADDRESS "tcp://mqtt.eclipseprojects.io:1883" #define CLIENTID "ExampleClientSub" #define TOPIC "MQTT Examples" #define PAYLOAD "Hello World!" diff --git a/src/samples/MQTTAsync_publish.c b/src/samples/MQTTAsync_publish.c index 34ee8fc71..b2ac829a3 100644 --- a/src/samples/MQTTAsync_publish.c +++ b/src/samples/MQTTAsync_publish.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2012, 2020 IBM Corp. + * Copyright (c) 2012, 2022 IBM Corp., Ian Craggs * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 @@ -29,7 +29,7 @@ #include #endif -#define ADDRESS "tcp://mqtt.eclipse.org:1883" +#define ADDRESS "tcp://mqtt.eclipseprojects.io:1883" #define CLIENTID "ExampleClientPub" #define TOPIC "MQTT Examples" #define PAYLOAD "Hello World!" diff --git a/src/samples/MQTTAsync_subscribe.c b/src/samples/MQTTAsync_subscribe.c index 6d5b8a716..ae3291164 100644 --- a/src/samples/MQTTAsync_subscribe.c +++ b/src/samples/MQTTAsync_subscribe.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2012, 2021 IBM Corp., Ian Craggs + * Copyright (c) 2012, 2022 IBM Corp., Ian Craggs * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 @@ -29,7 +29,7 @@ #include #endif -#define ADDRESS "tcp://mqtt.eclipse.org:1883" +#define ADDRESS "tcp://mqtt.eclipseprojects.io:1883" #define CLIENTID "ExampleClientSub" #define TOPIC "MQTT Examples" #define PAYLOAD "Hello World!" diff --git a/src/samples/MQTTClient_publish.c b/src/samples/MQTTClient_publish.c index bbe8b497d..399fd339f 100644 --- a/src/samples/MQTTClient_publish.c +++ b/src/samples/MQTTClient_publish.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2012, 2020 IBM Corp. + * Copyright (c) 2012, 2022 IBM Corp., Ian Craggs * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 @@ -19,7 +19,7 @@ #include #include "MQTTClient.h" -#define ADDRESS "tcp://mqtt.eclipse.org:1883" +#define ADDRESS "tcp://mqtt.eclipseprojects.io:1883" #define CLIENTID "ExampleClientPub" #define TOPIC "MQTT Examples" #define PAYLOAD "Hello World!" diff --git a/src/samples/MQTTClient_publish_async.c b/src/samples/MQTTClient_publish_async.c index d376ea5e4..c5685417d 100644 --- a/src/samples/MQTTClient_publish_async.c +++ b/src/samples/MQTTClient_publish_async.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2012, 2020 IBM Corp. + * Copyright (c) 2012, 2022 IBM Corp., Ian Craggs * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 @@ -25,7 +25,7 @@ #include #endif -#define ADDRESS "tcp://mqtt.eclipse.org:1883" +#define ADDRESS "tcp://mqtt.eclipseprojects.io:1883" #define CLIENTID "ExampleClientPub" #define TOPIC "MQTT Examples" #define PAYLOAD "Hello World!" diff --git a/src/samples/MQTTClient_subscribe.c b/src/samples/MQTTClient_subscribe.c index 29f7fa1a1..8a527a390 100644 --- a/src/samples/MQTTClient_subscribe.c +++ b/src/samples/MQTTClient_subscribe.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2012, 2020 IBM Corp. + * Copyright (c) 2012, 2022 IBM Corp., Ian Craggs * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 @@ -19,7 +19,7 @@ #include #include "MQTTClient.h" -#define ADDRESS "tcp://mqtt.eclipse.org:1883" +#define ADDRESS "tcp://mqtt.eclipseprojects.io:1883" #define CLIENTID "ExampleClientSub" #define TOPIC "MQTT Examples" #define PAYLOAD "Hello World!" diff --git a/test/test1.c b/test/test1.c index c1927bf48..4aa07c6e0 100644 --- a/test/test1.c +++ b/test/test1.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009, 2018 IBM Corp. + * Copyright (c) 2009, 2022 IBM Corp., Ian Craggs * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 @@ -56,9 +56,9 @@ struct Options int iterations; } options = { - "tcp://mqtt.eclipse.org:1883", - NULL, "tcp://localhost:1883", + NULL, + "tcp://localhost:1884", 0, 0, 0, diff --git a/test/test2.c b/test/test2.c index a12db24dc..ec970afb9 100644 --- a/test/test2.c +++ b/test/test2.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009, 2020 IBM Corp. and others + * Copyright (c) 2009, 2022 IBM Corp., Ian Craggs and others * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 @@ -55,7 +55,7 @@ struct Options int iterations; } options = { - "tcp://m2m.eclipse.org:1883", + "tcp://localhost:1883", NULL, 0, 0, diff --git a/test/test3.c b/test/test3.c index 6db990f48..4e46d2f48 100644 --- a/test/test3.c +++ b/test/test3.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2012, 2020 IBM Corp. and others + * Copyright (c) 2012, 2022 IBM Corp., Ian Craggs and others * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 @@ -88,12 +88,12 @@ struct Options int websockets; } options = { - "ssl://m2m.eclipse.org:18883", - "ssl://m2m.eclipse.org:18884", - "ssl://m2m.eclipse.org:18887", - "ssl://m2m.eclipse.org:18885", - "ssl://m2m.eclipse.org:18886", - "ssl://m2m.eclipse.org:18888", + "ssl://localhost:18883", + "ssl://localhost:18884", + "ssl://localhost:18887", + "ssl://localhost:18885", + "ssl://localhost:18886", + "ssl://localhost:18888", NULL, 0, "../../../test/ssl/client.pem", diff --git a/test/test4.c b/test/test4.c index beb7e1a5b..00385b901 100644 --- a/test/test4.c +++ b/test/test4.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009, 2020 IBM Corp. + * Copyright (c) 2009, 2022 IBM Corp., Ian Craggs * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 @@ -54,7 +54,7 @@ struct Options int iterations; } options = { - "mqtt.eclipse.org:1883", + "localhost:1883", 0, -1, 10000, diff --git a/test/test5.c b/test/test5.c index 682ad9f34..248133580 100644 --- a/test/test5.c +++ b/test/test5.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2012, 2020 IBM Corp. + * Copyright (c) 2012, 2022 IBM Corp., Ian Craggs * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 @@ -73,12 +73,12 @@ struct Options int start_port; } options = { - "ssl://m2m.eclipse.org:18883", - "ssl://m2m.eclipse.org:18884", - "ssl://m2m.eclipse.org:18887", - "ssl://m2m.eclipse.org:18885", - "ssl://m2m.eclipse.org:18886", - "ssl://m2m.eclipse.org:18888", + "ssl://localhost:18883", + "ssl://localhost:18884", + "ssl://localhost:18887", + "ssl://localhost:18885", + "ssl://localhost:18886", + "ssl://localhost:18888", NULL, // "../../../test/ssl/client.pem", NULL, NULL, // "../../../test/ssl/test-root-ca.crt", diff --git a/test/test9.c b/test/test9.c index 47a3f8c8d..fe9d08f20 100644 --- a/test/test9.c +++ b/test/test9.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2012, 2020 IBM Corp. and others + * Copyright (c) 2012, 2022 IBM Corp., Ian Craggs * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 @@ -56,8 +56,8 @@ struct Options int test_no; } options = { - "mqtt.eclipse.org:1883", "localhost:1883", + "localhost:1884", 0, 0, }; diff --git a/test/test95.c b/test/test95.c index b8ff688c3..8d0b21447 100644 --- a/test/test95.c +++ b/test/test95.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2012, 2020 IBM Corp. and others + * Copyright (c) 2012, 2022 IBM Corp., Ian Craggs * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 @@ -57,8 +57,8 @@ struct Options int test_no; } options = { - "mqtt.eclipse.org:1883", "localhost:1883", + "localhost:1884", 0, 0, }; diff --git a/test/test_mqtt4async.c b/test/test_mqtt4async.c index 2c7e7b3e0..4e7803960 100644 --- a/test/test_mqtt4async.c +++ b/test/test_mqtt4async.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009, 2020 IBM Corp. + * Copyright (c) 2009, 2022 IBM Corp., Ian Craggs * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 @@ -68,7 +68,7 @@ struct Options int iterations; } options = { - "m2m.eclipse.org:1883", + "localhost:1883", NULL, 0, 0, diff --git a/test/test_mqtt4sync.c b/test/test_mqtt4sync.c index 6460925e0..9305af199 100644 --- a/test/test_mqtt4sync.c +++ b/test/test_mqtt4sync.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009, 2020 IBM Corp. + * Copyright (c) 2009, 2022 IBM Corp., Ian Craggs * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 @@ -68,7 +68,7 @@ struct Options int iterations; } options = { - "tcp://m2m.eclipse.org:1883", + "tcp://localhost:1883", NULL, 0, 0, diff --git a/test/test_persistence.c b/test/test_persistence.c index 481768c21..f8d82f696 100644 --- a/test/test_persistence.c +++ b/test/test_persistence.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2012, 2018 IBM Corp. + * Copyright (c) 2012, 2022 IBM Corp., Ian Craggs * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 @@ -57,8 +57,8 @@ struct Options int test_no; } options = { - "mqtt.eclipse.org:1883", "localhost:1883", + "localhost:1884", 0, 0, }; diff --git a/test/test_sync_session_present.c b/test/test_sync_session_present.c index f54773e65..0e7201a7b 100644 --- a/test/test_sync_session_present.c +++ b/test/test_sync_session_present.c @@ -60,9 +60,9 @@ struct Options int reconnect_period; } options = { - "tcp://mqtt.eclipse.org:1883", - NULL, "tcp://localhost:1883", + NULL, + "tcp://localhost:1884", "cli/test", NULL, NULL, From d5b1f6a686abbd286f573d301481c56a3b31bc78 Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Fri, 28 Jan 2022 17:01:58 +0000 Subject: [PATCH 34/93] Add a loop in test15 test 4 to allow more time for protocol exchanges to complete --- test/test15.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/test/test15.c b/test/test15.c index 630d68649..22b80ba57 100644 --- a/test/test15.c +++ b/test/test15.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009, 2020 IBM Corp. + * Copyright (c) 2009, 2022 IBM Corp, Ian Craggs * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 @@ -1020,7 +1020,14 @@ int test4_run(int qos, int start_mqtt_version, int restore_mqtt_version) } } - MQTTClient_yield(); /* allow any unfinished protocol exchanges to finish */ + /* call yield a few times until unfinished protocol exchanges are finished */ + count = 0; + do + { + MQTTClient_yield(); + rc = MQTTClient_getPendingDeliveryTokens(c, &tokens); + assert("getPendingDeliveryTokens rc == 0", rc == MQTTCLIENT_SUCCESS, "rc was %d", rc); + } while (tokens != NULL && ++count < 10); rc = MQTTClient_getPendingDeliveryTokens(c, &tokens); assert("getPendingDeliveryTokens rc == 0", rc == MQTTCLIENT_SUCCESS, "rc was %d", rc); From 40f7862b41f92aba6544b6b0d2e0b96825bc4be0 Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Fri, 28 Jan 2022 19:30:56 +0000 Subject: [PATCH 35/93] Parse websocket URLs with topic and no port properly #1185 --- src/MQTTProtocolOut.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/MQTTProtocolOut.c b/src/MQTTProtocolOut.c index 733a3392a..184ff85b8 100644 --- a/src/MQTTProtocolOut.c +++ b/src/MQTTProtocolOut.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009, 2021 IBM Corp., Ian Craggs + * Copyright (c) 2009, 2022 IBM Corp., Ian Craggs * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 @@ -55,11 +55,14 @@ extern ClientStates* bstate; */ size_t MQTTProtocol_addressPort(const char* uri, int* port, const char **topic, int default_port) { - char* colon_pos = strrchr(uri, ':'); /* reverse find to allow for ':' in IPv6 addresses */ char* buf = (char*)uri; + char* colon_pos; size_t len; + char* topic_pos; FUNC_ENTRY; + colon_pos = strrchr(uri, ':'); /* reverse find to allow for ':' in IPv6 addresses */ + if (uri[0] == '[') { /* ip v6 */ if (colon_pos < strrchr(uri, ']')) @@ -77,13 +80,17 @@ size_t MQTTProtocol_addressPort(const char* uri, int* port, const char **topic, *port = default_port; } - /* try and find topic portion */ - if ( topic ) + /* find any topic portion */ + topic_pos = (char*)uri; + if (colon_pos) + topic_pos = colon_pos; + topic_pos = strchr(topic_pos, '/'); + if (topic_pos) { - const char* addr_start = uri; - if ( colon_pos ) - addr_start = colon_pos; - *topic = strchr( addr_start, '/' ); + if (topic) + *topic = topic_pos; + if (!colon_pos) + len = topic_pos - uri; } if (buf[len - 1] == ']') From 5e6e38947c6136e71e0bae8c06a98629fcf51803 Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Fri, 28 Jan 2022 20:30:19 +0000 Subject: [PATCH 36/93] Set default port for WSS to 443 #1048 --- src/MQTTAsyncUtils.c | 10 +++++----- src/MQTTClient.c | 8 ++++---- src/MQTTProtocolOut.c | 8 +++++--- src/MQTTProtocolOut.h | 3 ++- src/WebSocket.c | 5 +++-- src/WebSocket.h | 4 ++-- 6 files changed, 21 insertions(+), 17 deletions(-) diff --git a/src/MQTTAsyncUtils.c b/src/MQTTAsyncUtils.c index f57ad051d..1a37b5616 100644 --- a/src/MQTTAsyncUtils.c +++ b/src/MQTTAsyncUtils.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009, 2021 IBM Corp., Ian Craggs and others + * Copyright (c) 2009, 2022 IBM Corp., Ian Craggs and others * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 @@ -2719,7 +2719,7 @@ static int MQTTAsync_connecting(MQTTAsyncs* m) else if (strncmp(URI_WSS, serverURI, strlen(URI_WSS)) == 0) { serverURI += strlen(URI_WSS); - default_port = WS_DEFAULT_PORT; + default_port = WSS_DEFAULT_PORT; } #endif } @@ -2779,7 +2779,7 @@ static int MQTTAsync_connecting(MQTTAsyncs* m) if ( m->websocket ) { m->c->connect_state = WEBSOCKET_IN_PROGRESS; - if ((rc = WebSocket_connect(&m->c->net, serverURI)) == SOCKET_ERROR ) + if ((rc = WebSocket_connect(&m->c->net, m->ssl, serverURI)) == SOCKET_ERROR ) goto exit; } else @@ -2815,7 +2815,7 @@ static int MQTTAsync_connecting(MQTTAsyncs* m) if ( m->websocket ) { m->c->connect_state = WEBSOCKET_IN_PROGRESS; - if ((rc = WebSocket_connect(&m->c->net, serverURI)) == SOCKET_ERROR ) + if ((rc = WebSocket_connect(&m->c->net, 0, serverURI)) == SOCKET_ERROR ) goto exit; } else @@ -2846,7 +2846,7 @@ static int MQTTAsync_connecting(MQTTAsyncs* m) if ( m->websocket ) { m->c->connect_state = WEBSOCKET_IN_PROGRESS; - if ((rc = WebSocket_connect(&m->c->net, serverURI)) == SOCKET_ERROR ) + if ((rc = WebSocket_connect(&m->c->net, 1, serverURI)) == SOCKET_ERROR ) goto exit; } else diff --git a/src/MQTTClient.c b/src/MQTTClient.c index 275e075e0..8202c4678 100644 --- a/src/MQTTClient.c +++ b/src/MQTTClient.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009, 2021 IBM Corp., Ian Craggs and others + * Copyright (c) 2009, 2022 IBM Corp., Ian Craggs and others * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 @@ -1267,7 +1267,7 @@ static MQTTResponse MQTTClient_connectURIVersion(MQTTClient handle, MQTTClient_c if (m->websocket) { m->c->connect_state = WEBSOCKET_IN_PROGRESS; - rc = WebSocket_connect(&m->c->net, serverURI); + rc = WebSocket_connect(&m->c->net, 1, serverURI); if ( rc == SOCKET_ERROR ) goto exit; } @@ -1303,7 +1303,7 @@ static MQTTResponse MQTTClient_connectURIVersion(MQTTClient handle, MQTTClient_c if (m->websocket) { m->c->connect_state = WEBSOCKET_IN_PROGRESS; - if ( WebSocket_connect(&m->c->net, serverURI) == SOCKET_ERROR ) + if ( WebSocket_connect(&m->c->net, 0, serverURI) == SOCKET_ERROR ) { rc = SOCKET_ERROR; goto exit; @@ -1339,7 +1339,7 @@ static MQTTResponse MQTTClient_connectURIVersion(MQTTClient handle, MQTTClient_c { /* wait for websocket connect */ m->c->connect_state = WEBSOCKET_IN_PROGRESS; - rc = WebSocket_connect( &m->c->net, serverURI ); + rc = WebSocket_connect( &m->c->net, 1, serverURI); if ( rc != 1 ) { rc = SOCKET_ERROR; diff --git a/src/MQTTProtocolOut.c b/src/MQTTProtocolOut.c index 184ff85b8..1d6aab830 100644 --- a/src/MQTTProtocolOut.c +++ b/src/MQTTProtocolOut.c @@ -285,9 +285,11 @@ int MQTTProtocol_connect(const char* ip_address, Clients* aClient, int websocket #endif else { #if defined(OPENSSL) - addr_len = MQTTProtocol_addressPort(ip_address, &port, NULL, ssl ? SECURE_MQTT_DEFAULT_PORT : MQTT_DEFAULT_PORT); + addr_len = MQTTProtocol_addressPort(ip_address, &port, NULL, ssl ? + (websocket ? WSS_DEFAULT_PORT : SECURE_MQTT_DEFAULT_PORT) : + (websocket ? WS_DEFAULT_PORT : MQTT_DEFAULT_PORT) ); #else - addr_len = MQTTProtocol_addressPort(ip_address, &port, NULL, MQTT_DEFAULT_PORT); + addr_len = MQTTProtocol_addressPort(ip_address, &port, NULL, websocket ? WS_DEFAULT_PORT : MQTT_DEFAULT_PORT); #endif #if defined(__GNUC__) && defined(__linux__) if (timeout < 0) @@ -331,7 +333,7 @@ int MQTTProtocol_connect(const char* ip_address, Clients* aClient, int websocket } if ( websocket ) { - rc = WebSocket_connect( &aClient->net, ip_address ); + rc = WebSocket_connect( &aClient->net, 0, ip_address ); if ( rc == TCPSOCKET_INTERRUPTED ) aClient->connect_state = WEBSOCKET_IN_PROGRESS; /* Websocket connect called - wait for completion */ } diff --git a/src/MQTTProtocolOut.h b/src/MQTTProtocolOut.h index d8f43d73a..784a50947 100644 --- a/src/MQTTProtocolOut.h +++ b/src/MQTTProtocolOut.h @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009, 2021 IBM Corp., Ian Craggs + * Copyright (c) 2009, 2022 IBM Corp., Ian Craggs * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 @@ -33,6 +33,7 @@ #define MQTT_DEFAULT_PORT 1883 #define SECURE_MQTT_DEFAULT_PORT 8883 #define WS_DEFAULT_PORT 80 +#define WSS_DEFAULT_PORT 443 #define PROXY_DEFAULT_PORT 8080 size_t MQTTProtocol_addressPort(const char* uri, int* port, const char **topic, int default_port); diff --git a/src/WebSocket.c b/src/WebSocket.c index 42671d4cf..25b1eecdf 100644 --- a/src/WebSocket.c +++ b/src/WebSocket.c @@ -369,6 +369,7 @@ static void WebSocket_unmaskData(size_t idx, PacketBuffers* bufs) * sends out a websocket request on the given uri * * @param[in] net network connection + * @param[in] ssl ssl flag * @param[in] uri uri to connect to * * @retval SOCKET_ERROR on failure @@ -376,7 +377,7 @@ static void WebSocket_unmaskData(size_t idx, PacketBuffers* bufs) * * @see WebSocket_upgrade */ -int WebSocket_connect( networkHandles *net, const char *uri) +int WebSocket_connect( networkHandles *net, int ssl, const char *uri) { int rc; char *buf = NULL; @@ -413,7 +414,7 @@ int WebSocket_connect( networkHandles *net, const char *uri) Base64_encode( net->websocket_key, 25u, uuid, sizeof(uuid_t) ); #endif /* else if defined(_WIN32) || defined(_WIN64) */ - hostname_len = MQTTProtocol_addressPort(uri, &port, &topic, WS_DEFAULT_PORT); + hostname_len = MQTTProtocol_addressPort(uri, &port, &topic, ssl ? WSS_DEFAULT_PORT : WS_DEFAULT_PORT); /* if no topic, use default */ if ( !topic ) diff --git a/src/WebSocket.h b/src/WebSocket.h index 1183c9691..4e437d4af 100644 --- a/src/WebSocket.h +++ b/src/WebSocket.h @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2018, 2020 Wind River Systems, Inc. and others. All Rights Reserved. + * Copyright (c) 2018, 2022 Wind River Systems, Inc. and others. All Rights Reserved. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 @@ -55,7 +55,7 @@ void WebSocket_close(networkHandles *net, int status_code, const char *reason); /* sends upgrade request */ -int WebSocket_connect(networkHandles *net, const char *uri); +int WebSocket_connect(networkHandles *net, int ssl, const char *uri); /* obtain data from network socket */ int WebSocket_getch(networkHandles *net, char* c); From efc5706f57944efbaba48f5a33e9dc20f314fd53 Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Fri, 28 Jan 2022 23:10:50 +0000 Subject: [PATCH 37/93] Set default port for WSS to 443 #1048 --- src/MQTTProtocolOut.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/MQTTProtocolOut.c b/src/MQTTProtocolOut.c index 1d6aab830..25ca0a18a 100644 --- a/src/MQTTProtocolOut.c +++ b/src/MQTTProtocolOut.c @@ -333,7 +333,10 @@ int MQTTProtocol_connect(const char* ip_address, Clients* aClient, int websocket } if ( websocket ) { - rc = WebSocket_connect( &aClient->net, 0, ip_address ); +#if defined(OPENSSL) + rc = WebSocket_connect(&aClient->net, ssl, ip_address); +#endif + rc = WebSocket_connect(&aClient->net, 0, ip_address); if ( rc == TCPSOCKET_INTERRUPTED ) aClient->connect_state = WEBSOCKET_IN_PROGRESS; /* Websocket connect called - wait for completion */ } From d03b3ba6a10e50fa146080ea436bd39aaa791aea Mon Sep 17 00:00:00 2001 From: Daniel Starikov Date: Thu, 6 Jan 2022 19:21:26 -0800 Subject: [PATCH 38/93] Fix for issue #1190 use-after-free when discarding the oldest message with persistence --- src/MQTTAsyncUtils.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/MQTTAsyncUtils.c b/src/MQTTAsyncUtils.c index 1a37b5616..a7dc35e08 100644 --- a/src/MQTTAsyncUtils.c +++ b/src/MQTTAsyncUtils.c @@ -889,11 +889,12 @@ int MQTTAsync_addCommand(MQTTAsync_queuedCommand* command, int command_size) { ListDetach(MQTTAsync_commands, first_publish); - MQTTAsync_freeCommand(first_publish); #if !defined(NO_PERSISTENCE) if (command->client->c->persistence) MQTTAsync_unpersistCommand(first_publish); #endif + + MQTTAsync_freeCommand(first_publish); } } else From a43528ba96cb66cd5ad510f65d3bde19398f02e0 Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Fri, 4 Feb 2022 17:23:56 +0000 Subject: [PATCH 39/93] Use poll instead of select #1033 --- src/Clients.c | 2 +- src/Clients.h | 7 +- src/Keysight_ws_add | 22 +++ src/MQTTAsync.c | 4 +- src/MQTTAsyncUtils.c | 26 ++-- src/MQTTAsyncUtils.h | 4 +- src/MQTTClient.c | 35 +++-- src/MQTTPersistence.c | 4 +- src/MQTTPersistence.h | 4 +- src/MQTTProtocol.h | 4 +- src/MQTTProtocolClient.c | 14 +- src/MQTTProtocolClient.h | 14 +- src/MQTTProtocolOut.c | 15 +- src/MQTTProtocolOut.h | 10 +- src/SSLSocket.c | 32 +++-- src/SSLSocket.h | 12 +- src/Socket.c | 303 ++++++++++++++++++++------------------- src/Socket.h | 46 +++--- src/SocketBuffer.c | 24 ++-- src/SocketBuffer.h | 35 +++-- test/test1.c | 9 +- 21 files changed, 331 insertions(+), 295 deletions(-) create mode 100644 src/Keysight_ws_add diff --git a/src/Clients.c b/src/Clients.c index 585257d2c..b22bf8340 100644 --- a/src/Clients.c +++ b/src/Clients.c @@ -51,5 +51,5 @@ int clientSocketCompare(void* a, void* b) { Clients* client = (Clients*)a; /*printf("comparing %d with %d\n", (char*)a, (char*)b); */ - return client->net.socket == *(int*)b; + return client->net.socket == *(SOCKET*)b; } diff --git a/src/Clients.h b/src/Clients.h index ae4306e1b..de2f52159 100644 --- a/src/Clients.h +++ b/src/Clients.h @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009, 2021 IBM Corp. and Ian Craggs + * Copyright (c) 2009, 2022 IBM Corp. and Ian Craggs * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 @@ -24,15 +24,16 @@ #include #include "MQTTTime.h" -#if defined(OPENSSL) #if defined(_WIN32) || defined(_WIN64) #include #endif +#if defined(OPENSSL) #include #endif #include "MQTTClient.h" #include "LinkedList.h" #include "MQTTClientPersistence.h" +#include "Socket.h" /** * Stored publication data to minimize copying @@ -77,7 +78,7 @@ typedef struct typedef struct { - int socket; + SOCKET socket; START_TIME_TYPE lastSent; START_TIME_TYPE lastReceived; START_TIME_TYPE lastPing; diff --git a/src/Keysight_ws_add b/src/Keysight_ws_add new file mode 100644 index 000000000..f6103546a --- /dev/null +++ b/src/Keysight_ws_add @@ -0,0 +1,22 @@ +#if WINVER <= _WIN32_WINNT_WIN8 +#define HTON(x) hton((uint64_t) (x), sizeof(x)) +uint64_t hton(uint64_t x, size_t n) +{ + uint64_t y = 0; + size_t i = 0; + + for (i=0; i < n; ++i) + { + y = (y << 8) | (x & 0xff); + x = (x >> 8); + } + return y; +} +#define htons(x) (uint16_t) HTON(x) +#define htonl(x) (uint32_t) HTON(x) +#define htonll(x) (uint64_t) HTON(x) + +#define ntohs(x) htons(x) +#define ntohl(x) htonl(x) +#define ntohll(x) htonll(x) +#endif diff --git a/src/MQTTAsync.c b/src/MQTTAsync.c index d6fb2181b..0437e28e7 100644 --- a/src/MQTTAsync.c +++ b/src/MQTTAsync.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009, 2021 IBM Corp., Ian Craggs and others + * Copyright (c) 2009, 2022 IBM Corp., Ian Craggs and others * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 @@ -486,7 +486,7 @@ void MQTTAsync_destroy(MQTTAsync* handle) if (m->c) { - int saved_socket = m->c->net.socket; + SOCKET saved_socket = m->c->net.socket; char* saved_clientid = MQTTStrdup(m->c->clientID); #if !defined(NO_PERSISTENCE) MQTTPersistence_close(m->c); diff --git a/src/MQTTAsyncUtils.c b/src/MQTTAsyncUtils.c index 1a37b5616..3c5076510 100644 --- a/src/MQTTAsyncUtils.c +++ b/src/MQTTAsyncUtils.c @@ -60,7 +60,7 @@ static int MQTTAsync_deliverMessage(MQTTAsyncs* m, char* topicName, size_t topic static int MQTTAsync_disconnect_internal(MQTTAsync handle, int timeout); static int cmdMessageIDCompare(void* a, void* b); static void MQTTAsync_retry(void); -static MQTTPacket* MQTTAsync_cycle(int* sock, unsigned long timeout, int* rc); +static MQTTPacket* MQTTAsync_cycle(SOCKET* sock, unsigned long timeout, int* rc); static int MQTTAsync_connecting(MQTTAsyncs* m); extern MQTTProtocol state; /* defined in MQTTAsync.c */ @@ -889,11 +889,12 @@ int MQTTAsync_addCommand(MQTTAsync_queuedCommand* command, int command_size) { ListDetach(MQTTAsync_commands, first_publish); - MQTTAsync_freeCommand(first_publish); #if !defined(NO_PERSISTENCE) if (command->client->c->persistence) MQTTAsync_unpersistCommand(first_publish); #endif + + MQTTAsync_freeCommand(first_publish); } } else @@ -976,7 +977,7 @@ void MQTTAsync_checkDisconnect(MQTTAsync handle, MQTTAsync_command* command) /** * Call Socket_noPendingWrites(int socket) with protection by socket_mutex, see https://github.com/eclipse/paho.mqtt.c/issues/385 */ -static int MQTTAsync_Socket_noPendingWrites(int socket) +static int MQTTAsync_Socket_noPendingWrites(SOCKET socket) { int rc; MQTTAsync_lock_mutex(socket_mutex); @@ -1059,7 +1060,7 @@ static void MQTTAsync_freeCommand(MQTTAsync_queuedCommand *command) } -void MQTTAsync_writeComplete(int socket, int rc) +void MQTTAsync_writeComplete(SOCKET socket, int rc) { ListElement* found = NULL; @@ -1976,7 +1977,7 @@ thread_return_type WINAPI MQTTAsync_receiveThread(void* n) while (!MQTTAsync_tostop) { int rc = SOCKET_ERROR; - int sock = -1; + SOCKET sock = -1; MQTTAsyncs* m = NULL; MQTTPacket* pack = NULL; @@ -2879,19 +2880,12 @@ static int MQTTAsync_connecting(MQTTAsyncs* m) } -static MQTTPacket* MQTTAsync_cycle(int* sock, unsigned long timeout, int* rc) +static MQTTPacket* MQTTAsync_cycle(SOCKET* sock, unsigned long timeout, int* rc) { - struct timeval tp = {0L, 0L}; MQTTPacket* pack = NULL; + int rc1 = 0; FUNC_ENTRY; - if (timeout > 0L) - { - tp.tv_sec = timeout / 1000; - tp.tv_usec = (timeout % 1000) * 1000; /* this field is microseconds! */ - } - - int rc1 = 0; #if defined(OPENSSL) if ((*sock = SSLSocket_getPendingRead()) == -1) { @@ -2899,12 +2893,12 @@ static MQTTPacket* MQTTAsync_cycle(int* sock, unsigned long timeout, int* rc) int should_stop = 0; /* 0 from getReadySocket indicates no work to do, rc -1 == error */ - *sock = Socket_getReadySocket(0, &tp, socket_mutex, &rc1); + *sock = Socket_getReadySocket(0, (int)timeout, socket_mutex, &rc1); *rc = rc1; MQTTAsync_lock_mutex(mqttasync_mutex); should_stop = MQTTAsync_tostop; MQTTAsync_unlock_mutex(mqttasync_mutex); - if (!should_stop && *sock == 0 && (tp.tv_sec > 0L || tp.tv_usec > 0L)) + if (!should_stop && *sock == 0 && (timeout > 0L)) MQTTAsync_sleep(100L); #if defined(OPENSSL) } diff --git a/src/MQTTAsyncUtils.h b/src/MQTTAsyncUtils.h index 42a3145b4..f65980e3b 100644 --- a/src/MQTTAsyncUtils.h +++ b/src/MQTTAsyncUtils.h @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009, 2020 IBM Corp. and others + * Copyright (c) 2009, 2022 IBM Corp. and others * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 @@ -169,7 +169,7 @@ void MQTTAsync_closeSession(Clients* client, enum MQTTReasonCodes reasonCode, MQ int MQTTAsync_disconnect1(MQTTAsync handle, const MQTTAsync_disconnectOptions* options, int internal); int MQTTAsync_assignMsgId(MQTTAsyncs* m); int MQTTAsync_getNoBufferedMessages(MQTTAsyncs* m); -void MQTTAsync_writeComplete(int socket, int rc); +void MQTTAsync_writeComplete(SOCKET socket, int rc); void setRetryLoopInterval(int keepalive); #if defined(_WIN32) || defined(_WIN64) diff --git a/src/MQTTClient.c b/src/MQTTClient.c index 8202c4678..7cba42b92 100644 --- a/src/MQTTClient.c +++ b/src/MQTTClient.c @@ -361,11 +361,11 @@ static MQTTResponse MQTTClient_connectURI(MQTTClient handle, MQTTClient_connectO static int MQTTClient_disconnect1(MQTTClient handle, int timeout, int internal, int stop, enum MQTTReasonCodes, MQTTProperties*); static int MQTTClient_disconnect_internal(MQTTClient handle, int timeout); static void MQTTClient_retry(void); -static MQTTPacket* MQTTClient_cycle(int* sock, ELAPSED_TIME_TYPE timeout, int* rc); +static MQTTPacket* MQTTClient_cycle(SOCKET* sock, ELAPSED_TIME_TYPE timeout, int* rc); static MQTTPacket* MQTTClient_waitfor(MQTTClient handle, int packet_type, int* rc, int64_t timeout); /*static int pubCompare(void* a, void* b); */ static void MQTTProtocol_checkPendingWrites(void); -static void MQTTClient_writeComplete(int socket, int rc); +static void MQTTClient_writeComplete(SOCKET socket, int rc); int MQTTClient_createWithOptions(MQTTClient* handle, const char* serverURI, const char* clientId, @@ -576,7 +576,7 @@ void MQTTClient_destroy(MQTTClient* handle) if (m->c) { - int saved_socket = m->c->net.socket; + SOCKET saved_socket = m->c->net.socket; char* saved_clientid = MQTTStrdup(m->c->clientID); #if !defined(NO_PERSISTENCE) MQTTPersistence_close(m->c); @@ -807,7 +807,7 @@ static thread_return_type WINAPI MQTTClient_run(void* n) while (!tostop) { int rc = SOCKET_ERROR; - int sock = -1; + SOCKET sock = -1; MQTTClients* m = NULL; MQTTPacket* pack = NULL; @@ -2484,27 +2484,24 @@ static void MQTTClient_retry(void) } -static MQTTPacket* MQTTClient_cycle(int* sock, ELAPSED_TIME_TYPE timeout, int* rc) +static MQTTPacket* MQTTClient_cycle(SOCKET* sock, ELAPSED_TIME_TYPE timeout, int* rc) { - struct timeval tp = {0L, 0L}; static Ack ack; MQTTPacket* pack = NULL; + int rc1 = 0; + START_TIME_TYPE start; FUNC_ENTRY; - if (timeout > 0L) - { - tp.tv_sec = (long)(timeout / 1000); - tp.tv_usec = (long)((timeout % 1000) * 1000); /* this field is microseconds! */ - } - - int rc1 = 0; #if defined(OPENSSL) if ((*sock = SSLSocket_getPendingRead()) == -1) { /* 0 from getReadySocket indicates no work to do, rc -1 == error */ #endif - *sock = Socket_getReadySocket(0, &tp, socket_mutex, rc); + start = MQTTTime_start_clock(); + *sock = Socket_getReadySocket(0, (int)timeout, socket_mutex, rc); *rc = rc1; + if (*sock == 0 && timeout >= 100L && MQTTTime_elapsed(start) < (int64_t)10) + MQTTTime_sleep(100L); #if defined(OPENSSL) } #endif @@ -2618,7 +2615,7 @@ static MQTTPacket* MQTTClient_waitfor(MQTTClient handle, int packet_type, int* r *rc = TCPSOCKET_COMPLETE; while (1) { - int sock = -1; + SOCKET sock = -1; pack = MQTTClient_cycle(&sock, 100L, rc); if (sock == m->c->net.socket) { @@ -2678,7 +2675,7 @@ static MQTTPacket* MQTTClient_waitfor(MQTTClient handle, int packet_type, int* r } } } - if (MQTTTime_elapsed(start) > (int64_t)timeout) + if (MQTTTime_elapsed(start) > (uint64_t)timeout) { pack = NULL; break; @@ -2723,7 +2720,7 @@ int MQTTClient_receive(MQTTClient handle, char** topicName, int* topicLen, MQTTC elapsed = MQTTTime_elapsed(start); do { - int sock = 0; + SOCKET sock = 0; MQTTClient_cycle(&sock, (timeout > elapsed) ? timeout - elapsed : 0L, &rc); if (rc == SOCKET_ERROR) @@ -2765,7 +2762,7 @@ void MQTTClient_yield(void) elapsed = MQTTTime_elapsed(start); do { - int sock = -1; + SOCKET sock = -1; MQTTClient_cycle(&sock, (timeout > elapsed) ? timeout - elapsed : 0L, &rc); Thread_lock_mutex(mqttclient_mutex); if (rc == SOCKET_ERROR && ListFindItem(handles, &sock, clientSockCompare)) @@ -3012,7 +3009,7 @@ static void MQTTProtocol_checkPendingWrites(void) } -static void MQTTClient_writeComplete(int socket, int rc) +static void MQTTClient_writeComplete(SOCKET socket, int rc) { ListElement* found = NULL; diff --git a/src/MQTTPersistence.c b/src/MQTTPersistence.c index c5634ded4..7c156245b 100644 --- a/src/MQTTPersistence.c +++ b/src/MQTTPersistence.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009, 2020 IBM Corp. + * Copyright (c) 2009, 2022 IBM Corp. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 @@ -431,7 +431,7 @@ void MQTTPersistence_insertInOrder(List* list, void* content, size_t size) * @param the MQTT version being used (>= MQTTVERSION_5 means properties included) * @return 0 if success, #MQTTCLIENT_PERSISTENCE_ERROR otherwise. */ -int MQTTPersistence_putPacket(int socket, char* buf0, size_t buf0len, int count, +int MQTTPersistence_putPacket(SOCKET socket, char* buf0, size_t buf0len, int count, char** buffers, size_t* buflens, int htype, int msgId, int scr, int MQTTVersion) { int rc = 0; diff --git a/src/MQTTPersistence.h b/src/MQTTPersistence.h index e48111618..3c62a79c5 100644 --- a/src/MQTTPersistence.h +++ b/src/MQTTPersistence.h @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009, 2020 IBM Corp. + * Copyright (c) 2009, 2022 IBM Corp. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 @@ -63,7 +63,7 @@ int MQTTPersistence_clear(Clients* c); int MQTTPersistence_restorePackets(Clients* c); void* MQTTPersistence_restorePacket(int MQTTVersion, char* buffer, size_t buflen); void MQTTPersistence_insertInOrder(List* list, void* content, size_t size); -int MQTTPersistence_putPacket(int socket, char* buf0, size_t buf0len, int count, +int MQTTPersistence_putPacket(SOCKET socket, char* buf0, size_t buf0len, int count, char** buffers, size_t* buflens, int htype, int msgId, int scr, int MQTTVersion); int MQTTPersistence_remove(Clients* c, char* type, int qos, int msgId); void MQTTPersistence_wrapMsgID(Clients *c); diff --git a/src/MQTTProtocol.h b/src/MQTTProtocol.h index 52bcd159d..3bb816d82 100644 --- a/src/MQTTProtocol.h +++ b/src/MQTTProtocol.h @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009, 2014 IBM Corp. + * Copyright (c) 2009, 2022 IBM Corp., Ian Craggs * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 @@ -27,7 +27,7 @@ typedef struct { - int socket; + SOCKET socket; Publications* p; } pending_write; diff --git a/src/MQTTProtocolClient.c b/src/MQTTProtocolClient.c index b467d3914..3e834ecbd 100644 --- a/src/MQTTProtocolClient.c +++ b/src/MQTTProtocolClient.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009, 2021 IBM Corp. and Ian Craggs + * Copyright (c) 2009, 2022 IBM Corp. and Ian Craggs * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 @@ -314,7 +314,7 @@ void MQTTProtocol_removePublication(Publications* p) * @param sock the socket on which the packet was received * @return completion code */ -int MQTTProtocol_handlePublishes(void* pack, int sock) +int MQTTProtocol_handlePublishes(void* pack, SOCKET sock) { Publish* publish = (Publish*)pack; Clients* client = NULL; @@ -431,7 +431,7 @@ int MQTTProtocol_handlePublishes(void* pack, int sock) * @param sock the socket on which the packet was received * @return completion code */ -int MQTTProtocol_handlePubacks(void* pack, int sock) +int MQTTProtocol_handlePubacks(void* pack, SOCKET sock) { Puback* puback = (Puback*)pack; Clients* client = NULL; @@ -477,7 +477,7 @@ int MQTTProtocol_handlePubacks(void* pack, int sock) * @param sock the socket on which the packet was received * @return completion code */ -int MQTTProtocol_handlePubrecs(void* pack, int sock) +int MQTTProtocol_handlePubrecs(void* pack, SOCKET sock) { Pubrec* pubrec = (Pubrec*)pack; Clients* client = NULL; @@ -546,7 +546,7 @@ int MQTTProtocol_handlePubrecs(void* pack, int sock) * @param sock the socket on which the packet was received * @return completion code */ -int MQTTProtocol_handlePubrels(void* pack, int sock) +int MQTTProtocol_handlePubrels(void* pack, SOCKET sock) { Pubrel* pubrel = (Pubrel*)pack; Clients* client = NULL; @@ -629,7 +629,7 @@ int MQTTProtocol_handlePubrels(void* pack, int sock) * @param sock the socket on which the packet was received * @return completion code */ -int MQTTProtocol_handlePubcomps(void* pack, int sock) +int MQTTProtocol_handlePubcomps(void* pack, SOCKET sock) { Pubcomp* pubcomp = (Pubcomp*)pack; Clients* client = NULL; @@ -980,7 +980,7 @@ void MQTTProtocol_freeMessageList(List* msgList) * occur here are ignored. * @param socket the socket that is available for writing */ -void MQTTProtocol_writeAvailable(int socket) +void MQTTProtocol_writeAvailable(SOCKET socket) { Clients* client = NULL; ListElement* current = NULL; diff --git a/src/MQTTProtocolClient.h b/src/MQTTProtocolClient.h index 093711dff..b9b22a4eb 100644 --- a/src/MQTTProtocolClient.h +++ b/src/MQTTProtocolClient.h @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009, 2020 IBM Corp. + * Copyright (c) 2009, 2022 IBM Corp. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 @@ -39,11 +39,11 @@ int MQTTProtocol_assignMsgId(Clients* client); void MQTTProtocol_removePublication(Publications* p); void Protocol_processPublication(Publish* publish, Clients* client, int allocatePayload); -int MQTTProtocol_handlePublishes(void* pack, int sock); -int MQTTProtocol_handlePubacks(void* pack, int sock); -int MQTTProtocol_handlePubrecs(void* pack, int sock); -int MQTTProtocol_handlePubrels(void* pack, int sock); -int MQTTProtocol_handlePubcomps(void* pack, int sock); +int MQTTProtocol_handlePublishes(void* pack, SOCKET sock); +int MQTTProtocol_handlePubacks(void* pack, SOCKET sock); +int MQTTProtocol_handlePubrecs(void* pack, SOCKET sock); +int MQTTProtocol_handlePubrels(void* pack, SOCKET sock); +int MQTTProtocol_handlePubcomps(void* pack, SOCKET sock); void MQTTProtocol_closeSession(Clients* c, int sendwill); void MQTTProtocol_keepalive(START_TIME_TYPE); @@ -55,7 +55,7 @@ void MQTTProtocol_freeMessageList(List* msgList); char* MQTTStrncpy(char *dest, const char* src, size_t num); char* MQTTStrdup(const char* src); -void MQTTProtocol_writeAvailable(int socket); +void MQTTProtocol_writeAvailable(SOCKET socket); //#define MQTTStrdup(src) MQTTStrncpy(malloc(strlen(src)+1), src, strlen(src)+1) diff --git a/src/MQTTProtocolOut.c b/src/MQTTProtocolOut.c index 1d6aab830..c588819ed 100644 --- a/src/MQTTProtocolOut.c +++ b/src/MQTTProtocolOut.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009, 2022 IBM Corp., Ian Craggs + * Copyright (c) 2009, 2022 IBM Corp., Ian Craggs and others * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 @@ -333,7 +333,10 @@ int MQTTProtocol_connect(const char* ip_address, Clients* aClient, int websocket } if ( websocket ) { - rc = WebSocket_connect( &aClient->net, 0, ip_address ); +#if defined(OPENSSL) + rc = WebSocket_connect(&aClient->net, ssl, ip_address); +#endif + rc = WebSocket_connect(&aClient->net, 0, ip_address); if ( rc == TCPSOCKET_INTERRUPTED ) aClient->connect_state = WEBSOCKET_IN_PROGRESS; /* Websocket connect called - wait for completion */ } @@ -359,7 +362,7 @@ int MQTTProtocol_connect(const char* ip_address, Clients* aClient, int websocket * @param sock the socket on which the packet was received * @return completion code */ -int MQTTProtocol_handlePingresps(void* pack, int sock) +int MQTTProtocol_handlePingresps(void* pack, SOCKET sock) { Clients* client = NULL; int rc = TCPSOCKET_COMPLETE; @@ -400,7 +403,7 @@ int MQTTProtocol_subscribe(Clients* client, List* topics, List* qoss, int msgID, * @param sock the socket on which the packet was received * @return completion code */ -int MQTTProtocol_handleSubacks(void* pack, int sock) +int MQTTProtocol_handleSubacks(void* pack, SOCKET sock) { Suback* suback = (Suback*)pack; Clients* client = NULL; @@ -438,7 +441,7 @@ int MQTTProtocol_unsubscribe(Clients* client, List* topics, int msgID, MQTTPrope * @param sock the socket on which the packet was received * @return completion code */ -int MQTTProtocol_handleUnsubacks(void* pack, int sock) +int MQTTProtocol_handleUnsubacks(void* pack, SOCKET sock) { Unsuback* unsuback = (Unsuback*)pack; Clients* client = NULL; @@ -459,7 +462,7 @@ int MQTTProtocol_handleUnsubacks(void* pack, int sock) * @param sock the socket on which the packet was received * @return completion code */ -int MQTTProtocol_handleDisconnects(void* pack, int sock) +int MQTTProtocol_handleDisconnects(void* pack, SOCKET sock) { Ack* disconnect = (Ack*)pack; Clients* client = NULL; diff --git a/src/MQTTProtocolOut.h b/src/MQTTProtocolOut.h index 784a50947..adc95abfd 100644 --- a/src/MQTTProtocolOut.h +++ b/src/MQTTProtocolOut.h @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009, 2022 IBM Corp., Ian Craggs + * Copyright (c) 2009, 2022 IBM Corp., Ian Craggs, and others * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 @@ -55,12 +55,12 @@ int MQTTProtocol_connect(const char* ip_address, Clients* acClients, int websock MQTTProperties* connectProperties, MQTTProperties* willProperties); #endif #endif -int MQTTProtocol_handlePingresps(void* pack, int sock); +int MQTTProtocol_handlePingresps(void* pack, SOCKET sock); int MQTTProtocol_subscribe(Clients* client, List* topics, List* qoss, int msgID, MQTTSubscribe_options* opts, MQTTProperties* props); -int MQTTProtocol_handleSubacks(void* pack, int sock); +int MQTTProtocol_handleSubacks(void* pack, SOCKET sock); int MQTTProtocol_unsubscribe(Clients* client, List* topics, int msgID, MQTTProperties* props); -int MQTTProtocol_handleUnsubacks(void* pack, int sock); -int MQTTProtocol_handleDisconnects(void* pack, int sock); +int MQTTProtocol_handleUnsubacks(void* pack, SOCKET sock); +int MQTTProtocol_handleDisconnects(void* pack, SOCKET sock); #endif diff --git a/src/SSLSocket.c b/src/SSLSocket.c index a303d370a..ade31e11d 100644 --- a/src/SSLSocket.c +++ b/src/SSLSocket.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009, 2020 IBM Corp. + * Copyright (c) 2009, 2022 IBM Corp., Ian Craggs * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 @@ -46,7 +46,7 @@ extern Sockets mod_s; -static int SSLSocket_error(char* aString, SSL* ssl, int sock, int rc, int (*cb)(const char *str, size_t len, void *u), void* u); +static int SSLSocket_error(char* aString, SSL* ssl, SOCKET sock, int rc, int (*cb)(const char *str, size_t len, void *u), void* u); char* SSL_get_verify_result_string(int rc); void SSL_CTX_info_callback(const SSL* ssl, int where, int ret); char* SSLSocket_get_version_string(int version); @@ -69,7 +69,7 @@ extern unsigned long SSLThread_id(void); extern void SSLLocks_callback(int mode, int n, const char *file, int line); int SSLSocket_createContext(networkHandles* net, MQTTClient_SSLOptions* opts); void SSLSocket_destroyContext(networkHandles* net); -void SSLSocket_addPendingRead(int sock); +void SSLSocket_addPendingRead(SOCKET sock); /* 1 ~ we are responsible for initializing openssl; 0 ~ openssl init is done externally */ static int handle_openssl_init = 1; @@ -94,7 +94,7 @@ static int tls_ex_index_ssl_opts; * @param u context to be passed as second argument to ERR_print_errors_cb * @return the specific TCP error code */ -static int SSLSocket_error(char* aString, SSL* ssl, int sock, int rc, int (*cb)(const char *str, size_t len, void *u), void* u) +static int SSLSocket_error(char* aString, SSL* ssl, SOCKET sock, int rc, int (*cb)(const char *str, size_t len, void *u), void* u) { int error; @@ -593,6 +593,8 @@ int SSLSocket_createContext(networkHandles* net, MQTTClient_SSLOptions* opts) } } + SSL_CTX_set_security_level(net->ctx, 1); + if (opts->keyStore) { if ((rc = SSL_CTX_use_certificate_chain_file(net->ctx, opts->keyStore)) != 1) @@ -728,7 +730,7 @@ int SSLSocket_setSocketForSSL(networkHandles* net, MQTTClient_SSLOptions* opts, break; Log(TRACE_PROTOCOL, 1, "SSL cipher available: %d:%s", i, cipher); } - if ((rc = SSL_set_fd(net->ssl, net->socket)) != 1) { + if ((rc = (int)SSL_set_fd(net->ssl, (int)net->socket)) != 1) { if (opts->struct_version >= 3) SSLSocket_error("SSL_set_fd", net->ssl, net->socket, rc, opts->ssl_error_cb, opts->ssl_error_context); else @@ -757,7 +759,7 @@ int SSLSocket_setSocketForSSL(networkHandles* net, MQTTClient_SSLOptions* opts, /* * Return value: 1 - success, TCPSOCKET_INTERRUPTED - try again, anything else is failure */ -int SSLSocket_connect(SSL* ssl, int sock, const char* hostname, int verify, int (*cb)(const char *str, size_t len, void *u), void* u) +int SSLSocket_connect(SSL* ssl, SOCKET sock, const char* hostname, int verify, int (*cb)(const char *str, size_t len, void *u), void* u) { int rc = 0; @@ -831,7 +833,7 @@ int SSLSocket_connect(SSL* ssl, int sock, const char* hostname, int verify, int * @param c the character read, returned * @return completion code */ -int SSLSocket_getch(SSL* ssl, int socket, char* c) +int SSLSocket_getch(SSL* ssl, SOCKET socket, char* c) { int rc = SOCKET_ERROR; @@ -871,7 +873,7 @@ int SSLSocket_getch(SSL* ssl, int socket, char* c) * @param actual_len the actual number of bytes read * @return completion code */ -char *SSLSocket_getdata(SSL* ssl, int socket, size_t bytes, size_t* actual_len, int* rc) +char *SSLSocket_getdata(SSL* ssl, SOCKET socket, size_t bytes, size_t* actual_len, int* rc) { char* buf; @@ -956,7 +958,7 @@ int SSLSocket_close(networkHandles* net) /* No SSL_writev() provided by OpenSSL. Boo. */ -int SSLSocket_putdatas(SSL* ssl, int socket, char* buf0, size_t buf0len, PacketBuffers bufs) +int SSLSocket_putdatas(SSL* ssl, SOCKET socket, char* buf0, size_t buf0len, PacketBuffers bufs) { int rc = 0; int i; @@ -996,7 +998,7 @@ int SSLSocket_putdatas(SSL* ssl, int socket, char* buf0, size_t buf0len, PacketB if (sslerror == SSL_ERROR_WANT_WRITE) { - int* sockmem = (int*)malloc(sizeof(int)); + SOCKET* sockmem = (SOCKET*)malloc(sizeof(SOCKET)); int free = 1; if (!sockmem) @@ -1010,7 +1012,7 @@ int SSLSocket_putdatas(SSL* ssl, int socket, char* buf0, size_t buf0len, PacketB SocketBuffer_pendingWrite(socket, ssl, 1, &iovec, &free, iovec.iov_len, 0); *sockmem = socket; ListAppend(mod_s.write_pending, sockmem, sizeof(int)); - FD_SET(socket, &(mod_s.pending_wset)); + //FD_SET(socket, &(mod_s.pending_wset)); rc = TCPSOCKET_INTERRUPTED; } else @@ -1039,12 +1041,12 @@ int SSLSocket_putdatas(SSL* ssl, int socket, char* buf0, size_t buf0len, PacketB } -void SSLSocket_addPendingRead(int sock) +void SSLSocket_addPendingRead(SOCKET sock) { FUNC_ENTRY; if (ListFindItem(&pending_reads, &sock, intcompare) == NULL) /* make sure we don't add the same socket twice */ { - int* psock = (int*)malloc(sizeof(sock)); + SOCKET* psock = (SOCKET*)malloc(sizeof(SOCKET)); if (psock) { *psock = sock; @@ -1058,9 +1060,9 @@ void SSLSocket_addPendingRead(int sock) } -int SSLSocket_getPendingRead(void) +SOCKET SSLSocket_getPendingRead(void) { - int sock = -1; + SOCKET sock = -1; if (pending_reads.count > 0) { diff --git a/src/SSLSocket.h b/src/SSLSocket.h index 86273c8e2..7234b9642 100644 --- a/src/SSLSocket.h +++ b/src/SSLSocket.h @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009, 2020 IBM Corp. + * Copyright (c) 2009, 2022 IBM Corp., Ian Craggs * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 @@ -39,14 +39,14 @@ int SSLSocket_initialize(void); void SSLSocket_terminate(void); int SSLSocket_setSocketForSSL(networkHandles* net, MQTTClient_SSLOptions* opts, const char* hostname, size_t hostname_len); -int SSLSocket_getch(SSL* ssl, int socket, char* c); -char *SSLSocket_getdata(SSL* ssl, int socket, size_t bytes, size_t* actual_len, int* rc); +int SSLSocket_getch(SSL* ssl, SOCKET socket, char* c); +char *SSLSocket_getdata(SSL* ssl, SOCKET socket, size_t bytes, size_t* actual_len, int* rc); int SSLSocket_close(networkHandles* net); -int SSLSocket_putdatas(SSL* ssl, int socket, char* buf0, size_t buf0len, PacketBuffers bufs); -int SSLSocket_connect(SSL* ssl, int sock, const char* hostname, int verify, int (*cb)(const char *str, size_t len, void *u), void* u); +int SSLSocket_putdatas(SSL* ssl, SOCKET socket, char* buf0, size_t buf0len, PacketBuffers bufs); +int SSLSocket_connect(SSL* ssl, SOCKET sock, const char* hostname, int verify, int (*cb)(const char *str, size_t len, void *u), void* u); -int SSLSocket_getPendingRead(void); +SOCKET SSLSocket_getPendingRead(void); int SSLSocket_continueWrite(pending_writes* pw); #endif diff --git a/src/Socket.c b/src/Socket.c index 189a84125..dc4254caf 100644 --- a/src/Socket.c +++ b/src/Socket.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009, 2021 IBM Corp., Ian Craggs and others + * Copyright (c) 2009, 2022 IBM Corp., Ian Craggs and others * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 @@ -44,16 +44,16 @@ #include "Heap.h" -int Socket_setnonblocking(int sock); -int Socket_error(char* aString, int sock); -int Socket_addSocket(int newSd); -int isReady(int socket, fd_set* read_set, fd_set* write_set); -int Socket_writev(int socket, iobuf* iovecs, int count, unsigned long* bytes); -int Socket_close_only(int socket); -int Socket_continueWrite(int socket); -int Socket_continueWrites(fd_set* pwset, int* socket, mutex_type mutex); -char* Socket_getaddrname(struct sockaddr* sa, int sock); -int Socket_abortWrite(int socket); +int Socket_setnonblocking(SOCKET sock); +int Socket_error(char* aString, SOCKET sock); +int Socket_addSocket(SOCKET newSd); +int isReady(int index); +int Socket_writev(SOCKET socket, iobuf* iovecs, int count, unsigned long* bytes); +int Socket_close_only(SOCKET socket); +int Socket_continueWrite(SOCKET socket); +int Socket_continueWrites(SOCKET* socket, mutex_type mutex); +char* Socket_getaddrname(struct sockaddr* sa, SOCKET sock); +int Socket_abortWrite(SOCKET socket); #if defined(_WIN32) || defined(_WIN64) #define iov_len len @@ -65,14 +65,13 @@ int Socket_abortWrite(int socket); * Structure to hold all socket data for this module */ Sockets mod_s; -static fd_set wset; /** * Set a socket non-blocking, OS independently * @param sock the socket to set non-blocking * @return TCP call error code */ -int Socket_setnonblocking(int sock) +int Socket_setnonblocking(SOCKET sock) { int rc; #if defined(_WIN32) || defined(_WIN64) @@ -99,7 +98,7 @@ int Socket_setnonblocking(int sock) * @param sock the socket on which the error occurred * @return the specific TCP error code */ -int Socket_error(char* aString, int sock) +int Socket_error(char* aString, SOCKET sock) { int err; @@ -134,14 +133,15 @@ void Socket_outInitialize(void) #endif SocketBuffer_initialize(); - mod_s.clientsds = ListInitialize(); mod_s.connect_pending = ListInitialize(); mod_s.write_pending = ListInitialize(); - mod_s.cur_clientsds = NULL; - FD_ZERO(&(mod_s.rset)); /* Initialize the descriptor set */ - FD_ZERO(&(mod_s.pending_wset)); - mod_s.maxfdp1 = 0; - memcpy((void*)&(mod_s.rset_saved), (void*)&(mod_s.rset), sizeof(mod_s.rset_saved)); + + mod_s.nfds = 0; + mod_s.fds = NULL; + + mod_s.saved.cur_fd = -1; + mod_s.saved.fds = NULL; + mod_s.saved.nfds = 0; FUNC_EXIT; } @@ -154,7 +154,11 @@ void Socket_outTerminate(void) FUNC_ENTRY; ListFree(mod_s.connect_pending); ListFree(mod_s.write_pending); - ListFree(mod_s.clientsds); + //ListFree(mod_s.clientsds); + if (mod_s.fds) + free(mod_s.fds); + if (mod_s.saved.fds) + free(mod_s.saved.fds); SocketBuffer_terminate(); #if defined(_WIN32) || defined(_WIN64) WSACleanup(); @@ -163,49 +167,55 @@ void Socket_outTerminate(void) } +static int cmpfds(const void *p1, const void *p2) +{ + SOCKET key1 = ((struct pollfd*)p1)->fd; + SOCKET key2 = ((struct pollfd*)p2)->fd; + + return (key1 == key2) ? 0 : ((key1 < key2) ? -1 : 1); +} + + +static int cmpsockfds(const void *p1, const void *p2) +{ + int key1 = *(int*)p1; + SOCKET key2 = ((struct pollfd*)p2)->fd; + + return (key1 == key2) ? 0 : ((key1 < key2) ? -1 : 1); +} + + /** * Add a socket to the list of socket to check with select * @param newSd the new socket to add */ -int Socket_addSocket(int newSd) +int Socket_addSocket(SOCKET newSd) { int rc = 0; FUNC_ENTRY; - if (ListFindItem(mod_s.clientsds, &newSd, intcompare) == NULL) /* make sure we don't add the same socket twice */ + mod_s.nfds++; + if (mod_s.fds) + mod_s.fds = realloc(mod_s.fds, mod_s.nfds * sizeof(mod_s.fds[0])); + else + mod_s.fds = malloc(mod_s.nfds * sizeof(mod_s.fds[0])); + if (!mod_s.fds) { - if (mod_s.clientsds->count >= FD_SETSIZE) - { - Log(LOG_ERROR, -1, "addSocket: exceeded FD_SETSIZE %d", FD_SETSIZE); - rc = SOCKET_ERROR; - } - else - { - int* pnewSd = (int*)malloc(sizeof(newSd)); - - if (!pnewSd) - { - rc = PAHO_MEMORY_ERROR; - goto exit; - } - *pnewSd = newSd; - if (!ListAppend(mod_s.clientsds, pnewSd, sizeof(newSd))) - { - free(pnewSd); - rc = PAHO_MEMORY_ERROR; - goto exit; - } - FD_SET(newSd, &(mod_s.rset_saved)); - mod_s.maxfdp1 = max(mod_s.maxfdp1, newSd + 1); - rc = Socket_setnonblocking(newSd); - if (rc == SOCKET_ERROR) - Log(LOG_ERROR, -1, "addSocket: setnonblocking"); - } + rc = PAHO_MEMORY_ERROR; + goto exit; } - else - Log(LOG_ERROR, -1, "addSocket: socket %d already in the list", newSd); -exit: + mod_s.fds[mod_s.nfds - 1].fd = newSd; + mod_s.fds[mod_s.nfds - 1].events = POLLIN | POLLOUT/* | POLLNVAL*/; + + /* sort the poll fds array by socket number */ + qsort(mod_s.fds, (size_t)mod_s.nfds, sizeof(mod_s.fds[0]), cmpfds); + + rc = Socket_setnonblocking(newSd); + if (rc == SOCKET_ERROR) + Log(LOG_ERROR, -1, "addSocket: setnonblocking"); + + exit: FUNC_EXIT_RC(rc); return rc; } @@ -214,20 +224,25 @@ int Socket_addSocket(int newSd) /** * Don't accept work from a client unless it is accepting work back, i.e. its socket is writeable * this seems like a reasonable form of flow control, and practically, seems to work. - * @param socket the socket to check - * @param read_set the socket read set (see select doc) - * @param write_set the socket write set (see select doc) + * @param index the socket index to check * @return boolean - is the socket ready to go? */ -int isReady(int socket, fd_set* read_set, fd_set* write_set) +int isReady(int index) { int rc = 1; + SOCKET* socket = &mod_s.fds[index].fd; FUNC_ENTRY; - if (ListFindItem(mod_s.connect_pending, &socket, intcompare) && FD_ISSET(socket, write_set)) - ListRemoveItem(mod_s.connect_pending, &socket, intcompare); + + if (mod_s.saved.fds[index].revents & POLLHUP || mod_s.saved.fds[index].revents & POLLNVAL) + ; /* signal work to be done if there is an error on the socket */ + else if (ListFindItem(mod_s.connect_pending, socket, intcompare) && + (mod_s.saved.fds[index].revents & POLLOUT)) + ListRemoveItem(mod_s.connect_pending, socket, intcompare); else - rc = FD_ISSET(socket, read_set) && FD_ISSET(socket, write_set) && Socket_noPendingWrites(socket); + rc = (mod_s.saved.fds[index].revents & POLLIN) && + (mod_s.saved.fds[index].revents & POLLOUT) && + Socket_noPendingWrites(*socket); FUNC_EXIT_RC(rc); return rc; } @@ -237,92 +252,84 @@ int isReady(int socket, fd_set* read_set, fd_set* write_set) * Returns the next socket ready for communications as indicated by select * @param more_work flag to indicate more work is waiting, and thus a timeout value of 0 should * be used for the select - * @param tp the timeout to be used for the select, unless overridden + * @param timeout the timeout to be used in ms * @param rc a value other than 0 indicates an error of the returned socket * @return the socket next ready, or 0 if none is ready */ -int Socket_getReadySocket(int more_work, struct timeval *tp, mutex_type mutex, int* rc) +SOCKET Socket_getReadySocket(int more_work, int timeout, mutex_type mutex, int* rc) { - int sock = 0; + SOCKET sock = 0; *rc = 0; - static struct timeval zero = {0L, 0L}; /* 0 seconds */ - static struct timeval one = {1L, 0L}; /* 1 second */ - struct timeval timeout = one; + int timeout_ms = 1000; FUNC_ENTRY; Thread_lock_mutex(mutex); - if (mod_s.clientsds->count == 0) + if (mod_s.nfds == 0) goto exit; if (more_work) - timeout = zero; - else if (tp) - timeout = *tp; + timeout_ms = 0; + else if (timeout >= 0) + timeout_ms = timeout; - while (mod_s.cur_clientsds != NULL) + while (mod_s.saved.cur_fd != -1) { - if (isReady(*((int*)(mod_s.cur_clientsds->content)), &(mod_s.rset), &wset)) + if (isReady(mod_s.saved.cur_fd)) break; - ListNextElement(mod_s.clientsds, &mod_s.cur_clientsds); + mod_s.saved.cur_fd = (mod_s.saved.cur_fd == mod_s.saved.nfds - 1) ? -1 : mod_s.saved.cur_fd + 1; } - if (mod_s.cur_clientsds == NULL) + if (mod_s.saved.cur_fd == -1) { - int rc1, maxfdp1_saved; - fd_set pwset; + if (mod_s.nfds != mod_s.saved.nfds) + { + mod_s.saved.nfds = mod_s.nfds; + if (mod_s.saved.fds) + mod_s.saved.fds = realloc(mod_s.saved.fds, mod_s.nfds * sizeof(struct pollfd)); + else + mod_s.saved.fds = malloc(mod_s.nfds * sizeof(struct pollfd)); + } + memcpy(mod_s.saved.fds, mod_s.fds, mod_s.nfds * sizeof(struct pollfd)); - memcpy((void*)&(mod_s.rset), (void*)&(mod_s.rset_saved), sizeof(mod_s.rset)); - memcpy((void*)&(pwset), (void*)&(mod_s.pending_wset), sizeof(pwset)); /* Prevent performance issue by unlocking the socket_mutex while waiting for a ready socket. */ - maxfdp1_saved = mod_s.maxfdp1; Thread_unlock_mutex(mutex); - *rc = select(maxfdp1_saved, &(mod_s.rset), &pwset, NULL, &timeout); + *rc = poll(mod_s.saved.fds, mod_s.saved.nfds, timeout_ms); Thread_lock_mutex(mutex); if (*rc == SOCKET_ERROR) { - Socket_error("read select", 0); + Socket_error("poll", 0); goto exit; } - Log(TRACE_MAX, -1, "Return code %d from read select", *rc); + Log(TRACE_MAX, -1, "Return code %d from poll", *rc); - if (Socket_continueWrites(&pwset, &sock, mutex) == SOCKET_ERROR) + if (Socket_continueWrites(&sock, mutex) == SOCKET_ERROR) { *rc = SOCKET_ERROR; goto exit; } - memcpy((void*)&wset, (void*)&(mod_s.rset_saved), sizeof(wset)); - if ((rc1 = select(mod_s.maxfdp1, NULL, &(wset), NULL, &zero)) == SOCKET_ERROR) - { - Socket_error("write select", 0); - *rc = rc1; - goto exit; - } - Log(TRACE_MAX, -1, "Return code %d from write select", rc1); - - if (*rc == 0 && rc1 == 0) + if (*rc == 0) { sock = 0; goto exit; /* no work to do */ } - mod_s.cur_clientsds = mod_s.clientsds->first; - while (mod_s.cur_clientsds != NULL) + mod_s.saved.cur_fd = 0; + while (mod_s.saved.cur_fd != -1) { - int cursock = *((int*)(mod_s.cur_clientsds->content)); - if (isReady(cursock, &(mod_s.rset), &wset)) + if (isReady(mod_s.saved.cur_fd)) break; - ListNextElement(mod_s.clientsds, &mod_s.cur_clientsds); + mod_s.saved.cur_fd = (mod_s.saved.cur_fd == mod_s.saved.nfds - 1) ? -1 : mod_s.saved.cur_fd + 1; } } *rc = 0; - if (mod_s.cur_clientsds == NULL) + if (mod_s.saved.cur_fd == -1) sock = 0; else { - sock = *((int*)(mod_s.cur_clientsds->content)); - ListNextElement(mod_s.clientsds, &mod_s.cur_clientsds); + sock = mod_s.saved.fds[mod_s.saved.cur_fd].fd; + mod_s.saved.cur_fd = (mod_s.saved.cur_fd == mod_s.saved.nfds - 1) ? -1 : mod_s.saved.cur_fd + 1; } exit: Thread_unlock_mutex(mutex); @@ -337,7 +344,7 @@ int Socket_getReadySocket(int more_work, struct timeval *tp, mutex_type mutex, i * @param c the character read, returned * @return completion code */ -int Socket_getch(int socket, char* c) +int Socket_getch(SOCKET socket, char* c) { int rc = SOCKET_ERROR; @@ -375,7 +382,7 @@ int Socket_getch(int socket, char* c) * @param actual_len the actual number of bytes read * @return completion code */ -char *Socket_getdata(int socket, size_t bytes, size_t* actual_len, int *rc) +char *Socket_getdata(SOCKET socket, size_t bytes, size_t* actual_len, int *rc) { char* buf; @@ -422,9 +429,9 @@ char *Socket_getdata(int socket, size_t bytes, size_t* actual_len, int *rc) * Indicate whether any data is pending outbound for a socket. * @return boolean - true == data pending. */ -int Socket_noPendingWrites(int socket) +int Socket_noPendingWrites(SOCKET socket) { - int cursock = socket; + SOCKET cursock = socket; return ListFindItem(mod_s.write_pending, &cursock, intcompare) == NULL; } @@ -438,7 +445,7 @@ int Socket_noPendingWrites(int socket) * @param bytes number of bytes actually written returned * @return completion code, especially TCPSOCKET_INTERRUPTED */ -int Socket_writev(int socket, iobuf* iovecs, int count, unsigned long* bytes) +int Socket_writev(SOCKET socket, iobuf* iovecs, int count, unsigned long* bytes) { int rc; @@ -510,7 +517,7 @@ for testing purposes only! * @param buflens an array of corresponding buffer lengths * @return completion code, especially TCPSOCKET_INTERRUPTED */ -int Socket_putdatas(int socket, char* buf0, size_t buf0len, PacketBuffers bufs) +int Socket_putdatas(SOCKET socket, char* buf0, size_t buf0len, PacketBuffers bufs) { unsigned long bytes = 0L; iobuf iovecs[5]; @@ -545,7 +552,7 @@ int Socket_putdatas(int socket, char* buf0, size_t buf0len, PacketBuffers bufs) rc = TCPSOCKET_COMPLETE; else { - int* sockmem = (int*)malloc(sizeof(int)); + SOCKET* sockmem = (SOCKET*)malloc(sizeof(SOCKET)); if (!sockmem) { @@ -566,7 +573,7 @@ int Socket_putdatas(int socket, char* buf0, size_t buf0len, PacketBuffers bufs) rc = PAHO_MEMORY_ERROR; goto exit; } - FD_SET(socket, &(mod_s.pending_wset)); + //FD_SET(socket, &(mod_s.pending_wset)); rc = TCPSOCKET_INTERRUPTED; } } @@ -582,9 +589,9 @@ int Socket_putdatas(int socket, char* buf0, size_t buf0len, PacketBuffers bufs) * ready to read and write states. * @param socket the socket to add */ -void Socket_addPendingWrite(int socket) +void Socket_addPendingWrite(SOCKET socket) { - FD_SET(socket, &(mod_s.pending_wset)); + //FD_SET(socket, &(mod_s.pending_wset)); } @@ -592,10 +599,10 @@ void Socket_addPendingWrite(int socket) * Clear a socket from the pending write list - if one was added with Socket_addPendingWrite * @param socket the socket to remove */ -void Socket_clearPendingWrite(int socket) +void Socket_clearPendingWrite(SOCKET socket) { - if (FD_ISSET(socket, &(mod_s.pending_wset))) - FD_CLR(socket, &(mod_s.pending_wset)); + /*if (FD_ISSET(socket, &(mod_s.pending_wset))) + FD_CLR(socket, &(mod_s.pending_wset));*/ } @@ -604,7 +611,7 @@ void Socket_clearPendingWrite(int socket) * @param socket the socket to close * @return completion code */ -int Socket_close_only(int socket) +int Socket_close_only(SOCKET socket) { int rc; @@ -632,35 +639,33 @@ int Socket_close_only(int socket) * @param socket the socket to close * @return completion code */ -void Socket_close(int socket) +void Socket_close(SOCKET socket) { + struct pollfd* fd; + struct pollfd* last_fd = &mod_s.fds[mod_s.nfds - 1]; + FUNC_ENTRY; Socket_close_only(socket); - FD_CLR(socket, &(mod_s.rset_saved)); - if (FD_ISSET(socket, &(mod_s.pending_wset))) - FD_CLR(socket, &(mod_s.pending_wset)); - if (mod_s.cur_clientsds != NULL && *(int*)(mod_s.cur_clientsds->content) == socket) - mod_s.cur_clientsds = mod_s.cur_clientsds->next; Socket_abortWrite(socket); SocketBuffer_cleanup(socket); ListRemoveItem(mod_s.connect_pending, &socket, intcompare); ListRemoveItem(mod_s.write_pending, &socket, intcompare); - if (ListRemoveItem(mod_s.clientsds, &socket, intcompare)) + /* find the socket in the fds structure */ + fd = bsearch(&socket, mod_s.fds, (size_t)mod_s.nfds, sizeof(mod_s.fds[0]), cmpsockfds); + if (fd) + { + if (fd != last_fd) + { + /* shift array to remove the socket in question */ + memmove(fd, fd + 1, (mod_s.fds + ((mod_s.nfds - 1) * sizeof(struct pollfd))) - fd); + } + mod_s.nfds--; + mod_s.fds = realloc(mod_s.fds, sizeof(mod_s.fds[0]) * mod_s.nfds); Log(TRACE_MIN, -1, "Removed socket %d", socket); + } else Log(LOG_ERROR, -1, "Failed to remove socket %d", socket); - if (socket + 1 >= mod_s.maxfdp1) - { - /* now we have to reset mod_s.maxfdp1 */ - ListElement* cur_clientsds = NULL; - - mod_s.maxfdp1 = 0; - while (ListNextElement(mod_s.clientsds, &cur_clientsds)) - mod_s.maxfdp1 = max(*((int*)(cur_clientsds->content)), mod_s.maxfdp1); - ++(mod_s.maxfdp1); - Log(TRACE_MAX, -1, "Reset max fdp1 to %d", mod_s.maxfdp1); - } FUNC_EXIT; } @@ -674,9 +679,9 @@ void Socket_close(int socket) * @return completion code */ #if defined(__GNUC__) && defined(__linux__) -int Socket_new(const char* addr, size_t addr_len, int port, int* sock, long timeout) +int Socket_new(const char* addr, size_t addr_len, int port, SOCKET* sock, long timeout) #else -int Socket_new(const char* addr, size_t addr_len, int port, int* sock) +int Socket_new(const char* addr, size_t addr_len, int port, SOCKET* sock) #endif { int type = SOCK_STREAM; @@ -779,7 +784,7 @@ int Socket_new(const char* addr, size_t addr_len, int port, int* sock) Log(LOG_ERROR, -1, "%s is not a valid IP address", addr_mem); else { - *sock = (int)socket(family, type, 0); + *sock = socket(family, type, 0); if (*sock == INVALID_SOCKET) rc = Socket_error("socket", *sock); else @@ -819,7 +824,7 @@ int Socket_new(const char* addr, size_t addr_len, int port, int* sock) rc = Socket_error("connect", *sock); if (rc == EINPROGRESS || rc == EWOULDBLOCK) { - int* pnewSd = (int*)malloc(sizeof(int)); + SOCKET* pnewSd = (SOCKET*)malloc(sizeof(SOCKET)); if (!pnewSd) { @@ -827,7 +832,7 @@ int Socket_new(const char* addr, size_t addr_len, int port, int* sock) goto exit; } *pnewSd = *sock; - if (!ListAppend(mod_s.connect_pending, pnewSd, sizeof(int))) + if (!ListAppend(mod_s.connect_pending, pnewSd, sizeof(SOCKET))) { free(pnewSd); rc = PAHO_MEMORY_ERROR; @@ -874,7 +879,7 @@ void Socket_setWriteAvailableCallback(Socket_writeAvailable* mywriteavailable) * @param socket that socket * @return completion code: 0=incomplete, 1=complete, -1=socket error */ -int Socket_continueWrite(int socket) +int Socket_continueWrite(SOCKET socket) { int rc = 0; pending_writes* pw; @@ -959,7 +964,7 @@ int Socket_continueWrite(int socket) * @param socket that socket * @return completion code: 0=incomplete, 1=complete, -1=socket error */ -int Socket_abortWrite(int socket) +int Socket_abortWrite(SOCKET socket) { int i = -1, rc = 0; pending_writes* pw; @@ -988,12 +993,11 @@ int Socket_abortWrite(int socket) /** - * Continue any outstanding writes for a socket set - * @param pwset the set of sockets + * Continue any outstanding socket writes * @param sock in case of a socket error contains the affected socket * @return completion code, 0 or SOCKET_ERROR */ -int Socket_continueWrites(fd_set* pwset, int* sock, mutex_type mutex) +int Socket_continueWrites(SOCKET* sock, mutex_type mutex) { int rc1 = 0; ListElement* curpending = mod_s.write_pending->first; @@ -1003,12 +1007,15 @@ int Socket_continueWrites(fd_set* pwset, int* sock, mutex_type mutex) { int socket = *(int*)(curpending->content); int rc = 0; + struct pollfd* fd; + + /* find the socket in the fds structure */ + fd = bsearch(&socket, mod_s.saved.fds, (size_t)mod_s.saved.nfds, sizeof(mod_s.saved.fds[0]), cmpsockfds); - if (FD_ISSET(socket, pwset) && ((rc = Socket_continueWrite(socket)) != 0)) + if ((fd->revents & POLLOUT) && ((rc = Socket_continueWrite(socket)) != 0)) { if (!SocketBuffer_writeComplete(socket)) Log(LOG_SEVERE, -1, "Failed to remove pending write from socket buffer list"); - FD_CLR(socket, &(mod_s.pending_wset)); if (!ListRemove(mod_s.write_pending, curpending->content)) { Log(LOG_SEVERE, -1, "Failed to remove pending write from list"); @@ -1029,7 +1036,7 @@ int Socket_continueWrites(fd_set* pwset, int* sock, mutex_type mutex) else ListNextElement(mod_s.write_pending, &curpending); - if(rc == SOCKET_ERROR) + if (rc == SOCKET_ERROR) { *sock = socket; rc1 = SOCKET_ERROR; @@ -1046,7 +1053,7 @@ int Socket_continueWrites(fd_set* pwset, int* sock, mutex_type mutex) * @param sock socket * @return the peer information */ -char* Socket_getaddrname(struct sockaddr* sa, int sock) +char* Socket_getaddrname(struct sockaddr* sa, SOCKET sock) { /** * maximum length of the address string @@ -1084,7 +1091,7 @@ char* Socket_getaddrname(struct sockaddr* sa, int sock) * @param sock the socket to inquire on * @return the peer information */ -char* Socket_getpeer(int sock) +char* Socket_getpeer(SOCKET sock) { struct sockaddr_in6 sa; socklen_t sal = sizeof(sa); diff --git a/src/Socket.h b/src/Socket.h index e9e61e08a..390552b28 100644 --- a/src/Socket.h +++ b/src/Socket.h @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009, 2020 IBM Corp. and others + * Copyright (c) 2009, 2022 IBM Corp., Ian Craggs and others * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 @@ -26,6 +26,7 @@ #include #include #define MAXHOSTNAMELEN 256 +#define poll WSAPoll #if !defined(SSLSOCKET_H) #undef EAGAIN #define EAGAIN WSAEWOULDBLOCK @@ -51,6 +52,7 @@ #include #include #include +#include #include #else #include @@ -65,6 +67,7 @@ #include #include #define ULONG size_t +#define SOCKET int #endif #include "mutex_type.h" /* Needed for mutex_type */ @@ -108,41 +111,44 @@ typedef struct */ typedef struct { - fd_set rset, /**< socket read set (see select doc) */ - rset_saved; /**< saved socket read set */ - int maxfdp1; /**< max descriptor used +1 (again see select doc) */ - List* clientsds; /**< list of client socket descriptors */ - ListElement* cur_clientsds; /**< current client socket descriptor (iterator) */ List* connect_pending; /**< list of sockets for which a connect is pending */ List* write_pending; /**< list of sockets for which a write is pending */ - fd_set pending_wset; /**< socket pending write set for select */ + + unsigned int nfds; /**< no of file descriptors for poll */ + struct pollfd* fds; /**< poll read file descriptors */ + + struct { + int cur_fd; /**< index into the fds_saved array */ + unsigned int nfds; /**< number of fds in the fds_saved array */ + struct pollfd* fds; + } saved; } Sockets; void Socket_outInitialize(void); void Socket_outTerminate(void); -int Socket_getReadySocket(int more_work, struct timeval *tp, mutex_type mutex, int* rc); -int Socket_getch(int socket, char* c); -char *Socket_getdata(int socket, size_t bytes, size_t* actual_len, int* rc); -int Socket_putdatas(int socket, char* buf0, size_t buf0len, PacketBuffers bufs); -void Socket_close(int socket); +SOCKET Socket_getReadySocket(int more_work, int timeout, mutex_type mutex, int* rc); +int Socket_getch(SOCKET socket, char* c); +char *Socket_getdata(SOCKET socket, size_t bytes, size_t* actual_len, int* rc); +int Socket_putdatas(SOCKET socket, char* buf0, size_t buf0len, PacketBuffers bufs); +void Socket_close(SOCKET socket); #if defined(__GNUC__) && defined(__linux__) /* able to use GNU's getaddrinfo_a to make timeouts possible */ -int Socket_new(const char* addr, size_t addr_len, int port, int* socket, long timeout); +int Socket_new(const char* addr, size_t addr_len, int port, SOCKET* socket, long timeout); #else -int Socket_new(const char* addr, size_t addr_len, int port, int* socket); +int Socket_new(const char* addr, size_t addr_len, int port, SOCKET* socket); #endif -int Socket_noPendingWrites(int socket); -char* Socket_getpeer(int sock); +int Socket_noPendingWrites(SOCKET socket); +char* Socket_getpeer(SOCKET sock); -void Socket_addPendingWrite(int socket); -void Socket_clearPendingWrite(int socket); +void Socket_addPendingWrite(SOCKET socket); +void Socket_clearPendingWrite(SOCKET socket); -typedef void Socket_writeComplete(int socket, int rc); +typedef void Socket_writeComplete(SOCKET socket, int rc); void Socket_setWriteCompleteCallback(Socket_writeComplete*); -typedef void Socket_writeAvailable(int socket); +typedef void Socket_writeAvailable(SOCKET socket); void Socket_setWriteAvailableCallback(Socket_writeAvailable*); #endif /* SOCKET_H */ diff --git a/src/SocketBuffer.c b/src/SocketBuffer.c index f6b817af5..42eff81fe 100644 --- a/src/SocketBuffer.c +++ b/src/SocketBuffer.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009, 2020 IBM Corp. + * Copyright (c) 2009, 2022 IBM Corp., Ian Craggs and others * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 @@ -148,7 +148,7 @@ void SocketBuffer_terminate(void) * Cleanup any buffers for a specific socket * @param socket the socket to clean up */ -void SocketBuffer_cleanup(int socket) +void SocketBuffer_cleanup(SOCKET socket) { FUNC_ENTRY; SocketBuffer_writeComplete(socket); /* clean up write buffers */ @@ -173,7 +173,7 @@ void SocketBuffer_cleanup(int socket) * @param actual_len the actual length returned * @return the actual data */ -char* SocketBuffer_getQueuedData(int socket, size_t bytes, size_t* actual_len) +char* SocketBuffer_getQueuedData(SOCKET socket, size_t bytes, size_t* actual_len) { socket_queue* queue = NULL; @@ -216,7 +216,7 @@ char* SocketBuffer_getQueuedData(int socket, size_t bytes, size_t* actual_len) * @param c the character returned if any * @return completion code */ -int SocketBuffer_getQueuedChar(int socket, char* c) +int SocketBuffer_getQueuedChar(SOCKET socket, char* c) { int rc = SOCKETBUFFER_INTERRUPTED; @@ -249,7 +249,7 @@ int SocketBuffer_getQueuedChar(int socket, char* c) * @param socket the socket to get queued data for * @param actual_len the actual length of data that was read */ -void SocketBuffer_interrupted(int socket, size_t actual_len) +void SocketBuffer_interrupted(SOCKET socket, size_t actual_len) { socket_queue* queue = NULL; @@ -278,7 +278,7 @@ void SocketBuffer_interrupted(int socket, size_t actual_len) * @param socket the socket for which the operation is now complete * @return pointer to the default queue data */ -char* SocketBuffer_complete(int socket) +char* SocketBuffer_complete(SOCKET socket) { FUNC_ENTRY; if (ListFindItem(queues, &socket, socketcompare)) @@ -300,7 +300,7 @@ char* SocketBuffer_complete(int socket) * @param socket the socket for which to queue char for * @param c the character to queue */ -void SocketBuffer_queueChar(int socket, char c) +void SocketBuffer_queueChar(SOCKET socket, char c) { int error = 0; socket_queue* curq = def_queue; @@ -344,9 +344,9 @@ void SocketBuffer_queueChar(int socket, char c) * @param bytes actual data length that was written */ #if defined(OPENSSL) -int SocketBuffer_pendingWrite(int socket, SSL* ssl, int count, iobuf* iovecs, int* frees, size_t total, size_t bytes) +int SocketBuffer_pendingWrite(SOCKET socket, SSL* ssl, int count, iobuf* iovecs, int* frees, size_t total, size_t bytes) #else -int SocketBuffer_pendingWrite(int socket, int count, iobuf* iovecs, int* frees, size_t total, size_t bytes) +int SocketBuffer_pendingWrite(SOCKET socket, int count, iobuf* iovecs, int* frees, size_t total, size_t bytes) #endif { int i = 0; @@ -396,7 +396,7 @@ int pending_socketcompare(void* a, void* b) * @param socket the socket to get queued data for * @return pointer to the queued data or NULL */ -pending_writes* SocketBuffer_getWrite(int socket) +pending_writes* SocketBuffer_getWrite(SOCKET socket) { ListElement* le = ListFindItem(&writes, &socket, pending_socketcompare); return (le) ? (pending_writes*)(le->content) : NULL; @@ -408,7 +408,7 @@ pending_writes* SocketBuffer_getWrite(int socket) * @param socket the socket for which the operation is now complete * @return completion code, boolean - was the queue removed? */ -int SocketBuffer_writeComplete(int socket) +int SocketBuffer_writeComplete(SOCKET socket) { return ListRemoveItem(&writes, &socket, pending_socketcompare); } @@ -421,7 +421,7 @@ int SocketBuffer_writeComplete(int socket) * @param payload the payload of the QoS 0 write * @return pointer to the updated queued data structure, or NULL */ -pending_writes* SocketBuffer_updateWrite(int socket, char* topic, char* payload) +pending_writes* SocketBuffer_updateWrite(SOCKET socket, char* topic, char* payload) { pending_writes* pw = NULL; ListElement* le = NULL; diff --git a/src/SocketBuffer.h b/src/SocketBuffer.h index 0fc7d6e7d..1b2ab915a 100644 --- a/src/SocketBuffer.h +++ b/src/SocketBuffer.h @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009, 2020 IBM Corp. + * Copyright (c) 2009, 2022 IBM Corp., Ian Craggs and others * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 @@ -18,11 +18,7 @@ #if !defined(SOCKETBUFFER_H) #define SOCKETBUFFER_H -#if defined(_WIN32) || defined(_WIN64) -#include -#else -#include -#endif +#include "Socket.h" #if defined(OPENSSL) #include @@ -36,7 +32,7 @@ typedef struct { - int socket; + SOCKET socket; unsigned int index; size_t headerlen; char fixed_header[5]; /**< header plus up to 4 length bytes */ @@ -47,7 +43,8 @@ typedef struct typedef struct { - int socket, count; + SOCKET socket; + int count; size_t total; #if defined(OPENSSL) SSL* ssl; @@ -65,20 +62,20 @@ typedef struct int SocketBuffer_initialize(void); void SocketBuffer_terminate(void); -void SocketBuffer_cleanup(int socket); -char* SocketBuffer_getQueuedData(int socket, size_t bytes, size_t* actual_len); -int SocketBuffer_getQueuedChar(int socket, char* c); -void SocketBuffer_interrupted(int socket, size_t actual_len); -char* SocketBuffer_complete(int socket); -void SocketBuffer_queueChar(int socket, char c); +void SocketBuffer_cleanup(SOCKET socket); +char* SocketBuffer_getQueuedData(SOCKET socket, size_t bytes, size_t* actual_len); +int SocketBuffer_getQueuedChar(SOCKET socket, char* c); +void SocketBuffer_interrupted(SOCKET socket, size_t actual_len); +char* SocketBuffer_complete(SOCKET socket); +void SocketBuffer_queueChar(SOCKET socket, char c); #if defined(OPENSSL) -int SocketBuffer_pendingWrite(int socket, SSL* ssl, int count, iobuf* iovecs, int* frees, size_t total, size_t bytes); +int SocketBuffer_pendingWrite(SOCKET socket, SSL* ssl, int count, iobuf* iovecs, int* frees, size_t total, size_t bytes); #else -int SocketBuffer_pendingWrite(int socket, int count, iobuf* iovecs, int* frees, size_t total, size_t bytes); +int SocketBuffer_pendingWrite(SOCKET socket, int count, iobuf* iovecs, int* frees, size_t total, size_t bytes); #endif -pending_writes* SocketBuffer_getWrite(int socket); -int SocketBuffer_writeComplete(int socket); -pending_writes* SocketBuffer_updateWrite(int socket, char* topic, char* payload); +pending_writes* SocketBuffer_getWrite(SOCKET socket); +int SocketBuffer_writeComplete(SOCKET socket); +pending_writes* SocketBuffer_updateWrite(SOCKET socket, char* topic, char* payload); #endif diff --git a/test/test1.c b/test/test1.c index 4aa07c6e0..8410f7454 100644 --- a/test/test1.c +++ b/test/test1.c @@ -805,7 +805,14 @@ int test4_run(int qos) } } - MQTTClient_yield(); /* allow any unfinished protocol exchanges to finish */ + /* call yield a few times until unfinished protocol exchanges are finished */ + count = 0; + do + { + MQTTClient_yield(); + rc = MQTTClient_getPendingDeliveryTokens(c, &tokens); + assert("getPendingDeliveryTokens rc == 0", rc == MQTTCLIENT_SUCCESS, "rc was %d", rc); + } while (tokens != NULL && ++count < 10); rc = MQTTClient_getPendingDeliveryTokens(c, &tokens); assert("getPendingDeliveryTokens rc == 0", rc == MQTTCLIENT_SUCCESS, "rc was %d", rc); From 017e0b4064f515c4e123f2b6d4db0221483678d5 Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Fri, 4 Feb 2022 19:08:15 +0000 Subject: [PATCH 40/93] Fix clash of commits that resulted in some QoS2 packets being sent twice --- src/MQTTProtocolClient.c | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/src/MQTTProtocolClient.c b/src/MQTTProtocolClient.c index 3e834ecbd..5cc4eafd6 100644 --- a/src/MQTTProtocolClient.c +++ b/src/MQTTProtocolClient.c @@ -338,13 +338,11 @@ int MQTTProtocol_handlePublishes(void* pack, SOCKET sock) if (publish->header.bits.qos == 1) { - /* if we get a socket error from sending the puback, should we ignore the publication? */ Protocol_processPublication(publish, client, 1); if (socketHasPendingWrites) rc = MQTTProtocol_queueAck(client, PUBACK, publish->msgId); else - /* send puback before processing the publications because a lot of return publications could fill up the socket buffer */ rc = MQTTPacket_send_puback(publish->MQTTVersion, publish->msgId, &client->net, client->clientID); } else if (publish->header.bits.qos == 2) @@ -382,11 +380,6 @@ int MQTTProtocol_handlePublishes(void* pack, SOCKET sock) } else ListAppend(client->inboundMsgs, m, sizeof(Messages) + len); - if (socketHasPendingWrites) - rc = MQTTProtocol_queueAck(client, PUBREC, publish->msgId); - else - rc = MQTTPacket_send_pubrec(publish->MQTTVersion, publish->msgId, &client->net, client->clientID); - if (m->MQTTVersion >= MQTTVERSION_5 && already_received == 0) { Publish publish1; @@ -416,7 +409,10 @@ int MQTTProtocol_handlePublishes(void* pack, SOCKET sock) } memcpy(m->publish->payload, temp, m->publish->payloadlen); } - rc = MQTTPacket_send_pubrec(publish->MQTTVersion, publish->msgId, &client->net, client->clientID); + if (socketHasPendingWrites) + rc = MQTTProtocol_queueAck(client, PUBREC, publish->msgId); + else + rc = MQTTPacket_send_pubrec(publish->MQTTVersion, publish->msgId, &client->net, client->clientID); publish->topic = NULL; } exit: @@ -580,12 +576,6 @@ int MQTTProtocol_handlePubrels(void* pack, SOCKET sock) memset(&publish, '\0', sizeof(publish)); - /* send pubcomp before processing the publications because a lot of return publications could fill up the socket buffer */ - if (!Socket_noPendingWrites(sock)) - rc = MQTTProtocol_queueAck(client, PUBCOMP, pubrel->msgId); - else - rc = MQTTPacket_send_pubcomp(pubrel->MQTTVersion, pubrel->msgId, &client->net, client->clientID); - publish.header.bits.qos = m->qos; publish.header.bits.retain = m->retain; publish.msgId = m->msgid; @@ -612,7 +602,11 @@ int MQTTProtocol_handlePubrels(void* pack, SOCKET sock) ListRemove(&(state.publications), m->publish); ListRemove(client->inboundMsgs, m); ++(state.msgs_received); - rc = MQTTPacket_send_pubcomp(pubrel->MQTTVersion, pubrel->msgId, &client->net, client->clientID); + + if (!Socket_noPendingWrites(sock)) + rc = MQTTProtocol_queueAck(client, PUBCOMP, pubrel->msgId); + else + rc = MQTTPacket_send_pubcomp(pubrel->MQTTVersion, pubrel->msgId, &client->net, client->clientID); } } if (pubrel->MQTTVersion >= MQTTVERSION_5) From 46daa7d47dbd14b787471b8c0a3ec7c62a8eba45 Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Fri, 4 Feb 2022 19:08:15 +0000 Subject: [PATCH 41/93] Fix clash of commits that resulted in some QoS2 packets being sent twice --- src/MQTTProtocolClient.c | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/src/MQTTProtocolClient.c b/src/MQTTProtocolClient.c index b467d3914..9800fb76e 100644 --- a/src/MQTTProtocolClient.c +++ b/src/MQTTProtocolClient.c @@ -338,13 +338,11 @@ int MQTTProtocol_handlePublishes(void* pack, int sock) if (publish->header.bits.qos == 1) { - /* if we get a socket error from sending the puback, should we ignore the publication? */ Protocol_processPublication(publish, client, 1); if (socketHasPendingWrites) rc = MQTTProtocol_queueAck(client, PUBACK, publish->msgId); else - /* send puback before processing the publications because a lot of return publications could fill up the socket buffer */ rc = MQTTPacket_send_puback(publish->MQTTVersion, publish->msgId, &client->net, client->clientID); } else if (publish->header.bits.qos == 2) @@ -382,11 +380,6 @@ int MQTTProtocol_handlePublishes(void* pack, int sock) } else ListAppend(client->inboundMsgs, m, sizeof(Messages) + len); - if (socketHasPendingWrites) - rc = MQTTProtocol_queueAck(client, PUBREC, publish->msgId); - else - rc = MQTTPacket_send_pubrec(publish->MQTTVersion, publish->msgId, &client->net, client->clientID); - if (m->MQTTVersion >= MQTTVERSION_5 && already_received == 0) { Publish publish1; @@ -416,7 +409,10 @@ int MQTTProtocol_handlePublishes(void* pack, int sock) } memcpy(m->publish->payload, temp, m->publish->payloadlen); } - rc = MQTTPacket_send_pubrec(publish->MQTTVersion, publish->msgId, &client->net, client->clientID); + if (socketHasPendingWrites) + rc = MQTTProtocol_queueAck(client, PUBREC, publish->msgId); + else + rc = MQTTPacket_send_pubrec(publish->MQTTVersion, publish->msgId, &client->net, client->clientID); publish->topic = NULL; } exit: @@ -580,12 +576,6 @@ int MQTTProtocol_handlePubrels(void* pack, int sock) memset(&publish, '\0', sizeof(publish)); - /* send pubcomp before processing the publications because a lot of return publications could fill up the socket buffer */ - if (!Socket_noPendingWrites(sock)) - rc = MQTTProtocol_queueAck(client, PUBCOMP, pubrel->msgId); - else - rc = MQTTPacket_send_pubcomp(pubrel->MQTTVersion, pubrel->msgId, &client->net, client->clientID); - publish.header.bits.qos = m->qos; publish.header.bits.retain = m->retain; publish.msgId = m->msgid; @@ -612,7 +602,11 @@ int MQTTProtocol_handlePubrels(void* pack, int sock) ListRemove(&(state.publications), m->publish); ListRemove(client->inboundMsgs, m); ++(state.msgs_received); - rc = MQTTPacket_send_pubcomp(pubrel->MQTTVersion, pubrel->msgId, &client->net, client->clientID); + + if (!Socket_noPendingWrites(sock)) + rc = MQTTProtocol_queueAck(client, PUBCOMP, pubrel->msgId); + else + rc = MQTTPacket_send_pubcomp(pubrel->MQTTVersion, pubrel->msgId, &client->net, client->clientID); } } if (pubrel->MQTTVersion >= MQTTVERSION_5) From 7baa11e3309aa506272733d2d21971a45b90d8e1 Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Fri, 4 Feb 2022 21:31:19 +0000 Subject: [PATCH 42/93] Add OpenSSL version conditional around set security level --- src/SSLSocket.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/SSLSocket.c b/src/SSLSocket.c index ade31e11d..ac046a6d0 100644 --- a/src/SSLSocket.c +++ b/src/SSLSocket.c @@ -593,7 +593,9 @@ int SSLSocket_createContext(networkHandles* net, MQTTClient_SSLOptions* opts) } } +#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) SSL_CTX_set_security_level(net->ctx, 1); +#endif if (opts->keyStore) { From 34f8c52d42643dd797934cdaf38e88d603999166 Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Sat, 5 Feb 2022 18:27:59 +0000 Subject: [PATCH 43/93] Fix some errors in the poll implementation --- src/Socket.c | 46 ++++++++++++++++++++++++++++++++-------------- src/Socket.h | 2 +- 2 files changed, 33 insertions(+), 15 deletions(-) diff --git a/src/Socket.c b/src/Socket.c index dc4254caf..6b4d7e34e 100644 --- a/src/Socket.c +++ b/src/Socket.c @@ -154,7 +154,6 @@ void Socket_outTerminate(void) FUNC_ENTRY; ListFree(mod_s.connect_pending); ListFree(mod_s.write_pending); - //ListFree(mod_s.clientsds); if (mod_s.fds) free(mod_s.fds); if (mod_s.saved.fds) @@ -206,7 +205,11 @@ int Socket_addSocket(SOCKET newSd) } mod_s.fds[mod_s.nfds - 1].fd = newSd; - mod_s.fds[mod_s.nfds - 1].events = POLLIN | POLLOUT/* | POLLNVAL*/; +#if defined(_WIN32) || defined(_WIN64) + mod_s.fds[mod_s.nfds - 1].events = POLLIN | POLLOUT; +#else + mod_s.fds[mod_s.nfds - 1].events = POLLIN | POLLOUT | POLLNVAL; +#endif /* sort the poll fds array by socket number */ qsort(mod_s.fds, (size_t)mod_s.nfds, sizeof(mod_s.fds[0]), cmpfds); @@ -215,7 +218,7 @@ int Socket_addSocket(SOCKET newSd) if (rc == SOCKET_ERROR) Log(LOG_ERROR, -1, "addSocket: setnonblocking"); - exit: +exit: FUNC_EXIT_RC(rc); return rc; } @@ -230,7 +233,7 @@ int Socket_addSocket(SOCKET newSd) int isReady(int index) { int rc = 1; - SOCKET* socket = &mod_s.fds[index].fd; + SOCKET* socket = &mod_s.saved.fds[index].fd; FUNC_ENTRY; @@ -264,7 +267,7 @@ SOCKET Socket_getReadySocket(int more_work, int timeout, mutex_type mutex, int* FUNC_ENTRY; Thread_lock_mutex(mutex); - if (mod_s.nfds == 0) + if (mod_s.nfds == 0 && mod_s.saved.nfds == 0) goto exit; if (more_work) @@ -639,10 +642,10 @@ int Socket_close_only(SOCKET socket) * @param socket the socket to close * @return completion code */ -void Socket_close(SOCKET socket) +int Socket_close(SOCKET socket) { struct pollfd* fd; - struct pollfd* last_fd = &mod_s.fds[mod_s.nfds - 1]; + int rc = 0; FUNC_ENTRY; Socket_close_only(socket); @@ -651,22 +654,37 @@ void Socket_close(SOCKET socket) ListRemoveItem(mod_s.connect_pending, &socket, intcompare); ListRemoveItem(mod_s.write_pending, &socket, intcompare); - /* find the socket in the fds structure */ fd = bsearch(&socket, mod_s.fds, (size_t)mod_s.nfds, sizeof(mod_s.fds[0]), cmpsockfds); if (fd) { - if (fd != last_fd) + struct pollfd* last_fd = &mod_s.fds[mod_s.nfds - 1]; + + if (--mod_s.nfds == 0) { - /* shift array to remove the socket in question */ - memmove(fd, fd + 1, (mod_s.fds + ((mod_s.nfds - 1) * sizeof(struct pollfd))) - fd); + free(mod_s.fds); + mod_s.fds = NULL; + } + else + { + if (fd != last_fd) + { + /* shift array to remove the socket in question */ + memmove(fd, fd + 1, (mod_s.fds + (mod_s.nfds * sizeof(struct pollfd))) - fd); + } + mod_s.fds = realloc(mod_s.fds, sizeof(mod_s.fds[0]) * mod_s.nfds); + if (mod_s.fds == NULL) + { + rc = PAHO_MEMORY_ERROR; + goto exit; + } } - mod_s.nfds--; - mod_s.fds = realloc(mod_s.fds, sizeof(mod_s.fds[0]) * mod_s.nfds); Log(TRACE_MIN, -1, "Removed socket %d", socket); } else Log(LOG_ERROR, -1, "Failed to remove socket %d", socket); - FUNC_EXIT; +exit: + FUNC_EXIT_RC(rc); + return rc; } diff --git a/src/Socket.h b/src/Socket.h index 390552b28..93a8982fe 100644 --- a/src/Socket.h +++ b/src/Socket.h @@ -131,7 +131,7 @@ SOCKET Socket_getReadySocket(int more_work, int timeout, mutex_type mutex, int* int Socket_getch(SOCKET socket, char* c); char *Socket_getdata(SOCKET socket, size_t bytes, size_t* actual_len, int* rc); int Socket_putdatas(SOCKET socket, char* buf0, size_t buf0len, PacketBuffers bufs); -void Socket_close(SOCKET socket); +int Socket_close(SOCKET socket); #if defined(__GNUC__) && defined(__linux__) /* able to use GNU's getaddrinfo_a to make timeouts possible */ int Socket_new(const char* addr, size_t addr_len, int port, SOCKET* socket, long timeout); From 333bc57ffe2d2461d5b8da9738e9ec568e94031f Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Sat, 5 Feb 2022 19:52:54 +0000 Subject: [PATCH 44/93] Add some debugging --- test/CMakeLists.txt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index fe4c97af8..fc07acd04 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1025,7 +1025,7 @@ IF (PAHO_WITH_SSL) ADD_TEST( NAME test5-6-multiple-connections-static - COMMAND test5-static "--test_no" "9" "--hostname" ${MQTT_SSL_HOSTNAME} "--client_key" "${CERTDIR}/client.pem" "--server_key" "${CERTDIR}/test-root-ca.crt" + COMMAND test5-static "--test_no" "9" "--hostname" ${MQTT_SSL_HOSTNAME} "--client_key" "${CERTDIR}/client.pem" "--server_key" "${CERTDIR}/test-root-ca.crt" --verbose ) ADD_TEST( @@ -1040,7 +1040,7 @@ IF (PAHO_WITH_SSL) ADD_TEST( NAME test5-7-ws-big-messages-static - COMMAND test5-static "--test_no" "10" "--ws" "--hostname" ${MQTT_SSL_HOSTNAME} "--client_key" "${CERTDIR}/client.pem" "--server_key" "${CERTDIR}/test-root-ca.crt" + COMMAND test5-static "--test_no" "10" "--ws" "--hostname" ${MQTT_SSL_HOSTNAME} "--client_key" "${CERTDIR}/client.pem" "--server_key" "${CERTDIR}/test-root-ca.crt" --verbose ) ADD_TEST( @@ -1226,7 +1226,7 @@ IF (PAHO_WITH_SSL) ADD_TEST( NAME test5-7-ws-big-messages - COMMAND test5 "--test_no" "10" "--ws" "--hostname" ${MQTT_SSL_HOSTNAME} "--client_key" "${CERTDIR}/client.pem" "--server_key" "${CERTDIR}/test-root-ca.crt" + COMMAND test5 "--test_no" "10" "--ws" "--hostname" ${MQTT_SSL_HOSTNAME} "--client_key" "${CERTDIR}/client.pem" "--server_key" "${CERTDIR}/test-root-ca.crt" --verbose ) ADD_TEST( @@ -1399,7 +1399,7 @@ IF (PAHO_BUILD_STATIC) ADD_TEST( NAME test8-6-blocked-acks-static - COMMAND test8-static "--test_no" "8" "--connection" ${MQTT_TEST_BROKER} "--size" "500000" + COMMAND test8-static "--test_no" "8" "--connection" ${MQTT_TEST_BROKER} "--size" "500000" --verbose ) SET_TESTS_PROPERTIES( @@ -1463,7 +1463,7 @@ IF (PAHO_BUILD_SHARED) ADD_TEST( NAME test8-6-blocked-acks - COMMAND test8 "--test_no" "8" "--connection" ${MQTT_TEST_BROKER} "--size" "500000" + COMMAND test8 "--test_no" "8" "--connection" ${MQTT_TEST_BROKER} "--size" "500000" --verbose ) SET_TESTS_PROPERTIES( From 6a68f4420cf998c3a6dfa3bbc6e8c6d6913166f0 Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Sun, 6 Feb 2022 13:07:36 +0000 Subject: [PATCH 45/93] Add test debug and lengthen some timeouts --- test/test5.c | 7 ++++--- test/test8.c | 3 ++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/test/test5.c b/test/test5.c index 248133580..6f4012e22 100644 --- a/test/test5.c +++ b/test/test5.c @@ -529,6 +529,7 @@ void asyncTestOnUnsubscribe(void* context, MQTTAsync_successData* response) MyLog(LOGA_DEBUG, "In asyncTestOnUnsubscribe callback, %s", tc->clientid); opts.onSuccess = asyncTestOnDisconnect; opts.context = tc; + opts.timeout = 1000; rc = MQTTAsync_disconnect(tc->client, &opts); } @@ -2294,7 +2295,7 @@ int test7(struct Options options) tc.subscribed = 0; tc.testFinished = 0; - opts.keepAliveInterval = 20; + opts.keepAliveInterval = 60; opts.cleansession = 1; //opts.username = "testuser"; //opts.password = "testpassword"; @@ -2326,7 +2327,7 @@ int test7(struct Options options) if (rc != MQTTASYNC_SUCCESS) goto exit; - while (test7OnUnsubscribed == 0 && test7OnPublishSuccessCount < options.message_count) + while (tc.testFinished == 0 && test7OnUnsubscribed == 0 && test7OnPublishSuccessCount < options.message_count) #if defined(_WIN32) Sleep(100); #else @@ -2714,7 +2715,7 @@ int main(int argc, char** argv) } else { - MQTTAsync_setTraceLevel(MQTTASYNC_TRACE_ERROR); + MQTTAsync_setTraceLevel(MQTTASYNC_TRACE_PROTOCOL); rc = tests[options.test_no](options); /* run just the selected test */ } diff --git a/test/test8.c b/test/test8.c index e5140cc89..e1b53a74b 100644 --- a/test/test8.c +++ b/test/test8.c @@ -525,6 +525,7 @@ void test3_onUnsubscribe(void* context, MQTTAsync_successData* response) MyLog(LOGA_DEBUG, "In onUnsubscribe onSuccess callback \"%s\"", cd->clientid); opts.onSuccess = test3_onDisconnect; opts.context = cd; + opts.timeout = 1000; rc = MQTTAsync_disconnect(cd->c, &opts); assert("Disconnect successful", rc == MQTTASYNC_SUCCESS, "rc was %d", rc); @@ -1371,7 +1372,7 @@ int main(int argc, char** argv) } else { - MQTTAsync_setTraceLevel(MQTTASYNC_TRACE_ERROR); + MQTTAsync_setTraceLevel(MQTTASYNC_TRACE_PROTOCOL); rc = tests[options.test_no](options); /* run just the selected test */ } From 8d1aa132c25a119e97140afb6779e5731e7c1431 Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Sun, 6 Feb 2022 15:07:20 +0000 Subject: [PATCH 46/93] Add further poll debug --- src/Socket.c | 4 ++-- test/test5.c | 5 ++++- test/test8.c | 5 ++++- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/Socket.c b/src/Socket.c index 6b4d7e34e..ef9019711 100644 --- a/src/Socket.c +++ b/src/Socket.c @@ -237,8 +237,8 @@ int isReady(int index) FUNC_ENTRY; - if (mod_s.saved.fds[index].revents & POLLHUP || mod_s.saved.fds[index].revents & POLLNVAL) - ; /* signal work to be done if there is an error on the socket */ + if ((mod_s.saved.fds[index].revents & POLLHUP) || (mod_s.saved.fds[index].revents & POLLNVAL)) + printf("isReady error on socket %d\n", mod_s.saved.fds[index].revents); /* signal work to be done if there is an error on the socket */ else if (ListFindItem(mod_s.connect_pending, socket, intcompare) && (mod_s.saved.fds[index].revents & POLLOUT)) ListRemoveItem(mod_s.connect_pending, socket, intcompare); diff --git a/test/test5.c b/test/test5.c index 6f4012e22..ba62690a3 100644 --- a/test/test5.c +++ b/test/test5.c @@ -2715,7 +2715,10 @@ int main(int argc, char** argv) } else { - MQTTAsync_setTraceLevel(MQTTASYNC_TRACE_PROTOCOL); + if (options.test_no == 10) + MQTTAsync_setTraceLevel(MQTTASYNC_TRACE_MINIMUM); + else + MQTTAsync_setTraceLevel(MQTTASYNC_TRACE_PROTOCOL); rc = tests[options.test_no](options); /* run just the selected test */ } diff --git a/test/test8.c b/test/test8.c index e1b53a74b..6b95afe02 100644 --- a/test/test8.c +++ b/test/test8.c @@ -1372,7 +1372,10 @@ int main(int argc, char** argv) } else { - MQTTAsync_setTraceLevel(MQTTASYNC_TRACE_PROTOCOL); + if (options.test_no == 8) + MQTTAsync_setTraceLevel(MQTTASYNC_TRACE_MINIMUM); + else + MQTTAsync_setTraceLevel(MQTTASYNC_TRACE_ERROR); rc = tests[options.test_no](options); /* run just the selected test */ } From 140418771ce687430a5dae6d7a11c9c9a2554911 Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Sun, 6 Feb 2022 17:03:12 +0000 Subject: [PATCH 47/93] Some more test adjustments --- src/Socket.c | 2 +- test/test4.c | 3 +++ test/test5.c | 5 +---- test/test8.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++------ 4 files changed, 55 insertions(+), 11 deletions(-) diff --git a/src/Socket.c b/src/Socket.c index ef9019711..417ab8e5b 100644 --- a/src/Socket.c +++ b/src/Socket.c @@ -238,7 +238,7 @@ int isReady(int index) FUNC_ENTRY; if ((mod_s.saved.fds[index].revents & POLLHUP) || (mod_s.saved.fds[index].revents & POLLNVAL)) - printf("isReady error on socket %d\n", mod_s.saved.fds[index].revents); /* signal work to be done if there is an error on the socket */ + ; /* signal work to be done if there is an error on the socket */ else if (ListFindItem(mod_s.connect_pending, socket, intcompare) && (mod_s.saved.fds[index].revents & POLLOUT)) ListRemoveItem(mod_s.connect_pending, socket, intcompare); diff --git a/test/test4.c b/test/test4.c index 00385b901..9c34a9715 100644 --- a/test/test4.c +++ b/test/test4.c @@ -277,6 +277,7 @@ void test1_onUnsubscribe(void* context, MQTTAsync_successData* response) MyLog(LOGA_DEBUG, "In onUnsubscribe onSuccess callback %p", c); opts.onSuccess = test1_onDisconnect; opts.context = c; + opts.timeout = 1000; rc = MQTTAsync_disconnect(c, &opts); assert("Disconnect successful", rc == MQTTASYNC_SUCCESS, "rc was %d", rc); @@ -554,6 +555,7 @@ void test3_onUnsubscribe(void* context, MQTTAsync_successData* response) MyLog(LOGA_DEBUG, "In onUnsubscribe onSuccess callback \"%s\"", cd->clientid); opts.onSuccess = test3_onDisconnect; opts.context = cd; + opts.timeout = 1000; rc = MQTTAsync_disconnect(cd->c, &opts); assert("Disconnect successful", rc == MQTTASYNC_SUCCESS, "rc was %d", rc); @@ -1176,6 +1178,7 @@ void test7_onUnsubscribe(void* context, MQTTAsync_successData* response) MyLog(LOGA_DEBUG, "In onUnsubscribe onSuccess callback %p", c); opts.onSuccess = test7_onDisconnect; opts.context = c; + opts.timeout = 1000; rc = MQTTAsync_disconnect(c, &opts); assert("Disconnect successful", rc == MQTTASYNC_SUCCESS, "rc was %d", rc); diff --git a/test/test5.c b/test/test5.c index ba62690a3..4e188c489 100644 --- a/test/test5.c +++ b/test/test5.c @@ -2715,10 +2715,7 @@ int main(int argc, char** argv) } else { - if (options.test_no == 10) - MQTTAsync_setTraceLevel(MQTTASYNC_TRACE_MINIMUM); - else - MQTTAsync_setTraceLevel(MQTTASYNC_TRACE_PROTOCOL); + MQTTAsync_setTraceLevel(MQTTASYNC_TRACE_ERROR); rc = tests[options.test_no](options); /* run just the selected test */ } diff --git a/test/test8.c b/test/test8.c index 6b95afe02..56d86fe1e 100644 --- a/test/test8.c +++ b/test/test8.c @@ -242,6 +242,7 @@ void test1_onUnsubscribe(void* context, MQTTAsync_successData* response) MyLog(LOGA_DEBUG, "In onUnsubscribe onSuccess callback %p", c); opts.onSuccess = test1_onDisconnect; opts.context = c; + opts.timeout = 1000; rc = MQTTAsync_disconnect(c, &opts); assert("Disconnect successful", rc == MQTTASYNC_SUCCESS, "rc was %d", rc); @@ -1104,16 +1105,29 @@ char* test6_topic = "test6_topic"; char* test6_payload = NULL; int test6_connected = 0; int test6_payloadlen = 0; +int test6_message_count = 0; +int test6_disconnected = 0; + + +void test6_onDisconnect(void* context, MQTTAsync_successData* response) +{ + MyLog(LOGA_DEBUG, "In onDisconnect callback"); + test6_disconnected = 1; +} + int test6_messageArrived(void* context, char* topicName, int topicLen, MQTTAsync_message* message) { MQTTAsync c = (MQTTAsync)context; - static int message_count = 0; MyLog(LOGA_DEBUG, "In messageArrived callback %p", c); assert("Message size correct", message->payloadlen == test6_payloadlen, "message size was %d", message->payloadlen); + + MQTTAsync_freeMessage(&message); + MQTTAsync_free(topicName); + return 1; } @@ -1242,9 +1256,11 @@ int test6(struct Options options) { MQTTAsync c, d; MQTTAsync_connectOptions opts = MQTTAsync_connectOptions_initializer; + MQTTAsync_disconnectOptions dopts = MQTTAsync_disconnectOptions_initializer; MQTTAsync_message pubmsg = MQTTAsync_message_initializer; int rc = 0; char* test_topic = "C client test8 - test6"; + int messages_sent = 0; failures = 0; test_finished = 0; @@ -1309,13 +1325,44 @@ int test6(struct Options options) pubmsg.payloadlen = test6_payloadlen = strlen(pubmsg.payload)+1; pubmsg.qos = 1; pubmsg.retained = 0; + while (test_finished == 0 && failures == 0) { rc = MQTTAsync_sendMessage(d, test6_topic, &pubmsg, NULL); assert("Good rc from publish", rc == MQTTASYNC_SUCCESS, "rc was %d", rc); if (rc != MQTTASYNC_SUCCESS) break; + messages_sent++; + + #if defined(_WIN32) + Sleep(1000); + #else + usleep(100000L); + #endif + } + dopts.onSuccess = test6_onDisconnect; + dopts.timeout = 1000; + + dopts.context = d; + rc = MQTTAsync_disconnect(d, &dopts); + test6_disconnected = 0; + assert("Disconnect start successful", rc == MQTTASYNC_SUCCESS, "rc was %d", rc); + while (test6_disconnected == 0) + { + #if defined(_WIN32) + Sleep(1000); + #else + usleep(100000L); + #endif + } + + dopts.context = c; + rc = MQTTAsync_disconnect(c, &dopts); + test6_disconnected = 0; + assert("Disconnect start successful", rc == MQTTASYNC_SUCCESS, "rc was %d", rc); + while (test6_disconnected == 0) + { #if defined(_WIN32) Sleep(1000); #else @@ -1338,7 +1385,7 @@ int test6(struct Options options) void trace_callback(enum MQTTASYNC_TRACE_LEVELS level, char* message) { - if (strstr(message, "onnect") && !strstr(message, "isconnect")) + if ((strstr(message, "onnect") && !strstr(message, "isconnect")) || level == MQTTASYNC_TRACE_ERROR) printf("Trace : %d, %s\n", level, message); } @@ -1372,10 +1419,7 @@ int main(int argc, char** argv) } else { - if (options.test_no == 8) - MQTTAsync_setTraceLevel(MQTTASYNC_TRACE_MINIMUM); - else - MQTTAsync_setTraceLevel(MQTTASYNC_TRACE_ERROR); + MQTTAsync_setTraceLevel(MQTTASYNC_TRACE_ERROR); rc = tests[options.test_no](options); /* run just the selected test */ } From af76f620fac4b9267a2d33e0a60658b1e0fce6b4 Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Sun, 6 Feb 2022 22:38:54 +0000 Subject: [PATCH 48/93] Narrow down test debug --- .github/workflows/build_linux.yml | 2 +- .github/workflows/build_macos.yml | 2 +- appveyor.yml | 2 +- test/test5.c | 2 +- test/test8.c | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build_linux.yml b/.github/workflows/build_linux.yml index 5bd1d200f..171bc6642 100644 --- a/.github/workflows/build_linux.yml +++ b/.github/workflows/build_linux.yml @@ -30,7 +30,7 @@ jobs: - name: run tests run: | cd build.paho - ctest -VV --timeout 600 + ctest -VV --timeout 600 -R "test5-7-ws-big-messages" - name: clean up run: | killall python3 || true diff --git a/.github/workflows/build_macos.yml b/.github/workflows/build_macos.yml index b45d18c99..bfb18c3be 100644 --- a/.github/workflows/build_macos.yml +++ b/.github/workflows/build_macos.yml @@ -30,7 +30,7 @@ jobs: - name: run tests run: | cd build.paho - ctest -VV --timeout 600 + ctest -VV --timeout 600 -R "test5-7-ws-big-messages" - name: clean up run: | killall python3 || true diff --git a/appveyor.yml b/appveyor.yml index 6ab1abb46..e1238697c 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -52,7 +52,7 @@ build_script: nmake - ctest -T test -VV + ctest -T test -VV -R "test8-6-blocked-acks|test5-6-multiple-connections-static|test8-3-multiple-client-objects-simultaneous-working" cd .. diff --git a/test/test5.c b/test/test5.c index 4e188c489..7876b8e78 100644 --- a/test/test5.c +++ b/test/test5.c @@ -2715,7 +2715,7 @@ int main(int argc, char** argv) } else { - MQTTAsync_setTraceLevel(MQTTASYNC_TRACE_ERROR); + MQTTAsync_setTraceLevel(MQTTASYNC_TRACE_MINIMUM); rc = tests[options.test_no](options); /* run just the selected test */ } diff --git a/test/test8.c b/test/test8.c index 56d86fe1e..e155b1cbd 100644 --- a/test/test8.c +++ b/test/test8.c @@ -1419,7 +1419,7 @@ int main(int argc, char** argv) } else { - MQTTAsync_setTraceLevel(MQTTASYNC_TRACE_ERROR); + MQTTAsync_setTraceLevel(MQTTASYNC_TRACE_MINIMUM); rc = tests[options.test_no](options); /* run just the selected test */ } From 9f5a4a322dd7b3d2dc8b894d48b8737f64ba841d Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Mon, 7 Feb 2022 10:01:35 +0000 Subject: [PATCH 49/93] More debugging --- test/test5.c | 2 +- test/test8.c | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/test/test5.c b/test/test5.c index 7876b8e78..4e188c489 100644 --- a/test/test5.c +++ b/test/test5.c @@ -2715,7 +2715,7 @@ int main(int argc, char** argv) } else { - MQTTAsync_setTraceLevel(MQTTASYNC_TRACE_MINIMUM); + MQTTAsync_setTraceLevel(MQTTASYNC_TRACE_ERROR); rc = tests[options.test_no](options); /* run just the selected test */ } diff --git a/test/test8.c b/test/test8.c index e155b1cbd..79aa1b821 100644 --- a/test/test8.c +++ b/test/test8.c @@ -1385,7 +1385,7 @@ int test6(struct Options options) void trace_callback(enum MQTTASYNC_TRACE_LEVELS level, char* message) { - if ((strstr(message, "onnect") && !strstr(message, "isconnect")) || level == MQTTASYNC_TRACE_ERROR) + //if ((strstr(message, "onnect") && !strstr(message, "isconnect")) || level == MQTTASYNC_TRACE_ERROR) printf("Trace : %d, %s\n", level, message); } @@ -1419,7 +1419,10 @@ int main(int argc, char** argv) } else { - MQTTAsync_setTraceLevel(MQTTASYNC_TRACE_MINIMUM); + if (options.test_no == 8) + MQTTAsync_setTraceLevel(MQTTASYNC_TRACE_MINIMUM); + else + MQTTAsync_setTraceLevel(MQTTASYNC_TRACE_ERROR); rc = tests[options.test_no](options); /* run just the selected test */ } From 9500f4b7e2e5578a2661ccd3c4dca633289b5faf Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Mon, 7 Feb 2022 10:29:09 +0000 Subject: [PATCH 50/93] Fix MacOS compile warnings --- src/Log.c | 6 +++--- src/Log.h | 12 ++++++++++-- src/StackTrace.c | 8 ++++---- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/Log.c b/src/Log.c index 6ef09248d..92054db08 100644 --- a/src/Log.c +++ b/src/Log.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009, 2020 IBM Corp. + * Copyright (c) 2009, 2022 IBM Corp. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 @@ -86,7 +86,7 @@ typedef struct #endif int sametime_count; int number; - int thread_id; + thread_id_type thread_id; int depth; char name[MAX_FUNCTION_NAME_LENGTH + 1]; int line; @@ -453,7 +453,7 @@ void Log(enum LOG_LEVELS log_level, int msgno, const char *format, ...) * @param aFormat the printf format string to be used if the message id does not exist * @param ... the printf inserts */ -void Log_stackTrace(enum LOG_LEVELS log_level, int msgno, int thread_id, int current_depth, const char* name, int line, int* rc) +void Log_stackTrace(enum LOG_LEVELS log_level, int msgno, thread_id_type thread_id, int current_depth, const char* name, int line, int* rc) { traceEntry *cur_entry = NULL; diff --git a/src/Log.h b/src/Log.h index 102e31dfd..ae9bb9ef4 100644 --- a/src/Log.h +++ b/src/Log.h @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009, 2013 IBM Corp. + * Copyright (c) 2009, 2022 IBM Corp. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 @@ -18,6 +18,14 @@ #if !defined(LOG_H) #define LOG_H +#if defined(_WIN32) || defined(_WIN64) + #include + #define thread_id_type DWORD +#else + #include + #define thread_id_type pthread_t +#endif + /*BE map LOG_LEVELS { @@ -76,7 +84,7 @@ int Log_initialize(Log_nameValue*); void Log_terminate(void); void Log(enum LOG_LEVELS, int, const char *, ...); -void Log_stackTrace(enum LOG_LEVELS, int, int, int, const char*, int, int*); +void Log_stackTrace(enum LOG_LEVELS, int, thread_id_type, int, const char*, int, int*); typedef void Log_traceCallback(enum LOG_LEVELS level, const char *message); void Log_setTraceCallback(Log_traceCallback* callback); diff --git a/src/StackTrace.c b/src/StackTrace.c index d618b1fe7..0fd61e315 100644 --- a/src/StackTrace.c +++ b/src/StackTrace.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009, 2020 IBM Corp. + * Copyright (c) 2009, 2022 IBM Corp. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 @@ -109,7 +109,7 @@ void StackTrace_entry(const char* name, int line, enum LOG_LEVELS trace_level) if (!setStack(1)) goto exit; if (trace_level != -1) - Log_stackTrace(trace_level, 9, (int)my_thread->id, my_thread->current_depth, name, line, NULL); + Log_stackTrace(trace_level, 9, my_thread->id, my_thread->current_depth, name, line, NULL); strncpy(my_thread->callstack[my_thread->current_depth].name, name, sizeof(my_thread->callstack[0].name)-1); my_thread->callstack[(my_thread->current_depth)++].line = line; if (my_thread->current_depth > my_thread->maxdepth) @@ -133,9 +133,9 @@ void StackTrace_exit(const char* name, int line, void* rc, enum LOG_LEVELS trace if (trace_level != -1) { if (rc == NULL) - Log_stackTrace(trace_level, 10, (int)my_thread->id, my_thread->current_depth, name, line, NULL); + Log_stackTrace(trace_level, 10, my_thread->id, my_thread->current_depth, name, line, NULL); else - Log_stackTrace(trace_level, 11, (int)my_thread->id, my_thread->current_depth, name, line, (int*)rc); + Log_stackTrace(trace_level, 11, my_thread->id, my_thread->current_depth, name, line, (int*)rc); } exit: Thread_unlock_mutex(stack_mutex); From 4a36d346a12eaa0fae6703926a35411daaf06d94 Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Mon, 7 Feb 2022 11:07:14 +0000 Subject: [PATCH 51/93] Debug --- src/Socket.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/Socket.c b/src/Socket.c index 417ab8e5b..91dfb81d1 100644 --- a/src/Socket.c +++ b/src/Socket.c @@ -237,6 +237,17 @@ int isReady(int index) FUNC_ENTRY; +#if defined(_WIN32) || defined(_WIN64) + printf("isReady socket %ld POLLHUP %d POLLNVAL %d POLLIN %d POLLOUT %d\n", +#else + printf("isReady socket %d POLLHUP %d POLLNVAL %d POLLIN %d POLLOUT %d\n", +#endif + *socket, + (mod_s.saved.fds[index].revents & POLLHUP), + (mod_s.saved.fds[index].revents & POLLNVAL), + (mod_s.saved.fds[index].revents & POLLIN), + (mod_s.saved.fds[index].revents & POLLOUT)); + if ((mod_s.saved.fds[index].revents & POLLHUP) || (mod_s.saved.fds[index].revents & POLLNVAL)) ; /* signal work to be done if there is an error on the socket */ else if (ListFindItem(mod_s.connect_pending, socket, intcompare) && From 01b72b55aeb2e3f26bd3231d0635749f53b39e46 Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Mon, 7 Feb 2022 14:31:00 +0000 Subject: [PATCH 52/93] Debug variation --- src/Socket.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Socket.c b/src/Socket.c index 91dfb81d1..5d81fadef 100644 --- a/src/Socket.c +++ b/src/Socket.c @@ -237,6 +237,8 @@ int isReady(int index) FUNC_ENTRY; + if ((mod_s.saved.fds[index].revents & POLLHUP) || (mod_s.saved.fds[index].revents & POLLNVAL)) + //; /* signal work to be done if there is an error on the socket */ #if defined(_WIN32) || defined(_WIN64) printf("isReady socket %ld POLLHUP %d POLLNVAL %d POLLIN %d POLLOUT %d\n", #else @@ -247,9 +249,6 @@ int isReady(int index) (mod_s.saved.fds[index].revents & POLLNVAL), (mod_s.saved.fds[index].revents & POLLIN), (mod_s.saved.fds[index].revents & POLLOUT)); - - if ((mod_s.saved.fds[index].revents & POLLHUP) || (mod_s.saved.fds[index].revents & POLLNVAL)) - ; /* signal work to be done if there is an error on the socket */ else if (ListFindItem(mod_s.connect_pending, socket, intcompare) && (mod_s.saved.fds[index].revents & POLLOUT)) ListRemoveItem(mod_s.connect_pending, socket, intcompare); @@ -690,6 +689,9 @@ int Socket_close(SOCKET socket) } } Log(TRACE_MIN, -1, "Removed socket %d", socket); + + printf("Socket_close:\n"); + StackTrace_printStack(stdout); } else Log(LOG_ERROR, -1, "Failed to remove socket %d", socket); From 51559f5224cc8743e660c0ec8811586d48de3b49 Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Mon, 7 Feb 2022 14:53:04 +0000 Subject: [PATCH 53/93] Debug variation --- src/Socket.c | 2 ++ test/test8.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Socket.c b/src/Socket.c index 5d81fadef..61177b325 100644 --- a/src/Socket.c +++ b/src/Socket.c @@ -691,7 +691,9 @@ int Socket_close(SOCKET socket) Log(TRACE_MIN, -1, "Removed socket %d", socket); printf("Socket_close:\n"); +#if !defined(HIGH_PERFORMANCE) StackTrace_printStack(stdout); +#endif } else Log(LOG_ERROR, -1, "Failed to remove socket %d", socket); diff --git a/test/test8.c b/test/test8.c index 79aa1b821..202554256 100644 --- a/test/test8.c +++ b/test/test8.c @@ -1420,7 +1420,7 @@ int main(int argc, char** argv) else { if (options.test_no == 8) - MQTTAsync_setTraceLevel(MQTTASYNC_TRACE_MINIMUM); + MQTTAsync_setTraceLevel(MQTTASYNC_TRACE_ERROR); else MQTTAsync_setTraceLevel(MQTTASYNC_TRACE_ERROR); rc = tests[options.test_no](options); /* run just the selected test */ From 14fcec24bf704faa9803b3dfae363723683b0f4a Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Mon, 7 Feb 2022 15:04:50 +0000 Subject: [PATCH 54/93] Don't build high perf on Linux (for debug) --- .github/workflows/build_linux.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_linux.yml b/.github/workflows/build_linux.yml index 171bc6642..152edcf49 100644 --- a/.github/workflows/build_linux.yml +++ b/.github/workflows/build_linux.yml @@ -17,7 +17,7 @@ jobs: mkdir build.paho cd build.paho echo "pwd $PWD" - cmake -DPAHO_BUILD_STATIC=FALSE -DPAHO_BUILD_SHARED=TRUE -DCMAKE_BUILD_TYPE=Debug -DPAHO_WITH_SSL=TRUE -DOPENSSL_ROOT_DIR= -DPAHO_BUILD_DOCUMENTATION=FALSE -DPAHO_BUILD_SAMPLES=TRUE -DPAHO_HIGH_PERFORMANCE=TRUE .. + cmake -DPAHO_BUILD_STATIC=FALSE -DPAHO_BUILD_SHARED=TRUE -DCMAKE_BUILD_TYPE=Debug -DPAHO_WITH_SSL=TRUE -DOPENSSL_ROOT_DIR= -DPAHO_BUILD_DOCUMENTATION=FALSE -DPAHO_BUILD_SAMPLES=TRUE -DPAHO_HIGH_PERFORMANCE=FALSE .. cmake --build . - name: Start test broker run: | From 35a29737a2ccee3e9ee4b70135bc9b196ebed715 Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Mon, 7 Feb 2022 17:45:14 +0000 Subject: [PATCH 55/93] Fix return code from getrawsocketdata --- src/WebSocket.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/WebSocket.c b/src/WebSocket.c index 25b1eecdf..4870f9160 100644 --- a/src/WebSocket.c +++ b/src/WebSocket.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2018, 2021 Wind River Systems, Inc., Ian Craggs and others + * Copyright (c) 2018, 2022 Wind River Systems, Inc., Ian Craggs and others * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 @@ -780,7 +780,7 @@ char *WebSocket_getRawSocketData(networkHandles *net, size_t bytes, size_t* actu *actual_len = bytes; rv = frame_buffer + frame_buffer_index; frame_buffer_index += bytes; - + *rc = (int)bytes; goto exit; } else From 60bf17c36e8a4b74c635d857e243458ea14fc3b3 Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Mon, 7 Feb 2022 18:11:08 +0000 Subject: [PATCH 56/93] Remove debugging for Linux/MacOS --- .github/workflows/build_linux.yml | 4 ++-- .github/workflows/build_macos.yml | 2 +- src/Socket.c | 17 +---------------- 3 files changed, 4 insertions(+), 19 deletions(-) diff --git a/.github/workflows/build_linux.yml b/.github/workflows/build_linux.yml index 152edcf49..5bd1d200f 100644 --- a/.github/workflows/build_linux.yml +++ b/.github/workflows/build_linux.yml @@ -17,7 +17,7 @@ jobs: mkdir build.paho cd build.paho echo "pwd $PWD" - cmake -DPAHO_BUILD_STATIC=FALSE -DPAHO_BUILD_SHARED=TRUE -DCMAKE_BUILD_TYPE=Debug -DPAHO_WITH_SSL=TRUE -DOPENSSL_ROOT_DIR= -DPAHO_BUILD_DOCUMENTATION=FALSE -DPAHO_BUILD_SAMPLES=TRUE -DPAHO_HIGH_PERFORMANCE=FALSE .. + cmake -DPAHO_BUILD_STATIC=FALSE -DPAHO_BUILD_SHARED=TRUE -DCMAKE_BUILD_TYPE=Debug -DPAHO_WITH_SSL=TRUE -DOPENSSL_ROOT_DIR= -DPAHO_BUILD_DOCUMENTATION=FALSE -DPAHO_BUILD_SAMPLES=TRUE -DPAHO_HIGH_PERFORMANCE=TRUE .. cmake --build . - name: Start test broker run: | @@ -30,7 +30,7 @@ jobs: - name: run tests run: | cd build.paho - ctest -VV --timeout 600 -R "test5-7-ws-big-messages" + ctest -VV --timeout 600 - name: clean up run: | killall python3 || true diff --git a/.github/workflows/build_macos.yml b/.github/workflows/build_macos.yml index bfb18c3be..6d69b479c 100644 --- a/.github/workflows/build_macos.yml +++ b/.github/workflows/build_macos.yml @@ -30,7 +30,7 @@ jobs: - name: run tests run: | cd build.paho - ctest -VV --timeout 600 -R "test5-7-ws-big-messages" + ctest -VV --timeout 600 - name: clean up run: | killall python3 || true diff --git a/src/Socket.c b/src/Socket.c index 61177b325..417ab8e5b 100644 --- a/src/Socket.c +++ b/src/Socket.c @@ -238,17 +238,7 @@ int isReady(int index) FUNC_ENTRY; if ((mod_s.saved.fds[index].revents & POLLHUP) || (mod_s.saved.fds[index].revents & POLLNVAL)) - //; /* signal work to be done if there is an error on the socket */ -#if defined(_WIN32) || defined(_WIN64) - printf("isReady socket %ld POLLHUP %d POLLNVAL %d POLLIN %d POLLOUT %d\n", -#else - printf("isReady socket %d POLLHUP %d POLLNVAL %d POLLIN %d POLLOUT %d\n", -#endif - *socket, - (mod_s.saved.fds[index].revents & POLLHUP), - (mod_s.saved.fds[index].revents & POLLNVAL), - (mod_s.saved.fds[index].revents & POLLIN), - (mod_s.saved.fds[index].revents & POLLOUT)); + ; /* signal work to be done if there is an error on the socket */ else if (ListFindItem(mod_s.connect_pending, socket, intcompare) && (mod_s.saved.fds[index].revents & POLLOUT)) ListRemoveItem(mod_s.connect_pending, socket, intcompare); @@ -689,11 +679,6 @@ int Socket_close(SOCKET socket) } } Log(TRACE_MIN, -1, "Removed socket %d", socket); - - printf("Socket_close:\n"); -#if !defined(HIGH_PERFORMANCE) - StackTrace_printStack(stdout); -#endif } else Log(LOG_ERROR, -1, "Failed to remove socket %d", socket); From 33880dff72dbf8a331819f70f98a11eb72dee525 Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Tue, 8 Feb 2022 15:17:19 +0000 Subject: [PATCH 57/93] Don't call poll if no sockets --- src/Socket.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Socket.c b/src/Socket.c index 417ab8e5b..12d709735 100644 --- a/src/Socket.c +++ b/src/Socket.c @@ -294,6 +294,12 @@ SOCKET Socket_getReadySocket(int more_work, int timeout, mutex_type mutex, int* } memcpy(mod_s.saved.fds, mod_s.fds, mod_s.nfds * sizeof(struct pollfd)); + if (mod_s.saved.nfds == 0) + { + sock = 0; + goto exit; /* no work to do */ + } + /* Prevent performance issue by unlocking the socket_mutex while waiting for a ready socket. */ Thread_unlock_mutex(mutex); *rc = poll(mod_s.saved.fds, mod_s.saved.nfds, timeout_ms); From be636e0b84ef7a11e3a384b097b1c60bcf745786 Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Tue, 8 Feb 2022 17:51:38 +0000 Subject: [PATCH 58/93] Add test8 debug --- test/test8.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/test8.c b/test/test8.c index 202554256..f0bb1d055 100644 --- a/test/test8.c +++ b/test/test8.c @@ -1194,6 +1194,7 @@ void test6_onSubscribe(void* context, MQTTAsync_successData* response) if (test6_payload == NULL) { test6_payload = malloc(options.size); + memset(test6_payload, ' ', options.size); } MyLog(LOGA_INFO, "In subscribe onSuccess callback, context %p", context); @@ -1420,7 +1421,7 @@ int main(int argc, char** argv) else { if (options.test_no == 8) - MQTTAsync_setTraceLevel(MQTTASYNC_TRACE_ERROR); + MQTTAsync_setTraceLevel(MQTTASYNC_TRACE_MINIMUM); else MQTTAsync_setTraceLevel(MQTTASYNC_TRACE_ERROR); rc = tests[options.test_no](options); /* run just the selected test */ From 897aad789b6187705ff5017a29d79f84878bcaf9 Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Tue, 8 Feb 2022 20:19:23 +0000 Subject: [PATCH 59/93] Debug for test 8 --- src/MQTTAsyncUtils.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/MQTTAsyncUtils.c b/src/MQTTAsyncUtils.c index 3c5076510..2288a5b2d 100644 --- a/src/MQTTAsyncUtils.c +++ b/src/MQTTAsyncUtils.c @@ -1093,10 +1093,13 @@ void MQTTAsync_writeComplete(SOCKET socket, int rc) if (cur_response) /* we found a response */ { + printf("writeComplete: cur_response\n"); if (command->type == PUBLISH) { + printf("writeComplete: PUBLISH %d %d\n", rc, command->details.pub.qos); if (rc == 1 && command->details.pub.qos == 0) { + printf("writeComplete: rc 1 onSuccess %p\n", command->onSuccess); if (command->onSuccess) { MQTTAsync_successData data; From fa410ae37daf0626d926965c9e0178be7721e908 Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Tue, 8 Feb 2022 21:44:34 +0000 Subject: [PATCH 60/93] More test8 debug --- test/test8.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/test8.c b/test/test8.c index f0bb1d055..2100dfaca 100644 --- a/test/test8.c +++ b/test/test8.c @@ -1158,6 +1158,7 @@ void test6_onPublish(void* context, MQTTAsync_successData* response) if (test6_payload == NULL) { test6_payload = malloc(options.size); + memset(test6_payload, ' ', options.size); } MyLog(LOGA_DEBUG, "In publish onSuccess callback, context %p", context); @@ -1170,10 +1171,12 @@ void test6_onPublish(void* context, MQTTAsync_successData* response) opts.onFailure = test6_onPublishFailure; opts.context = c; + MyLog(LOGA_INFO, "Calling sendMessage, count %d", publish_count); rc = MQTTAsync_sendMessage(c, "test6_big_messages", &pubmsg, &opts); + MyLog(LOGA_INFO, "Called sendMessage, count %d rc %d", publish_count, rc); assert("Good rc from publish", rc == MQTTASYNC_SUCCESS, "rc was %d", rc); exit: - MyLog(LOGA_DEBUG, "Leaving publish onSuccess callback, context %p", context); + MyLog(LOGA_DEBUG, "Leaving publish onSuccess callback, count %d, context %p", publish_count, context); } From f3c5df63764c9f7d96cc243fff7a99d85cc76a23 Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Tue, 8 Feb 2022 23:00:31 +0000 Subject: [PATCH 61/93] Some locking for callbacks --- src/MQTTAsyncUtils.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/MQTTAsyncUtils.c b/src/MQTTAsyncUtils.c index 2288a5b2d..60daa587f 100644 --- a/src/MQTTAsyncUtils.c +++ b/src/MQTTAsyncUtils.c @@ -1065,8 +1065,9 @@ void MQTTAsync_writeComplete(SOCKET socket, int rc) ListElement* found = NULL; FUNC_ENTRY; - /* a partial write is now complete for a socket - this will be on a publish*/ + /* a partial write is now complete for a socket - this will be on a publish*/ + MQTTAsync_lock_mutex(mqttasync_mutex); MQTTProtocol_checkPendingWrites(); /* find the client using this socket */ @@ -1170,6 +1171,7 @@ void MQTTAsync_writeComplete(SOCKET socket, int rc) m->pending_write = NULL; } /* if pending_write */ } + MQTTAsync_unlock_mutex(mqttasync_mutex); FUNC_EXIT; } From 7004cb8a28ddaf522b4f53847627cb342d6ae7a1 Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Wed, 9 Feb 2022 10:49:39 +0000 Subject: [PATCH 62/93] Fix test8 and remove debug printfs --- src/MQTTAsyncUtils.c | 3 --- test/test8.c | 10 ++++++---- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/MQTTAsyncUtils.c b/src/MQTTAsyncUtils.c index 60daa587f..550569065 100644 --- a/src/MQTTAsyncUtils.c +++ b/src/MQTTAsyncUtils.c @@ -1094,13 +1094,10 @@ void MQTTAsync_writeComplete(SOCKET socket, int rc) if (cur_response) /* we found a response */ { - printf("writeComplete: cur_response\n"); if (command->type == PUBLISH) { - printf("writeComplete: PUBLISH %d %d\n", rc, command->details.pub.qos); if (rc == 1 && command->details.pub.qos == 0) { - printf("writeComplete: rc 1 onSuccess %p\n", command->onSuccess); if (command->onSuccess) { MQTTAsync_successData data; diff --git a/test/test8.c b/test/test8.c index 2100dfaca..f92dfc37e 100644 --- a/test/test8.c +++ b/test/test8.c @@ -1265,6 +1265,7 @@ int test6(struct Options options) int rc = 0; char* test_topic = "C client test8 - test6"; int messages_sent = 0; + int count = 0; failures = 0; test_finished = 0; @@ -1349,10 +1350,10 @@ int test6(struct Options options) dopts.timeout = 1000; dopts.context = d; - rc = MQTTAsync_disconnect(d, &dopts); test6_disconnected = 0; + rc = MQTTAsync_disconnect(d, &dopts); assert("Disconnect start successful", rc == MQTTASYNC_SUCCESS, "rc was %d", rc); - while (test6_disconnected == 0) + while (test6_disconnected == 0 && ++count < 5) { #if defined(_WIN32) Sleep(1000); @@ -1362,10 +1363,11 @@ int test6(struct Options options) } dopts.context = c; - rc = MQTTAsync_disconnect(c, &dopts); test6_disconnected = 0; + rc = MQTTAsync_disconnect(c, &dopts); assert("Disconnect start successful", rc == MQTTASYNC_SUCCESS, "rc was %d", rc); - while (test6_disconnected == 0) + count = 0; + while (test6_disconnected == 0 && ++count < 5) { #if defined(_WIN32) Sleep(1000); From 487d3a574f947b8a2b0ecd6349b8ea13c751f4c1 Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Wed, 9 Feb 2022 10:51:50 +0000 Subject: [PATCH 63/93] Remove test8 extra trace --- test/test8.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/test/test8.c b/test/test8.c index f92dfc37e..76dca58de 100644 --- a/test/test8.c +++ b/test/test8.c @@ -1425,10 +1425,7 @@ int main(int argc, char** argv) } else { - if (options.test_no == 8) - MQTTAsync_setTraceLevel(MQTTASYNC_TRACE_MINIMUM); - else - MQTTAsync_setTraceLevel(MQTTASYNC_TRACE_ERROR); + MQTTAsync_setTraceLevel(MQTTASYNC_TRACE_ERROR); rc = tests[options.test_no](options); /* run just the selected test */ } From 5b240c29a1c594c23d1d220e1ddd2d8591d1605f Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Wed, 9 Feb 2022 11:11:16 +0000 Subject: [PATCH 64/93] Reinstate all Windows tests --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index e1238697c..6ab1abb46 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -52,7 +52,7 @@ build_script: nmake - ctest -T test -VV -R "test8-6-blocked-acks|test5-6-multiple-connections-static|test8-3-multiple-client-objects-simultaneous-working" + ctest -T test -VV cd .. From 932cfbb62c021ad7ccf0d1f50d0179b99458caab Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Wed, 9 Feb 2022 20:25:19 +0000 Subject: [PATCH 65/93] Fix memmove length calculation --- src/Socket.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Socket.c b/src/Socket.c index 12d709735..df7b343f4 100644 --- a/src/Socket.c +++ b/src/Socket.c @@ -675,7 +675,7 @@ int Socket_close(SOCKET socket) if (fd != last_fd) { /* shift array to remove the socket in question */ - memmove(fd, fd + 1, (mod_s.fds + (mod_s.nfds * sizeof(struct pollfd))) - fd); + memmove(fd, fd + 1, (mod_s.nfds - (fd - mod_s.fds)) * sizeof(mod_s.fds[0])); } mod_s.fds = realloc(mod_s.fds, sizeof(mod_s.fds[0]) * mod_s.nfds); if (mod_s.fds == NULL) From de5e9509f7bff1e6b55f95fbc9d4e023b5babd97 Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Mon, 7 Feb 2022 17:45:14 +0000 Subject: [PATCH 66/93] Fix return code from getrawsocketdata --- src/WebSocket.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/WebSocket.c b/src/WebSocket.c index 25b1eecdf..4870f9160 100644 --- a/src/WebSocket.c +++ b/src/WebSocket.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2018, 2021 Wind River Systems, Inc., Ian Craggs and others + * Copyright (c) 2018, 2022 Wind River Systems, Inc., Ian Craggs and others * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 @@ -780,7 +780,7 @@ char *WebSocket_getRawSocketData(networkHandles *net, size_t bytes, size_t* actu *actual_len = bytes; rv = frame_buffer + frame_buffer_index; frame_buffer_index += bytes; - + *rc = (int)bytes; goto exit; } else From 5780587c0e19f6053a06f171dfe3f619d328b6a8 Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Tue, 8 Feb 2022 23:00:31 +0000 Subject: [PATCH 67/93] Some locking for callbacks --- src/MQTTAsyncUtils.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/MQTTAsyncUtils.c b/src/MQTTAsyncUtils.c index a7dc35e08..1a13b9ee6 100644 --- a/src/MQTTAsyncUtils.c +++ b/src/MQTTAsyncUtils.c @@ -1065,8 +1065,9 @@ void MQTTAsync_writeComplete(int socket, int rc) ListElement* found = NULL; FUNC_ENTRY; - /* a partial write is now complete for a socket - this will be on a publish*/ + /* a partial write is now complete for a socket - this will be on a publish*/ + MQTTAsync_lock_mutex(mqttasync_mutex); MQTTProtocol_checkPendingWrites(); /* find the client using this socket */ @@ -1167,6 +1168,7 @@ void MQTTAsync_writeComplete(int socket, int rc) m->pending_write = NULL; } /* if pending_write */ } + MQTTAsync_unlock_mutex(mqttasync_mutex); FUNC_EXIT; } From 1964b6697a021254399a8f7a7d1d3b95ecf4ad4e Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Thu, 10 Feb 2022 18:09:15 +0000 Subject: [PATCH 68/93] Correct freeing of some persistence buffers --- src/MQTTAsyncUtils.c | 8 ++++---- src/MQTTPersistence.c | 5 +++-- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/MQTTAsyncUtils.c b/src/MQTTAsyncUtils.c index 1a13b9ee6..a3e152714 100644 --- a/src/MQTTAsyncUtils.c +++ b/src/MQTTAsyncUtils.c @@ -662,14 +662,14 @@ int MQTTAsync_restoreCommands(MQTTAsyncs* client) cmd->seqno = atoi(strchr(msgkeys[i], '-')+1); /* key format is tag'-'seqno */ /* we can just append the commands to the list as they've already been sorted */ ListAppend(MQTTAsync_commands, cmd, sizeof(MQTTAsync_queuedCommand)); - if (buffer) - free(buffer); client->command_seqno = max(client->command_seqno, cmd->seqno); commands_restored++; if (cmd->command.type == PUBLISH) client->noBufferedMessages++; } } + if (buffer) + free(buffer); if (msgkeys[i]) free(msgkeys[i]); i++; @@ -1246,11 +1246,11 @@ static int MQTTAsync_processCommand(void) free(command->key); command->key = NULL; command = MQTTAsync_restoreCommand(buffer, buflen, MQTTVersion, command); - if (buffer) - free(buffer); } else Log(LOG_ERROR, -1, "Error restoring command: rc %d from pget\n", rc); + if (buffer) + free(buffer); } MQTTAsync_unpersistCommand(command); } diff --git a/src/MQTTPersistence.c b/src/MQTTPersistence.c index c5634ded4..fcc77c9fb 100644 --- a/src/MQTTPersistence.c +++ b/src/MQTTPersistence.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009, 2020 IBM Corp. + * Copyright (c) 2009, 2022 IBM Corp. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 @@ -886,10 +886,11 @@ int MQTTPersistence_restoreMessageQueue(Clients* c) { qe->seqno = atoi(strchr(msgkeys[i], '-')+1); /* key format is tag'-'seqno */ MQTTPersistence_insertInSeqOrder(c->messageQueue, qe, sizeof(MQTTPersistence_qEntry)); - free(buffer); c->qentry_seqno = max(c->qentry_seqno, qe->seqno); entries_restored++; } + if (buffer) + free(buffer); } if (msgkeys[i]) { From 8d37b94c38c32d4fbf1df92f89761bb58d6882b2 Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Thu, 10 Feb 2022 18:09:15 +0000 Subject: [PATCH 69/93] Correct freeing of some persistence buffers --- src/MQTTAsyncUtils.c | 8 ++++---- src/MQTTPersistence.c | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/MQTTAsyncUtils.c b/src/MQTTAsyncUtils.c index 550569065..a6dd71b77 100644 --- a/src/MQTTAsyncUtils.c +++ b/src/MQTTAsyncUtils.c @@ -662,14 +662,14 @@ int MQTTAsync_restoreCommands(MQTTAsyncs* client) cmd->seqno = atoi(strchr(msgkeys[i], '-')+1); /* key format is tag'-'seqno */ /* we can just append the commands to the list as they've already been sorted */ ListAppend(MQTTAsync_commands, cmd, sizeof(MQTTAsync_queuedCommand)); - if (buffer) - free(buffer); client->command_seqno = max(client->command_seqno, cmd->seqno); commands_restored++; if (cmd->command.type == PUBLISH) client->noBufferedMessages++; } } + if (buffer) + free(buffer); if (msgkeys[i]) free(msgkeys[i]); i++; @@ -1246,11 +1246,11 @@ static int MQTTAsync_processCommand(void) free(command->key); command->key = NULL; command = MQTTAsync_restoreCommand(buffer, buflen, MQTTVersion, command); - if (buffer) - free(buffer); } else Log(LOG_ERROR, -1, "Error restoring command: rc %d from pget\n", rc); + if (buffer) + free(buffer); } MQTTAsync_unpersistCommand(command); } diff --git a/src/MQTTPersistence.c b/src/MQTTPersistence.c index 7c156245b..7e6e11e8d 100644 --- a/src/MQTTPersistence.c +++ b/src/MQTTPersistence.c @@ -886,10 +886,11 @@ int MQTTPersistence_restoreMessageQueue(Clients* c) { qe->seqno = atoi(strchr(msgkeys[i], '-')+1); /* key format is tag'-'seqno */ MQTTPersistence_insertInSeqOrder(c->messageQueue, qe, sizeof(MQTTPersistence_qEntry)); - free(buffer); c->qentry_seqno = max(c->qentry_seqno, qe->seqno); entries_restored++; } + if (buffer) + free(buffer); } if (msgkeys[i]) { From 4b1389e6d8f60ece6a4e4770fc37446f2613cf34 Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Thu, 10 Feb 2022 18:09:15 +0000 Subject: [PATCH 70/93] Correct freeing of some persistence buffers --- src/MQTTAsyncUtils.c | 8 ++++---- src/MQTTPersistence.c | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/MQTTAsyncUtils.c b/src/MQTTAsyncUtils.c index 550569065..a6dd71b77 100644 --- a/src/MQTTAsyncUtils.c +++ b/src/MQTTAsyncUtils.c @@ -662,14 +662,14 @@ int MQTTAsync_restoreCommands(MQTTAsyncs* client) cmd->seqno = atoi(strchr(msgkeys[i], '-')+1); /* key format is tag'-'seqno */ /* we can just append the commands to the list as they've already been sorted */ ListAppend(MQTTAsync_commands, cmd, sizeof(MQTTAsync_queuedCommand)); - if (buffer) - free(buffer); client->command_seqno = max(client->command_seqno, cmd->seqno); commands_restored++; if (cmd->command.type == PUBLISH) client->noBufferedMessages++; } } + if (buffer) + free(buffer); if (msgkeys[i]) free(msgkeys[i]); i++; @@ -1246,11 +1246,11 @@ static int MQTTAsync_processCommand(void) free(command->key); command->key = NULL; command = MQTTAsync_restoreCommand(buffer, buflen, MQTTVersion, command); - if (buffer) - free(buffer); } else Log(LOG_ERROR, -1, "Error restoring command: rc %d from pget\n", rc); + if (buffer) + free(buffer); } MQTTAsync_unpersistCommand(command); } diff --git a/src/MQTTPersistence.c b/src/MQTTPersistence.c index 7c156245b..7e6e11e8d 100644 --- a/src/MQTTPersistence.c +++ b/src/MQTTPersistence.c @@ -886,10 +886,11 @@ int MQTTPersistence_restoreMessageQueue(Clients* c) { qe->seqno = atoi(strchr(msgkeys[i], '-')+1); /* key format is tag'-'seqno */ MQTTPersistence_insertInSeqOrder(c->messageQueue, qe, sizeof(MQTTPersistence_qEntry)); - free(buffer); c->qentry_seqno = max(c->qentry_seqno, qe->seqno); entries_restored++; } + if (buffer) + free(buffer); } if (msgkeys[i]) { From 90c3916819657d73a5b082ce2a2eaf1839795886 Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Fri, 11 Feb 2022 15:55:52 +0000 Subject: [PATCH 71/93] Allow old select code to be used optionally --- CMakeLists.txt | 14 ++- src/Clients.c | 2 +- src/SSLSocket.c | 4 +- src/Socket.c | 283 ++++++++++++++++++++++++++++++++++++++++++++++-- src/Socket.h | 9 ++ travis-build.sh | 2 +- 6 files changed, 300 insertions(+), 14 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7bfee10e4..a8bfd7dbb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,10 +36,6 @@ INCLUDE(GNUInstallDirs) STRING(TIMESTAMP BUILD_TIMESTAMP UTC) MESSAGE(STATUS "Timestamp is ${BUILD_TIMESTAMP}") -IF (PAHO_HIGH_PERFORMANCE) - ADD_DEFINITIONS(-DHIGH_PERFORMANCE=1) -ENDIF() - IF(WIN32) ADD_DEFINITIONS(-D_CRT_SECURE_NO_DEPRECATE -DWIN32_LEAN_AND_MEAN -MD) ELSEIF(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") @@ -55,6 +51,16 @@ SET(PAHO_BUILD_SAMPLES FALSE CACHE BOOL "Build sample programs") SET(PAHO_BUILD_DEB_PACKAGE FALSE CACHE BOOL "Build debian package") SET(PAHO_ENABLE_TESTING TRUE CACHE BOOL "Build tests and run") SET(PAHO_ENABLE_CPACK TRUE CACHE BOOL "Enable CPack") +SET(PAHO_HIGH_PERFORMANCE FALSE CACHE BOOL "Disable tracing and heap tracking") +SET(PAHO_USE_SELECT FALSE CACHE BOOL "Revert to select system call instead of poll") + +IF (PAHO_HIGH_PERFORMANCE) + ADD_DEFINITIONS(-DHIGH_PERFORMANCE=1) +ENDIF() + +IF (PAHO_USE_SELECT) + ADD_DEFINITIONS(-DUSE_SELECT=1) +ENDIF() IF (NOT PAHO_BUILD_SHARED AND NOT PAHO_BUILD_STATIC) MESSAGE(FATAL_ERROR "You must set either PAHO_BUILD_SHARED, PAHO_BUILD_STATIC, or both") diff --git a/src/Clients.c b/src/Clients.c index b22bf8340..9e70e48b8 100644 --- a/src/Clients.c +++ b/src/Clients.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009, 2013 IBM Corp. + * Copyright (c) 2009, 2022 IBM Corp. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 diff --git a/src/SSLSocket.c b/src/SSLSocket.c index ac046a6d0..3515bdff3 100644 --- a/src/SSLSocket.c +++ b/src/SSLSocket.c @@ -1014,7 +1014,9 @@ int SSLSocket_putdatas(SSL* ssl, SOCKET socket, char* buf0, size_t buf0len, Pack SocketBuffer_pendingWrite(socket, ssl, 1, &iovec, &free, iovec.iov_len, 0); *sockmem = socket; ListAppend(mod_s.write_pending, sockmem, sizeof(int)); - //FD_SET(socket, &(mod_s.pending_wset)); +#if defined(USE_SELECT) + FD_SET(socket, &(mod_s.pending_wset)); +#endif rc = TCPSOCKET_INTERRUPTED; } else diff --git a/src/Socket.c b/src/Socket.c index df7b343f4..ec68180b5 100644 --- a/src/Socket.c +++ b/src/Socket.c @@ -44,14 +44,19 @@ #include "Heap.h" +#if defined(USE_SELECT) +int isReady(int socket, fd_set* read_set, fd_set* write_set); +int Socket_continueWrites(fd_set* pwset, int* socket, mutex_type mutex); +#else +int isReady(int index); +int Socket_continueWrites(SOCKET* socket, mutex_type mutex); +#endif int Socket_setnonblocking(SOCKET sock); int Socket_error(char* aString, SOCKET sock); int Socket_addSocket(SOCKET newSd); -int isReady(int index); int Socket_writev(SOCKET socket, iobuf* iovecs, int count, unsigned long* bytes); int Socket_close_only(SOCKET socket); int Socket_continueWrite(SOCKET socket); -int Socket_continueWrites(SOCKET* socket, mutex_type mutex); char* Socket_getaddrname(struct sockaddr* sa, SOCKET sock); int Socket_abortWrite(SOCKET socket); @@ -65,6 +70,9 @@ int Socket_abortWrite(SOCKET socket); * Structure to hold all socket data for this module */ Sockets mod_s; +#if defined(USE_SELECT) +static fd_set wset; +#endif /** * Set a socket non-blocking, OS independently @@ -135,13 +143,22 @@ void Socket_outInitialize(void) SocketBuffer_initialize(); mod_s.connect_pending = ListInitialize(); mod_s.write_pending = ListInitialize(); - + +#if defined(USE_SELECT) + mod_s.clientsds = ListInitialize(); + mod_s.cur_clientsds = NULL; + FD_ZERO(&(mod_s.rset)); /* Initialize the descriptor set */ + FD_ZERO(&(mod_s.pending_wset)); + mod_s.maxfdp1 = 0; + memcpy((void*)&(mod_s.rset_saved), (void*)&(mod_s.rset), sizeof(mod_s.rset_saved)); +#else mod_s.nfds = 0; mod_s.fds = NULL; mod_s.saved.cur_fd = -1; mod_s.saved.fds = NULL; mod_s.saved.nfds = 0; +#endif FUNC_EXIT; } @@ -154,10 +171,14 @@ void Socket_outTerminate(void) FUNC_ENTRY; ListFree(mod_s.connect_pending); ListFree(mod_s.write_pending); +#if defined(USE_SELECT) + ListFree(mod_s.clientsds); +#else if (mod_s.fds) free(mod_s.fds); if (mod_s.saved.fds) free(mod_s.saved.fds); +#endif SocketBuffer_terminate(); #if defined(_WIN32) || defined(_WIN64) WSACleanup(); @@ -166,6 +187,54 @@ void Socket_outTerminate(void) } +#if defined(USE_SELECT) +/** + * Add a socket to the list of socket to check with select + * @param newSd the new socket to add + */ +int Socket_addSocket(int newSd) +{ + int rc = 0; + + FUNC_ENTRY; + if (ListFindItem(mod_s.clientsds, &newSd, intcompare) == NULL) /* make sure we don't add the same socket twice */ + { + if (mod_s.clientsds->count >= FD_SETSIZE) + { + Log(LOG_ERROR, -1, "addSocket: exceeded FD_SETSIZE %d", FD_SETSIZE); + rc = SOCKET_ERROR; + } + else + { + int* pnewSd = (int*)malloc(sizeof(newSd)); + + if (!pnewSd) + { + rc = PAHO_MEMORY_ERROR; + goto exit; + } + *pnewSd = newSd; + if (!ListAppend(mod_s.clientsds, pnewSd, sizeof(newSd))) + { + free(pnewSd); + rc = PAHO_MEMORY_ERROR; + goto exit; + } + FD_SET(newSd, &(mod_s.rset_saved)); + mod_s.maxfdp1 = max(mod_s.maxfdp1, newSd + 1); + rc = Socket_setnonblocking(newSd); + if (rc == SOCKET_ERROR) + Log(LOG_ERROR, -1, "addSocket: setnonblocking"); + } + } + else + Log(LOG_ERROR, -1, "addSocket: socket %d already in the list", newSd); + +exit: + FUNC_EXIT_RC(rc); + return rc; +} +#else static int cmpfds(const void *p1, const void *p2) { SOCKET key1 = ((struct pollfd*)p1)->fd; @@ -222,8 +291,31 @@ int Socket_addSocket(SOCKET newSd) FUNC_EXIT_RC(rc); return rc; } +#endif +#if defined(USE_SELECT) +/** + * Don't accept work from a client unless it is accepting work back, i.e. its socket is writeable + * this seems like a reasonable form of flow control, and practically, seems to work. + * @param socket the socket to check + * @param read_set the socket read set (see select doc) + * @param write_set the socket write set (see select doc) + * @return boolean - is the socket ready to go? + */ +int isReady(int socket, fd_set* read_set, fd_set* write_set) +{ + int rc = 1; + + FUNC_ENTRY; + if (ListFindItem(mod_s.connect_pending, &socket, intcompare) && FD_ISSET(socket, write_set)) + ListRemoveItem(mod_s.connect_pending, &socket, intcompare); + else + rc = FD_ISSET(socket, read_set) && FD_ISSET(socket, write_set) && Socket_noPendingWrites(socket); + FUNC_EXIT_RC(rc); + return rc; +} +#else /** * Don't accept work from a client unless it is accepting work back, i.e. its socket is writeable * this seems like a reasonable form of flow control, and practically, seems to work. @@ -249,8 +341,113 @@ int isReady(int index) FUNC_EXIT_RC(rc); return rc; } +#endif + + +#if defined(USE_SELECT) +/** + * Returns the next socket ready for communications as indicated by select + * @param more_work flag to indicate more work is waiting, and thus a timeout value of 0 should + * be used for the select + * @param timeout the timeout to be used for the select, unless overridden + * @param rc a value other than 0 indicates an error of the returned socket + * @return the socket next ready, or 0 if none is ready + */ +int Socket_getReadySocket(int more_work, int timeout, mutex_type mutex, int* rc) +{ + int sock = 0; + *rc = 0; + int timeout_ms = 1000; + + FUNC_ENTRY; + Thread_lock_mutex(mutex); + if (mod_s.clientsds->count == 0) + goto exit; + + if (more_work) + timeout_ms = 0; + else if (timeout >= 0) + timeout_ms = timeout; + + while (mod_s.cur_clientsds != NULL) + { + if (isReady(*((int*)(mod_s.cur_clientsds->content)), &(mod_s.rset), &wset)) + break; + ListNextElement(mod_s.clientsds, &mod_s.cur_clientsds); + } + + if (mod_s.cur_clientsds == NULL) + { + static struct timeval zero = {0L, 0L}; /* 0 seconds */ + int rc1, maxfdp1_saved; + fd_set pwset; + struct timeval timeout_tv = {0L, timeout_ms*1000}; + + memcpy((void*)&(mod_s.rset), (void*)&(mod_s.rset_saved), sizeof(mod_s.rset)); + memcpy((void*)&(pwset), (void*)&(mod_s.pending_wset), sizeof(pwset)); + maxfdp1_saved = mod_s.maxfdp1; + + if (maxfdp1_saved == 0) + { + sock = 0; + goto exit; /* no work to do */ + } + /* Prevent performance issue by unlocking the socket_mutex while waiting for a ready socket. */ + Thread_unlock_mutex(mutex); + *rc = select(maxfdp1_saved, &(mod_s.rset), &pwset, NULL, &timeout_tv); + Thread_lock_mutex(mutex); + if (*rc == SOCKET_ERROR) + { + Socket_error("read select", 0); + goto exit; + } + Log(TRACE_MAX, -1, "Return code %d from read select", *rc); + + if (Socket_continueWrites(&pwset, &sock, mutex) == SOCKET_ERROR) + { + *rc = SOCKET_ERROR; + goto exit; + } + + memcpy((void*)&wset, (void*)&(mod_s.rset_saved), sizeof(wset)); + if ((rc1 = select(mod_s.maxfdp1, NULL, &(wset), NULL, &zero)) == SOCKET_ERROR) + { + Socket_error("write select", 0); + *rc = rc1; + goto exit; + } + Log(TRACE_MAX, -1, "Return code %d from write select", rc1); + if (*rc == 0 && rc1 == 0) + { + sock = 0; + goto exit; /* no work to do */ + } + mod_s.cur_clientsds = mod_s.clientsds->first; + while (mod_s.cur_clientsds != NULL) + { + int cursock = *((int*)(mod_s.cur_clientsds->content)); + if (isReady(cursock, &(mod_s.rset), &wset)) + break; + ListNextElement(mod_s.clientsds, &mod_s.cur_clientsds); + } + } + + *rc = 0; + if (mod_s.cur_clientsds == NULL) + sock = 0; + else + { + sock = *((int*)(mod_s.cur_clientsds->content)); + ListNextElement(mod_s.clientsds, &mod_s.cur_clientsds); + } +exit: + Thread_unlock_mutex(mutex); + FUNC_EXIT_RC(sock); + return sock; +} /* end getReadySocket */ +#else /** * Returns the next socket ready for communications as indicated by select * @param more_work flag to indicate more work is waiting, and thus a timeout value of 0 should @@ -345,6 +542,7 @@ SOCKET Socket_getReadySocket(int more_work, int timeout, mutex_type mutex, int* FUNC_EXIT_RC(sock); return sock; } /* end getReadySocket */ +#endif /** @@ -582,7 +780,9 @@ int Socket_putdatas(SOCKET socket, char* buf0, size_t buf0len, PacketBuffers buf rc = PAHO_MEMORY_ERROR; goto exit; } - //FD_SET(socket, &(mod_s.pending_wset)); +#if defined(USE_SELECT) + FD_SET(socket, &(mod_s.pending_wset)); +#endif rc = TCPSOCKET_INTERRUPTED; } } @@ -600,7 +800,9 @@ int Socket_putdatas(SOCKET socket, char* buf0, size_t buf0len, PacketBuffers buf */ void Socket_addPendingWrite(SOCKET socket) { - //FD_SET(socket, &(mod_s.pending_wset)); +#if defined(USE_SELECT) + FD_SET(socket, &(mod_s.pending_wset)); +#endif } @@ -610,8 +812,10 @@ void Socket_addPendingWrite(SOCKET socket) */ void Socket_clearPendingWrite(SOCKET socket) { - /*if (FD_ISSET(socket, &(mod_s.pending_wset))) - FD_CLR(socket, &(mod_s.pending_wset));*/ +#if defined(USE_SELECT) + if (FD_ISSET(socket, &(mod_s.pending_wset))) + FD_CLR(socket, &(mod_s.pending_wset)); +#endif } @@ -642,7 +846,52 @@ int Socket_close_only(SOCKET socket) return rc; } +#if defined(USE_SELECT) +/** + * Close a socket and remove it from the select list. + * @param socket the socket to close + * @return completion code + */ +int Socket_close(SOCKET socket) +{ + int rc = 0; + FUNC_ENTRY; + Socket_close_only(socket); + FD_CLR(socket, &(mod_s.rset_saved)); + if (FD_ISSET(socket, &(mod_s.pending_wset))) + FD_CLR(socket, &(mod_s.pending_wset)); + if (mod_s.cur_clientsds != NULL && *(int*)(mod_s.cur_clientsds->content) == socket) + mod_s.cur_clientsds = mod_s.cur_clientsds->next; + Socket_abortWrite(socket); + SocketBuffer_cleanup(socket); + ListRemoveItem(mod_s.connect_pending, &socket, intcompare); + ListRemoveItem(mod_s.write_pending, &socket, intcompare); + + if (ListRemoveItem(mod_s.clientsds, &socket, intcompare)) + Log(TRACE_MIN, -1, "Removed socket %d", socket); + else + { + Log(LOG_ERROR, -1, "Failed to remove socket %d", socket); + rc = -1; + goto exit; + } + if (socket + 1 >= mod_s.maxfdp1) + { + /* now we have to reset mod_s.maxfdp1 */ + ListElement* cur_clientsds = NULL; + + mod_s.maxfdp1 = 0; + while (ListNextElement(mod_s.clientsds, &cur_clientsds)) + mod_s.maxfdp1 = max(*((int*)(cur_clientsds->content)), mod_s.maxfdp1); + ++(mod_s.maxfdp1); + Log(TRACE_MAX, -1, "Reset max fdp1 to %d", mod_s.maxfdp1); + } +exit: + FUNC_EXIT_RC(rc); + return rc; +} +#else /** * Close a socket and remove it from the select list. * @param socket the socket to close @@ -692,6 +941,7 @@ int Socket_close(SOCKET socket) FUNC_EXIT_RC(rc); return rc; } +#endif /** @@ -1016,12 +1266,23 @@ int Socket_abortWrite(SOCKET socket) } +#if defined(USE_SELECT) +/** + * Continue any outstanding writes for a socket set + * @param pwset the set of sockets + * @param sock in case of a socket error contains the affected socket + * @return completion code, 0 or SOCKET_ERROR + */ +int Socket_continueWrites(fd_set* pwset, int* sock, mutex_type mutex) +#else /** * Continue any outstanding socket writes + * @param sock in case of a socket error contains the affected socket * @return completion code, 0 or SOCKET_ERROR */ int Socket_continueWrites(SOCKET* sock, mutex_type mutex) +#endif { int rc1 = 0; ListElement* curpending = mod_s.write_pending->first; @@ -1031,15 +1292,23 @@ int Socket_continueWrites(SOCKET* sock, mutex_type mutex) { int socket = *(int*)(curpending->content); int rc = 0; +#if defined(USE_SELECT) + + if (FD_ISSET(socket, pwset) && ((rc = Socket_continueWrite(socket)) != 0)) +#else struct pollfd* fd; /* find the socket in the fds structure */ fd = bsearch(&socket, mod_s.saved.fds, (size_t)mod_s.saved.nfds, sizeof(mod_s.saved.fds[0]), cmpsockfds); if ((fd->revents & POLLOUT) && ((rc = Socket_continueWrite(socket)) != 0)) +#endif { if (!SocketBuffer_writeComplete(socket)) Log(LOG_SEVERE, -1, "Failed to remove pending write from socket buffer list"); +#if defined(USE_SELECT) + FD_CLR(socket, &(mod_s.pending_wset)); +#endif if (!ListRemove(mod_s.write_pending, curpending->content)) { Log(LOG_SEVERE, -1, "Failed to remove pending write from list"); diff --git a/src/Socket.h b/src/Socket.h index 93a8982fe..1d87274d9 100644 --- a/src/Socket.h +++ b/src/Socket.h @@ -114,6 +114,14 @@ typedef struct List* connect_pending; /**< list of sockets for which a connect is pending */ List* write_pending; /**< list of sockets for which a write is pending */ +#if defined(USE_SELECT) + fd_set rset, /**< socket read set (see select doc) */ + rset_saved; /**< saved socket read set */ + int maxfdp1; /**< max descriptor used +1 (again see select doc) */ + List* clientsds; /**< list of client socket descriptors */ + ListElement* cur_clientsds; /**< current client socket descriptor (iterator) */ + fd_set pending_wset; /**< socket pending write set for select */ +#else unsigned int nfds; /**< no of file descriptors for poll */ struct pollfd* fds; /**< poll read file descriptors */ @@ -122,6 +130,7 @@ typedef struct unsigned int nfds; /**< number of fds in the fds_saved array */ struct pollfd* fds; } saved; +#endif } Sockets; diff --git a/travis-build.sh b/travis-build.sh index 669a22c24..ef262ec0a 100755 --- a/travis-build.sh +++ b/travis-build.sh @@ -6,7 +6,7 @@ rm -rf build.paho mkdir build.paho cd build.paho echo "travis build dir $TRAVIS_BUILD_DIR pwd $PWD with OpenSSL root $OPENSSL_ROOT_DIR" -cmake -DPAHO_BUILD_STATIC=$PAHO_BUILD_STATIC -DPAHO_BUILD_SHARED=$PAHO_BUILD_SHARED -DCMAKE_BUILD_TYPE=Debug -DPAHO_WITH_SSL=TRUE -DOPENSSL_ROOT_DIR=$OPENSSL_ROOT_DIR -DPAHO_BUILD_DOCUMENTATION=FALSE -DPAHO_BUILD_SAMPLES=TRUE -DPAHO_HIGH_PERFORMANCE=$PAHO_HIGH_PERFORMANCE .. +cmake -DPAHO_BUILD_STATIC=$PAHO_BUILD_STATIC -DPAHO_BUILD_SHARED=$PAHO_BUILD_SHARED -DCMAKE_BUILD_TYPE=Debug -DPAHO_WITH_SSL=TRUE -DOPENSSL_ROOT_DIR=$OPENSSL_ROOT_DIR -DPAHO_BUILD_DOCUMENTATION=FALSE -DPAHO_BUILD_SAMPLES=TRUE -DPAHO_HIGH_PERFORMANCE=$PAHO_HIGH_PERFORMANCE -DPAHO_USE_SELECT=$PAHO_USE_SELECT .. cmake --build . python3 ../test/mqttsas.py & ctest -VV --timeout 600 From b7455f3330d2fe6c2e23822c746c3cb309f7a7d6 Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Fri, 11 Feb 2022 19:01:53 +0000 Subject: [PATCH 72/93] Fix select timeout calculation --- src/Socket.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Socket.c b/src/Socket.c index ec68180b5..20a9a22f6 100644 --- a/src/Socket.c +++ b/src/Socket.c @@ -381,7 +381,13 @@ int Socket_getReadySocket(int more_work, int timeout, mutex_type mutex, int* rc) static struct timeval zero = {0L, 0L}; /* 0 seconds */ int rc1, maxfdp1_saved; fd_set pwset; - struct timeval timeout_tv = {0L, timeout_ms*1000}; + struct timeval timeout_tv = {0L, 0L}; + + if (timeout_ms > 0L) + { + timeout_tv.tv_sec = timeout_ms / 1000; + timeout_tv.tv_usec = (timeout_ms % 1000) * 1000; /* this field is microseconds! */ + } memcpy((void*)&(mod_s.rset), (void*)&(mod_s.rset_saved), sizeof(mod_s.rset)); memcpy((void*)&(pwset), (void*)&(mod_s.pending_wset), sizeof(pwset)); From b35a2dc237290f69e46d74917f4db96bf6a4ef0b Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Mon, 14 Feb 2022 10:30:59 +0000 Subject: [PATCH 73/93] Avoid slow connect in MQTTAsync #1039 --- src/MQTTAsyncUtils.c | 8 +++++--- src/Thread.c | 22 +++++++++++++++++----- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/MQTTAsyncUtils.c b/src/MQTTAsyncUtils.c index a6dd71b77..d55648097 100644 --- a/src/MQTTAsyncUtils.c +++ b/src/MQTTAsyncUtils.c @@ -1753,6 +1753,8 @@ static void MQTTAsync_checkTimeouts(void) thread_return_type WINAPI MQTTAsync_sendThread(void* n) { + int timeout = 10; /* first time in we have a small timeout. Gets things started more quickly */ + FUNC_ENTRY; MQTTAsync_lock_mutex(mqttasync_mutex); sendThread_state = RUNNING; @@ -1775,13 +1777,13 @@ thread_return_type WINAPI MQTTAsync_sendThread(void* n) MQTTAsync_unlock_mutex(mqttcommand_mutex); } #if !defined(_WIN32) && !defined(_WIN64) - if ((rc = Thread_wait_cond(send_cond, 1)) != 0 && rc != ETIMEDOUT) + if ((rc = Thread_wait_cond(send_cond, timeout)) != 0 && rc != ETIMEDOUT) Log(LOG_ERROR, -1, "Error %d waiting for condition variable", rc); #else - if ((rc = Thread_wait_sem(send_sem, 1000)) != 0 && rc != ETIMEDOUT) + if ((rc = Thread_wait_sem(send_sem, timeout)) != 0 && rc != ETIMEDOUT) Log(LOG_ERROR, -1, "Error %d waiting for semaphore", rc); #endif - + timeout = 1000; /* 1 second for follow on waits */ MQTTAsync_checkTimeouts(); } sendThread_state = STOPPING; diff --git a/src/Thread.c b/src/Thread.c index b8f789d6e..4bcca868e 100644 --- a/src/Thread.c +++ b/src/Thread.c @@ -403,25 +403,37 @@ int Thread_signal_cond(cond_type condvar) } /** - * Wait with a timeout (seconds) for condition variable + * Wait with a timeout (ms) for condition variable * @return 0 for success, ETIMEDOUT otherwise */ -int Thread_wait_cond(cond_type condvar, int timeout) +int Thread_wait_cond(cond_type condvar, int timeout_ms) { int rc = 0; struct timespec cond_timeout; + struct timespec interval; FUNC_ENTRY; + interval.tv_sec = timeout_ms / 1000; + interval.tv_nsec = (timeout_ms % 1000) * 1000000L; + #if defined(__APPLE__) && __MAC_OS_X_VERSION_MIN_REQUIRED < 101200 /* for older versions of MacOS */ struct timeval cur_time; gettimeofday(&cur_time, NULL); - cond_timeout.tv_sec = cur_time.tv_sec + timeout; + cond_timeout.tv_sec = cur_time.tv_sec; cond_timeout.tv_nsec = cur_time.tv_usec * 1000; #else clock_gettime(CLOCK_REALTIME, &cond_timeout); - - cond_timeout.tv_sec += timeout; #endif + + cond_timeout.tv_sec += interval.tv_sec; + cond_timeout.tv_nsec += (timeout_ms % 1000) * 1000000L; + + if (cond_timeout.tv_nsec >= 1000000000L) + { + cond_timeout.tv_sec++; + cond_timeout.tv_nsec += (cond_timeout.tv_nsec - 1000000000L); + } + pthread_mutex_lock(&condvar->mutex); rc = pthread_cond_timedwait(&condvar->cond, &condvar->mutex, &cond_timeout); pthread_mutex_unlock(&condvar->mutex); From 655b87d22c1efa71901d21df6f6662a30a5e886b Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Tue, 15 Feb 2022 11:24:33 +0000 Subject: [PATCH 74/93] Debug for Windows --- appveyor.yml | 2 +- src/MQTTAsyncUtils.c | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 6ab1abb46..d11c269e1 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -52,7 +52,7 @@ build_script: nmake - ctest -T test -VV + ctest -T test -VV -R test95-5ws-offline-buffering-max-buffered cd .. diff --git a/src/MQTTAsyncUtils.c b/src/MQTTAsyncUtils.c index a3e152714..7e310f877 100644 --- a/src/MQTTAsyncUtils.c +++ b/src/MQTTAsyncUtils.c @@ -665,7 +665,10 @@ int MQTTAsync_restoreCommands(MQTTAsyncs* client) client->command_seqno = max(client->command_seqno, cmd->seqno); commands_restored++; if (cmd->command.type == PUBLISH) + { client->noBufferedMessages++; + printf("2 Number of buffered messages now %d\n", client->noBufferedMessages); + } } } if (buffer) @@ -898,7 +901,10 @@ int MQTTAsync_addCommand(MQTTAsync_queuedCommand* command, int command_size) } } else + { command->client->noBufferedMessages++; + printf("1 Number of buffered messages now %d\n", command->client->noBufferedMessages); + } } } exit: @@ -1225,7 +1231,10 @@ static int MQTTAsync_processCommand(void) if (command) { if (command->command.type == PUBLISH) + { command->client->noBufferedMessages--; + printf("-- Number of buffered messages now %d\n", command->client->noBufferedMessages); + } ListDetach(MQTTAsync_commands, command); #if !defined(NO_PERSISTENCE) /*printf("outboundmsgs count %d max inflight %d qos %d %d %d\n", command->client->c->outboundMsgs->count, command->client->c->maxInflightMessages, From 79e216b0fd03f2b1a7aae5771f74cac63cc49c5e Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Tue, 15 Feb 2022 11:46:01 +0000 Subject: [PATCH 75/93] Increase debug tests --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index d11c269e1..42bcd5760 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -52,7 +52,7 @@ build_script: nmake - ctest -T test -VV -R test95-5ws-offline-buffering-max-buffered + ctest -T test -VV -R test95 cd .. From 7eeffadd82017641065de629b07333898c1ba398 Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Tue, 15 Feb 2022 12:02:09 +0000 Subject: [PATCH 76/93] More testing --- src/MQTTAsyncUtils.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/MQTTAsyncUtils.c b/src/MQTTAsyncUtils.c index 9f23f2faf..98f121003 100644 --- a/src/MQTTAsyncUtils.c +++ b/src/MQTTAsyncUtils.c @@ -667,7 +667,7 @@ int MQTTAsync_restoreCommands(MQTTAsyncs* client) if (cmd->command.type == PUBLISH) { client->noBufferedMessages++; - printf("2 Number of buffered messages now %d\n", client->noBufferedMessages); + //printf("2 Number of buffered messages now %d\n", client->noBufferedMessages); } } } @@ -903,7 +903,7 @@ int MQTTAsync_addCommand(MQTTAsync_queuedCommand* command, int command_size) else { command->client->noBufferedMessages++; - printf("1 Number of buffered messages now %d\n", command->client->noBufferedMessages); + //printf("1 Number of buffered messages now %d\n", command->client->noBufferedMessages); } } } @@ -1233,7 +1233,7 @@ static int MQTTAsync_processCommand(void) if (command->command.type == PUBLISH) { command->client->noBufferedMessages--; - printf("-- Number of buffered messages now %d\n", command->client->noBufferedMessages); + //printf("-- Number of buffered messages now %d\n", command->client->noBufferedMessages); } ListDetach(MQTTAsync_commands, command); #if !defined(NO_PERSISTENCE) From 9e887a2b28a5a29433edbc2c399224eba98ebd28 Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Tue, 15 Feb 2022 12:08:36 +0000 Subject: [PATCH 77/93] Run all tests --- appveyor.yml | 2 +- src/MQTTAsyncUtils.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 42bcd5760..36d1425aa 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -52,7 +52,7 @@ build_script: nmake - ctest -T test -VV -R test95 + ctest -T test -VV cd .. diff --git a/src/MQTTAsyncUtils.c b/src/MQTTAsyncUtils.c index 98f121003..9f23f2faf 100644 --- a/src/MQTTAsyncUtils.c +++ b/src/MQTTAsyncUtils.c @@ -667,7 +667,7 @@ int MQTTAsync_restoreCommands(MQTTAsyncs* client) if (cmd->command.type == PUBLISH) { client->noBufferedMessages++; - //printf("2 Number of buffered messages now %d\n", client->noBufferedMessages); + printf("2 Number of buffered messages now %d\n", client->noBufferedMessages); } } } @@ -903,7 +903,7 @@ int MQTTAsync_addCommand(MQTTAsync_queuedCommand* command, int command_size) else { command->client->noBufferedMessages++; - //printf("1 Number of buffered messages now %d\n", command->client->noBufferedMessages); + printf("1 Number of buffered messages now %d\n", command->client->noBufferedMessages); } } } @@ -1233,7 +1233,7 @@ static int MQTTAsync_processCommand(void) if (command->command.type == PUBLISH) { command->client->noBufferedMessages--; - //printf("-- Number of buffered messages now %d\n", command->client->noBufferedMessages); + printf("-- Number of buffered messages now %d\n", command->client->noBufferedMessages); } ListDetach(MQTTAsync_commands, command); #if !defined(NO_PERSISTENCE) From 8786689299e10e6359599afbe3d5dc353c908a93 Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Tue, 15 Feb 2022 13:17:40 +0000 Subject: [PATCH 78/93] Remove debug again --- src/MQTTAsyncUtils.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/MQTTAsyncUtils.c b/src/MQTTAsyncUtils.c index 9f23f2faf..d55648097 100644 --- a/src/MQTTAsyncUtils.c +++ b/src/MQTTAsyncUtils.c @@ -665,10 +665,7 @@ int MQTTAsync_restoreCommands(MQTTAsyncs* client) client->command_seqno = max(client->command_seqno, cmd->seqno); commands_restored++; if (cmd->command.type == PUBLISH) - { client->noBufferedMessages++; - printf("2 Number of buffered messages now %d\n", client->noBufferedMessages); - } } } if (buffer) @@ -901,10 +898,7 @@ int MQTTAsync_addCommand(MQTTAsync_queuedCommand* command, int command_size) } } else - { command->client->noBufferedMessages++; - printf("1 Number of buffered messages now %d\n", command->client->noBufferedMessages); - } } } exit: @@ -1231,10 +1225,7 @@ static int MQTTAsync_processCommand(void) if (command) { if (command->command.type == PUBLISH) - { command->client->noBufferedMessages--; - printf("-- Number of buffered messages now %d\n", command->client->noBufferedMessages); - } ListDetach(MQTTAsync_commands, command); #if !defined(NO_PERSISTENCE) /*printf("outboundmsgs count %d max inflight %d qos %d %d %d\n", command->client->c->outboundMsgs->count, command->client->c->maxInflightMessages, From d00f6e9ac1a85afe993703d5de054b6c44bdb50f Mon Sep 17 00:00:00 2001 From: Ashechol <34626395+Ashechol@users.noreply.github.com> Date: Tue, 7 Dec 2021 13:39:50 +0800 Subject: [PATCH 79/93] Update paho_cs_sub.c Fixed myconnect() --- src/samples/paho_cs_sub.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/samples/paho_cs_sub.c b/src/samples/paho_cs_sub.c index b6241e2b9..358474295 100644 --- a/src/samples/paho_cs_sub.c +++ b/src/samples/paho_cs_sub.c @@ -49,7 +49,7 @@ struct pubsub_opts opts = }; -int myconnect(MQTTClient* client) +int myconnect(MQTTClient client) { MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer; MQTTClient_SSLOptions ssl_opts = MQTTClient_SSLOptions_initializer; @@ -243,7 +243,7 @@ int main(int argc, char** argv) MQTTClient_free(topicName); } if (rc != 0) - myconnect(&client); + myconnect(client); } exit: From 864ce620e0f5b5410c6d7dac4477046d28a85518 Mon Sep 17 00:00:00 2001 From: Ashechol <34626395+Ashechol@users.noreply.github.com> Date: Fri, 3 Dec 2021 01:31:43 +0800 Subject: [PATCH 80/93] Update paho_cs_pub.c --- src/samples/paho_cs_pub.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/samples/paho_cs_pub.c b/src/samples/paho_cs_pub.c index 574ab9fe7..7545a311a 100644 --- a/src/samples/paho_cs_pub.c +++ b/src/samples/paho_cs_pub.c @@ -52,7 +52,7 @@ struct pubsub_opts opts = }; -int myconnect(MQTTClient* client) +int myconnect(MQTTClient client) { MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer; MQTTClient_SSLOptions ssl_opts = MQTTClient_SSLOptions_initializer; From e4b0f66ad6a977a07f568673a20b796d510fc0b9 Mon Sep 17 00:00:00 2001 From: Ashechol <34626395+Ashechol@users.noreply.github.com> Date: Tue, 26 Oct 2021 18:43:39 +0800 Subject: [PATCH 81/93] Update paho_cs_pub.c The function MQTTClient_connect() first var client should be MQTTClient, but in function myconnect() var client is a pointer of MQTTClient --- src/samples/paho_cs_pub.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/samples/paho_cs_pub.c b/src/samples/paho_cs_pub.c index 7545a311a..f49efd5d9 100644 --- a/src/samples/paho_cs_pub.c +++ b/src/samples/paho_cs_pub.c @@ -107,14 +107,14 @@ int myconnect(MQTTClient client) MQTTResponse response = MQTTResponse_initializer; conn_opts.cleanstart = 1; - response = MQTTClient_connect5(client, &conn_opts, &props, &willProps); + response = MQTTClient_connect5(*client, &conn_opts, &props, &willProps); rc = response.reasonCode; MQTTResponse_free(response); } else { conn_opts.cleansession = 1; - rc = MQTTClient_connect(client, &conn_opts); + rc = MQTTClient_connect(*client, &conn_opts); } if (opts.verbose && rc == MQTTCLIENT_SUCCESS) From 3937812e0fc0ff77f8e3c223ee250e36445d079e Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Thu, 17 Feb 2022 11:24:00 +0000 Subject: [PATCH 82/93] Update copyright statements in changed samples --- src/samples/paho_cs_pub.c | 6 +++--- src/samples/paho_cs_sub.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/samples/paho_cs_pub.c b/src/samples/paho_cs_pub.c index f49efd5d9..a83203844 100644 --- a/src/samples/paho_cs_pub.c +++ b/src/samples/paho_cs_pub.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2012, 2020 IBM Corp. + * Copyright (c) 2012, 2022 IBM Corp. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 @@ -107,14 +107,14 @@ int myconnect(MQTTClient client) MQTTResponse response = MQTTResponse_initializer; conn_opts.cleanstart = 1; - response = MQTTClient_connect5(*client, &conn_opts, &props, &willProps); + response = MQTTClient_connect5(client, &conn_opts, &props, &willProps); rc = response.reasonCode; MQTTResponse_free(response); } else { conn_opts.cleansession = 1; - rc = MQTTClient_connect(*client, &conn_opts); + rc = MQTTClient_connect(client, &conn_opts); } if (opts.verbose && rc == MQTTCLIENT_SUCCESS) diff --git a/src/samples/paho_cs_sub.c b/src/samples/paho_cs_sub.c index 358474295..cf271175d 100644 --- a/src/samples/paho_cs_sub.c +++ b/src/samples/paho_cs_sub.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2012, 2020 IBM Corp., and others + * Copyright (c) 2012, 2022 IBM Corp., and others * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 From bd1c9e598a59b66b81e852206f4b16e647a60212 Mon Sep 17 00:00:00 2001 From: 10km <10km0811@sohu.com> Date: Wed, 5 Jan 2022 11:10:50 +0800 Subject: [PATCH 83/93] Update CMakeLists.txt remove '-MD' in ADD_DEFINITIONS command. why add the -MD? this -MD forcible control MSVC generate code with /MD option if user want to compile with /MT by set option -DCMAKE_USER_MAKE_RULES_OVERRIDE=compiler_flag_overrides.cmake in command line, the '-MD' definition cause it not work; --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a8bfd7dbb..cf0fd68bd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,7 +37,7 @@ STRING(TIMESTAMP BUILD_TIMESTAMP UTC) MESSAGE(STATUS "Timestamp is ${BUILD_TIMESTAMP}") IF(WIN32) - ADD_DEFINITIONS(-D_CRT_SECURE_NO_DEPRECATE -DWIN32_LEAN_AND_MEAN -MD) + ADD_DEFINITIONS(-D_CRT_SECURE_NO_DEPRECATE -DWIN32_LEAN_AND_MEAN) ELSEIF(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") ADD_DEFINITIONS(-DOSX) ENDIF() From 0f0e5e4d928f979895c263d2348e8ba9ad7f5814 Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Sat, 19 Feb 2022 18:14:50 +0000 Subject: [PATCH 84/93] Send QoS 2 responses under more circumstances #1114 --- src/MQTTProtocolClient.c | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/src/MQTTProtocolClient.c b/src/MQTTProtocolClient.c index 5cc4eafd6..2f73e0b98 100644 --- a/src/MQTTProtocolClient.c +++ b/src/MQTTProtocolClient.c @@ -478,6 +478,7 @@ int MQTTProtocol_handlePubrecs(void* pack, SOCKET sock) Pubrec* pubrec = (Pubrec*)pack; Clients* client = NULL; int rc = TCPSOCKET_COMPLETE; + int send_pubrel = 1; /* boolean to send PUBREL or not */ FUNC_ENTRY; client = (Clients*)(ListFindItem(bstate->clients, &sock, clientSocketCompare)->content); @@ -519,15 +520,22 @@ int MQTTProtocol_handlePubrecs(void* pack, SOCKET sock) MQTTProperties_free(&m->properties); ListRemove(client->outboundMsgs, m); (++state.msgs_sent); + send_pubrel = 0; /* in MQTT v5, stop the exchange if there is an error reported */ } else { - rc = MQTTPacket_send_pubrel(pubrec->MQTTVersion, pubrec->msgId, 0, &client->net, client->clientID); m->nextMessageType = PUBCOMP; m->lastTouch = MQTTTime_now(); } } } + if (!send_pubrel) + ; /* only don't send ack on MQTT v5 PUBREC error, otherwise send ack under all circumstances because MQTT state can get out of step */ + else if (!Socket_noPendingWrites(sock)) + rc = MQTTProtocol_queueAck(client, PUBREL, pubrec->msgId); + else + rc = MQTTPacket_send_pubrel(pubrec->MQTTVersion, pubrec->msgId, 0, &client->net, client->clientID); + if (pubrec->MQTTVersion >= MQTTVERSION_5) MQTTProperties_free(&pubrec->properties); free(pack); @@ -557,11 +565,6 @@ int MQTTProtocol_handlePubrels(void* pack, SOCKET sock) { if (pubrel->header.bits.dup == 0) Log(TRACE_MIN, 3, NULL, "PUBREL", client->clientID, pubrel->msgId); - else if (!Socket_noPendingWrites(sock)) - rc = MQTTProtocol_queueAck(client, PUBCOMP, pubrel->msgId); - else - /* Apparently this is "normal" behaviour, so we don't need to issue a warning */ - rc = MQTTPacket_send_pubcomp(pubrel->MQTTVersion, pubrel->msgId, &client->net, client->clientID); } else { @@ -602,13 +605,14 @@ int MQTTProtocol_handlePubrels(void* pack, SOCKET sock) ListRemove(&(state.publications), m->publish); ListRemove(client->inboundMsgs, m); ++(state.msgs_received); - - if (!Socket_noPendingWrites(sock)) - rc = MQTTProtocol_queueAck(client, PUBCOMP, pubrel->msgId); - else - rc = MQTTPacket_send_pubcomp(pubrel->MQTTVersion, pubrel->msgId, &client->net, client->clientID); } } + /* Send ack under all circumstances because MQTT state can get out of step - this standard also says to do this */ + if (!Socket_noPendingWrites(sock)) + rc = MQTTProtocol_queueAck(client, PUBCOMP, pubrel->msgId); + else + rc = MQTTPacket_send_pubcomp(pubrel->MQTTVersion, pubrel->msgId, &client->net, client->clientID); + if (pubrel->MQTTVersion >= MQTTVERSION_5) MQTTProperties_free(&pubrel->properties); free(pack); @@ -997,6 +1001,9 @@ void MQTTProtocol_writeAvailable(SOCKET socket) case PUBREC: rc = MQTTPacket_send_pubrec(client->MQTTVersion, ackReq->messageId, &client->net, client->clientID); break; + case PUBREL: + rc = MQTTPacket_send_pubrel(client->MQTTVersion, ackReq->messageId, 0, &client->net, client->clientID); + break; case PUBCOMP: rc = MQTTPacket_send_pubcomp(client->MQTTVersion, ackReq->messageId, &client->net, client->clientID); break; From 743ff1be69136f96e42a9342d0d7128bd5f773cd Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Sat, 19 Feb 2022 18:25:10 +0000 Subject: [PATCH 85/93] Ensure return code from Socket_new is SOCKET_ERROR on error #1192 --- src/Socket.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/Socket.c b/src/Socket.c index 20a9a22f6..f51f7fba7 100644 --- a/src/Socket.c +++ b/src/Socket.c @@ -879,7 +879,7 @@ int Socket_close(SOCKET socket) else { Log(LOG_ERROR, -1, "Failed to remove socket %d", socket); - rc = -1; + rc = SOCKET_ERROR; goto exit; } if (socket + 1 >= mod_s.maxfdp1) @@ -956,7 +956,7 @@ int Socket_close(SOCKET socket) * @param port the TCP port * @param sock returns the new socket * @param timeout the timeout in milliseconds - * @return completion code + * @return completion code 0=good, SOCKET_ERROR=fail */ #if defined(__GNUC__) && defined(__linux__) int Socket_new(const char* addr, size_t addr_len, int port, SOCKET* sock, long timeout) @@ -980,7 +980,7 @@ int Socket_new(const char* addr, size_t addr_len, int port, SOCKET* sock) struct addrinfo hints = {0, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP, 0, NULL, NULL, NULL}; FUNC_ENTRY; - *sock = -1; + *sock = SOCKET_ERROR; memset(&address6, '\0', sizeof(address6)); if (addr[0] == '[') @@ -1034,7 +1034,7 @@ int Socket_new(const char* addr, size_t addr_len, int port, SOCKET* sock) } if (res == NULL) - rc = -1; + rc = SOCKET_ERROR; else #if defined(AF_INET6) if (res->ai_family == AF_INET6) @@ -1053,12 +1053,15 @@ int Socket_new(const char* addr, size_t addr_len, int port, SOCKET* sock) address.sin_addr = ((struct sockaddr_in*)(res->ai_addr))->sin_addr; } else - rc = -1; + rc = SOCKET_ERROR; freeaddrinfo(result); } else - Log(LOG_ERROR, -1, "getaddrinfo failed for addr %s with rc %d", addr_mem, rc); + { + Log(LOG_ERROR, -1, "getaddrinfo failed for addr %s with rc %d", addr_mem, rc); + rc = SOCKET_ERROR; + } if (rc != 0) Log(LOG_ERROR, -1, "%s is not a valid IP address", addr_mem); @@ -1126,7 +1129,7 @@ int Socket_new(const char* addr, size_t addr_len, int port, SOCKET* sock) if (rc != 0 && (rc != EINPROGRESS) && (rc != EWOULDBLOCK)) { Socket_close(*sock); /* close socket and remove from our list of sockets */ - *sock = -1; /* as initialized before */ + *sock = SOCKET_ERROR; /* as initialized before */ } } } From 5bf0e00ea2ab63e973e7391d4bc330330bcdc0e9 Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Fri, 4 Mar 2022 10:48:41 +0000 Subject: [PATCH 86/93] Free data on SSL abort write #1206 --- src/SSLSocket.c | 11 +++++++++++ src/SSLSocket.h | 1 + src/Socket.c | 5 ++++- 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/SSLSocket.c b/src/SSLSocket.c index 1ca2c48d0..fd80c7276 100644 --- a/src/SSLSocket.c +++ b/src/SSLSocket.c @@ -1102,4 +1102,15 @@ int SSLSocket_continueWrite(pending_writes* pw) FUNC_EXIT_RC(rc); return rc; } + + +int SSLSocket_abortWrite(pending_writes* pw) +{ + int rc = 0; + + FUNC_ENTRY; + free(pw->iovecs[0].iov_base); + FUNC_EXIT_RC(rc); + return rc; +} #endif diff --git a/src/SSLSocket.h b/src/SSLSocket.h index 7234b9642..3fcf0c1d1 100644 --- a/src/SSLSocket.h +++ b/src/SSLSocket.h @@ -48,5 +48,6 @@ int SSLSocket_connect(SSL* ssl, SOCKET sock, const char* hostname, int verify, i SOCKET SSLSocket_getPendingRead(void); int SSLSocket_continueWrite(pending_writes* pw); +int SSLSocket_abortWrite(pending_writes* pw); #endif diff --git a/src/Socket.c b/src/Socket.c index f51f7fba7..bcff03d49 100644 --- a/src/Socket.c +++ b/src/Socket.c @@ -640,7 +640,7 @@ char *Socket_getdata(SOCKET socket, size_t bytes, size_t* actual_len, int *rc) /** * Indicate whether any data is pending outbound for a socket. - * @return boolean - true == data pending. + * @return boolean - true == no pending data. */ int Socket_noPendingWrites(SOCKET socket) { @@ -1258,7 +1258,10 @@ int Socket_abortWrite(SOCKET socket) #if defined(OPENSSL) if (pw->ssl) + { + rc = SSLSocket_abortWrite(pw); goto exit; + } #endif for (i = 0; i < pw->count; i++) From 5fa7baf22719804fbdaae8afa0a11d1ef3c93ce8 Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Fri, 4 Mar 2022 10:50:29 +0000 Subject: [PATCH 87/93] If first round of commit retries doesn't finish, complete it later #1203 --- src/MQTTProtocolClient.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/MQTTProtocolClient.c b/src/MQTTProtocolClient.c index 2f73e0b98..102c65fc6 100644 --- a/src/MQTTProtocolClient.c +++ b/src/MQTTProtocolClient.c @@ -751,12 +751,20 @@ void MQTTProtocol_keepalive(START_TIME_TYPE now) static void MQTTProtocol_retries(START_TIME_TYPE now, Clients* client, int regardless) { ListElement* outcurrent = NULL; + static int connect_count = 0; + static int connect_sent = 0; FUNC_ENTRY; - if (!regardless && client->retryInterval <= 0) /* 0 or -ive retryInterval turns off retry except on reconnect */ + if (!regardless && client->retryInterval <= 0 && /* 0 or -ive retryInterval turns off retry except on reconnect */ + connect_sent == connect_count) goto exit; + if (regardless) + connect_count = client->outboundMsgs->count; /* remember the number of messages to retry on connect */ + else if (connect_sent < connect_count) /* continue a connect retry which didn't complete first time around */ + regardless = 1; + while (client && ListNextElement(client->outboundMsgs, &outcurrent) && client->connected && client->good && /* client is connected and has no errors */ Socket_noPendingWrites(client->net.socket)) /* there aren't any previous packets still stacked up on the socket */ @@ -764,6 +772,8 @@ static void MQTTProtocol_retries(START_TIME_TYPE now, Clients* client, int regar Messages* m = (Messages*)(outcurrent->content); if (regardless || MQTTTime_difftime(now, m->lastTouch) > (DIFF_TIME_TYPE)(max(client->retryInterval, 10) * 1000)) { + if (regardless) + ++connect_sent; if (m->qos == 1 || (m->qos == 2 && m->nextMessageType == PUBREC)) { Publish publish; @@ -808,7 +818,6 @@ static void MQTTProtocol_retries(START_TIME_TYPE now, Clients* client, int regar else m->lastTouch = MQTTTime_now(); } - /* break; why not do all retries at once? */ } } exit: From b36c86e3baf5a063c33d530b574577c086da3c4b Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Mon, 7 Mar 2022 11:03:37 +0000 Subject: [PATCH 88/93] Add warning about API calls in trace callback #1200 --- src/MQTTAsync.h | 3 ++- src/MQTTClient.h | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/MQTTAsync.h b/src/MQTTAsync.h index 7777e50a0..64bfd4de5 100644 --- a/src/MQTTAsync.h +++ b/src/MQTTAsync.h @@ -1696,7 +1696,8 @@ LIBMQTT_API void MQTTAsync_setTraceLevel(enum MQTTASYNC_TRACE_LEVELS level); /** * This is a callback function prototype which must be implemented if you want - * to receive trace information. + * to receive trace information. Do not invoke any other Paho API calls in this + * callback function - unpredictable behavior may result. * @param level the trace level of the message returned * @param message the trace message. This is a pointer to a static buffer which * will be overwritten on each call. You must copy the data if you want to keep diff --git a/src/MQTTClient.h b/src/MQTTClient.h index ebc64be57..6fd31f6ea 100644 --- a/src/MQTTClient.h +++ b/src/MQTTClient.h @@ -1407,7 +1407,8 @@ LIBMQTT_API void MQTTClient_setTraceLevel(enum MQTTCLIENT_TRACE_LEVELS level); /** * This is a callback function prototype which must be implemented if you want - * to receive trace information. + * to receive trace information. Do not invoke any other Paho API calls in this + * callback function - unpredictable behavior may result. * @param level the trace level of the message returned * @param message the trace message. This is a pointer to a static buffer which * will be overwritten on each call. You must copy the data if you want to keep From 045ce2d4921c15a93fb302d58a7f4a5aeb702596 Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Mon, 7 Mar 2022 11:20:41 +0000 Subject: [PATCH 89/93] Don't allow maxBufferedMessages to be set to 0 #1193 --- src/MQTTAsync.c | 8 ++++++++ src/MQTTAsync.h | 9 ++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/MQTTAsync.c b/src/MQTTAsync.c index 0437e28e7..571db0e28 100644 --- a/src/MQTTAsync.c +++ b/src/MQTTAsync.c @@ -340,6 +340,12 @@ int MQTTAsync_createWithOptions(MQTTAsync* handle, const char* serverURI, const } } + if (options->maxBufferedMessages <= 0) + { + rc = MQTTASYNC_MAX_BUFFERED; + goto exit; + } + if (options && (strncmp(options->struct_id, "MQCO", 4) != 0 || options->struct_version < 0 || options->struct_version > 2)) { @@ -1780,6 +1786,8 @@ const char* MQTTAsync_strerror(int code) return "Zero length will topic on connect"; case MQTTASYNC_COMMAND_IGNORED: return "Connect or disconnect command ignored"; + case MQTTASYNC_MAX_BUFFERED: + return "maxBufferedMessages in the connect options must be >= 0"; } chars = snprintf(buf, sizeof(buf), "Unknown error code %d", code); diff --git a/src/MQTTAsync.h b/src/MQTTAsync.h index 64bfd4de5..41571db4f 100644 --- a/src/MQTTAsync.h +++ b/src/MQTTAsync.h @@ -193,6 +193,11 @@ * for the previous connect or disconnect command to be complete. */ #define MQTTASYNC_COMMAND_IGNORED -18 + /* + * Return code: maxBufferedMessages in the connect options must be >= 0 + */ + #define MQTTASYNC_MAX_BUFFERED -19 + /** * Default MQTT version to connect with. Use 3.1.1 then fall back to 3.1 */ @@ -950,7 +955,9 @@ typedef struct int struct_version; /** Whether to allow messages to be sent when the client library is not connected. */ int sendWhileDisconnected; - /** The maximum number of messages allowed to be buffered while not connected. */ + /** The maximum number of messages allowed to be buffered. This is intended to be used to + * limit the number of messages queued while the client is not connected. It also applies + * when the client is connected, however, so has to be greater than 0. */ int maxBufferedMessages; /** Whether the MQTT version is 3.1, 3.1.1, or 5. To use V5, this must be set. * MQTT V5 has to be chosen here, because during the create call the message persistence From 5bb49f8772b0ffb2a821bdf478c0fa9103f84b2d Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Mon, 7 Mar 2022 17:42:25 +0000 Subject: [PATCH 90/93] Ensure options aren't null #1193 --- src/MQTTAsync.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/MQTTAsync.c b/src/MQTTAsync.c index 571db0e28..b49f15805 100644 --- a/src/MQTTAsync.c +++ b/src/MQTTAsync.c @@ -340,7 +340,7 @@ int MQTTAsync_createWithOptions(MQTTAsync* handle, const char* serverURI, const } } - if (options->maxBufferedMessages <= 0) + if (options && options->maxBufferedMessages <= 0) { rc = MQTTASYNC_MAX_BUFFERED; goto exit; From 6af66f31e2aabf7586f37473880db26579eb455f Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Mon, 7 Mar 2022 20:30:24 +0000 Subject: [PATCH 91/93] Update tests so they don't try to assign a now invalid value #1193 --- test/test95.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test95.c b/test/test95.c index 8d0b21447..b759790cd 100644 --- a/test/test95.c +++ b/test/test95.c @@ -1656,7 +1656,7 @@ int test5(struct Options options) } createOptions.sendWhileDisconnected = 0; - createOptions.maxBufferedMessages = 0; + createOptions.maxBufferedMessages = 1; createOptions.MQTTVersion = MQTTVERSION_5; rc = MQTTAsync_createWithOptions(&d, options.connection, clientidd, MQTTCLIENT_PERSISTENCE_DEFAULT, NULL, &createOptions); @@ -1826,7 +1826,7 @@ int test6(struct Options options) } createOptions.sendWhileDisconnected = 0; - createOptions.maxBufferedMessages = 0; + createOptions.maxBufferedMessages = 1; createOptions.MQTTVersion = MQTTVERSION_5; rc = MQTTAsync_createWithOptions(&d, options.connection, clientidd, MQTTCLIENT_PERSISTENCE_DEFAULT, NULL, &createOptions); From 4b9103bc312e561461178d8bd6c7a00de20b4c8c Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Tue, 22 Mar 2022 15:00:05 +0000 Subject: [PATCH 92/93] Make #1203 fix work across multiple clients --- src/Clients.h | 4 +++- src/MQTTProtocolClient.c | 10 ++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Clients.h b/src/Clients.h index de2f52159..130a9622b 100644 --- a/src/Clients.h +++ b/src/Clients.h @@ -132,11 +132,13 @@ typedef struct networkHandles net; /**< network info for this client */ int msgID; /**< the MQTT message id */ int keepAliveInterval; /**< the MQTT keep alive interval */ - int retryInterval; + int retryInterval; /**< the MQTT retry interval for QoS > 0 */ int maxInflightMessages; /**< the max number of inflight outbound messages we allow */ willMessages* will; /**< the MQTT will message, if any */ List* inboundMsgs; /**< inbound in flight messages */ List* outboundMsgs; /**< outbound in flight messages */ + int connect_count; /**< the number of outbound messages on reconnect - to ensure we send them all */ + int connect_sent; /**< the current number of outbound messages on reconnect that we've sent */ List* messageQueue; /**< inbound complete but undelivered messages */ List* outboundQueue; /**< outbound queued messages */ unsigned int qentry_seqno; diff --git a/src/MQTTProtocolClient.c b/src/MQTTProtocolClient.c index 102c65fc6..aaf43f75a 100644 --- a/src/MQTTProtocolClient.c +++ b/src/MQTTProtocolClient.c @@ -751,18 +751,16 @@ void MQTTProtocol_keepalive(START_TIME_TYPE now) static void MQTTProtocol_retries(START_TIME_TYPE now, Clients* client, int regardless) { ListElement* outcurrent = NULL; - static int connect_count = 0; - static int connect_sent = 0; FUNC_ENTRY; if (!regardless && client->retryInterval <= 0 && /* 0 or -ive retryInterval turns off retry except on reconnect */ - connect_sent == connect_count) + client->connect_sent == client->connect_count) goto exit; if (regardless) - connect_count = client->outboundMsgs->count; /* remember the number of messages to retry on connect */ - else if (connect_sent < connect_count) /* continue a connect retry which didn't complete first time around */ + client->connect_count = client->outboundMsgs->count; /* remember the number of messages to retry on connect */ + else if (client->connect_sent < client->connect_count) /* continue a connect retry which didn't complete first time around */ regardless = 1; while (client && ListNextElement(client->outboundMsgs, &outcurrent) && @@ -773,7 +771,7 @@ static void MQTTProtocol_retries(START_TIME_TYPE now, Clients* client, int regar if (regardless || MQTTTime_difftime(now, m->lastTouch) > (DIFF_TIME_TYPE)(max(client->retryInterval, 10) * 1000)) { if (regardless) - ++connect_sent; + ++client->connect_sent; if (m->qos == 1 || (m->qos == 2 && m->nextMessageType == PUBREC)) { Publish publish; From 0b31833ade8b143661e16e5c6039797c3d97804d Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Tue, 22 Mar 2022 15:02:26 +0000 Subject: [PATCH 93/93] Update patch version number --- version.patch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.patch b/version.patch index f11c82a4c..9a037142a 100644 --- a/version.patch +++ b/version.patch @@ -1 +1 @@ -9 \ No newline at end of file +10 \ No newline at end of file