Skip to content

Commit

Permalink
Release v0.3
Browse files Browse the repository at this point in the history
  • Loading branch information
arobenko committed Feb 7, 2024
2 parents 28fea7c + 83ddbb5 commit 40fa608
Show file tree
Hide file tree
Showing 16 changed files with 165 additions and 31 deletions.
5 changes: 5 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ project ("cc_mqtt5_libs")

# Options
option (CC_MQTT5_CLIENT_DEFAULT_LIB "Build and install default variant of MQTT5 client library" ON)
option (CC_MQTT5_CLIENT_LIB_FORCE_PIC "Force Position Independent Code (PIC) when compiling client library(ies)" OFF)
option (CC_MQTT5_CLIENT_APPS "Build and install client applications" ${CC_MQTT5_CLIENT_DEFAULT_LIB})
option (CC_MQTT5_CLIENT_AFL_FUZZ "Build and install client AFL++ fuzzing application" OFF)
option (CC_MQTT5_WARN_AS_ERR "Treat warning as error" ON)
Expand All @@ -11,12 +12,16 @@ option (CC_MQTT5_BUILD_UNIT_TESTS "Build unit tests" OFF)
option (CC_MQTT5_BUILD_INTEGRATION_TESTS "Build integration tests which require MQTT broker on local port 1883." OFF)
option (CC_MQTT5_WITH_DEFAULT_SANITIZERS "Build with sanitizers" OFF)

# CMake built-in options
option (BUILD_SHARED_LIBS "Build as shared library" OFF)

# Extra Configuration Variables
# CC_MQTT5_CUSTOM_CLIENT_CONFIG_FILES - List of custom client configuration files

# Other variables
set(CMAKE_CXX_STANDARD 17 CACHE STRING "The C++ standard to use")


##########################################################################

cmake_policy(SET CMP0079 NEW)
Expand Down
6 changes: 5 additions & 1 deletion client/lib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ function (gen_lib_mqtt5_client config_file)
src/ClientImpl.cpp
src/TimerMgr.cpp
)
add_library (${lib_name} STATIC ${src} ${src_output})
add_library (${lib_name} ${src} ${src_output})
add_library (cc::${lib_name} ALIAS ${lib_name})
target_link_libraries(${lib_name} PRIVATE cc::cc_mqtt5 cc::comms)
target_include_directories(
Expand All @@ -170,6 +170,10 @@ function (gen_lib_mqtt5_client config_file)
)
add_dependencies(${lib_name} ${header_tgt_name} ${src_tgt_name} ${config_tgt_name} ${prot_opts_tgt_name})

if (CC_MQTT5_CLIENT_LIB_FORCE_PIC)
set_property(TARGET ${lib_name} PROPERTY POSITION_INDEPENDENT_CODE ON)
endif ()

file (READ "${CMAKE_CURRENT_SOURCE_DIR}/include/cc_mqtt5_client/common.h" version_file)
string (REGEX MATCH "CC_MQTT5_CLIENT_MAJOR_VERSION ([0-9]*)U*" _ ${version_file})
set (major_ver ${CMAKE_MATCH_1})
Expand Down
5 changes: 3 additions & 2 deletions client/lib/doxygen/main.dox
Original file line number Diff line number Diff line change
Expand Up @@ -596,7 +596,7 @@
/// CC_Mqtt5DisconnectConfig config;
///
/// // Assign default values to the "config"
/// client_disconnect_init_config(&config);
/// cc_mqtt5_client_disconnect_init_config(&config);
///
/// // Update the values if needed:
/// config.m_reasonCode = CC_Mqtt5ReasonCode_DisconnectWithWill;
Expand Down Expand Up @@ -1179,7 +1179,8 @@
///
/// When the "publish" operation completion callback is invoked the reported
/// "response" information is present <b>if and only if</b> the "status" is
/// @ref CC_Mqtt5AsyncOpStatus_Complete.
/// @ref CC_Mqtt5AsyncOpStatus_Complete and the publish QoS was 1 (@ref CC_Mqtt5QoS_AtLeastOnceDelivery)
/// or higher.
///
/// When the callback reporting the publish status is invoked, it is responsibility
/// of the application to check the @ref CC_Mqtt5PublishResponse::m_reasonCode value.
Expand Down
2 changes: 1 addition & 1 deletion client/lib/include/cc_mqtt5_client/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ extern "C" {

/// @brief Minor verion of the library
/// @ingroup global
#define CC_MQTT5_CLIENT_MINOR_VERSION 2U
#define CC_MQTT5_CLIENT_MINOR_VERSION 3U

/// @brief Patch level of the library
/// @ingroup global
Expand Down
16 changes: 12 additions & 4 deletions client/lib/src/ClientImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

#include "ClientImpl.h"

#include "comms/cast.h"
#include "comms/Assert.h"
#include "comms/process.h"

Expand Down Expand Up @@ -84,11 +85,13 @@ CC_Mqtt5ErrorCode ClientImpl::init()
}

terminateAllOps(CC_Mqtt5AsyncOpStatus_Aborted);
m_ops.clear();
bool firstConnect = m_sessionState.m_firstConnect;
m_sessionState = SessionState();
m_sessionState.m_initialized = true;
m_sessionState.m_firstConnect = firstConnect;
COMMS_ASSERT(m_timerMgr.getMinWait() == 0U);
COMMS_ASSERT(m_timerMgr.allocCount() == 0U);
return CC_Mqtt5ErrorCode_Success;
}

Expand Down Expand Up @@ -526,7 +529,7 @@ op::ReauthOp* ClientImpl::reauthPrepare(CC_Mqtt5ErrorCode* ec)
return reauthOp;
}

CC_Mqtt5ErrorCode ClientImpl::allocPubTopicAlias(const char* topic, std::uint8_t qos0RegsCount)
CC_Mqtt5ErrorCode ClientImpl::allocPubTopicAlias(const char* topic, unsigned qos0RegsCount)
{
if constexpr (Config::HasTopicAliases) {
if ((topic == nullptr) || (topic[0] == '\0')) {
Expand Down Expand Up @@ -554,6 +557,11 @@ CC_Mqtt5ErrorCode ClientImpl::allocPubTopicAlias(const char* topic, std::uint8_t
return CC_Mqtt5ErrorCode_OutOfMemory;
}

if (std::numeric_limits<std::uint8_t>::max() < qos0RegsCount) {
errorLog("The qos0RegsCount value is too high");
return CC_Mqtt5ErrorCode_BadParam;
}

auto iter =
std::lower_bound(
m_sessionState.m_sendTopicAliases.begin(), m_sessionState.m_sendTopicAliases.end(), topic,
Expand All @@ -564,8 +572,8 @@ CC_Mqtt5ErrorCode ClientImpl::allocPubTopicAlias(const char* topic, std::uint8_t

if ((iter != m_sessionState.m_sendTopicAliases.end()) &&
(iter->m_topic == topic)) {
iter->m_lowQosRegCountRequest = qos0RegsCount;
iter->m_lowQosRegRemCount = qos0RegsCount;
comms::cast_assign(iter->m_lowQosRegCountRequest) = qos0RegsCount;
comms::cast_assign(iter->m_lowQosRegRemCount) = qos0RegsCount;
iter->m_highQosRegRemCount = TopicAliasInfo::DefaultHighQosRegRemCount;
return CC_Mqtt5ErrorCode_Success;
}
Expand All @@ -586,7 +594,7 @@ CC_Mqtt5ErrorCode ClientImpl::allocPubTopicAlias(const char* topic, std::uint8_t
auto infoIter = m_sessionState.m_sendTopicAliases.insert(iter, TopicAliasInfo());
infoIter->m_topic = topic;
infoIter->m_alias = alias;
infoIter->m_lowQosRegRemCount = qos0RegsCount;
comms::cast_assign(infoIter->m_lowQosRegRemCount) = qos0RegsCount;
return CC_Mqtt5ErrorCode_Success;
}
else {
Expand Down
2 changes: 1 addition & 1 deletion client/lib/src/ClientImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ class ClientImpl final : public ProtMsgHandler
op::SendOp* publishPrepare(CC_Mqtt5ErrorCode* ec);
op::ReauthOp* reauthPrepare(CC_Mqtt5ErrorCode* ec);

CC_Mqtt5ErrorCode allocPubTopicAlias(const char* topic, std::uint8_t qos0RegsCount);
CC_Mqtt5ErrorCode allocPubTopicAlias(const char* topic, unsigned qos0RegsCount);
CC_Mqtt5ErrorCode freePubTopicAlias(const char* topic);
unsigned pubTopicAliasCount() const;
bool pubTopicAliasIsAllocated(const char* topic) const;
Expand Down
14 changes: 13 additions & 1 deletion client/lib/src/TimerMgr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,18 @@ unsigned TimerMgr::getMinWait() const
return static_cast<unsigned>(std::min(result, std::uint64_t(std::numeric_limits<unsigned>::max())));
}

unsigned TimerMgr::allocCount() const
{
return
static_cast<unsigned>(
std::count_if(
m_timers.begin(), m_timers.end(),
[](auto& info)
{
return info.m_allocated;
}));
}

void TimerMgr::freeTimer(unsigned idx)
{
COMMS_ASSERT(idx < m_timers.size());
Expand All @@ -121,7 +133,7 @@ void TimerMgr::freeTimer(unsigned idx)
COMMS_ASSERT(m_allocatedTimers > 0U);
auto& info = m_timers[idx];
COMMS_ASSERT(info.m_allocated);
info.m_allocated = false;
info = TimerInfo();
--m_allocatedTimers;
}

Expand Down
1 change: 1 addition & 0 deletions client/lib/src/TimerMgr.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ class TimerMgr
Timer allocTimer();
void tick(unsigned ms);
unsigned getMinWait() const;
unsigned allocCount() const;

private:
struct TimerInfo
Expand Down
2 changes: 1 addition & 1 deletion client/lib/templ/client.cpp.templ
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ unsigned cc_mqtt5_##NAME##client_get_default_response_timeout(CC_Mqtt5ClientHand
return clientFromHandle(handle)->configState().m_responseTimeoutMs;
}

CC_Mqtt5ErrorCode cc_mqtt5_##NAME##client_pub_topic_alias_alloc(CC_Mqtt5ClientHandle handle, const char* topic, unsigned char qos0RegsCount)
CC_Mqtt5ErrorCode cc_mqtt5_##NAME##client_pub_topic_alias_alloc(CC_Mqtt5ClientHandle handle, const char* topic, unsigned qos0RegsCount)
{
if (handle == nullptr) {
return CC_Mqtt5ErrorCode_BadParam;
Expand Down
4 changes: 2 additions & 2 deletions client/lib/templ/client.h.templ
Original file line number Diff line number Diff line change
Expand Up @@ -116,10 +116,10 @@ unsigned cc_mqtt5_##NAME##client_get_default_response_timeout(CC_Mqtt5ClientHand
/// @brief Allocate alias for topic.
/// @param[in] handle Handle returned by @ref cc_mqtt5_##NAME##client_alloc() function.
/// @param[in] topic Topic string for which the alias needs to be allocated.
/// @param[in] qos0RegsCount Amount of times to report topic alias to the broker when QoS0 messages are used.
/// @param[in] qos0RegsCount Amount of times to report topic alias to the broker when QoS0 messages are used, mustn't be greather than 255.
/// @return Error code of the operation
/// @ingroup client
CC_Mqtt5ErrorCode cc_mqtt5_##NAME##client_pub_topic_alias_alloc(CC_Mqtt5ClientHandle handle, const char* topic, unsigned char qos0RegsCount);
CC_Mqtt5ErrorCode cc_mqtt5_##NAME##client_pub_topic_alias_alloc(CC_Mqtt5ClientHandle handle, const char* topic, unsigned qos0RegsCount);

/// @brief Free alias for topic for another use.
/// @param[in] handle Handle returned by @ref cc_mqtt5_##NAME##client_alloc() function.
Expand Down
2 changes: 1 addition & 1 deletion client/lib/test/integration/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ find_package(Boost REQUIRED COMPONENTS system)

set (COMMON_BASE_LIB_NAME "IntegrationTestCommonBase")
set (COMMON_BASE_SRC "IntegrationTestCommonBase.cpp")
add_library(${COMMON_BASE_LIB_NAME} ${COMMON_BASE_SRC})
add_library(${COMMON_BASE_LIB_NAME} STATIC ${COMMON_BASE_SRC})
target_link_libraries(${COMMON_BASE_LIB_NAME} PUBLIC cc::cc_mqtt5_client Boost::system Boost::boost)
target_include_directories(
${COMMON_BASE_LIB_NAME} INTERFACE
Expand Down
6 changes: 3 additions & 3 deletions client/lib/test/unit/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ set (COMMON_BASE_SRC
"UnitTestCommonBase.cpp")


add_library(${COMMON_BASE_LIB_NAME} ${COMMON_BASE_SRC})
add_library(${COMMON_BASE_LIB_NAME} STATIC ${COMMON_BASE_SRC})
target_link_libraries(${COMMON_BASE_LIB_NAME} PUBLIC cc::cc_mqtt5)
target_include_directories(
${COMMON_BASE_LIB_NAME}
Expand Down Expand Up @@ -37,7 +37,7 @@ if (TARGET cc::cc_mqtt5_client)
set (DEFAULT_BASE_SRC
"UnitTestDefaultBase.cpp")

add_library(${DEFAULT_BASE_LIB_NAME} ${DEFAULT_BASE_SRC})
add_library(${DEFAULT_BASE_LIB_NAME} STATIC ${DEFAULT_BASE_SRC})
target_link_libraries(${DEFAULT_BASE_LIB_NAME} PUBLIC ${COMMON_BASE_LIB_NAME} cc::cc_mqtt5_client)
target_include_directories(
${DEFAULT_BASE_LIB_NAME} INTERFACE
Expand All @@ -59,7 +59,7 @@ if (TARGET cc::cc_mqtt5_bm_client)
set (BM_BASE_SRC
"UnitTestBmBase.cpp")

add_library(${BM_BASE_LIB_NAME} ${BM_BASE_SRC})
add_library(${BM_BASE_LIB_NAME} STATIC ${BM_BASE_SRC})
target_link_libraries(${BM_BASE_LIB_NAME} PUBLIC ${COMMON_BASE_LIB_NAME} cc::cc_mqtt5_bm_client)
target_include_directories(
${BM_BASE_LIB_NAME} INTERFACE
Expand Down
35 changes: 22 additions & 13 deletions client/lib/test/unit/UnitTestCommonBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -234,18 +234,7 @@ UnitTestCommonBase::UnitTestMessageInfo& UnitTestCommonBase::UnitTestMessageInfo
void UnitTestCommonBase::unitTestSetUp()
{
test_assert(!m_client);
m_tickReq.clear();
m_sentData.clear();
m_receivedData.clear();
m_connectResp.clear();
m_subscribeResp.clear();
m_publishResp.clear();
m_reauthResp.clear();
m_inAuthInfo.clear();
m_outAuthInfo.clear();
m_userPropsTmp.clear();
m_disconnectInfo.clear();
m_disconnected = false;
unitTestClearState();
}

void UnitTestCommonBase::unitTestTearDown()
Expand Down Expand Up @@ -962,7 +951,11 @@ UnitTestCommonBase::UnitTestClientPtr UnitTestCommonBase::unitTestAlloc()
CC_Mqtt5ErrorCode UnitTestCommonBase::unitTestInit(CC_Mqtt5Client* client)
{
test_assert(m_funcs.m_init != nullptr);
return m_funcs.m_init(client);
auto ec = m_funcs.m_init(client);
if (ec == CC_Mqtt5ErrorCode_Success) {
unitTestClearState();
}
return ec;
}

bool UnitTestCommonBase::unitTestIsInitialized(CC_Mqtt5Client* client) const
Expand Down Expand Up @@ -1201,6 +1194,22 @@ void UnitTestCommonBase::unitTestSetMessageReceivedReportCb(CC_Mqtt5ClientHandle
return m_funcs.m_set_message_received_report_callback(handle, cb, data);
}

void UnitTestCommonBase::unitTestClearState()
{
m_tickReq.clear();
m_sentData.clear();
m_receivedData.clear();
m_connectResp.clear();
m_subscribeResp.clear();
m_publishResp.clear();
m_reauthResp.clear();
m_inAuthInfo.clear();
m_outAuthInfo.clear();
m_userPropsTmp.clear();
m_disconnectInfo.clear();
m_disconnected = false;
}

void UnitTestCommonBase::unitTestErrorLogCb([[maybe_unused]] void* obj, const char* msg)
{
std::cout << "ERROR: " << msg << std::endl;
Expand Down
5 changes: 4 additions & 1 deletion client/lib/test/unit/UnitTestCommonBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ class UnitTestCommonBase
bool (*m_is_network_disconnected)(CC_Mqtt5ClientHandle) = nullptr;
CC_Mqtt5ErrorCode (*m_set_default_response_timeout)(CC_Mqtt5ClientHandle, unsigned) = nullptr;
unsigned (*m_get_default_response_timeout)(CC_Mqtt5ClientHandle) = nullptr;
CC_Mqtt5ErrorCode (*m_pub_topic_alias_alloc)(CC_Mqtt5ClientHandle, const char*, unsigned char) = nullptr;
CC_Mqtt5ErrorCode (*m_pub_topic_alias_alloc)(CC_Mqtt5ClientHandle, const char*, unsigned) = nullptr;
CC_Mqtt5ErrorCode (*m_pub_topic_alias_free)(CC_Mqtt5ClientHandle, const char*) = nullptr;
unsigned (*m_pub_topic_alias_count)(CC_Mqtt5ClientHandle) = nullptr;
bool (*m_pub_topic_alias_is_allocated)(CC_Mqtt5ClientHandle, const char*) = nullptr;
Expand Down Expand Up @@ -133,6 +133,7 @@ class UnitTestCommonBase
explicit UnitTestCommonBase(const LibFuncs& funcs);

static constexpr unsigned UnitTestDefaultOpTimeoutMs = 2000;
static constexpr unsigned UnitTestDefaultKeepAliveMs = 60000;

struct UnitTestUserProp
{
Expand Down Expand Up @@ -483,6 +484,8 @@ class UnitTestCommonBase

private:

void unitTestClearState();

static void unitTestErrorLogCb(void* obj, const char* msg);
static void unitTestBrokerDisconnectedCb(void* obj, const CC_Mqtt5DisconnectInfo* info);
static void unitTestMessageReceivedCb(void* obj, const CC_Mqtt5MessageInfo* info);
Expand Down
60 changes: 60 additions & 0 deletions client/lib/test/unit/UnitTestConnect.th
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ public:
void test30();
void test31();
void test32();
void test33();

private:
virtual void setUp() override
Expand Down Expand Up @@ -2069,3 +2070,62 @@ void UnitTestConnect::test32()
unitTestVerifyDisconnectSent(UnitTestDisconnectReason::ProtocolError);
}

void UnitTestConnect::test33()
{
// Extra keep alive testing
auto* client = unitTestAllocAndInitClient();
TS_ASSERT_DIFFERS(client, nullptr);
TS_ASSERT(unitTestCheckNoTicks());

unitTestPerformBasicConnect(client, __FUNCTION__);

auto* tickReq = unitTestTickReq();
TS_ASSERT_DIFFERS(tickReq, nullptr);
TS_ASSERT_EQUALS(tickReq->m_requested, UnitTestDefaultKeepAliveMs);

unitTestTick();
auto sentMsg = unitTestGetSentMessage();
TS_ASSERT(sentMsg);
TS_ASSERT_EQUALS(sentMsg->getId(), cc_mqtt5::MsgId_Pingreq);
TS_ASSERT(!unitTestIsDisconnected());

tickReq = unitTestTickReq();
TS_ASSERT_DIFFERS(tickReq, nullptr);
TS_ASSERT_EQUALS(tickReq->m_requested, UnitTestDefaultOpTimeoutMs);

const unsigned PingDelay = 1;
unitTestTick(PingDelay);
UnitTestPingrespMsg pingrespMsg;
unitTestReceiveMessage(pingrespMsg);

tickReq = unitTestTickReq();
auto nextTickMs = UnitTestDefaultKeepAliveMs - PingDelay;
TS_ASSERT_EQUALS(tickReq->m_requested, nextTickMs);

unitTestTick();
sentMsg = unitTestGetSentMessage();
TS_ASSERT(sentMsg);
TS_ASSERT_EQUALS(sentMsg->getId(), cc_mqtt5::MsgId_Pingreq);
TS_ASSERT(!unitTestIsDisconnected());

tickReq = unitTestTickReq();
TS_ASSERT_DIFFERS(tickReq, nullptr);
TS_ASSERT_EQUALS(tickReq->m_requested, PingDelay);

unitTestTick(PingDelay);
TS_ASSERT(!unitTestHasSentMessage());
unitTestReceiveMessage(pingrespMsg);
tickReq = unitTestTickReq();
TS_ASSERT_DIFFERS(tickReq, nullptr);
TS_ASSERT_EQUALS(tickReq->m_requested, nextTickMs);

unitTestTick(6000);
unitTestInit(client);
TS_ASSERT(unitTestCheckNoTicks());

unitTestPerformBasicConnect(client, __FUNCTION__);

tickReq = unitTestTickReq();
TS_ASSERT_DIFFERS(tickReq, nullptr);
TS_ASSERT_EQUALS(tickReq->m_requested, UnitTestDefaultKeepAliveMs);
}
Loading

0 comments on commit 40fa608

Please sign in to comment.