README.md
Two files. Drop mongoose.c and mongoose.h into any C/C++ project and get a
full network stack — HTTP, WebSocket, MQTT, TLS, firmware OTA
updates, device dashboard — on any microcontroller or desktop OS.
On the market since 2004, used by vast number of open source and commercial products - it even runs on the International Space Station! Features include:
Mongoose is ideal for IoT devices, embedded web servers, OTA updates, MQTT telemetry, secure device dashboards, REST APIs on microcontrollers
See https://mongoose.ws/ for complete documentation, videos, case studies, etc.
Mongoose can work on top of any TCP/IP stack that supports BSD sockets API. Platforms supported by the 3rd party TCP/IP stacks:
| TCP/IP stack | Notes |
|---|---|
| lwIP | All devices running lwIP, for example ESP32, ESP32S3, ESP32C3, ESP32C6, etc |
| Zephyr | All devices supported by Zephyr |
| Other | Any other TCP/IP stack that supports BSD socket API, for example Amazon FreeRTOS-TCP |
| Linux, Mac, Windows | Workstations, server, single board computers, embedded Linux devices running on MPUs or FPGAs |
Optionally, Mongoose provides its own built-in TCP/IP stack, eliminating the need for additional software to implement networking functionality. The built-in stack supports operation in both bare-metal and RTOS environments. Platforms supported by the Mongoose built-in TCP/IP stack:
| Hardware | Notes |
|---|---|
| STM32 | All STM32 MCUs with built-in Ethernet: STM32Fxx, STM32H5xx, STM32H7xx |
| NXP | All NXP MCUs with built-in Ethernet: IMXRT102x, IMXRT104x, IMXRT105x, IMXRT106x, IMXRT117x, RW612, MCXN94x |
| Microchip | ATSAME54 MCUs with built-int Ethernet |
| Renesas | RA5M, RA6M, RA8M MCUs with built-in Ethernet |
| Infineon | XMC4, XMC7 MCUs with built-in Ethernet |
| Texas Instruments | TM4C, TMS570 MCUs with built-in Ethernet |
| Cypress WiFi | Any MCU with CY43xx WiFi chips, like RP2040 Pico-W, RP2350 Pico2-W, Arduino Portenta |
| Wiznet Ethernet | Any MCU that use Wiznet W5500 or Wiznet 5100 MAC+PHY chips |
| Cellular | NRF9160, SIM800 |
Below are quick snippets that should give an idea how simple the API is and how easy it is to create applications with it.
Create a simple web server that serves a directory. The behavior of the HTTP server is specified by its event handler function:
#include "mongoose.h" // To build, run: cc main.c mongoose.c
// HTTP server event handler function
void ev_handler(struct mg_connection *c, int ev, void *ev_data) {
if (ev == MG_EV_HTTP_MSG) {
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
struct mg_http_serve_opts opts = { .root_dir = "./web_root/" };
mg_http_serve_dir(c, hm, &opts);
}
}
int main(void) {
struct mg_mgr mgr; // Declare event manager
mg_mgr_init(&mgr); // Initialise event manager
mg_http_listen(&mgr, "http://0.0.0.0:8000", ev_handler, NULL); // Setup listener
for (;;) { // Run an infinite event loop
mg_mgr_poll(&mgr, 1000);
}
return 0;
}
HTTP server implements a REST API that returns current time. JSON formatting:
static void ev_handler(struct mg_connection *c, int ev, void *ev_data) {
if (ev == MG_EV_HTTP_MSG) {
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
if (mg_match(hm->uri, mg_str("/api/time/get"), NULL)) {
mg_http_reply(c, 200, "", "{%m:%lu}\n", MG_ESC("time"), time(NULL));
} else {
mg_http_reply(c, 500, "", "{%m:%m}\n", MG_ESC("error"), MG_ESC("Unsupported URI"));
}
}
}
MQTT client that subscribes to a topic device1/rx and
echoes incoming messages to device1/tx:
#include "mongoose.h"
static const char *s_mqtt_url = "mqtt://broker.hivemq.com:1883";
static struct mg_connection *s_mqtt_conn = NULL;
// MQTT connection event handler function
static void ev_handler(struct mg_connection *c, int ev, void *ev_data) {
if (ev == MG_EV_OPEN) {
MG_INFO(("%lu created, connecting to %s ...", c->id, s_mqtt_url));
} else if (ev == MG_EV_MQTT_OPEN) {
struct mg_mqtt_opts opts = {.qos = 1, .topic = mg_str("device1/rx")};
mg_mqtt_sub(c, &opts);
MG_INFO(("%lu connected, subscribing to %s", c->id, opts.topic.buf));
} else if (ev == MG_EV_MQTT_MSG) {
char response[100];
struct mg_mqtt_message *mm = (struct mg_mqtt_message *) ev_data;
struct mg_mqtt_opts opts = {.qos = 1, .topic = mg_str("device1/tx")};
mg_snprintf(response, sizeof(response), "Received [%.*s] / [%.*s]",
mm->topic.len, mm->topic.buf, mm->data.len, mm->data.buf);
opts.message = mg_str(response);
mg_mqtt_pub(c, &opts);
} else if (ev == MG_EV_CLOSE) {
MG_INFO(("%u closing", c->id));
s_mqtt_conn = NULL;
}
}
// Reconnection timer function. If we get disconnected, reconnect again
static void timer_fn(void *arg) {
struct mg_mgr *mgr = (struct mg_mgr *) arg;
if (s_mqtt_conn == NULL) {
struct mg_mqtt_opts opts = {.clean = true};
s_mqtt_conn = mg_mqtt_connect(mgr, s_mqtt_url, &opts, ev_handler, NULL);
}
}
int main() {
struct mg_mgr mgr; // Mongoose event manager. Holds all connections
mg_mgr_init(&mgr); // Initialise event manager
mg_timer_add(&mgr, 3000, MG_TIMER_REPEAT | MG_TIMER_RUN_NOW, timer_fn, &mgr);
for (;;) {
mg_mgr_poll(&mgr, 1000); // Infinite event loop
}
return 0;
}
We take security seriously:
Please report via https://github.com/cesanta/mongoose/security/advisories. Do NOT create a github issue.
Technical guides and deep dives into embedded web servers, WebUI integration and embedded networking technologies:
Contributions are welcome! Please follow the guidelines below: