MQTTSuite
Loading...
Searching...
No Matches
Mqtt.cpp
Go to the documentation of this file.
1/*
2 * MQTTSuite - A lightweight MQTT Integration System
3 * Copyright (C) Volker Christian <me@vchrist.at>
4 * 2022, 2023, 2024, 2025, 2026
5 *
6 * This program is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the Free
8 * Software Foundation, either version 3 of the License, or (at your option)
9 * any later version.
10 */
11
12#include "Mqtt.h"
13
14#include "lib/MariaDbStorage.h"
15#include "lib/MqttMessage.h" // IWYU pragma: keep
16#include "lib/StoragePlan.h"
17
18#include <iot/mqtt/Topic.h>
19#include <iot/mqtt/packets/Connack.h>
20#include <iot/mqtt/packets/Publish.h>
21#include <iot/mqtt/packets/Suback.h>
22
23#ifndef DOXYGEN_SHOULD_SKIP_THIS
24
25#include <algorithm>
26#include <cstring>
27#include <iterator>
28#include <log/Logger.h>
29#include <stdexcept>
30#include <utility>
31#include <utils/system/signal.h>
32
33#endif
34
35namespace mqtt::mqttstore::lib {
36
37 Mqtt::Mqtt(const std::string& connectionName,
38 const std::string& clientId,
39 std::uint8_t qoSDefault,
40 std::uint16_t keepAlive,
41 bool cleanSession,
42 const std::string& willTopic,
43 const std::string& willMessage,
44 std::uint8_t willQoS,
45 bool willRetain,
46 const std::string& username,
47 const std::string& password,
48 const std::list<std::string>& subTopics,
49 MariaDbStorage::ConnectionConfig connectionConfig,
50 const std::string& rawTable,
51 bool autoCreateRawTable,
52 StoragePlan storagePlan,
53 const std::string& sessionStoreFileName)
54 : iot::mqtt::client::Mqtt(connectionName, clientId, keepAlive, sessionStoreFileName)
56 , qoSDefault(qoSDefault)
57 , cleanSession(cleanSession)
58 , willTopic(willTopic)
59 , willMessage(willMessage)
60 , willQoS(willQoS)
61 , willRetain(willRetain)
62 , username(username)
63 , password(password)
65 VLOG(1) << "MQTTStore client id: " << clientId;
66 VLOG(1) << " Keep Alive: " << keepAlive;
67 VLOG(1) << " Clean Session: " << cleanSession;
68 VLOG(1) << " Will Topic: " << willTopic;
69 VLOG(1) << " Will QoS: " << static_cast<std::uint16_t>(willQoS);
70 VLOG(1) << " Will Retain: " << willRetain;
71 VLOG(1) << " Username configured: " << (!username.empty());
72 }
73
74 void Mqtt::onConnected() {
75 VLOG(1) << "MQTTStore: initiating MQTT session";
77 }
78
79 bool Mqtt::onSignal(int signum) {
80 VLOG(1) << "MQTTStore: exit due to '" << strsignal(signum) << "' (SIG" << utils::system::sigabbrev_np(signum) << " = " << signum
81 << ")";
82 sendDisconnect();
83
84 return Super::onSignal(signum);
85 }
86
87 std::uint8_t Mqtt::getQos(const std::string& qoSString) {
88 const unsigned long qoS = std::stoul(qoSString);
89
90 if (qoS > 2) {
91 throw std::out_of_range("qos " + qoSString + " not in range [0..2]");
92 }
93
94 return static_cast<std::uint8_t>(qoS);
95 }
96
97 void Mqtt::onConnack(const iot::mqtt::packets::Connack& connack) {
98 if (connack.getReturnCode() != 0) {
99 VLOG(0) << connectionName << " MQTTStore: broker rejected connection with return code "
100 << static_cast<int>(connack.getReturnCode());
101 sendDisconnect();
102 return;
103 }
104
105 if (subTopics.empty()) {
106 VLOG(0) << connectionName << " MQTTStore: no subscriptions configured";
107 sendDisconnect();
108 return;
109 }
110
111 try {
112 std::list<iot::mqtt::Topic> topicList;
113 std::transform(subTopics.begin(),
114 subTopics.end(),
115 std::back_inserter(topicList),
116 [qoSDefault = this->qoSDefault](const std::string& compositeTopic) {
117 const std::size_t pos = compositeTopic.rfind("##");
118 const std::string topic = compositeTopic.substr(0, pos);
119 std::uint8_t qoS = qoSDefault;
120
121 if (pos != std::string::npos) {
122 qoS = getQos(compositeTopic.substr(pos + 2));
123 }
124
125 VLOG(0) << "MQTTStore subscribe: QoS " << static_cast<int>(qoS) << " | " << topic;
126 return iot::mqtt::Topic(topic, qoS);
127 });
128
129 sendSubscribe(topicList);
130 } catch (const std::logic_error& error) {
131 VLOG(0) << connectionName << " MQTTStore subscription failed: " << error.what();
132 sendDisconnect();
133 }
134 }
135
136 void Mqtt::onPublish(const iot::mqtt::packets::Publish& publish) {
137 VLOG(1) << connectionName << " MQTTStore received publish: topic='" << publish.getTopic()
138 << "' qos=" << static_cast<std::uint16_t>(publish.getQoS()) << " retain=" << (publish.getRetain() != 0)
139 << " dup=" << (publish.getDup() != 0);
140
141 storage.store({.connectionName = connectionName,
142 .topic = publish.getTopic(),
143 .payload = publish.getMessage(),
144 .qoS = publish.getQoS(),
145 .retain = publish.getRetain() != 0,
146 .dup = publish.getDup() != 0,
147 .packetIdentifier = publish.getPacketIdentifier()});
148 }
149
150 void Mqtt::onSuback(const iot::mqtt::packets::Suback& suback) {
151 VLOG(1) << "MQTTStore Suback";
152
153 for (auto returnCode : suback.getReturnCodes()) {
154 VLOG(0) << " r: " << static_cast<int>(returnCode);
155 }
156 }
157
158} // namespace mqtt::mqttstore::lib
void onConnected() final
Definition Mqtt.cpp:74
const std::string willTopic
Definition Mqtt.h:68
Mqtt(const std::string &connectionName, const std::string &clientId, std::uint8_t qoSDefault, std::uint16_t keepAlive, bool cleanSession, const std::string &willTopic, const std::string &willMessage, std::uint8_t willQoS, bool willRetain, const std::string &username, const std::string &password, const std::list< std::string > &subTopics, MariaDbStorage::ConnectionConfig connectionConfig, const std::string &rawTable, bool autoCreateRawTable, StoragePlan storagePlan, const std::string &sessionStoreFileName="")
Definition Mqtt.cpp:37
const std::uint8_t qoSDefault
Definition Mqtt.h:66
void onConnack(const iot::mqtt::packets::Connack &connack) final
Definition Mqtt.cpp:97
const bool cleanSession
Definition Mqtt.h:67
const bool willRetain
Definition Mqtt.h:71
const std::string willMessage
Definition Mqtt.h:69
iot::mqtt::client::Mqtt Super
Definition Mqtt.h:54
const std::uint8_t willQoS
Definition Mqtt.h:70
bool onSignal(int signum) final
Definition Mqtt.cpp:79
void onPublish(const iot::mqtt::packets::Publish &publish) final
Definition Mqtt.cpp:136
const std::string username
Definition Mqtt.h:72
const std::string password
Definition Mqtt.h:73
static std::uint8_t getQos(const std::string &qoSString)
Definition Mqtt.cpp:87
void onSuback(const iot::mqtt::packets::Suback &suback) final
Definition Mqtt.cpp:150