wolfSSL / wolfMQTT

wolfMQTT is a small, fast, portable MQTT client implementation, including support for TLS 1.3.
https://www.wolfssl.com
GNU General Public License v2.0
522 stars 156 forks source link

How to use this library? #401

Closed LubinLew closed 4 months ago

LubinLew commented 5 months ago

Hi team, I'm new to MQTT and I have a few questions about wolfMQTT.

infos

wolfMQTT version platform broker
v1.19.0 ubuntu 20.04 x64 ActiveMQ Artemis v2.33.0, TCP:1883
./autogen.sh 

./configure \
        --enable-static=yes \
        --enable-shared=no \
        --enable-v5=yes \
        --enable-tls=no 

questions

What the effect of MqttNet.read and MqttNet.write ? I want to build a client which only do subscribe. I don't know what's to do in the callback.

The program below MqttClient_NetConnect() and MqttClient_Subscribe() return 0, but I can‘t capture any packet(even SYN) on server side.

I tested the broker with MQTTX and it works fine.

#include <wolfmqtt/mqtt_client.h>

#define MQTT_BUF_SIZE        (1024)
#define MQTT_CMD_TIMEOUT_MS  (30000)
#define MQTT_CON_TIMEOUT_MS  (5000)
#define MQTT_KEEP_ALIVE_SEC  (60)
#define MQTT_CLEAN_SESSION   (1)

#define MQTT_BROKER_IP   "10.1.79.180"
#define MQTT_BROKER_PORT ((word16)1883)
#define MQTT_BROKER_USER "broker"
#define MQTT_BROKER_PASS "broker"

#define MQTT_CLIENT_ID "client1"

#define DBG(fmt, ...) printf("[%s:%d]"fmt"\n", __func__, __LINE__, ##__VA_ARGS__)

int _MqttMsgCb(MqttClient *client, MqttMessage *message, byte msg_new, byte msg_done)
{
    DBG();
    return MQTT_CODE_SUCCESS;
}

int _MqttNetConnectCb(void *context, const char* host, word16 port, int timeout_ms)
{
    DBG();
    return MQTT_CODE_SUCCESS;
}
int _MqttNetWriteCb(void *context, const byte* buf, int buf_len, int timeout_ms)
{
    DBG("bufsize: %d", buf_len);
    return MQTT_CODE_SUCCESS;
}

int _MqttNetReadCb(void *context, byte* buf, int buf_len, int timeout_ms)
{

    DBG("bufsize: %d", buf_len);
    return MQTT_CODE_SUCCESS;
}

int _MqttNetDisconnectCb(void *context)
{
    DBG();
    return MQTT_CODE_SUCCESS;
}

int main(int argc, char* argv[0])
{
    int rc = MQTT_CODE_SUCCESS;

    MqttClient    client;
    MqttNet       net;
    MqttConnect   connect;
    MqttSubscribe subscribe;
    MqttTopic     topics[1];

    byte tx_buf[MQTT_BUF_SIZE];
    byte rx_buf[MQTT_BUF_SIZE];

    int  cmd_timeout_ms = MQTT_CMD_TIMEOUT_MS;

    memset(&net, 0x00, sizeof(net));
    net.connect    = _MqttNetConnectCb;
    net.disconnect = _MqttNetDisconnectCb;
    net.read       = _MqttNetReadCb;
    net.write      = _MqttNetWriteCb;
    net.context    = NULL;

    rc = MqttClient_Init(&client, &net, _MqttMsgCb, tx_buf, MQTT_BUF_SIZE, rx_buf, MQTT_BUF_SIZE, cmd_timeout_ms);
    if (rc != MQTT_CODE_SUCCESS) {
        DBG("MqttClient_Init() falied, %s", MqttClient_ReturnCodeToString(rc));
        return -1;
    }

    /* Connect to broker */
    rc = MqttClient_NetConnect(&client, MQTT_BROKER_IP, MQTT_BROKER_PORT, MQTT_CON_TIMEOUT_MS, 0, NULL);
    if (rc != MQTT_CODE_SUCCESS) {
        DBG("MqttClient_NetConnect() falied, %s", MqttClient_ReturnCodeToString(rc));
        return -1;
    }

    /* Build connect packet */
    memset(&connect, 0x00, sizeof(connect));
    connect.keep_alive_sec = MQTT_KEEP_ALIVE_SEC;
    connect.clean_session  = MQTT_CLEAN_SESSION;
    connect.client_id      = MQTT_CLIENT_ID;
     /* Optional authentication */
     connect.username = MQTT_BROKER_USER;
     connect.password = MQTT_BROKER_PASS;

     /* Send Connect and wait for Connect Ack */
    rc = MqttClient_Connect(&client, &connect);
    if (rc != MQTT_CODE_SUCCESS) {
        DBG("MqttClient_Connect() falied, %s", MqttClient_ReturnCodeToString(rc));
        return -1;
    }

    /* Validate Connect Ack info */
    DBG("MQTT Connect Ack: Return Code %u, Session Present %d", \
        connect.ack.return_code, \
        (connect.ack.flags & MQTT_CONNECT_ACK_FLAG_SESSION_PRESENT) ? 1 : 0);
    if (connect.ack.return_code != 0) {
        return -1;
    }

    /* Subscribe Topic */
    memset(&subscribe, 0x00, sizeof(subscribe));
    memset(&topics,    0x00, sizeof(topics));

    topics[0].topic_filter = "hello";
    topics[0].qos          = MQTT_QOS_1;

    subscribe.packet_id   = 0;
    subscribe.topic_count = 1;
    subscribe.topics      = topics;
    rc = MqttClient_Subscribe(&client, &subscribe);
    DBG("MQTT Subscribe: %s (%d)", MqttClient_ReturnCodeToString(rc), rc);
    if (rc != MQTT_CODE_SUCCESS) {
        DBG("MqttClient_Subscribe() falied, %s(%d)", MqttClient_ReturnCodeToString(rc), rc);
        return -1;
    }

    /* show subscribe results */
    for (int i = 0; i < subscribe.topic_count; i++) {
        MqttTopic *topic = &subscribe.topics[i];
        DBG("  Topic %s, Qos %u, Return Code %u",
            topic->topic_filter,
            topic->qos, topic->return_code);
    }

    do {
        /* Try and read packet */
        rc = MqttClient_WaitMessage(&client, cmd_timeout_ms);
        if (rc != MQTT_CODE_SUCCESS) {
            DBG("MqttClient_WaitMessage() falied, %s(%d)", MqttClient_ReturnCodeToString(rc), rc);
            return -1;
        }

    } while(1);

    return 0;
}
embhorn commented 5 months ago

Hi @LubinLew

Thanks for your interest in the wolfMQTT project.

What the effect of MqttNet.read and MqttNet.write ?

Those are the IO interface function pointers in the network layer abstraction object. This provides flexibility for the library to use any medium for transmitting IO. They will not be used directly by the application for MQTT messaging.

If you are running the client in Ubuntu, try the example/mqttclient demo https://github.com/wolfSSL/wolfMQTT/tree/master/examples/mqttclient

./examples/mqttclient/mqttclient -h <broker address>

Can you tell us a bit about your project using wolfMQTT? Feel free to email support@wolfssl.com for a more private format.

Thanks, Eric - wolfSSL Support

LubinLew commented 5 months ago

@embhorn

Thanks for your answer. I know how this library works. It is a low-level library. But what I want is a high-level API, Hiding the details of the potocol. I don't want to create socket myself and read/write to the socket directly. The examples are great but too many macro conditions. I think the examples should be packaging to a high-level API works as below.

int subscribe_callback(msg)
{ // read msg
}

int main()
{
    mqtt_init(version=V5, io_mode=BLOCK, ...)
    mqtt_connect(host, port, ...)
    mqtt_subscribe(topic_list, subscribe_callback, ...)

    mqtt_loop_run(...);
}
embhorn commented 5 months ago

Hi @LubinLew

That's the typical tradeoff - functionality VS complexity. The wolfMQTT API is not significantly more complex than what you shared: Here is a simple client subscribe: https://github.com/wolfSSL/wolfMQTT/blob/master/examples/pub-sub/mqtt-sub.c

We are happy to help answer any questions you might have.

LubinLew commented 4 months ago

Thanks for the help.