Commit 940d7edcfc79174cff791b336000dbc2025a58c1

Authored by Wiebe Cazemier
1 parent 592e12eb

Replace the thread_local global subtopic memory

It caused typical global variable issues, showing in the retained
messages recursive alghorithm breaking, because the referenced subtopics
changed half way (see previous commit of the test for it).

I need to perform some benchmarks to see if I need to devise an
alternative.
mqttpacket.cpp
... ... @@ -24,10 +24,6 @@ License along with FlashMQ. If not, see <https://www.gnu.org/licenses/>.
24 24 #include "utils.h"
25 25 #include "threadauth.h"
26 26  
27   -// We can void constant reallocation of space for parsed subtopics by using this. But, beware to only use it during handling of the current
28   -// packet. Don't access it for a stored packet, because then it will have changed.
29   -thread_local std::vector<std::string> gSubtopics;
30   -
31 27 RemainingLength::RemainingLength()
32 28 {
33 29 memset(bytes, 0, 4);
... ... @@ -110,8 +106,7 @@ MqttPacket::MqttPacket(const Publish &amp;publish) :
110 106 }
111 107  
112 108 this->topic = publish.topic;
113   - this->subtopics = &gSubtopics;
114   - splitTopic(this->topic, gSubtopics);
  109 + splitTopic(this->topic, subtopics);
115 110  
116 111 packetType = PacketType::PUBLISH;
117 112 this->qos = publish.qos;
... ... @@ -417,7 +412,6 @@ void MqttPacket::handleDisconnect()
417 412  
418 413 void MqttPacket::handleSubscribe()
419 414 {
420   - this->subtopics = &gSubtopics;
421 415 const char firstByteFirstNibble = (first_byte & 0x0F);
422 416  
423 417 if (firstByteFirstNibble != 2)
... ... @@ -449,11 +443,11 @@ void MqttPacket::handleSubscribe()
449 443 if (qos > 2)
450 444 throw ProtocolError("QoS is greater than 2, and/or reserved bytes in QoS field are not 0.");
451 445  
452   - splitTopic(topic, *subtopics);
453   - if (authentication.aclCheck(sender->getClientId(), sender->getUsername(), topic, *subtopics, AclAccess::subscribe, qos, false) == AuthResult::success)
  446 + splitTopic(topic, subtopics);
  447 + if (authentication.aclCheck(sender->getClientId(), sender->getUsername(), topic, subtopics, AclAccess::subscribe, qos, false) == AuthResult::success)
454 448 {
455 449 logger->logf(LOG_SUBSCRIBE, "Client '%s' subscribed to '%s' QoS %d", sender->repr().c_str(), topic.c_str(), qos);
456   - sender->getThreadData()->getSubscriptionStore()->addSubscription(sender, topic, *subtopics, qos);
  450 + sender->getThreadData()->getSubscriptionStore()->addSubscription(sender, topic, subtopics, qos);
457 451 subs_reponse_codes.push_back(qos);
458 452 }
459 453 else
... ... @@ -477,7 +471,6 @@ void MqttPacket::handleSubscribe()
477 471 SubAck subAck(packet_id, subs_reponse_codes);
478 472 MqttPacket response(subAck);
479 473 sender->writeMqttPacket(response);
480   - this->subtopics = nullptr;
481 474 }
482 475  
483 476 void MqttPacket::handleUnsubscribe()
... ... @@ -540,8 +533,7 @@ void MqttPacket::handlePublish()
540 533 throw ProtocolError("Duplicate flag is set for QoS 0 packet. This is illegal.");
541 534  
542 535 topic = std::string(readBytes(variable_header_length), variable_header_length);
543   - subtopics = &gSubtopics;
544   - splitTopic(topic, gSubtopics);
  536 + splitTopic(topic, subtopics);
545 537  
546 538 if (!isValidUtf8(topic, true))
547 539 {
... ... @@ -593,12 +585,12 @@ void MqttPacket::handlePublish()
593 585 payloadStart = pos;
594 586  
595 587 Authentication &authentication = *ThreadAuth::getAuth();
596   - if (authentication.aclCheck(sender->getClientId(), sender->getUsername(), topic, *subtopics, AclAccess::write, qos, retain) == AuthResult::success)
  588 + if (authentication.aclCheck(sender->getClientId(), sender->getUsername(), topic, subtopics, AclAccess::write, qos, retain) == AuthResult::success)
597 589 {
598 590 if (retain)
599 591 {
600 592 std::string payload(readBytes(payloadLen), payloadLen);
601   - sender->getThreadData()->getSubscriptionStore()->setRetainedMessage(topic, *subtopics, payload, qos);
  593 + sender->getThreadData()->getSubscriptionStore()->setRetainedMessage(topic, subtopics, payload, qos);
602 594 }
603 595  
604 596 // Set dup flag to 0, because that must not be propagated [MQTT-3.3.1-3].
... ... @@ -607,9 +599,8 @@ void MqttPacket::handlePublish()
607 599 first_byte = bites[0];
608 600  
609 601 // For the existing clients, we can just write the same packet back out, with our small alterations.
610   - sender->getThreadData()->getSubscriptionStore()->queuePacketAtSubscribers(*subtopics, *this);
  602 + sender->getThreadData()->getSubscriptionStore()->queuePacketAtSubscribers(subtopics, *this);
611 603 }
612   - this->subtopics = nullptr;
613 604 }
614 605  
615 606 void MqttPacket::handlePubAck()
... ... @@ -767,7 +758,7 @@ const std::string &amp;MqttPacket::getTopic() const
767 758 * @brief MqttPacket::getSubtopics returns a pointer to the parsed subtopics. Use with care!
768 759 * @return a pointer to a vector of subtopics that will be overwritten the next packet!
769 760 */
770   -const std::vector<std::string> *MqttPacket::getSubtopics() const
  761 +const std::vector<std::string> &MqttPacket::getSubtopics() const
771 762 {
772 763 return this->subtopics;
773 764 }
... ...
mqttpacket.h
... ... @@ -48,7 +48,7 @@ class MqttPacket
48 48 #endif
49 49  
50 50 std::string topic;
51   - std::vector<std::string> *subtopics = nullptr;
  51 + std::vector<std::string> subtopics;
52 52 std::vector<char> bites;
53 53 size_t fixed_header_length = 0; // if 0, this packet does not contain the bytes of the fixed header.
54 54 RemainingLength remainingLength;
... ... @@ -108,7 +108,7 @@ public:
108 108 const std::vector<char> &getBites() const { return bites; }
109 109 char getQos() const { return qos; }
110 110 const std::string &getTopic() const;
111   - const std::vector<std::string> *getSubtopics() const;
  111 + const std::vector<std::string> &getSubtopics() const;
112 112 std::shared_ptr<Client> getSender() const;
113 113 void setSender(const std::shared_ptr<Client> &value);
114 114 bool containsFixedHeader() const;
... ...
session.cpp
... ... @@ -129,7 +129,7 @@ void Session::writePacket(const MqttPacket &amp;packet, char max_qos, bool retain, u
129 129 Authentication *_auth = ThreadAuth::getAuth();
130 130 assert(_auth);
131 131 Authentication &auth = *_auth;
132   - if (auth.aclCheck(client_id, username, packet.getTopic(), *packet.getSubtopics(), AclAccess::read, qos, retain) == AuthResult::success)
  132 + if (auth.aclCheck(client_id, username, packet.getTopic(), packet.getSubtopics(), AclAccess::read, qos, retain) == AuthResult::success)
133 133 {
134 134 if (qos == 0)
135 135 {
... ...