### Example Build and Test Workflow Source: https://github.com/emqx/nanosdk/blob/main/docs/BUILD_TLS.md A complete example demonstrating how to set up the build environment, configure NNG with TLS enabled, build the project using Ninja, and run the TLS test utility. Assumes Mbed TLS is installed and NNG source is checked out. ```bash $ export NNGDIR=$HOME/work/nng $ mkdir build $ cd build $ cmake -G Ninja -DNNG_ENABLE_TLS=ON .. ... (lots of lines of output from cmake...) $ ninja build ... (lots of lines of output from ninja...) $ ./src/supplemental/tls/tls_test -v ... (lots of lines of output from the test ...) Summary: Count of all unit tests: 9 Count of run unit tests: 9 Count of failed unit tests: 0 Count of skipped unit tests: 0 SUCCESS: All unit tests have passed. ``` -------------------------------- ### Example Option Specification and Parsing Setup Source: https://github.com/emqx/nanosdk/blob/main/docs/man/nng_opts_parse.3supp.adoc Demonstrates how to define an array of nng_optspec structures to describe supported command-line options, including long names, short flags, unique values, and whether they take arguments. The array must be terminated with an entry where o_val is 0. ```c enum { OPT_LOGFILE, OPT_VERBOSE }; char *logfile; // options to be set bool verbose; static nng_optspec specs[] = { { .o_name = "logfile", .o_short = 'D', .o_val = OPT_LOGFILE, .o_arg = true, }, { .o_name = "verbose", .o_short = 'V', .o_val = OPT_VERBOSE, .o_arg = false, }, { .o_val = 0; // Terminate array } ``` -------------------------------- ### Build libzerotiercore and NNG with ZeroTier Support Source: https://github.com/emqx/nanosdk/blob/main/docs/BUILD_ZEROTIER.adoc This example demonstrates the complete build process for libzerotiercore and NNG with ZeroTier transport enabled. It includes cloning the repository, configuring CMake, building, and installing both projects. Ensure NNGDIR and ZTDIR environment variables are set correctly. ```sh $ export NNGDIR=$HOME/work/nng $ export ZTDIR=$HOME/work/libzerotiercore $ git clone https://github.com/staysail/libzerotiercore $ZTDIR $ cd $ZTDIR $ mkdir build $ cd build $ cmake .. ... (lots of lines of output from cmake...) $ make ... (lots of lines of output from make...) $ make install $ cd $NNGDIR $ mkdir build $ cd build $ cmake -DNNG_TRANSPORT_ZEROTIER=ON .. ... (lots of lines of output from cmake...) $ make ... (lots of lines of output from make...) $ ./tests/zt ok ./tests/zt 22.837s ``` -------------------------------- ### Start HTTP Server - C Source: https://github.com/emqx/nanosdk/blob/main/docs/man/nng_http_server_start.3http.adoc Call this function to start the HTTP server instance. Ensure necessary headers are included. ```c #include #include int nng_http_server_start(nng_http_server *server); ``` -------------------------------- ### Example of Establishing an HTTP Client Connection in C Source: https://github.com/emqx/nanosdk/blob/main/docs/man/nng_http_client_connect.3http.adoc This example demonstrates how to use nng_http_client_connect to establish an HTTP connection. It includes allocating necessary structures, initiating the connection, waiting for the asynchronous operation to complete, and handling potential errors or success. ```c nng_aio *aio; nng_url *url; nng_http_client *client; nng_http_conn *conn; int rv; // Error checks elided for clarity. nng_url_parse(&url, "http://www.google.com"); nng_aio_alloc(&aio, NULL, NULL); nng_http_client_alloc(&client, url); nng_http_client_connect(client, aio); // Wait for connection to establish (or attempt to fail). nng_aio_wait(aio); if ((rv = nng_aio_result(aio)) != 0) { printf("Connection failed: %s\n", nng_strerror(rv)); } else { // Connection established, get it. conn = nng_aio_get_output(aio, 0); // ... do something with it here // Close the connection when done to avoid leaking it. nng_http_conn_close(conn); } ``` -------------------------------- ### Compile HTTP Client with GCC Source: https://github.com/emqx/nanosdk/blob/main/demo/http_client/README.adoc Example compilation command for UNIX-like systems using GCC. Ensure nng library is installed and include/library paths are correctly set. ```bash % export CPPFLAGS="-I /usr/local/include" % export LDFLAGS="-L /usr/local/lib -lnng" % export CC="cc" % ${CC} ${CPPFLAGS} http_client.c -o http_client ${LDFLAGS} ``` -------------------------------- ### nng_http_server_start Source: https://github.com/emqx/nanosdk/blob/main/docs/man/nng_http_server_start.3http.adoc Starts the HTTP server instance. This causes it to bind to the appropriate TCP port, and start accepting connections and handling HTTP requests. ```APIDOC ## nng_http_server_start ### Description Starts the HTTP server instance `server`. This causes it to bind to the appropriate TCP port, and start accepting connections and handling HTTP requests. ### Function Signature ```c int nng_http_server_start(nng_http_server *server); ``` ### Parameters * `server` (nng_http_server *) - A pointer to the HTTP server instance to start. ### Return Values * 0 on success. * Non-zero on failure. ### Errors * `NNG_EADDRINUSE`:: The TCP port is unavailable. * `NNG_EADDRINVAL`:: The server is configured with an invalid address. * `NNG_ENOMEM`:: Insufficient free memory exists. * `NNG_ENOTSUP`:: HTTP not supported. ``` -------------------------------- ### Multi-URL Failover with Manual Reconnect Loop Source: https://context7.com/emqx/nanosdk/llms.txt Demonstrates connecting to multiple broker URLs with automatic failover and optional round-robin selection. Uses nng_cv and nng_mtx for synchronization. Setup involves allocating mutex and condition variable, defining URLs, and starting the connect loop. ```c static nng_cv *switch_cv; static nng_mtx *switch_mtx; static void disconnect_cb(nng_pipe p, nng_pipe_ev ev, void *arg) { nng_mtx_lock(switch_mtx); nng_cv_wake(switch_cv); // wake the connect loop nng_mtx_unlock(switch_mtx); } void connect_loop(const char **urls, int len) { int cnt = -1; while (1) { nng_socket sock; nng_mqtt_client_open(&sock); nng_mqtt_set_disconnect_cb(sock, disconnect_cb, NULL); cnt = (cnt + 1) % len; // round-robin; set cnt=-1 for always-first nng_dialer dialer; nng_dialer_create(&dialer, sock, urls[cnt]); nng_dialer_set_ptr(dialer, NNG_OPT_MQTT_CONNMSG, connmsg); if (nng_dialer_start(dialer, NNG_FLAG_ALLOC) != 0) { nng_close(sock); continue; // try next URL immediately } // Block until disconnect event nng_mtx_lock(switch_mtx); nng_cv_wait(switch_cv); nng_mtx_unlock(switch_mtx); nng_close(sock); } } // Setup nng_mtx_alloc(&switch_mtx); nng_cv_alloc(&switch_cv, switch_mtx); const char *urls[] = { "mqtt-tcp://primary.broker:1883", "mqtt-tcp://secondary.broker:1883", "mqtt-tcp://fallback.broker:1883", }; connect_loop(urls, 3); ``` -------------------------------- ### Create and Start MQTT Dialer Source: https://context7.com/emqx/nanosdk/llms.txt Creates a dialer, attaches the CONNECT message, and starts the connection. Use NNG_FLAG_NONBLOCK for asynchronous connection or NNG_FLAG_ALLOC for blocking until connected. ```c nng_dialer dialer; int rv; rv = nng_dialer_create(&dialer, sock, "mqtt-tcp://broker.emqx.io:1883"); if (rv != 0) { fatal("nng_dialer_create", rv); } // Attach the pre-built CONNECT message nng_dialer_set_ptr(dialer, NNG_OPT_MQTT_CONNMSG, connmsg); // Non-blocking connect (returns immediately, connection occurs in background) nng_dialer_start(dialer, NNG_FLAG_NONBLOCK); // Supported URL schemes: // mqtt-tcp://host:port Plain TCP // tls+mqtt-tcp://host:port MQTT over TLS // mqtt-quic://host:port MQTT over QUIC (requires NNG_ENABLE_QUIC=ON) // ws://host:port/path MQTT over WebSocket // wss://host:port/path MQTT over WebSocket + TLS ``` -------------------------------- ### Start Listener - C Source: https://github.com/emqx/nanosdk/blob/main/docs/man/nng_listener_start.3.adoc Starts the specified listener 'l'. This function causes the listener to bind to its configured address and begin accepting connections. The flags argument is reserved for future use and is currently ignored. Once started, listener configuration is typically immutable. ```c #include int nng_listener_start(nng_listener l, int flags); ``` -------------------------------- ### CMake Project Setup Source: https://github.com/emqx/nanosdk/blob/main/demo/pubsub_forwarder/CMakeLists.txt Sets the minimum required CMake version and defines the project name and language. ```cmake cmake_minimum_required(VERSION 3.10) project(pubsub_forwarder C) ``` -------------------------------- ### nng_listener_start Source: https://github.com/emqx/nanosdk/blob/main/docs/man/nng_listener_start.3.adoc Starts the listener `l`. This causes the listener to bind to the address it was created with, and to start accepting connections from remote dialers. Each new connection results in an `nng_pipe` object, which will be attached to the listener's socket. The `flags` argument is ignored, but reserved for future use. Once a listener has started, it is generally not possible to change its configuration. ```APIDOC ## nng_listener_start ### Description Starts the listener `l`. This causes the listener to bind to the address it was created with, and to start accepting connections from remote dialers. Each new connection results in an `nng_pipe` object, which will be attached to the listener's socket. The `flags` argument is ignored, but reserved for future use. Once a listener has started, it is generally not possible to change its configuration. ### Synopsis ```c #include int nng_listener_start(nng_listener l, int flags); ``` ### Parameters #### Path Parameters * **l** (nng_listener) - The listener to start. * **flags** (int) - Reserved for future use and currently ignored. ### Return Values * 0 on success. * Non-zero on failure. ### Errors * `NNG_ECLOSED`:: Parameter `l` does not refer to an open listener. * `NNG_ESTATE`:: The listener `l` is already started. ``` -------------------------------- ### Run Publisher Client Source: https://github.com/emqx/nanosdk/blob/main/demo/pubsub_forwarder/README.adoc Publish messages to the forwarder. This example publishes a sequence of numbers from 0 to 99. ```bash for n in $(seq 0 99); do nngcat --pub --dial "tcp://localhost:3327" --data "$n"; done ``` -------------------------------- ### Run Server and Concurrent Clients Source: https://github.com/emqx/nanosdk/blob/main/demo/raw/README.adoc Start the server in the background and then launch multiple clients concurrently. The URL should be set to the desired network address. ```bash % export URL="tcp://127.0.0.1:55995" # start the server % ./raw $URL -s & # start a bunch of clients # Note that these all run concurrently! % ./raw $URL 2 & % ./raw $URL 2 & % ./raw $URL 2 & % ./raw $URL 2 & % ./raw $URL 2 & ``` -------------------------------- ### Start Dialer - C Synopsis Source: https://github.com/emqx/nanosdk/blob/main/docs/man/nng_dialer_start.3.adoc This is the function signature for nng_dialer_start in C. It takes a dialer handle and flags as input. ```c #include int nng_dialer_start(nng_dialer d, int flags); ``` -------------------------------- ### CMake Minimum Requirements and Project Setup Source: https://github.com/emqx/nanosdk/blob/main/demo/multiurls_switch/CMakeLists.txt Sets the minimum CMake version and defines the project name. This is standard practice for CMake projects. ```cmake cmake_minimum_required(VERSION 3.13) project(multiurls_switch) ``` -------------------------------- ### Get NNG Library Version Source: https://github.com/emqx/nanosdk/blob/main/docs/man/nng_version.3.adoc Call this function to retrieve the human-readable version string of the NNG library. No special setup is required beyond including the nng header. ```c #include const char * nng_version(void); ``` -------------------------------- ### MQTT Client Demo Snippet Source: https://github.com/emqx/nanosdk/blob/main/docs/man/nng_mqtt_client_open.3.adoc This snippet demonstrates opening an MQTT client socket, allocating and setting up a CONNECT message, creating a dialer, and starting the connection process. ```c if ((rv = nng_mqtt_client_open(&sock)) != 0) { fatal("nng_socket", rv); } nng_msg *msg; nng_mqtt_msg_alloc(&msg, 0); nng_mqtt_msg_set_packet_type(msg, NNG_MQTT_CONNECT); if ((rv = nng_dialer_create(&dialer, sock, url)) != 0) { fatal("nng_dialer_create", rv); } nng_dialer_set_ptr(dialer, NNG_OPT_MQTT_CONNMSG, msg); nng_dialer_start(dialer, NNG_FLAG_NONBLOCK); ``` -------------------------------- ### Run Client and Server Source: https://github.com/emqx/nanosdk/blob/main/demo/reqrep/README.adoc Demonstrates how to launch the server in the background and then run the client to interact with it. The client sends a 'DATE' command and receives a timestamp. ```bash ./reqrep server tcp://127.0.0.1:8899 & ./reqrep client tcp://127.0.0.1:8899 ``` -------------------------------- ### nng_mqtt_sqlite_db_init Source: https://github.com/emqx/nanosdk/blob/main/docs/man/nng_mqtt_set_sqlite.3.adoc Initializes SQLite options and creates or opens the database file. ```APIDOC ## nng_mqtt_sqlite_db_init ### Description Initializes SQLite options and creates or opens the database file based on the provided options. ### Method `void nng_mqtt_sqlite_db_init(nng_mqtt_sqlite_option *opt, const char *db_name, uint8_t mqtt_proto);` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Parameters - **opt** (`nng_mqtt_sqlite_option *`): Pointer to the SQLite option object. - **db_name** (`const char *`): The name of the SQLite database file. - **mqtt_proto** (`uint8_t`): The MQTT protocol version. ``` -------------------------------- ### Project Setup and Dependencies Source: https://github.com/emqx/nanosdk/blob/main/demo/quic_mqtt/CMakeLists.txt Sets the minimum CMake version, project name, and finds required packages like nng, msquic, and Threads. Conditional logic is used for nng configuration based on BUILD_DEMO. ```cmake cmake_minimum_required(VERSION 3.13) project(quic_client) if (BUILD_DEMO) else () # Call this from your own project's makefile. find_package(nng CONFIG REQUIRED) endif (BUILD_DEMO) find_package(Threads) find_package(msquic) ``` -------------------------------- ### nng_dialer_start Source: https://github.com/emqx/nanosdk/blob/main/docs/man/nng_dialer_start.3.adoc Starts the dialer `d`. This causes the dialer to start connecting to the address with which it was created. If `NNG_FLAG_NONBLOCK` is supplied in `flags`, the connection attempt is made asynchronously. ```APIDOC ## nng_dialer_start ### Description Starts the dialer `d`. This causes the dialer to start connecting to the address with which it was created. If `NNG_FLAG_NONBLOCK` is supplied in `flags`, the connection attempt is made asynchronously. ### Function Signature ```c int nng_dialer_start(nng_dialer d, int flags); ``` ### Parameters #### Path Parameters - **d** (nng_dialer) - The dialer to start. - **flags** (int) - Flags to control the connection behavior. Use `NNG_FLAG_NONBLOCK` for asynchronous connection attempts. ### Return Values - 0 on success. - Non-zero on failure. ### Errors - `NNG_EADDRINVAL`: Invalid URL specified. - `NNG_ECLOSED`: The socket is not open. - `NNG_ECONNREFUSED`: The remote peer refused the connection. - `NNG_ECONNRESET`: The remote peer reset the connection. - `NNG_EINVAL`: Invalid set of flags specified. - `NNG_ENOMEM`: Insufficient memory available. - `NNG_EPEERAUTH`: Authentication or authorization failure. - `NNG_EPROTO`: A protocol error occurred. - `NNG_ESTATE`: The dialer is already started. - `NNG_EUNREACHABLE`: The remote address is not reachable. ``` -------------------------------- ### nng_mqtt_client_open Source: https://github.com/emqx/nanosdk/blob/main/docs/man/nng_mqtt_client_open.3.adoc Creates a MQTT client socket. The client must then be connected to a server using nng_dialer_create() and nng_dialer_start(). A CONNECT message must be prepared using nng_mqtt_msg_alloc() and nng_mqtt_msg_set_connect() and then set on the dialer using nng_dialer_set_ptr() with the option NNG_OPT_MQTT_CONNMSG. ```APIDOC ## nng_mqtt_client_open ### Description Creates a MQTT client socket but does not connect it. Note that MQTT sockets can be connected to at most a single server. Must create MQTT CONNECT message for *dialer* by message functions: nng_mqtt_msg_alloc(), nng_mqtt_msg_set_connect(). ### Synopsis ```c #include #include int nng_mqtt_client_open(nng_socket *sock); ``` ### Parameters #### Path Parameters * **sock** (nng_socket *) - Output parameter to store the newly created socket. ### Return Values This function returns 0 on success, and non-zero otherwise. ### Errors * `NNG_ENOTSUP`:: MQTT not supported. ### Example ```c if ((rv = nng_mqtt_client_open(&sock)) != 0) { fatal("nng_socket", rv); } nng_msg *msg; nng_mqtt_msg_alloc(&msg, 0); nng_mqtt_msg_set_packet_type(msg, NNG_MQTT_CONNECT); if ((rv = nng_dialer_create(&dialer, sock, url)) != 0) { fatal("nng_dialer_create", rv); } nng_dialer_set_ptr(dialer, NNG_OPT_MQTT_CONNMSG, msg); nng_dialer_start(dialer, NNG_FLAG_NONBLOCK); ``` ``` -------------------------------- ### Example: Waiting for a condition with nng_cv_wait Source: https://github.com/emqx/nanosdk/blob/main/docs/man/nng_cv_wait.3supp.adoc This example shows how to safely wait for a condition to become true. The condition must be checked within a loop to handle spurious wakeups. ```c nng_mtx_lock(m); // assume cv was allocated using m while (!condition_true) { nng_cv_wait(cv); } // condition_true is true nng_mtx_unlock(m); ``` -------------------------------- ### Open Push Socket (Version 0) Source: https://github.com/emqx/nanosdk/blob/main/docs/man/nng_push_open.3.adoc Use nng_push0_open() to create a standard push socket. Ensure nng/nng.h and nng/protocol/pipeline0/push.h are included. ```c #include #include int nng_push0_open(nng_socket *s); ``` -------------------------------- ### Example: Signaling a condition with nng_cv_wake Source: https://github.com/emqx/nanosdk/blob/main/docs/man/nng_cv_wait.3supp.adoc This example demonstrates how to signal a condition variable after changing the condition. It locks the mutex, sets the condition, wakes one waiting thread, and then unlocks the mutex. ```c nng_mtx_lock(m); condition_true = true; nng_cv_wake(cv); nng_mtx_unlock(m); ``` -------------------------------- ### nng_mqtt_client_open() Synopsis Source: https://github.com/emqx/nanosdk/blob/main/docs/man/nng_mqtt_client_open.3.adoc Include the necessary headers for NNG and MQTT client functionality. ```c #include #include ``` -------------------------------- ### nng_http_client_connect Source: https://github.com/emqx/nanosdk/blob/main/docs/man/nng_http_client_connect.3http.adoc The `nng_http_client_connect()` starts the process of establishing an HTTP connection from _client_ to the server that was indicated in the URL that _client_ was configured with. The result of the operation will be stored in the _aio_ when the operation is complete, and will be obtainable via nng_aio_result(). On success, a pointer to the underlying HTTP client (type `nng_http_conn *`) will be stored in the first output result of the _aio_, and can be obtained by nng_aio_get_output() with an _index_ of zero (0). ```APIDOC ## nng_http_client_connect ### Description Starts the process of establishing an HTTP connection from a client to a server specified in the client's configuration URL. The result is stored in the provided `nng_aio` structure. ### Synopsis ```c #include #include void nng_http_client_connect(nng_http_client *client, nng_aio *aio); ``` ### Parameters * `client` (nng_http_client *) - Pointer to the HTTP client structure. * `aio` (nng_aio *) - Pointer to the asynchronous I/O structure to store the result. ### Return Values None. ### Errors * `NNG_EADDRINVAL`: The client is configured with an invalid address. * `NNG_ECANCELED`: The operation was aborted. * `NNG_ECONNREFUSED`: The TCP connection was refused by the server. * `NNG_ECONNRESET`: The TCP connection was reset by the server. * `NNG_ENOMEM`: Insufficient free memory exists. ### Example ```c nng_aio *aio; nng_url *url; nng_http_client *client; nng_http_conn *conn; int rv; // Error checks elided for clarity. nng_url_parse(&url, "http://www.google.com"); nng_aio_alloc(&aio, NULL, NULL); nng_http_client_alloc(&client, url); nng_http_client_connect(client, aio); // Wait for connection to establish (or attempt to fail). nng_aio_wait(aio); if ((rv = nng_aio_result(aio)) != 0) { printf("Connection failed: %s\n", nng_strerror(rv)); } else { // Connection established, get it. conn = nng_aio_get_output(aio, 0); // ... do something with it here // Close the connection when done to avoid leaking it. nng_http_conn_close(conn); } ``` ``` -------------------------------- ### nng_http_conn_write Source: https://github.com/emqx/nanosdk/blob/main/docs/man/nng_http_conn_write.3http.adoc Starts an asynchronous write operation to an HTTP connection. ```APIDOC ## nng_http_conn_write ### Description Starts an asynchronous write to the HTTP connection `conn` from the scatter/gather vector located in the asynchronous I/O structure `aio`. The `nng_aio_set_iov()` function must have been called first to set the scatter/gather vector for `aio`. ### Method `void nng_http_conn_write(nng_http_conn *conn, nng_aio *aio);` ### Parameters * `conn` (nng_http_conn *) - The HTTP connection to write to. * `aio` (nng_aio *) - The asynchronous I/O structure containing the scatter/gather vector. ### Return Values None. ### Errors * `NNG_ECANCELED`: The operation was canceled. * `NNG_ECLOSED`: The connection was closed. * `NNG_ECONNRESET`: The peer closed the connection. * `NNG_EINVAL`: The `aio` does not contain a valid scatter/gather vector. * `NNG_ENOMEM`: Insufficient free memory to perform the operation. * `NNG_ENOTSUP`: HTTP operations are not supported. * `NNG_ETIMEDOUT`: Timeout waiting for data from the connection. ``` -------------------------------- ### nng_msg_trim Source: https://github.com/emqx/nanosdk/blob/main/docs/man/nng_msg_trim.3.adoc Removes a specified number of bytes from the start of the message body. ```APIDOC ## nng_msg_trim ### Description Removes `size` bytes from the start of the message body. ### Parameters #### Path Parameters - **msg** (*nng_msg* *) - Required - Pointer to the message to trim. - **size** (*size_t*) - Required - The number of bytes to remove. ### Return Values Returns 0 on success, and non-zero otherwise. ### Errors - **NNG_EINVAL** - The message body is too short to remove the requested data. ``` -------------------------------- ### nng_msg_header_trim Source: https://github.com/emqx/nanosdk/blob/main/docs/man/nng_msg_header_trim.3.adoc Removes a specified number of bytes from the start of the message header. ```APIDOC ## nng_msg_header_trim ### Description Removes `size` bytes from the start of the header of message `msg`. ### Parameters - **msg** (*nng_msg* *) - A pointer to the message whose header will be trimmed. - **size** (*size_t*) - The number of bytes to remove from the header. ### Return Values Returns 0 on success, and a non-zero error code otherwise. ### Errors - **NNG_EINVAL**: The message header is too short to remove the requested data. ``` -------------------------------- ### nng_http_server_hold Source: https://github.com/emqx/nanosdk/blob/main/docs/man/nng_http_server_hold.3http.adoc Acquires an instance of an HTTP server suitable for use in serving the URL identified by _url_, and stores a pointer to it at the location pointed to by _serverp_. If an existing server is suitable, its reference count is incremented. Otherwise, a new server instance is created with a reference count of one. The server is not started and can be configured before being started with nng_http_server_start. ```APIDOC ## nng_http_server_hold ### Description Acquires an instance of an HTTP server suitable for use in serving the URL identified by _url_, and stores a pointer to it at the location pointed to by _serverp_. This function first looks to see if an existing HTTP server instance exists, that is suitable for this. If so, it increments the reference count on it and uses that. Otherwise, it will attempt to create a new server instance with an initial reference count of one (1). The server instance is not started, and can have additional configuration applied to it before it is later started with nng_http_server_start(). NOTE: The URL matching logic in determining servers is unable to distinguish between different aliases for the same local IP address. This may create problems when using URLs for virtual hosting. It is recommended to use canonical IP addresses or names in the _url_ to avoid confusion. ### Synopsis ```c #include #include int nng_http_server_hold(nng_http_server **serverp, const nng_url *url); ``` ### Parameters * `serverp` - A pointer to a pointer where the HTTP server instance will be stored. * `url` - A pointer to the nng_url structure identifying the server to acquire or create. ### Return Values This function returns 0 on success, and non-zero otherwise. ### Errors * `NNG_ENOMEM` - Insufficient free memory exists. * `NNG_ENOTSUP` - HTTP not supported. ``` -------------------------------- ### Open Raw Push Socket (Version 0) Source: https://github.com/emqx/nanosdk/blob/main/docs/man/nng_push_open.3.adoc Use nng_push0_open_raw() to create a push socket in raw mode. Include nng/nng.h and nng/protocol/pipeline0/push.h. ```c #include #include int nng_push0_open_raw(nng_socket *s); ``` -------------------------------- ### Get Socket Option Signature Source: https://github.com/emqx/nanosdk/blob/main/docs/man/nn_getsockopt.3compat.adoc This is the function signature for nn_getsockopt, used to retrieve socket options. ```c #include int nn_getsockopt(int sock, int level, int option, void *val, size_t *szp); ``` -------------------------------- ### Compile with Traditional Makefiles Source: https://github.com/emqx/nanosdk/blob/main/demo/reqrep/README.adoc This example shows a traditional compilation approach suitable for UNIX-like systems. Set CPPFLAGS and LDFLAGS to specify include and library paths. ```bash export CPPFLAGS="-I /usr/local/include" export LDFLAGS="-L /usr/local/lib -lnng" export CC="cc" ${CC} ${CPPFLAGS} reqrep.c -o reqrep ${LDFLAGS} ``` -------------------------------- ### Get Statistic Stub Signature Source: https://github.com/emqx/nanosdk/blob/main/docs/man/nn_get_statistic.3compat.adoc This is the function signature for nn_get_statistic. It is a stub and always returns zero. ```c #include uint64_t nn_get_statistic(int sock, int stat); ``` -------------------------------- ### nng_msg_trim_u64 Source: https://github.com/emqx/nanosdk/blob/main/docs/man/nng_msg_trim.3.adoc Removes 8 bytes from the start of the message body and converts them to a uint64_t in native byte order. ```APIDOC ## nng_msg_trim_u64 ### Description Removes 8 bytes from the start of the message body and stores them in `val64` after converting them from network-byte order (big-endian) to native byte order. ### Parameters #### Path Parameters - **msg** (*nng_msg* *) - Required - Pointer to the message to trim. - **val64** (*uint64_t* *) - Required - Pointer to store the trimmed value. ### Return Values Returns 0 on success, and non-zero otherwise. ### Errors - **NNG_EINVAL** - The message body is too short to remove the requested data. ``` -------------------------------- ### Configure MSQuic Root Hints Source: https://github.com/emqx/nanosdk/blob/main/src/supplemental/quic/msquic/CMakeLists.txt Sets hints for finding the MSQuic installation directory. Use this to specify custom locations if MSQuic is not found automatically. ```cmake set(_MSQUIC_ROOT_HINTS ${MSQUIC_ROOT_DIR} ENV MSQUIC_ROOT_DIR) ``` -------------------------------- ### Build NanoSDK with MQTT over QUIC Source: https://github.com/emqx/nanosdk/blob/main/README.md Build NanoSDK with MQTT over QUIC support enabled. Requires MsQUIC to be installed. Building shared libraries is disabled. ```bash cmake -G Ninja -DBUILD_SHARED_LIBS=OFF -DNNG_ENABLE_QUIC=ON .. ``` -------------------------------- ### nng_msg_trim_u32 Source: https://github.com/emqx/nanosdk/blob/main/docs/man/nng_msg_trim.3.adoc Removes 4 bytes from the start of the message body and converts them to a uint32_t in native byte order. ```APIDOC ## nng_msg_trim_u32 ### Description Removes 4 bytes from the start of the message body and stores them in `val32` after converting them from network-byte order (big-endian) to native byte order. ### Parameters #### Path Parameters - **msg** (*nng_msg* *) - Required - Pointer to the message to trim. - **val32** (*uint32_t* *) - Required - Pointer to store the trimmed value. ### Return Values Returns 0 on success, and non-zero otherwise. ### Errors - **NNG_EINVAL** - The message body is too short to remove the requested data. ``` -------------------------------- ### Build with CMake and Ninja Source: https://github.com/emqx/nanosdk/blob/main/demo/raw/README.adoc Use CMake and Ninja for building the project. Ensure you are in the build directory before running these commands. ```bash % mkdir build % cd build % cmake -G Ninja .. % ninja ``` -------------------------------- ### nng_msg_trim_u16 Source: https://github.com/emqx/nanosdk/blob/main/docs/man/nng_msg_trim.3.adoc Removes 2 bytes from the start of the message body and converts them to a uint16_t in native byte order. ```APIDOC ## nng_msg_trim_u16 ### Description Removes 2 bytes from the start of the message body and stores them in `val16` after converting them from network-byte order (big-endian) to native byte order. ### Parameters #### Path Parameters - **msg** (*nng_msg* *) - Required - Pointer to the message to trim. - **val16** (*uint16_t* *) - Required - Pointer to store the trimmed value. ### Return Values Returns 0 on success, and non-zero otherwise. ### Errors - **NNG_EINVAL** - The message body is too short to remove the requested data. ``` -------------------------------- ### Setting up concurrent echo service contexts Source: https://github.com/emqx/nanosdk/blob/main/docs/man/nng_ctx.5.adoc Initializes multiple echo contexts and their associated asynchronous I/O objects for a concurrent service. Ensure error checks are implemented for production code. ```c #define CONCURRENCY 1024 static struct echo_context ecs[CONCURRENCY]; void start_echo_service(nng_socket rep_socket) { for (int i = 0; i < CONCURRENCY; i++) { // error checks elided for clarity nng_ctx_open(&ecs[i].ctx, rep_socket); nng_aio_alloc(&ecs[i].aio, echo, ecs+i); ``` -------------------------------- ### nng_aio_cancel Source: https://github.com/emqx/nanosdk/blob/main/docs/man/nng_aio_cancel.3.adoc Aborts an operation previously started with the handle aio. If the operation is aborted, then the callback for the handle will be called, and the function nng_aio_result() will return the error NNG_ECANCELED. This function does not wait for the operation to be fully aborted, but returns immediately. If no operation is currently in progress (either because it has already finished, or no operation has been started yet), then this function has no effect. This function is the same as calling nng_aio_abort() with the error NNG_ECANCELED. ```APIDOC ## nng_aio_cancel ### Description Aborts an operation previously started with the handle `aio`. If the operation is aborted, then the callback for the handle will be called, and the function `nng_aio_result()` will return the error `NNG_ECANCELED`. This function does not wait for the operation to be fully aborted, but returns immediately. If no operation is currently in progress (either because it has already finished, or no operation has been started yet), then this function has no effect. NOTE: This function is the same as calling `nng_aio_abort()` with the error `NNG_ECANCELED`. ### Synopsis ```c #include void nng_aio_cancel(nng_aio *aio); ``` ### Parameters #### Parameters - **aio** (*nng_aio* *) - A pointer to the asynchronous I/O descriptor. ### Return Value None. ``` -------------------------------- ### Open MQTT 5.0 Client Socket Source: https://github.com/emqx/nanosdk/blob/main/docs/man/nng_mqttv5_client_open.3.adoc This snippet demonstrates how to open an MQTT 5.0 client socket using nng_mqttv5_client_open. It also shows the subsequent steps to create a dialer, allocate and set a CONNECT message, and start the connection process. ```c if ((rv = nng_mqttv5_client_open(&sock)) != 0) { fatal("nng_socket", rv); } nng_msg *msg; nng_mqtt_msg_alloc(&msg, 0); nng_mqtt_msg_set_packet_type(msg, NNG_MQTT_CONNECT); if ((rv = nng_dialer_create(&dialer, sock, url)) != 0) { fatal("nng_dialer_create", rv); } nng_dialer_set_ptr(dialer, NNG_OPT_MQTT_CONNMSG, msg); nng_dialer_start(dialer, NNG_FLAG_NONBLOCK); ``` -------------------------------- ### nng_listen Function Signature Source: https://github.com/emqx/nanosdk/blob/main/docs/man/nng_listen.3.adoc This is the function signature for nng_listen. It is used to create and start a listener on a given socket and URL. ```c #include int nng_listen(nng_socket s, const char *url, nng_listener *lp, int flags); ``` -------------------------------- ### Create Pub Socket - nng_pub0_open Source: https://github.com/emqx/nanosdk/blob/main/docs/man/nng_pub_open.3.adoc Use this function to create a standard publish socket version 0. It returns the socket via the provided pointer. ```c #include #include int nng_pub0_open(nng_socket *s); ``` -------------------------------- ### nng_listener_create Source: https://github.com/emqx/nanosdk/blob/main/docs/man/nng_listener_create.3.adoc Creates a new listener object associated with a given socket and URL. The listener is not started automatically and can be further configured. ```APIDOC ## nng_listener_create ### Description The `nng_listener_create()` function creates a newly initialized `nng_listener` object, associated with socket `s`, and configured to listen at the address specified by `url`, and stores a pointer to it at the location referenced by `listenerp`. Listeners are used to accept connections initiated by remote dialers. An incoming connection generally results in a pipe being created and attached to the socket `s`. Unlike dialers, listeners generally can create many pipes, which may be open concurrently. The listener is not started, but may be further configured with the `nng_listener_setopt()` family of functions. Once it is fully configured, the listener may be started using the `nng_listener_start()` function. ### Parameters * **listenerp** (*nng_listener* *) - Output parameter to store the created listener. * **s** (*nng_socket*) - The socket to associate the listener with. * **url** (*const char* *) - The URL at which to listen for incoming connections. ### Return Values This function returns 0 on success, and non-zero otherwise. ### Errors * `NNG_EADDRINVAL`:: An invalid `url` was specified. * `NNG_ECLOSED`:: The socket `s` is not open. * `NNG_ENOMEM`:: Insufficient memory is available. ``` -------------------------------- ### Compile Server and Client with CMake Source: https://github.com/emqx/nanosdk/blob/main/demo/async/README.adoc Compile the server and client applications using GCC on UNIX-style systems. Ensure necessary flags for parallel processing and library linking are set. ```bash % export CPPFLAGS="-D PARALLEL=32 -I /usr/local/include" % export LDFLAGS="-L /usr/local/lib -lnng" % export CC="cc" % ${CC} ${CPPFLAGS} server.c -o server ${LDFLAGS} % ${CC} ${CPPFLAGS} client.c -o client ${LDFLAGS} ``` -------------------------------- ### NNG_OPT_IPC_SECURITY_DESCRIPTOR Source: https://github.com/emqx/nanosdk/blob/main/docs/man/nng_ipc_options.5.adoc Configures the security descriptor for named pipes on Windows platforms. This option is write-only and applicable to listeners before they are started. ```APIDOC ## NNG_OPT_IPC_SECURITY_DESCRIPTOR This write-only option may be used on listeners on Windows platforms to configure the `SECURITY_DESCRIPTOR` that is used when creating the underlying named pipe. The value is a pointer, `PSECURITY_DESCRIPTOR`, and may only be applied to listeners that have not been started yet. ``` -------------------------------- ### Compile HTTP Client with CMake and Ninja Source: https://github.com/emqx/nanosdk/blob/main/demo/http_client/README.adoc Steps to compile the HTTP client using CMake and Ninja build system. This is a recommended approach for managing build configurations. ```bash % mkdir build % cd build % cmake -G Ninja .. % ninja ``` -------------------------------- ### nng_dialer_create / nng_dialer_set_ptr / nng_dialer_start Source: https://context7.com/emqx/nanosdk/llms.txt Creates a dialer, attaches the CONNECT message as an option, and starts the connection. Use NNG_FLAG_NONBLOCK for asynchronous connection or NNG_FLAG_ALLOC for blocking until connected. ```APIDOC ## `nng_dialer_create` / `nng_dialer_set_ptr` / `nng_dialer_start` — Dial the MQTT Broker Creates a dialer, attaches the CONNECT message as an option, and starts the connection. Use `NNG_FLAG_NONBLOCK` for asynchronous connection or `NNG_FLAG_ALLOC` for blocking until connected. ```c nng_dialer dialer; int rv; rv = nng_dialer_create(&dialer, sock, "mqtt-tcp://broker.emqx.io:1883"); if (rv != 0) { fatal("nng_dialer_create", rv); } // Attach the pre-built CONNECT message nng_dialer_set_ptr(dialer, NNG_OPT_MQTT_CONNMSG, connmsg); // Non-blocking connect (returns immediately, connection occurs in background) nng_dialer_start(dialer, NNG_FLAG_NONBLOCK); // Supported URL schemes: // mqtt-tcp://host:port Plain TCP // tls+mqtt-tcp://host:port MQTT over TLS // mqtt-quic://host:port MQTT over QUIC (requires NNG_ENABLE_QUIC=ON) // ws://host:port/path MQTT over WebSocket // wss://host:port/path MQTT over WebSocket + TLS ``` ``` -------------------------------- ### Type-Specific Listener Get Functions Source: https://github.com/emqx/nanosdk/blob/main/docs/man/nng_listener_get.3.adoc These functions provide type-safe ways to retrieve specific option types from a listener. ```APIDOC ## Type-Specific Listener Get Functions ### Description These functions are specialized versions of `nng_listener_get()` for retrieving options of specific data types. They simplify the process by handling type casting and buffer management internally. ### Forms `nng_listener_get_bool()`:: Retrieves a boolean option. `nng_listener_get_int()`:: Retrieves an integer option. `nng_listener_get_ms()`:: Retrieves a time duration option in milliseconds. `nng_listener_get_ptr()`:: Retrieves a pointer to structured data. `nng_listener_get_size()`:: Retrieves a size value. `nng_listener_get_addr()`:: Retrieves a socket address structure. `nng_listener_get_string()`:: Retrieves a string option. The caller must free the returned string using `nng_strfree()`. `nng_listener_get_uint64()`:: Retrieves a 64-bit unsigned integer option. ### Synopsis ```c int nng_listener_get_bool(nng_listener l, const char *opt, bool *bvalp); int nng_listener_get_int(nng_listener l, const char *opt, int *ivalp); int nng_listener_get_ms(nng_listener l, const char *opt, nng_duration *durp); int nng_listener_get_ptr(nng_listener l, const char *opt, void **ptr); int nng_listener_get_size(nng_listener l, const char *opt, size_t *zp); int nng_listener_get_addr(nng_listener l, const char *opt, nng_sockaddr *sap); int nng_listener_get_string(nng_listener l, const char *opt, char **strp); int nng_listener_get_uint64(nng_listener l, const char *opt, uint64_t *u64p); ``` ### Parameters * `l` (nng_listener) - The listener to retrieve the option from. * `opt` (const char *) - The name of the option to retrieve. * `bvalp`, `ivalp`, `durp`, `ptr`, `zp`, `sap`, `strp`, `u64p` - Pointers to variables where the retrieved option value will be stored. ### Return Values Returns 0 on success, and non-zero otherwise. ``` -------------------------------- ### nng_dialer_getopt_sockaddr - Get Socket Address Dialer Option Source: https://github.com/emqx/nanosdk/blob/main/docs/man/nng_dialer_getopt.3.adoc Retrieves a nng_sockaddr structure representing a network address from the dialer. ```c int nng_dialer_getopt_sockaddr(nng_dialer d, const char *opt, nng_sockaddr *sap); ``` -------------------------------- ### Echo Service with Request/Reply Source: https://github.com/emqx/nanosdk/blob/main/docs/man/nngcat.1.adoc Demonstrates setting up a listening socket in reply mode and then sending a request to it. The server echoes the received data back to the client. ```sh $ addr="tcp://127.0.0.1:4567" $ nngcat --rep --listen=${addr} --data="42" --quoted & $ nngcat --req --dial=${addr} --data="what is the answer?" --quoted "what is the answer?" "42" ``` -------------------------------- ### Basic CMake Configuration Source: https://github.com/emqx/nanosdk/blob/main/demo/mqtt/CMakeLists.txt Sets the minimum CMake version and project name. It finds the nng package, which is required for MQTT client functionality. ```cmake cmake_minimum_required(VERSION 3.13) project(mqtt_client) ``` ```cmake if (BUILD_DEMO) else () # Call this from your own project's makefile. find_package(nng CONFIG REQUIRED) endif (BUILD_DEMO) ``` ```cmake find_package(Threads) ``` -------------------------------- ### nng_dialer_getopt_size - Get Size Dialer Option Source: https://github.com/emqx/nanosdk/blob/main/docs/man/nng_dialer_getopt.3.adoc Retrieves a size value, typically for buffer or message sizes, from the dialer. ```c int nng_dialer_getopt_size(nng_dialer d, const char *opt, size_t *zp); ``` -------------------------------- ### nng_aio_begin Function Signature Source: https://github.com/emqx/nanosdk/blob/main/docs/man/nng_aio_begin.3.adoc This is the function signature for nng_aio_begin. It is used by I/O providers to indicate the start of an asynchronous I/O operation. ```c #include bool nng_aio_begin(nng_aio *aio); ``` -------------------------------- ### nng_pub0_open Source: https://github.com/emqx/nanosdk/blob/main/docs/man/nng_pub_open.3.adoc Creates a pub version 0 socket and returns it. ```APIDOC ## nng_pub0_open ### Description Creates a pub version 0 socket and returns it at the location pointed to by _s_. ### Synopsis ```c #include #include int nng_pub0_open(nng_socket *s); ``` ### Return Values Returns 0 on success, and non-zero otherwise. ### Errors - `NNG_ENOMEM`: Insufficient memory is available. - `NNG_ENOTSUP`: The protocol is not supported. ``` -------------------------------- ### Get Message Header Length Source: https://github.com/emqx/nanosdk/blob/main/docs/man/nng_msg_header_len.3.adoc Use this function to retrieve the size of the message header. Include the nng/nng.h header for access. ```c #include size_t nng_msg_header_len(nng_msg *msg); ``` -------------------------------- ### Acquire HTTP Server Instance Source: https://github.com/emqx/nanosdk/blob/main/docs/man/nng_http_server_hold.3http.adoc Acquires an HTTP server instance for the given URL. If a suitable server exists, its reference count is incremented; otherwise, a new server is created. The server is not started by this call. ```c #include #include int nng_http_server_hold(nng_http_server **serverp, const nng_url *url); ``` -------------------------------- ### Run REST API Server and Test Source: https://github.com/emqx/nanosdk/blob/main/demo/rest/README.adoc Starts the REST API server and tests its functionality using curl. Ensure the PORT environment variable is set if not using the default. ```bash % env PORT=8888 # default % ./rest-server & % curl -d ABC http://127.0.0.1:8888/api/rest/rot13; echo NOP % curl -d NOP http://127.0.0.1:8888/api/rest/rot13; echo ABC ``` -------------------------------- ### IPC Option Definitions Source: https://github.com/emqx/nanosdk/blob/main/docs/man/nng_ipc_options.5.adoc Defines symbolic constants for IPC-specific socket options. Use these definitions when setting or getting options. ```c #include #define NNG_OPT_IPC_PEER_GID "ipc:peer-gid" #define NNG_OPT_IPC_PEER_PID "ipc:peer-pid" #define NNG_OPT_IPC_PEER_UID "ipc:peer-uid" #define NNG_OPT_IPC_PEER_ZONEID "ipc:peer-zoneid" #define NNG_OPT_IPC_PERMISSIONS "ipc:permissions" #define NNG_OPT_IPC_SECURITY_DESCRIPTOR "ipc:security-descriptor" ```