mongoose/docs/README.md

1287 lines
37 KiB
Markdown
Raw Normal View History

2020-12-09 00:26:17 +08:00
# User Guide
2020-12-07 05:12:05 +08:00
2020-12-09 00:53:35 +08:00
2020-12-07 05:12:05 +08:00
## Introduction
2020-12-09 00:53:35 +08:00
Mongoose is a networking library for C/C++. It implements an event-driven,
2020-12-07 05:12:05 +08:00
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:
2020-12-10 21:26:05 +08:00
1. Declare and initialise an event manager:
2020-12-07 05:12:05 +08:00
2020-12-10 21:26:05 +08:00
```c
struct mg_mgr mgr;
mg_mgr_init(&mgr);
```
2020-12-07 05:12:05 +08:00
2020-12-10 21:26:05 +08:00
2. Create connections. For example, a server application should create listening
2020-12-07 05:12:05 +08:00
connections. When any connection is created (listening or outgoing), an
event handler function must be specified. An event handler function defines
connection's behavior.
2020-12-10 21:26:05 +08:00
```c
struct mg_connection *c = mg_http_listen(&mgr, "0.0.0.0:8000", fn, arg);
```
2020-12-07 05:12:05 +08:00
2020-12-10 21:26:05 +08:00
3. Create an event loop by calling `mg_mgr_poll()`:
2020-12-07 05:12:05 +08:00
2020-12-10 21:26:05 +08:00
```c
for (;;) {
mg_mgr_poll(&mgr, 1000);
}
```
2020-12-07 05:12:05 +08:00
`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.
2020-12-10 21:26:05 +08:00
Since the Mongoose's core is not protected against concurrent accesses,
2020-12-07 05:12:05 +08:00
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
2020-12-10 21:26:05 +08:00
arrives on an inbound connection, ev would be `MG_EV_RECV`
2020-12-07 05:12:05 +08:00
- `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`
2020-12-10 21:26:05 +08:00
pointing to structures that hold protocol-specific information
2020-12-07 05:12:05 +08:00
- `void *fn_data` - a user-defined pointer for the connection, which is a
2020-12-10 21:26:05 +08:00
placeholder for application-specific data
2020-12-07 05:12:05 +08:00
## 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 {
2021-01-17 19:16:19 +08:00
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 struct mg_http_message *
MG_EV_WS_MSG, // Websocket msg, text or bin struct mg_ws_message *
MG_EV_WS_CTL, // Websocket control msg struct mg_ws_message *
MG_EV_MQTT_CMD, // MQTT low-level command struct mg_mqtt_message *
MG_EV_MQTT_MSG, // MQTT PUBLISH received struct mg_mqtt_message *
2020-12-07 05:12:05 +08:00
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_draining` flag, if set by an application, tells Mongoose to send
2020-12-07 05:12:05 +08:00
the remaining data to peer, and when everything is sent, close the connection.
User-changeable flags are: `is_hexdumping`, `is_draining`, `is_closing`.
2020-12-07 05:12:05 +08:00
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
<PREPROCESSOR_FLAG>` 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:
2020-12-09 00:26:17 +08:00
2020-12-07 05:12:05 +08:00
| 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_SOCKETPAIR` | 0 | Enable `mg_socketpair()` for multi-threading |
|`MG_ENABLE_SSI` | 0 | Enable serving SSI files by `mg_http_serve_dir()` |
2020-12-07 05:12:05 +08:00
|`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 |
2020-12-17 19:19:13 +08:00
NOTE: `MG_IO_SIZE` controls the maximum UDP message size, see
https://github.com/cesanta/mongoose/issues/907 for details. If application
uses large UDP messages, increase the `MG_IO_SIZE` limit accordingly.
2021-01-20 19:28:47 +08:00
## Custom build
It is possible to use Mongoose on an architecture that is not yet supported
by the current codebase. In order to do so, follow these steps:
1. Create a file called `mongoose_custom.h`, with defines and includes that
are relevant to your platform. Mongoose uses `bool` type, `MG_DIRSEP` define,
and optionally other structures like `DIR *` depending on the functionality
you have enabled - see previous section. Below is an example:
```c
#include <dirent.h> // For DIR *
#include <stdbool.h> // For bool
#include <sys/time.h> // For gettimeofday()
#include <unistd.h> // For usleep()
#define MG_DIRSEP '/'
#define MG_ENABLE_SOCKET 0 // Disable BSD socket API, implement your own
```
2. Add `-DMG_ARCH=MG_ARCH_CUSTOM` to your build flags.
3. This step is optional. If you have disabled BSD socket API, your build is
going to fail due to several undefined symbols. Create `mongoose_custom.c`
and implement the following functions (take a look at `src/sock.c` for the
reference implementation):
```c
struct mg_connection *mg_connect(struct mg_mgr *mgr, const char *url,
mg_event_handler_t fn, void *fn_data) {
// implement this!
}
void mg_connect_resolved(struct mg_connection *c) {
// implement this!
}
struct mg_connection *mg_listen(struct mg_mgr *mgr, const char *url,
mg_event_handler_t fn, void *fn_data) {
// implement this!
}
void mg_mgr_poll(struct mg_mgr *mgr, int ms) {
// implement this!
}
int mg_send(struct mg_connection *c, const void *buf, size_t len) {
// implement this!
}
```
2020-12-09 00:26:17 +08:00
## Minimal HTTP server
2020-12-07 05:12:05 +08:00
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) {
struct mg_http_serve_opts opts = {.root_dir = s_web_root_dir};
if (ev == MG_EV_HTTP_MSG) mg_http_serve_dir(c, ev_data, &opts);
2020-12-07 05:12:05 +08:00
}
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;
}
```
2020-12-09 00:26:17 +08:00
## Minimal TCP echo server
This example is a simple TCP echo server that listens on port 1234:
```c
#include "mongoose.h"
static const char *s_listening_address = "tcp://0.0.0.0:1234";
static void cb(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
if (ev == MG_EV_RECV) {
mg_send(c, c->recv.buf, c->recv.len); // Echo received data back
mg_iobuf_delete(&c->recv, c->recv.len); // And discard it
}
}
int main(int argc, char *argv[]) {
struct mg_mgr mgr;
mg_mgr_init(&mgr);
mg_listen(&mgr, s_listening_address, cb, &mgr);
for (;;) mg_mgr_poll(&mgr, 1000);
mg_mgr_free(&mgr);
return 0;
}
```
# API Reference
## Core
### struct mg_mgr
```c
2020-12-09 00:53:35 +08:00
struct mg_mgr {
2020-12-09 00:26:17 +08:00
struct mg_connection *conns; // List of active connections
struct mg_connection *dnsc; // DNS resolver connection
const char *dnsserver; // DNS server URL
int dnstimeout; // DNS resolve timeout in milliseconds
};
```
Event management structure that holds a list of active connections, together
with some housekeeping information.
### struct mg\_connection
```c
struct mg_connection {
struct mg_connection *next; // Linkage in struct mg_mgr :: connections
struct mg_mgr *mgr; // Our container
struct mg_addr peer; // Remote peer address
void *fd; // Connected socket, or LWIP data
struct mg_iobuf recv; // Incoming data
struct mg_iobuf send; // Outgoing data
mg_event_handler_t fn; // User-specified event handler function
void *fn_data; // User-speficied function parameter
mg_event_handler_t pfn; // Protocol-specific handler function
void *pfn_data; // Protocol-specific function parameter
char label[32]; // Arbitrary label
void *tls; // TLS specific data
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
};
```
A connection - either a listening connection, or an accepted connection,
or an outbout connection.
### mg\_mgr_init()
```c
void mg_mgr_init(struct mg_mgr *);
```
Initialise event manager structure: set a list of active connections to NULL,
set DNS server and timeout to their default values, etc.
### mg\_mgr_poll()
```c
void mg_mgr_poll(struct mg_mgr *mgr, int ms);
```
Perform a single poll iteration. For each connection in the `mgr->conns` list,
- See if there is incoming data. If it is, read it into the `c->recv` buffer, send `MG_EV_RECV` event
- See if there is data in the `c->send` buffer, and write it, send `MG_EV_WRITE` event
- If a connection is listening, accept an incoming connection if any, and send `MG_EV_ACCEPT` event to it
- Send `MG_EV_POLL` event
Each connection has two event handler functions: `c->fn` and `c->pfn`. The
`c->fn` is a user-specified event handler function. The `c->pfn` is a
protocol-specific handler function that is set implicitly. For example, a
`mg_http_listen()` sets `c->pfn` to a Mongoose's HTTP event handler. A
protocol-specific handler is called before user-specific handler. It parses
incoming data and may invoke protocol-specific events like `MG_EV_HTTP_MSG`.
2021-01-23 15:49:55 +08:00
### mg\_mgr\_free()
2020-12-09 00:26:17 +08:00
```c
void mg_mgr_free(struct mg_mgr *mgr);
```
Close all connections, and free all resources.
### mg\_listen()
```c
struct mg_connection *mg_listen(struct mg_mgr *mgr, const char *url,
mg_event_handler_t fn, void *fn_data);
```
Create a listening connection, append this connection to `mgr->conns`.
- `url` - specifies local IP address and port to listen on, e.g.
`tcp://127.0.0.1:1234` or `udp://0.0.0.0:9000`
- `fn` - an event handler function
- `fn_data` - an arbitrary pointer, which will be passed as `fn_data` when an
event handler is called. This pointer is also stored in a connection
structure as `c->fn_data`
Return value: created connection, or `NULL` on error.
### mg\_connect()
```c
struct mg_connection *mg_connect(struct mg_mgr *mgr, const char *url,
mg_event_handler_t fn, void *fn_data);
```
Create an outbout connection, append this connection to `mgr->conns`.
- `url` - specifies remote IP address/port to connect to, e.g. `http://a.com`
- `fn` - an event handler function
- `fn_data` - an arbitrary pointer, which will be passed as `fn_data` when an
event handler is called. This pointer is also stored in a connection
structure as `c->fn_data`
Return value: created connection, or `NULL` on error.
### mg\_send()
```c
int mg_send(struct mg_connection *c, const void *data, size_t size);
```
Append `data` of size `size` to the `c->send` buffer. Return number of bytes
appended.
Note: this function does not push data to the network! It only appends data to
the output buffer. The data is being sent when `mg_mgr_poll()` is called. If
`mg_send()` is called multiple times, the output buffer grows.
### mg\_printf()
```c
int mg_printf(struct mg_connection *, const char *fmt, ...);
```
Same as `mg_send()`, but formats data using `printf()` semantics. Return
number of bytes appended to the output buffer.
### mg\_vprintf()
```c
int mg_vprintf(struct mg_connection *, const char *fmt, va_list ap);
```
Same as `mg_printf()`, but takes `va_list` argument as a parameter.
### mg\_socketpair()
```c
bool mg_socketpair(int *blocking, int *non_blocking);
```
Create a socket pair for exchanging data in multi-threaded environment. The
`blocking` socket is blocking - it should be passed to the processing task.
The `non_blocking` socket is non blocking, it should be used by an event
handler function. Return value: true on success, false on error.
## IO buffers
### struct mg\_iobuf
```c
struct mg_iobuf {
unsigned char *buf;
size_t size, len;
};
```
Generic IO buffer. The `size` specifies an allocation size of the data pointed
by `buf`, and `len` specifies number of bytes currently stored.
### mg\_iobuf\_init()
```c
2021-01-29 20:32:34 +08:00
int mg_iobuf_init(struct mg_iobuf *io, size_t size);
2020-12-09 00:26:17 +08:00
```
2021-01-29 20:32:34 +08:00
Initialise IO buffer, allocate `size` bytes. Return 1 on success,
0 on allocation failure.
2020-12-09 00:26:17 +08:00
### mg\_iobuf\_resize()
```c
2021-01-29 20:32:34 +08:00
int mg_iobuf_resize(struct mg_iobuf *io, size_t size);
2020-12-09 00:26:17 +08:00
```
Resize IO buffer, set the new size to `size`. The `io->buf` pointer could
change after this, for example if the buffer grows. If `size` is 0, then the
`io->buf` is freed and set to NULL, and both `size` and `len` are set to 0.
2021-01-29 20:32:34 +08:00
Return 1 on success, 0 on allocation failure.
2020-12-09 00:26:17 +08:00
### mg\_iobuf\_free()
```c
void mg_iobuf_free(struct mg_iobuf *io);
```
Free memory pointed by `io->buf` and set to NULL. Both `size` and `len` are set
to 0.
### mg\_iobuf\_append()
```c
size_t mg_iobuf_append(struct mg_iobuf *io, const void *data, size_t data_size, size_t granularity);
```
Append `data` bytes of size `data_size` to the end of the buffer. The buffer
is expanded if `data_size` is greater than `io->size - io->len`. If that
happens, the `io->buf` can change. The resulting `io->size` is always
set to the `granularity` byte boundary. Example:
```c
struct mg_iobuf io;
mg_iobuf_init(&io, 0); // Empty buffer
mg_iobuf_append(&io, "hi", 2, 1024); // io->len is 2, io->size is 1024
```
### mg\_iobuf\_delete()
```c
size_t mg_iobuf_delete(struct mg_iobuf *io, size_t len);
```
Discard `len` bytes from the beginning of the buffer, and shift the remaining
bytes to the beginning. If `len` is greater than `io->len`, nothing happens,
so such call is silently ignored.
## HTTP
### struct mg\_http\_header
```c
struct mg_http_header {
struct mg_str name;
struct mg_str value;
};
```
### struct mg\_http\_message
```c
struct mg_http_message {
// GET /foo/bar/baz?aa=b&cc=ddd HTTP/1.1
// method |-| |----uri---| |--query--| |proto-|
struct mg_str method, uri, query, proto; // Request/response line
struct mg_http_header headers[MG_MAX_HTTP_HEADERS]; // Headers
struct mg_str body; // Body
struct mg_str message; // Request line + headers + body
};
```
### mg\_http\_listen()
```c
struct mg_connection *mg_http_listen(struct mg_mgr *, const char *url,
mg_event_handler_t fn, void *fn_data);
```
Create HTTP listener.
- `url` - specifies local IP address and port to listen on, e.g. `http://0.0.0.0:8000`
- `fn` - an event handler function
- `fn_data` - an arbitrary pointer, which will be passed as `fn_data` when an
event handler is called. This pointer is also stored in a connection
structure as `c->fn_data`
### mg\_http\_connect()
```c
struct mg_connection *mg_http_connect(struct mg_mgr *, const char *url,
mg_event_handler_t fn, void *fn_data);
```
Create HTTP client connection.
- `url` - specifies remote URL, e.g. `http://google.com`
- `fn` - an event handler function
- `fn_data` - an arbitrary pointer, which will be passed as `fn_data` when an
event handler is called. This pointer is also stored in a connection
structure as `c->fn_data`
### mg\_http\_get\_request\_len()
```c
int mg_http_get_request_len(const unsigned char *buf, size_t buf_len);
```
Return value: -1 on error,
0 if a message is incomplete, or the length of request. The length of
request is a number of bytes till the end of HTTP headers. It does not include
length of HTTP body.
### mg\_http\_parse()
```c
int mg_http_parse(const char *s, size_t len, struct mg_http_message *hm);
```
Parse string `s`, `len` into a structure `hm`. Return request length - see
`mg_http_get_request_len()`.
### mg\_http\_printf\_chunk()
```
void mg_http_printf_chunk(struct mg_connection *cnn, const char *fmt, ...);
```
Write a chunk of data in chunked encoding format, using `printf()` semantic.
### mg\_http\_write\_chunk()
```c
void mg_http_write_chunk(struct mg_connection *c, const char *buf, size_t len);
```
Write a chunk of data in chunked encoding format.
2021-01-12 18:28:41 +08:00
### mg\_http\_serve\_dir()
2020-12-09 00:26:17 +08:00
```c
struct mg_http_serve_opts {
const char *root_dir; // Web root directory, must be non-NULL
const char *ssi_pattern; // SSI filename pattern, e.g. #.shtml
};
2020-12-09 00:26:17 +08:00
void mg_http_serve_dir(struct mg_connection *, struct mg_http_message *hm,
const struct mg_http_serve_opts *opts);
2020-12-09 00:26:17 +08:00
```
Serve static files according to the given options. Note that in order to
enable SSI, set a `-DMG_ENABLE_SSI=1` build flag.
2020-12-09 00:26:17 +08:00
2021-01-12 18:28:41 +08:00
### mg\_http\_serve\_file()
2020-12-09 00:26:17 +08:00
```c
void mg_http_serve_file(struct mg_connection *, struct mg_http_message *hm,
const char *path, const char *mimetype,
const char *extra_headers);
2020-12-09 00:26:17 +08:00
```
2021-01-08 00:21:01 +08:00
Serve static file. Note that the `extra_headers` must end with `\r\n`. Here
is an example call:
```c
mg_http_serve_file(c, hm, "a.png", "image/png", "AA: bb\r\nCC: dd\r\n");
```
2020-12-09 00:26:17 +08:00
### mg\_http\_reply()
```c
2020-12-18 06:45:22 +08:00
void mg_http_reply(struct mg_connection *c, int status_code, const char *headers,
const char *body_fmt, ...);
2020-12-09 00:26:17 +08:00
```
2020-12-18 06:45:22 +08:00
Send simple HTTP response using `printf()` semantic. This function formats
response body according to a `body_fmt`, and automatically appends a correct
`Content-Length` header. Extra headers could be passed via `headers`
parameter.
- `status_code` - an HTTP response code
- `headers` - extra headers, default NULL. If not NULL, must end with `\r\n`
- `fmt` - a format string for the HTTP body, in a printf semantics
2020-12-09 00:26:17 +08:00
### mg\_http\_header()
```c
struct mg_str *mg_http_get_header(struct mg_http_message *, const char *name);
```
Return value of HTTP header, or NULL if not found.
### mg\_http\_get\_var()
```c
int mg_http_get_var(const struct mg_str *, const char *name, char *buf, int len);
```
Decode HTTP variable `name` into a given buffer. Return length of decoded
variable. Zero or negative value means error.
### mg\_url\_decode()
```c
int mg_url_decode(const char *s, size_t n, char *to, size_t to_len, int form);
```
URL-decode string `s`, `n` unto a buffer `buf`, `len`. Return decoded length.
If `form` is non-zero, then `+` is decoded as whitespace.
### mg\_http\_creds()
```c
void mg_http_creds(struct mg_http_message *, char *user, int userlen, char *pass, int passlen);
```
Fetch authentication credential from the request, and store into the
`user`, `userlen` and `pass`, `passlen` buffers. The credentials are looked
up in the following order:
- from the `Authorization` HTTP header,
- Basic auth fills both user and pass
- Bearer auth fills only pass
- from the `access_token` cookie, fills pass
- from the `?access_token=...` query string parameter, fills pass
If none is found, then both user and pass are set to empty nul-terminated strings.
### mg\_http\_match\_uri()
```c
bool mg_http_match_uri(const struct mg_http_message *, const char *glob);
```
Return true if HTTP request matches a given glob pattern; false otherwise.
### mg\_http\_upload()
```c
int mg_http_upload(struct mg_connection *, struct mg_http_message *hm,
const char *dir);
```
2020-12-14 17:31:03 +08:00
Handle file upload. See [file upload example](https://github.com/cesanta/mongoose/tree/master/examples/file-upload).
2020-12-09 00:26:17 +08:00
2020-12-14 17:36:46 +08:00
This function expects a series of POST requests with file data. POST requests
should have `name` and `offset` query string parameters set:
2020-12-14 17:31:03 +08:00
2020-12-14 17:35:03 +08:00
```text
2020-12-14 17:31:03 +08:00
POST /whatever_uri?name=myfile.txt&offset=1234 HTTP/1.0
Content-Length: 5
hello
```
- `name` - a mandatory query string parameter, specifies a file name. It it
created in the `dir` directory
- `offset` - an optional parameter, default `0`. If it set to `0`, or omitted,
then a file gets truncated before write. Otherwise, the body of
the POST request gets appended to the file
2020-12-14 17:35:03 +08:00
- Server must call `mg_http_upload()` when `/whatever_uri` is hit
2020-12-14 17:31:03 +08:00
So, the expected usage of this API function is this:
- A client splits a file into small enough chunks, to ensure that a chunk
fits into the server's RAM
- Then, each chunk is POST-ed to the server with using URI like
`/some_uri?name=FILENAME&offset=OFFSET`
- Initial OFFSET is `0`, and subsequent offsets are non-zero
- Each chunk gets appended to the file
- When the last chunk is POSTed, upload finishes
- POST data must not be encoded in any way, it it saved as-is
2020-12-09 00:26:17 +08:00
### mg\_http\_bauth()
```c
void mg_http_bauth(struct mg_connection *, const char *user, const char *pass);
```
Write a Basic `Authorization` header to the output buffer.
## Websocket
### struct mg\_ws\_message
```c
struct mg_ws_message {
struct mg_str data;
uint8_t flags; // Websocket message flags
};
```
### mg\_ws\_connect()
```c
struct mg_connection *mg_ws_connect(struct mg_mgr *, const char *url,
mg_event_handler_t fn, void *fn_data,
const char *fmt, ...);
```
Create client Websocket connection.
- `url` - specifies remote URL, e.g. `http://google.com`
- `opts` - MQTT options, with client ID, qos, etc
- `fn` - an event handler function
- `fn_data` - an arbitrary pointer, which will be passed as `fn_data` when an
event handler is called. This pointer is also stored in a connection
structure as `c->fn_data`
- `fmt` - printf-like format string for additional HTTP headers, or NULL
### mg\_ws\_upgrade()
```c
void mg_ws_upgrade(struct mg_connection *, struct mg_http_message *,
const char *fmt, ...);
2020-12-09 00:26:17 +08:00
```
Upgrade given HTTP connection to Websocket. The `fmt` is a printf-like
format string for the extra HTTP headers returned to the client in a
Websocket handshake. Set `fmt` to `NULL` if no extra headers needs to be passed.
2020-12-09 00:26:17 +08:00
### mg\_ws\_send()
```c
size_t mg_ws_send(struct mg_connection *, const char *buf, size_t len, int op);
```
Send `buf`, `len` to the websocket peer. `op` is the Websocket message type:
```c
#define WEBSOCKET_OP_CONTINUE 0
#define WEBSOCKET_OP_TEXT 1
#define WEBSOCKET_OP_BINARY 2
#define WEBSOCKET_OP_CLOSE 8
#define WEBSOCKET_OP_PING 9
#define WEBSOCKET_OP_PONG 10
```
## MQTT
### struct mg\_mqtt\_opts
```c
struct mg_mqtt_opts {
struct mg_str client_id;
struct mg_str will_topic;
struct mg_str will_message;
uint8_t qos; // Quality of service
bool will_retain; // Retain last will
bool clean; // Use clean session, 0 or 1
uint16_t keepalive; // Keep-alive timer in seconds
};
```
### struct mg\_mqtt\_message
```c
struct mg_mqtt_message {
struct mg_str topic;
struct mg_str data;
};
```
### mg\_mqtt\_connect()
```c
struct mg_connection *mg_mqtt_connect(struct mg_mgr *, const char *url,
struct mg_mqtt_opts *opts,
mg_event_handler_t fn, void *fn_data);
```
Create client MQTT connection.
- `url` - specifies remote URL, e.g. `http://google.com`
- `opts` - MQTT options, with client ID, qos, etc
- `fn` - an event handler function
- `fn_data` - an arbitrary pointer, which will be passed as `fn_data` when an
event handler is called. This pointer is also stored in a connection
structure as `c->fn_data`
### mg\_mqtt\_pub()
```c
void mg_mqtt_pub(struct mg_connection *, struct mg_str *topic,
struct mg_str *data);
```
Publish message `data` to the topic `topic`.
### mg\_mqtt\_sub()
```c
void mg_mqtt_sub(struct mg_connection *, struct mg_str *topic);
```
Subscribe to topic `topic`.
2021-03-09 19:29:53 +08:00
### mg\_mqtt\_next\_sub()
```c
int mg_mqtt_next_sub(struct mg_mqtt_message *msg, struct mg_str *topic,
uint8_t *qos, int pos);
```
Traverse list of subscribed topics.
Used to implement MQTT server when `MQTT_CMD_SUBSCRIBE` is received.
Return next position. Initial position `pos` should be 4. Example:
```c
if (ev == MG_EV_MQTT_CMD) {
struct mg_mqtt_message *mm = (struct mg_mqtt_message *) ev_data;
if (mm->cmd == MQTT_CMD_SUBSCRIBE) {
int pos = 4;
uint8_t qos;
struct mg_str topic;
while ((pos = mg_mqtt_next_sub(mm, &topic, &qos, pos)) > 0) {
2021-03-10 01:44:15 +08:00
LOG(LL_INFO, ("SUB [%.*s]", (int) topic.len, topic.ptr));
2021-03-09 19:29:53 +08:00
}
}
}
```
### mg\_mqtt\_next\_unsub()
```c
int mg_mqtt_next_unsub(struct mg_mqtt_message *msg, struct mg_str *topic,
int pos);
```
Same as `mg_mqtt_next_sub()`, but for unsubscribed topics. The difference
is that there is no QoS in unsubscribe request.
2020-12-09 00:26:17 +08:00
## TLS
2021-01-30 21:03:11 +08:00
### mg\_tls\_init()
2020-12-09 00:26:17 +08:00
```c
struct mg_tls_opts {
const char *ca; // CA certificate file. For both listeners and clients
const char *cert; // Certificate
const char *certkey; // Certificate key
const char *ciphers; // Cipher list
2021-01-30 21:03:11 +08:00
struct mg_str srvname; // If not empty, enables server name verification
2020-12-09 00:26:17 +08:00
};
int mg_tls_init(struct mg_connection *c, struct mg_tls_opts *opts);
```
2021-01-30 21:03:11 +08:00
Initialise TLS on a given connection.
2020-12-09 00:26:17 +08:00
## Timers
### struct mg\_timer
```c
struct mg_timer {
int period_ms; // Timer period in milliseconds
int flags; // Possible flags values below
#define MG_TIMER_REPEAT 1 // Call function periodically, otherwise run once
#define MG_TIMER_RUN_NOW 2 // Call immediately when timer is set
void (*fn)(void *); // Function to call
void *arg; // Function agrument
unsigned long expire; // Expiration timestamp in milliseconds
struct mg_timer *next; // Linkage in g_timers list
};
```
Timer structure.
### mg\_timer\_init()
```c
void mg_timer_init(struct mg_timer *, int ms, int flags, void (*fn)(void *), void *fn_data);
```
Setup a timer.
- `ms` - an interval in milliseconds
- `flags` - timer flags bitmask, `MG_TIMER_REPEAT` and `MG_TIMER_RUN_NOW`
- `fn` - function to invoke
- `fn_data` - function argument
A timer gets initialised and linked into the `g_timers` list:
```c
struct mg_timer *g_timers;
```
### mg\_timer\_free()
```c
void mg_timer_free(struct mg_timer *);
```
Free timer, remove it from the `g_timers` list.
### mg\_timer\_poll()
```c
void mg_timer_poll(unsigned long uptime_ms);
```
Traverse list of timers, and call them if current timestamp `uptime_ms` is
past the timer's expiration time.
## Utility functions
### mg\_file\_read()
```c
char *mg_file_read(const char *path);
```
Read file contents into a nul-terminated malloc-ed string. It is a caller's
responsibility to free() a returned pointer.
### mg\_file\_size()
```c
size_t mg_file_size(const char *path);
```
Return file size, or 0 on failure. Empty files also report 0 length.
### mg\_file\_write()
```c
2021-01-27 00:30:44 +08:00
bool mg_file_write(const char *path, const void *buf, size_t len);
```
Write data to a file, return `true` if written, `false` otherwise.
The write is atomic, i.e. data gets written to a temporary file first,
then `rename()-ed` to a destination file name.
### mg\_file\_printf()
```c
int mg_file_printf(const char *path, const char *fmt, ...);
2020-12-09 00:26:17 +08:00
```
2021-01-27 00:30:44 +08:00
Write into a file `path` using `printf()` semantics.
Return `true` on success, `false` otherwise. This function prints data to
a temporary in-memory buffer first, then calls `mg_file_write()`.
2020-12-09 00:26:17 +08:00
### mg\_random()
```c
void mg_random(void *buf, size_t len);
```
Fill in buffer `buf`, `len` with random data.
### mg\_globmatch()
```c
bool mg_globmatch(const char *pattern, int plen, const char *s, int n);
```
Return true if string `s`, `n` matches glob pattern `pattern`, `plen`.
The glob pattern matching rules are as follows:
- `?` matches any single character
- `*` matches zero or more characters except `/`
- `#` matches zero or more characters
- any other caracter matches itself
### mg\_next\_comma\_entry()
```c
bool mg_next_comma_entry(struct mg_str *s, struct mg_str *k, struct mg_str *v);
```
Parse string `s`, which is a comma-separated list of entries. An entry could be
either an arbitrary string, which gets stored in `v`, or a `KEY=VALUE` which
gets stored in `k` and `v` respectively.
IMPORTANT: this function modifies `s` by pointing to the next entry. Usage
example:
```c
struct mg_str k, v, s = mg_str("a=333,b=777");
while (mg_next_comma_entry(&s, &k, &v)) // This loop output:
printf("[%.*s] set to [%.*s]\n", // [a] set to [333]
(int) k.len, k.ptr, (int) v.len, v.ptr); // [b] set to [777]
```
### mg\_ntohs()
```c
uint16_t mg_ntohs(uint16_t net);
```
Convert `uint16_t` value to host order.
### mg\_ntohl()
```c
uint32_t mg_ntohl(uint32_t net);
```
Convert `uint32_t` value to host order.
### mg\_hexdump()
```c
char *mg_hexdump(const void *buf, int len);
```
Hexdump binary data `buf`, `len` into malloc-ed buffer and return it.
It is a caller's responsibility to free() returned pointer.
### mg\_hex()
```c
char *mg_hex(const void *buf, int len, char *dst);
```
Hex-encode binary data `buf`, `len` into a buffer `dst` and nul-terminate it.
The output buffer must be at least 2 x `len` + 1 big.
Return value: `dst` pointer. The encoded characters are lowecase,
for example `mg_hex("hi", 2, buf)` outputs `6869` and 0 byte, 5 bytes overall.
### mg\_unhex()
```c
void mg_unhex(const char *buf, int len, unsigned char *to);
```
Hex-decode string `buf`, `len` into a buffer `to`. The `to` buffer should be
at least `lsn` / 2 big.
### mg\_unhexn()
```c
unsigned long mg_unhexn(const char *s, int len);
```
Parse `len` characters of the hex-encoded string `s`, return parsed value.
The maximum value of `len` is the width of the `long` x 2, for example
on 32-bit platforms it is 8.
### mg\_asprintf()
```c
int mg_asprintf(char **buf, size_t size, const char *fmt, ...);
```
Print message specified by printf-like format string `fmt` into a buffer
pointed by `buf` of size `size`. If `size` is large enough to hold the whole
message, then a message is stored in `*buf`. If it does not fit, then
a large enough buffer is allocated to hold a message, and `buf` is changed to
point to that buffer. Return value: number of bytes printed.
### mg\_vasprintf()
```c
int mg_vasprintf(char **buf, size_t size, const char *fmt, va_list ap);
```
Same as `mg_asprintf()` but uses `va_list` argument.
### mg\_to64()
```
int64_t mg_to64(const char *s);
```
Parse 64-bit integer value held by string `s`.
### mg\_aton()
```
2020-12-21 00:55:33 +08:00
bool mg_aton(struct mg_str str, uint32_t *ipaddr);
2020-12-09 00:26:17 +08:00
```
2020-12-21 00:55:33 +08:00
Parse IP address held by `str` and store it in `ipaddr`. Return true on success.
2020-12-09 00:26:17 +08:00
### mg\_ntoa()
```c
2020-12-21 00:55:33 +08:00
char *mg_ntoa(const struct mg_addr *, char *buf, size_t len);
2020-12-09 00:26:17 +08:00
```
Stringify IP address `ipaddr` into a buffer `buf`, `len`. Return `buf`.
### mg\_time()
```
double mg_time(void);
```
Return current time as UNIX epoch, using `double` value for sub-second accuracy.
### mg\_millis()
```c
unsigned long mg_millis(void);
```
Return current uptime in milliseconds.
### mg\_usleep()
```c
void mg_usleep(unsigned long usecs);
```
Block for a given number of microseconds.
### mg\_crc32()
```c
uint32_t mg_crc32(uint32_t crc, const uint8_t *buf, size_t len);
```
Calculate CRC32 checksum for a given buffer. An initial `crc` value should
be `0`.