Commit 98366c6dfb466bf89d2258d8b446278dd7d600b1

Authored by Wiebe Cazemier
1 parent 39c1873d

Get the semantics of incoming and outgoing aliases correct

client.cpp
@@ -208,11 +208,10 @@ int Client::writeMqttPacket(const MqttPacket &packet) @@ -208,11 +208,10 @@ int Client::writeMqttPacket(const MqttPacket &packet)
208 208
209 int Client::writeMqttPacketAndBlameThisClient(PublishCopyFactory &copyFactory, char max_qos, uint16_t packet_id) 209 int Client::writeMqttPacketAndBlameThisClient(PublishCopyFactory &copyFactory, char max_qos, uint16_t packet_id)
210 { 210 {
211 - const Settings *settings = ThreadGlobals::getSettings();  
212 uint16_t topic_alias = 0; 211 uint16_t topic_alias = 0;
213 bool skip_topic = false; 212 bool skip_topic = false;
214 213
215 - if (protocolVersion >= ProtocolVersion::Mqtt5 && settings->maxOutgoingTopicAliases > this->curOutgoingTopicAlias) 214 + if (protocolVersion >= ProtocolVersion::Mqtt5 && this->maxOutgoingTopicAliasValue > this->curOutgoingTopicAlias)
216 { 215 {
217 uint16_t &id = this->outgoingTopicAliases[copyFactory.getTopic()]; 216 uint16_t &id = this->outgoingTopicAliases[copyFactory.getTopic()];
218 217
@@ -358,15 +357,18 @@ void Client::setTopicAlias(const uint16_t alias_id, const std::string &topic) @@ -358,15 +357,18 @@ void Client::setTopicAlias(const uint16_t alias_id, const std::string &topic)
358 if (topic.empty()) 357 if (topic.empty())
359 return; 358 return;
360 359
361 - if (alias_id > this->maxTopicAliases)  
362 - throw ProtocolError("Client exceeded max topic aliases."); 360 + const Settings *settings = ThreadGlobals::getSettings();
  361 +
  362 + // The specs actually say "The Client MUST NOT send a Topic Alias [...] to the Server greater than this value [Topic Alias Maximum]". So, it's not about count.
  363 + if (alias_id > settings->maxIncomingTopicAliasValue)
  364 + throw ProtocolError(formatString("Client tried to set more topic aliases than the server max of %d per client", settings->maxIncomingTopicAliasValue));
363 365
364 - this->topicAliases[alias_id] = topic; 366 + this->incomingTopicAliases[alias_id] = topic;
365 } 367 }
366 368
367 const std::string &Client::getTopicAlias(const uint16_t id) 369 const std::string &Client::getTopicAlias(const uint16_t id)
368 { 370 {
369 - return this->topicAliases[id]; 371 + return this->incomingTopicAliases[id];
370 } 372 }
371 373
372 #ifndef NDEBUG 374 #ifndef NDEBUG
@@ -460,7 +462,7 @@ void Client::setClientProperties(ProtocolVersion protocolVersion, const std::str @@ -460,7 +462,7 @@ void Client::setClientProperties(ProtocolVersion protocolVersion, const std::str
460 462
461 463
462 void Client::setClientProperties(ProtocolVersion protocolVersion, const std::string &clientId, const std::string username, bool connectPacketSeen, uint16_t keepalive, 464 void Client::setClientProperties(ProtocolVersion protocolVersion, const std::string &clientId, const std::string username, bool connectPacketSeen, uint16_t keepalive,
463 - uint32_t maxPacketSize, uint16_t maxTopicAliases) 465 + uint32_t maxPacketSize, uint16_t maxOutgoingTopicAliasValue)
464 { 466 {
465 this->protocolVersion = protocolVersion; 467 this->protocolVersion = protocolVersion;
466 this->clientid = clientId; 468 this->clientid = clientId;
@@ -468,7 +470,7 @@ void Client::setClientProperties(ProtocolVersion protocolVersion, const std::str @@ -468,7 +470,7 @@ void Client::setClientProperties(ProtocolVersion protocolVersion, const std::str
468 this->connectPacketSeen = connectPacketSeen; 470 this->connectPacketSeen = connectPacketSeen;
469 this->keepalive = keepalive; 471 this->keepalive = keepalive;
470 this->maxPacketSize = maxPacketSize; 472 this->maxPacketSize = maxPacketSize;
471 - this->maxTopicAliases = maxTopicAliases; 473 + this->maxOutgoingTopicAliasValue = maxOutgoingTopicAliasValue;
472 } 474 }
473 475
474 void Client::setWill(Publish &&willPublish) 476 void Client::setWill(Publish &&willPublish)
client.h
@@ -53,7 +53,7 @@ class Client @@ -53,7 +53,7 @@ class Client
53 53
54 const size_t initialBufferSize = 0; 54 const size_t initialBufferSize = 0;
55 uint32_t maxPacketSize = 0; 55 uint32_t maxPacketSize = 0;
56 - uint16_t maxTopicAliases = 0; 56 + uint16_t maxOutgoingTopicAliasValue = 0;
57 57
58 IoWrapper ioWrapper; 58 IoWrapper ioWrapper;
59 std::string transportStr; 59 std::string transportStr;
@@ -82,7 +82,7 @@ class Client @@ -82,7 +82,7 @@ class Client
82 82
83 std::shared_ptr<Session> session; 83 std::shared_ptr<Session> session;
84 84
85 - std::unordered_map<uint16_t, std::string> topicAliases; 85 + std::unordered_map<uint16_t, std::string> incomingTopicAliases;
86 86
87 uint16_t curOutgoingTopicAlias = 0; 87 uint16_t curOutgoingTopicAlias = 0;
88 std::unordered_map<std::string, uint16_t> outgoingTopicAliases; 88 std::unordered_map<std::string, uint16_t> outgoingTopicAliases;
@@ -111,7 +111,7 @@ public: @@ -111,7 +111,7 @@ public:
111 void bufferToMqttPackets(std::vector<MqttPacket> &packetQueueIn, std::shared_ptr<Client> &sender); 111 void bufferToMqttPackets(std::vector<MqttPacket> &packetQueueIn, std::shared_ptr<Client> &sender);
112 void setClientProperties(ProtocolVersion protocolVersion, const std::string &clientId, const std::string username, bool connectPacketSeen, uint16_t keepalive); 112 void setClientProperties(ProtocolVersion protocolVersion, const std::string &clientId, const std::string username, bool connectPacketSeen, uint16_t keepalive);
113 void setClientProperties(ProtocolVersion protocolVersion, const std::string &clientId, const std::string username, bool connectPacketSeen, uint16_t keepalive, 113 void setClientProperties(ProtocolVersion protocolVersion, const std::string &clientId, const std::string username, bool connectPacketSeen, uint16_t keepalive,
114 - uint32_t maxPacketSize, uint16_t maxTopicAliases); 114 + uint32_t maxPacketSize, uint16_t maxOutgoingTopicAliasValue);
115 void setWill(const std::string &topic, const std::string &payload, bool retain, char qos); 115 void setWill(const std::string &topic, const std::string &payload, bool retain, char qos);
116 void setWill(Publish &&willPublish); 116 void setWill(Publish &&willPublish);
117 void clearWill(); 117 void clearWill();
configfileparser.cpp
@@ -461,6 +461,26 @@ void ConfigFileParser::loadFile(bool test) @@ -461,6 +461,26 @@ void ConfigFileParser::loadFile(bool test)
461 } 461 }
462 tmpSettings->maxQosBytesPendingPerClient = newVal; 462 tmpSettings->maxQosBytesPendingPerClient = newVal;
463 } 463 }
  464 +
  465 + if (key == "max_incoming_topic_alias_value")
  466 + {
  467 + int newVal = std::stoi(value);
  468 + if (newVal < 0 || newVal > 0xFFFF)
  469 + {
  470 + throw ConfigFileException(formatString("max_incoming_topic_alias_value value '%d' is invalid. Valid values are between 0 and 65535.", newVal));
  471 + }
  472 + tmpSettings->maxIncomingTopicAliasValue = newVal;
  473 + }
  474 +
  475 + if (key == "max_outgoing_topic_alias_value")
  476 + {
  477 + int newVal = std::stoi(value);
  478 + if (newVal < 0 || newVal > 0xFFFF)
  479 + {
  480 + throw ConfigFileException(formatString("max_outgoing_topic_alias_value value '%d' is invalid. Valid values are between 0 and 65535.", newVal));
  481 + }
  482 + tmpSettings->maxOutgoingTopicAliasValue = newVal;
  483 + }
464 } 484 }
465 } 485 }
466 catch (std::invalid_argument &ex) // catch for the stoi() 486 catch (std::invalid_argument &ex) // catch for the stoi()
mqttpacket.cpp
@@ -345,7 +345,7 @@ void MqttPacket::handleConnect() @@ -345,7 +345,7 @@ void MqttPacket::handleConnect()
345 uint16_t max_qos_packets = settings.maxQosMsgPendingPerClient; 345 uint16_t max_qos_packets = settings.maxQosMsgPendingPerClient;
346 uint32_t session_expire = settings.expireSessionsAfterSeconds > 0 ? settings.expireSessionsAfterSeconds : std::numeric_limits<uint32_t>::max(); 346 uint32_t session_expire = settings.expireSessionsAfterSeconds > 0 ? settings.expireSessionsAfterSeconds : std::numeric_limits<uint32_t>::max();
347 uint32_t max_packet_size = settings.maxPacketSize; 347 uint32_t max_packet_size = settings.maxPacketSize;
348 - uint16_t max_topic_aliases = settings.maxOutgoingTopicAliases; 348 + uint16_t max_outgoing_topic_aliases = 0; // Default MUST BE 0, meaning server won't initiate aliases
349 bool request_response_information = false; 349 bool request_response_information = false;
350 bool request_problem_information = false; 350 bool request_problem_information = false;
351 351
@@ -370,7 +370,7 @@ void MqttPacket::handleConnect() @@ -370,7 +370,7 @@ void MqttPacket::handleConnect()
370 max_packet_size = std::min<uint32_t>(readFourBytesToUint32(), max_packet_size); 370 max_packet_size = std::min<uint32_t>(readFourBytesToUint32(), max_packet_size);
371 break; 371 break;
372 case Mqtt5Properties::TopicAliasMaximum: 372 case Mqtt5Properties::TopicAliasMaximum:
373 - max_topic_aliases = std::min<uint16_t>(readTwoBytesToUInt16(), max_topic_aliases); 373 + max_outgoing_topic_aliases = std::min<uint16_t>(readTwoBytesToUInt16(), settings.maxOutgoingTopicAliasValue);
374 break; 374 break;
375 case Mqtt5Properties::RequestResponseInformation: 375 case Mqtt5Properties::RequestResponseInformation:
376 request_response_information = !!readByte(); 376 request_response_information = !!readByte();
@@ -541,7 +541,7 @@ void MqttPacket::handleConnect() @@ -541,7 +541,7 @@ void MqttPacket::handleConnect()
541 clientIdGenerated = true; 541 clientIdGenerated = true;
542 } 542 }
543 543
544 - sender->setClientProperties(protocolVersion, client_id, username, true, keep_alive, max_packet_size, max_topic_aliases); 544 + sender->setClientProperties(protocolVersion, client_id, username, true, keep_alive, max_packet_size, max_outgoing_topic_aliases);
545 545
546 if (will_flag) 546 if (will_flag)
547 sender->setWill(std::move(willpublish)); 547 sender->setWill(std::move(willpublish));
@@ -582,7 +582,7 @@ void MqttPacket::handleConnect() @@ -582,7 +582,7 @@ void MqttPacket::handleConnect()
582 connAck.propertyBuilder->writeMaxPacketSize(max_packet_size); 582 connAck.propertyBuilder->writeMaxPacketSize(max_packet_size);
583 if (clientIdGenerated) 583 if (clientIdGenerated)
584 connAck.propertyBuilder->writeAssignedClientId(client_id); 584 connAck.propertyBuilder->writeAssignedClientId(client_id);
585 - connAck.propertyBuilder->writeMaxTopicAliases(max_topic_aliases); 585 + connAck.propertyBuilder->writeMaxTopicAliases(settings.maxIncomingTopicAliasValue);
586 connAck.propertyBuilder->writeWildcardSubscriptionAvailable(1); 586 connAck.propertyBuilder->writeWildcardSubscriptionAvailable(1);
587 connAck.propertyBuilder->writeSubscriptionIdentifiersAvailable(0); 587 connAck.propertyBuilder->writeSubscriptionIdentifiersAvailable(0);
588 connAck.propertyBuilder->writeSharedSubscriptionAvailable(0); 588 connAck.propertyBuilder->writeSharedSubscriptionAvailable(0);
settings.h
@@ -42,8 +42,8 @@ public: @@ -42,8 +42,8 @@ public:
42 bool authPluginSerializeAuthChecks = false; 42 bool authPluginSerializeAuthChecks = false;
43 int clientInitialBufferSize = 1024; // Must be power of 2 43 int clientInitialBufferSize = 1024; // Must be power of 2
44 int maxPacketSize = 268435461; // 256 MB + 5 44 int maxPacketSize = 268435461; // 256 MB + 5
45 - uint16_t maxIncomingTopicAliases = 65535;  
46 - uint16_t maxOutgoingTopicAliases = 0; // TODO: setting, when I can confirm with clients that support it that it works. 45 + uint16_t maxIncomingTopicAliasValue = 65535;
  46 + uint16_t maxOutgoingTopicAliasValue = 65535;
47 #ifdef TESTING 47 #ifdef TESTING
48 bool logDebug = true; 48 bool logDebug = true;
49 #else 49 #else