eclipse-mosquitto / mosquitto

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

Cannot connect to an AWS endpoint using TLS #2264

Open josecgon opened 3 years ago

josecgon commented 3 years ago

Hi!

I'm trying to connect to an AWS endpoing using TLS and your library.

I have tried with this command: mosquitto_pub --cafile root-CA.crt --cert cert.pem --key private.key -d -h amazonendpoint -t test -m "Hello Im a mosquitto"

And it works with no problem, it gets connected, it publishes the message and I can see the message in the AWS broker.

After doing that, I started writting a C++ class using the mosquitto library to do the same thing:

#include <mosquitto.h>
#include <cstdio>
#include <cstring>
#include <string>
#include <cstdint>
#include <chrono>
#include <unistd.h>

void on_connect(struct mosquitto *mosq, void *obj, int reason_code)
{
    printf("on_connect: %s\n", mosquitto_connack_string(reason_code));
    if(reason_code != 0)
    {
        mosquitto_disconnect(mosq);
    }
}

void my_disconnect_callback(struct mosquitto *mosq, void *obj, int rc)
{
    (void)(mosq);
    (void)(obj);
    (void)(rc);

    if(rc == 0) { printf("Disconnected!\n"); }
}

void on_publish(struct mosquitto *mosq, void *obj, int mid)
{
    printf("Message with mid %d has been published.\n", mid);
}

void my_log_callback(struct mosquitto *mosq, void *obj, int level, const char *str)
{
    (void)(mosq);
    (void)(obj);
    (void)(level);

    printf("%s\n", str);
}

class MosquittoPublisher
{
public:
    bool connect(std::string const& p_host, uint16_t p_port, std::string const& p_CAPath = "", std::string const& p_certPath = "", std::string const& p_keyPath = "")
    {
        // Initialize.
        if(mosquitto_lib_init() != MOSQ_ERR_SUCCESS) { return false; }

        std::string client_id = "client-001";
        m_handler = mosquitto_new(client_id.c_str(), true, 0);

        if (!m_handler) { return false; }

        // Callbacks.
        mosquitto_connect_callback_set(m_handler, on_connect);
        mosquitto_publish_callback_set(m_handler, on_publish);

        // Set options.
        if(!p_CAPath.empty())
        {
            if(mosquitto_tls_set(m_handler, p_CAPath.c_str(), nullptr, p_certPath.c_str(), p_keyPath.c_str(), nullptr) != MOSQ_ERR_SUCCESS) { return false; }
            if(mosquitto_int_option(m_handler, MOSQ_OPT_TLS_USE_OS_CERTS, 1) != MOSQ_ERR_SUCCESS) { return false; }
        }

        // Connect
        std::chrono::seconds l_keepalive{10U};
        if(mosquitto_connect(m_handler, p_host.c_str(), p_port, l_keepalive.count()) != MOSQ_ERR_SUCCESS) { return false; }

        return mosquitto_loop_start(m_handler) == MOSQ_ERR_SUCCESS;
    }

    bool disconnect()
    {
        if(mosquitto_loop_stop(m_handler, true) != MOSQ_ERR_SUCCESS) { return false; }

        mosquitto_destroy(m_handler);

        return mosquitto_lib_cleanup() == MOSQ_ERR_SUCCESS;
    }

    bool publish(std::string const& p_topic, std::string const& p_msg)
    {
        int l_qos = 2;
        bool l_retain = false;

        int res = mosquitto_publish_v5(m_handler, nullptr, p_topic.c_str(), p_msg.size(), p_msg.c_str(), l_qos, l_retain, nullptr);

        return res == MOSQ_ERR_SUCCESS;
    }
private:
    mosquitto *m_handler;
};

int main()
{
    MosquittoPublisher publisher;

    std::string const mqttEndpoint = "amazonendpoint";
    uint16_t port = 8883U;
    std::string const ca = "root-CA.crt";
    std::string const cert = "cert.pem";
    std::string const key = "private.key";

    printf("Connecting...\n");

    if(!publisher.connect(mqttEndpoint, port, ca, cert, key))
    {
        printf("Error connecting\n");
        return 1;
    }

    uint16_t times = 10;
    std::string const& topic = "test";
    std::string const& msg = "Hello";

    printf("Publishing...\n");

    while(times)
    {
        printf("------------------------------------\n");
        if(!publisher.publish(topic, msg)) { printf("Error publishing %u\n", times); }
        printf("------------------------------------\n");
        --times;

        ::sleep(10u);
    }

    printf("Disconnecting...\n");

    if(!publisher.disconnect())
    {
        printf("Error disconnecting\n");
        return 1;
    }

    printf("Finished!\n");

    return 0;

It seems like it gets connected but keeps on trying to reconect (I don't knwo why), and I cant see the published messages in the AWS broker.

I attach the logs output:

Connecting...
Client client-001 sending CONNECT
Waiting to be actually connected!
Client client-001 received CONNACK (0)
on_connect: Connection Accepted.
Publishing...
------------------------------------
Client client-001 sending PUBLISH (d0, q2, r0, m1, 'test', ... (5 bytes))
Result for publish: 0
------------------------------------
Client client-001 sending CONNECT
Client client-001 received CONNACK (0)
on_connect: Connection Accepted.
Client client-001 sending PUBLISH (d1, q2, r0, m1, 'test', ... (5 bytes))
Client client-001 sending CONNECT
Client client-001 received CONNACK (0)
on_connect: Connection Accepted.
Client client-001 sending PUBLISH (d1, q2, r0, m1, 'test', ... (5 bytes))
Client client-001 sending CONNECT
Client client-001 received CONNACK (0)
on_connect: Connection Accepted.
Client client-001 sending PUBLISH (d1, q2, r0, m1, 'test', ... (5 bytes))
Client client-001 sending CONNECT
Client client-001 received CONNACK (0)
on_connect: Connection Accepted.
Client client-001 sending PUBLISH (d1, q2, r0, m1, 'test', ... (5 bytes))
Client client-001 sending CONNECT
Client client-001 received CONNACK (0)
on_connect: Connection Accepted.
Client client-001 sending PUBLISH (d1, q2, r0, m1, 'test', ... (5 bytes))
------------------------------------
Result for publish: 4
Error publishing 9
------------------------------------
Client client-001 sending CONNECT
Client client-001 received CONNACK (0)
on_connect: Connection Accepted.
Client client-001 sending PUBLISH (d1, q2, r0, m1, 'test', ... (5 bytes))
Client client-001 sending PUBLISH (d1, q2, r0, m2, 'test', ... (5 bytes))

I also tried this same piece of code with a localhost broker, and it works with no problem (I have another C++ code to subscribe to a topic, and I see the sent message there).

Am I missing some configuration?

Thank you very much!

abiliojr commented 3 years ago

I am not sure if you're talking about the MQTT service provided by AWS IoT Core (or something similar). If that is the case, they don't support QoS 2, and maybe they are disconnecting your client as a result.

Could you try publishing with QoS 0 or 1?