eclipse / mosquitto

Eclipse Mosquitto - An open source MQTT broker
https://mosquitto.org
Other
8.93k stars 2.37k forks source link

Unable to reconnect to a different broker via 1883 in runtime, mosquitto_username_pw_set always causing CONNACK(5), duplicated CONNECT message from client #1471

Open VasyaKodovich opened 4 years ago

VasyaKodovich commented 4 years ago

Hello! I was looking to make my mosquitto client be able to switch between different brokers in runtime. The idea is that the address is given, as well as username and password and user connects to a different broker in runtime if need be. I am using broker run on a local machine and a remote one in the network to switch between them. What I stumbled upon is that when I try to connect to a different broker in runtime, client falls into a reconnection loop (which was similar to duplicate ID, but my IDs are always random). Remote broker always refuses connections (CONNACK 5) when local doesn't. Client also apparently sends out CONNECT message twice.

I am not using SSL/TLS and connect through 1883, which remote broker accepts connections from.

I built a minimal example that reproduces the problem. I figured out through removing lines which set parameters to mosquitto instance, is that mosquitto_username_pw_set() invokes refusal from broker - CONNACK(5). When this function is removed, connectoin is accepted CONNACK(0), but CONNECT is still going off twice.

The question is why removing this particular function allows connection to go well and why CONNECT is sent twice at all?

Here's what I've checked and tried:

The only thing that keeps happening is that mosquitto_username_pw_set() invokes CONNACK(5) on remote broker no matter what is put there, and when I remove mosquitto_username_pw_set() from the code entirely, the client connects just fine (CONNACK(0)), but CONNECT is still going off twice, with no CONNACK(5).

I'm not sure why this behavior occurs. Maybe there has to be a specific kind of procedure that is required to reconnect to another broker in runtime?

I'm open to any feedback and clarification requests!

Here's my minimal example: I am building on kubuntu 17.04 (using mosquitto 1.6.7) For network loop I just use mosquitto_loop_start().

#include <iostream>
#include <mosquitto.h>
#include <time.h>
#include <unistd.h>

using namespace std;

struct mosquitto *g_mosq_ext = NULL;

void log_callback(struct mosquitto *mosq, void *userdata, int level, const char *str)
{
    struct timespec ts;

    printf("[%s] %lu.%03lu %s\n", __FUNCTION__, ts.tv_sec, ts.tv_nsec/1000000, str);
}

void connect_callback(struct mosquitto *mosq, void *obj, int rc)
{
    printf("[%s] %s %d \n", __FUNCTION__, mosquitto_connack_string(rc), rc);

    //mosquitto_subscribe(g_mosq_ext, NULL, "test/1", 2);
    //mosquitto_subscribe(g_mosq_ext, NULL, "test/2",2);
}

void disconnect_callback(struct mosquitto *, void *, int reason)
{
    struct timespec ts;

    printf("[%s] %s %d \n", __FUNCTION__, mosquitto_reason_string(reason), reason);
}

int main(int argc, char *argv[])
{

    int num;

    mosquitto_lib_init();

    int*major = NULL;
    int*minor = NULL;
    int*rev = NULL;
    char version[256];
    int res;
    res = mosquitto_lib_version(major,minor,rev);
    sprintf(version,"mosq version: %d",res);
    printf("%s \n",version);

    bool clean_session = true;

    g_mosq_ext = mosquitto_new(NULL, clean_session, NULL);
    if (!g_mosq_ext) {
        fprintf(stderr, "Error: Out of memory.\n");
        return 1;
    }

    while(true)
    {
        num = getchar();
        if(num == '1')
        {
            printf("Connecting to localhost \n");
            int rc;
            do {
                mosquitto_disconnect(g_mosq_ext);

                //Removing this line from anywhere in the code
                //makes client connect to broker just fine
                //Otherwise, broker refuses connections
                rc = mosquitto_username_pw_set(g_mosq_ext, "guest", "guest");
                switch(rc)
                {
                case MOSQ_ERR_SUCCESS:
                {
                    printf("[%s] localhost: username password set %d \n", __FUNCTION__, MOSQ_ERR_SUCCESS);
                            break;
                }
                default:
                {
                    printf("[%s] localhost: %s \n", __FUNCTION__, mosquitto_strerror(rc));
                    break;
                }
                }

                mosquitto_log_callback_set(g_mosq_ext,log_callback);
                mosquitto_connect_callback_set(g_mosq_ext,connect_callback);
                //mosquitto_disconnect_callback_set(g_mosq_ext,disconnect_callback);

                rc = NULL;

                rc = mosquitto_connect(g_mosq_ext, "localhost", 1883, true);

                printf("[%s] localhost: %s rc=%d\n",
                       __FUNCTION__,
                       mosquitto_strerror(rc),
                       rc);
                usleep(1000);
            } while (rc != MOSQ_ERR_SUCCESS);

            mosquitto_loop_start(g_mosq_ext);
        }
        if(num == '2')
        {
            printf("Connecting to 192.168.1.75 \n");
            int rc;
            do {
                mosquitto_disconnect(g_mosq_ext);

                //Removing this line from anywhere in the code
                //makes client connect to broker just fine
                //Otherwise, broker refuses connections
                rc= mosquitto_username_pw_set(g_mosq_ext, "guest", "guest");

                switch(rc)
                {
                case MOSQ_ERR_SUCCESS:
                {
                    printf("[%s] 192.168.1.75: username password set %d \n", __FUNCTION__, MOSQ_ERR_SUCCESS);
                            break;
                }
                default:
                {
                    printf("[%s] 192.168.1.75: %s \n", __FUNCTION__, mosquitto_strerror(rc));
                    break;
                }
                }

                mosquitto_log_callback_set(g_mosq_ext,log_callback);
                mosquitto_connect_callback_set(g_mosq_ext,connect_callback);
                //mosquitto_disconnect_callback_set(g_mosq_ext,disconnect_callback);

                rc = NULL;

                rc = mosquitto_connect(g_mosq_ext, "192.168.1.75", 1883, true);
                printf("[%s] 192.168.1.75: %s rc=%d\n",
                       __FUNCTION__,
                       mosquitto_strerror(rc),
                       rc);
                printf("sleep 1 sec \n");
                usleep(1000);
                printf("sleep done \n");
            } while (rc != MOSQ_ERR_SUCCESS);

            mosquitto_loop_start(g_mosq_ext);
        }
    }

    return 0;
}
FacundoNieto commented 3 years ago

Hi! I wonder why you don't use a client ID for de mosquitto_new() function? I'm new in mqtt protocol, and I have to create a C client with any C library, and at the time I'm guiding myself with this video: https://www.youtube.com/watch?v=K6Q1Sd9edCw&list=LL&index=1 and here an integer ID is used in mosquitto_new() (and it works)

ralight commented 3 years ago

@FacundoNieto There's often no need to specify a client id. If you're using persistent clients you must provide a client id, but otherwise usually not.