Jack Hansdampf / mbed-mqtt-GSOE1

Dependents:   ESP8266MQTT

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers MQTTSNGWTopic.cpp Source File

MQTTSNGWTopic.cpp

00001 /**************************************************************************************
00002  * Copyright (c) 2016, Tomoaki Yamaguchi
00003  *
00004  * All rights reserved. This program and the accompanying materials
00005  * are made available under the terms of the Eclipse Public License v1.0
00006  * and Eclipse Distribution License v1.0 which accompany this distribution.
00007  *
00008  * The Eclipse Public License is available at
00009  *    http://www.eclipse.org/legal/epl-v10.html
00010  * and the Eclipse Distribution License is available at
00011  *   http://www.eclipse.org/org/documents/edl-v10.php.
00012  *
00013  * Contributors:
00014  *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
00015  *    Tieto Poland Sp. z o.o. - Gateway improvements
00016  **************************************************************************************/
00017 #include "MQTTSNGWTopic.h"
00018 #include "MQTTSNGWDefines.h"
00019 #include "MQTTSNGateway.h"
00020 #include <string.h>
00021 
00022 using namespace MQTTSNGW;
00023 
00024 /*=====================================
00025  Class Topic
00026  ======================================*/
00027 Topic::Topic()
00028 {
00029     _type = MQTTSN_TOPIC_TYPE_NORMAL;
00030     _topicName = nullptr;
00031     _topicId = 0;
00032     _next = nullptr;
00033 }
00034 
00035 Topic::Topic(string* topic, MQTTSN_topicTypes type)
00036 {
00037     _type = type;
00038     _topicName = topic;
00039     _topicId = 0;
00040     _next = nullptr;
00041 }
00042 
00043 Topic::~Topic()
00044 {
00045     if ( _topicName )
00046     {
00047         delete _topicName;
00048     }
00049 }
00050 
00051 string* Topic::getTopicName(void)
00052 {
00053     return _topicName;
00054 }
00055 
00056 uint16_t Topic::getTopicId(void)
00057 {
00058     return _topicId;
00059 }
00060 
00061 MQTTSN_topicTypes Topic::getType(void)
00062 {
00063     return _type;
00064 }
00065 
00066 bool Topic::isMatch(string* topicName)
00067 {
00068     string::size_type tlen = _topicName->size();
00069 
00070     string::size_type tpos = 0;
00071     string::size_type tloc = 0;
00072     string::size_type pos = 0;
00073     string::size_type loc = 0;
00074     string wildcard = "#";
00075     string wildcards = "+";
00076 
00077     while(true)
00078     {
00079         loc = topicName->find('/', pos);
00080         tloc = _topicName->find('/', tpos);
00081 
00082         if ( loc != string::npos && tloc != string::npos )
00083         {
00084             string subtopic = topicName->substr(pos, loc - pos);
00085             string subtopict = _topicName->substr(tpos, tloc - tpos);
00086             if (subtopict == wildcard)
00087             {
00088                 return true;
00089             }
00090             else if (subtopict == wildcards)
00091             {
00092                 if ( (tpos = tloc + 1 ) > tlen )
00093                 {
00094                     pos = loc + 1;
00095                     loc = topicName->find('/', pos);
00096                     if ( loc == string::npos )
00097                     {
00098                         return true;
00099                     }
00100                     else
00101                     {
00102                         return false;
00103                     }
00104                 }
00105                 pos = loc + 1;
00106             }
00107             else if ( subtopic != subtopict )
00108             {
00109                 return false;
00110             }
00111             else
00112             {
00113                 if ( (tpos = tloc + 1) > tlen )
00114                 {
00115                     return false;
00116                 }
00117 
00118                 pos = loc + 1;
00119             }
00120         }
00121         else if ( loc == string::npos && tloc == string::npos )
00122         {
00123             string subtopic = topicName->substr(pos);
00124             string subtopict = _topicName->substr(tpos);
00125             if ( subtopict == wildcard || subtopict == wildcards)
00126             {
00127                 return true;
00128             }
00129             else if ( subtopic == subtopict )
00130             {
00131                 return true;
00132             }
00133             else
00134             {
00135                 return false;
00136             }
00137         }
00138         else if ( loc == string::npos && tloc != string::npos )
00139         {
00140             string subtopic = topicName->substr(pos);
00141             string subtopict = _topicName->substr(tpos, tloc - tpos);
00142             if ( subtopic != subtopict)
00143             {
00144                 return false;
00145             }
00146 
00147             tpos = tloc + 1;
00148 
00149             return _topicName->substr(tpos) == wildcard;
00150         }
00151         else if ( loc != string::npos && tloc == string::npos )
00152         {
00153             return _topicName->substr(tpos) == wildcard;
00154         }
00155     }
00156 }
00157 
00158 void Topic::print(void)
00159 {
00160     WRITELOG("TopicName=%s  ID=%d  Type=%d\n", _topicName->c_str(), _topicId, _type);
00161 }
00162 
00163 /*=====================================
00164  Class Topics
00165  ======================================*/
00166 Topics::Topics()
00167 {
00168     _first = nullptr;
00169     _nextTopicId = 0;
00170     _cnt = 0;
00171 }
00172 
00173 Topics::~Topics()
00174 {
00175     Topic* p = _first;
00176     while (p)
00177     {
00178         Topic* q = p->_next;
00179         delete p;
00180         p = q;
00181     }
00182 }
00183 
00184 Topic* Topics::getTopicByName(const MQTTSN_topicid* topicid)
00185 {
00186     Topic* p = _first;
00187     char* ch = topicid->data.long_.name;
00188 
00189     string sname = string(ch, ch + topicid->data.long_.len);
00190     while (p)
00191     {
00192          if (  p->_topicName->compare(sname) == 0 )
00193          {
00194              return p;
00195          }
00196          p = p->_next;
00197     }
00198     return 0;
00199 }
00200 
00201 Topic* Topics::getTopicById(const MQTTSN_topicid* topicid)
00202 {
00203     Topic* p = _first;
00204 
00205     while (p)
00206     {
00207         if ( p->_type == topicid->type && p->_topicId == topicid->data.id )
00208         {
00209             return p;
00210         }
00211         p = p->_next;
00212     }
00213     return 0;
00214 }
00215 
00216 // For MQTTSN_TOPIC_TYPE_NORMAL */
00217 Topic* Topics::add(const MQTTSN_topicid* topicid)
00218 {
00219     if (topicid->type != MQTTSN_TOPIC_TYPE_NORMAL )
00220     {
00221         return 0;
00222     }
00223 
00224     Topic* topic = getTopicByName(topicid);
00225 
00226     if ( topic )
00227     {
00228         return topic;
00229     }
00230     string name(topicid->data.long_.name, topicid->data.long_.len);
00231     return add(name.c_str(), 0);
00232 }
00233 
00234 Topic* Topics::add(const char* topicName, uint16_t id)
00235 {
00236     MQTTSN_topicid topicId;
00237 
00238     if (  _cnt >= MAX_TOPIC_PAR_CLIENT )
00239     {
00240         return 0;
00241     }
00242 
00243     topicId.data.long_.name = (char*)const_cast<char*>(topicName);
00244     topicId.data.long_.len = strlen(topicName);
00245 
00246 
00247     Topic* topic = getTopicByName(&topicId);
00248 
00249     if ( topic )
00250     {
00251         return topic;
00252     }
00253 
00254     topic = new Topic();
00255 
00256     if (topic == nullptr)
00257     {
00258         return nullptr;
00259     }
00260 
00261     string* name = new string(topicName);
00262     topic->_topicName = name;
00263 
00264     if ( id == 0 )
00265     {
00266         topic->_type = MQTTSN_TOPIC_TYPE_NORMAL;
00267         topic->_topicId = getNextTopicId();
00268     }
00269     else
00270     {
00271         topic->_type = MQTTSN_TOPIC_TYPE_PREDEFINED;
00272         topic->_topicId  = id;
00273     }
00274 
00275     _cnt++;
00276 
00277     if ( _first == nullptr)
00278     {
00279         _first = topic;
00280     }
00281     else
00282     {
00283         Topic* tp = _first;
00284         while (tp)
00285         {
00286             if (tp->_next == nullptr)
00287             {
00288                 tp->_next = topic;
00289                 break;
00290             }
00291             else
00292             {
00293                 tp = tp->_next;
00294             }
00295         }
00296     }
00297     return topic;
00298 }
00299 
00300 uint16_t Topics::getNextTopicId()
00301 {
00302     return ++_nextTopicId == 0xffff ? _nextTopicId += 2 : _nextTopicId;
00303 }
00304 
00305 Topic* Topics::match(const MQTTSN_topicid* topicid)
00306 {
00307     if (topicid->type != MQTTSN_TOPIC_TYPE_NORMAL)
00308     {
00309         return 0;
00310     }
00311     string topicName(topicid->data.long_.name, topicid->data.long_.len);
00312 
00313     Topic* topic = _first;
00314     while (topic)
00315     {
00316         if (topic->isMatch(&topicName))
00317         {
00318             return topic;
00319         }
00320         topic = topic->_next;
00321     }
00322     return 0;
00323 }
00324 
00325 
00326 void Topics::eraseNormal(void)
00327 {
00328     Topic* topic = _first;
00329     Topic* next = nullptr;
00330     Topic* prev = nullptr;
00331 
00332     while (topic)
00333     {
00334         if ( topic->_type == MQTTSN_TOPIC_TYPE_NORMAL )
00335         {
00336             next = topic->_next;
00337             if ( _first == topic )
00338             {
00339                 _first = next;
00340             }
00341             if ( prev  )
00342             {
00343                 prev->_next = next;
00344             }
00345             delete topic;
00346             _cnt--;
00347             topic = next;
00348         }
00349         else
00350         {
00351             prev = topic;
00352             topic = topic->_next;
00353         }
00354     }
00355 }
00356 
00357 void Topics::print(void)
00358 {
00359     Topic* topic = _first;
00360     if (topic == nullptr )
00361     {
00362         WRITELOG("No Topic.\n");
00363     }
00364     else
00365     {
00366         while (topic)
00367         {
00368             topic->print();
00369             topic = topic->_next;
00370         }
00371     }
00372 }
00373 
00374 uint8_t Topics::getCount(void)
00375 {
00376     return _cnt;
00377 }
00378 
00379 /*=====================================
00380  Class TopicIdMap
00381  =====================================*/
00382 TopicIdMapElement::TopicIdMapElement(uint16_t msgId, uint16_t topicId, MQTTSN_topicTypes type)
00383 {
00384     _msgId = msgId;
00385     _topicId = topicId;
00386     _type = type;
00387     _next = nullptr;
00388     _prev = nullptr;
00389 }
00390 
00391 TopicIdMapElement::~TopicIdMapElement()
00392 {
00393 
00394 }
00395 
00396 MQTTSN_topicTypes TopicIdMapElement::getTopicType(void)
00397 {
00398     return _type;
00399 }
00400 
00401 uint16_t TopicIdMapElement::getTopicId(void)
00402 {
00403     return  _topicId;
00404 }
00405 
00406 TopicIdMap::TopicIdMap()
00407 {
00408     _maxInflight = MAX_INFLIGHTMESSAGES;
00409     _msgIds = 0;
00410     _first = nullptr;
00411     _end = nullptr;
00412     _cnt = 0;
00413 }
00414 
00415 TopicIdMap::~TopicIdMap()
00416 {
00417     TopicIdMapElement* p = _first;
00418     while ( p )
00419     {
00420         TopicIdMapElement* q = p->_next;
00421         delete p;
00422         p = q;
00423     }
00424 }
00425 
00426 TopicIdMapElement* TopicIdMap::getElement(uint16_t msgId)
00427 {
00428     TopicIdMapElement* p = _first;
00429     while ( p )
00430     {
00431         if ( p->_msgId == msgId )
00432         {
00433             return p;
00434         }
00435         p = p->_next;
00436     }
00437     return 0;
00438 }
00439 
00440 TopicIdMapElement* TopicIdMap::add(uint16_t msgId, uint16_t topicId, MQTTSN_topicTypes type)
00441 {
00442     if ( _cnt > _maxInflight * 2 || ( topicId == 0 && type != MQTTSN_TOPIC_TYPE_SHORT ) )
00443     {
00444         return 0;
00445     }
00446     if ( getElement(msgId) )
00447     {
00448         erase(msgId);
00449     }
00450 
00451     TopicIdMapElement* elm = new TopicIdMapElement(msgId, topicId, type);
00452     if ( elm == 0 )
00453     {
00454         return 0;
00455     }
00456     if ( _first == nullptr )
00457     {
00458         _first = elm;
00459         _end = elm;
00460     }
00461     else
00462     {
00463         elm->_prev = _end;
00464         _end->_next = elm;
00465         _end = elm;
00466     }
00467     _cnt++;
00468     return elm;
00469 }
00470 
00471 void TopicIdMap::erase(uint16_t msgId)
00472 {
00473     TopicIdMapElement* p = _first;
00474     while ( p )
00475     {
00476         if ( p->_msgId == msgId )
00477         {
00478             if ( p->_prev == nullptr )
00479             {
00480                 _first = p->_next;
00481             }
00482             else
00483             {
00484                 p->_prev->_next = p->_next;
00485             }
00486 
00487             if ( p->_next == nullptr )
00488             {
00489                 _end = p->_prev;
00490             }
00491             else
00492             {
00493                 p->_next->_prev = p->_prev;
00494             }
00495             delete p;
00496             break;
00497 
00498         }
00499         p = p->_next;
00500     }
00501     _cnt--;
00502 }
00503 
00504 void TopicIdMap::clear(void)
00505 {
00506     TopicIdMapElement* p = _first;
00507     while ( p )
00508     {
00509         TopicIdMapElement* q = p->_next;
00510         delete p;
00511         p = q;
00512     }
00513     _first = nullptr;
00514     _end = nullptr;
00515     _cnt = 0;
00516 }
00517 
00518 
00519