mirror of
https://github.com/eclipse-mosquitto/mosquitto.git
synced 2026-09-22 16:15:05 +08:00
Reduce heap allocation churn when tokenising topics.
This commit is contained in:
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user