--- title: "Embed NanoMQTT in C" source_url: https://dev.digicert.com/trustcore-sdk/nanomqtt/embed-nanomqtt-in-c.html --- This topic shows the *smallest* synchronous flow needed to connect, subscribe, publish, and service the receive loop in a single-threaded application. ## Before you begin - If you plan to use TLS, create and negotiate a NanoSSL connection: - Create the NanoSSL handle with `SSL_connect()`. - Complete the handshake with `SSL_negotiateConnection()`. - Bind the SSL handle to the MQTT connection with `MQTT_setTransportSSL(connInst, sslConnInst)` *before* you call `MQTT_negotiateConnection()`. - Examples assume sockets are **non-blocking** so a single event loop can multiplex TCP/TLS traffic. Build with the asynchronous client enabled (`__ENABLE_MQTT_ASYNC_CLIENT__` or `--async` in the build script) and open your sockets in non-blocking mode. Blocking sockets work, but they prevent multiplexing. - A reachable MQTT 5 or 3.1.1 broker (port **1883** for TCP, **8883** for TLS). ## Minimal synchronous example ```c #include "mqtt_client.h" #include "ssl_api.h" /* Needed only for TLS */ static void on_publish(const MqttPublishRx *msg, void *arg) { /* Handle inbound publishes here */ } /* ---------- 1. Allocate an MQTT connection (stores Client-ID) */ MqttConnectionHandle conn = MQTT_connect(MQTT_V5, "device-123", strlen("device-123")); /* ---------- 2. Bind a transport ----------------------------------------- */ /* (a) Clear-text TCP: */ /* int socketFd = ... ; MQTT_setTransportTCP(conn, socketFd); */ /* (b) TLS transport (shown): */ MQTT_setTransportSSL(conn, sslConnInst); /* sslConnInst = NanoSSL handle */ /* Transport may be bound at any point *before* MQTT_negotiateConnection. */ /* ---------- 3. Register control-packet handlers ------------------------- */ MqttPacketHandlers h = { .publishHandler = on_publish }; MQTT_setControlPacketHandlers(conn, &h); /* ---------- 4. Negotiate the session (CONNECT / CONNACK) --------------- */ MqttConnectOptions opts = { .cleanStart = true, .keepAliveInterval = 30, /* seconds; 0 disables keep-alive */ }; if (MQTT_negotiateConnection(conn, &opts) < 0) { /* handle error */ } /* ---------- 5. Subscribe and publish ------------------------------------ */ MqttSubscribeTopic subTopic = { .pTopic = "alerts/#", .topicLen = 8, .qos = 1 }; MqttSubscribeOptions subOpts = { 0 }; /* no extra options */ MQTT_subscribe(conn, &subTopic, 1, &subOpts); MqttPublishOptions pubOpts = { .qos = 0, .retain = false }; const char payload[] = "Hello NanoMQTT"; MQTT_publish(conn, &pubOpts, "telemetry", 9, payload, sizeof payload - 1); /* ---------- 6. Main receive loop ---------------------------------------- */ while (running) { if (MQTT_recv(conn) < 0) { /* dispatches callbacks */ /* handle error or reconnect */ } } /* ---------- 7. Graceful shutdown --------------------------------------- */ MQTT_disconnect(conn, NULL); /* default DISCONNECT */ MQTT_closeConnection(conn); /* free all connection memory */ ``` ### How it works | Step | Call | Purpose | | --- | --- | --- | | 1 | `MQTT_connect` | Allocate the client state machine and store the Client-ID. | | 2 | `MQTT_setTransportSSL` / `MQTT_setTransportTCP` | Bind TLS or clear-text transport *before* negotiation. | | 3 | `MQTT_setControlPacketHandlers` | Register application callbacks (publish, disconnect, etc.). | | 4 | `MQTT_negotiateConnection` | Send CONNECT, wait for CONNACK, apply keep-alive. | | 5 | `MQTT_subscribe` / `MQTT_publish` | Add subscriptions or transmit payloads. | | 6 | `MQTT_recv` | Drive the synchronous loop; dispatch callbacks. | | 7 | `MQTT_disconnect` / `MQTT_closeConnection` | Clean up network state and free all allocated memory. | > **Info** > > **Return codes:** All NanoMQTT functions return `MQTT_OK` (0) or a negative error code. Check each call; on failure disconnect, free, and reconnect. ## Implementation notes | Topic | Note | | --- | --- | | **Build toggle** | NanoMQTT is part of the default TrustCore SDK build. Use `./build.sh nanomqtt` (or the `--module nanomqtt` CMake option) if you want to build only the NanoMQTT components. | | **Auto-PING logic** | `MQTT_recv()` automatically injects a PINGREQ whenever no other data has flowed for one keep-alive interval. Applications do **not** need to call `MQTT_pingRequest()` unless they choose to manage keep-alive manually. If the keep-alive interval is `0`, NanoMQTT will not send PINGREQ packets. | | **Memory ownership** | `MQTT_disconnect()` terminates the network session but *does not* free the client state. Always follow it with `MQTT_closeConnection(conn)` (or drop the handle) to release memory. |