2014-05-07 22:27:00 +00:00
|
|
|
/*
|
2020-02-27 23:26:58 +00:00
|
|
|
Copyright (c) 2009-2020 Roger Light <roger@atchoo.org>
|
2014-05-07 22:27:00 +00:00
|
|
|
|
|
|
|
All rights reserved. This program and the accompanying materials
|
|
|
|
are made available under the terms of the Eclipse Public License v1.0
|
|
|
|
and Eclipse Distribution License v1.0 which accompany this distribution.
|
|
|
|
|
|
|
|
The Eclipse Public License is available at
|
|
|
|
http://www.eclipse.org/legal/epl-v10.html
|
|
|
|
and the Eclipse Distribution License is available at
|
|
|
|
http://www.eclipse.org/org/documents/edl-v10.php.
|
|
|
|
|
|
|
|
Contributors:
|
|
|
|
Roger Light - initial implementation and documentation.
|
|
|
|
*/
|
|
|
|
|
2018-04-05 23:33:22 +00:00
|
|
|
#include "config.h"
|
|
|
|
|
2014-05-07 22:27:00 +00:00
|
|
|
#include <assert.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#ifndef WIN32
|
|
|
|
#include <netdb.h>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#else
|
|
|
|
#include <winsock2.h>
|
|
|
|
#include <ws2tcpip.h>
|
|
|
|
#endif
|
|
|
|
|
2019-07-11 13:43:32 +00:00
|
|
|
#ifndef WIN32
|
|
|
|
#include <unistd.h>
|
|
|
|
#else
|
|
|
|
#include <process.h>
|
|
|
|
#include <winsock2.h>
|
|
|
|
#include <ws2tcpip.h>
|
|
|
|
#endif
|
|
|
|
|
2018-12-19 10:45:40 +00:00
|
|
|
#include "mqtt_protocol.h"
|
2015-04-29 20:37:47 +00:00
|
|
|
#include "mosquitto.h"
|
2016-07-08 09:10:04 +00:00
|
|
|
#include "mosquitto_broker_internal.h"
|
2015-04-29 20:37:47 +00:00
|
|
|
#include "mosquitto_internal.h"
|
|
|
|
#include "net_mosq.h"
|
|
|
|
#include "memory_mosq.h"
|
2015-04-29 20:23:59 +00:00
|
|
|
#include "packet_mosq.h"
|
2015-04-29 20:37:47 +00:00
|
|
|
#include "send_mosq.h"
|
|
|
|
#include "time_mosq.h"
|
|
|
|
#include "tls_mosq.h"
|
|
|
|
#include "util_mosq.h"
|
|
|
|
#include "will_mosq.h"
|
2014-05-07 22:27:00 +00:00
|
|
|
|
|
|
|
#ifdef WITH_BRIDGE
|
|
|
|
|
2019-02-27 13:52:19 +00:00
|
|
|
static void bridge__backoff_step(struct mosquitto *context);
|
2018-11-09 06:38:48 +00:00
|
|
|
static void bridge__backoff_reset(struct mosquitto *context);
|
|
|
|
|
2020-04-08 10:34:31 +00:00
|
|
|
void bridge__start_all(struct mosquitto_db *db)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for(i=0; i<db->config->bridge_count; i++){
|
|
|
|
if(bridge__new(db, &(db->config->bridges[i]))){
|
|
|
|
log__printf(NULL, MOSQ_LOG_WARNING, "Warning: Unable to connect to bridge %s.",
|
|
|
|
db->config->bridges[i].name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-05-16 18:03:12 +00:00
|
|
|
int bridge__new(struct mosquitto_db *db, struct mosquitto__bridge *bridge)
|
2014-05-07 22:27:00 +00:00
|
|
|
{
|
|
|
|
struct mosquitto *new_context = NULL;
|
2014-11-18 23:34:54 +00:00
|
|
|
struct mosquitto **bridges;
|
2015-06-09 22:18:13 +00:00
|
|
|
char *local_id;
|
2014-05-07 22:27:00 +00:00
|
|
|
|
|
|
|
assert(db);
|
|
|
|
assert(bridge);
|
|
|
|
|
2015-06-09 22:18:13 +00:00
|
|
|
local_id = mosquitto__strdup(bridge->local_clientid);
|
2014-05-07 22:27:00 +00:00
|
|
|
|
2014-06-23 16:57:35 +00:00
|
|
|
HASH_FIND(hh_id, db->contexts_by_id, local_id, strlen(local_id), new_context);
|
|
|
|
if(new_context){
|
|
|
|
/* (possible from persistent db) */
|
2015-04-19 21:10:59 +00:00
|
|
|
mosquitto__free(local_id);
|
2014-06-23 16:57:35 +00:00
|
|
|
}else{
|
2014-05-07 22:27:00 +00:00
|
|
|
/* id wasn't found, so generate a new context */
|
2015-05-16 14:24:24 +00:00
|
|
|
new_context = context__init(db, -1);
|
2014-05-07 22:27:00 +00:00
|
|
|
if(!new_context){
|
2015-04-19 21:10:59 +00:00
|
|
|
mosquitto__free(local_id);
|
2014-05-07 22:27:00 +00:00
|
|
|
return MOSQ_ERR_NOMEM;
|
|
|
|
}
|
2014-07-03 20:55:25 +00:00
|
|
|
new_context->id = local_id;
|
2014-06-23 16:57:35 +00:00
|
|
|
HASH_ADD_KEYPTR(hh_id, db->contexts_by_id, new_context->id, strlen(new_context->id), new_context);
|
2014-05-07 22:27:00 +00:00
|
|
|
}
|
|
|
|
new_context->bridge = bridge;
|
|
|
|
new_context->is_bridge = true;
|
|
|
|
|
2014-08-16 20:31:12 +00:00
|
|
|
new_context->username = new_context->bridge->remote_username;
|
|
|
|
new_context->password = new_context->bridge->remote_password;
|
2014-05-07 22:27:00 +00:00
|
|
|
|
|
|
|
#ifdef WITH_TLS
|
|
|
|
new_context->tls_cafile = new_context->bridge->tls_cafile;
|
|
|
|
new_context->tls_capath = new_context->bridge->tls_capath;
|
|
|
|
new_context->tls_certfile = new_context->bridge->tls_certfile;
|
|
|
|
new_context->tls_keyfile = new_context->bridge->tls_keyfile;
|
2014-05-08 21:48:13 +00:00
|
|
|
new_context->tls_cert_reqs = SSL_VERIFY_PEER;
|
2017-06-09 13:52:50 +00:00
|
|
|
new_context->tls_ocsp_required = new_context->bridge->tls_ocsp_required;
|
2014-05-07 22:27:00 +00:00
|
|
|
new_context->tls_version = new_context->bridge->tls_version;
|
|
|
|
new_context->tls_insecure = new_context->bridge->tls_insecure;
|
2019-04-04 23:38:08 +00:00
|
|
|
new_context->tls_alpn = new_context->bridge->tls_alpn;
|
2019-09-05 13:13:44 +00:00
|
|
|
new_context->tls_engine = db->config->default_listener.tls_engine;
|
|
|
|
new_context->tls_keyform = db->config->default_listener.tls_keyform;
|
2018-12-09 13:40:38 +00:00
|
|
|
#ifdef FINAL_WITH_TLS_PSK
|
2014-05-07 22:27:00 +00:00
|
|
|
new_context->tls_psk_identity = new_context->bridge->tls_psk_identity;
|
|
|
|
new_context->tls_psk = new_context->bridge->tls_psk;
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
bridge->try_private_accepted = true;
|
2020-01-31 11:57:00 +00:00
|
|
|
if(bridge->clean_start_local == -1){
|
|
|
|
/* default to "regular" clean start setting */
|
|
|
|
bridge->clean_start_local = bridge->clean_start;
|
|
|
|
}
|
2019-11-07 11:58:43 +00:00
|
|
|
new_context->retain_available = bridge->outgoing_retain;
|
2015-01-27 17:12:36 +00:00
|
|
|
new_context->protocol = bridge->protocol_version;
|
2014-05-07 22:27:00 +00:00
|
|
|
|
2015-04-19 21:10:59 +00:00
|
|
|
bridges = mosquitto__realloc(db->bridges, (db->bridge_count+1)*sizeof(struct mosquitto *));
|
2014-11-18 23:34:54 +00:00
|
|
|
if(bridges){
|
|
|
|
db->bridges = bridges;
|
|
|
|
db->bridge_count++;
|
|
|
|
db->bridges[db->bridge_count-1] = new_context;
|
|
|
|
}else{
|
|
|
|
return MOSQ_ERR_NOMEM;
|
|
|
|
}
|
2014-06-23 16:57:35 +00:00
|
|
|
|
2017-02-08 22:30:00 +00:00
|
|
|
#if defined(__GLIBC__) && defined(WITH_ADNS)
|
2017-02-06 22:39:39 +00:00
|
|
|
new_context->bridge->restart_t = 1; /* force quick restart of bridge */
|
2017-03-06 21:19:53 +00:00
|
|
|
return bridge__connect_step1(db, new_context);
|
2017-02-06 22:39:39 +00:00
|
|
|
#else
|
2015-05-16 14:24:24 +00:00
|
|
|
return bridge__connect(db, new_context);
|
2017-02-06 22:39:39 +00:00
|
|
|
#endif
|
2014-05-07 22:27:00 +00:00
|
|
|
}
|
|
|
|
|
2017-02-09 16:41:48 +00:00
|
|
|
#if defined(__GLIBC__) && defined(WITH_ADNS)
|
2017-03-06 21:19:53 +00:00
|
|
|
int bridge__connect_step1(struct mosquitto_db *db, struct mosquitto *context)
|
2014-05-07 22:27:00 +00:00
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
char *notification_topic;
|
|
|
|
int notification_topic_len;
|
|
|
|
uint8_t notification_payload;
|
2019-02-28 15:38:15 +00:00
|
|
|
int i;
|
2014-05-07 22:27:00 +00:00
|
|
|
|
|
|
|
if(!context || !context->bridge) return MOSQ_ERR_INVAL;
|
|
|
|
|
2019-09-24 10:54:05 +00:00
|
|
|
mosquitto__set_state(context, mosq_cs_new);
|
2015-03-29 09:43:08 +00:00
|
|
|
context->sock = INVALID_SOCKET;
|
2014-05-07 22:27:00 +00:00
|
|
|
context->last_msg_in = mosquitto_time();
|
2016-02-28 17:24:43 +00:00
|
|
|
context->next_msg_out = mosquitto_time() + context->bridge->keepalive;
|
2014-05-07 22:27:00 +00:00
|
|
|
context->keepalive = context->bridge->keepalive;
|
2018-11-27 10:02:10 +00:00
|
|
|
context->clean_start = context->bridge->clean_start;
|
2014-05-07 22:27:00 +00:00
|
|
|
context->in_packet.payload = NULL;
|
|
|
|
context->ping_t = 0;
|
|
|
|
context->bridge->lazy_reconnect = false;
|
2018-04-19 19:38:10 +00:00
|
|
|
bridge__packet_cleanup(context);
|
|
|
|
db__message_reconnect_reset(db, context);
|
2014-05-07 22:27:00 +00:00
|
|
|
|
2020-01-31 11:57:00 +00:00
|
|
|
db__messages_delete(db, context);
|
2014-05-07 22:27:00 +00:00
|
|
|
|
2018-11-27 10:02:10 +00:00
|
|
|
/* Delete all local subscriptions even for clean_start==false. We don't
|
2014-05-07 22:27:00 +00:00
|
|
|
* remove any messages and the next loop carries out the resubscription
|
|
|
|
* anyway. This means any unwanted subs will be removed.
|
|
|
|
*/
|
2018-04-19 19:38:10 +00:00
|
|
|
sub__clean_session(db, context);
|
2014-05-07 22:27:00 +00:00
|
|
|
|
|
|
|
for(i=0; i<context->bridge->topic_count; i++){
|
|
|
|
if(context->bridge->topics[i].direction == bd_out || context->bridge->topics[i].direction == bd_both){
|
2018-04-19 19:38:10 +00:00
|
|
|
log__printf(NULL, MOSQ_LOG_DEBUG, "Bridge %s doing local SUBSCRIBE on topic %s", context->id, context->bridge->topics[i].local_topic);
|
2018-12-19 10:45:40 +00:00
|
|
|
if(sub__add(db,
|
|
|
|
context,
|
|
|
|
context->bridge->topics[i].local_topic,
|
|
|
|
context->bridge->topics[i].qos,
|
2018-12-20 15:32:43 +00:00
|
|
|
0,
|
2018-12-19 10:45:40 +00:00
|
|
|
MQTT_SUB_OPT_NO_LOCAL | MQTT_SUB_OPT_RETAIN_AS_PUBLISHED,
|
|
|
|
&db->subs) > 0){
|
2018-12-06 22:15:49 +00:00
|
|
|
return 1;
|
|
|
|
}
|
2019-05-14 12:24:46 +00:00
|
|
|
retain__queue(db, context,
|
2018-09-25 10:39:58 +00:00
|
|
|
context->bridge->topics[i].local_topic,
|
2019-02-12 17:05:42 +00:00
|
|
|
context->bridge->topics[i].qos, 0);
|
2014-05-07 22:27:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-09 06:38:48 +00:00
|
|
|
/* prepare backoff for a possible failure. Restart timeout will be reset if connection gets established */
|
2019-02-27 13:52:19 +00:00
|
|
|
bridge__backoff_step(context);
|
2018-11-09 06:38:48 +00:00
|
|
|
|
2014-05-07 22:27:00 +00:00
|
|
|
if(context->bridge->notifications){
|
|
|
|
if(context->bridge->notification_topic){
|
2015-05-16 11:02:18 +00:00
|
|
|
if(!context->bridge->initial_notification_done){
|
|
|
|
notification_payload = '0';
|
2019-02-12 17:05:42 +00:00
|
|
|
db__messages_easy_queue(db, context, context->bridge->notification_topic, 1, 1, ¬ification_payload, 1, 0, NULL);
|
2015-05-16 11:02:18 +00:00
|
|
|
context->bridge->initial_notification_done = true;
|
|
|
|
}
|
2014-09-17 21:40:49 +00:00
|
|
|
notification_payload = '0';
|
2018-11-01 11:37:57 +00:00
|
|
|
rc = will__set(context, context->bridge->notification_topic, 1, ¬ification_payload, 1, true, NULL);
|
2014-05-07 22:27:00 +00:00
|
|
|
if(rc != MOSQ_ERR_SUCCESS){
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
}else{
|
2015-04-17 19:42:54 +00:00
|
|
|
notification_topic_len = strlen(context->bridge->remote_clientid)+strlen("$SYS/broker/connection//state");
|
2018-04-19 19:38:10 +00:00
|
|
|
notification_topic = mosquitto__malloc(sizeof(char)*(notification_topic_len+1));
|
2014-05-07 22:27:00 +00:00
|
|
|
if(!notification_topic) return MOSQ_ERR_NOMEM;
|
|
|
|
|
2015-04-17 19:42:54 +00:00
|
|
|
snprintf(notification_topic, notification_topic_len+1, "$SYS/broker/connection/%s/state", context->bridge->remote_clientid);
|
|
|
|
|
2015-05-16 11:02:18 +00:00
|
|
|
if(!context->bridge->initial_notification_done){
|
|
|
|
notification_payload = '0';
|
2019-02-12 17:05:42 +00:00
|
|
|
db__messages_easy_queue(db, context, notification_topic, 1, 1, ¬ification_payload, 1, 0, NULL);
|
2015-05-16 11:02:18 +00:00
|
|
|
context->bridge->initial_notification_done = true;
|
|
|
|
}
|
2014-08-16 22:14:41 +00:00
|
|
|
|
2014-09-17 21:40:49 +00:00
|
|
|
notification_payload = '0';
|
2018-11-01 11:37:57 +00:00
|
|
|
rc = will__set(context, notification_topic, 1, ¬ification_payload, 1, true, NULL);
|
2018-04-19 19:38:10 +00:00
|
|
|
mosquitto__free(notification_topic);
|
2014-05-07 22:27:00 +00:00
|
|
|
if(rc != MOSQ_ERR_SUCCESS){
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-19 11:55:08 +00:00
|
|
|
log__printf(NULL, MOSQ_LOG_NOTICE, "Connecting bridge (step 1) %s (%s:%d)", context->bridge->name, context->bridge->addresses[context->bridge->cur_address].address, context->bridge->addresses[context->bridge->cur_address].port);
|
2018-04-19 19:38:10 +00:00
|
|
|
rc = net__try_connect_step1(context, context->bridge->addresses[context->bridge->cur_address].address);
|
2017-02-06 22:39:39 +00:00
|
|
|
if(rc > 0 ){
|
|
|
|
if(rc == MOSQ_ERR_TLS){
|
2018-04-19 19:38:10 +00:00
|
|
|
net__socket_close(db, context);
|
2017-02-06 22:39:39 +00:00
|
|
|
return rc; /* Error already printed */
|
|
|
|
}else if(rc == MOSQ_ERR_ERRNO){
|
2018-04-19 19:38:10 +00:00
|
|
|
log__printf(NULL, MOSQ_LOG_ERR, "Error creating bridge: %s.", strerror(errno));
|
2017-02-06 22:39:39 +00:00
|
|
|
}else if(rc == MOSQ_ERR_EAI){
|
2018-04-19 19:38:10 +00:00
|
|
|
log__printf(NULL, MOSQ_LOG_ERR, "Error creating bridge: %s.", gai_strerror(errno));
|
2017-02-06 22:39:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
return MOSQ_ERR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-03-06 21:19:53 +00:00
|
|
|
int bridge__connect_step2(struct mosquitto_db *db, struct mosquitto *context)
|
2017-02-06 22:39:39 +00:00
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
if(!context || !context->bridge) return MOSQ_ERR_INVAL;
|
|
|
|
|
2018-09-19 11:55:08 +00:00
|
|
|
log__printf(NULL, MOSQ_LOG_NOTICE, "Connecting bridge (step 2) %s (%s:%d)", context->bridge->name, context->bridge->addresses[context->bridge->cur_address].address, context->bridge->addresses[context->bridge->cur_address].port);
|
2018-04-19 19:38:10 +00:00
|
|
|
rc = net__try_connect_step2(context, context->bridge->addresses[context->bridge->cur_address].port, &context->sock);
|
2018-09-19 11:55:08 +00:00
|
|
|
if(rc > 0){
|
2017-02-06 23:10:43 +00:00
|
|
|
if(rc == MOSQ_ERR_TLS){
|
2018-04-19 19:38:10 +00:00
|
|
|
net__socket_close(db, context);
|
2017-02-06 23:10:43 +00:00
|
|
|
return rc; /* Error already printed */
|
|
|
|
}else if(rc == MOSQ_ERR_ERRNO){
|
2018-04-19 19:38:10 +00:00
|
|
|
log__printf(NULL, MOSQ_LOG_ERR, "Error creating bridge: %s.", strerror(errno));
|
2017-02-06 23:10:43 +00:00
|
|
|
}else if(rc == MOSQ_ERR_EAI){
|
2018-04-19 19:38:10 +00:00
|
|
|
log__printf(NULL, MOSQ_LOG_ERR, "Error creating bridge: %s.", gai_strerror(errno));
|
2017-02-06 23:10:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2018-09-19 11:55:08 +00:00
|
|
|
HASH_ADD(hh_sock, db->contexts_by_sock, sock, sizeof(context->sock), context);
|
|
|
|
|
|
|
|
if(rc == MOSQ_ERR_CONN_PENDING){
|
2019-09-24 10:54:05 +00:00
|
|
|
mosquitto__set_state(context, mosq_cs_connect_pending);
|
2018-09-19 11:55:08 +00:00
|
|
|
}
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int bridge__connect_step3(struct mosquitto_db *db, struct mosquitto *context)
|
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
|
2019-02-08 21:34:08 +00:00
|
|
|
rc = net__socket_connect_step3(context, context->bridge->addresses[context->bridge->cur_address].address);
|
2018-09-19 11:55:08 +00:00
|
|
|
if(rc > 0){
|
2014-05-07 22:27:00 +00:00
|
|
|
if(rc == MOSQ_ERR_TLS){
|
2018-04-19 19:38:10 +00:00
|
|
|
net__socket_close(db, context);
|
2014-05-07 22:27:00 +00:00
|
|
|
return rc; /* Error already printed */
|
|
|
|
}else if(rc == MOSQ_ERR_ERRNO){
|
2018-04-19 19:38:10 +00:00
|
|
|
log__printf(NULL, MOSQ_LOG_ERR, "Error creating bridge: %s.", strerror(errno));
|
2014-05-07 22:27:00 +00:00
|
|
|
}else if(rc == MOSQ_ERR_EAI){
|
2018-04-19 19:38:10 +00:00
|
|
|
log__printf(NULL, MOSQ_LOG_ERR, "Error creating bridge: %s.", gai_strerror(errno));
|
2014-05-07 22:27:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2018-09-19 13:40:22 +00:00
|
|
|
if(context->bridge->round_robin == false && context->bridge->cur_address != 0){
|
|
|
|
context->bridge->primary_retry = mosquitto_time() + 5;
|
|
|
|
}
|
|
|
|
|
2018-11-27 10:02:10 +00:00
|
|
|
rc = send__connect(context, context->keepalive, context->clean_start, NULL);
|
2014-05-07 22:27:00 +00:00
|
|
|
if(rc == MOSQ_ERR_SUCCESS){
|
2018-11-09 06:38:48 +00:00
|
|
|
bridge__backoff_reset(context);
|
2014-05-07 22:27:00 +00:00
|
|
|
return MOSQ_ERR_SUCCESS;
|
|
|
|
}else if(rc == MOSQ_ERR_ERRNO && errno == ENOTCONN){
|
2018-11-09 06:38:48 +00:00
|
|
|
bridge__backoff_reset(context);
|
2014-05-07 22:27:00 +00:00
|
|
|
return MOSQ_ERR_SUCCESS;
|
|
|
|
}else{
|
|
|
|
if(rc == MOSQ_ERR_TLS){
|
|
|
|
return rc; /* Error already printed */
|
|
|
|
}else if(rc == MOSQ_ERR_ERRNO){
|
2018-04-19 19:38:10 +00:00
|
|
|
log__printf(NULL, MOSQ_LOG_ERR, "Error creating bridge: %s.", strerror(errno));
|
2014-05-07 22:27:00 +00:00
|
|
|
}else if(rc == MOSQ_ERR_EAI){
|
2018-04-19 19:38:10 +00:00
|
|
|
log__printf(NULL, MOSQ_LOG_ERR, "Error creating bridge: %s.", gai_strerror(errno));
|
2014-05-07 22:27:00 +00:00
|
|
|
}
|
2018-04-19 19:38:10 +00:00
|
|
|
net__socket_close(db, context);
|
2014-05-07 22:27:00 +00:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
}
|
2017-02-09 16:41:48 +00:00
|
|
|
#else
|
2014-05-07 22:27:00 +00:00
|
|
|
|
2015-05-16 14:24:24 +00:00
|
|
|
int bridge__connect(struct mosquitto_db *db, struct mosquitto *context)
|
2014-05-07 22:27:00 +00:00
|
|
|
{
|
2018-09-19 13:40:22 +00:00
|
|
|
int rc, rc2;
|
2014-05-07 22:27:00 +00:00
|
|
|
int i;
|
|
|
|
char *notification_topic;
|
|
|
|
int notification_topic_len;
|
|
|
|
uint8_t notification_payload;
|
|
|
|
|
|
|
|
if(!context || !context->bridge) return MOSQ_ERR_INVAL;
|
|
|
|
|
2019-09-24 10:54:05 +00:00
|
|
|
mosquitto__set_state(context, mosq_cs_new);
|
2015-03-29 09:43:08 +00:00
|
|
|
context->sock = INVALID_SOCKET;
|
2014-05-07 22:27:00 +00:00
|
|
|
context->last_msg_in = mosquitto_time();
|
2016-02-28 17:24:43 +00:00
|
|
|
context->next_msg_out = mosquitto_time() + context->bridge->keepalive;
|
2014-05-07 22:27:00 +00:00
|
|
|
context->keepalive = context->bridge->keepalive;
|
2018-11-27 10:02:10 +00:00
|
|
|
context->clean_start = context->bridge->clean_start;
|
2014-05-07 22:27:00 +00:00
|
|
|
context->in_packet.payload = NULL;
|
|
|
|
context->ping_t = 0;
|
|
|
|
context->bridge->lazy_reconnect = false;
|
2015-05-16 14:24:24 +00:00
|
|
|
bridge__packet_cleanup(context);
|
|
|
|
db__message_reconnect_reset(db, context);
|
2014-05-07 22:27:00 +00:00
|
|
|
|
2020-01-31 11:57:00 +00:00
|
|
|
db__messages_delete(db, context);
|
2014-05-07 22:27:00 +00:00
|
|
|
|
2018-11-27 10:02:10 +00:00
|
|
|
/* Delete all local subscriptions even for clean_start==false. We don't
|
2014-05-07 22:27:00 +00:00
|
|
|
* remove any messages and the next loop carries out the resubscription
|
|
|
|
* anyway. This means any unwanted subs will be removed.
|
|
|
|
*/
|
2015-05-18 08:29:22 +00:00
|
|
|
sub__clean_session(db, context);
|
2014-05-07 22:27:00 +00:00
|
|
|
|
|
|
|
for(i=0; i<context->bridge->topic_count; i++){
|
|
|
|
if(context->bridge->topics[i].direction == bd_out || context->bridge->topics[i].direction == bd_both){
|
2015-05-18 07:53:21 +00:00
|
|
|
log__printf(NULL, MOSQ_LOG_DEBUG, "Bridge %s doing local SUBSCRIBE on topic %s", context->id, context->bridge->topics[i].local_topic);
|
2018-12-19 10:45:40 +00:00
|
|
|
if(sub__add(db,
|
|
|
|
context,
|
|
|
|
context->bridge->topics[i].local_topic,
|
|
|
|
context->bridge->topics[i].qos,
|
2018-12-20 15:32:43 +00:00
|
|
|
0,
|
2018-12-19 10:45:40 +00:00
|
|
|
MQTT_SUB_OPT_NO_LOCAL | MQTT_SUB_OPT_RETAIN_AS_PUBLISHED,
|
|
|
|
&db->subs) > 0){
|
|
|
|
|
2018-12-06 22:15:49 +00:00
|
|
|
return 1;
|
|
|
|
}
|
2014-05-07 22:27:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-09 06:38:48 +00:00
|
|
|
/* prepare backoff for a possible failure. Restart timeout will be reset if connection gets established */
|
2019-02-27 13:52:19 +00:00
|
|
|
bridge__backoff_step(context);
|
2018-11-09 06:38:48 +00:00
|
|
|
|
2014-05-07 22:27:00 +00:00
|
|
|
if(context->bridge->notifications){
|
|
|
|
if(context->bridge->notification_topic){
|
2015-05-16 11:02:18 +00:00
|
|
|
if(!context->bridge->initial_notification_done){
|
|
|
|
notification_payload = '0';
|
2019-01-22 17:51:57 +00:00
|
|
|
db__messages_easy_queue(db, context, context->bridge->notification_topic, 1, 1, ¬ification_payload, 1, 0, NULL);
|
2015-05-16 11:02:18 +00:00
|
|
|
context->bridge->initial_notification_done = true;
|
|
|
|
}
|
2016-12-04 21:47:38 +00:00
|
|
|
|
|
|
|
if (!context->bridge->notifications_local_only) {
|
|
|
|
notification_payload = '0';
|
2018-11-01 11:37:57 +00:00
|
|
|
rc = will__set(context, context->bridge->notification_topic, 1, ¬ification_payload, 1, true, NULL);
|
2016-12-04 21:47:38 +00:00
|
|
|
if(rc != MOSQ_ERR_SUCCESS){
|
|
|
|
return rc;
|
|
|
|
}
|
2014-05-07 22:27:00 +00:00
|
|
|
}
|
|
|
|
}else{
|
2015-04-17 19:42:54 +00:00
|
|
|
notification_topic_len = strlen(context->bridge->remote_clientid)+strlen("$SYS/broker/connection//state");
|
2015-04-19 21:10:59 +00:00
|
|
|
notification_topic = mosquitto__malloc(sizeof(char)*(notification_topic_len+1));
|
2014-05-07 22:27:00 +00:00
|
|
|
if(!notification_topic) return MOSQ_ERR_NOMEM;
|
|
|
|
|
2014-08-16 22:14:41 +00:00
|
|
|
snprintf(notification_topic, notification_topic_len+1, "$SYS/broker/connection/%s/state", context->bridge->remote_clientid);
|
2015-04-17 19:42:54 +00:00
|
|
|
|
2015-05-16 11:02:18 +00:00
|
|
|
if(!context->bridge->initial_notification_done){
|
|
|
|
notification_payload = '0';
|
2019-01-22 17:51:57 +00:00
|
|
|
db__messages_easy_queue(db, context, notification_topic, 1, 1, ¬ification_payload, 1, 0, NULL);
|
2015-05-16 11:02:18 +00:00
|
|
|
context->bridge->initial_notification_done = true;
|
|
|
|
}
|
2014-08-16 22:14:41 +00:00
|
|
|
|
2016-12-04 21:47:38 +00:00
|
|
|
if (!context->bridge->notifications_local_only) {
|
|
|
|
notification_payload = '0';
|
2018-11-01 11:37:57 +00:00
|
|
|
rc = will__set(context, notification_topic, 1, ¬ification_payload, 1, true, NULL);
|
2016-12-04 21:47:38 +00:00
|
|
|
mosquitto__free(notification_topic);
|
|
|
|
if(rc != MOSQ_ERR_SUCCESS){
|
|
|
|
return rc;
|
|
|
|
}
|
2014-05-07 22:27:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-18 07:53:21 +00:00
|
|
|
log__printf(NULL, MOSQ_LOG_NOTICE, "Connecting bridge %s (%s:%d)", context->bridge->name, context->bridge->addresses[context->bridge->cur_address].address, context->bridge->addresses[context->bridge->cur_address].port);
|
2015-05-18 08:29:22 +00:00
|
|
|
rc = net__socket_connect(context, context->bridge->addresses[context->bridge->cur_address].address, context->bridge->addresses[context->bridge->cur_address].port, NULL, false);
|
2018-09-19 13:40:22 +00:00
|
|
|
if(rc > 0){
|
2014-05-07 22:27:00 +00:00
|
|
|
if(rc == MOSQ_ERR_TLS){
|
2016-02-09 23:03:26 +00:00
|
|
|
net__socket_close(db, context);
|
2014-05-07 22:27:00 +00:00
|
|
|
return rc; /* Error already printed */
|
|
|
|
}else if(rc == MOSQ_ERR_ERRNO){
|
2015-05-18 07:53:21 +00:00
|
|
|
log__printf(NULL, MOSQ_LOG_ERR, "Error creating bridge: %s.", strerror(errno));
|
2014-05-07 22:27:00 +00:00
|
|
|
}else if(rc == MOSQ_ERR_EAI){
|
2015-05-18 07:53:21 +00:00
|
|
|
log__printf(NULL, MOSQ_LOG_ERR, "Error creating bridge: %s.", gai_strerror(errno));
|
2014-05-07 22:27:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return rc;
|
2018-09-19 13:40:22 +00:00
|
|
|
}else if(rc == MOSQ_ERR_CONN_PENDING){
|
2019-09-24 10:54:05 +00:00
|
|
|
mosquitto__set_state(context, mosq_cs_connect_pending);
|
2014-05-07 22:27:00 +00:00
|
|
|
}
|
|
|
|
|
2014-06-23 16:57:35 +00:00
|
|
|
HASH_ADD(hh_sock, db->contexts_by_sock, sock, sizeof(context->sock), context);
|
2014-10-24 20:28:24 +00:00
|
|
|
|
2018-11-27 10:02:10 +00:00
|
|
|
rc2 = send__connect(context, context->keepalive, context->clean_start, NULL);
|
2018-09-19 13:40:22 +00:00
|
|
|
if(rc2 == MOSQ_ERR_SUCCESS){
|
2018-11-09 06:38:48 +00:00
|
|
|
bridge__backoff_reset(context);
|
2018-09-19 13:40:22 +00:00
|
|
|
return rc;
|
|
|
|
}else if(rc2 == MOSQ_ERR_ERRNO && errno == ENOTCONN){
|
2018-11-09 06:38:48 +00:00
|
|
|
bridge__backoff_reset(context);
|
2014-05-07 22:27:00 +00:00
|
|
|
return MOSQ_ERR_SUCCESS;
|
|
|
|
}else{
|
2018-09-19 13:40:22 +00:00
|
|
|
if(rc2 == MOSQ_ERR_TLS){
|
|
|
|
return rc2; /* Error already printed */
|
|
|
|
}else if(rc2 == MOSQ_ERR_ERRNO){
|
2015-05-18 07:53:21 +00:00
|
|
|
log__printf(NULL, MOSQ_LOG_ERR, "Error creating bridge: %s.", strerror(errno));
|
2018-09-19 13:40:22 +00:00
|
|
|
}else if(rc2 == MOSQ_ERR_EAI){
|
2015-05-18 07:53:21 +00:00
|
|
|
log__printf(NULL, MOSQ_LOG_ERR, "Error creating bridge: %s.", gai_strerror(errno));
|
2014-05-07 22:27:00 +00:00
|
|
|
}
|
2015-05-18 08:29:22 +00:00
|
|
|
net__socket_close(db, context);
|
2018-09-19 13:40:22 +00:00
|
|
|
return rc2;
|
2014-05-07 22:27:00 +00:00
|
|
|
}
|
|
|
|
}
|
2017-02-09 16:41:48 +00:00
|
|
|
#endif
|
2017-02-06 22:39:39 +00:00
|
|
|
|
2014-05-07 22:27:00 +00:00
|
|
|
|
2019-10-09 09:51:42 +00:00
|
|
|
int bridge__on_connect(struct mosquitto_db *db, struct mosquitto *context)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
char *notification_topic;
|
|
|
|
int notification_topic_len;
|
|
|
|
char notification_payload;
|
2019-10-09 09:52:58 +00:00
|
|
|
int sub_opts;
|
2019-11-07 13:31:42 +00:00
|
|
|
bool retain = true;
|
2019-10-09 09:51:42 +00:00
|
|
|
|
|
|
|
if(context->bridge->notifications){
|
2019-11-07 13:31:42 +00:00
|
|
|
if(!context->retain_available){
|
|
|
|
retain = false;
|
|
|
|
}
|
2019-10-09 09:51:42 +00:00
|
|
|
notification_payload = '1';
|
|
|
|
if(context->bridge->notification_topic){
|
|
|
|
if(!context->bridge->notifications_local_only){
|
|
|
|
if(send__real_publish(context, mosquitto__mid_generate(context),
|
2019-11-07 13:31:42 +00:00
|
|
|
context->bridge->notification_topic, 1, ¬ification_payload, 1, retain, 0, NULL, NULL, 0)){
|
2019-10-09 09:51:42 +00:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
db__messages_easy_queue(db, context, context->bridge->notification_topic, 1, 1, ¬ification_payload, 1, 0, NULL);
|
|
|
|
}else{
|
|
|
|
notification_topic_len = strlen(context->bridge->remote_clientid)+strlen("$SYS/broker/connection//state");
|
|
|
|
notification_topic = mosquitto__malloc(sizeof(char)*(notification_topic_len+1));
|
|
|
|
if(!notification_topic) return MOSQ_ERR_NOMEM;
|
|
|
|
|
|
|
|
snprintf(notification_topic, notification_topic_len+1, "$SYS/broker/connection/%s/state", context->bridge->remote_clientid);
|
|
|
|
notification_payload = '1';
|
|
|
|
if(!context->bridge->notifications_local_only){
|
|
|
|
if(send__real_publish(context, mosquitto__mid_generate(context),
|
2019-11-07 13:31:42 +00:00
|
|
|
notification_topic, 1, ¬ification_payload, 1, retain, 0, NULL, NULL, 0)){
|
2019-10-09 09:51:42 +00:00
|
|
|
|
|
|
|
mosquitto__free(notification_topic);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
db__messages_easy_queue(db, context, notification_topic, 1, 1, ¬ification_payload, 1, 0, NULL);
|
|
|
|
mosquitto__free(notification_topic);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for(i=0; i<context->bridge->topic_count; i++){
|
|
|
|
if(context->bridge->topics[i].direction == bd_in || context->bridge->topics[i].direction == bd_both){
|
2019-10-09 09:52:58 +00:00
|
|
|
sub_opts = context->bridge->topics[i].qos;
|
|
|
|
if(context->bridge->protocol_version == mosq_p_mqtt5){
|
|
|
|
sub_opts = sub_opts
|
|
|
|
| MQTT_SUB_OPT_NO_LOCAL
|
|
|
|
| MQTT_SUB_OPT_RETAIN_AS_PUBLISHED
|
|
|
|
| MQTT_SUB_OPT_SEND_RETAIN_ALWAYS;
|
|
|
|
}
|
|
|
|
if(send__subscribe(context, NULL, 1, &context->bridge->topics[i].remote_topic, sub_opts, NULL)){
|
2019-10-09 09:51:42 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}else{
|
|
|
|
if(context->bridge->attempt_unsubscribe){
|
|
|
|
if(send__unsubscribe(context, NULL, 1, &context->bridge->topics[i].remote_topic, NULL)){
|
|
|
|
/* direction = inwards only. This means we should not be subscribed
|
|
|
|
* to the topic. It is possible that we used to be subscribed to
|
|
|
|
* this topic so unsubscribe. */
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for(i=0; i<context->bridge->topic_count; i++){
|
|
|
|
if(context->bridge->topics[i].direction == bd_out || context->bridge->topics[i].direction == bd_both){
|
2019-05-14 12:24:46 +00:00
|
|
|
retain__queue(db, context,
|
2019-10-09 09:51:42 +00:00
|
|
|
context->bridge->topics[i].local_topic,
|
|
|
|
context->bridge->topics[i].qos, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return MOSQ_ERR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-07-11 13:43:32 +00:00
|
|
|
int bridge__register_local_connections(struct mosquitto_db *db)
|
|
|
|
{
|
|
|
|
#ifdef WITH_EPOLL
|
|
|
|
struct mosquitto *context, *ctxt_tmp = NULL;
|
|
|
|
|
|
|
|
HASH_ITER(hh_sock, db->contexts_by_sock, context, ctxt_tmp){
|
|
|
|
if(context->bridge){
|
2020-02-15 14:49:53 +00:00
|
|
|
if(mux__add_in(db, context)){
|
2019-07-11 13:43:32 +00:00
|
|
|
log__printf(NULL, MOSQ_LOG_ERR, "Error in epoll initial registering bridge: %s", strerror(errno));
|
|
|
|
return MOSQ_ERR_UNKNOWN;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
return MOSQ_ERR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void bridge__cleanup(struct mosquitto_db *db, struct mosquitto *context)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for(i=0; i<db->bridge_count; i++){
|
|
|
|
if(db->bridges[i] == context){
|
|
|
|
db->bridges[i] = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
mosquitto__free(context->bridge->local_clientid);
|
|
|
|
context->bridge->local_clientid = NULL;
|
|
|
|
|
|
|
|
mosquitto__free(context->bridge->local_username);
|
|
|
|
context->bridge->local_username = NULL;
|
|
|
|
|
|
|
|
mosquitto__free(context->bridge->local_password);
|
|
|
|
context->bridge->local_password = NULL;
|
|
|
|
|
|
|
|
if(context->bridge->remote_clientid != context->id){
|
|
|
|
mosquitto__free(context->bridge->remote_clientid);
|
|
|
|
}
|
|
|
|
context->bridge->remote_clientid = NULL;
|
|
|
|
|
|
|
|
if(context->bridge->remote_username != context->username){
|
|
|
|
mosquitto__free(context->bridge->remote_username);
|
|
|
|
}
|
|
|
|
context->bridge->remote_username = NULL;
|
|
|
|
|
|
|
|
if(context->bridge->remote_password != context->password){
|
|
|
|
mosquitto__free(context->bridge->remote_password);
|
|
|
|
}
|
|
|
|
context->bridge->remote_password = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-05-16 14:24:24 +00:00
|
|
|
void bridge__packet_cleanup(struct mosquitto *context)
|
2014-05-07 22:27:00 +00:00
|
|
|
{
|
2015-04-19 21:10:59 +00:00
|
|
|
struct mosquitto__packet *packet;
|
2014-05-07 22:27:00 +00:00
|
|
|
if(!context) return;
|
|
|
|
|
2014-09-22 23:32:34 +00:00
|
|
|
if(context->current_out_packet){
|
2015-05-16 13:16:40 +00:00
|
|
|
packet__cleanup(context->current_out_packet);
|
2015-04-19 21:10:59 +00:00
|
|
|
mosquitto__free(context->current_out_packet);
|
2014-09-22 23:32:34 +00:00
|
|
|
context->current_out_packet = NULL;
|
|
|
|
}
|
2014-05-07 22:27:00 +00:00
|
|
|
while(context->out_packet){
|
2015-05-16 13:16:40 +00:00
|
|
|
packet__cleanup(context->out_packet);
|
2014-05-07 22:27:00 +00:00
|
|
|
packet = context->out_packet;
|
|
|
|
context->out_packet = context->out_packet->next;
|
2015-04-19 21:10:59 +00:00
|
|
|
mosquitto__free(packet);
|
2014-05-07 22:27:00 +00:00
|
|
|
}
|
2014-09-22 23:32:34 +00:00
|
|
|
context->out_packet = NULL;
|
|
|
|
context->out_packet_last = NULL;
|
2014-05-07 22:27:00 +00:00
|
|
|
|
2015-05-16 13:16:40 +00:00
|
|
|
packet__cleanup(&(context->in_packet));
|
2014-05-07 22:27:00 +00:00
|
|
|
}
|
|
|
|
|
2018-11-09 06:38:48 +00:00
|
|
|
static int rand_between(int base, int cap)
|
|
|
|
{
|
2019-02-27 14:15:31 +00:00
|
|
|
int r;
|
|
|
|
util__random_bytes(&r, sizeof(int));
|
|
|
|
return (r % (cap - base)) + base;
|
2018-11-09 06:38:48 +00:00
|
|
|
}
|
|
|
|
|
2019-02-27 13:52:19 +00:00
|
|
|
static void bridge__backoff_step(struct mosquitto *context)
|
2018-11-09 06:38:48 +00:00
|
|
|
{
|
|
|
|
struct mosquitto__bridge *bridge;
|
|
|
|
if(!context || !context->bridge) return;
|
|
|
|
|
|
|
|
bridge = context->bridge;
|
|
|
|
|
|
|
|
/* skip if not using backoff */
|
|
|
|
if(bridge->backoff_cap){
|
|
|
|
/* “Decorrelated Jitter” calculation, according to:
|
|
|
|
* https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/
|
|
|
|
*/
|
|
|
|
bridge->restart_timeout = rand_between(bridge->backoff_base, bridge->restart_timeout * 3);
|
|
|
|
if(bridge->restart_timeout > bridge->backoff_cap){
|
|
|
|
bridge->restart_timeout = bridge->backoff_cap;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void bridge__backoff_reset(struct mosquitto *context)
|
|
|
|
{
|
|
|
|
struct mosquitto__bridge *bridge;
|
|
|
|
if(!context || !context->bridge) return;
|
|
|
|
|
|
|
|
bridge = context->bridge;
|
|
|
|
|
|
|
|
/* skip if not using backoff */
|
|
|
|
if(bridge->backoff_cap){
|
|
|
|
bridge->restart_timeout = bridge->backoff_base;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-11 13:43:32 +00:00
|
|
|
void bridge_check(struct mosquitto_db *db)
|
|
|
|
{
|
|
|
|
static time_t last_check = 0;
|
|
|
|
time_t now;
|
|
|
|
struct mosquitto *context = NULL;
|
|
|
|
socklen_t len;
|
|
|
|
int i;
|
|
|
|
int rc;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
now = mosquitto_time();
|
|
|
|
|
|
|
|
if(now <= last_check) return;
|
|
|
|
|
|
|
|
for(i=0; i<db->bridge_count; i++){
|
|
|
|
if(!db->bridges[i]) continue;
|
|
|
|
|
|
|
|
context = db->bridges[i];
|
|
|
|
|
|
|
|
if(context->sock != INVALID_SOCKET){
|
|
|
|
mosquitto__check_keepalive(db, context);
|
|
|
|
|
|
|
|
/* Check for bridges that are not round robin and not currently
|
|
|
|
* connected to their primary broker. */
|
|
|
|
if(context->bridge->round_robin == false
|
|
|
|
&& context->bridge->cur_address != 0
|
|
|
|
&& context->bridge->primary_retry
|
|
|
|
&& now > context->bridge->primary_retry){
|
|
|
|
|
|
|
|
if(context->bridge->primary_retry_sock == INVALID_SOCKET){
|
|
|
|
rc = net__try_connect(context->bridge->addresses[0].address,
|
|
|
|
context->bridge->addresses[0].port,
|
|
|
|
&context->bridge->primary_retry_sock, NULL, false);
|
|
|
|
|
|
|
|
if(rc == 0){
|
|
|
|
COMPAT_CLOSE(context->bridge->primary_retry_sock);
|
|
|
|
context->bridge->primary_retry_sock = INVALID_SOCKET;
|
|
|
|
context->bridge->primary_retry = 0;
|
|
|
|
net__socket_close(db, context);
|
|
|
|
context->bridge->cur_address = 0;
|
|
|
|
}
|
|
|
|
}else{
|
|
|
|
len = sizeof(int);
|
|
|
|
if(!getsockopt(context->bridge->primary_retry_sock, SOL_SOCKET, SO_ERROR, (char *)&err, &len)){
|
|
|
|
if(err == 0){
|
|
|
|
COMPAT_CLOSE(context->bridge->primary_retry_sock);
|
|
|
|
context->bridge->primary_retry_sock = INVALID_SOCKET;
|
|
|
|
context->bridge->primary_retry = 0;
|
|
|
|
net__socket_close(db, context);
|
|
|
|
context->bridge->cur_address = context->bridge->address_count-1;
|
|
|
|
}else{
|
|
|
|
COMPAT_CLOSE(context->bridge->primary_retry_sock);
|
|
|
|
context->bridge->primary_retry_sock = INVALID_SOCKET;
|
|
|
|
context->bridge->primary_retry = now+5;
|
|
|
|
}
|
|
|
|
}else{
|
|
|
|
COMPAT_CLOSE(context->bridge->primary_retry_sock);
|
|
|
|
context->bridge->primary_retry_sock = INVALID_SOCKET;
|
|
|
|
context->bridge->primary_retry = now+5;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if(context->sock == INVALID_SOCKET){
|
|
|
|
/* Want to try to restart the bridge connection */
|
|
|
|
if(!context->bridge->restart_t){
|
|
|
|
context->bridge->restart_t = now+context->bridge->restart_timeout;
|
|
|
|
context->bridge->cur_address++;
|
|
|
|
if(context->bridge->cur_address == context->bridge->address_count){
|
|
|
|
context->bridge->cur_address = 0;
|
|
|
|
}
|
|
|
|
}else{
|
|
|
|
if((context->bridge->start_type == bst_lazy && context->bridge->lazy_reconnect)
|
|
|
|
|| (context->bridge->start_type == bst_automatic && now > context->bridge->restart_t)){
|
|
|
|
|
|
|
|
#if defined(__GLIBC__) && defined(WITH_ADNS)
|
|
|
|
if(context->adns){
|
|
|
|
/* Connection attempted, waiting on DNS lookup */
|
|
|
|
rc = gai_error(context->adns);
|
|
|
|
if(rc == EAI_INPROGRESS){
|
|
|
|
/* Just keep on waiting */
|
|
|
|
}else if(rc == 0){
|
|
|
|
rc = bridge__connect_step2(db, context);
|
|
|
|
if(rc == MOSQ_ERR_SUCCESS){
|
2020-02-15 14:49:53 +00:00
|
|
|
rc = mux__add_in(db, context);
|
2019-07-11 13:43:32 +00:00
|
|
|
if(context->current_out_packet){
|
2020-02-15 14:49:53 +00:00
|
|
|
rc = mux__add_out(db, context);
|
2019-07-11 13:43:32 +00:00
|
|
|
}
|
|
|
|
}else if(rc == MOSQ_ERR_CONN_PENDING){
|
|
|
|
context->bridge->restart_t = 0;
|
|
|
|
}else{
|
|
|
|
context->bridge->cur_address++;
|
|
|
|
if(context->bridge->cur_address == context->bridge->address_count){
|
|
|
|
context->bridge->cur_address = 0;
|
|
|
|
}
|
|
|
|
context->bridge->restart_t = 0;
|
|
|
|
}
|
|
|
|
}else{
|
|
|
|
/* Need to retry */
|
|
|
|
if(context->adns->ar_result){
|
|
|
|
freeaddrinfo(context->adns->ar_result);
|
|
|
|
}
|
|
|
|
mosquitto__free(context->adns);
|
|
|
|
context->adns = NULL;
|
|
|
|
context->bridge->restart_t = 0;
|
|
|
|
}
|
|
|
|
}else{
|
|
|
|
rc = bridge__connect_step1(db, context);
|
|
|
|
if(rc){
|
|
|
|
context->bridge->cur_address++;
|
|
|
|
if(context->bridge->cur_address == context->bridge->address_count){
|
|
|
|
context->bridge->cur_address = 0;
|
|
|
|
}
|
|
|
|
}else{
|
|
|
|
/* Short wait for ADNS lookup */
|
|
|
|
context->bridge->restart_t = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
{
|
|
|
|
rc = bridge__connect(db, context);
|
|
|
|
context->bridge->restart_t = 0;
|
|
|
|
if(rc == MOSQ_ERR_SUCCESS){
|
|
|
|
if(context->bridge->round_robin == false && context->bridge->cur_address != 0){
|
|
|
|
context->bridge->primary_retry = now + 5;
|
|
|
|
}
|
2020-02-15 14:49:53 +00:00
|
|
|
rc = mux__add_in(db, context);
|
2019-07-11 13:43:32 +00:00
|
|
|
if(context->current_out_packet){
|
2020-02-15 14:49:53 +00:00
|
|
|
rc = mux__add_out(db, context);
|
2019-07-11 13:43:32 +00:00
|
|
|
}
|
|
|
|
}else{
|
|
|
|
context->bridge->cur_address++;
|
|
|
|
if(context->bridge->cur_address == context->bridge->address_count){
|
|
|
|
context->bridge->cur_address = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-05-07 22:27:00 +00:00
|
|
|
#endif
|