eclipse-paho / paho.mqtt.c

An Eclipse Paho C client library for MQTT for Windows, Linux and MacOS. API documentation: https://eclipse.github.io/paho.mqtt.c/
https://eclipse.org/paho
Other
1.97k stars 1.1k forks source link

A segment error occurred after the conn_lost() was executed #1507

Open okyihu opened 2 months ago

okyihu commented 2 months ago

HI,SIR A segment fault occurred after the conn_lost() was executed , once I called MQTTClient_connect(client, &conn_opts) in conn_lost() function , the programe could re-connect the broker, but immediately a segment fault occured , why, what am I doing wrong. more information : just now I re-compile this program with gcc and run it on unbuntu desktop system , this program run correctly ,no segment fault . so strange.

My code is :

include "stdlib.h"

include "string.h"

include "unistd.h"

include "MQTTClient.h"

include "mqtt_req_proc.h"

// Enable or disable SSL/TLS connection (1 for SSL/TLS, 0 for TCP)

define USE_SSL 0

if USE_SSL

define ADDRESS "ssl://broker.emqx.io:8883"

else

// #define ADDRESS "tcp://47.106.203.236:1883"

define ADDRESS "tcp://112.74.85.63:1883"

// #define ADDRESS "b187a1e0.ala.dedicated.aliyun.emqxcloud.cn:1883"

endif

define USERNAME "steve"

define PASSWORD "Zrr_4410693"

define CLIENTID "c-client"

define QOS 0

define PUB_TOPIC "192.168.1.103_internal_service"

define SUB_TOPIC "192.168.1.103_public_service"

define TIMEOUT 10000L

MQTTClient_SSLOptions configureSSLOptions() { MQTTClient_SSLOptions ssl_opts = MQTTClient_SSLOptions_initializer; ssl_opts.enableServerCertAuth = 1; // ssl_opts.trustStore = CA_CERTIFICATE_FILE; return ssl_opts; }

void publish(MQTTClient client, char topic, char payload) { MQTTClient_message message = MQTTClient_message_initializer; message.payload = payload; message.payloadlen = strlen(payload); message.qos = QOS; message.retained = 1; MQTTClient_deliveryToken token; MQTTClient_publishMessage(client, topic, &message, &token); MQTTClient_waitForCompletion(client, token, TIMEOUT); printf("Send %s to topic %s \n", payload, PUB_TOPIC); } int request_completed = 0; int on_message(void context, char topicName, int topicLen, MQTTClient_message message) { char payload = message->payload; // printf("Received %s from %s topic \n", payload, topicName);

    request_completed = 1;
    MQTTClient_freeMessage(&message);
    MQTTClient_free(topicName);
    return 1;

}

void conn_lost(void context, char cause) { printf("\nConnection lost\n"); printf(" cause: %s\n", cause); int rc; MQTTClient client = (MQTTClient )context;

MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer;
     conn_opts.username = USERNAME;
    conn_opts.password = PASSWORD;
conn_opts.keepAliveInterval = 10;
conn_opts.cleansession = 1;

while (1)
{
            rc= MQTTClient_connect(client, &conn_opts);
    if (rc == MQTTCLIENT_SUCCESS)
    {
        printf("Reconnection Successful\n");
        break;
    }
    else
    {
        printf("Failed to connect, return code %d\n", rc);
    }
    sleep(10);
}

while (1)
{
    if (MQTTClient_subscribe(client, SUB_TOPIC, QOS) == MQTTCLIENT_SUCCESS)
    {
        printf("Resubscribe Successful\n");
        break;
    }
    else
    {
        printf("Resubscribe Failure\n");
    }
    sleep(1);
}

}

int main(int argc, char *argv[]) { int rc; MQTTClient client;

     MQTTClient_create(&client, ADDRESS, CLIENTID, MQTTCLIENT_PERSISTENCE_NONE, NULL);

    MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer;
    conn_opts.username = USERNAME;
    conn_opts.password = PASSWORD;

if USE_SSL

    MQTTClient_SSLOptions ssl_opts = configureSSLOptions();
    conn_opts.ssl = &ssl_opts;

endif

    conn_opts.keepAliveInterval = 10;
    conn_opts.cleansession = 1;
    MQTTClient_setCallbacks(client, client, conn_lost, on_message, NULL);
    if ((rc = MQTTClient_connect(client, &conn_opts)) != MQTTCLIENT_SUCCESS)
    {
            printf("Failed to connect, return code %d\n", rc);
            exit(-1);

    }
    else
    {
            printf("Connected to MQTT Broker!\n");
    }
    // subscribe topic
    MQTTClient_subscribe(client, SUB_TOPIC, QOS);

    while (1)
    {
            if (request_completed)
            {
                    request_completed = 0;
                    publish(client, PUB_TOPIC, res);  
            }
    }
    MQTTClient_unsubscribe(client, TOPIC);
    MQTTClient_disconnect(client, TIMEOUT);
    MQTTClient_destroy(&client);
    return rc;

}

icraggs commented 2 months ago

The first thing is that the cause field in the connectionLost callback can be null, so it should be checked for that before printing.

Next, the program should not spend a long time in callbacks, which means no sleeping. The only API call allowed in connectionLost is connect - no subscribe or any other.

SeaAndSand commented 1 month ago

"The only API call allowed in connectionLost is connect。" How should understand this sentence? In fact, I called B client's publish function in A client's connlost. When A client triggers connlost, it crashes very easily.

[19:13:25.384]Program received signal SIGSEGV, Segmentation fault. [19:13:25.384]malloc_consolidate (av=av@entry=0x75b00010) at malloc.c:4141 [19:13:25.384]4141    malloc.c: No such file or directory. 19:13:29.134 bt [19:13:29.134]#0  malloc_consolidate (av=av@entry=0x75b00010) at malloc.c:4141 [19:13:29.134]#1  0x76edd538 in _int_free (av=0x75b00010, p=, have_lock=0) at malloc.c:4049 [19:13:29.134]#2  0x76e757c4 in MQTTProperties_free () from /usr/lib/libpaho-mqtt3c.so.1 [19:13:29.134]Backtrace stopped: previous frame identical to this frame (corrupt stack?)