Commit 9dab7a48e665f59212a6bcf5f2b726ff99098d22

Authored by Wiebe Cazemier
1 parent 8ce485ee

Beginning of topic aliases

client.cpp
... ... @@ -334,6 +334,25 @@ void Client::resetBuffersIfEligible()
334 334 writebuf.resetSizeIfEligable(initialBufferSize);
335 335 }
336 336  
  337 +void Client::setTopicAlias(const uint16_t alias_id, const std::string &topic)
  338 +{
  339 + if (alias_id == 0)
  340 + throw ProtocolError("Client tried to set topic alias 0, which is a protocol error.");
  341 +
  342 + if (topic.empty())
  343 + return;
  344 +
  345 + if (alias_id > this->maxTopicAliases)
  346 + throw ProtocolError("Client exceeded max topic aliases.");
  347 +
  348 + this->topicAliases[alias_id] = topic;
  349 +}
  350 +
  351 +const std::string &Client::getTopicAlias(const uint16_t id)
  352 +{
  353 + return this->topicAliases[id];
  354 +}
  355 +
337 356 #ifndef NDEBUG
338 357 /**
339 358 * @brief IoWrapper::setFakeUpgraded().
... ...
client.h
... ... @@ -82,6 +82,8 @@ class Client
82 82  
83 83 std::shared_ptr<Session> session;
84 84  
  85 + std::unordered_map<uint16_t, std::string> topicAliases;
  86 +
85 87 Logger *logger = Logger::getInstance();
86 88  
87 89 void setReadyForWriting(bool val);
... ... @@ -137,6 +139,9 @@ public:
137 139 std::string getKeepAliveInfoString() const;
138 140 void resetBuffersIfEligible();
139 141  
  142 + void setTopicAlias(const uint16_t alias_id, const std::string &topic);
  143 + const std::string &getTopicAlias(const uint16_t id);
  144 +
140 145 #ifndef NDEBUG
141 146 void setFakeUpgraded();
142 147 #endif
... ...
mqttpacket.cpp
... ... @@ -343,7 +343,7 @@ void MqttPacket::handleConnect()
343 343 uint16_t max_qos_packets = settings.maxQosMsgPendingPerClient;
344 344 uint32_t session_expire = settings.expireSessionsAfterSeconds > 0 ? settings.expireSessionsAfterSeconds : std::numeric_limits<uint32_t>::max();
345 345 uint32_t max_packet_size = settings.maxPacketSize;
346   - uint16_t max_topic_aliases = 0;
  346 + uint16_t max_topic_aliases = settings.maxTopicAliases;
347 347 bool request_response_information = false;
348 348 bool request_problem_information = false;
349 349  
... ... @@ -750,10 +750,7 @@ void MqttPacket::handleUnsubscribe()
750 750  
751 751 void MqttPacket::handlePublish()
752 752 {
753   - uint16_t variable_header_length = readTwoBytesToUInt16();
754   -
755   - if (variable_header_length == 0)
756   - throw ProtocolError("Empty publish topic");
  753 + const uint16_t variable_header_length = readTwoBytesToUInt16();
757 754  
758 755 bool retain = (first_byte & 0b00000001);
759 756 bool dup = !!(first_byte & 0b00001000);
... ... @@ -767,19 +764,6 @@ void MqttPacket::handlePublish()
767 764 throw ProtocolError("Duplicate flag is set for QoS 0 packet. This is illegal.");
768 765  
769 766 publishData.topic = std::string(readBytes(variable_header_length), variable_header_length);
770   - splitTopic(publishData.topic, publishData.subtopics);
771   -
772   - if (!isValidUtf8(publishData.topic, true))
773   - {
774   - logger->logf(LOG_WARNING, "Client '%s' published a message with invalid UTF8 or $/+/# in it. Dropping.", sender->repr().c_str());
775   - return;
776   - }
777   -
778   -#ifndef NDEBUG
779   - logger->logf(LOG_DEBUG, "Publish received, topic '%s'. QoS=%d. Retain=%d, dup=%d", publishData.topic.c_str(), qos, retain, dup);
780   -#endif
781   -
782   - sender->getThreadData()->incrementReceivedMessageCount();
783 767  
784 768 if (qos)
785 769 {
... ... @@ -820,6 +804,7 @@ void MqttPacket::handlePublish()
820 804 const size_t proplen = decodeVariableByteIntAtPos();
821 805 const size_t prop_end_at = pos + proplen;
822 806  
  807 + // TODO: don't do this when the only properties are expiry and topic alias; they don't need the builder.
823 808 if (proplen > 0)
824 809 publishData.constructPropertyBuilder();
825 810  
... ... @@ -836,7 +821,21 @@ void MqttPacket::handlePublish()
836 821 publishData.createdAt = std::chrono::steady_clock::now();
837 822 publishData.expiresAfter = std::chrono::seconds(readFourBytesToUint32());
838 823 case Mqtt5Properties::TopicAlias:
  824 + {
  825 + const uint16_t alias_id = readTwoBytesToUInt16();
  826 + this->hasTopicAlias = true;
  827 +
  828 + if (publishData.topic.empty())
  829 + {
  830 + publishData.topic = sender->getTopicAlias(alias_id);
  831 + }
  832 + else
  833 + {
  834 + sender->setTopicAlias(alias_id, publishData.topic);
  835 + }
  836 +
839 837 break;
  838 + }
840 839 case Mqtt5Properties::ResponseTopic:
841 840 {
842 841 const uint16_t len = readTwoBytesToUInt16();
... ... @@ -878,6 +877,23 @@ void MqttPacket::handlePublish()
878 877 }
879 878 }
880 879  
  880 + splitTopic(publishData.topic, publishData.subtopics);
  881 +
  882 + if (!isValidUtf8(publishData.topic, true))
  883 + {
  884 + logger->logf(LOG_WARNING, "Client '%s' published a message with invalid UTF8 or $/+/# in it. Dropping.", sender->repr().c_str());
  885 + return;
  886 + }
  887 +
  888 + if (publishData.topic.empty())
  889 + throw ProtocolError("Empty publish topic");
  890 +
  891 +#ifndef NDEBUG
  892 + logger->logf(LOG_DEBUG, "Publish received, topic '%s'. QoS=%d. Retain=%d, dup=%d", publishData.topic.c_str(), qos, retain, dup);
  893 +#endif
  894 +
  895 + sender->getThreadData()->incrementReceivedMessageCount();
  896 +
881 897 payloadLen = remainingAfterPos();
882 898 payloadStart = pos;
883 899  
... ... @@ -1237,7 +1253,7 @@ bool MqttPacket::containsClientSpecificProperties() const
1237 1253 if (protocolVersion <= ProtocolVersion::Mqtt311 || !publishData.propertyBuilder)
1238 1254 return false;
1239 1255  
1240   - if (publishData.createdAt.time_since_epoch().count() == 0) // TODO: better
  1256 + if (publishData.createdAt.time_since_epoch().count() == 0 || this->hasTopicAlias) // TODO: better
1241 1257 {
1242 1258 return true;
1243 1259 }
... ...
mqttpacket.h
... ... @@ -54,6 +54,7 @@ class MqttPacket
54 54 ProtocolVersion protocolVersion = ProtocolVersion::None;
55 55 size_t payloadStart = 0;
56 56 size_t payloadLen = 0;
  57 + bool hasTopicAlias = false;
57 58 Logger *logger = Logger::getInstance();
58 59  
59 60 char *readBytes(size_t length);
... ...
settings.h
... ... @@ -42,6 +42,7 @@ public:
42 42 bool authPluginSerializeAuthChecks = false;
43 43 int clientInitialBufferSize = 1024; // Must be power of 2
44 44 int maxPacketSize = 268435461; // 256 MB + 5
  45 + uint16_t maxTopicAliases = 65535;
45 46 #ifdef TESTING
46 47 bool logDebug = true;
47 48 #else
... ...