mqttmosquittolibmosquitto

Why libmosquitto publlish callback is called before connection callback?


I have this program using the mosquitto MQTT library:

/*
  compile using:
  $ gcc -o libmosq libmosq.c -lmosquitto
*/
#include <stdio.h>
#include <mosquitto.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

void connection_callback(struct mosquitto* mosq, void *obj, int rc)
{
  if (rc) {
    printf("connection error: %d (%s)\n", rc, mosquitto_connack_string(rc));
  }
  else {
    printf("connection success\n");
  }
}

void publish_callback(struct mosquitto* mosq, void *obj, int mid)
{
  printf("this is the publish callback\n");
}

int main(int argc, char *argv[])
{
  struct mosquitto *mosq = NULL;
  
  mosquitto_lib_init();
  mosq = mosquitto_new(NULL, true, NULL);
  if(!mosq) {
     fprintf(stderr, "Error: Out of memory.\n");
     exit(1);
  }

  mosquitto_connect_callback_set(mosq, connection_callback);
  mosquitto_publish_callback_set(mosq, publish_callback);
  mosquitto_username_pw_set(mosq, "user1", "passwd1");
  
  int resultCode = mosquitto_connect(mosq, "localhost", 1883, 60);
  if (resultCode != MOSQ_ERR_SUCCESS) {
    fprintf(stderr, "error calling mosquitto_connect\n");
    exit(1);
  }

  int loop = mosquitto_loop_start(mosq);
  if(loop != MOSQ_ERR_SUCCESS){
    fprintf(stderr, "Unable to start loop: %i\n", loop);
    exit(1);
  }

  char topic[] = "/testtopic";
  char msg[] = "foobar";
  int publish = mosquitto_publish(mosq, NULL, topic, (int) strlen(msg), msg, 0, false);
  if(publish != MOSQ_ERR_SUCCESS){
    fprintf(stderr, "Unable to publish: %i\n", publish);
    exit(1);
  }

  // hang until control+C is done
  sleep(1000000);
}

Basically, it connects to a MQTT broker and publish a message on it.

If I run the program I get the following output:

this is the publish callback
connection success

This means that the publish callback is invoked before the connection callback, which from my point of view is counterintuitive (as the order of the events is the opposite: first the connection takes place, then the publish message is sent from my program to the MQTT broker).

How is this possible? Why is this counterintuitive behaviour happening? Thanks!


Solution

  • The important thing to realise is that mosquitto_connect() while blocking, doesn't block for the complete connection process, it only blocks until the CONNECT packet has been sent, it doesn't wait for the CONNACT packet to be returned, hence the on_connect callback.

    So it is entirely possible for all the code after the call to mosquitto_connect() to execute up to and including the call to publish before that CONNACT packet has been received. And given the on_publish callback for a QOS 0 message will be called as soon as the PUBLISH packet is sent (or possibly even when it is added to the outbound queue) because there is no confirmation this can also happen before the CONNACT is received.

    If you want to do this properly then all the publish code should be moved to the on_connect callback (or gated on a flag set in that callback)

    P.S. your topic REALLY shouldn't start with a leading /. While technically in spec, it is just storing up problems for later as it adds a null entry to the start of the topic tree which is going to break things like shared subscriptions when you get to them.