Reduce heap allocation churn when tokenising topics.

This commit is contained in:
Roger A. Light
2019-12-11 13:23:59 +00:00
parent 9ee6e2725c
commit 3f0c202aa5
6 changed files with 156 additions and 228 deletions
+2 -2
View File
@@ -665,7 +665,7 @@ void sub__tree_print(struct mosquitto__subhier *root, int level);
int sub__clean_session(struct mosquitto_db *db, struct mosquitto *context);
int sub__retain_queue(struct mosquitto_db *db, struct mosquitto *context, const char *sub, int sub_qos, uint32_t subscription_identifier);
int sub__messages_queue(struct mosquitto_db *db, const char *source_id, const char *topic, int qos, int retain, struct mosquitto_msg_store **stored);
int sub__topic_tokenise(const char *subtopic, struct sub__token **topics);
int sub__topic_tokenise(const char *subtopic, char **local_sub, char ***topics, const char **sharename);
void sub__topic_tokens_free(struct sub__token *tokens);
/* ============================================================
@@ -724,7 +724,7 @@ int property__process_disconnect(struct mosquitto *context, mosquitto_property *
int retain__init(struct mosquitto_db *db);
void retain__clean(struct mosquitto_db *db, struct mosquitto__retainhier **retainhier);
int retain__queue(struct mosquitto_db *db, struct mosquitto *context, const char *sub, int sub_qos, uint32_t subscription_identifier);
int retain__store(struct mosquitto_db *db, const char *topic, struct mosquitto_msg_store *stored, struct sub__token *tokens);
int retain__store(struct mosquitto_db *db, const char *topic, struct mosquitto_msg_store *stored, char **split_topics);
/* ============================================================
* Security related functions
+6 -1
View File
@@ -316,6 +316,8 @@ static int persist__retain_chunk_restore(struct mosquitto_db *db, FILE *db_fptr)
struct mosquitto_msg_store_load *load;
struct P_retain chunk;
int rc;
char **split_topics;
char *local_topic;
memset(&chunk, 0, sizeof(struct P_retain));
@@ -331,7 +333,10 @@ static int persist__retain_chunk_restore(struct mosquitto_db *db, FILE *db_fptr)
HASH_FIND(hh, db->msg_store_load, &chunk.F.store_id, sizeof(dbid_t), load);
if(load){
retain__store(db, load->store->topic, load->store, NULL);
if(sub__topic_tokenise(load->store->topic, &local_topic, &split_topics, NULL)) return 1;
retain__store(db, load->store->topic, load->store, split_topics);
mosquitto__free(local_topic);
mosquitto__free(split_topics);
}else{
/* Can't find the message - probably expired */
}
+30 -36
View File
@@ -70,35 +70,29 @@ int retain__init(struct mosquitto_db *db)
}
int retain__store(struct mosquitto_db *db, const char *topic, struct mosquitto_msg_store *stored, struct sub__token *tokens)
int retain__store(struct mosquitto_db *db, const char *topic, struct mosquitto_msg_store *stored, char **split_topics)
{
struct mosquitto__retainhier *retainhier;
struct mosquitto__retainhier *branch;
struct sub__token *local_tokens = NULL, *token_current;
int i;
int slen;
assert(stored);
if(tokens == NULL){
if(sub__topic_tokenise(topic, &local_tokens)) return 1;
}else{
local_tokens = tokens;
}
token_current = local_tokens;
assert(split_topics);
HASH_FIND(hh, db->retains, local_tokens->topic, local_tokens->topic_len, retainhier);
HASH_FIND(hh, db->retains, split_topics[0], strlen(split_topics[0]), retainhier);
if(retainhier == NULL) return 1;
while(token_current){
HASH_FIND(hh, retainhier->children, token_current->topic, token_current->topic_len, branch);
for(i=0; split_topics[i] != NULL; i++){
slen = strlen(split_topics[i]);
HASH_FIND(hh, retainhier->children, split_topics[i], slen, branch);
if(branch == NULL){
branch = retain__add_hier_entry(retainhier, &retainhier->children, token_current->topic, token_current->topic_len);
branch = retain__add_hier_entry(retainhier, &retainhier->children, split_topics[i], slen);
if(branch == NULL){
if(tokens == NULL){
sub__topic_tokens_free(local_tokens);
}
return MOSQ_ERR_NOMEM;
}
}
retainhier = branch;
token_current = token_current->next;
}
#ifdef WITH_PERSISTENCE
@@ -124,10 +118,6 @@ int retain__store(struct mosquitto_db *db, const char *topic, struct mosquitto_m
retainhier->retained = NULL;
}
if(tokens == NULL){
sub__topic_tokens_free(local_tokens);
}
return MOSQ_ERR_SUCCESS;
}
@@ -198,12 +188,12 @@ static int retain__process(struct mosquitto_db *db, struct mosquitto__retainhier
}
static int retain__search(struct mosquitto_db *db, struct mosquitto__retainhier *retainhier, struct sub__token *tokens, struct mosquitto *context, const char *sub, int sub_qos, uint32_t subscription_identifier, time_t now, int level)
static int retain__search(struct mosquitto_db *db, struct mosquitto__retainhier *retainhier, char **split_topics, struct mosquitto *context, const char *sub, int sub_qos, uint32_t subscription_identifier, time_t now, int level)
{
struct mosquitto__retainhier *branch, *branch_tmp;
int flag = 0;
if(!strcmp(tokens->topic, "#") && !tokens->next){
if(!strcmp(split_topics[0], "#") && split_topics[1] == NULL){
HASH_ITER(hh, retainhier->children, branch, branch_tmp){
/* Set flag to indicate that we should check for retained messages
* on "foo" when we are subscribing to e.g. "foo/#" and then exit
@@ -214,15 +204,15 @@ static int retain__search(struct mosquitto_db *db, struct mosquitto__retainhier
retain__process(db, branch, context, sub_qos, subscription_identifier, now);
}
if(branch->children){
retain__search(db, branch, tokens, context, sub, sub_qos, subscription_identifier, now, level+1);
retain__search(db, branch, split_topics, context, sub, sub_qos, subscription_identifier, now, level+1);
}
}
}else{
if(!strcmp(tokens->topic, "+")){
if(!strcmp(split_topics[0], "+")){
HASH_ITER(hh, retainhier->children, branch, branch_tmp){
if(tokens->next){
if(retain__search(db, branch, tokens->next, context, sub, sub_qos, subscription_identifier, now, level+1) == -1
|| (tokens->next && !strcmp(tokens->next->topic, "#") && level>0)){
if(split_topics[1] != NULL){
if(retain__search(db, branch, &(split_topics[1]), context, sub, sub_qos, subscription_identifier, now, level+1) == -1
|| (split_topics[1] != NULL && !strcmp(split_topics[1], "#") && level>0)){
if(branch->retained){
retain__process(db, branch, context, sub_qos, subscription_identifier, now);
@@ -235,11 +225,11 @@ static int retain__search(struct mosquitto_db *db, struct mosquitto__retainhier
}
}
}else{
HASH_FIND(hh, retainhier->children, tokens->topic, tokens->topic_len, branch);
HASH_FIND(hh, retainhier->children, split_topics[0], strlen(split_topics[0]), branch);
if(branch){
if(tokens->next){
if(retain__search(db, branch, tokens->next, context, sub, sub_qos, subscription_identifier, now, level+1) == -1
|| (tokens->next && !strcmp(tokens->next->topic, "#") && level>0)){
if(split_topics[1] != NULL){
if(retain__search(db, branch, &(split_topics[1]), context, sub, sub_qos, subscription_identifier, now, level+1) == -1
|| (split_topics[1] != NULL && !strcmp(split_topics[1], "#") && level>0)){
if(branch->retained){
retain__process(db, branch, context, sub_qos, subscription_identifier, now);
@@ -260,22 +250,26 @@ static int retain__search(struct mosquitto_db *db, struct mosquitto__retainhier
int retain__queue(struct mosquitto_db *db, struct mosquitto *context, const char *sub, int sub_qos, uint32_t subscription_identifier)
{
struct mosquitto__retainhier *retainhier;
struct sub__token *tokens = NULL;
char *local_sub;
char **split_topics;
time_t now;
int rc;
assert(db);
assert(context);
assert(sub);
if(sub__topic_tokenise(sub, &tokens)) return 1;
rc = sub__topic_tokenise(sub, &local_sub, &split_topics, NULL);
if(rc) return rc;
HASH_FIND(hh, db->retains, tokens->topic, tokens->topic_len, retainhier);
HASH_FIND(hh, db->retains, split_topics[0], strlen(split_topics[0]), retainhier);
if(retainhier){
now = time(NULL);
retain__search(db, retainhier, tokens, context, sub, sub_qos, subscription_identifier, now, 0);
retain__search(db, retainhier, split_topics, context, sub, sub_qos, subscription_identifier, now, 0);
}
sub__topic_tokens_free(tokens);
mosquitto__free(local_sub);
mosquitto__free(split_topics);
return MOSQ_ERR_SUCCESS;
}
+59 -96
View File
@@ -190,14 +190,13 @@ static void sub__remove_shared_leaf(struct mosquitto__subhier *subhier, struct m
DL_DELETE(shared->subs, leaf);
if(shared->subs == NULL){
HASH_DELETE(hh, subhier->shared, shared);
mosquitto__free(shared->name);
mosquitto__free(shared);
}
mosquitto__free(leaf);
}
static int sub__add_shared(struct mosquitto_db *db, struct mosquitto *context, int qos, uint32_t identifier, int options, struct mosquitto__subhier *subhier, char *sharename)
static int sub__add_shared(struct mosquitto_db *db, struct mosquitto *context, int qos, uint32_t identifier, int options, struct mosquitto__subhier *subhier, const char *sharename)
{
struct mosquitto__subleaf *newleaf;
struct mosquitto__subshared *shared = NULL;
@@ -210,15 +209,16 @@ static int sub__add_shared(struct mosquitto_db *db, struct mosquitto *context, i
slen = strlen(sharename);
HASH_FIND(hh, subhier->shared, sharename, slen, shared);
if(shared){
mosquitto__free(sharename);
}else{
if(shared == NULL){
shared = mosquitto__calloc(1, sizeof(struct mosquitto__subshared));
if(!shared){
mosquitto__free(sharename);
return MOSQ_ERR_NOMEM;
}
shared->name = sharename;
shared->name = mosquitto__strdup(sharename);
if(shared->name == NULL){
mosquitto__free(shared);
return MOSQ_ERR_NOMEM;
}
HASH_ADD_KEYPTR(hh, subhier->shared, shared->name, slen, shared);
}
@@ -318,20 +318,21 @@ static int sub__add_normal(struct mosquitto_db *db, struct mosquitto *context, i
}
static int sub__add_context(struct mosquitto_db *db, struct mosquitto *context, int qos, uint32_t identifier, int options, struct mosquitto__subhier *subhier, struct sub__token *tokens, char *sharename)
static int sub__add_context(struct mosquitto_db *db, struct mosquitto *context, int qos, uint32_t identifier, int options, struct mosquitto__subhier *subhier, char *const *const topics, const char *sharename)
{
struct mosquitto__subhier *branch;
int topic_index = 0;
/* Find leaf node */
while(tokens){
HASH_FIND(hh, subhier->children, tokens->topic, tokens->topic_len, branch);
while(topics && topics[topic_index] != NULL){
HASH_FIND(hh, subhier->children, topics[topic_index], strlen(topics[topic_index]), branch);
if(!branch){
/* Not found */
branch = sub__add_hier_entry(subhier, &subhier->children, tokens->topic, tokens->topic_len);
branch = sub__add_hier_entry(subhier, &subhier->children, topics[topic_index], strlen(topics[topic_index]));
if(!branch) return MOSQ_ERR_NOMEM;
}
subhier = branch;
tokens = tokens ->next;
topic_index++;
}
/* Add add our context */
@@ -380,14 +381,13 @@ static int sub__remove_normal(struct mosquitto_db *db, struct mosquitto *context
}
static int sub__remove_shared(struct mosquitto_db *db, struct mosquitto *context, struct mosquitto__subhier *subhier, uint8_t *reason, char *sharename)
static int sub__remove_shared(struct mosquitto_db *db, struct mosquitto *context, struct mosquitto__subhier *subhier, uint8_t *reason, const char *sharename)
{
struct mosquitto__subshared *shared;
struct mosquitto__subleaf *leaf;
int i;
HASH_FIND(hh, subhier->shared, sharename, strlen(sharename), shared);
mosquitto__free(sharename);
if(shared){
leaf = shared->subs;
while(leaf){
@@ -431,11 +431,11 @@ static int sub__remove_shared(struct mosquitto_db *db, struct mosquitto *context
}
static int sub__remove_recurse(struct mosquitto_db *db, struct mosquitto *context, struct mosquitto__subhier *subhier, struct sub__token *tokens, uint8_t *reason, char *sharename)
static int sub__remove_recurse(struct mosquitto_db *db, struct mosquitto *context, struct mosquitto__subhier *subhier, char **topics, uint8_t *reason, const char *sharename)
{
struct mosquitto__subhier *branch;
if(!tokens){
if(topics == NULL || topics[0] == NULL){
if(sharename){
return sub__remove_shared(db, context, subhier, reason, sharename);
}else{
@@ -443,9 +443,9 @@ static int sub__remove_recurse(struct mosquitto_db *db, struct mosquitto *contex
}
}
HASH_FIND(hh, subhier->children, tokens->topic, tokens->topic_len, branch);
HASH_FIND(hh, subhier->children, topics[0], strlen(topics[0]), branch);
if(branch){
sub__remove_recurse(db, context, branch, tokens->next, reason, sharename);
sub__remove_recurse(db, context, branch, &(topics[1]), reason, sharename);
if(!branch->children && !branch->subs && !branch->shared){
HASH_DELETE(hh, subhier->children, branch);
mosquitto__free(branch->topic);
@@ -455,25 +455,26 @@ static int sub__remove_recurse(struct mosquitto_db *db, struct mosquitto *contex
return MOSQ_ERR_SUCCESS;
}
static int sub__search(struct mosquitto_db *db, struct mosquitto__subhier *subhier, struct sub__token *tokens, const char *source_id, const char *topic, int qos, int retain, struct mosquitto_msg_store *stored)
static int sub__search(struct mosquitto_db *db, struct mosquitto__subhier *subhier, char **split_topics, const char *source_id, const char *topic, int qos, int retain, struct mosquitto_msg_store *stored)
{
/* FIXME - need to take into account source_id if the client is a bridge */
struct mosquitto__subhier *branch;
int rc;
bool have_subscribers = false;
if(tokens){
if(split_topics && split_topics[0]){
/* Check for literal match */
HASH_FIND(hh, subhier->children, tokens->topic, tokens->topic_len, branch);
HASH_FIND(hh, subhier->children, split_topics[0], strlen(split_topics[0]), branch);
if(branch){
rc = sub__search(db, branch, tokens->next, source_id, topic, qos, retain, stored);
rc = sub__search(db, branch, &(split_topics[1]), source_id, topic, qos, retain, stored);
if(rc == MOSQ_ERR_SUCCESS){
have_subscribers = true;
}else if(rc != MOSQ_ERR_NO_SUBSCRIBERS){
return rc;
}
if(!tokens->next){
if(split_topics[1] == NULL){ /* End of list */
rc = subs__process(db, branch, source_id, topic, qos, retain, stored);
if(rc == MOSQ_ERR_SUCCESS){
have_subscribers = true;
@@ -487,13 +488,13 @@ static int sub__search(struct mosquitto_db *db, struct mosquitto__subhier *subhi
HASH_FIND(hh, subhier->children, "+", 1, branch);
if(branch){
rc = sub__search(db, branch, tokens->next, source_id, topic, qos, retain, stored);
rc = sub__search(db, branch, &(split_topics[1]), source_id, topic, qos, retain, stored);
if(rc == MOSQ_ERR_SUCCESS){
have_subscribers = true;
}else if(rc != MOSQ_ERR_NO_SUBSCRIBERS){
return rc;
}
if(!tokens->next){
if(split_topics[1] == NULL){ /* End of list */
rc = subs__process(db, branch, source_id, topic, qos, retain, stored);
if(rc == MOSQ_ERR_SUCCESS){
have_subscribers = true;
@@ -540,14 +541,12 @@ struct mosquitto__subhier *sub__add_hier_entry(struct mosquitto__subhier *parent
}
child->parent = parent;
child->topic_len = len;
child->topic = mosquitto__malloc(len+1);
child->topic = mosquitto__strdup(topic);
if(!child->topic){
child->topic_len = 0;
mosquitto__free(child);
log__printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory.");
return NULL;
}else{
strncpy(child->topic, topic, child->topic_len+1);
}
HASH_ADD_KEYPTR(hh, *sibling, child->topic, child->topic_len, child);
@@ -560,49 +559,32 @@ int sub__add(struct mosquitto_db *db, struct mosquitto *context, const char *sub
{
int rc = 0;
struct mosquitto__subhier *subhier;
struct sub__token *tokens = NULL, *t;
char *sharename = NULL;
const char *sharename = NULL;
char *local_sub;
char **topics;
assert(root);
assert(*root);
assert(sub);
if(sub__topic_tokenise(sub, &tokens)) return 1;
rc = sub__topic_tokenise(sub, &local_sub, &topics, &sharename);
if(rc) return rc;
if(!strcmp(tokens->topic, "$share")){
if(!tokens->next || !tokens->next->next){
sub__topic_tokens_free(tokens);
return MOSQ_ERR_PROTOCOL;
}
t = tokens->next;
mosquitto__free(tokens->topic);
mosquitto__free(tokens);
tokens = t;
sharename = tokens->topic;
tokens->topic = mosquitto__strdup("");
if(!tokens->topic){
tokens->topic = sharename;
sub__topic_tokens_free(tokens);
return MOSQ_ERR_PROTOCOL;
}
tokens->topic_len = 0;
}
HASH_FIND(hh, *root, tokens->topic, tokens->topic_len, subhier);
HASH_FIND(hh, *root, topics[0], strlen(topics[0]), subhier);
if(!subhier){
subhier = sub__add_hier_entry(NULL, root, tokens->topic, tokens->topic_len);
subhier = sub__add_hier_entry(NULL, root, topics[0], strlen(topics[0]));
if(!subhier){
sub__topic_tokens_free(tokens);
mosquitto__free(local_sub);
mosquitto__free(topics);
log__printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory.");
return MOSQ_ERR_NOMEM;
}
}
rc = sub__add_context(db, context, qos, identifier, options, subhier, tokens, sharename);
rc = sub__add_context(db, context, qos, identifier, options, subhier, topics, sharename);
sub__topic_tokens_free(tokens);
mosquitto__free(local_sub);
mosquitto__free(topics);
return rc;
}
@@ -611,56 +593,39 @@ int sub__remove(struct mosquitto_db *db, struct mosquitto *context, const char *
{
int rc = 0;
struct mosquitto__subhier *subhier;
struct sub__token *tokens = NULL, *t;
char *sharename = NULL;
const char *sharename = NULL;
char *local_sub = NULL;
char **topics = NULL;
assert(root);
assert(sub);
if(sub__topic_tokenise(sub, &tokens)) return 1;
rc = sub__topic_tokenise(sub, &local_sub, &topics, &sharename);
if(rc) return rc;
if(!strcmp(tokens->topic, "$share")){
if(!tokens->next || !tokens->next->next){
sub__topic_tokens_free(tokens);
return MOSQ_ERR_PROTOCOL;
}
t = tokens->next;
mosquitto__free(tokens->topic);
mosquitto__free(tokens);
tokens = t;
sharename = tokens->topic;
tokens->topic = mosquitto__strdup("");
if(!tokens->topic){
tokens->topic = sharename;
sub__topic_tokens_free(tokens);
return MOSQ_ERR_PROTOCOL;
}
tokens->topic_len = 0;
}
HASH_FIND(hh, root, tokens->topic, tokens->topic_len, subhier);
HASH_FIND(hh, root, topics[0], strlen(topics[0]), subhier);
if(subhier){
*reason = MQTT_RC_NO_SUBSCRIPTION_EXISTED;
rc = sub__remove_recurse(db, context, subhier, tokens, reason, sharename);
rc = sub__remove_recurse(db, context, subhier, topics, reason, sharename);
}
sub__topic_tokens_free(tokens);
mosquitto__free(local_sub);
mosquitto__free(topics);
return rc;
}
int sub__messages_queue(struct mosquitto_db *db, const char *source_id, const char *topic, int qos, int retain, struct mosquitto_msg_store **stored)
{
int rc = 0, rc2;
int rc = MOSQ_ERR_SUCCESS, rc2;
struct mosquitto__subhier *subhier;
struct sub__token *tokens = NULL;
char **split_topics = NULL;
char *local_topic = NULL;
assert(db);
assert(topic);
if(sub__topic_tokenise(topic, &tokens)) return 1;
if(sub__topic_tokenise(topic, &local_topic, &split_topics, NULL)) return 1;
/* Protect this message until we have sent it to all
clients - this is required because websockets client calls
@@ -668,20 +633,18 @@ int sub__messages_queue(struct mosquitto_db *db, const char *source_id, const ch
*/
db__msg_store_ref_inc(*stored);
HASH_FIND(hh, db->subs, tokens->topic, tokens->topic_len, subhier);
HASH_FIND(hh, db->subs, split_topics[0], strlen(split_topics[0]), subhier);
if(subhier){
rc = sub__search(db, subhier, tokens, source_id, topic, qos, retain, *stored);
rc = sub__search(db, subhier, split_topics, source_id, topic, qos, retain, *stored);
}
if(retain){
rc2 = retain__store(db, topic, *stored, tokens);
if(rc2){
sub__topic_tokens_free(tokens);
db__msg_store_ref_dec(db, stored);
return rc2;
}
rc2 = retain__store(db, topic, *stored, split_topics);
if(rc2) rc = rc2;
}
sub__topic_tokens_free(tokens);
mosquitto__free(split_topics);
mosquitto__free(local_topic);
/* Remove our reference and free if needed. */
db__msg_store_ref_dec(db, stored);
+58 -92
View File
@@ -28,117 +28,83 @@ Contributors:
#include "utlist.h"
static struct sub__token *sub__topic_append(struct sub__token **tail, struct sub__token **topics, char *topic)
static char *strtok_hier(char *str, char **saveptr)
{
struct sub__token *new_topic;
char *c;
if(!topic){
return NULL;
if(str != NULL){
*saveptr = str;
}
new_topic = mosquitto__malloc(sizeof(struct sub__token));
if(!new_topic){
return NULL;
}
new_topic->next = NULL;
new_topic->topic_len = strlen(topic);
new_topic->topic = mosquitto__malloc(new_topic->topic_len+1);
if(!new_topic->topic){
mosquitto__free(new_topic);
return NULL;
}
strncpy(new_topic->topic, topic, new_topic->topic_len+1);
if(*tail){
(*tail)->next = new_topic;
*tail = (*tail)->next;
}else{
*topics = new_topic;
*tail = new_topic;
if(*saveptr == NULL){
return NULL;
}
return new_topic;
c = strchr(*saveptr, '/');
if(c){
str = *saveptr;
*saveptr = c+1;
c[0] = '\0';
}else if(*saveptr){
/* No match, but surplus string */
str = *saveptr;
*saveptr = NULL;
}
return str;
}
int sub__topic_tokenise(const char *subtopic, struct sub__token **topics)
int sub__topic_tokenise(const char *subtopic, char **local_sub, char ***topics, const char **sharename)
{
struct sub__token *new_topic, *tail = NULL;
int len;
int start, stop, tlen;
char *saveptr = NULL;
char *token;
int count;
int topic_index = 0;
int i;
char *topic;
int count = 0;
assert(subtopic);
assert(topics);
*local_sub = mosquitto__strdup(subtopic);
if((*local_sub) == NULL) return MOSQ_ERR_NOMEM;
if(subtopic[0] != '$'){
new_topic = sub__topic_append(&tail, topics, "");
if(!new_topic) goto cleanup;
count = 0;
saveptr = *local_sub;
while(saveptr){
saveptr = strchr(&saveptr[1], '/');
count++;
}
*topics = mosquitto__calloc(count+3 /* 3=$,shared,sharename */, sizeof(char *));
if((*topics) == NULL){
mosquitto__free(*local_sub);
return MOSQ_ERR_NOMEM;
}
len = strlen(subtopic);
if(subtopic[0] == '/'){
new_topic = sub__topic_append(&tail, topics, "");
if(!new_topic) goto cleanup;
start = 1;
}else{
start = 0;
if((*local_sub)[0] != '$'){
(*topics)[topic_index] = "";
topic_index++;
}
stop = 0;
for(i=start; i<len+1; i++){
if(subtopic[i] == '/' || subtopic[i] == '\0'){
stop = i;
count++;
token = strtok_hier((*local_sub), &saveptr);
while(token){
(*topics)[topic_index] = token;
topic_index++;
token = strtok_hier(NULL, &saveptr);
}
if(start != stop){
tlen = stop-start;
topic = mosquitto__malloc(tlen+1);
if(!topic) goto cleanup;
memcpy(topic, &subtopic[start], tlen);
topic[tlen] = '\0';
new_topic = sub__topic_append(&tail, topics, topic);
mosquitto__free(topic);
}else{
new_topic = sub__topic_append(&tail, topics, "");
}
if(!new_topic) goto cleanup;
start = i+1;
if(!strcmp((*topics)[0], "$share")){
if(count < 2){
mosquitto__free(*local_sub);
mosquitto__free(*topics);
return MOSQ_ERR_PROTOCOL;
}
}
if(count > TOPIC_HIERARCHY_LIMIT){
/* Set limit on hierarchy levels, to restrict stack usage. */
goto cleanup;
}
if(sharename){
(*sharename) = (*topics)[1];
}
for(i=1; i<count-1; i++){
(*topics)[i] = (*topics)[i+1];
}
(*topics)[0] = "";
(*topics)[count-1] = NULL;
}
return MOSQ_ERR_SUCCESS;
cleanup:
tail = *topics;
*topics = NULL;
while(tail){
mosquitto__free(tail->topic);
new_topic = tail->next;
mosquitto__free(tail);
tail = new_topic;
}
return 1;
}
void sub__topic_tokens_free(struct sub__token *tokens)
{
struct sub__token *tail;
while(tokens){
tail = tokens->next;
mosquitto__free(tokens->topic);
mosquitto__free(tokens);
tokens = tail;
}
}
+1 -1
View File
@@ -43,7 +43,7 @@ do_test("/"*200, True) # 200 max hierarchy limit
do_test("abc/"*199+"d", True) # 200 max hierarchy limit, longer overall string than 200
do_test("/"*201, False) # Exceeds 200 max hierarchy limit
do_test("abc/"*200+"d", False) # Exceeds 200 max hierarchy limit, longer overall string than 200
do_test("abc/"*201+"d", False) # Exceeds 200 max hierarchy limit, longer overall string than 200
exit(0)