From 47b606091082fec21ef01fc2ae9d558fb284a918 Mon Sep 17 00:00:00 2001 From: cpq Date: Sun, 6 Dec 2020 21:12:05 +0000 Subject: [PATCH] Add docs --- README.md | 11 ++- docs/README.md | 251 +++++++++++++++++++++++++++++++++++++++++++++++++ mongoose.h | 4 +- src/net.h | 4 +- 4 files changed, 261 insertions(+), 9 deletions(-) create mode 100644 docs/README.md diff --git a/README.md b/README.md index 2addeb94..d7fd55a2 100644 --- a/README.md +++ b/README.md @@ -4,11 +4,12 @@ [![Build Status](https://travis-ci.org/cesanta/mongoose.svg?branch=7.0)](https://travis-ci.org/cesanta/mongoose) [![Code Coverage](https://codecov.io/gh/cesanta/mongoose/branch/7.0/graph/badge.svg)](https://codecov.io/gh/cesanta/mongoose) -Mongoose is ideal for embedded environments. It has been designed -for connecting devices and bringing them online. On the market since 2004, -used by vast number of open source and -commercial products - it even runs on the International Space Station! -Mongoose makes embedded network programming fast, robust, and easy. +Mongoose is a networking library for C/C++. It implements event-driven +non-blocking APIs for TCP, UDP, HTTP, WebSocket, MQTT. It has been designed +for connecting devices and bringing them online. On the market since 2004, used +by vast number of open source and commercial products - it even runs on the +International Space Station! Mongoose makes embedded network programming fast, +robust, and easy. - [Download Mongoose Source Code here](https://www.cesanta.com/download.html) diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 00000000..146305cf --- /dev/null +++ b/docs/README.md @@ -0,0 +1,251 @@ +# Overview + +## Introduction + +Mongoose is a networking library for C/C++. It implements event-driven +non-blocking APIs for TCP, UDP, HTTP, WebSocket, MQTT. It has been designed +for connecting devices and bringing them online. On the market since 2004, used +by vast number of open source and commercial products - it even runs on the +International Space Station! Mongoose makes embedded network programming fast, +robust, and easy. + + +## Features + +* Cross-platform: works on Linux/UNIX, MacOS, QNX, eCos, Windows, Android, + iPhone, FreeRTOS, etc +* Supported hardware platforms: TI CC3200, TI MSP432, NRF52, STM32, PIC32, ESP8266, ESP32 and more +* Builtin protocols: + - plain TCP, plain UDP, SSL/TLS (over TCP, one-way or two-way) + - HTTP client, HTTP server + - WebSocket client, WebSocket server + - MQTT client + - DNS client, async DNS resolver +* Single-threaded, asynchronous, non-blocking core with simple event-based API +* Native support for [LWIP embedded TCP/IP stack](https://en.wikipedia.org/wiki/LwIP) +* Tiny static and run-time footprint +* Source code is both ISO C and ISO C++ compliant +* Very easy to integrate: just copy + [mongoose.c](https://raw.githubusercontent.com/cesanta/mongoose/master/mongoose.c) and + [mongoose.h](https://raw.githubusercontent.com/cesanta/mongoose/master/mongoose.h) + files to your build tree + +## Concept + +Mongoose has three basic data structures: + +- `struct mg_mgr` - an event manager that holds all active connections +- `struct mg_connection` - describes a connection +- `struct mg_iobuf` - describes data buffer (received or sent data) + +Connections could be either listening, outbound or inbound. Outbound +connections are created by the `mg_connect()` call. Listening connections are +created by the `mg_listen()` call. Inbound connections are those accepted by a +listening connection. Each connection is described by a `struct mg_connection` +structure, which has a number of fields. All fields are exposed to the +application by design, to give an application a full visibility into the +Mongoose's internals. + +An application that uses mongoose should follow a standard pattern of +event-driven application: + +- Declare and initialise an event manager: + +```c +struct mg_mgr mgr; +mg_mgr_init(&mgr); +``` + +- Create connections. For example, a server application should create listening + connections. When any connection is created (listening or outgoing), an + event handler function must be specified. An event handler function defines + connection's behavior. + +```c +struct mg_connection *c = mg_http_listen(&mgr, "0.0.0.0:8000", fn, arg); +``` + +- Create an event loop by calling `mg_mgr_poll()`: + +```c + for (;;) { + mg_mgr_poll(&mgr, 1000); + } +``` + +`mg_mgr_poll()` iterates over all sockets, accepts new connections, sends and +receives data, closes connections and calls event handler functions for the +respective events. + +Since the Mongoose's core is not protected against the concurrent access, +make sure that all `mg_*` API functions are called from the same thread +or RTOS task. + +## Send and receive buffers + + +Each connection has a send and receive buffer: +- `struct mg_connection::send` - data to be sent to a peer +- `struct mg_connection::recv` - data received from a peer + +When data arrives, Mongoose appends received data to the `recv` and triggers an +`MG_EV_RECV` event. The user may send data back by calling one of the output +functions, like `mg_send()` or `mg_printf()`. Output functions append data to +the `send` buffer. When Mongoose successfully writes data to the socket, it +discards data from struct `mg_connection::send` and sends an `MG_EV_SEND` +event. + +## Event handler function + +Each connection has an event handler function associated with it. That function +must be implemented by the user. Event handler is the key element of the +Mongoose application, since it defines the connection's behaviour. This is +what an event handler function looks like: + +```c +static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) { + switch (ev) { + /* Event handler code that defines behavior of the connection */ + ... + } +} +``` + +- `struct mg_connection *c` - a connection that received an event +- `int ev` - an event number, defined in mongoose.h. For example, when data + arrives on an inbound connection, ev would be `MG_EV_RECV`. +- `void *ev_data` - points to the event-specific data, and it has a different + meaning for different events. For example, for an `MG_EV_RECV` event, + `ev_data` + is an `int *` pointing to the number of bytes received from a remote + peer and saved into the `c->recv` IO buffer. The exact meaning of `ev_data` is + described for each event. Protocol-specific events usually have `ev_data` + pointing to structures that hold protocol-specific information. +- `void *fn_data` - a user-defined pointer for the connection, which is a + placeholder for application-specific data. Mongoose does not use that + pointer. An event handler can store any kind of information there + +## Events + +Below is the list of events trigged by Mongoose, taken as-is from `mongoose.h`. +For each event, a comment describes a meaning of the `ev_data` pointer passed +to an event handler: + +```c +enum { + MG_EV_ERROR, // Error char *error_message + MG_EV_POLL, // mg_mgr_poll iteration unsigned long *millis + MG_EV_RESOLVE, // Host name is resolved NULL + MG_EV_CONNECT, // Connection established NULL + MG_EV_ACCEPT, // Connection accepted NULL + MG_EV_READ, // Data received from socket struct mg_str * + MG_EV_WRITE, // Data written to socket int *num_bytes_written + MG_EV_CLOSE, // Connection closed NULL + MG_EV_HTTP_MSG, // HTTP request/response struct mg_http_message * + MG_EV_WS_OPEN, // Websocket handshake done NULL + MG_EV_WS_MSG, // Websocket message received struct mg_ws_message * + MG_EV_MQTT_MSG, // MQTT message struct mg_mqtt_message * + MG_EV_MQTT_OPEN, // MQTT CONNACK received int *connack_status_code + MG_EV_SNTP_TIME, // SNTP time received struct timeval * + MG_EV_USER, // Starting ID for user events +}; +``` + +## Connection flags + +`struct mg_connection` has a bitfield with connection flags. Flags are binary, +they can be either 0 or 1. Some flags are set by Mongoose and must be not +changed by an application code, for example `is_udp` flag tells application if +that connection is UDP or not. Some flags can be changed by application, for +example, `is_drainig` flag, if set by an application, tells Mongoose to send +the remaining data to peer, and when everything is sent, close the connection. + +User-changeable flags are: `is_hexdumping`, `is_drainig`, `is_closing`. + +This is taken from `mongoose.h` as-is: + +```c +struct mg_connection { + ... + unsigned is_listening : 1; // Listening connection + unsigned is_client : 1; // Outbound (client) connection + unsigned is_accepted : 1; // Accepted (server) connection + unsigned is_resolving : 1; // Non-blocking DNS resolv is in progress + unsigned is_connecting : 1; // Non-blocking connect is in progress + unsigned is_tls : 1; // TLS-enabled connection + unsigned is_tls_hs : 1; // TLS handshake is in progress + unsigned is_udp : 1; // UDP connection + unsigned is_websocket : 1; // WebSocket connection + unsigned is_hexdumping : 1; // Hexdump in/out traffic + unsigned is_draining : 1; // Send remaining data, then close and free + unsigned is_closing : 1; // Close and free the connection immediately + unsigned is_readable : 1; // Connection is ready to read + unsigned is_writable : 1; // Connection is ready to write +}; +``` + +## Build options + +Mongoose source code ships in two files: +- [mongoose.h](https://github.com/cesanta/mongoose/blob/master/mongoose.h) - API definitions +- [mongoose.c](https://github.com/cesanta/mongoose/blob/master/mongoose.c) - implementation + +Therefore to integrate Mongoose into an application, simply copy these two +files to the application's source tree. + +The `mongoose.c` and `mongoose.h` files are, actually, an amalgamation - +a non-amalgamated sources can be found at https://github.com/cesanta/mongoose/tree/master/src + +Mongoose source code uses a bunch of build constants defined at +https://github.com/cesanta/mongoose/blob/master/src/config.h, together with +their default values. + +In order to change the constant during build time, use the `-D +` compiler option. For example, to disable both MQTT, +compile the application `my_app.c` like this (assumed UNIX system): + +```sh +$ cc my_app.c mongoose.c -D MG_MQTT_ENABLE=0 +``` + +Here is a list of build constants and their default values: +| Name | Default | Description | +| ---- | ------- | ----------- | +|`MG_ENABLE_LWIP` | 0 | Use LWIP low-level API instead of BSD sockets | +|`MG_ENABLE_SOCKET` | 1 | Use BSD socket low-level API | +|`MG_ENABLE_MBEDTLS` | 0 | Enable Mbed TLS library | +|`MG_ENABLE_OPENSSL` | 0 | Enable OpenSSL library | +|`MG_ENABLE_FS` | 1 | Enable API that use filesystem, like `mg_http_send_file()` | +|`MG_ENABLE_IPV6` | 0 | Enable IPv6 | +|`MG_ENABLE_LOG` | 1 | Enable `LOG()` macro | +|`MG_ENABLE_MD5` | 0 | Use native MD5 implementation | +|`MG_ENABLE_DIRECTORY_LISTING` | 0 | Enable directory listing for HTTP server | +|`MG_ENABLE_HTTP_DEBUG_ENDPOINT` | 0 | Enable `/debug/info` debug URI | +|`MG_ENABLE_SOCKETPAIR` | 0 | Enable `mg_socketpair()` for multi-threading | +|`MG_IO_SIZE` | 512 | Granularity of the send/recv IO buffer growth | +|`MG_MAX_RECV_BUF_SIZE` | (3 * 1024 * 1024) | Maximum recv buffer size | +|`MG_MAX_HTTP_HEADERS` | 40 | Maximum number of HTTP headers | + +## Minimal example + +This example is a simple static HTTP server that serves current directory: + +```c +#include "mongoose.h" + +static const char *s_web_root_dir = "."; +static const char *s_listening_address = "http://localhost:8000"; + +static void cb(struct mg_connection *c, int ev, void *ev_data, void *fn_data) { + if (ev == MG_EV_HTTP_MSG) mg_http_serve_dir(c, ev_data, s_web_root_dir); +} + +int main(int argc, char *argv[]) { + struct mg_mgr mgr; + mg_mgr_init(&mgr); + mg_http_listen(&mgr, s_listening_address, cb, &mgr); + for (;;) mg_mgr_poll(&mgr, 1000); + mg_mgr_free(&mgr); + return 0; +} +``` diff --git a/mongoose.h b/mongoose.h index cc0025e1..652cc71d 100644 --- a/mongoose.h +++ b/mongoose.h @@ -623,8 +623,8 @@ struct mg_connection { unsigned is_udp : 1; // UDP connection unsigned is_websocket : 1; // WebSocket connection unsigned is_hexdumping : 1; // Hexdump in/out traffic - unsigned is_draining : 1; // Send remaining data, then deallocate - unsigned is_closing : 1; // Deallocate connection + unsigned is_draining : 1; // Send remaining data, then close and free + unsigned is_closing : 1; // Close and free the connection immediately unsigned is_readable : 1; // Connection is ready to read unsigned is_writable : 1; // Connection is ready to write }; diff --git a/src/net.h b/src/net.h index 67f709ba..c3cee318 100644 --- a/src/net.h +++ b/src/net.h @@ -42,8 +42,8 @@ struct mg_connection { unsigned is_udp : 1; // UDP connection unsigned is_websocket : 1; // WebSocket connection unsigned is_hexdumping : 1; // Hexdump in/out traffic - unsigned is_draining : 1; // Send remaining data, then deallocate - unsigned is_closing : 1; // Deallocate connection + unsigned is_draining : 1; // Send remaining data, then close and free + unsigned is_closing : 1; // Close and free the connection immediately unsigned is_readable : 1; // Connection is ready to read unsigned is_writable : 1; // Connection is ready to write };