Part of TI's mqtt

Dependents:   mqtt_V1 cc3100_Test_mqtt_CM3

Committer:
dflet
Date:
Sat Jun 06 13:29:08 2015 +0000
Revision:
0:547251f42a60
Part of mqtt_V1

Who changed what in which revision?

UserRevisionLine numberNew contents of line
dflet 0:547251f42a60 1 /******************************************************************************
dflet 0:547251f42a60 2 *
dflet 0:547251f42a60 3 * Copyright (C) 2014 Texas Instruments Incorporated
dflet 0:547251f42a60 4 *
dflet 0:547251f42a60 5 * All rights reserved. Property of Texas Instruments Incorporated.
dflet 0:547251f42a60 6 * Restricted rights to use, duplicate or disclose this code are
dflet 0:547251f42a60 7 * granted through contract.
dflet 0:547251f42a60 8 *
dflet 0:547251f42a60 9 * The program may not be used without the written permission of
dflet 0:547251f42a60 10 * Texas Instruments Incorporated or against the terms and conditions
dflet 0:547251f42a60 11 * stipulated in the agreement under which this program has been supplied,
dflet 0:547251f42a60 12 * and under no circumstances can it be used with non-TI connectivity device.
dflet 0:547251f42a60 13 *
dflet 0:547251f42a60 14 ******************************************************************************/
dflet 0:547251f42a60 15
dflet 0:547251f42a60 16 #include "client_mgmt.h"
dflet 0:547251f42a60 17 #include "server_util.h"
dflet 0:547251f42a60 18 #include "server_pkts.h"
dflet 0:547251f42a60 19 #include "server_plug.h"
dflet 0:547251f42a60 20 #include "server_core.h"
dflet 0:547251f42a60 21
dflet 0:547251f42a60 22 namespace mbed_mqtt {
dflet 0:547251f42a60 23
dflet 0:547251f42a60 24 #ifndef CFG_SR_MAX_SUBTOP_LEN
dflet 0:547251f42a60 25 #define MAX_SUBTOP_LEN 32
dflet 0:547251f42a60 26 #else
dflet 0:547251f42a60 27 #define MAX_SUBTOP_LEN CFG_SR_MAX_SUBTOP_LEN
dflet 0:547251f42a60 28 #endif
dflet 0:547251f42a60 29
dflet 0:547251f42a60 30 #ifndef CFG_SR_MAX_TOPIC_NODE
dflet 0:547251f42a60 31 #define MAX_TOP_NODES 32
dflet 0:547251f42a60 32 #else
dflet 0:547251f42a60 33 #define MAX_TOP_NODES CFG_SR_MAX_TOPIC_NODE
dflet 0:547251f42a60 34 #endif
dflet 0:547251f42a60 35
dflet 0:547251f42a60 36 /* A topic name (or string or tree or hierarchy) is handled as a series of nodes.
dflet 0:547251f42a60 37 A 'topic node' refers to a level in the topic tree or hierarchy and it stores
dflet 0:547251f42a60 38 the associated part of the topic string at that level. For example, a topic
dflet 0:547251f42a60 39 having a name "abc/x/1" will have three nodes for each of the subtopics, viz,
dflet 0:547251f42a60 40 "abc/", "x/" and "1". Further, the association between the nodes is indicated
dflet 0:547251f42a60 41 as following.
dflet 0:547251f42a60 42
dflet 0:547251f42a60 43 -- down link hierarchy --> -- down link hierarchy -->
dflet 0:547251f42a60 44 "abc/" "x/" "1"
dflet 0:547251f42a60 45 <-- up link hierarchy -- <-- up link hierarchy --
dflet 0:547251f42a60 46
dflet 0:547251f42a60 47 To extend this example, another topic having a name "abc/y/2" will be managed
dflet 0:547251f42a60 48 as following.
dflet 0:547251f42a60 49
dflet 0:547251f42a60 50 -- down link hierarchy --> -- down link hierarchy -->
dflet 0:547251f42a60 51 "abc/" "x/" "1"
dflet 0:547251f42a60 52 <-- up link hierarchy -- <-- up link hierarchy --
dflet 0:547251f42a60 53 | ^
dflet 0:547251f42a60 54 | |
dflet 0:547251f42a60 55 down link neighbour up link neighbour
dflet 0:547251f42a60 56 | |
dflet 0:547251f42a60 57 V |
dflet 0:547251f42a60 58 -- down link hierarchy -->
dflet 0:547251f42a60 59 "y/" "2"
dflet 0:547251f42a60 60 <-- up link hierarchy --
dflet 0:547251f42a60 61
dflet 0:547251f42a60 62 To reduce wasted in byte alignments, the structure has been hand packed.
dflet 0:547251f42a60 63 */
dflet 0:547251f42a60 64 static struct topic_node {
dflet 0:547251f42a60 65
dflet 0:547251f42a60 66 struct topic_node *dn_nhbr; /* Down Link Neighbour node */
dflet 0:547251f42a60 67 struct topic_node *up_nhbr; /* Up Link Neighbour node */
dflet 0:547251f42a60 68
dflet 0:547251f42a60 69 struct topic_node *dn_hier; /* Down Link Hierarchy node */
dflet 0:547251f42a60 70 struct topic_node *up_hier; /* Up Link Hierarchy node */
dflet 0:547251f42a60 71
dflet 0:547251f42a60 72 uint32_t cl_map[3]; /* Subscribers for each QOS */
dflet 0:547251f42a60 73
dflet 0:547251f42a60 74 uint8_t *my_data; /* Leaf node: retained data */
dflet 0:547251f42a60 75 uint32_t my_dlen;
dflet 0:547251f42a60 76
dflet 0:547251f42a60 77 void *will_cl; /* CL OBJ of WILL Leaf node */
dflet 0:547251f42a60 78
dflet 0:547251f42a60 79 #define TNODE_PROP_RETAIN_DATA 0x04
dflet 0:547251f42a60 80 /* Bits 0,1 for QOS and rest are flags */
dflet 0:547251f42a60 81 uint8_t my_prop;
dflet 0:547251f42a60 82
dflet 0:547251f42a60 83 uint8_t pg_map; /* Map: application plugins */
dflet 0:547251f42a60 84
dflet 0:547251f42a60 85 uint16_t toplen; /* Length of node sub-topic */
dflet 0:547251f42a60 86 char subtop[MAX_SUBTOP_LEN];/* NUL terminated sub-topic */
dflet 0:547251f42a60 87
dflet 0:547251f42a60 88 } nodes[MAX_TOP_NODES];
dflet 0:547251f42a60 89
dflet 0:547251f42a60 90 /*
dflet 0:547251f42a60 91 Housekeeping to manage subtopics (nodes) at run-time.
dflet 0:547251f42a60 92 */
dflet 0:547251f42a60 93 static struct _node_stack {
dflet 0:547251f42a60 94 struct topic_node *node;
dflet 0:547251f42a60 95 uint32_t val1;
dflet 0:547251f42a60 96 uint32_t val2;
dflet 0:547251f42a60 97
dflet 0:547251f42a60 98 } node_stack[MAX_TOP_NODES];
dflet 0:547251f42a60 99
dflet 0:547251f42a60 100 static int32_t stack_idx = 0;
dflet 0:547251f42a60 101
dflet 0:547251f42a60 102 static void stack_add(struct topic_node *node, uint32_t val1, uint32_t val2)
dflet 0:547251f42a60 103 {
dflet 0:547251f42a60 104 node_stack[stack_idx].node = node;
dflet 0:547251f42a60 105 node_stack[stack_idx].val1 = val1;
dflet 0:547251f42a60 106 node_stack[stack_idx].val2 = val2;
dflet 0:547251f42a60 107
dflet 0:547251f42a60 108 stack_idx++;
dflet 0:547251f42a60 109 }
dflet 0:547251f42a60 110
dflet 0:547251f42a60 111 static inline struct _node_stack *stack_pop()
dflet 0:547251f42a60 112 {
dflet 0:547251f42a60 113 if(0 == stack_idx)
dflet 0:547251f42a60 114 return NULL;
dflet 0:547251f42a60 115
dflet 0:547251f42a60 116 return node_stack + (--stack_idx);
dflet 0:547251f42a60 117 }
dflet 0:547251f42a60 118
dflet 0:547251f42a60 119 static inline bool is_node_retain(const struct topic_node *node)
dflet 0:547251f42a60 120 {
dflet 0:547251f42a60 121 return (node->my_prop & TNODE_PROP_RETAIN_DATA)? true : false;
dflet 0:547251f42a60 122 }
dflet 0:547251f42a60 123
dflet 0:547251f42a60 124 static inline void node_retain_set(struct topic_node *node, bool retain)
dflet 0:547251f42a60 125 {
dflet 0:547251f42a60 126 if(retain)
dflet 0:547251f42a60 127 node->my_prop |= TNODE_PROP_RETAIN_DATA;
dflet 0:547251f42a60 128 else
dflet 0:547251f42a60 129 node->my_prop &= ~TNODE_PROP_RETAIN_DATA;
dflet 0:547251f42a60 130 }
dflet 0:547251f42a60 131
dflet 0:547251f42a60 132 static inline void node_qid_set(struct topic_node *node, uint8_t qid)
dflet 0:547251f42a60 133 {
dflet 0:547251f42a60 134 node->my_prop &= ~QID_VMASK;
dflet 0:547251f42a60 135 node->my_prop |= qid;
dflet 0:547251f42a60 136 }
dflet 0:547251f42a60 137
dflet 0:547251f42a60 138 static inline uint8_t node_qid_get(struct topic_node *node)
dflet 0:547251f42a60 139 {
dflet 0:547251f42a60 140 return node->my_prop & QID_VMASK;
dflet 0:547251f42a60 141 }
dflet 0:547251f42a60 142
dflet 0:547251f42a60 143 static inline bool is_node_willed(const struct topic_node *node)
dflet 0:547251f42a60 144 {
dflet 0:547251f42a60 145 return (NULL != node->will_cl)? true : false;
dflet 0:547251f42a60 146 }
dflet 0:547251f42a60 147
dflet 0:547251f42a60 148 static inline bool enrolls_plugin(const struct topic_node *node)
dflet 0:547251f42a60 149 {
dflet 0:547251f42a60 150 return (PG_MAP_ALL_DFLTS != node->pg_map)? true : false;
dflet 0:547251f42a60 151 }
dflet 0:547251f42a60 152
dflet 0:547251f42a60 153 static struct topic_node *free_nodes = NULL;
dflet 0:547251f42a60 154 static struct topic_node *root_node = NULL;
dflet 0:547251f42a60 155
dflet 0:547251f42a60 156 static void node_reset(struct topic_node *node)
dflet 0:547251f42a60 157 {
dflet 0:547251f42a60 158 node->dn_nhbr = NULL;
dflet 0:547251f42a60 159 node->up_nhbr = NULL;
dflet 0:547251f42a60 160 node->dn_hier = NULL;
dflet 0:547251f42a60 161 node->up_hier = NULL;
dflet 0:547251f42a60 162
dflet 0:547251f42a60 163 node->cl_map[0] = node->cl_map[1] = node->cl_map[2] = 0;
dflet 0:547251f42a60 164 node->my_data = NULL;
dflet 0:547251f42a60 165 node->my_dlen = 0;
dflet 0:547251f42a60 166 node->will_cl = NULL;
dflet 0:547251f42a60 167 node->my_prop = QID_VMASK;
dflet 0:547251f42a60 168
dflet 0:547251f42a60 169 node->pg_map = PG_MAP_ALL_DFLTS;
dflet 0:547251f42a60 170 node->toplen = 0;
dflet 0:547251f42a60 171 }
dflet 0:547251f42a60 172
dflet 0:547251f42a60 173 static void topic_node_init(void)
dflet 0:547251f42a60 174 {
dflet 0:547251f42a60 175 int i = 0;
dflet 0:547251f42a60 176
dflet 0:547251f42a60 177 for(i = 0; i < MAX_TOP_NODES; i++) {
dflet 0:547251f42a60 178 struct topic_node *node = nodes + i;
dflet 0:547251f42a60 179
dflet 0:547251f42a60 180 node_reset(node);
dflet 0:547251f42a60 181
dflet 0:547251f42a60 182 node->dn_nhbr = free_nodes;
dflet 0:547251f42a60 183 free_nodes = node;
dflet 0:547251f42a60 184 }
dflet 0:547251f42a60 185
dflet 0:547251f42a60 186 return;
dflet 0:547251f42a60 187 }
dflet 0:547251f42a60 188
dflet 0:547251f42a60 189 static struct topic_node *alloc_topic_node(void)
dflet 0:547251f42a60 190 {
dflet 0:547251f42a60 191 struct topic_node *node = free_nodes;
dflet 0:547251f42a60 192 if(NULL != node) {
dflet 0:547251f42a60 193 free_nodes = node->dn_nhbr;
dflet 0:547251f42a60 194
dflet 0:547251f42a60 195 node_reset(node);
dflet 0:547251f42a60 196 }
dflet 0:547251f42a60 197
dflet 0:547251f42a60 198 return node;
dflet 0:547251f42a60 199 }
dflet 0:547251f42a60 200
dflet 0:547251f42a60 201 static void free_node(struct topic_node *node)
dflet 0:547251f42a60 202 {
dflet 0:547251f42a60 203 node_reset(node);
dflet 0:547251f42a60 204
dflet 0:547251f42a60 205 node->dn_nhbr = free_nodes;
dflet 0:547251f42a60 206 free_nodes = node;
dflet 0:547251f42a60 207 }
dflet 0:547251f42a60 208
dflet 0:547251f42a60 209 static bool is_end_of_subtop(const char *topstr, char const **next_subtop)
dflet 0:547251f42a60 210 {
dflet 0:547251f42a60 211 bool rv = false;
dflet 0:547251f42a60 212
dflet 0:547251f42a60 213 if('\0' == *topstr) {
dflet 0:547251f42a60 214 *next_subtop = NULL; /* Reached end of topstr */
dflet 0:547251f42a60 215 rv = true;
dflet 0:547251f42a60 216 }
dflet 0:547251f42a60 217
dflet 0:547251f42a60 218 if('/' == *topstr) {
dflet 0:547251f42a60 219 /* Next sub-topic is NULL, if a '\0' follows '/' */
dflet 0:547251f42a60 220 *next_subtop = *(topstr + 1)? topstr + 1 : NULL;
dflet 0:547251f42a60 221 rv = true;
dflet 0:547251f42a60 222 }
dflet 0:547251f42a60 223
dflet 0:547251f42a60 224 return rv;
dflet 0:547251f42a60 225 }
dflet 0:547251f42a60 226
dflet 0:547251f42a60 227 static int32_t subtop_read(const char *topstr, char *subtop_buf, uint16_t buf_length,
dflet 0:547251f42a60 228 char const **next_subtop)
dflet 0:547251f42a60 229 {
dflet 0:547251f42a60 230 int32_t idx = 0, len = buf_length;
dflet 0:547251f42a60 231
dflet 0:547251f42a60 232 *next_subtop = topstr;
dflet 0:547251f42a60 233
dflet 0:547251f42a60 234 while(idx < (len - 1)) {
dflet 0:547251f42a60 235 subtop_buf[idx++] = *topstr;
dflet 0:547251f42a60 236
dflet 0:547251f42a60 237 if(is_end_of_subtop(topstr, next_subtop))
dflet 0:547251f42a60 238 break;
dflet 0:547251f42a60 239
dflet 0:547251f42a60 240 topstr++;
dflet 0:547251f42a60 241 }
dflet 0:547251f42a60 242
dflet 0:547251f42a60 243 if(idx == len) {
dflet 0:547251f42a60 244 USR_INFO("S: Fatal, insufficient buffer for sub-str\n\r");
dflet 0:547251f42a60 245 return -1; /* zero or insufficient buffer provided */
dflet 0:547251f42a60 246 }
dflet 0:547251f42a60 247
dflet 0:547251f42a60 248 /* NUL terminated buffer: unless '\0' ended copy, make one */
dflet 0:547251f42a60 249 if('\0' == subtop_buf[idx - 1])
dflet 0:547251f42a60 250 idx--; /* A fix up */
dflet 0:547251f42a60 251 else
dflet 0:547251f42a60 252 subtop_buf[idx] = '\0';
dflet 0:547251f42a60 253
dflet 0:547251f42a60 254 return idx;
dflet 0:547251f42a60 255 }
dflet 0:547251f42a60 256
dflet 0:547251f42a60 257 static
dflet 0:547251f42a60 258 struct topic_node *alloc_node_subtop(const char *topstr, char const **next_subtop)
dflet 0:547251f42a60 259 {
dflet 0:547251f42a60 260 uint16_t len = 0;
dflet 0:547251f42a60 261 struct topic_node *node = alloc_topic_node();
dflet 0:547251f42a60 262 if(NULL == node)
dflet 0:547251f42a60 263 return NULL;
dflet 0:547251f42a60 264
dflet 0:547251f42a60 265 len = subtop_read(topstr, node->subtop, MAX_SUBTOP_LEN, next_subtop);
dflet 0:547251f42a60 266 if(len <= 0) {
dflet 0:547251f42a60 267 free_node(node);
dflet 0:547251f42a60 268 return NULL;
dflet 0:547251f42a60 269 }
dflet 0:547251f42a60 270
dflet 0:547251f42a60 271 node->toplen = len;
dflet 0:547251f42a60 272
dflet 0:547251f42a60 273 return node;
dflet 0:547251f42a60 274 }
dflet 0:547251f42a60 275
dflet 0:547251f42a60 276 /* Returns true if string 'subtop' is part of string 'topstr' otherwise false.
dflet 0:547251f42a60 277 Additionally, on success, pointer to next subtopic in 'topstr' is provided.
dflet 0:547251f42a60 278 */
dflet 0:547251f42a60 279 bool is_first_subtop(const char *subtop, const char *topstr, char const **next_subtop)
dflet 0:547251f42a60 280 {
dflet 0:547251f42a60 281 while(*subtop == *topstr) {
dflet 0:547251f42a60 282 if(is_end_of_subtop(topstr, next_subtop))
dflet 0:547251f42a60 283 return true;
dflet 0:547251f42a60 284
dflet 0:547251f42a60 285 subtop++;
dflet 0:547251f42a60 286 topstr++;
dflet 0:547251f42a60 287 }
dflet 0:547251f42a60 288
dflet 0:547251f42a60 289 return false;
dflet 0:547251f42a60 290 }
dflet 0:547251f42a60 291
dflet 0:547251f42a60 292 /* Find a topic node in neighbour list that matches first subtopic in 'topstr'.
dflet 0:547251f42a60 293 Additionally, on success, pointer to next subtopic in 'topstr' is provided.
dflet 0:547251f42a60 294 */
dflet 0:547251f42a60 295 struct topic_node *subtop_nhbr_node_find(const struct topic_node *root_nh,
dflet 0:547251f42a60 296 const char *topstr,
dflet 0:547251f42a60 297 char const **next_subtop)
dflet 0:547251f42a60 298 {
dflet 0:547251f42a60 299 /* This routine does not make use of 'next_subtop' */
dflet 0:547251f42a60 300 while(root_nh) {
dflet 0:547251f42a60 301 if(true == is_first_subtop(root_nh->subtop, topstr, next_subtop))
dflet 0:547251f42a60 302 break;
dflet 0:547251f42a60 303
dflet 0:547251f42a60 304 root_nh = root_nh->dn_nhbr;
dflet 0:547251f42a60 305 }
dflet 0:547251f42a60 306
dflet 0:547251f42a60 307 return (struct topic_node*) root_nh;/* Bad: const from poiner removed */
dflet 0:547251f42a60 308 }
dflet 0:547251f42a60 309
dflet 0:547251f42a60 310 /* Find a topic node in neighbour list that matches the given 'subtop' string */
dflet 0:547251f42a60 311 struct topic_node *nhbr_node_find(const struct topic_node *root_nh,
dflet 0:547251f42a60 312 const char *subtop)
dflet 0:547251f42a60 313 {
dflet 0:547251f42a60 314 const char *next_subtop = NULL;
dflet 0:547251f42a60 315
dflet 0:547251f42a60 316 return subtop_nhbr_node_find(root_nh, subtop, &next_subtop);
dflet 0:547251f42a60 317 }
dflet 0:547251f42a60 318
dflet 0:547251f42a60 319 /* Find leaf node of branch-combo that matches complete 'topstr'.
dflet 0:547251f42a60 320 Modus Operandi: For each sub topic in 'topstr', go across neighbour list,
dflet 0:547251f42a60 321 then for matching neighbour node, make its child node as root of neighbour
dflet 0:547251f42a60 322 list for another iteration for next sub topic.
dflet 0:547251f42a60 323 */
dflet 0:547251f42a60 324 /* Complex */
dflet 0:547251f42a60 325 static struct topic_node *lowest_node_find(const char *topstr, bool *flag_nh,
dflet 0:547251f42a60 326 char const **next_subtop)
dflet 0:547251f42a60 327 {
dflet 0:547251f42a60 328 struct topic_node *root_nh = root_node, *node = NULL;
dflet 0:547251f42a60 329
dflet 0:547251f42a60 330 *next_subtop = topstr;
dflet 0:547251f42a60 331 *flag_nh = false;
dflet 0:547251f42a60 332
dflet 0:547251f42a60 333 while(root_nh) {
dflet 0:547251f42a60 334 node = subtop_nhbr_node_find(root_nh, topstr, next_subtop);
dflet 0:547251f42a60 335 if(NULL == node) { /* Partial or no match */
dflet 0:547251f42a60 336 *flag_nh = true;
dflet 0:547251f42a60 337 node = root_nh;
dflet 0:547251f42a60 338 break;
dflet 0:547251f42a60 339 }
dflet 0:547251f42a60 340
dflet 0:547251f42a60 341 /* NULL '*next_subtop' indicates a complete match */
dflet 0:547251f42a60 342 if(NULL == (*next_subtop))
dflet 0:547251f42a60 343 break;
dflet 0:547251f42a60 344
dflet 0:547251f42a60 345 root_nh = node->dn_hier;
dflet 0:547251f42a60 346 topstr = *next_subtop;
dflet 0:547251f42a60 347 }
dflet 0:547251f42a60 348
dflet 0:547251f42a60 349 return node;
dflet 0:547251f42a60 350 }
dflet 0:547251f42a60 351
dflet 0:547251f42a60 352 struct topic_node *leaf_node_find(const char *topstr)
dflet 0:547251f42a60 353 {
dflet 0:547251f42a60 354 const char *next_subtop;
dflet 0:547251f42a60 355 bool flag_nh;
dflet 0:547251f42a60 356 struct topic_node *node = lowest_node_find(topstr, &flag_nh,
dflet 0:547251f42a60 357 &next_subtop);
dflet 0:547251f42a60 358
dflet 0:547251f42a60 359 return (NULL == next_subtop)? node : NULL;
dflet 0:547251f42a60 360 }
dflet 0:547251f42a60 361
dflet 0:547251f42a60 362 static void try_node_delete(struct topic_node *node); /* Forward declaration */
dflet 0:547251f42a60 363
dflet 0:547251f42a60 364 /* Create 'child only' hierarchy of nodes to hold all sub topics in 'topstr'.
dflet 0:547251f42a60 365 The routine returns a start node of hierarchy and also provides leaf node.
dflet 0:547251f42a60 366 */
dflet 0:547251f42a60 367 static
dflet 0:547251f42a60 368 struct topic_node *hier_nodes_create(const char *topstr, struct topic_node **leaf)
dflet 0:547251f42a60 369 {
dflet 0:547251f42a60 370 struct topic_node *base = NULL, *node = NULL, *prev = NULL;
dflet 0:547251f42a60 371 const char *next_subtop = NULL;
dflet 0:547251f42a60 372
dflet 0:547251f42a60 373 do {
dflet 0:547251f42a60 374 node = alloc_node_subtop(topstr, &next_subtop);
dflet 0:547251f42a60 375
dflet 0:547251f42a60 376 if(NULL == node) {
dflet 0:547251f42a60 377 /* Allocation of a node failed, free up
dflet 0:547251f42a60 378 the previous allocations, if any, in
dflet 0:547251f42a60 379 the hierarchy that was being created */
dflet 0:547251f42a60 380 if(prev)
dflet 0:547251f42a60 381 try_node_delete(prev);
dflet 0:547251f42a60 382
dflet 0:547251f42a60 383 base = NULL;
dflet 0:547251f42a60 384 break;
dflet 0:547251f42a60 385 }
dflet 0:547251f42a60 386
dflet 0:547251f42a60 387 if(NULL == prev) {
dflet 0:547251f42a60 388 // prev = node;
dflet 0:547251f42a60 389 base = node; /* First node of hierarchy */
dflet 0:547251f42a60 390 } else {
dflet 0:547251f42a60 391 prev->dn_hier = node;
dflet 0:547251f42a60 392 node->up_hier = prev;
dflet 0:547251f42a60 393 // prev = node;
dflet 0:547251f42a60 394 }
dflet 0:547251f42a60 395
dflet 0:547251f42a60 396 prev = node;
dflet 0:547251f42a60 397 topstr = next_subtop;
dflet 0:547251f42a60 398
dflet 0:547251f42a60 399 } while(next_subtop);
dflet 0:547251f42a60 400
dflet 0:547251f42a60 401 *leaf = node;
dflet 0:547251f42a60 402
dflet 0:547251f42a60 403 DBG_INFO("S: Hierarchy of nodes created: Base: %s & Leaf: %s\n\r",
dflet 0:547251f42a60 404 base? base->subtop : " ", (*leaf)? (*leaf)->subtop : " ");
dflet 0:547251f42a60 405
dflet 0:547251f42a60 406 return base;
dflet 0:547251f42a60 407 }
dflet 0:547251f42a60 408
dflet 0:547251f42a60 409 static void install_nhbr_node(struct topic_node *base, struct topic_node *node)
dflet 0:547251f42a60 410 {
dflet 0:547251f42a60 411 while(base->dn_nhbr) {
dflet 0:547251f42a60 412 base = base->dn_nhbr;
dflet 0:547251f42a60 413 }
dflet 0:547251f42a60 414
dflet 0:547251f42a60 415 base->dn_nhbr = node;
dflet 0:547251f42a60 416 node->up_nhbr = base;
dflet 0:547251f42a60 417
dflet 0:547251f42a60 418 DBG_INFO("S: %s added as a neighbour to %s\n\r",
dflet 0:547251f42a60 419 node->subtop, base->subtop);
dflet 0:547251f42a60 420 }
dflet 0:547251f42a60 421
dflet 0:547251f42a60 422 static void set_up_hier_nodes(struct topic_node *up_hier,
dflet 0:547251f42a60 423 struct topic_node *dn_hier)
dflet 0:547251f42a60 424 {
dflet 0:547251f42a60 425 up_hier->dn_hier = dn_hier;
dflet 0:547251f42a60 426 dn_hier->up_hier = up_hier;
dflet 0:547251f42a60 427
dflet 0:547251f42a60 428 DBG_INFO("%s added as DN HIER to %s \n\r",
dflet 0:547251f42a60 429 dn_hier->subtop, up_hier->subtop);
dflet 0:547251f42a60 430 }
dflet 0:547251f42a60 431
dflet 0:547251f42a60 432 static inline void install_topic_root_node(struct topic_node *node)
dflet 0:547251f42a60 433 {
dflet 0:547251f42a60 434 root_node = node;
dflet 0:547251f42a60 435 }
dflet 0:547251f42a60 436
dflet 0:547251f42a60 437 /* Create or update tree to create branch-combo to refer to 'topstr'.
dflet 0:547251f42a60 438 Modus operandi:
dflet 0:547251f42a60 439
dflet 0:547251f42a60 440 */
dflet 0:547251f42a60 441 struct topic_node *topic_node_create(const char *topstr)
dflet 0:547251f42a60 442 {
dflet 0:547251f42a60 443 struct topic_node *base, *node, *leaf;
dflet 0:547251f42a60 444 const char *next_subtop = topstr;
dflet 0:547251f42a60 445 bool flag_nh;
dflet 0:547251f42a60 446
dflet 0:547251f42a60 447 base = lowest_node_find(topstr, &flag_nh, &next_subtop);
dflet 0:547251f42a60 448 if(NULL == next_subtop)
dflet 0:547251f42a60 449 return base; /* Found exact match */
dflet 0:547251f42a60 450
dflet 0:547251f42a60 451 /* Control reaches here, if either no or partial branch-combo has been
dflet 0:547251f42a60 452 found for 'topstr'. Now, let's create remaining branches for string
dflet 0:547251f42a60 453 'next_subtop' and assign them to appropriately to topic tree.
dflet 0:547251f42a60 454 */
dflet 0:547251f42a60 455 DBG_INFO("S: Creating Hierarchy for %s\n\r", next_subtop);
dflet 0:547251f42a60 456
dflet 0:547251f42a60 457 node = hier_nodes_create(next_subtop, &leaf);
dflet 0:547251f42a60 458 if(node) {
dflet 0:547251f42a60 459 if(NULL == base)
dflet 0:547251f42a60 460 install_topic_root_node(node);
dflet 0:547251f42a60 461 else if(flag_nh)
dflet 0:547251f42a60 462 install_nhbr_node(base, node);
dflet 0:547251f42a60 463 else
dflet 0:547251f42a60 464 set_up_hier_nodes(base, node);
dflet 0:547251f42a60 465
dflet 0:547251f42a60 466 return leaf;
dflet 0:547251f42a60 467 }
dflet 0:547251f42a60 468
dflet 0:547251f42a60 469 return NULL;
dflet 0:547251f42a60 470 }
dflet 0:547251f42a60 471
dflet 0:547251f42a60 472 static bool can_delete_node(const struct topic_node *node)
dflet 0:547251f42a60 473 {
dflet 0:547251f42a60 474 if(node->up_nhbr && node->up_hier) {
dflet 0:547251f42a60 475 USR_INFO("S: fatal, node w/ up-nhbr & up-hier.\n\r");
dflet 0:547251f42a60 476 return false;
dflet 0:547251f42a60 477 }
dflet 0:547251f42a60 478
dflet 0:547251f42a60 479 if(node->dn_nhbr ||
dflet 0:547251f42a60 480 node->dn_hier)
dflet 0:547251f42a60 481 return false;
dflet 0:547251f42a60 482
dflet 0:547251f42a60 483 return true;
dflet 0:547251f42a60 484 }
dflet 0:547251f42a60 485
dflet 0:547251f42a60 486 static struct topic_node *node_delete(struct topic_node *node)
dflet 0:547251f42a60 487 {
dflet 0:547251f42a60 488 struct topic_node *next = NULL;
dflet 0:547251f42a60 489
dflet 0:547251f42a60 490 if(false == can_delete_node(node))
dflet 0:547251f42a60 491 return NULL;
dflet 0:547251f42a60 492
dflet 0:547251f42a60 493 if(node->up_nhbr) {
dflet 0:547251f42a60 494 node->up_nhbr->dn_nhbr = NULL;
dflet 0:547251f42a60 495 next = node->up_nhbr;
dflet 0:547251f42a60 496 }
dflet 0:547251f42a60 497
dflet 0:547251f42a60 498 if(node->up_hier) {
dflet 0:547251f42a60 499 node->up_hier->dn_hier = NULL;
dflet 0:547251f42a60 500 next = node->up_hier;
dflet 0:547251f42a60 501 }
dflet 0:547251f42a60 502
dflet 0:547251f42a60 503 if((NULL == node->up_nhbr) &&
dflet 0:547251f42a60 504 (NULL == node->up_hier))
dflet 0:547251f42a60 505 root_node = NULL;
dflet 0:547251f42a60 506
dflet 0:547251f42a60 507 DBG_INFO("S: Deleted node %s\n\r", node->subtop);
dflet 0:547251f42a60 508
dflet 0:547251f42a60 509 free_node(node);
dflet 0:547251f42a60 510
dflet 0:547251f42a60 511 return next;
dflet 0:547251f42a60 512 }
dflet 0:547251f42a60 513
dflet 0:547251f42a60 514 struct topbuf_desc {
dflet 0:547251f42a60 515 char *buffer;
dflet 0:547251f42a60 516 uint16_t maxlen;
dflet 0:547251f42a60 517 uint16_t offset;
dflet 0:547251f42a60 518 };
dflet 0:547251f42a60 519
dflet 0:547251f42a60 520 static bool topbuf_add(struct topbuf_desc *buf_desc, const struct topic_node *node)
dflet 0:547251f42a60 521 {
dflet 0:547251f42a60 522 const char *next_subtop;
dflet 0:547251f42a60 523 char *buf = buf_desc->buffer + buf_desc->offset;
dflet 0:547251f42a60 524 uint16_t len = buf_desc->maxlen - buf_desc->offset;
dflet 0:547251f42a60 525
dflet 0:547251f42a60 526 int32_t rv = subtop_read(node->subtop, buf, len, &next_subtop);
dflet 0:547251f42a60 527 if(rv < 0)
dflet 0:547251f42a60 528 return false;
dflet 0:547251f42a60 529
dflet 0:547251f42a60 530 if(NULL != next_subtop) {
dflet 0:547251f42a60 531 USR_INFO("S: topstr_add fatal, bad subtop.\n\r");
dflet 0:547251f42a60 532 return false;
dflet 0:547251f42a60 533 }
dflet 0:547251f42a60 534
dflet 0:547251f42a60 535 buf_desc->offset += rv;
dflet 0:547251f42a60 536
dflet 0:547251f42a60 537 return true;
dflet 0:547251f42a60 538 }
dflet 0:547251f42a60 539
dflet 0:547251f42a60 540 static bool topbuf_cpy(struct topbuf_desc *buf_desc, const char *subtop)
dflet 0:547251f42a60 541 {
dflet 0:547251f42a60 542 const char *next_subtop;
dflet 0:547251f42a60 543 char *buf = buf_desc->buffer + buf_desc->offset;
dflet 0:547251f42a60 544 uint16_t len = buf_desc->maxlen - buf_desc->offset;
dflet 0:547251f42a60 545
dflet 0:547251f42a60 546 int32_t rv = subtop_read(subtop, buf, len, &next_subtop);
dflet 0:547251f42a60 547 if(rv < 0)
dflet 0:547251f42a60 548 return false;
dflet 0:547251f42a60 549
dflet 0:547251f42a60 550 if(NULL != next_subtop) {
dflet 0:547251f42a60 551 USR_INFO("S: topstr_copy fatal, bad subtop.\n\r");
dflet 0:547251f42a60 552 return false;
dflet 0:547251f42a60 553 }
dflet 0:547251f42a60 554
dflet 0:547251f42a60 555 buf_desc->offset += rv;
dflet 0:547251f42a60 556
dflet 0:547251f42a60 557 return true;
dflet 0:547251f42a60 558 }
dflet 0:547251f42a60 559
dflet 0:547251f42a60 560 static bool has_a_wildcard(const struct topic_node *node)
dflet 0:547251f42a60 561 {
dflet 0:547251f42a60 562 const char *str = node->subtop;
dflet 0:547251f42a60 563 while('\0' != *str) {
dflet 0:547251f42a60 564 if(('+' == *str) || ('#' == *str))
dflet 0:547251f42a60 565 return true;
dflet 0:547251f42a60 566
dflet 0:547251f42a60 567 str++;
dflet 0:547251f42a60 568 }
dflet 0:547251f42a60 569
dflet 0:547251f42a60 570 return false;
dflet 0:547251f42a60 571 }
dflet 0:547251f42a60 572
dflet 0:547251f42a60 573 static bool is_node_SUB_subtop(const struct topic_node *node, const char *subtop)
dflet 0:547251f42a60 574 {
dflet 0:547251f42a60 575 if(false == has_a_wildcard(node))
dflet 0:547251f42a60 576 return ((0 == strcmp(node->subtop, subtop)) ||
dflet 0:547251f42a60 577 (node->dn_hier && (0 == strcmp("+/", subtop))) ||
dflet 0:547251f42a60 578 (!node->dn_hier && (0 == strcmp("+", subtop))))?
dflet 0:547251f42a60 579 true : false;
dflet 0:547251f42a60 580
dflet 0:547251f42a60 581 return false;
dflet 0:547251f42a60 582 }
dflet 0:547251f42a60 583
dflet 0:547251f42a60 584 /* Search node tree, created by PUB retention, for the branch combo, whose
dflet 0:547251f42a60 585 absolute sub-topic sequence 'matches', in entirety, the topic, which is
dflet 0:547251f42a60 586 being subscribed. The 'match' criteria is met either through the
dflet 0:547251f42a60 587 wildcard sub-topics or exact compare.
dflet 0:547251f42a60 588
dflet 0:547251f42a60 589 The hierarchical search starts at the specified 'base' node and ends at
dflet 0:547251f42a60 590 the leaf node. If the sequence of 'base-to-leaf' sub-topics 'match' the
dflet 0:547251f42a60 591 'topSUB', then the leaf node is returned, otherwise a NULL is returned.
dflet 0:547251f42a60 592
dflet 0:547251f42a60 593 As part of hierarchical search, neighbouring nodes, if any, are logged
dflet 0:547251f42a60 594 for subsequent iteration of the routine.
dflet 0:547251f42a60 595 */
dflet 0:547251f42a60 596 static struct topic_node *pub_hier_search(const char *topSUB,
dflet 0:547251f42a60 597 const struct topic_node *base,
dflet 0:547251f42a60 598 struct topbuf_desc *mk_pubtop)
dflet 0:547251f42a60 599 {
dflet 0:547251f42a60 600 const struct topic_node *node = base, *prev = NULL;
dflet 0:547251f42a60 601 const char *next_subtop = topSUB;
dflet 0:547251f42a60 602 char subtop[MAX_SUBTOP_LEN];
dflet 0:547251f42a60 603
dflet 0:547251f42a60 604 while(next_subtop && node) {
dflet 0:547251f42a60 605 if(subtop_read(topSUB, subtop, MAX_SUBTOP_LEN,
dflet 0:547251f42a60 606 &next_subtop) <= 0)
dflet 0:547251f42a60 607 break;
dflet 0:547251f42a60 608
dflet 0:547251f42a60 609 if(node->dn_nhbr)
dflet 0:547251f42a60 610 stack_add(node->dn_nhbr, (uint32_t)topSUB, mk_pubtop->offset);
dflet 0:547251f42a60 611
dflet 0:547251f42a60 612 if(false == is_node_SUB_subtop(node, subtop))
dflet 0:547251f42a60 613 break; /* Node doesn't form part of published topic */
dflet 0:547251f42a60 614
dflet 0:547251f42a60 615 if(false == topbuf_add(mk_pubtop, node))
dflet 0:547251f42a60 616 break;
dflet 0:547251f42a60 617
dflet 0:547251f42a60 618 prev = node;
dflet 0:547251f42a60 619 node = node->dn_hier;
dflet 0:547251f42a60 620
dflet 0:547251f42a60 621 topSUB = next_subtop;
dflet 0:547251f42a60 622 }
dflet 0:547251f42a60 623
dflet 0:547251f42a60 624 if(NULL != next_subtop)
dflet 0:547251f42a60 625 node = NULL;
dflet 0:547251f42a60 626 else
dflet 0:547251f42a60 627 node = prev;
dflet 0:547251f42a60 628
dflet 0:547251f42a60 629 return (struct topic_node *)node;
dflet 0:547251f42a60 630 }
dflet 0:547251f42a60 631
dflet 0:547251f42a60 632 static bool is_node_PUB_subtop(const struct topic_node *node,
dflet 0:547251f42a60 633 const char *subtop, bool endtop)
dflet 0:547251f42a60 634 {
dflet 0:547251f42a60 635 /* Assumes that subtop hasn't got any wildcard characater */
dflet 0:547251f42a60 636 return ((0 == strcmp(subtop, node->subtop)) ||
dflet 0:547251f42a60 637 (!endtop && (0 == strcmp("+/", node->subtop))) ||
dflet 0:547251f42a60 638 (endtop && (0 == strcmp("+", node->subtop))))?
dflet 0:547251f42a60 639 true : false;
dflet 0:547251f42a60 640 }
dflet 0:547251f42a60 641
dflet 0:547251f42a60 642 /* Search node tree, created by subscriptions, for the branch combo, whose
dflet 0:547251f42a60 643 sub-topic sequence 'matches', in entirety, the absolute topic, to which
dflet 0:547251f42a60 644 data has been published. The 'match' criteria is met either through the
dflet 0:547251f42a60 645 wildcard sub-topics or exact compare.
dflet 0:547251f42a60 646
dflet 0:547251f42a60 647 The hierarchical search starts at the specified 'base' node and ends at
dflet 0:547251f42a60 648 the leaf node. If the sequence of 'base-to-leaf' sub-topics 'match' the
dflet 0:547251f42a60 649 'topPUB', then the leaf node is returned, otherwise a NULL is returned.
dflet 0:547251f42a60 650
dflet 0:547251f42a60 651 As part of hierarchical search, neighbouring nodes, if any, are logged
dflet 0:547251f42a60 652 for subsequent iteration of the routine.
dflet 0:547251f42a60 653 */
dflet 0:547251f42a60 654 static struct topic_node *SUB_leaf_search(const char *topPUB,
dflet 0:547251f42a60 655 const struct topic_node *base)
dflet 0:547251f42a60 656 {
dflet 0:547251f42a60 657 const struct topic_node *node = base, *prev = NULL;
dflet 0:547251f42a60 658 const char *next_subtop = topPUB;
dflet 0:547251f42a60 659 char subtop[MAX_SUBTOP_LEN];
dflet 0:547251f42a60 660
dflet 0:547251f42a60 661 while(next_subtop && node) {
dflet 0:547251f42a60 662 if(subtop_read(topPUB, subtop, MAX_SUBTOP_LEN,
dflet 0:547251f42a60 663 &next_subtop) <= 0)
dflet 0:547251f42a60 664 break;
dflet 0:547251f42a60 665
dflet 0:547251f42a60 666 if(node->dn_nhbr)
dflet 0:547251f42a60 667 stack_add(node->dn_nhbr, (uint32_t)topPUB, 0);
dflet 0:547251f42a60 668
dflet 0:547251f42a60 669 if(0 == strcmp("#", node->subtop))
dflet 0:547251f42a60 670 goto SUB_leaf_search_exit1;
dflet 0:547251f42a60 671
dflet 0:547251f42a60 672 if(false == is_node_PUB_subtop(node, subtop, !next_subtop))
dflet 0:547251f42a60 673 break; /* Node doesn't form part of published topic */
dflet 0:547251f42a60 674
dflet 0:547251f42a60 675 prev = node;
dflet 0:547251f42a60 676 node = node->dn_hier;
dflet 0:547251f42a60 677
dflet 0:547251f42a60 678 topPUB = next_subtop;
dflet 0:547251f42a60 679 }
dflet 0:547251f42a60 680
dflet 0:547251f42a60 681 if(NULL != next_subtop)
dflet 0:547251f42a60 682 node = NULL;
dflet 0:547251f42a60 683 else
dflet 0:547251f42a60 684 node = prev;
dflet 0:547251f42a60 685
dflet 0:547251f42a60 686 SUB_leaf_search_exit1:
dflet 0:547251f42a60 687 return (struct topic_node*) node; // Bad
dflet 0:547251f42a60 688 }
dflet 0:547251f42a60 689
dflet 0:547251f42a60 690
dflet 0:547251f42a60 691 /*-------------------------------------------------------------------------
dflet 0:547251f42a60 692 * MQTT Routines
dflet 0:547251f42a60 693 *-------------------------------------------------------------------------
dflet 0:547251f42a60 694 */
dflet 0:547251f42a60 695
dflet 0:547251f42a60 696 #define WBUF_LEN MQP_SERVER_RX_LEN /* Assignment to ease implementation */
dflet 0:547251f42a60 697 static char work_buf[WBUF_LEN];
dflet 0:547251f42a60 698
dflet 0:547251f42a60 699 static void try_node_delete(struct topic_node *node)
dflet 0:547251f42a60 700 {
dflet 0:547251f42a60 701 while(node) {
dflet 0:547251f42a60 702
dflet 0:547251f42a60 703 if(is_node_retain(node) ||
dflet 0:547251f42a60 704 is_node_willed(node) ||
dflet 0:547251f42a60 705 enrolls_plugin(node) ||
dflet 0:547251f42a60 706 node->cl_map[0] ||
dflet 0:547251f42a60 707 node->cl_map[1] ||
dflet 0:547251f42a60 708 node->cl_map[2])
dflet 0:547251f42a60 709 break;
dflet 0:547251f42a60 710
dflet 0:547251f42a60 711 node = node_delete(node);
dflet 0:547251f42a60 712 }
dflet 0:547251f42a60 713 }
dflet 0:547251f42a60 714
dflet 0:547251f42a60 715 /* Move this to a common file */
dflet 0:547251f42a60 716 static void pub_msg_send(const struct utf8_string *topic, const uint8_t *data_buf,
dflet 0:547251f42a60 717 uint32_t data_len, uint8_t fh_flags, uint32_t cl_map)
dflet 0:547251f42a60 718 {
dflet 0:547251f42a60 719 enum mqtt_qos qos = ENUM_QOS(fh_flags);
dflet 0:547251f42a60 720 struct mqtt_packet *mqp = NULL;
dflet 0:547251f42a60 721
dflet 0:547251f42a60 722 mqp = mqp_server_alloc(MQTT_PUBLISH, 2 + topic->length + 2 + data_len);
dflet 0:547251f42a60 723 if(NULL == mqp)
dflet 0:547251f42a60 724 return;
dflet 0:547251f42a60 725
dflet 0:547251f42a60 726 if((0 > mqp_pub_append_topic(mqp, topic, qos? mqp_new_id_server(): 0)) ||
dflet 0:547251f42a60 727 (data_len && (0 > mqp_pub_append_data(mqp, data_buf, data_len)))) {
dflet 0:547251f42a60 728 mqp_free(mqp);
dflet 0:547251f42a60 729 return;
dflet 0:547251f42a60 730 }
dflet 0:547251f42a60 731
dflet 0:547251f42a60 732 mqp_prep_fh(mqp, fh_flags);
dflet 0:547251f42a60 733
dflet 0:547251f42a60 734 if(cl_map)
dflet 0:547251f42a60 735 cl_pub_dispatch(cl_map, mqp);
dflet 0:547251f42a60 736
dflet 0:547251f42a60 737 return;
dflet 0:547251f42a60 738 }
dflet 0:547251f42a60 739
dflet 0:547251f42a60 740 static struct topic_node *SUB_node_create(const char *topSUB, uint8_t qid, void *usr_cl)
dflet 0:547251f42a60 741 {
dflet 0:547251f42a60 742 struct topic_node *leaf = topic_node_create(topSUB);
dflet 0:547251f42a60 743 if(leaf) {
dflet 0:547251f42a60 744 uint8_t j = 0;
dflet 0:547251f42a60 745 uint32_t map = cl_bmap_get(usr_cl);
dflet 0:547251f42a60 746
dflet 0:547251f42a60 747 for(j = 0; j < 3; j++)
dflet 0:547251f42a60 748 /* Client: clear QOS of existing sub, if any */
dflet 0:547251f42a60 749 leaf->cl_map[j] &= ~map;
dflet 0:547251f42a60 750
dflet 0:547251f42a60 751 leaf->cl_map[qid] |= map;
dflet 0:547251f42a60 752
dflet 0:547251f42a60 753 cl_sub_count_add(usr_cl);
dflet 0:547251f42a60 754 }
dflet 0:547251f42a60 755
dflet 0:547251f42a60 756 return leaf;
dflet 0:547251f42a60 757 }
dflet 0:547251f42a60 758
dflet 0:547251f42a60 759 static uint8_t proc_pub_leaf(struct topic_node *leaf, const struct utf8_string *topic,
dflet 0:547251f42a60 760 enum mqtt_qos qos, void *usr_cl)
dflet 0:547251f42a60 761 {
dflet 0:547251f42a60 762 uint8_t qid = QOS_VALUE(qos);
dflet 0:547251f42a60 763
dflet 0:547251f42a60 764 if(is_node_retain(leaf)) {
dflet 0:547251f42a60 765 /* If it is an earlier created topic w/ retained
dflet 0:547251f42a60 766 data, then pick lower of the two QOS(s) */
dflet 0:547251f42a60 767 qid = MIN(node_qid_get(leaf), qid);
dflet 0:547251f42a60 768
dflet 0:547251f42a60 769 /* Publish the retained data to this client */
dflet 0:547251f42a60 770 pub_msg_send(topic, leaf->my_data, leaf->my_dlen,
dflet 0:547251f42a60 771 MAKE_FH_FLAGS(false, qid, true),
dflet 0:547251f42a60 772 cl_bmap_get(usr_cl));
dflet 0:547251f42a60 773 }
dflet 0:547251f42a60 774
dflet 0:547251f42a60 775 return qid;
dflet 0:547251f42a60 776 }
dflet 0:547251f42a60 777
dflet 0:547251f42a60 778 /* Multi-level wild-card subscription - search of all of the tree i.e.
dflet 0:547251f42a60 779 "no topic" ('no_top') in particular and publish it to client, if
dflet 0:547251f42a60 780 the hierarchy has no wild-card node. */
dflet 0:547251f42a60 781 static
dflet 0:547251f42a60 782 uint8_t proc_pub_hier_no_top(struct topic_node *base, struct topbuf_desc *mk_pubtop,
dflet 0:547251f42a60 783 enum mqtt_qos qos, void *usr_cl)
dflet 0:547251f42a60 784 {
dflet 0:547251f42a60 785 struct topic_node *node = base, *leaf = NULL;
dflet 0:547251f42a60 786 uint8_t ack = QOS_VALUE(qos);
dflet 0:547251f42a60 787
dflet 0:547251f42a60 788 /* 1. Find the leaf node of a non wildcard branch-combo */
dflet 0:547251f42a60 789 while(node) {
dflet 0:547251f42a60 790 if(node->dn_nhbr)
dflet 0:547251f42a60 791 stack_add(node->dn_nhbr, 0, mk_pubtop->offset);
dflet 0:547251f42a60 792
dflet 0:547251f42a60 793 if(has_a_wildcard(node))
dflet 0:547251f42a60 794 break;
dflet 0:547251f42a60 795
dflet 0:547251f42a60 796 if(false == topbuf_add(mk_pubtop, node))
dflet 0:547251f42a60 797 break;
dflet 0:547251f42a60 798
dflet 0:547251f42a60 799 leaf = node;
dflet 0:547251f42a60 800 node = node->dn_hier;
dflet 0:547251f42a60 801 }
dflet 0:547251f42a60 802
dflet 0:547251f42a60 803 /* A non NULL value of 'node' would indicate a hierarchy with a
dflet 0:547251f42a60 804 wildcard (sub-)topic (the 'node') - not suitable for PUB. */
dflet 0:547251f42a60 805
dflet 0:547251f42a60 806 if(NULL == node) {
dflet 0:547251f42a60 807 /* 2. Send retained data, if any, to SUB Client */
dflet 0:547251f42a60 808 struct utf8_string topic = {mk_pubtop->buffer,
dflet 0:547251f42a60 809 mk_pubtop->offset};
dflet 0:547251f42a60 810
dflet 0:547251f42a60 811 /* In this version, at this juncture, the 'leaf'
dflet 0:547251f42a60 812 will not be NULL. Nevertheless a check (for
dflet 0:547251f42a60 813 the sake of static analytical tools).........*/
dflet 0:547251f42a60 814 if(leaf)
dflet 0:547251f42a60 815 ack = proc_pub_leaf(leaf, &topic, qos, usr_cl);
dflet 0:547251f42a60 816 }
dflet 0:547251f42a60 817
dflet 0:547251f42a60 818 return ack;
dflet 0:547251f42a60 819 }
dflet 0:547251f42a60 820
dflet 0:547251f42a60 821 /* Multi-level wild-card subscription - search of all of the tree i.e.
dflet 0:547251f42a60 822 "no topic" ('no_top') in particular and publish it to client, if
dflet 0:547251f42a60 823 a hierarchy in the tree has no wild-card node. */
dflet 0:547251f42a60 824 static
dflet 0:547251f42a60 825 uint8_t proc_pub_tree_no_top(struct topic_node *base, struct topbuf_desc *mk_pubtop,
dflet 0:547251f42a60 826 enum mqtt_qos qos, void *usr_cl)
dflet 0:547251f42a60 827 {
dflet 0:547251f42a60 828 uint32_t stack_ref = stack_idx;
dflet 0:547251f42a60 829 uint8_t min = QOS_VALUE(qos);
dflet 0:547251f42a60 830
dflet 0:547251f42a60 831 if(base != NULL)
dflet 0:547251f42a60 832 stack_add(base, 0, mk_pubtop->offset);
dflet 0:547251f42a60 833
dflet 0:547251f42a60 834 while(stack_ref < stack_idx) {
dflet 0:547251f42a60 835 struct _node_stack *stack = stack_pop();
dflet 0:547251f42a60 836 uint8_t ack;
dflet 0:547251f42a60 837
dflet 0:547251f42a60 838 mk_pubtop->offset = (uint16_t) stack->val2;
dflet 0:547251f42a60 839
dflet 0:547251f42a60 840 ack = proc_pub_hier_no_top(stack->node, mk_pubtop, qos, usr_cl);
dflet 0:547251f42a60 841 if(ack < min)
dflet 0:547251f42a60 842 min = ack;
dflet 0:547251f42a60 843 }
dflet 0:547251f42a60 844
dflet 0:547251f42a60 845 return min;
dflet 0:547251f42a60 846 }
dflet 0:547251f42a60 847
dflet 0:547251f42a60 848 static uint8_t proc_pub_hier_SUBtop(const char *topSUB, const struct topic_node *base,
dflet 0:547251f42a60 849 struct topbuf_desc *mk_pubtop, enum mqtt_qos qos,
dflet 0:547251f42a60 850 void *usr_cl)
dflet 0:547251f42a60 851 {
dflet 0:547251f42a60 852 struct topic_node *leaf = pub_hier_search(topSUB, base, mk_pubtop);
dflet 0:547251f42a60 853 uint8_t min = QOS_VALUE(qos);
dflet 0:547251f42a60 854
dflet 0:547251f42a60 855 if(leaf) {
dflet 0:547251f42a60 856 struct utf8_string topic = {mk_pubtop->buffer,
dflet 0:547251f42a60 857 mk_pubtop->offset};
dflet 0:547251f42a60 858
dflet 0:547251f42a60 859 min = proc_pub_leaf(leaf, &topic, qos, usr_cl);
dflet 0:547251f42a60 860 }
dflet 0:547251f42a60 861
dflet 0:547251f42a60 862 return min;
dflet 0:547251f42a60 863 }
dflet 0:547251f42a60 864
dflet 0:547251f42a60 865 /* used by sl or no wc */
dflet 0:547251f42a60 866 static uint8_t proc_pub_tree_SUBtop(const char *topSUB, struct topic_node *base,
dflet 0:547251f42a60 867 struct topbuf_desc *mk_pubtop,
dflet 0:547251f42a60 868 enum mqtt_qos qos, void *usr_cl)
dflet 0:547251f42a60 869 {
dflet 0:547251f42a60 870 uint32_t stack_ref = stack_idx;
dflet 0:547251f42a60 871 uint8_t min = QOS_VALUE(qos);
dflet 0:547251f42a60 872
dflet 0:547251f42a60 873 if(NULL != base)
dflet 0:547251f42a60 874 stack_add(base, (uint32_t)topSUB, mk_pubtop->offset);
dflet 0:547251f42a60 875
dflet 0:547251f42a60 876 while(stack_ref < stack_idx) {
dflet 0:547251f42a60 877 struct _node_stack *stack = stack_pop();
dflet 0:547251f42a60 878 uint8_t ack;
dflet 0:547251f42a60 879
dflet 0:547251f42a60 880 mk_pubtop->offset = stack->val2;
dflet 0:547251f42a60 881 ack = proc_pub_hier_SUBtop((char*)stack->val1, stack->node,
dflet 0:547251f42a60 882 mk_pubtop, qos, usr_cl);
dflet 0:547251f42a60 883
dflet 0:547251f42a60 884 if(ack < min)
dflet 0:547251f42a60 885 min = ack;
dflet 0:547251f42a60 886 }
dflet 0:547251f42a60 887
dflet 0:547251f42a60 888 return min;
dflet 0:547251f42a60 889 }
dflet 0:547251f42a60 890
dflet 0:547251f42a60 891 static
dflet 0:547251f42a60 892 uint8_t proc_sub_ml_wc_hier(const char *grandpa_topSUB, char *parent_subtop,
dflet 0:547251f42a60 893 struct topic_node *base, struct topbuf_desc *mk_pubtop,
dflet 0:547251f42a60 894 enum mqtt_qos qos, void *usr_cl)
dflet 0:547251f42a60 895 {
dflet 0:547251f42a60 896 uint8_t min = QOS_VALUE(qos), ack = QFL_VALUE;
dflet 0:547251f42a60 897 char *subtop = NULL;
dflet 0:547251f42a60 898
dflet 0:547251f42a60 899 /* 1. Search hier node for 'grandpa' and if found, get to parent level */
dflet 0:547251f42a60 900 if('\0' != grandpa_topSUB[0]) {
dflet 0:547251f42a60 901 struct topic_node *leaf = pub_hier_search(grandpa_topSUB, base,
dflet 0:547251f42a60 902 mk_pubtop);
dflet 0:547251f42a60 903 if(NULL == leaf)
dflet 0:547251f42a60 904 return min;
dflet 0:547251f42a60 905
dflet 0:547251f42a60 906 base = leaf->dn_hier; /* nhbr root at parent level */
dflet 0:547251f42a60 907 }
dflet 0:547251f42a60 908
dflet 0:547251f42a60 909 /* 2. If present, process parent as a leaf and get its down hierarchy */
dflet 0:547251f42a60 910 subtop = parent_subtop;
dflet 0:547251f42a60 911 if(('\0' != subtop[0]) && ('+' != subtop[0]) && ('/' != subtop[0])) {
dflet 0:547251f42a60 912 uint16_t offset = mk_pubtop->offset; /* Refer to grandpa's pubtop */
dflet 0:547251f42a60 913 uint16_t sublen = 0;
dflet 0:547251f42a60 914
dflet 0:547251f42a60 915 while(subtop[sublen]){sublen++;}
dflet 0:547251f42a60 916
dflet 0:547251f42a60 917 ack = proc_pub_tree_SUBtop(subtop, base, mk_pubtop, qos, usr_cl);
dflet 0:547251f42a60 918 mk_pubtop->offset = offset; /* Restores grandpa's pubtop */
dflet 0:547251f42a60 919
dflet 0:547251f42a60 920 subtop[sublen] = '/'; /* Make parent's hier subtop */
dflet 0:547251f42a60 921
dflet 0:547251f42a60 922 base = nhbr_node_find(base, subtop);
dflet 0:547251f42a60 923 if(base)
dflet 0:547251f42a60 924 base = topbuf_cpy(mk_pubtop, subtop)?
dflet 0:547251f42a60 925 base->dn_hier : NULL;
dflet 0:547251f42a60 926 subtop[sublen] = '\0'; /* Get back, original subtop */
dflet 0:547251f42a60 927 }
dflet 0:547251f42a60 928
dflet 0:547251f42a60 929 min = MIN(min, ack);
dflet 0:547251f42a60 930 /* 3. Process '#' WC by walking thru entire sub-tree of parent 'base' */
dflet 0:547251f42a60 931 if(NULL != base)
dflet 0:547251f42a60 932 ack = proc_pub_tree_no_top(base, mk_pubtop, qos, usr_cl);
dflet 0:547251f42a60 933
dflet 0:547251f42a60 934 return MIN(min, ack);
dflet 0:547251f42a60 935 }
dflet 0:547251f42a60 936
dflet 0:547251f42a60 937 static uint8_t proc_sub_ml_wc_tree(char *grandpa_topSUB, char *parent_subtop,
dflet 0:547251f42a60 938 struct topic_node *base,
dflet 0:547251f42a60 939 enum mqtt_qos qos, void *usr_cl)
dflet 0:547251f42a60 940 {
dflet 0:547251f42a60 941 struct topbuf_desc mk_pubtop = {work_buf, WBUF_LEN, 0 /* offset */};
dflet 0:547251f42a60 942 uint32_t stack_ref = stack_idx;
dflet 0:547251f42a60 943 uint8_t min = QOS_VALUE(qos);
dflet 0:547251f42a60 944
dflet 0:547251f42a60 945 if(NULL != base)
dflet 0:547251f42a60 946 stack_add(base, (uint32_t)grandpa_topSUB, mk_pubtop.offset);
dflet 0:547251f42a60 947
dflet 0:547251f42a60 948 while(stack_ref < stack_idx) {
dflet 0:547251f42a60 949 struct _node_stack *stack = stack_pop();
dflet 0:547251f42a60 950 uint8_t ack;
dflet 0:547251f42a60 951
dflet 0:547251f42a60 952 mk_pubtop.offset = stack->val2;
dflet 0:547251f42a60 953 ack = proc_sub_ml_wc_hier((char*)stack->val1, parent_subtop,
dflet 0:547251f42a60 954 stack->node, &mk_pubtop, qos, usr_cl);
dflet 0:547251f42a60 955 if(ack < min)
dflet 0:547251f42a60 956 min = ack;
dflet 0:547251f42a60 957 }
dflet 0:547251f42a60 958
dflet 0:547251f42a60 959 return min;
dflet 0:547251f42a60 960 }
dflet 0:547251f42a60 961
dflet 0:547251f42a60 962 static uint8_t ml_wc_nodes_create(char *parent_topSUB, uint16_t toplen, uint8_t qid, void *usr_cl)
dflet 0:547251f42a60 963 {
dflet 0:547251f42a60 964 struct topic_node *parent_leaf = NULL;
dflet 0:547251f42a60 965
dflet 0:547251f42a60 966 if('\0' != parent_topSUB[0]) {
dflet 0:547251f42a60 967 parent_leaf = SUB_node_create(parent_topSUB, qid, usr_cl);
dflet 0:547251f42a60 968 if(NULL == parent_leaf)
dflet 0:547251f42a60 969 return QFL_VALUE;
dflet 0:547251f42a60 970 }
dflet 0:547251f42a60 971
dflet 0:547251f42a60 972 /* Get the topic SUB to it's original state */
dflet 0:547251f42a60 973 if(toplen > 1) parent_topSUB[toplen - 2] = '/';
dflet 0:547251f42a60 974 parent_topSUB[toplen - 1] = '#';
dflet 0:547251f42a60 975
dflet 0:547251f42a60 976 if(NULL == SUB_node_create(parent_topSUB, qid, usr_cl)) {
dflet 0:547251f42a60 977 /* Failed to create WC topic, so delete parent as well.
dflet 0:547251f42a60 978 In this revision, 'parent_leaf' will not be a 'NULL'
dflet 0:547251f42a60 979 at this juncture, nevertheless a check (for tools) */
dflet 0:547251f42a60 980 if(parent_leaf)
dflet 0:547251f42a60 981 node_delete(parent_leaf);
dflet 0:547251f42a60 982
dflet 0:547251f42a60 983 return QFL_VALUE;
dflet 0:547251f42a60 984 }
dflet 0:547251f42a60 985
dflet 0:547251f42a60 986 return qid;
dflet 0:547251f42a60 987 }
dflet 0:547251f42a60 988
dflet 0:547251f42a60 989 /* Process Multi-level Wildcard Topic SUBSCRIBE */
dflet 0:547251f42a60 990 static uint8_t proc_sub_ml_wildcard(char *topSUB, uint16_t toplen, enum mqtt_qos qos,
dflet 0:547251f42a60 991 void *usr_cl)
dflet 0:547251f42a60 992 {
dflet 0:547251f42a60 993 uint16_t len = 0, limit = MIN(toplen, MAX_SUBTOP_LEN);
dflet 0:547251f42a60 994 char subtop[MAX_SUBTOP_LEN], *ptr;
dflet 0:547251f42a60 995 uint8_t min = QOS_VALUE(qos);
dflet 0:547251f42a60 996
dflet 0:547251f42a60 997 /* 'topSUB': Need to create grandpa topic and parent-subtopic */
dflet 0:547251f42a60 998 topSUB[toplen - 1] = '\0'; /* Remove '#' */
dflet 0:547251f42a60 999 if(toplen > 1) /* Remove '/' */
dflet 0:547251f42a60 1000 topSUB[toplen - 2] = '\0';
dflet 0:547251f42a60 1001
dflet 0:547251f42a60 1002 do { /* Do processing to get parent sub-topic into buffer */
dflet 0:547251f42a60 1003 if('/' == topSUB[toplen - len - 1])
dflet 0:547251f42a60 1004 break; /* found '/' */
dflet 0:547251f42a60 1005
dflet 0:547251f42a60 1006 len++; /* Copy parent characters */
dflet 0:547251f42a60 1007 subtop[MAX_SUBTOP_LEN - len] = topSUB[toplen - len];
dflet 0:547251f42a60 1008 } while(len < limit);
dflet 0:547251f42a60 1009
dflet 0:547251f42a60 1010 if((toplen > len) && ('/' != topSUB[toplen - len - 1]))
dflet 0:547251f42a60 1011 return QFL_VALUE; /* Bad Length */
dflet 0:547251f42a60 1012
dflet 0:547251f42a60 1013 topSUB[toplen - len] = '\0'; /* End of grand-pa's topic name */
dflet 0:547251f42a60 1014 ptr = subtop + MAX_SUBTOP_LEN - len; /* Parent's leaf subtop */
dflet 0:547251f42a60 1015 min = proc_sub_ml_wc_tree(topSUB, ptr, root_node, qos, usr_cl);
dflet 0:547251f42a60 1016
dflet 0:547251f42a60 1017 /* Make branch-combo to complete processing of parent' topic */
dflet 0:547251f42a60 1018 strcpy(topSUB + toplen - len, ptr); // topSUB[toplen - len] = *ptr;
dflet 0:547251f42a60 1019
dflet 0:547251f42a60 1020 /* Create nodes for multi-level wildcard topic & it's parent */
dflet 0:547251f42a60 1021 min = ml_wc_nodes_create(topSUB, toplen, min, usr_cl);
dflet 0:547251f42a60 1022
dflet 0:547251f42a60 1023 return min;
dflet 0:547251f42a60 1024 }
dflet 0:547251f42a60 1025
dflet 0:547251f42a60 1026 /* Process Single-level Wildcard or No Wild Card Topic SUBSCRIBE */
dflet 0:547251f42a60 1027 static
dflet 0:547251f42a60 1028 uint8_t proc_sub_sl_or_no_wc(const char *topSUB, enum mqtt_qos qos, void *usr_cl)
dflet 0:547251f42a60 1029 {
dflet 0:547251f42a60 1030 struct topbuf_desc mk_pubtop = {work_buf, WBUF_LEN, 0 /* offset */};
dflet 0:547251f42a60 1031 uint8_t min = QOS_VALUE(qos);
dflet 0:547251f42a60 1032
dflet 0:547251f42a60 1033 /* For single level wildcard or absolute topic, find PUB nodes */
dflet 0:547251f42a60 1034 min = proc_pub_tree_SUBtop(topSUB, root_node, &mk_pubtop, qos, usr_cl);
dflet 0:547251f42a60 1035
dflet 0:547251f42a60 1036 if(NULL == SUB_node_create(topSUB, min, usr_cl))
dflet 0:547251f42a60 1037 min = QFL_VALUE;
dflet 0:547251f42a60 1038
dflet 0:547251f42a60 1039 return min;
dflet 0:547251f42a60 1040 }
dflet 0:547251f42a60 1041
dflet 0:547251f42a60 1042 static uint16_t proc_forward_slash(char *buf, uint16_t len)
dflet 0:547251f42a60 1043 {
dflet 0:547251f42a60 1044 uint16_t i, j;
dflet 0:547251f42a60 1045 for(i = 1, j = 1; i < len; i++) {
dflet 0:547251f42a60 1046 char curr = buf[i];
dflet 0:547251f42a60 1047 if(('/' == curr) && (buf[i - 1] == curr))
dflet 0:547251f42a60 1048 continue; /* Drop consecutive '/' */
dflet 0:547251f42a60 1049
dflet 0:547251f42a60 1050 buf[j++] = curr;
dflet 0:547251f42a60 1051 }
dflet 0:547251f42a60 1052
dflet 0:547251f42a60 1053 if((1 != j) && ('/' == buf[j - 1]))
dflet 0:547251f42a60 1054 j--; /* Topic can not end with a '/' */
dflet 0:547251f42a60 1055
dflet 0:547251f42a60 1056 buf[j] = '\0';
dflet 0:547251f42a60 1057
dflet 0:547251f42a60 1058 return j;
dflet 0:547251f42a60 1059 }
dflet 0:547251f42a60 1060
dflet 0:547251f42a60 1061 static inline bool is_valid_char_order(char prev, char curr)
dflet 0:547251f42a60 1062 {
dflet 0:547251f42a60 1063 return ((('/' != prev) && ('+' == curr)) ||
dflet 0:547251f42a60 1064 (('+' == prev) && ('/' != curr)) ||
dflet 0:547251f42a60 1065 (('/' != prev) && ('#' == curr)) ||
dflet 0:547251f42a60 1066 (('#' == prev)))? false : true;
dflet 0:547251f42a60 1067 }
dflet 0:547251f42a60 1068
dflet 0:547251f42a60 1069
dflet 0:547251f42a60 1070 static bool is_valid_SUB_top(const char *buf, uint16_t len)
dflet 0:547251f42a60 1071 {
dflet 0:547251f42a60 1072 char prev, curr;
dflet 0:547251f42a60 1073 uint16_t i = 0;
dflet 0:547251f42a60 1074
dflet 0:547251f42a60 1075 if((0 == len) || ('\0' == *buf))
dflet 0:547251f42a60 1076 return false;
dflet 0:547251f42a60 1077
dflet 0:547251f42a60 1078 curr = buf[0];
dflet 0:547251f42a60 1079 for(i = 1; (i < len) && ('\0' != curr); i++) {
dflet 0:547251f42a60 1080 prev = curr;
dflet 0:547251f42a60 1081 curr = buf[i];
dflet 0:547251f42a60 1082
dflet 0:547251f42a60 1083 if(false == is_valid_char_order(prev, curr))
dflet 0:547251f42a60 1084 break;
dflet 0:547251f42a60 1085 }
dflet 0:547251f42a60 1086
dflet 0:547251f42a60 1087 return (i == len)? true : false;
dflet 0:547251f42a60 1088 }
dflet 0:547251f42a60 1089
dflet 0:547251f42a60 1090 static bool proc_sub_msg_rx(void *usr_cl, const struct utf8_strqos *qos_topics,
dflet 0:547251f42a60 1091 uint32_t n_topics, uint16_t msg_id, uint8_t *ack)
dflet 0:547251f42a60 1092 {
dflet 0:547251f42a60 1093 int32_t i = 0;
dflet 0:547251f42a60 1094 for(i = 0; i < n_topics; i++) {
dflet 0:547251f42a60 1095 const struct utf8_strqos *qos_top = qos_topics + i;
dflet 0:547251f42a60 1096 enum mqtt_qos qos = qos_top->qosreq;
dflet 0:547251f42a60 1097 char *buf = (char*)qos_top->buffer;
dflet 0:547251f42a60 1098 uint16_t len = qos_top->length;
dflet 0:547251f42a60 1099
dflet 0:547251f42a60 1100 /* Remove zero-topics and trailing '/' from SUB top */
dflet 0:547251f42a60 1101 len = proc_forward_slash(buf, len);
dflet 0:547251f42a60 1102 ack[i] = QFL_VALUE;
dflet 0:547251f42a60 1103 if(false == is_valid_SUB_top(buf, len))
dflet 0:547251f42a60 1104 continue;
dflet 0:547251f42a60 1105
dflet 0:547251f42a60 1106 buf[len] = '\0'; /* Dirty trick, cheeky one */
dflet 0:547251f42a60 1107
dflet 0:547251f42a60 1108 ack[i] = ('#' == buf[len - 1])?
dflet 0:547251f42a60 1109 proc_sub_ml_wildcard(buf, len, qos, usr_cl) :
dflet 0:547251f42a60 1110 proc_sub_sl_or_no_wc(buf, qos, usr_cl);
dflet 0:547251f42a60 1111
dflet 0:547251f42a60 1112 DBG_INFO("SUB Topic%-2d %s is ACK'ed w/ 0x%02x\n\r",
dflet 0:547251f42a60 1113 i + 1, buf, ack[i]);
dflet 0:547251f42a60 1114 }
dflet 0:547251f42a60 1115
dflet 0:547251f42a60 1116 return true; /* Send SUB-ACK and do not close network */
dflet 0:547251f42a60 1117 }
dflet 0:547251f42a60 1118
dflet 0:547251f42a60 1119 static
dflet 0:547251f42a60 1120 bool proc_sub_msg_rx_locked(void *usr_cl, const struct utf8_strqos *qos_topics,
dflet 0:547251f42a60 1121 uint32_t n_topics, uint16_t msg_id, uint8_t *ack)
dflet 0:547251f42a60 1122 {
dflet 0:547251f42a60 1123 return proc_sub_msg_rx(usr_cl, qos_topics, n_topics, msg_id, ack);
dflet 0:547251f42a60 1124 }
dflet 0:547251f42a60 1125
dflet 0:547251f42a60 1126 static void leaf_un_sub(struct topic_node *leaf, void *usr_cl)
dflet 0:547251f42a60 1127 {
dflet 0:547251f42a60 1128 uint8_t j = 0;
dflet 0:547251f42a60 1129 uint32_t map = cl_bmap_get(usr_cl);
dflet 0:547251f42a60 1130
dflet 0:547251f42a60 1131 for(j = 0; j < 3; j++) {
dflet 0:547251f42a60 1132 /* Client: clear QOS of existing sub, if any */
dflet 0:547251f42a60 1133 if(0 == (leaf->cl_map[j] & map))
dflet 0:547251f42a60 1134 continue;
dflet 0:547251f42a60 1135
dflet 0:547251f42a60 1136 leaf->cl_map[j] &= ~map;
dflet 0:547251f42a60 1137 cl_sub_count_del(usr_cl);
dflet 0:547251f42a60 1138
dflet 0:547251f42a60 1139 try_node_delete(leaf);
dflet 0:547251f42a60 1140
dflet 0:547251f42a60 1141 break;
dflet 0:547251f42a60 1142 }
dflet 0:547251f42a60 1143 }
dflet 0:547251f42a60 1144
dflet 0:547251f42a60 1145 static bool proc_un_sub_msg(void *usr_cl, const struct utf8_string *topics,
dflet 0:547251f42a60 1146 uint32_t n_topics, uint16_t msg_id)
dflet 0:547251f42a60 1147 {
dflet 0:547251f42a60 1148 uint32_t i = 0;
dflet 0:547251f42a60 1149
dflet 0:547251f42a60 1150 for(i = 0; i < n_topics; i++) {
dflet 0:547251f42a60 1151 const struct utf8_string *topic = topics + i;
dflet 0:547251f42a60 1152 struct topic_node *leaf = NULL;
dflet 0:547251f42a60 1153 uint16_t len = topic->length;
dflet 0:547251f42a60 1154
dflet 0:547251f42a60 1155 /* The maximum length of 'work_buf' is same as that of RX buffer
dflet 0:547251f42a60 1156 in the PKT-LIB. Therefore, the WBUF_LEN is not being checked
dflet 0:547251f42a60 1157 against the length of the topic (a constituent of RX buffer).
dflet 0:547251f42a60 1158 */
dflet 0:547251f42a60 1159 strncpy(work_buf, topic->buffer, topic->length);
dflet 0:547251f42a60 1160 work_buf[len] = '\0';
dflet 0:547251f42a60 1161
dflet 0:547251f42a60 1162 if('#' == work_buf[len - 1]) { /* Multi-level Wildcard */
dflet 0:547251f42a60 1163 work_buf[len - 1] = '\0';
dflet 0:547251f42a60 1164 if(len > 1)
dflet 0:547251f42a60 1165 work_buf[len - 2] = '\0';
dflet 0:547251f42a60 1166
dflet 0:547251f42a60 1167 leaf = leaf_node_find(work_buf);
dflet 0:547251f42a60 1168 if(leaf)
dflet 0:547251f42a60 1169 leaf_un_sub(leaf, usr_cl);
dflet 0:547251f42a60 1170
dflet 0:547251f42a60 1171 if(len > 1)
dflet 0:547251f42a60 1172 work_buf[len - 2] = '/';
dflet 0:547251f42a60 1173 work_buf[len - 1] = '#';
dflet 0:547251f42a60 1174 }
dflet 0:547251f42a60 1175
dflet 0:547251f42a60 1176 leaf = leaf_node_find(work_buf);
dflet 0:547251f42a60 1177 if(leaf)
dflet 0:547251f42a60 1178 leaf_un_sub(leaf, usr_cl);
dflet 0:547251f42a60 1179 }
dflet 0:547251f42a60 1180
dflet 0:547251f42a60 1181 return true; /* Do not close network */
dflet 0:547251f42a60 1182 }
dflet 0:547251f42a60 1183
dflet 0:547251f42a60 1184 static
dflet 0:547251f42a60 1185 bool proc_un_sub_msg_locked(void *usr_cl, const struct utf8_string *topics,
dflet 0:547251f42a60 1186 uint32_t n_topics, uint16_t msg_id)
dflet 0:547251f42a60 1187 {
dflet 0:547251f42a60 1188 return proc_un_sub_msg(usr_cl, topics, n_topics, msg_id);
dflet 0:547251f42a60 1189 }
dflet 0:547251f42a60 1190
dflet 0:547251f42a60 1191 static void
dflet 0:547251f42a60 1192 leaf_msg_send(const struct topic_node *leaf, const struct utf8_string *topic,
dflet 0:547251f42a60 1193 const uint8_t *data_buf, uint32_t data_len, bool dup, enum mqtt_qos qos,
dflet 0:547251f42a60 1194 bool retain)
dflet 0:547251f42a60 1195 {
dflet 0:547251f42a60 1196 uint8_t qid = 0, fh_fgs = 0;
dflet 0:547251f42a60 1197
dflet 0:547251f42a60 1198 for(qid = 0; qid < 3; qid++) {
dflet 0:547251f42a60 1199 uint8_t map = leaf->cl_map[qid];
dflet 0:547251f42a60 1200 fh_fgs = MAKE_FH_FLAGS(dup, MIN(qid, QOS_VALUE(qos)), retain);
dflet 0:547251f42a60 1201
dflet 0:547251f42a60 1202 if(map)
dflet 0:547251f42a60 1203 pub_msg_send(topic, data_buf, data_len, fh_fgs, map);
dflet 0:547251f42a60 1204 }
dflet 0:547251f42a60 1205
dflet 0:547251f42a60 1206 if(enrolls_plugin(leaf))
dflet 0:547251f42a60 1207 plugin_publish(leaf->pg_map, topic, data_buf, data_len,
dflet 0:547251f42a60 1208 dup, qos, retain);
dflet 0:547251f42a60 1209
dflet 0:547251f42a60 1210 return;
dflet 0:547251f42a60 1211 }
dflet 0:547251f42a60 1212
dflet 0:547251f42a60 1213 static void node_data_set(struct topic_node *node, uint8_t *data,
dflet 0:547251f42a60 1214 uint32_t dlen, uint8_t qid, bool retain)
dflet 0:547251f42a60 1215 {
dflet 0:547251f42a60 1216 node->my_data = data;
dflet 0:547251f42a60 1217 node->my_dlen = dlen;
dflet 0:547251f42a60 1218
dflet 0:547251f42a60 1219 node_qid_set(node, qid);
dflet 0:547251f42a60 1220 node_retain_set(node, retain);
dflet 0:547251f42a60 1221
dflet 0:547251f42a60 1222 return;
dflet 0:547251f42a60 1223 }
dflet 0:547251f42a60 1224
dflet 0:547251f42a60 1225 static bool node_data_update(struct topic_node *node, bool drop_qid0,
dflet 0:547251f42a60 1226 const uint8_t *data_buf, uint32_t data_len,
dflet 0:547251f42a60 1227 uint8_t qid, bool retain)
dflet 0:547251f42a60 1228 {
dflet 0:547251f42a60 1229 #define NODE_DATA_RESET_PARAMS NULL, 0, 0, false
dflet 0:547251f42a60 1230
dflet 0:547251f42a60 1231 /* Assumes that caller has provided either reset or valid params */
dflet 0:547251f42a60 1232
dflet 0:547251f42a60 1233 uint8_t *data = NULL;
dflet 0:547251f42a60 1234
dflet 0:547251f42a60 1235 if(node->my_dlen)
dflet 0:547251f42a60 1236 my_free(node->my_data);
dflet 0:547251f42a60 1237
dflet 0:547251f42a60 1238 /* Watch out for assignment in 'if' statement - avoid such smarts */
dflet 0:547251f42a60 1239 if((drop_qid0 && (0 == qid)) || (data_buf && !(data = (uint8_t*)my_malloc(data_len)))) {
dflet 0:547251f42a60 1240 node_data_set(node, NODE_DATA_RESET_PARAMS);
dflet 0:547251f42a60 1241 } else {
dflet 0:547251f42a60 1242
dflet 0:547251f42a60 1243 if(data)
dflet 0:547251f42a60 1244 buf_wr_nbytes(data, data_buf, data_len);
dflet 0:547251f42a60 1245
dflet 0:547251f42a60 1246 node_data_set(node, data, data_len, qid, retain);
dflet 0:547251f42a60 1247 }
dflet 0:547251f42a60 1248
dflet 0:547251f42a60 1249 return ((!!data) ^ (!!data_len))? false : true;
dflet 0:547251f42a60 1250 }
dflet 0:547251f42a60 1251
dflet 0:547251f42a60 1252 static inline bool is_wildcard_char(char c)
dflet 0:547251f42a60 1253 {
dflet 0:547251f42a60 1254 return (('+' == c) || ('#' == c))? true : false;
dflet 0:547251f42a60 1255 }
dflet 0:547251f42a60 1256
dflet 0:547251f42a60 1257 static int32_t pub_topic_read(const struct utf8_string *topic, char *buf, uint32_t len)
dflet 0:547251f42a60 1258 {
dflet 0:547251f42a60 1259 uint32_t i = 0;
dflet 0:547251f42a60 1260 uint32_t toplen = topic->length;
dflet 0:547251f42a60 1261
dflet 0:547251f42a60 1262 if(len < (toplen + 1))
dflet 0:547251f42a60 1263 return -1;
dflet 0:547251f42a60 1264
dflet 0:547251f42a60 1265 for(i = 0; i < toplen; i++) {
dflet 0:547251f42a60 1266 char c = topic->buffer[i];
dflet 0:547251f42a60 1267 if(is_wildcard_char(c))
dflet 0:547251f42a60 1268 return -1; /* Invalid: wildcard in PUB topic */
dflet 0:547251f42a60 1269
dflet 0:547251f42a60 1270 if('\0' == c)
dflet 0:547251f42a60 1271 return -1; /* Invalid: NUL char in PUB topic */
dflet 0:547251f42a60 1272
dflet 0:547251f42a60 1273 buf[i] = c;
dflet 0:547251f42a60 1274 }
dflet 0:547251f42a60 1275
dflet 0:547251f42a60 1276 buf[i] = '\0';
dflet 0:547251f42a60 1277
dflet 0:547251f42a60 1278 return i;
dflet 0:547251f42a60 1279 }
dflet 0:547251f42a60 1280
dflet 0:547251f42a60 1281 static
dflet 0:547251f42a60 1282 void proc_sub_tree_topPUB(const char *topPUB, const struct utf8_string *topic,
dflet 0:547251f42a60 1283 const uint8_t *data_buf, uint32_t data_len, enum mqtt_qos qos,
dflet 0:547251f42a60 1284 bool retain)
dflet 0:547251f42a60 1285 {
dflet 0:547251f42a60 1286 struct topic_node *leaf = NULL;
dflet 0:547251f42a60 1287 uint32_t stack_ref = stack_idx;
dflet 0:547251f42a60 1288
dflet 0:547251f42a60 1289 if(NULL != root_node)
dflet 0:547251f42a60 1290 stack_add(root_node, (uint32_t)topPUB, 0 /* Not used */);
dflet 0:547251f42a60 1291
dflet 0:547251f42a60 1292 while(stack_ref < stack_idx) {
dflet 0:547251f42a60 1293 struct _node_stack *stack = stack_pop();
dflet 0:547251f42a60 1294
dflet 0:547251f42a60 1295 /* Find leaf node of SUB that matches the PUB topic */
dflet 0:547251f42a60 1296 leaf = SUB_leaf_search((char*)stack->val1, stack->node);
dflet 0:547251f42a60 1297 if(leaf)
dflet 0:547251f42a60 1298 leaf_msg_send(leaf, topic, data_buf, data_len,
dflet 0:547251f42a60 1299 false, qos, retain);
dflet 0:547251f42a60 1300 }
dflet 0:547251f42a60 1301 }
dflet 0:547251f42a60 1302
dflet 0:547251f42a60 1303 static bool _proc_pub_msg_rx(void *usr_cl, const struct utf8_string *topic,
dflet 0:547251f42a60 1304 const uint8_t *data_buf, uint32_t data_len, uint8_t msg_id,
dflet 0:547251f42a60 1305 enum mqtt_qos qos, bool retain)
dflet 0:547251f42a60 1306 {
dflet 0:547251f42a60 1307 int32_t err = -1;
dflet 0:547251f42a60 1308
dflet 0:547251f42a60 1309 /* Prior to msg processing, chk for topic or buffer errors */
dflet 0:547251f42a60 1310 if((pub_topic_read(topic, work_buf, WBUF_LEN) <= 0) ||
dflet 0:547251f42a60 1311 (proc_forward_slash(work_buf, topic->length) <= 0))
dflet 0:547251f42a60 1312 goto _proc_pub_msg_rx_exit;
dflet 0:547251f42a60 1313
dflet 0:547251f42a60 1314 /* If a valid MSG ID is specified for a QOS2 pkt, track it */
dflet 0:547251f42a60 1315 err = -2;
dflet 0:547251f42a60 1316 if((msg_id) &&
dflet 0:547251f42a60 1317 (MQTT_QOS2 == qos) &&
dflet 0:547251f42a60 1318 (false == cl_mgmt_qos2_pub_rx_update(usr_cl, msg_id)))
dflet 0:547251f42a60 1319 goto _proc_pub_msg_rx_exit;
dflet 0:547251f42a60 1320
dflet 0:547251f42a60 1321 /* Forward data to all subscribers of PUB topic in server */
dflet 0:547251f42a60 1322 proc_sub_tree_topPUB(work_buf, topic, data_buf,
dflet 0:547251f42a60 1323 data_len, qos, false);
dflet 0:547251f42a60 1324
dflet 0:547251f42a60 1325 err = 0;
dflet 0:547251f42a60 1326 if(retain) {
dflet 0:547251f42a60 1327 struct topic_node *leaf = topic_node_create(work_buf);
dflet 0:547251f42a60 1328 if((NULL == leaf) ||
dflet 0:547251f42a60 1329 (false == node_data_update(leaf, true, data_buf, data_len,
dflet 0:547251f42a60 1330 QOS_VALUE(qos), retain)))
dflet 0:547251f42a60 1331 err = -3; /* Resources no more available */
dflet 0:547251f42a60 1332
dflet 0:547251f42a60 1333 if(leaf)
dflet 0:547251f42a60 1334 try_node_delete(leaf);
dflet 0:547251f42a60 1335 }
dflet 0:547251f42a60 1336
dflet 0:547251f42a60 1337 _proc_pub_msg_rx_exit:
dflet 0:547251f42a60 1338 DBG_INFO("Processing of PUB message from %s (0x%08x) has %s (%d)\n\r",
dflet 0:547251f42a60 1339 usr_cl? "client" : "plugin", usr_cl? cl_bmap_get(usr_cl) : 0,
dflet 0:547251f42a60 1340 err? "failed" : "succeeded", err);
dflet 0:547251f42a60 1341
dflet 0:547251f42a60 1342 return (err < 0)? false : true;
dflet 0:547251f42a60 1343 }
dflet 0:547251f42a60 1344
dflet 0:547251f42a60 1345 static
dflet 0:547251f42a60 1346 bool proc_pub_msg_rx_locked(void *usr_cl, const struct utf8_string *topic,
dflet 0:547251f42a60 1347 const uint8_t *data_buf, uint32_t data_len, uint16_t msg_id,
dflet 0:547251f42a60 1348 bool dup, enum mqtt_qos qos, bool retain)
dflet 0:547251f42a60 1349 {
dflet 0:547251f42a60 1350 return _proc_pub_msg_rx(usr_cl, topic, data_buf, data_len,
dflet 0:547251f42a60 1351 msg_id, qos, retain);
dflet 0:547251f42a60 1352 }
dflet 0:547251f42a60 1353
dflet 0:547251f42a60 1354 static int32_t utf8_str_rd(const struct utf8_string *utf8, char *buf, uint32_t len)
dflet 0:547251f42a60 1355 {
dflet 0:547251f42a60 1356 if((NULL == utf8) || (utf8->length > (len - 1)))
dflet 0:547251f42a60 1357 return -1;
dflet 0:547251f42a60 1358
dflet 0:547251f42a60 1359 buf_wr_nbytes((uint8_t*)buf, (uint8_t*)utf8->buffer, utf8->length);
dflet 0:547251f42a60 1360 buf[utf8->length] = '\0';
dflet 0:547251f42a60 1361
dflet 0:547251f42a60 1362 return utf8->length;
dflet 0:547251f42a60 1363 }
dflet 0:547251f42a60 1364
dflet 0:547251f42a60 1365 #define CONN_FLAGS_WQID_GET(conn_flags) \
dflet 0:547251f42a60 1366 ((conn_flags >> 3) & QID_VMASK) /* WILL QOS VAL */
dflet 0:547251f42a60 1367
dflet 0:547251f42a60 1368 static uint16_t proc_connect_rx(void *ctx_cl, uint8_t conn_flags,
dflet 0:547251f42a60 1369 struct utf8_string * const *utf8_vec, void **usr_cl)
dflet 0:547251f42a60 1370 {
dflet 0:547251f42a60 1371 struct topic_node *leaf = NULL;
dflet 0:547251f42a60 1372 struct utf8_string *utf8 = NULL;
dflet 0:547251f42a60 1373 void *app_cl = NULL;
dflet 0:547251f42a60 1374 uint16_t utf8_len = 0;
dflet 0:547251f42a60 1375 uint16_t rv = plugin_connect(MQC_UTF8_CLIENTID(utf8_vec),
dflet 0:547251f42a60 1376 MQC_UTF8_USERNAME(utf8_vec),
dflet 0:547251f42a60 1377 MQC_UTF8_PASSWORD(utf8_vec),
dflet 0:547251f42a60 1378 &app_cl);
dflet 0:547251f42a60 1379 if(rv)
dflet 0:547251f42a60 1380 goto proc_connect_rx_exit1; /* Admin did not permit connection */
dflet 0:547251f42a60 1381
dflet 0:547251f42a60 1382 rv = CONNACK_RC_SVR_UNAVBL; /* Server (resource) unavailable */
dflet 0:547251f42a60 1383
dflet 0:547251f42a60 1384 utf8 = MQC_UTF8_WILL_TOP(utf8_vec);
dflet 0:547251f42a60 1385 if(utf8 && utf8->length) {
dflet 0:547251f42a60 1386 utf8_str_rd(utf8, work_buf, WBUF_LEN);
dflet 0:547251f42a60 1387
dflet 0:547251f42a60 1388 leaf = topic_node_create(work_buf);
dflet 0:547251f42a60 1389 if(NULL == leaf)
dflet 0:547251f42a60 1390 goto proc_connect_rx_exit2;
dflet 0:547251f42a60 1391
dflet 0:547251f42a60 1392 if(false == node_data_update(leaf, false,
dflet 0:547251f42a60 1393 (uint8_t*)MQC_WILL_MSG_BUF(utf8_vec),
dflet 0:547251f42a60 1394 MQC_WILL_MSG_LEN(utf8_vec),
dflet 0:547251f42a60 1395 CONN_FLAGS_WQID_GET(conn_flags),
dflet 0:547251f42a60 1396 conn_flags & WILL_RETAIN_VAL))
dflet 0:547251f42a60 1397 goto proc_connect_rx_exit3;
dflet 0:547251f42a60 1398 }
dflet 0:547251f42a60 1399
dflet 0:547251f42a60 1400 utf8 = MQC_UTF8_CLIENTID(utf8_vec);
dflet 0:547251f42a60 1401 if(utf8)
dflet 0:547251f42a60 1402 utf8_len = utf8_str_rd(utf8, work_buf, WBUF_LEN);
dflet 0:547251f42a60 1403
dflet 0:547251f42a60 1404 rv = cl_connect_rx(ctx_cl, (conn_flags & CLEAN_START_VAL)? true : false,
dflet 0:547251f42a60 1405 utf8_len? work_buf : NULL, app_cl, leaf, usr_cl);
dflet 0:547251f42a60 1406 if(CONNACK_RC_REQ_ACCEPT == (rv & 0xFF)) {
dflet 0:547251f42a60 1407 if(leaf)
dflet 0:547251f42a60 1408 leaf->will_cl = *usr_cl;
dflet 0:547251f42a60 1409
dflet 0:547251f42a60 1410 return rv; /* Connection successful */
dflet 0:547251f42a60 1411 }
dflet 0:547251f42a60 1412
dflet 0:547251f42a60 1413 if(leaf)
dflet 0:547251f42a60 1414 node_data_update(leaf, true, NODE_DATA_RESET_PARAMS);
dflet 0:547251f42a60 1415
dflet 0:547251f42a60 1416 proc_connect_rx_exit3: try_node_delete(leaf);
dflet 0:547251f42a60 1417 proc_connect_rx_exit2: plugin_disconn(app_cl, true);
dflet 0:547251f42a60 1418 proc_connect_rx_exit1:
dflet 0:547251f42a60 1419 return rv;
dflet 0:547251f42a60 1420 }
dflet 0:547251f42a60 1421
dflet 0:547251f42a60 1422 static
dflet 0:547251f42a60 1423 uint16_t proc_connect_rx_locked(void *ctx_cl, uint8_t conn_flags,
dflet 0:547251f42a60 1424 struct utf8_string * const *utf8_vec, void **usr_cl)
dflet 0:547251f42a60 1425 {
dflet 0:547251f42a60 1426 return proc_connect_rx(ctx_cl, conn_flags, utf8_vec, usr_cl);
dflet 0:547251f42a60 1427 }
dflet 0:547251f42a60 1428
dflet 0:547251f42a60 1429 static void session_hier_delete(struct topic_node *node, void *usr_cl)
dflet 0:547251f42a60 1430 {
dflet 0:547251f42a60 1431 struct topic_node *prev = NULL;
dflet 0:547251f42a60 1432 uint32_t cl_map = cl_bmap_get(usr_cl);
dflet 0:547251f42a60 1433
dflet 0:547251f42a60 1434 while(node) {
dflet 0:547251f42a60 1435 int32_t i = 0;
dflet 0:547251f42a60 1436 for(i = 0; i < 3; i++) {
dflet 0:547251f42a60 1437 if(node->cl_map[i] & cl_map) {
dflet 0:547251f42a60 1438 node->cl_map[i] &= ~cl_map;
dflet 0:547251f42a60 1439 cl_sub_count_del(usr_cl);
dflet 0:547251f42a60 1440 /* Client/Topic/QID 1-to-1 map */
dflet 0:547251f42a60 1441 break;
dflet 0:547251f42a60 1442 }
dflet 0:547251f42a60 1443 }
dflet 0:547251f42a60 1444
dflet 0:547251f42a60 1445 if(node->dn_nhbr)
dflet 0:547251f42a60 1446 stack_add(node->dn_nhbr, 0, 0);
dflet 0:547251f42a60 1447
dflet 0:547251f42a60 1448 prev = node;
dflet 0:547251f42a60 1449 node = node->dn_hier;
dflet 0:547251f42a60 1450 }
dflet 0:547251f42a60 1451
dflet 0:547251f42a60 1452 if(prev)
dflet 0:547251f42a60 1453 try_node_delete(prev);
dflet 0:547251f42a60 1454 }
dflet 0:547251f42a60 1455
dflet 0:547251f42a60 1456 void session_tree_delete(void *usr_cl)
dflet 0:547251f42a60 1457 {
dflet 0:547251f42a60 1458 uint32_t stack_ref = stack_idx;
dflet 0:547251f42a60 1459
dflet 0:547251f42a60 1460 if(NULL != root_node)
dflet 0:547251f42a60 1461 stack_add(root_node, 0, 0);
dflet 0:547251f42a60 1462
dflet 0:547251f42a60 1463 while(stack_ref < stack_idx) {
dflet 0:547251f42a60 1464 struct _node_stack *stack = stack_pop();
dflet 0:547251f42a60 1465 session_hier_delete(stack->node, usr_cl);
dflet 0:547251f42a60 1466 }
dflet 0:547251f42a60 1467 }
dflet 0:547251f42a60 1468
dflet 0:547251f42a60 1469 static void proc_client_will(struct topic_node *leaf)
dflet 0:547251f42a60 1470 {
dflet 0:547251f42a60 1471 uint32_t wbuf_len = WBUF_LEN - 1; /* Make space for '\0' in wbuf */
dflet 0:547251f42a60 1472 uint32_t offset = wbuf_len;
dflet 0:547251f42a60 1473 struct utf8_string topic;
dflet 0:547251f42a60 1474 struct topic_node *node;
dflet 0:547251f42a60 1475
dflet 0:547251f42a60 1476 work_buf[offset] = '\0'; /* Ensures wbuf is NUL terminated */
dflet 0:547251f42a60 1477 node = leaf;
dflet 0:547251f42a60 1478
dflet 0:547251f42a60 1479 /* Prepare a topic string by walking back from leaf to root */
dflet 0:547251f42a60 1480 do {
dflet 0:547251f42a60 1481 if(offset < node->toplen)
dflet 0:547251f42a60 1482 return;
dflet 0:547251f42a60 1483
dflet 0:547251f42a60 1484 offset -= node->toplen;
dflet 0:547251f42a60 1485 strncpy(work_buf + offset, node->subtop, node->toplen);
dflet 0:547251f42a60 1486
dflet 0:547251f42a60 1487 while(node->up_nhbr)
dflet 0:547251f42a60 1488 node = node->up_nhbr;
dflet 0:547251f42a60 1489
dflet 0:547251f42a60 1490 node = node->up_hier;
dflet 0:547251f42a60 1491
dflet 0:547251f42a60 1492 } while(node);
dflet 0:547251f42a60 1493
dflet 0:547251f42a60 1494 topic.buffer = work_buf + offset;
dflet 0:547251f42a60 1495 topic.length = wbuf_len - offset;
dflet 0:547251f42a60 1496
dflet 0:547251f42a60 1497 #define MK_QOS_ENUM(qid) ((enum mqtt_qos)(qid & QID_VMASK))
dflet 0:547251f42a60 1498
dflet 0:547251f42a60 1499 proc_sub_tree_topPUB((char*)topic.buffer,
dflet 0:547251f42a60 1500 &topic, leaf->my_data, leaf->my_dlen,
dflet 0:547251f42a60 1501 MK_QOS_ENUM(node_qid_get(leaf)),
dflet 0:547251f42a60 1502 is_node_retain(leaf));
dflet 0:547251f42a60 1503
dflet 0:547251f42a60 1504 }
dflet 0:547251f42a60 1505
dflet 0:547251f42a60 1506 static void on_cl_net_close(void *usr_cl, bool due2err)
dflet 0:547251f42a60 1507 {
dflet 0:547251f42a60 1508 struct topic_node *leaf = NULL;
dflet 0:547251f42a60 1509 void *app_cl = NULL;
dflet 0:547251f42a60 1510
dflet 0:547251f42a60 1511 /* See if client has a WILL that it intends to broadcast */
dflet 0:547251f42a60 1512 leaf = (struct topic_node*) cl_will_hndl_get(usr_cl);
dflet 0:547251f42a60 1513 if(NULL != leaf) {
dflet 0:547251f42a60 1514 if(usr_cl != leaf->will_cl)
dflet 0:547251f42a60 1515 return; /* Mismatch: should never happen */
dflet 0:547251f42a60 1516
dflet 0:547251f42a60 1517 if(due2err)
dflet 0:547251f42a60 1518 proc_client_will(leaf); /* pls broadcast */
dflet 0:547251f42a60 1519
dflet 0:547251f42a60 1520 /* Network is closing, so cleanup WILL msg store */
dflet 0:547251f42a60 1521 node_data_update(leaf, true, NODE_DATA_RESET_PARAMS);
dflet 0:547251f42a60 1522 leaf->will_cl = NULL;
dflet 0:547251f42a60 1523 try_node_delete(leaf);
dflet 0:547251f42a60 1524 }
dflet 0:547251f42a60 1525
dflet 0:547251f42a60 1526 /* If not needed for future, delete session info */
dflet 0:547251f42a60 1527 if(cl_can_session_delete(usr_cl))
dflet 0:547251f42a60 1528 session_tree_delete(usr_cl);
dflet 0:547251f42a60 1529
dflet 0:547251f42a60 1530 /* Inform app that client has been disconnected */
dflet 0:547251f42a60 1531 app_cl = cl_app_hndl_get(usr_cl);
dflet 0:547251f42a60 1532 plugin_disconn(app_cl, due2err);
dflet 0:547251f42a60 1533
dflet 0:547251f42a60 1534 cl_on_net_close(usr_cl);
dflet 0:547251f42a60 1535 }
dflet 0:547251f42a60 1536
dflet 0:547251f42a60 1537 static
dflet 0:547251f42a60 1538 void on_cl_net_close_locked(void *usr_cl, bool due2err)
dflet 0:547251f42a60 1539 {
dflet 0:547251f42a60 1540 on_cl_net_close(usr_cl, due2err);
dflet 0:547251f42a60 1541 return;
dflet 0:547251f42a60 1542 }
dflet 0:547251f42a60 1543
dflet 0:547251f42a60 1544 static void on_connack_send(void *usr_cl, bool clean_session)
dflet 0:547251f42a60 1545 {
dflet 0:547251f42a60 1546 /* If asserted, then need to start w/ clean state */
dflet 0:547251f42a60 1547 if(clean_session)
dflet 0:547251f42a60 1548 session_tree_delete(usr_cl);
dflet 0:547251f42a60 1549
dflet 0:547251f42a60 1550 cl_on_connack_send(usr_cl, clean_session);
dflet 0:547251f42a60 1551
dflet 0:547251f42a60 1552 return;
dflet 0:547251f42a60 1553 }
dflet 0:547251f42a60 1554
dflet 0:547251f42a60 1555 static
dflet 0:547251f42a60 1556 void on_connack_send_locked(void *usr_cl, bool clean_session)
dflet 0:547251f42a60 1557 {
dflet 0:547251f42a60 1558 on_connack_send(usr_cl, clean_session);
dflet 0:547251f42a60 1559 return;
dflet 0:547251f42a60 1560 }
dflet 0:547251f42a60 1561
dflet 0:547251f42a60 1562 static
dflet 0:547251f42a60 1563 bool proc_notify_ack_locked(void *usr_cl, uint8_t msg_type, uint16_t msg_id)
dflet 0:547251f42a60 1564 {
dflet 0:547251f42a60 1565 return cl_notify_ack(usr_cl, msg_type, msg_id);
dflet 0:547251f42a60 1566 }
dflet 0:547251f42a60 1567
dflet 0:547251f42a60 1568 static int32_t proc_topic_enroll(uint8_t pg_id, const struct utf8_string *topic,
dflet 0:547251f42a60 1569 enum mqtt_qos qos)
dflet 0:547251f42a60 1570 {
dflet 0:547251f42a60 1571 struct topic_node *leaf = NULL;
dflet 0:547251f42a60 1572 uint16_t len = 0;
dflet 0:547251f42a60 1573
dflet 0:547251f42a60 1574 if((NULL == topic) || (NULL == topic->buffer) || (0 == topic->length))
dflet 0:547251f42a60 1575 return -1;
dflet 0:547251f42a60 1576
dflet 0:547251f42a60 1577 if(WBUF_LEN < (topic->length + 1))
dflet 0:547251f42a60 1578 return -2;
dflet 0:547251f42a60 1579
dflet 0:547251f42a60 1580 len = topic->length;
dflet 0:547251f42a60 1581 strncpy(work_buf, topic->buffer, len);
dflet 0:547251f42a60 1582 work_buf[len] = '\0';
dflet 0:547251f42a60 1583
dflet 0:547251f42a60 1584 leaf = topic_node_create(work_buf);
dflet 0:547251f42a60 1585 if(NULL == leaf)
dflet 0:547251f42a60 1586 return -3;
dflet 0:547251f42a60 1587
dflet 0:547251f42a60 1588 PG_MAP_VAL_SETUP(leaf->pg_map, QOS_VALUE(qos), pg_id);
dflet 0:547251f42a60 1589
dflet 0:547251f42a60 1590 return 0;
dflet 0:547251f42a60 1591 }
dflet 0:547251f42a60 1592
dflet 0:547251f42a60 1593 static
dflet 0:547251f42a60 1594 int32_t proc_topic_enroll_locked(uint8_t pg_id, const struct utf8_string *topic,
dflet 0:547251f42a60 1595 enum mqtt_qos qos)
dflet 0:547251f42a60 1596 {
dflet 0:547251f42a60 1597 int32_t rv = 0;
dflet 0:547251f42a60 1598
dflet 0:547251f42a60 1599 MUTEX_LOCKIN();
dflet 0:547251f42a60 1600 rv = proc_topic_enroll(pg_id, topic, qos);
dflet 0:547251f42a60 1601 MUTEX_UNLOCK();
dflet 0:547251f42a60 1602
dflet 0:547251f42a60 1603 return rv;
dflet 0:547251f42a60 1604 }
dflet 0:547251f42a60 1605
dflet 0:547251f42a60 1606 static int32_t proc_topic_cancel(uint8_t pg_id, const struct utf8_string *topic)
dflet 0:547251f42a60 1607 {
dflet 0:547251f42a60 1608 struct topic_node *leaf = NULL;
dflet 0:547251f42a60 1609 uint16_t len = 0;
dflet 0:547251f42a60 1610
dflet 0:547251f42a60 1611 if(NULL == topic)
dflet 0:547251f42a60 1612 return -1;
dflet 0:547251f42a60 1613
dflet 0:547251f42a60 1614 if(WBUF_LEN < (topic->length + 1))
dflet 0:547251f42a60 1615 return -2;
dflet 0:547251f42a60 1616
dflet 0:547251f42a60 1617 len = topic->length;
dflet 0:547251f42a60 1618 strncpy(work_buf, topic->buffer, len);
dflet 0:547251f42a60 1619 work_buf[len] = '\0';
dflet 0:547251f42a60 1620
dflet 0:547251f42a60 1621 leaf = leaf_node_find(work_buf);
dflet 0:547251f42a60 1622 if(NULL == leaf)
dflet 0:547251f42a60 1623 return -2;
dflet 0:547251f42a60 1624
dflet 0:547251f42a60 1625 PG_MAP_VAL_RESET(leaf->pg_map, pg_id);
dflet 0:547251f42a60 1626
dflet 0:547251f42a60 1627 try_node_delete(leaf);
dflet 0:547251f42a60 1628
dflet 0:547251f42a60 1629 return 0;
dflet 0:547251f42a60 1630 }
dflet 0:547251f42a60 1631
dflet 0:547251f42a60 1632 static
dflet 0:547251f42a60 1633 int32_t proc_topic_cancel_locked(uint8_t pg_id, const struct utf8_string *topic)
dflet 0:547251f42a60 1634 {
dflet 0:547251f42a60 1635 int32_t rv = 0;
dflet 0:547251f42a60 1636
dflet 0:547251f42a60 1637 MUTEX_LOCKIN();
dflet 0:547251f42a60 1638 rv = proc_topic_cancel(pg_id, topic);
dflet 0:547251f42a60 1639 MUTEX_UNLOCK();
dflet 0:547251f42a60 1640
dflet 0:547251f42a60 1641 return rv;
dflet 0:547251f42a60 1642 }
dflet 0:547251f42a60 1643
dflet 0:547251f42a60 1644 static
dflet 0:547251f42a60 1645 int32_t proc_app_pub_send_locked(const struct utf8_string *topic, const uint8_t *data_buf,
dflet 0:547251f42a60 1646 uint32_t data_len, enum mqtt_qos qos, bool retain)
dflet 0:547251f42a60 1647 {
dflet 0:547251f42a60 1648 bool rv;
dflet 0:547251f42a60 1649
dflet 0:547251f42a60 1650 MUTEX_LOCKIN();
dflet 0:547251f42a60 1651 /* Received from application, process topic for distribution */
dflet 0:547251f42a60 1652 rv = _proc_pub_msg_rx(NULL, topic, data_buf, data_len,
dflet 0:547251f42a60 1653 0x00, qos, retain);
dflet 0:547251f42a60 1654 MUTEX_UNLOCK();
dflet 0:547251f42a60 1655
dflet 0:547251f42a60 1656 return rv? (int32_t)data_len : -1;
dflet 0:547251f42a60 1657 }
dflet 0:547251f42a60 1658
dflet 0:547251f42a60 1659 int32_t mqtt_server_init(const struct mqtt_server_lib_cfg *lib_cfg,
dflet 0:547251f42a60 1660 const struct mqtt_server_app_cfg *app_cfg)
dflet 0:547251f42a60 1661 {
dflet 0:547251f42a60 1662 /* If mutex is specified, then the following set of callbacks
dflet 0:547251f42a60 1663 are invoked in the locked state - enumerated by 'locked' */
dflet 0:547251f42a60 1664 struct mqtt_server_msg_cbs pkts_cbs = {proc_connect_rx_locked,
dflet 0:547251f42a60 1665 proc_sub_msg_rx_locked,
dflet 0:547251f42a60 1666 proc_un_sub_msg_locked,
dflet 0:547251f42a60 1667 proc_pub_msg_rx_locked,
dflet 0:547251f42a60 1668 proc_notify_ack_locked,
dflet 0:547251f42a60 1669 on_cl_net_close_locked,
dflet 0:547251f42a60 1670 on_connack_send_locked};
dflet 0:547251f42a60 1671
dflet 0:547251f42a60 1672 struct plugin_core_msg_cbs core_cbs = {proc_topic_enroll_locked,
dflet 0:547251f42a60 1673 proc_topic_cancel_locked,
dflet 0:547251f42a60 1674 proc_app_pub_send_locked};
dflet 0:547251f42a60 1675
dflet 0:547251f42a60 1676 util_params_set(lib_cfg->debug_printf,
dflet 0:547251f42a60 1677 lib_cfg->mutex,
dflet 0:547251f42a60 1678 lib_cfg->mutex_lockin,
dflet 0:547251f42a60 1679 lib_cfg->mutex_unlock);
dflet 0:547251f42a60 1680
dflet 0:547251f42a60 1681 USR_INFO("Version: Server LIB %s, Common LIB %s.\n\r",
dflet 0:547251f42a60 1682 MQTT_SERVER_VERSTR, MQTT_COMMON_VERSTR);
dflet 0:547251f42a60 1683
dflet 0:547251f42a60 1684 topic_node_init();
dflet 0:547251f42a60 1685
dflet 0:547251f42a60 1686 cl_mgmt_init();
dflet 0:547251f42a60 1687
dflet 0:547251f42a60 1688 plugin_init(&core_cbs);
dflet 0:547251f42a60 1689
dflet 0:547251f42a60 1690 mqtt_server_lib_init(lib_cfg, &pkts_cbs);
dflet 0:547251f42a60 1691
dflet 0:547251f42a60 1692 return 0;
dflet 0:547251f42a60 1693 }
dflet 0:547251f42a60 1694
dflet 0:547251f42a60 1695 }//namespace mbed_mqtt