@@ -54,14 +54,19 @@ static struct sol sol;
5454 * Statistics topics, published every N seconds defined by configuration
5555 * interval
5656 */
57- static const char * sys_topics [7 ] = {
58- "$SOL/broker/uptime" ,
59- "$SOL/broker/clients/connected" ,
60- "$SOL/broker/clients/disconnected" ,
61- "$SOL/broker/bytes/sent" ,
62- "$SOL/broker/bytes/received" ,
63- "$SOL/broker/messages/sent" ,
64- "$SOL/broker/messages/received"
57+ static const char * sys_topics [12 ] = {
58+ "$SOL/" ,
59+ "$SOL/broker/" ,
60+ "$SOL/broker/clients/" ,
61+ "$SOL/broker/bytes/" ,
62+ "$SOL/broker/messages/" ,
63+ "$SOL/broker/uptime/" ,
64+ "$SOL/broker/clients/connected/" ,
65+ "$SOL/broker/clients/disconnected/" ,
66+ "$SOL/broker/bytes/sent/" ,
67+ "$SOL/broker/bytes/received/" ,
68+ "$SOL/broker/messages/sent/" ,
69+ "$SOL/broker/messages/received/"
6570};
6671
6772
@@ -280,9 +285,28 @@ static int disconnect_handler(struct closure *cb, union mqtt_packet *pkt) {
280285}
281286
282287
288+ static void recursive_subscription (struct trie_node * node , void * arg ) {
289+
290+ if (!node || !node -> data )
291+ return ;
292+
293+ struct list_node * child = node -> children -> head ;
294+ for (; child ; child = child -> next )
295+ recursive_subscription (child -> data , arg );
296+
297+ struct topic * t = node -> data ;
298+
299+ struct subscriber * s = arg ;
300+
301+ t -> subscribers = list_push (t -> subscribers , s );
302+ }
303+
304+
283305static int subscribe_handler (struct closure * cb , union mqtt_packet * pkt ) {
284306
285307 struct sol_client * c = cb -> obj ;
308+ bool wildcard = false;
309+ bool alloced = false;
286310
287311 /* Subscribe packets contains a list of topics and QoS tuples */
288312 for (unsigned i = 0 ; i < pkt -> subscribe .tuples_len ; i ++ ) {
@@ -293,19 +317,43 @@ static int subscribe_handler(struct closure *cb, union mqtt_packet *pkt) {
293317 * Check if the topic exists already or in case create it and store in
294318 * the global map
295319 */
296- const char * topic_name = (const char * ) pkt -> subscribe .tuples [i ].topic ;
297- struct topic * t = sol_topic_get (& sol , topic_name );
320+ char * topic = (char * ) pkt -> subscribe .tuples [i ].topic ;
321+
322+ sol_debug ("\t%s (QoS %i)" , topic , pkt -> subscribe .tuples [i ].qos );
323+
324+ /* Recursive subscribe to all children topics if the topic ends with "/#" */
325+ if (topic [pkt -> subscribe .tuples [i ].topic_len - 1 ] == '#' &&
326+ topic [pkt -> subscribe .tuples [i ].topic_len - 2 ] == '/' ) {
327+ topic = remove_occur (topic , '#' );
328+ wildcard = true;
329+ } else if (topic [pkt -> subscribe .tuples [i ].topic_len - 1 ] != '/' ) {
330+ topic = sol_malloc (pkt -> subscribe .tuples [i ].topic_len + 2 );
331+ memcpy (topic , pkt -> subscribe .tuples [i ].topic ,
332+ pkt -> subscribe .tuples [i ].topic_len );
333+ topic [pkt -> subscribe .tuples [i ].topic_len ] = '/' ;
334+ topic [pkt -> subscribe .tuples [i ].topic_len + 1 ] = '\0' ;
335+ alloced = true;
336+ }
298337
299- sol_debug ( "\t%s (QoS %i)" , topic_name , pkt -> subscribe . tuples [ i ]. qos );
338+ struct topic * t = sol_topic_get ( & sol , topic );
300339
301340 // TODO check for callback correctly set to obj
302341
303342 if (!t ) {
304- t = topic_create (sol_strdup (topic_name ));
343+ t = topic_create (sol_strdup (topic ));
305344 sol_topic_put (& sol , t );
345+ } else if (wildcard == true) {
346+ struct subscriber * sub = sol_malloc (sizeof (* sub ));
347+ sub -> client = cb -> obj ;
348+ sub -> qos = pkt -> subscribe .tuples [i ].qos ;
349+ trie_prefix_map_tuple (& sol .topics , topic ,
350+ recursive_subscription , sub );
306351 }
307352
308353 topic_add_subscriber (t , cb -> obj , pkt -> subscribe .tuples [i ].qos );
354+
355+ if (alloced )
356+ sol_free (topic );
309357 }
310358
311359 /*
@@ -374,17 +422,31 @@ static int publish_handler(struct closure *cb, union mqtt_packet *pkt) {
374422
375423 info .messages_recv ++ ;
376424
425+ char * topic = (char * ) pkt -> publish .topic ;
426+ bool alloced = false;
427+
428+ if (topic [pkt -> publish .topiclen - 1 ] != '/' ) {
429+ topic = sol_malloc (pkt -> publish .topiclen + 2 );
430+ memcpy (topic , pkt -> publish .topic , pkt -> publish .topiclen );
431+ topic [pkt -> publish .topiclen ] = '/' ;
432+ topic [pkt -> publish .topiclen + 1 ] = '\0' ;
433+ alloced = true;
434+ }
435+
377436 /*
378437 * Retrieve the topic from the global map, if it wasn't created before,
379438 * create a new one with the name selected
380439 */
381- struct topic * t = sol_topic_get (& sol , ( const char * ) pkt -> publish . topic );
440+ struct topic * t = sol_topic_get (& sol , topic );
382441
383442 if (!t ) {
384- t = topic_create (sol_strdup (( const char * ) pkt -> publish . topic ));
443+ t = topic_create (sol_strdup (topic ));
385444 sol_topic_put (& sol , t );
386445 }
387446
447+ if (alloced == true)
448+ sol_free (topic );
449+
388450 // TODO Check for QoS of subscriber, it should override the PUBLISH one
389451
390452 unsigned char * pub = pack_mqtt_packet (pkt , PUBLISH_TYPE );
@@ -822,16 +884,16 @@ static void publish_stats(struct evloop *loop, void *args) {
822884 unsigned char * pmrecv = (unsigned char * ) & mrecv [0 ];
823885 unsigned char * putime = (unsigned char * ) & utime [0 ];
824886
825- publish_message (0 , strlen (sys_topics [0 ]),
826- sys_topics [0 ], strlen (utime ), putime );
827- publish_message (0 , strlen (sys_topics [1 ]),
828- sys_topics [1 ], strlen (cclients ), pcclients );
829- publish_message (0 , strlen (sys_topics [3 ]),
830- sys_topics [3 ], strlen (bsent ), pbsent );
831887 publish_message (0 , strlen (sys_topics [5 ]),
832- sys_topics [5 ], strlen (msent ), pmsent );
888+ sys_topics [5 ], strlen (utime ), putime );
833889 publish_message (0 , strlen (sys_topics [6 ]),
834- sys_topics [6 ], strlen (mrecv ), pmrecv );
890+ sys_topics [6 ], strlen (cclients ), pcclients );
891+ publish_message (0 , strlen (sys_topics [8 ]),
892+ sys_topics [8 ], strlen (bsent ), pbsent );
893+ publish_message (0 , strlen (sys_topics [10 ]),
894+ sys_topics [10 ], strlen (msent ), pmsent );
895+ publish_message (0 , strlen (sys_topics [11 ]),
896+ sys_topics [11 ], strlen (mrecv ), pmrecv );
835897
836898}
837899
@@ -891,7 +953,7 @@ int start_server(const char *addr, const char *port) {
891953 generate_uuid (server_closure .closure_id );
892954
893955 /* Generate stats topics */
894- for (int i = 0 ; i < 7 ; i ++ )
956+ for (int i = 0 ; i < 12 ; i ++ )
895957 sol_topic_put (& sol , topic_create (sol_strdup (sys_topics [i ])));
896958
897959 struct evloop * event_loop = evloop_create (EPOLL_MAX_EVENTS , EPOLL_TIMEOUT );
0 commit comments