mirror of
https://github.com/eclipse/paho.mqtt-sn.embedded-c.git
synced 2025-12-13 23:46:51 +01:00
520 lines
9.6 KiB
C++
520 lines
9.6 KiB
C++
/**************************************************************************************
|
|
* Copyright (c) 2016, Tomoaki Yamaguchi
|
|
*
|
|
* All rights reserved. This program and the accompanying materials
|
|
* are made available under the terms of the Eclipse Public License v1.0
|
|
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
|
*
|
|
* The Eclipse Public License is available at
|
|
* http://www.eclipse.org/legal/epl-v10.html
|
|
* and the Eclipse Distribution License is available at
|
|
* http://www.eclipse.org/org/documents/edl-v10.php.
|
|
*
|
|
* Contributors:
|
|
* Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
|
|
* Tieto Poland Sp. z o.o. - Gateway improvements
|
|
**************************************************************************************/
|
|
#include "MQTTSNGWTopic.h"
|
|
#include "MQTTSNGWDefines.h"
|
|
#include "MQTTSNGateway.h"
|
|
#include <string.h>
|
|
|
|
using namespace MQTTSNGW;
|
|
|
|
/*=====================================
|
|
Class Topic
|
|
======================================*/
|
|
Topic::Topic()
|
|
{
|
|
_type = MQTTSN_TOPIC_TYPE_NORMAL;
|
|
_topicName = nullptr;
|
|
_topicId = 0;
|
|
_next = nullptr;
|
|
}
|
|
|
|
Topic::Topic(string* topic, MQTTSN_topicTypes type)
|
|
{
|
|
_type = type;
|
|
_topicName = topic;
|
|
_topicId = 0;
|
|
_next = nullptr;
|
|
}
|
|
|
|
Topic::~Topic()
|
|
{
|
|
if ( _topicName )
|
|
{
|
|
delete _topicName;
|
|
}
|
|
}
|
|
|
|
string* Topic::getTopicName(void)
|
|
{
|
|
return _topicName;
|
|
}
|
|
|
|
uint16_t Topic::getTopicId(void)
|
|
{
|
|
return _topicId;
|
|
}
|
|
|
|
MQTTSN_topicTypes Topic::getType(void)
|
|
{
|
|
return _type;
|
|
}
|
|
|
|
bool Topic::isMatch(string* topicName)
|
|
{
|
|
string::size_type tlen = _topicName->size();
|
|
|
|
string::size_type tpos = 0;
|
|
string::size_type tloc = 0;
|
|
string::size_type pos = 0;
|
|
string::size_type loc = 0;
|
|
string wildcard = "#";
|
|
string wildcards = "+";
|
|
|
|
while(true)
|
|
{
|
|
loc = topicName->find('/', pos);
|
|
tloc = _topicName->find('/', tpos);
|
|
|
|
if ( loc != string::npos && tloc != string::npos )
|
|
{
|
|
string subtopic = topicName->substr(pos, loc - pos);
|
|
string subtopict = _topicName->substr(tpos, tloc - tpos);
|
|
if (subtopict == wildcard)
|
|
{
|
|
return true;
|
|
}
|
|
else if (subtopict == wildcards)
|
|
{
|
|
if ( (tpos = tloc + 1 ) > tlen )
|
|
{
|
|
pos = loc + 1;
|
|
loc = topicName->find('/', pos);
|
|
if ( loc == string::npos )
|
|
{
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
pos = loc + 1;
|
|
}
|
|
else if ( subtopic != subtopict )
|
|
{
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
if ( (tpos = tloc + 1) > tlen )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
pos = loc + 1;
|
|
}
|
|
}
|
|
else if ( loc == string::npos && tloc == string::npos )
|
|
{
|
|
string subtopic = topicName->substr(pos);
|
|
string subtopict = _topicName->substr(tpos);
|
|
if ( subtopict == wildcard || subtopict == wildcards)
|
|
{
|
|
return true;
|
|
}
|
|
else if ( subtopic == subtopict )
|
|
{
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
else if ( loc == string::npos && tloc != string::npos )
|
|
{
|
|
string subtopic = topicName->substr(pos);
|
|
string subtopict = _topicName->substr(tpos, tloc - tpos);
|
|
if ( subtopic != subtopict)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
tpos = tloc + 1;
|
|
|
|
return _topicName->substr(tpos) == wildcard;
|
|
}
|
|
else if ( loc != string::npos && tloc == string::npos )
|
|
{
|
|
return _topicName->substr(tpos) == wildcard;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Topic::print(void)
|
|
{
|
|
WRITELOG("TopicName=%s ID=%d Type=%d\n", _topicName->c_str(), _topicId, _type);
|
|
}
|
|
|
|
/*=====================================
|
|
Class Topics
|
|
======================================*/
|
|
Topics::Topics()
|
|
{
|
|
_first = nullptr;
|
|
_nextTopicId = 0;
|
|
_cnt = 0;
|
|
}
|
|
|
|
Topics::~Topics()
|
|
{
|
|
Topic* p = _first;
|
|
while (p)
|
|
{
|
|
Topic* q = p->_next;
|
|
delete p;
|
|
p = q;
|
|
}
|
|
}
|
|
|
|
Topic* Topics::getTopicByName(const MQTTSN_topicid* topicid)
|
|
{
|
|
Topic* p = _first;
|
|
char* ch = topicid->data.long_.name;
|
|
|
|
string sname = string(ch, ch + topicid->data.long_.len);
|
|
while (p)
|
|
{
|
|
if ( p->_topicName->compare(sname) == 0 )
|
|
{
|
|
return p;
|
|
}
|
|
p = p->_next;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
Topic* Topics::getTopicById(const MQTTSN_topicid* topicid)
|
|
{
|
|
Topic* p = _first;
|
|
|
|
while (p)
|
|
{
|
|
if ( p->_type == topicid->type && p->_topicId == topicid->data.id )
|
|
{
|
|
return p;
|
|
}
|
|
p = p->_next;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// For MQTTSN_TOPIC_TYPE_NORMAL */
|
|
Topic* Topics::add(const MQTTSN_topicid* topicid)
|
|
{
|
|
if (topicid->type != MQTTSN_TOPIC_TYPE_NORMAL )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
Topic* topic = getTopicByName(topicid);
|
|
|
|
if ( topic )
|
|
{
|
|
return topic;
|
|
}
|
|
string name(topicid->data.long_.name, topicid->data.long_.len);
|
|
return add(name.c_str(), 0);
|
|
}
|
|
|
|
Topic* Topics::add(const char* topicName, uint16_t id)
|
|
{
|
|
MQTTSN_topicid topicId;
|
|
|
|
if ( _cnt >= MAX_TOPIC_PAR_CLIENT )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
topicId.data.long_.name = (char*)const_cast<char*>(topicName);
|
|
topicId.data.long_.len = strlen(topicName);
|
|
|
|
|
|
Topic* topic = getTopicByName(&topicId);
|
|
|
|
if ( topic )
|
|
{
|
|
return topic;
|
|
}
|
|
|
|
topic = new Topic();
|
|
|
|
if (topic == nullptr)
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
string* name = new string(topicName);
|
|
topic->_topicName = name;
|
|
|
|
if ( id == 0 )
|
|
{
|
|
topic->_type = MQTTSN_TOPIC_TYPE_NORMAL;
|
|
topic->_topicId = getNextTopicId();
|
|
}
|
|
else
|
|
{
|
|
topic->_type = MQTTSN_TOPIC_TYPE_PREDEFINED;
|
|
topic->_topicId = id;
|
|
}
|
|
|
|
_cnt++;
|
|
|
|
if ( _first == nullptr)
|
|
{
|
|
_first = topic;
|
|
}
|
|
else
|
|
{
|
|
Topic* tp = _first;
|
|
while (tp)
|
|
{
|
|
if (tp->_next == nullptr)
|
|
{
|
|
tp->_next = topic;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
tp = tp->_next;
|
|
}
|
|
}
|
|
}
|
|
return topic;
|
|
}
|
|
|
|
uint16_t Topics::getNextTopicId()
|
|
{
|
|
return ++_nextTopicId == 0xffff ? _nextTopicId += 2 : _nextTopicId;
|
|
}
|
|
|
|
Topic* Topics::match(const MQTTSN_topicid* topicid)
|
|
{
|
|
if (topicid->type != MQTTSN_TOPIC_TYPE_NORMAL)
|
|
{
|
|
return 0;
|
|
}
|
|
string topicName(topicid->data.long_.name, topicid->data.long_.len);
|
|
|
|
Topic* topic = _first;
|
|
while (topic)
|
|
{
|
|
if (topic->isMatch(&topicName))
|
|
{
|
|
return topic;
|
|
}
|
|
topic = topic->_next;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
void Topics::eraseNormal(void)
|
|
{
|
|
Topic* topic = _first;
|
|
Topic* next = nullptr;
|
|
Topic* prev = nullptr;
|
|
|
|
while (topic)
|
|
{
|
|
if ( topic->_type == MQTTSN_TOPIC_TYPE_NORMAL )
|
|
{
|
|
next = topic->_next;
|
|
if ( _first == topic )
|
|
{
|
|
_first = next;
|
|
}
|
|
if ( prev )
|
|
{
|
|
prev->_next = next;
|
|
}
|
|
delete topic;
|
|
_cnt--;
|
|
topic = next;
|
|
}
|
|
else
|
|
{
|
|
prev = topic;
|
|
topic = topic->_next;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Topics::print(void)
|
|
{
|
|
Topic* topic = _first;
|
|
if (topic == nullptr )
|
|
{
|
|
WRITELOG("No Topic.\n");
|
|
}
|
|
else
|
|
{
|
|
while (topic)
|
|
{
|
|
topic->print();
|
|
topic = topic->_next;
|
|
}
|
|
}
|
|
}
|
|
|
|
uint8_t Topics::getCount(void)
|
|
{
|
|
return _cnt;
|
|
}
|
|
|
|
/*=====================================
|
|
Class TopicIdMap
|
|
=====================================*/
|
|
TopicIdMapElement::TopicIdMapElement(uint16_t msgId, uint16_t topicId, MQTTSN_topicTypes type)
|
|
{
|
|
_msgId = msgId;
|
|
_topicId = topicId;
|
|
_type = type;
|
|
_next = nullptr;
|
|
_prev = nullptr;
|
|
}
|
|
|
|
TopicIdMapElement::~TopicIdMapElement()
|
|
{
|
|
|
|
}
|
|
|
|
MQTTSN_topicTypes TopicIdMapElement::getTopicType(void)
|
|
{
|
|
return _type;
|
|
}
|
|
|
|
uint16_t TopicIdMapElement::getTopicId(void)
|
|
{
|
|
return _topicId;
|
|
}
|
|
|
|
TopicIdMap::TopicIdMap()
|
|
{
|
|
_maxInflight = MAX_INFLIGHTMESSAGES;
|
|
_msgIds = 0;
|
|
_first = nullptr;
|
|
_end = nullptr;
|
|
_cnt = 0;
|
|
}
|
|
|
|
TopicIdMap::~TopicIdMap()
|
|
{
|
|
TopicIdMapElement* p = _first;
|
|
while ( p )
|
|
{
|
|
TopicIdMapElement* q = p->_next;
|
|
delete p;
|
|
p = q;
|
|
}
|
|
}
|
|
|
|
TopicIdMapElement* TopicIdMap::getElement(uint16_t msgId)
|
|
{
|
|
TopicIdMapElement* p = _first;
|
|
while ( p )
|
|
{
|
|
if ( p->_msgId == msgId )
|
|
{
|
|
return p;
|
|
}
|
|
p = p->_next;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
TopicIdMapElement* TopicIdMap::add(uint16_t msgId, uint16_t topicId, MQTTSN_topicTypes type)
|
|
{
|
|
if ( _cnt > _maxInflight * 2 || ( topicId == 0 && type != MQTTSN_TOPIC_TYPE_SHORT ) )
|
|
{
|
|
return 0;
|
|
}
|
|
if ( getElement(msgId) > 0 )
|
|
{
|
|
erase(msgId);
|
|
}
|
|
|
|
TopicIdMapElement* elm = new TopicIdMapElement(msgId, topicId, type);
|
|
if ( elm == 0 )
|
|
{
|
|
return 0;
|
|
}
|
|
if ( _first == nullptr )
|
|
{
|
|
_first = elm;
|
|
_end = elm;
|
|
}
|
|
else
|
|
{
|
|
elm->_prev = _end;
|
|
_end->_next = elm;
|
|
_end = elm;
|
|
}
|
|
_cnt++;
|
|
return elm;
|
|
}
|
|
|
|
void TopicIdMap::erase(uint16_t msgId)
|
|
{
|
|
TopicIdMapElement* p = _first;
|
|
while ( p )
|
|
{
|
|
if ( p->_msgId == msgId )
|
|
{
|
|
if ( p->_prev == nullptr )
|
|
{
|
|
_first = p->_next;
|
|
}
|
|
else
|
|
{
|
|
p->_prev->_next = p->_next;
|
|
}
|
|
|
|
if ( p->_next == nullptr )
|
|
{
|
|
_end = p->_prev;
|
|
}
|
|
else
|
|
{
|
|
p->_next->_prev = p->_prev;
|
|
}
|
|
delete p;
|
|
break;
|
|
|
|
}
|
|
p = p->_next;
|
|
}
|
|
_cnt--;
|
|
}
|
|
|
|
void TopicIdMap::clear(void)
|
|
{
|
|
TopicIdMapElement* p = _first;
|
|
while ( p )
|
|
{
|
|
TopicIdMapElement* q = p->_next;
|
|
delete p;
|
|
p = q;
|
|
}
|
|
_first = nullptr;
|
|
_end = nullptr;
|
|
_cnt = 0;
|
|
}
|
|
|
|
|
|
|