From cd3b5886010d0bb74a90ef620e7be6f79abfc2ad Mon Sep 17 00:00:00 2001 From: Chris Elston Date: Fri, 17 Sep 2021 11:52:22 +0100 Subject: [PATCH 1/3] Fix dynamic bridge start-up delay Signed-off-by: Chris Elston The first packet sent by a dynamic bridge was failing because it was sent before the socket was fully established and the OS returned -EAGAIN. We had to wait for the next PINGREQ to cause the initial packet to be sent, and therefore bridge startup was delayed by the configured keepalive timeout (default 60 seconds). This change adds the new bridge's output socket to the list managed by the mux, and we now send the initial CONNECT as soon as the output socket becomes available. --- src/bridge_dynamic.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bridge_dynamic.c b/src/bridge_dynamic.c index 4a34bb6f..ce6348c4 100644 --- a/src/bridge_dynamic.c +++ b/src/bridge_dynamic.c @@ -74,6 +74,7 @@ int bridge__dynamic_analyse(struct mosquitto_db *db, char *topic, void* payload, log__printf(NULL, MOSQ_LOG_WARNING, "Information : Start connection with bridge %s.", config.bridges[config.bridge_count-1].name); mux__add_in(db->bridges[db->bridge_count-1]); + mux__add_out(db->bridges[db->bridge_count-1]); } }else if(strncmp("$BRIDGE/del", topic, 11)==0){ rc = bridge__dynamic_parse_payload_del_json(payload,db,index); From 8491fd4a0c31705c6312a03ef9cc42f1a982625f Mon Sep 17 00:00:00 2001 From: Chris Elston Date: Fri, 17 Sep 2021 12:28:35 +0100 Subject: [PATCH 2/3] Fix segfault in dynamic bridge support Signed-off-by: Chris Elston Sending an empty packet to $BRIDGE/new would cause a segfault because the payload pointer was accessed without checking for NULL. This change rejects an empty payload with MOSQ_ERR_INVAL. --- src/bridge_dynamic.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/bridge_dynamic.c b/src/bridge_dynamic.c index ce6348c4..dfe51182 100644 --- a/src/bridge_dynamic.c +++ b/src/bridge_dynamic.c @@ -418,6 +418,8 @@ int bridge__dynamic_parse_payload_new(struct mosquitto_db *db, void* payload, st int len; int nb_param = 0; + if(!payload) return MOSQ_ERR_INVAL; + buf = strtok(payload, "\n"); while(buf) { From 63d400dc50cff8920d0b65f8f72532bc492d8dcf Mon Sep 17 00:00:00 2001 From: Chris Elston Date: Fri, 17 Sep 2021 13:02:51 +0100 Subject: [PATCH 3/3] Additional bridge parameters for dynamic bridges Signed-off-by: Chris Elston Adds the following bridge configuration as parameters for dynamic bridges: - remote_username - try_private - notification_topic - remote_clientid --- src/bridge_dynamic.c | 101 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) diff --git a/src/bridge_dynamic.c b/src/bridge_dynamic.c index dfe51182..90cbe167 100644 --- a/src/bridge_dynamic.c +++ b/src/bridge_dynamic.c @@ -152,6 +152,10 @@ int bridge__dynamic_parse_payload_new_json(struct mosquitto_db *db, void* payloa const cJSON *qos_json= NULL; const cJSON *local_prefix_json = NULL; const cJSON *remote_prefix_json = NULL; + const cJSON *remote_username = NULL; + const cJSON *try_private = NULL; + const cJSON *notification_topic = NULL; + const cJSON *remote_clientid = NULL; connection_json = cJSON_GetObjectItemCaseSensitive(bridge_json, "connection"); if(cJSON_IsString(connection_json) && (connection_json->valuestring != NULL)) { @@ -326,6 +330,49 @@ int bridge__dynamic_parse_payload_new_json(struct mosquitto_db *db, void* payloa } } } + remote_username = cJSON_GetObjectItemCaseSensitive(bridge_json, "remote_username"); + if(cJSON_IsString(remote_username) && (remote_username->valuestring != NULL)) { + if(!strcmp(remote_username->valuestring, "\"\"")){ + cur_bridge->remote_username = NULL; + }else{ + cur_bridge->remote_username = mosquitto__strdup(remote_username->valuestring); + if(!cur_bridge->remote_username){ + log__printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); + cJSON_Delete(message_json); + return MOSQ_ERR_NOMEM; + } + } + } + try_private = cJSON_GetObjectItemCaseSensitive(bridge_json, "try_private"); + if(cJSON_IsBool(try_private)){ + cur_bridge->try_private = cJSON_IsTrue(try_private) ? true : false; + } + notification_topic = cJSON_GetObjectItemCaseSensitive(bridge_json, "notification_topic"); + if(cJSON_IsString(notification_topic) && (notification_topic->valuestring != NULL)) { + if(!strcmp(notification_topic->valuestring, "\"\"")){ + cur_bridge->notification_topic = NULL; + }else{ + cur_bridge->notification_topic = mosquitto__strdup(notification_topic->valuestring); + if(!cur_bridge->notification_topic){ + log__printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); + cJSON_Delete(message_json); + return MOSQ_ERR_NOMEM; + } + } + } + remote_clientid = cJSON_GetObjectItemCaseSensitive(bridge_json, "remote_clientid"); + if(cJSON_IsString(remote_clientid) && (remote_clientid->valuestring != NULL)) { + if(!strcmp(remote_clientid->valuestring, "\"\"")){ + cur_bridge->remote_clientid = NULL; + }else{ + cur_bridge->remote_clientid = mosquitto__strdup(remote_clientid->valuestring); + if(!cur_bridge->remote_clientid){ + log__printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); + cJSON_Delete(message_json); + return MOSQ_ERR_NOMEM; + } + } + } //Last verification if(cur_bridge->address_count == 0){ @@ -515,6 +562,60 @@ int bridge__dynamic_parse_payload_new(struct mosquitto_db *db, void* payload, st return MOSQ_ERR_INVAL; } } + else if(!strcmp(token, "try_private")) + { + nb_param ++; + if(!cur_bridge){ + log__printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge configuration."); + return MOSQ_ERR_INVAL; + } + token = strtok_r(NULL, " ", &saveptr); + if(token){ + if(!strcmp(token,"false")){ + cur_bridge->try_private = false; + }else if(strcmp(token,"true")){ + log__printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge configuration."); + return MOSQ_ERR_INVAL; + } + } + } + else if(!strcmp(token, "notification_topic")) + { + nb_param ++; + if(!cur_bridge){ + log__printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge configuration."); + return MOSQ_ERR_INVAL; + } + token = strtok_r(NULL, " ", &saveptr); + if(token){ + cur_bridge->notification_topic = mosquitto__strdup(token); + } + } + else if(!strcmp(token, "remote_username")) + { + log__printf(NULL, MOSQ_LOG_INFO, "Found remote_username"); + nb_param ++; + if(!cur_bridge){ + log__printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge configuration."); + return MOSQ_ERR_INVAL; + } + token = strtok_r(NULL, " ", &saveptr); + if(token){ + cur_bridge->remote_username = mosquitto__strdup(token); + } + } + else if(!strcmp(token, "remote_clientid")) + { + nb_param ++; + if(!cur_bridge){ + log__printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge configuration."); + return MOSQ_ERR_INVAL; + } + token = strtok_r(NULL, " ", &saveptr); + if(token){ + cur_bridge->remote_clientid = mosquitto__strdup(token); + } + } else if(!strcmp(token, "topic")) { nb_param ++;