How to write a C MQTT client using Mosquitto

Introduction

How to write a C MQTT client using Mosquitto The 2018 version, based upon this excellent post by Kevin Boone:

Writing an MQTT client C for ActiveMQ from the ground up

The article above is a good and easy starting point, but it hasn’t been updated for 2 years so when you run it with the latest version of Mosquitto, it doesn’t work – and it’s a bit hacky (using “sleep” to avoid a concurrency problem).

So I analyzed the latest mosquitto_pub code from mosquitto repository itself to see how it’s working, and this article is the result.

What’s changed

  • There’s a queue inside mosquitto, `mosquitto_loop` must be called for it to be processed. Alternatively, you can also use the `mosquitto_loop_start` and `mosquitto_loop_stop`
  • I added asynchronous (callback) processing to wait for calls to complete, instead of the ole’ sleep function
  • It’s 2018! Everyone is adopting HTTPS. Accordingly, your MQTT traffic shouldn’t be left bare for all to see! Let’s use TLS to encrypt the traffic

The code

How to use callback

I want to publish just once message, so my flow is the following

  • On connect complete -> publish a message
  • On publish complete -> start to disconnect
  • On disconnect complete -> exit the loop and return control to the main thread. If you don’t wait for this, data may not even get sent!

To do this, I set up 3 “hooks” (callback function), like this

mosquitto_connect_callback_set(mosq, my_connect_callback);

mosquitto_disconnect_callback_set(mosq, my_disconnect_callback);

mosquitto_publish_callback_set(mosq, my_publish_callback);
And then write the callback functions to execute my flow
void my_connect_callback(struct mosquitto *mosq, void *obj, int result)
{
    int rc = MOSQ_ERR_SUCCESS;
    if(!result){
        printf("Sending message...\n");
        rc = mosquitto_publish(mosq, &mid_sent, MQTT_TOPIC, strlen(text), text, qos, retain);
        if(rc){
            switch(rc){
                case MOSQ_ERR_INVAL:
                    fprintf(stderr, "Error: Invalid input. Does your topic contain '+' or '#'?\n");
                    break;
                case MOSQ_ERR_NOMEM:
                    fprintf(stderr, "Error: Out of memory when trying to publish message.\n");
                    break;
                case MOSQ_ERR_NO_CONN:
                    fprintf(stderr, "Error: Client not connected when trying to publish.\n");
                    break;
                case MOSQ_ERR_PROTOCOL:
                    fprintf(stderr, "Error: Protocol error when communicating with broker.\n");
                    break;
                case MOSQ_ERR_PAYLOAD_SIZE:
                    fprintf(stderr, "Error: Message payload is too large.\n");
                    break;
            }
            mosquitto_disconnect(mosq);
        }
    } else {
        if(result){
            fprintf(stderr, "%s\n", mosquitto_connack_string(result));
        }
    }
}

void my_disconnect_callback(struct mosquitto *mosq, void *obj, int rc)
{
    printf("Disconnected!\n");
    connected = false;
}

void my_publish_callback(struct mosquitto *mosq, void *obj, int mid)
{
    printf("Published!\n");
    if(disconnect_sent == false){
        mosquitto_disconnect(mosq);
        disconnect_sent = true;
    }
}

How to process the queue with mosquitto_loop

In the main trunk of your code, do this

int rc;
do {
//network동작 끝나기 전에 모스키토 동작을 막기위해 잠깐 딜레이가 필요
  rc = mosquitto_loop(mosq, -1, 1);
} while (rc == MOSQ_ERR_SUCCESS && connected);

How to add TLS to the connection process

Before connecting, set TLS options with mosquitto_tls_set

mosquitto_username_pw_set(mosq, MQTT_USERNAME, MQTT_PASSWORD);
mosquitto_tls_set(mosq, "ca-cert.pem", NULL, NULL, NULL, NULL);
int ret = mosquitto_connect(mosq, MQTT_HOSTNAME, MQTT_PORT, 0);

Complete publish – subscribe sample

Available at https://github.com/thanhphu/mosquitto-sample. Happy cloning!

 

Resolving ClassCastException using ADT’s visual designer

Recently when maintaining an old android program I encountered a strange exception when attempting to view a layout in visual designer:

error!
ClassCastException: com.android.layoutlib.bridge.MockView cannot be cast to android.view.ViewGroup
Exception details are logged in Window > Show View > Error Log
The following classes could not be found:
- TableLayout (Change to android.widget.TableLayout, Fix Build Path, Edit XML)

Searching stack overflow and Android developers, I found this could be caused by using an old version SDK for an application targeted to a newer version, with new elements. But TableLayout was available since API level 1, and I’m using the latest version of the development tools, so these could not be the problem. The temporary fix was to remove the table layout and replace it with something else.

Today I have the time to compare my code to Android’s example. It turned out to be one tiny little thing that messed the designer up:

<TableLayout

			android:layout_width="fill_parent"
			android:layout_height="wrap_content"
			android:orientation="vertical"
			android:stretchColumns="">

There, one attribute doesn’t match the schema (it should be 0 or 1, not empty “”), and the designer will refuse to load. Worse still, the code will compile but will crash at run-time for the same reason.

My recommendation? Android team should note this case and provide better details on the loading exception in upcoming versions. “ClassCastException” is not really helpful!

 

Debugging the Galaxy Tab 10.1

When I first plug the tab in, my computer automatically install all the drivers, but it won’t show up in ADB and Eclipse. I did a little searching but people were pointing me to Samsung’s developer page with a USB driver for phones. Sadly that driver just isn’t for the tab, a search on their site found nothing interesting either. It looks like Samsung can’t keep information for developers updated while they are still battling legal issues around the tab.

Fortunately, I remembered I haven’t turned debugging mode on the tab on, so I went ahead and do it, this time… Success!

Where to turn on debugging

Device in Eclipse

Now I’m installing Android 3.1 platform and looking forward for a happy time debugging 🙂

Android 2.3

Has been released with a new set of tools. ADT skipped from version 0.9.9 to 8.0.0, and you will get this:

error: Multiple substitutions specified in non-positional format; did you mean to add the formatted=”false” attribute

If you had something like

<string name="loading">my key %s is associated with a value of %s</string>

The reason is, Android now enforce substitution parameter order, you have to made the above.

<string name="loading">my key %1$s is associated with a value of %2$s</string>

This change is possibly due to internationalization problems, in some languages the second parameter should appear first.

Things to note when developing on Android

Putting files onto the emulator

There are two: using adb (see below) and through file explorer (in ADT)

File explorer

Oh, and one file at a time only

Update music

Maybe on real phones, there’s supposed to be an Intent to process your music files when they are copied over to the device. The emulator doesn’t do this, so any music you threw in using the file explorer won’t show up in your “Music” or “Media” application (depends on the version).

You have to start developer tools > Media scanner to scan for music files

Media scanner

Controlling the emulator

There’s more to the emulator than what your can control with ADT. ADT is quite nice to use, but it only let you:

  • Simulate incoming SMS and call
  • Simulate geolocation
  • View / terminate processes
  • Manage files

Actually you can use several tools that come with the SDK and talk to the emulator itself to get more out of it. To connect to the emulator, telnet to local host with the port as the emulator’s number (5554, 5556 and so on). These numbers can be used as phone numbers so the emulators can call / SMS each other, but not receive calls from a connected phone.

The list of commands can be found here

Setting the battery to full

There’s a tool called ADB (android debug bridge) that can install packages and put files on to the sdcard. ADB is used internally by ADT itself, but you can use it to manually control the emulator, doing things like setting the telnet listening port, view system log (logcat) or issuing shell commands on the device (alternatively you can do this with Dev tools inside the phone)

Solving errors that appear to came out of nowhere

In addition to usual Java errors like forgetting to add imports, put some files in the wrong folder… Sometimes when you import a project from somewhere (like… from Google’s examples :p), the project turns all red (indicating error), you checked the import, they are there, you checked the classes, they are there, you cleaned the project and rebuild as a routine habit when things go wrong with Android, the errors are still there!

Check your project’s properties (default.properties) to see if the target is right. For example, if you are using 2.2 platform, it should be target=android-8 for 2.1 it should be android-7 and so on… assumed you installed the platform with the AVD manager.

Also, when you change API level requirement in AndroidManifest.xml, the project doesn’t seem to build right and it just can’t run, saying something like “Android requires .class compatibility set to 5.0. Please fix project properties”

You know you need to use this

ADT's magic wand