Mongoose

Usage Example

  1. Copy mongoose.c and mongoose.h to your build tree

  2. Write code that uses Mongoose API, e.g. in my_app.c

  3. Compile application: $ cc my_app.c mongoose.c

my_app.c
#include "mongoose.h"  1

  static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) { 2
  struct iobuf *io = &nc->recv_iobuf;

  switch (ev) {
  case MG_EV_RECV:
  // This event handler implements simple TCP echo server
  mg_send(nc, io->buf, io->len);  // Echo received data back
  iobuf_remove(io, io->len);      // Discard data from recv buffer
  break;
  default:
  break;
  }
  }

  int main(void) {
  struct mg_mgr mgr;

  mg_mgr_init(&mgr, NULL);  3

  // Note that many connections can be added to a single event manager
  // Connections can be created at any point, e.g. in event handler function
  mg_bind(&mgr, "1234", ev_handler, NULL);  4

  for (;;) {  5
  mg_mgr_poll(&mgr, 1000);
  }

  mg_mgr_free(&mgr);
  return 0;
  }
1 Include Mongoose API definitions
2 Define an event handler function
3 Initialize event manager object
4 Create listening connection and add it to the event manager
5 Start infinite event loop

Design Concept

Mongoose is a multi-protocol networking library that implements non-blocking, asyncronous IO and provides event-based API. It has three basic data structures:

Connections could be either listening, outbound or inbound. Outbound connections are created by mg_connect() call. Listening connections are created by mg_bind() call. Inbound connections are those accepted by a listening connection. Each connection is described by struct mg_connection structure, which has a number of fields like socket, event handler function, send/receive buffer, flags, et cetera.

Mongoose usage pattern is to declare and initialize event manager, create connections and create an event loop by calling mg_mgr_poll() in a loop. 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.

Memory buffers

Each connection has send and receive buffer, struct mg_connection::send_mbuf and struct mg_connection::recv_mbuf respectively. When data arrives, Mongoose appends received data to the recv_mbuf and triggers MG_EV_RECV event. 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_mbuf. When Mongoose successfully writes data to the socket, it discards data from mg_connection::send_mbuf and sends MG_EV_SEND event. When connection is closed, MG_EV_CLOSE event is sent.

mbuf

Event handler function

Each connection has an event handler function associated with it. That function must be implemented by user. Event handler is the key element of the Mongoose application, since it defines application’s behavior. This is how an event handler function looks like:

static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) {
  switch (ev) {
  /* Event handler code that defines behavior of the connection */
  ...
  }
  }
struct mg_connection *nc

Connection that has received an event.

int ev

Event number, defined in mongoose.h. For example, when data arrives on inbound connection ev would be MG_EV_RECV.

void *ev_data

This pointer points to the event-specific data, and it has different meaning for different events. For example, for MG_EV_RECV event, ev_data is an int * pointer, pointing to the number of bytes received from the remote peer and saved into the receive IO buffer. 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.

Note struct mg_connection has void *user_data which is a placeholder for a application-specific data. Mongoose does not use that pointer. Event handler can store any kind of information there.

Events

Mongoose accepts incoming connections, reads and writes data, and calls specified event handler for each connection when appropriate. Typical event sequence is this:

  • For outbound connection: MG_EV_CONNECT → (MG_EV_RECV, MG_EV_SEND, MG_EV_POLL …​) → MG_EV_CLOSE

  • For inbound connection: MG_EV_ACCEPT → (MG_EV_RECV, MG_EV_SEND, MG_EV_POLL …​) → MG_EV_CLOSE

Below is a list of core events triggered by Mongoose (note that each protocol triggers protocol-specific events in addition to the core ones):

MG_EV_ACCEPT

sent when new server connection is accepted by a listening connection. void *ev_data is union socket_address of the remote peer.

MG_EV_CONNECT

sent when a new outbound connection created by mg_connect() either failed or succeeded. void *ev_data is int *success. If success is 0, then connection has been established, otherwise it contains error code. See mg_connect_opt() function for code example.

MG_EV_RECV

New data is received and appended to the end of recv_mbuf. void *ev_data is int *num_received_bytes. Typically, event handler should check received data in nc→recv_mbuf, discard processed data by calling mbuf_remove(), set connection flags nc→flags if necessary (see struct mg_connection), and write data the remote peer by output functions like mg_send().

Warning Mongoose uses realloc() to expand receive buffer. It is user’s responsibility to discard processed data from the beginning of receive buffer, note the mbuf_remove() call in the example above.
MG_EV_SEND

Mongoose has written data to the remote peer and discarded written data from the mg_connection::send_mbuf. void *ev_data is int *num_sent_bytes.

Note Mongoose output functions only append data to the mg_connection::send_mbuf, they do not do any socket writes. An actual IO is done by mg_mgr_poll(). MG_EV_SEND event is just a notification about an IO has been done.
MG_EV_POLL

Sent to all connections on each invocation of mg_mgr_poll(). This event could be used to do any housekeeping, for example check whether certain timeout has expired and close the connection, or send heartbeet message, et cetera.

Connection flags

Each connection has a flags bit field. Some flags are set by Mongoose, for example if a user creates an outbound UDP connection using udp://1.2.3.4:5678 address, Mongoose is going to set MG_F_UDP flag for that connection. Other flags are meant to be set only by user event handler to tell Mongoose how to behave. Below is a list of connection flags that are meant to be set by event handlers:

  • MG_F_FINISHED_SENDING_DATA tells Mongoose that all data has been appended to the send_mbuf. As soon as Mongoose sends it to the socket, the connection will be closed.

  • MG_F_BUFFER_BUT_DONT_SEND tells Mongoose to append data to the send_mbuf but hold on sending it, because the data will be modified later and then will be sent by clearing MG_F_BUFFER_BUT_DONT_SEND flag.

  • MG_F_CLOSE_IMMEDIATELY tells Mongoose to close the connection immediately, usually after some error

  • MG_F_USER_1, MG_F_USER_2, MG_F_USER_3, MG_F_USER_4 could be used by a developer to store application-specific state

Flags below are set by Mongoose:

  • MG_F_SSL_HANDSHAKE_DONE SSL only, set when SSL handshake is done.

  • MG_F_CONNECTING set when connection is in connecting state after mg_connect() call but connect did not finish yet.

  • MG_F_LISTENING set for all listening connections

  • MG_F_UDP set if connection is UDP

  • MG_F_IS_WEBSOCKET set if connection is a Websocket connection

  • MG_F_WEBSOCKET_NO_DEFRAG should be set by a user if user wants to switch off automatic Websocket frame defragmentation

Build Options

Mongoose source code ships in a single .c file that contains functionality for all supported protocols (modules). Modules can be disabled at compile time which reduces executable size. That can be done by setting preprocessor flags. Also, some preprocessor flags can be used to tune internal Mongoose parameters.

To set a preprocessor flag during compile time, use -D <PREPROCESSOR_FLAG> compiler option. For example, to disable both MQTT and JSON-RPC, compile the application my_app.c like this (assumed UNIX system):

  $ cc my_app.c mongoose.c -D MG_DISABLE_MQTT -D MG_DISABLE_JSON_RPC

Enabling flags

  • MG_ENABLE_SSL Enable OpenSSL support

  • MG_ENABLE_IPV6 Enable IPV6 support

  • MG_ENABLE_THREADS enable mg_start_thread() API

  • MG_ENABLE_MQTT_BROKER enable MQTT broker

  • MG_ENABLE_DNS_SERVER enable DNS server

  • MG_ENABLE_COAP enable CoAP protocol

  • MG_ENABLE_GETADDRINFO enable getaddrinfo() in mg_resolve2()

Disabling flags

  • MG_DISABLE_HTTP_WEBSOCKET disable HTTP + Websocket protocol support

  • MG_DISABLE_HTTP_DIGEST_AUTH disable HTTP Digest (MD5) authorization support

  • MG_DISABLE_MQTT disable MQTT support

  • MG_DISABLE_SHA1 disable SHA1 support (used by Websocket)

  • MG_DISABLE_MD5 disable MD5 support (used by HTTP auth)

  • MG_DISABLE_JSON_RPC disable JSON-RPC support

  • MG_DISABLE_SOCKETPAIR disable mg_broadcast() API

Tunables

  • MG_MALLOC, MG_CALLOC, MG_REALLOC, MG_FREE allow to use custom memory allocator, e.g. -DMG_MALLOC=my_malloc

  • MG_USE_READ_WRITE when set replaces calls to recv with read and send with write, thus enabling to add any kind of file descriptor (files, serial devices) to an event manager.

  • MG_SSL_CRYPTO_MODERN, MG_SSL_CRYPTO_OLD - choose either "Modern" or "Old" ciphers instead of the default "Intermediate" setting. See [this article](https://wiki.mozilla.org/Security/Server_Side_TLS#Recommended_configurations) for details.

API Reference

Memory Buffers

Mbufs are mutable/growing memory buffers, like C++ strings. Mbuf can append data to the end of a buffer, or insert data into arbitrary position in the middle of a buffer. The buffer grows automatically when needed.

struct mbuf

struct mbuf {
  char *buf;   /* Buffer pointer */
  size_t len;  /* Data length. Data is located between offset 0 and len. */
  size_t size; /* Buffer size allocated by realloc(1). Must be >= len */
  };

Memory buffer descriptor

mbuf_init()

void mbuf_init(struct mbuf *, size_t initial_capacity);

Initialize an Mbuf. initial_capacity specifies the initial capacity of the mbuf.

mbuf_free()

void mbuf_free(struct mbuf *);

Free the space allocated for the mbuffer and resets the mbuf structure.

mbuf_append()

size_t mbuf_append(struct mbuf *, const void *data, size_t data_size);

Appends data to the Mbuf.

Return the number of bytes appended, or 0 if out of memory.

mbuf_insert()

size_t mbuf_insert(struct mbuf *, size_t, const void *, size_t);

Insert data at a specified offset in the Mbuf.

Existing data will be shifted forwards and the buffer will be grown if necessary. Return the number of bytes inserted.

mbuf_remove()

void mbuf_remove(struct mbuf *, size_t data_size);

Remove data_size bytes from the beginning of the buffer.

mbuf_resize()

void mbuf_resize(struct mbuf *, size_t new_size);

Resize an Mbuf.

If new_size is smaller than buffer’s len, the resize is not performed.

mbuf_trim()

void mbuf_trim(struct mbuf *);

Shrink an Mbuf by resizing its size to len.

Core: TCP/UDP/SSL

Note Mongoose manager is single threaded. It does not protect its data structures by mutexes, therefore all functions that are dealing with particular event manager should be called from the same thread, with exception of mg_broadcast() function. It is fine to have different event managers handled by different threads.

struct mg_str

struct mg_str {
  const char *p; /* Memory chunk pointer */
  size_t len;    /* Memory chunk length */
  };

Describes chunk of memory

struct mg_mgr

struct mg_mgr {
  struct mg_connection *active_connections;
  const char *hexdump_file; /* Debug hexdump file path */
  sock_t ctl[2];            /* Socketpair for mg_wakeup() */
  void *user_data;          /* User data */
  void *mgr_data;           /* Implementation-specific event manager's data. */
  #ifdef MG_ENABLE_JAVASCRIPT
  struct v7 *v7;
  #endif
  };

Mongoose event manager.

struct mg_connection

struct mg_connection {
  struct mg_connection *next, *prev; /* mg_mgr::active_connections linkage */
  struct mg_connection *listener;    /* Set only for accept()-ed connections */
  struct mg_mgr *mgr;                /* Pointer to containing manager */

  sock_t sock;             /* Socket to the remote peer */
  union socket_address sa; /* Remote peer address */
  size_t recv_mbuf_limit;  /* Max size of recv buffer */
  struct mbuf recv_mbuf;   /* Received data */
  struct mbuf send_mbuf;   /* Data scheduled for sending */
  SSL *ssl;
  SSL_CTX *ssl_ctx;
  time_t last_io_time;              /* Timestamp of the last socket IO */
  mg_event_handler_t proto_handler; /* Protocol-specific event handler */
  void *proto_data;                 /* Protocol-specific data */
  mg_event_handler_t handler;       /* Event handler function */
  void *user_data;                  /* User-specific data */
  void *priv_1;                     /* Used by mg_enable_multithreading() */
  void *priv_2;                     /* Used by mg_enable_multithreading() */
  void *mgr_data; /* Implementation-specific event manager's data. */

  unsigned long flags;
  /* Flags set by Mongoose */
  #define MG_F_LISTENING (1 << 0)          /* This connection is listening */
  #define MG_F_UDP (1 << 1)                /* This connection is UDP */
  #define MG_F_RESOLVING (1 << 2)          /* Waiting for async resolver */
  #define MG_F_CONNECTING (1 << 3)         /* connect() call in progress */
  #define MG_F_SSL_HANDSHAKE_DONE (1 << 4) /* SSL specific */
  #define MG_F_WANT_READ (1 << 5)          /* SSL specific */
  #define MG_F_WANT_WRITE (1 << 6)         /* SSL specific */
  #define MG_F_IS_WEBSOCKET (1 << 7)       /* Websocket specific */

  /* Flags that are settable by user */
  #define MG_F_SEND_AND_CLOSE (1 << 10)      /* Push remaining data and close  */
  #define MG_F_DONT_SEND (1 << 11)           /* Do not send data to peer */
  #define MG_F_CLOSE_IMMEDIATELY (1 << 12)   /* Disconnect */
  #define MG_F_WEBSOCKET_NO_DEFRAG (1 << 13) /* Websocket specific */
  #define MG_F_DELETE_CHUNK (1 << 14)        /* HTTP specific */

  #define MG_F_USER_1 (1 << 20) /* Flags left for application */
  #define MG_F_USER_2 (1 << 21)
  #define MG_F_USER_3 (1 << 22)
  #define MG_F_USER_4 (1 << 23)
  #define MG_F_USER_5 (1 << 24)
  #define MG_F_USER_6 (1 << 25)
  };

Mongoose connection.

struct mg_add_sock_opts

struct mg_add_sock_opts {
  void *user_data;           /* Initial value for connection's user_data */
  unsigned int flags;        /* Initial connection flags */
  const char **error_string; /* Placeholder for the error string */
  };

Optional parameters to mg_add_sock_opt() flags is an initial struct mg_connection::flags bitmask to set, see MG_F_* flags definitions.

struct mg_bind_opts

struct mg_bind_opts {
  void *user_data;           /* Initial value for connection's user_data */
  unsigned int flags;        /* Extra connection flags */
  const char **error_string; /* Placeholder for the error string */
  };

Optional parameters to mg_bind_opt() flags is an initial struct mg_connection::flags bitmask to set, see MG_F_* flags definitions.

struct mg_connect_opts

struct mg_connect_opts {
  void *user_data;           /* Initial value for connection's user_data */
  unsigned int flags;        /* Extra connection flags */
  const char **error_string; /* Placeholder for the error string */
  };

Optional parameters to mg_connect_opt()

mg_mgr_init()

void mg_mgr_init(struct mg_mgr *mgr, void *user_data);

Initialize Mongoose manager. Side effect: ignores SIGPIPE signal. mgr→user_data field will be initialized with user_data parameter. That is an arbitrary pointer, where user code can associate some data with the particular Mongoose manager. For example, a C++ wrapper class could be written, in which case user_data can hold a pointer to the class instance.

mg_mgr_free()

void mg_mgr_free(struct mg_mgr *);

De-initializes Mongoose manager.

Close and deallocate all active connections.

mg_mgr_poll()

time_t mg_mgr_poll(struct mg_mgr *, int milli);

This function performs the actual IO, and must be called in a loop (an event loop). Returns the current timestamp. milli is the maximum number of milliseconds to sleep. mg_mgr_poll() checks all connection for IO readiness. If at least one of the connections is IO-ready, mg_mgr_poll() triggers respective event handlers and returns.

mg_broadcast()

void mg_broadcast(struct mg_mgr *, mg_event_handler_t func, void *, size_t);

Pass a message of a given length to all connections.

Must be called from a thread that does NOT call mg_mgr_poll(). Note that mg_broadcast() is the only function that can be, and must be, called from a different (non-IO) thread.

func callback function will be called by the IO thread for each connection. When called, event would be MG_EV_POLL, and message will be passed as ev_data pointer. Maximum message size is capped by MG_CTL_MSG_MESSAGE_SIZE which is set to 8192 bytes.

mg_next()

struct mg_connection *mg_next(struct mg_mgr *, struct mg_connection *);

Iterate over all active connections.

Returns next connection from the list of active connections, or NULL if there is no more connections. Below is the iteration idiom:

for (c = mg_next(srv, NULL); c != NULL; c = mg_next(srv, c)) {
  // Do something with connection `c`
  }

mg_add_sock()

struct mg_connection *mg_add_sock(struct mg_mgr *, sock_t, mg_event_handler_t);

Create a connection, associate it with the given socket and event handler, and add it to the manager.

For more options see the mg_add_sock_opt variant.

mg_add_sock_opt()

struct mg_connection *mg_add_sock_opt(struct mg_mgr *, sock_t,
  mg_event_handler_t,
  struct mg_add_sock_opts);

Create a connection, associate it with the given socket and event handler, and add to the manager.

See the mg_add_sock_opts structure for a description of the options.

mg_bind()

struct mg_connection *mg_bind(struct mg_mgr *, const char *,
  mg_event_handler_t);

Create listening connection.

See mg_bind_opt for full documentation.

mg_bind_opt()

struct mg_connection *mg_bind_opt(struct mg_mgr *, const char *,
  mg_event_handler_t, struct mg_bind_opts);

Create listening connection.

address parameter tells which address to bind to. It’s format is the same as for the mg_connect() call, where HOST part is optional. address can be just a port number, e.g. :8000. To bind to a specific interface, an IP address can be specified, e.g. 1.2.3.4:8000. By default, a TCP connection is created. To create UDP connection, prepend udp:// prefix, e.g. udp://:8000. To summarize, address paramer has following format: [PROTO://][IP_ADDRESS]:PORT, where PROTO could be tcp or udp.

See the mg_bind_opts structure for a description of the optional parameters.

Return a new listening connection, or NULL on error. NOTE: Connection remains owned by the manager, do not free().

mg_connect()

struct mg_connection *mg_connect(struct mg_mgr *, const char *,
  mg_event_handler_t);

Connect to a remote host.

See mg_connect_opt() for full documentation.

mg_connect_opt()

struct mg_connection *mg_connect_opt(struct mg_mgr *, const char *,
  mg_event_handler_t,
  struct mg_connect_opts);

Connect to a remote host.

address format is [PROTO://]HOST:PORT. PROTO could be tcp or udp. HOST could be an IP address, IPv6 address (if Mongoose is compiled with -DMG_ENABLE_IPV6), or a host name. If HOST is a name, Mongoose will resolve it asynchronously. Examples of valid addresses: google.com:80, udp://1.2.3.4:53, 10.0.0.1:443, [::1]:80

See the mg_connect_opts structure for a description of the optional parameters.

Returns a new outbound connection, or NULL on error.

Note Connection remains owned by the manager, do not free().
Note To enable IPv6 addresses, -DMG_ENABLE_IPV6 should be specified in the compilation flags.
Note New connection will receive MG_EV_CONNECT as it’s first event which will report connect success status. If asynchronous resolution fail, or connect() syscall fail for whatever reason (e.g. with ECONNREFUSED or ENETUNREACH), then MG_EV_CONNECT event report failure. Code example below:
static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) {
  int connect_status;

  switch (ev) {
  case MG_EV_CONNECT:
  connect_status = * (int *) ev_data;
  if (connect_status == 0) {
  // Success
  } else  {
  // Error
  printf("connect() error: %s\n", strerror(connect_status));
  }
  break;
  ...
  }
  }

  ...
  mg_connect(mgr, "my_site.com:80", ev_handler);

mg_set_ssl()

const char *mg_set_ssl(struct mg_connection *nc, const char *cert,
  const char *ca_cert);

Enable SSL for a given connection. cert is a server certificate file name for a listening connection, or a client certificate file name for an outgoing connection. Certificate files must be in PEM format. Server certificate file must contain a certificate, concatenated with a private key, optionally concatenated with parameters. ca_cert is a CA certificate, or NULL if peer verification is not required. Return: NULL on success, or error message on error.

mg_send()

int mg_send(struct mg_connection *, const void *buf, int len);

Send data to the connection.

Return number of written bytes. Note that sending functions do not actually push data to the socket. They just append data to the output buffer. The exception is UDP connections. For UDP, data is sent immediately, and returned value indicates an actual number of bytes sent to the socket.

mg_printf()

int mg_printf(struct mg_connection *, const char *fmt, ...);

Send printf-style formatted data to the connection.

See mg_send for more details on send semantics.

mg_vprintf()

int mg_vprintf(struct mg_connection *, const char *fmt, va_list ap);

Same as mg_printf(), but takes va_list ap as an argument.

mg_socketpair()

int mg_socketpair(sock_t[2], int sock_type);

Create a socket pair. sock_type can be either SOCK_STREAM or SOCK_DGRAM. Return 0 on failure, 1 on success.

mg_resolve()

int mg_resolve(const char *domain_name, char *ip_addr_buf, size_t buf_len);

Convert domain name into IP address.

This is a utility function. If compilation flags have -DMG_ENABLE_GETADDRINFO, then getaddrinfo() call is used for name resolution. Otherwise, gethostbyname() is used.

Caution this function can block. Return 1 on success, 0 on failure.

mg_check_ip_acl()

int mg_check_ip_acl(const char *acl, uint32_t remote_ip);

Verify given IP address against the ACL.

remote_ip - an IPv4 address to check, in host byte order acl - a comma separated list of IP subnets: x.x.x.x/x or x.x.x.x. Each subnet is prepended by either a - or a + sign. A plus sign means allow, where a minus sign means deny. If a subnet mask is omitted, such as -1.2.3.4, this means to deny only that single IP address. Subnet masks may vary from 0 to 32, inclusive. The default setting is to allow all accesses. On each request the full list is traversed, and the last match wins. Example:

-0.0.0.0/0,+192.168/16 - deny all acccesses, only allow 192.168/16 subnet

To learn more about subnet masks, see the Wikipedia page on Subnetwork

Return -1 if ACL is malformed, 0 if address is disallowed, 1 if allowed.

mg_enable_multithreading()

void mg_enable_multithreading(struct mg_connection *nc);

Enable multi-threaded handling for the given listening connection nc. For each accepted connection, Mongoose will create a separate thread and run event handler in that thread. Thus, if an event hanler is doing a blocking call or some long computation, that will not slow down other connections.

mg_enable_javascript()

enum v7_err mg_enable_javascript(struct mg_mgr *m, struct v7 *v7,
  const char *init_js_file_name);

Enable server-side JavaScript scripting. Requires -DMG_ENABLE_JAVASCRIPT compilation flag, and V7 engine sources. v7 instance must not be destroyed during manager’s lifetime. Return V7 error.

HTTP + Websocket

struct http_message

struct http_message {
  struct mg_str message; /* Whole message: request line + headers + body */

  struct mg_str proto; /* "HTTP/1.1" -- for both request and response */
  /* HTTP Request line (or HTTP response line) */
  struct mg_str method; /* "GET" */
  struct mg_str uri;    /* "/my_file.html" */
  /* For responses, code and response status message are set */
  int resp_code;
  struct mg_str resp_status_msg;

  /*
     * Query-string part of the URI. For example, for HTTP request
     *    GET /foo/bar?param1=val1&param2=val2
     *    |    uri    |     query_string     |
     *
     * Note that question mark character doesn't belong neither to the uri,
     * nor to the query_string
     */
  struct mg_str query_string;

  /* Headers */
  struct mg_str header_names[MG_MAX_HTTP_HEADERS];
  struct mg_str header_values[MG_MAX_HTTP_HEADERS];

  /* Message body */
  struct mg_str body; /* Zero-length for requests with no body */
  };

HTTP message

struct mg_serve_http_opts

struct mg_serve_http_opts {
  /* Path to web root directory */
  const char *document_root;

  /* List of index files. Default is "" */
  const char *index_files;

  /*
     * Leave as NULL to disable authentication.
     * To enable directory protection with authentication, set this to ".htpasswd"
     * Then, creating ".htpasswd" file in any directory automatically protects
     * it with digest authentication.
     * Use `mongoose` web server binary, or `htdigest` Apache utility to
     * create/manipulate passwords file.
     * Make sure `auth_domain` is set to a valid domain name.
     */
  const char *per_directory_auth_file;

  /* Authorization domain (domain name of this web server) */
  const char *auth_domain;

  /*
     * Leave as NULL to disable authentication.
     * Normally, only selected directories in the document root are protected.
     * If absolutely every access to the web server needs to be authenticated,
     * regardless of the URI, set this option to the path to the passwords file.
     * Format of that file is the same as ".htpasswd" file. Make sure that file
     * is located outside document root to prevent people fetching it.
     */
  const char *global_auth_file;

  /* Set to "no" to disable directory listing. Enabled by default. */
  const char *enable_directory_listing;

  /* SSI files pattern. If not set, "**.shtml$|**.shtm$" is used. */
  const char *ssi_pattern;

  /* IP ACL. By default, NULL, meaning all IPs are allowed to connect */
  const char *ip_acl;

  /* URL rewrites.
     *
     * Comma-separated list of `uri_pattern=file_or_directory_path` rewrites.
     * When HTTP request is received, Mongoose constructs a file name from the
     * requested URI by combining `document_root` and the URI. However, if the
     * rewrite option is used and `uri_pattern` matches requested URI, then
     * `document_root` is ignored. Instead, `file_or_directory_path` is used,
     * which should be a full path name or a path relative to the web server's
     * current working directory. Note that `uri_pattern`, as all Mongoose
     * patterns, is a prefix pattern.
     *
     * If uri_pattern starts with `@` symbol, then Mongoose compares it with the
     * HOST header of the request. If they are equal, Mongoose sets document root
     * to `file_or_directory_path`, implementing virtual hosts support.
     */
  const char *url_rewrites;

  /* DAV document root. If NULL, DAV requests are going to fail. */
  const char *dav_document_root;

  /* Glob pattern for the files to hide. */
  const char *hidden_file_pattern;

  /* Set to non-NULL to enable CGI, e.g. **.cgi$|**.php$" */
  const char *cgi_file_pattern;

  /* If not NULL, ignore CGI script hashbang and use this interpreter */
  const char *cgi_interpreter;

  /*
     * Comma-separated list of Content-Type overrides for path suffixes, e.g.
     * ".txt=text/plain; charset=utf-8,.c=text/plain"
     */
  const char *custom_mime_types;
  };

This structure defines how mg_serve_http() works. Best practice is to set only required settings, and leave the rest as NULL.

mg_set_protocol_http_websocket()

void mg_set_protocol_http_websocket(struct mg_connection *nc);

Attach built-in HTTP event handler to the given connection. User-defined event handler will receive following extra events:

  • MG_EV_HTTP_REQUEST: HTTP request has arrived. Parsed HTTP request is passed *as struct http_message through the handler’s void *ev_data pointer.

  • MG_EV_HTTP_REPLY: HTTP reply has arrived. Parsed HTTP reply is passed as struct http_message through the handler’s void *ev_data pointer.

  • MG_EV_HTTP_CHUNK: HTTP chunked-encoding chunk has arrived. Parsed HTTP reply is passed as struct http_message through the handler’s void *ev_data pointer. http_message::body would contain incomplete, reassembled HTTP body. It will grow with every new chunk arrived, and potentially can consume a lot of memory. An event handler may process the body as chunks are coming, and signal Mongoose to delete processed body by setting MG_F_DELETE_CHUNK in mg_connection::flags. When the last zero chunk is received, Mongoose sends MG_EV_HTTP_REPLY event with full reassembled body (if handler did not signal to delete chunks) or with empty body (if handler did signal to delete chunks).

  • MG_EV_WEBSOCKET_HANDSHAKE_REQUEST: server has received websocket handshake request. ev_data contains parsed HTTP request.

  • MG_EV_WEBSOCKET_HANDSHAKE_DONE: server has completed Websocket handshake. ev_data is NULL.

  • MG_EV_WEBSOCKET_FRAME: new websocket frame has arrived. ev_data is struct websocket_message *

mg_send_websocket_handshake()

void mg_send_websocket_handshake(struct mg_connection *nc, const char *uri,
  const char *extra_headers);

Send websocket handshake to the server.

nc must be a valid connection, connected to a server. uri is an URI to fetch, extra_headers` is extra HTTP headers to send or NULL.

This function is intended to be used by websocket client.

mg_send_websocket_frame()

void mg_send_websocket_frame(struct mg_connection *nc, int op_and_flags,
  const void *data, size_t data_len);

Send websocket frame to the remote end.

op_and_flags specifies frame’s type, one of:

  • WEBSOCKET_OP_CONTINUE

  • WEBSOCKET_OP_TEXT

  • WEBSOCKET_OP_BINARY

  • WEBSOCKET_OP_CLOSE

  • WEBSOCKET_OP_PING

  • WEBSOCKET_OP_PONG

Orred with one of the flags:

  • WEBSOCKET_DONT_FIN: Don’t set the FIN flag on the frame to be sent.

data and data_len contain frame data.

mg_send_websocket_framev()

void mg_send_websocket_framev(struct mg_connection *nc, int op_and_flags,
  const struct mg_str *strings, int num_strings);

Send multiple websocket frames.

Like mg_send_websocket_frame(), but composes a frame from multiple buffers.

mg_printf_websocket_frame()

void mg_printf_websocket_frame(struct mg_connection *nc, int op_and_flags,
  const char *fmt, ...);

Send websocket frame to the remote end.

Like mg_send_websocket_frame(), but allows to create formatted message with printf()-like semantics.

mg_send_http_chunk()

void mg_send_http_chunk(struct mg_connection *nc, const char *buf, size_t len);

Send buffer buf of size len to the client using chunked HTTP encoding. This function first sends buffer size as hex number + newline, then buffer itself, then newline. For example, mg_send_http_chunk(nc, "foo", 3) whill append 3\r\nfoo\r\n string to the nc→send_mbuf output IO buffer.

Note HTTP header "Transfer-Encoding: chunked" should be sent prior to using this function.
Note do not forget to send empty chunk at the end of the response, to tell the client that everything was sent. Example:
  mg_printf_http_chunk(nc, "%s", "my response!");
  mg_send_http_chunk(nc, "", 0); // Tell the client we're finished

mg_printf_http_chunk()

void mg_printf_http_chunk(struct mg_connection *, const char *, ...);

Send printf-formatted HTTP chunk. Functionality is similar to mg_send_http_chunk().

mg_printf_html_escape()

void mg_printf_html_escape(struct mg_connection *, const char *, ...);

Send printf-formatted HTTP chunk, escaping HTML tags.

mg_parse_http()

int mg_parse_http(const char *s, int n, struct http_message *hm, int is_req);

Parse a HTTP message.

is_req should be set to 1 if parsing request, 0 if reply.

Return number of bytes parsed. If HTTP message is incomplete, 0 is returned. On parse error, negative number is returned.

mg_get_http_header()

struct mg_str *mg_get_http_header(struct http_message *hm, const char *name);

Search and return header name in parsed HTTP message hm. If header is not found, NULL is returned. Example:

struct mg_str *host_hdr = mg_get_http_header(hm, "Host");

mg_http_parse_header()

int mg_http_parse_header(struct mg_str *hdr, const char *var_name, char *buf,
  size_t buf_size);

Parse HTTP header hdr. Find variable var_name and store it’s value in the buffer buf, buf_size. Return 0 if variable not found, non-zero otherwise.

This function is supposed to parse cookies, authentication headers, etcetera. Example (error handling omitted):

char user[20];
struct mg_str *hdr = mg_get_http_header(hm, "Authorization");
mg_http_parse_header(hdr, "username", user, sizeof(user));

Return length of the variable’s value. If buffer is not large enough, or variable not found, 0 is returned.

mg_parse_multipart()

size_t mg_parse_multipart(const char *buf, size_t buf_len, char *var_name,
  size_t var_name_len, char *file_name,
  size_t file_name_len, const char **chunk,
  size_t *chunk_len);

Parse buffer buf, buf_len that contains multipart form data chunks. Store chunk name in a var_name, var_name_len buffer. If a chunk is an uploaded file, then file_name, file_name_len is filled with an uploaded file name. chunk, chunk_len points to the chunk data.

Return: number of bytes to skip to the next chunk, or 0 if there are no more chunks.

Usage example:

static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) {
  switch(ev) {
    case MG_EV_HTTP_REQUEST: {
      struct http_message *hm = (struct http_message *) ev_data;
      char var_name[100], file_name[100];
      const char *chunk;
      size_t chunk_len, n1, n2;
  n1 = n2 = 0;
  while ((n2 = mg_parse_multipart(hm->body.p + n1,
                                  hm->body.len - n1,
                                  var_name, sizeof(var_name),
                                  file_name, sizeof(file_name),
                                  &chunk, &chunk_len)) > 0) {
    printf("var: %s, file_name: %s, size: %d, chunk: [%.*s]\n",
           var_name, file_name, (int) chunk_len,
           (int) chunk_len, chunk);
    n1 += n2;
  }
}
break;

mg_get_http_var()

int mg_get_http_var(const struct mg_str *, const char *, char *dst, size_t);

Fetch an HTTP form variable.

Fetch a variable name from a buf into a buffer specified by dst, dst_len. Destination is always zero-terminated. Return length of a fetched variable. If not found, 0 is returned. buf must be valid url-encoded buffer. If destination is too small, -1 is returned.

mg_http_create_digest_auth_header()

int mg_http_create_digest_auth_header(char *buf, size_t buf_len,
  const char *method, const char *uri,
  const char *auth_domain, const char *user,
  const char *passwd);

Create Digest authentication header for client request.

mg_connect_http()

struct mg_connection *mg_connect_http(struct mg_mgr *,
  mg_event_handler_t event_handler,
  const char *url,
  const char *extra_headers,
  const char *post_data);

Helper function that creates outbound HTTP connection.

url is a URL to fetch. It must be properly URL-encoded, e.g. have no spaces, etc. By default, mg_connect_http() sends Connection and Host headers. extra_headers is an extra HTTP headers to send, e.g. "User-Agent: my-app\r\n". If post_data is NULL, then GET request is created. Otherwise, POST request is created with the specified POST data. Examples:

  nc1 = mg_connect_http(mgr, ev_handler_1, "http://www.google.com", NULL,
  NULL);
  nc2 = mg_connect_http(mgr, ev_handler_1, "https://github.com", NULL, NULL);
  nc3 = mg_connect_http(mgr, ev_handler_1, "my_server:8000/form_submit/",
  NULL, "var_1=value_1&var_2=value_2");

mg_serve_http()

void mg_serve_http(struct mg_connection *, struct http_message *,
  struct mg_serve_http_opts);

Serve given HTTP request according to the options.

Example code snippet:

web_server.c
static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) {
  struct http_message *hm = (struct http_message *) ev_data;
  struct mg_serve_http_opts opts = { .document_root = "/var/www" };  // C99

  switch (ev) {
  case MG_EV_HTTP_REQUEST:
  mg_serve_http(nc, hm, opts);
  break;
  default:
  break;
  }
  }

JSON-RPC

struct mg_rpc_request

struct mg_rpc_request {
  struct json_token *message; /* Whole RPC message */
  struct json_token *id;      /* Message ID */
  struct json_token *method;  /* Method name */
  struct json_token *params;  /* Method params */
  };

JSON-RPC request

struct mg_rpc_reply

struct mg_rpc_reply {
  struct json_token *message; /* Whole RPC message */
  struct json_token *id;      /* Message ID */
  struct json_token *result;  /* Remote call result */
  };

JSON-RPC response

struct mg_rpc_error

struct mg_rpc_error {
  struct json_token *message;       /* Whole RPC message */
  struct json_token *id;            /* Message ID */
  struct json_token *error_code;    /* error.code */
  struct json_token *error_message; /* error.message */
  struct json_token *error_data;    /* error.data, can be NULL */
  };

JSON-RPC error

mg_rpc_parse_reply()

int mg_rpc_parse_reply(const char *buf, int len, struct json_token *toks,
  int max_toks, struct mg_rpc_reply *,
  struct mg_rpc_error *);

Parse JSON-RPC reply contained in buf, len into JSON tokens array toks, max_toks. If buffer contains valid reply, reply structure is populated. The result of RPC call is located in reply.result. On error, error structure is populated. Returns: the result of calling parse_json(buf, len, toks, max_toks):

On success, an offset inside json_string is returned where parsing has finished. On failure, a negative number is returned, one of:

  • #define JSON_STRING_INVALID -1

  • #define JSON_STRING_INCOMPLETE -2

  • #define JSON_TOKEN_ARRAY_TOO_SMALL -3

mg_rpc_create_request()

int mg_rpc_create_request(char *buf, int len, const char *method,
  const char *id, const char *params_fmt, ...);

Create JSON-RPC request in a given buffer.

Return length of the request, which can be larger then len that indicates an overflow. params_fmt format string should conform to json_emit() API, see https://github.com/cesanta/frozen

mg_rpc_create_reply()

int mg_rpc_create_reply(char *buf, int len, const struct mg_rpc_request *req,
  const char *result_fmt, ...);

Create JSON-RPC reply in a given buffer.

Return length of the reply, which can be larger then len that indicates an overflow. result_fmt format string should conform to json_emit() API, see https://github.com/cesanta/frozen

mg_rpc_create_error()

int mg_rpc_create_error(char *buf, int len, struct mg_rpc_request *req,
  int code, const char *message, const char *fmt, ...);

Create JSON-RPC error reply in a given buffer.

Return length of the error, which can be larger then len that indicates an overflow. fmt format string should conform to json_emit() API, see https://github.com/cesanta/frozen

mg_rpc_create_std_error()

int mg_rpc_create_std_error(char *, int, struct mg_rpc_request *, int code);

Create JSON-RPC error in a given buffer.

Return length of the error, which can be larger then len that indicates an overflow. See JSON_RPC_*_ERROR definitions for standard error values:

  • #define JSON_RPC_PARSE_ERROR (-32700)

  • #define JSON_RPC_INVALID_REQUEST_ERROR (-32600)

  • #define JSON_RPC_METHOD_NOT_FOUND_ERROR (-32601)

  • #define JSON_RPC_INVALID_PARAMS_ERROR (-32602)

  • #define JSON_RPC_INTERNAL_ERROR (-32603)

  • #define JSON_RPC_SERVER_ERROR (-32000)

mg_rpc_dispatch()

int mg_rpc_dispatch(const char *buf, int, char *dst, int dst_len,
  const char **methods, mg_rpc_handler_t *handlers);

Dispatches a JSON-RPC request.

Parses JSON-RPC request contained in buf, len. Then, dispatches the request to the correct handler method. Valid method names should be specified in NULL terminated array methods, and corresponding handlers in handlers. Result is put in dst, dst_len. Return: length of the result, which can be larger then dst_len that indicates an overflow. Overflown bytes are not written to the buffer. If method is not found, an error is automatically generated.

DNS

struct mg_dmg_resource_record

struct mg_dmg_resource_record {
  struct mg_str name; /* buffer with compressed name */
  int rtype;
  int rclass;
  int ttl;
  enum mg_dmg_resource_record_kind kind;
  struct mg_str rdata; /* protocol data (can be a compressed name) */
  };

DNS resource record.

struct mg_dmg_message

struct mg_dmg_message {
  struct mg_str pkt; /* packet body */
  uint16_t flags;
  uint16_t transaction_id;
  int num_questions;
  int num_answers;
  struct mg_dmg_resource_record questions[MG_MAX_DNS_QUESTIONS];
  struct mg_dmg_resource_record answers[MG_MAX_DNS_ANSWERS];
  };

DNS message (request and response).

mg_dmg_parse_record_data()

int mg_dmg_parse_record_data(struct mg_dmg_message *,
  struct mg_dmg_resource_record *, void *, size_t);

Parse the record data from a DNS resource record.

  • A: struct in_addr *ina

  • AAAA: struct in6_addr *ina

  • CNAME: char buffer

Returns -1 on error.

TODO(mkm): MX

mg_send_dmg_query()

void mg_send_dmg_query(struct mg_connection *, const char *, int);

Send a DNS query to the remote end.

mg_dmg_insert_header()

int mg_dmg_insert_header(struct mbuf *, size_t, struct mg_dmg_message *);

Insert a DNS header to an IO buffer.

Return number of bytes inserted.

mg_dmg_copy_body()

int mg_dmg_copy_body(struct mbuf *, struct mg_dmg_message *);

Append already encoded body from an existing message.

This is useful when generating a DNS reply message which includes all question records.

Return number of appened bytes.

mg_dmg_encode_record()

int mg_dmg_encode_record(struct mbuf *, struct mg_dmg_resource_record *,
  const char *, size_t, const void *, size_t);

Encode and append a DNS resource record to an IO buffer.

The record metadata is taken from the rr parameter, while the name and data are taken from the parameters, encoded in the appropriate format depending on record type, and stored in the IO buffer. The encoded values might contain offsets within the IO buffer. It’s thus important that the IO buffer doesn’t get trimmed while a sequence of records are encoded while preparing a DNS *reply.

This function doesn’t update the name and rdata pointers in the rr *struct because they might be invalidated as soon as the IO buffer grows again.

Return the number of bytes appened or -1 in case of error.

mg_parse_dns()

int mg_parse_dns(const char *, int, struct mg_dmg_message *);

Low-level: parses a DNS response.

mg_dmg_uncompress_name()

size_t mg_dmg_uncompress_name(struct mg_dmg_message *, struct mg_str *, char *,
  int);

Uncompress a DNS compressed name.

The containing dns message is required because the compressed encoding and reference suffixes present elsewhere in the packet.

If name is less than dst_len characters long, the remainder of dst is terminated with \0' characters. Otherwise, `dst is not *terminated.

If dst_len is 0 dst can be NULL. Return the uncompressed name length.

mg_set_protocol_dns()

void mg_set_protocol_dns(struct mg_connection *);

Attach built-in DNS event handler to the given listening connection.

DNS event handler parses incoming UDP packets, treating them as DNS requests. If incoming packet gets successfully parsed by the DNS event handler, a user event handler will receive MG_DNS_REQUEST event, with ev_data pointing to the parsed struct mg_dmg_message.

See captive_dmg_server example on how to handle DNS request and send DNS reply.

DNS server

Disabled by default; enable with -DMG_ENABLE_DNS_SERVER.

mg_dmg_create_reply()

struct mg_dmg_reply mg_dmg_create_reply(struct mbuf *, struct mg_dmg_message *);

Create a DNS reply.

The reply will be based on an existing query message msg. The query body will be appended to the output buffer. "reply + recursion allowed" will be added to the message flags and message’s num_answers will be set to 0.

Answer records can be appended with mg_dmg_send_reply or by lower level function defined in the DNS API.

In order to send the reply use mg_dmg_send_reply. It’s possible to use a connection’s send buffer as reply buffers, and it will work for both UDP and TCP connections.

Example:

reply = mg_dmg_create_reply(&nc->send_mbuf, msg);
  for (i = 0; i < msg->num_questions; i++) {
  rr = &msg->questions[i];
  if (rr->rtype == MG_DNS_A_RECORD) {
  mg_dmg_reply_record(&reply, rr, 3600, &dummy_ip_addr, 4);
  }
  }
  mg_dmg_send_reply(nc, &reply);

mg_dmg_reply_record()

int mg_dmg_reply_record(struct mg_dmg_reply *, struct mg_dmg_resource_record *,
  const char *, int, int, const void *, size_t);

Append a DNS reply record to the IO buffer and to the DNS message.

The message num_answers field will be incremented. It’s caller’s duty to ensure num_answers is propertly initialized.

Returns -1 on error.

mg_dmg_send_reply()

int mg_dmg_send_reply(struct mg_connection *, struct mg_dmg_reply *);

Send a DNS reply through a connection.

The DNS data is stored in an IO buffer pointed by reply structure in r. This function mutates the content of that buffer in order to ensure that the DNS header reflects size and flags of the mssage, that might have been updated either with mg_dmg_reply_record or by direct manipulation of r→message.

Once sent, the IO buffer will be trimmed unless the reply IO buffer is the connection’s send buffer and the connection is not in UDP mode.

MQTT

mg_set_protocol_mqtt()

void mg_set_protocol_mqtt(struct mg_connection *);

Attach built-in MQTT event handler to the given connection.

The user-defined event handler will receive following extra events:

  • MG_EV_MQTT_CONNACK

  • MG_EV_MQTT_PUBLISH

  • MG_EV_MQTT_PUBACK

  • MG_EV_MQTT_PUBREC

  • MG_EV_MQTT_PUBREL

  • MG_EV_MQTT_PUBCOMP

  • MG_EV_MQTT_SUBACK

mg_send_mqtt_handshake()

void mg_send_mqtt_handshake(struct mg_connection *nc, const char *client_id);

Send MQTT handshake.

mg_send_mqtt_handshake_opt()

void mg_send_mqtt_handshake_opt(struct mg_connection *, const char *client_id,
  struct mg_send_mqtt_handshake_opts);

Send MQTT handshake with optional parameters.

mg_mqtt_publish()

void mg_mqtt_publish(struct mg_connection *nc, const char *topic,
  uint16_t message_id, int flags, const void *data,
  size_t len);

Publish a message to a given topic.

mg_mqtt_subscribe()

void mg_mqtt_subscribe(struct mg_connection *nc,
  const struct mg_mqtt_topic_expression *topics,
  size_t topics_len, uint16_t message_id);

Subscribe to a bunch of topics.

mg_mqtt_unsubscribe()

void mg_mqtt_unsubscribe(struct mg_connection *nc, char **topics,
  size_t topics_len, uint16_t message_id);

Unsubscribe from a bunch of topics.

mg_mqtt_disconnect()

void mg_mqtt_disconnect(struct mg_connection *nc);

Send a DISCONNECT command.

mg_mqtt_connack()

void mg_mqtt_connack(struct mg_connection *, uint8_t);

Send a CONNACK command with a given return_code.

mg_mqtt_puback()

void mg_mqtt_puback(struct mg_connection *, uint16_t);

Send a PUBACK command with a given message_id.

mg_mqtt_pubrec()

void mg_mqtt_pubrec(struct mg_connection *, uint16_t);

Send a PUBREC command with a given message_id.

mg_mqtt_pubrel()

void mg_mqtt_pubrel(struct mg_connection *, uint16_t);

Send a PUBREL command with a given message_id.

mg_mqtt_pubcomp()

void mg_mqtt_pubcomp(struct mg_connection *, uint16_t);

Send a PUBCOMP command with a given message_id.

mg_mqtt_suback()

void mg_mqtt_suback(struct mg_connection *, uint8_t *, size_t, uint16_t);

Send a SUBACK command with a given message_id and a sequence of granted QoSs.

mg_mqtt_unsuback()

void mg_mqtt_unsuback(struct mg_connection *, uint16_t);

Send a UNSUBACK command with a given message_id.

mg_mqtt_ping()

void mg_mqtt_ping(struct mg_connection *);

Send a PINGREQ command.

mg_mqtt_pong()

void mg_mqtt_pong(struct mg_connection *);

Send a PINGRESP command.

mg_mqtt_next_subscribe_topic()

int mg_mqtt_next_subscribe_topic(struct mg_mqtt_message *, struct mg_str *,
  uint8_t *, int);

Extract the next topic expression from a SUBSCRIBE command payload.

Topic expression name will point to a string in the payload buffer. Return the pos of the next topic expression or -1 when the list of topics is exhausted.

MQTT Broker

struct mg_mqtt_session

struct mg_mqtt_session {
  struct mg_mqtt_broker *brk;          /* Broker */
  struct mg_mqtt_session *next, *prev; /* mg_mqtt_broker::sessions linkage */
  struct mg_connection *nc;            /* Connection with the client */
  size_t num_subscriptions;            /* Size of `subscriptions` array */
  struct mg_mqtt_topic_expression *subscriptions;
  void *user_data; /* User data */
  };

MQTT session (Broker side).

struct mg_mqtt_broker

struct mg_mqtt_broker {
  struct mg_mqtt_session *sessions; /* Session list */
  void *user_data;                  /* User data */
  };

MQTT broker.

mg_mqtt_broker_init()

void mg_mqtt_broker_init(struct mg_mqtt_broker *, void *);

Initialize a MQTT broker.

mg_mqtt_broker()

void mg_mqtt_broker(struct mg_connection *, int, void *);

Process a MQTT broker message.

Listening connection expects a pointer to an initialized mg_mqtt_broker structure in the user_data field.

Basic usage:

mg_mqtt_broker_init(&brk, NULL);

  if ((nc = mg_bind(&mgr, address, mg_mqtt_broker)) == NULL) {
  // fail;
  }
  nc->user_data = &brk;

New incoming connections will receive a mg_mqtt_session structure in the connection user_data. The original user_data will be stored in the user_data field of the session structure. This allows the user handler to store user data before mg_mqtt_broker creates the session.

Since only the MG_EV_ACCEPT message is processed by the listening socket, for most events the user_data will thus point to a mg_mqtt_session.

mg_mqtt_next()

struct mg_mqtt_session *mg_mqtt_next(struct mg_mqtt_broker *,
  struct mg_mqtt_session *);

Iterate over all mqtt sessions connections. Example:

struct mg_mqtt_session *s;
for (s = mg_mqtt_next(brk, NULL); s != NULL; s = mg_mqtt_next(brk, s)) {
   // Do something
}

CoAP

CoAP message format:

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
|Ver| T | TKL | Code | Message ID | Token (if any, TKL bytes) ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
| Options (if any) ...            |1 1 1 1 1 1 1 1| Payload (if any) ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-

struct mg_coap_option

struct mg_coap_option {
  struct mg_coap_option *next;
  uint32_t number;
  struct mg_str value;
  };

CoAP options. Use mg_coap_add_option and mg_coap_free_options for creation and destruction.

struct mg_coap_message

struct mg_coap_message {
  uint32_t flags;
  uint8_t msg_type;
  uint8_t code_class;
  uint8_t code_detail;
  uint16_t msg_id;
  struct mg_str token;
  struct mg_coap_option *options;
  struct mg_str payload;
  struct mg_coap_option *optiomg_tail;
  };

CoAP message. See RFC 7252 for details.

mg_set_protocol_coap()

int mg_set_protocol_coap(struct mg_connection *nc);

Set CoAP protocol handler - trigger CoAP specific events

mg_coap_add_option()

struct mg_coap_option *mg_coap_add_option(struct mg_coap_message *cm,
  uint32_t number, char *value,
  size_t len);

Add new option to mg_coap_message structure. Returns pointer to the newly created option.

mg_coap_free_options()

void mg_coap_free_options(struct mg_coap_message *cm);

Free the memory allocated for options, if cm paramater doesn’t contain any option does nothing.

mg_coap_send_message()

uint32_t mg_coap_send_message(struct mg_connection *nc,
  struct mg_coap_message *cm);

Compose CoAP message from mg_coap_message and send it into nc connection. Return 0 on success. On error, it is a bitmask:

  • #define MG_COAP_ERROR 0x10000

  • #define MG_COAP_FORMAT_ERROR (MG_COAP_ERROR | 0x20000)

  • #define MG_COAP_IGNORE (MG_COAP_ERROR | 0x40000)

  • #define MG_COAP_NOT_ENOUGH_DATA (MG_COAP_ERROR | 0x80000)

  • #define MG_COAP_NETWORK_ERROR (MG_COAP_ERROR | 0x100000)

mg_coap_send_ack()

uint32_t mg_coap_send_ack(struct mg_connection *nc, uint16_t msg_id);

Compose CoAP acknowledgement from mg_coap_message and send it into nc connection. Return value: see mg_coap_send_message()

mg_coap_parse()

uint32_t mg_coap_parse(struct mbuf *io, struct mg_coap_message *cm);

Parse COAP message and fills mg_coap_message and returns cm→flags. This is a helper function.

Note usually CoAP work over UDP, so lack of data means format error, but in theory it is possible to use CoAP over TCP (according to RFC)

The caller have to check results and treat COAP_NOT_ENOUGH_DATA according to underlying protocol:

  • in case of UDP COAP_NOT_ENOUGH_DATA means COAP_FORMAT_ERROR,

  • in case of TCP client can try to receive more data

Return value: see mg_coap_send_message()

mg_coap_compose()

uint32_t mg_coap_compose(struct mg_coap_message *cm, struct mbuf *io);

Composes CoAP message from mg_coap_message structure. This is a helper function. Return value: see mg_coap_send_message()

Utilities

mg_skip()

const char *mg_skip(const char *s, const char *end_string,
  const char *delimiters, struct mg_str *v);

Fetch substring from input string s, end into v. Skips initial delimiter characters. Records first non-delimiter character as the beginning of substring v. Then scans the rest of the string until a delimiter character or end-of-string is found. delimiters is a 0-terminated string containing delimiter characters. Either one of delimiters or end_string terminates the search. Return an s pointer, advanced forward where parsing stopped.

mg_ncasecmp()

int mg_ncasecmp(const char *s1, const char *s2, size_t len);

Cross-platform version of strncasecmp().

mg_casecmp()

int mg_casecmp(const char *s1, const char *s2);

Cross-platform version of strcasecmp().

mg_vcmp()

int mg_vcmp(const struct mg_str *str2, const char *str1);

Cross-platform version of strcmp() where where first string is specified by struct mg_str.

mg_vcasecmp()

int mg_vcasecmp(const struct mg_str *str2, const char *str1);

Cross-platform version of strncasecmp() where first string is specified by struct mg_str.

mg_base64_decode()

int mg_base64_decode(const unsigned char *s, int len, char *dst);

Decode base64-encoded string s, len into the destination dst. Destination has to have enough space to hold decoded buffer. Decoding stops either when all string has been decoded, or invalid character appeared. Destination is '\0'-terminated. Return number of decoded characters. On success, that should be equal to len. On error (invalid character) the return value is smaller then len.

mg_base64_encode()

void mg_base64_encode(const unsigned char *src, int src_len, char *dst);

Base64-encode chunk of memory src, src_len into the destination dst. Destination has to have enough space to hold encoded buffer. Destination is '\0'-terminated.

mg_stat()

int mg_stat(const char *path, cs_stat_t *st);

Perform a 64-bit stat() call against given file.

path should be UTF8 encoded.

Return value is the same as for stat() syscall.

mg_fopen()

FILE *mg_fopen(const char *path, const char *mode);

Open the given file and return a file stream.

path and mode should be UTF8 encoded.

Return value is the same as for the fopen() call.

mg_open()

int mg_open(const char *path, int flag, int mode);

Open the given file and return a file stream.

path should be UTF8 encoded.

Return value is the same as for the open() syscall.

mg_start_thread()

void *mg_start_thread(void *(*thread_func);

Start a new detached thread. Arguments and semantic is the same as pthead’s pthread_create(). thread_func is a thread function, thread_func_param is a parameter that is passed to the thread function.

mg_sock_to_str()

void mg_sock_to_str(sock_t sock, char *buf, size_t len, int flags);

Convert socket’s local or remote address into string.

The flags parameter is a bit mask that controls the behavior, see MG_SOCK_STRINGIFY_* definitions.

  • MG_SOCK_STRINGIFY_IP - print IP address

  • MG_SOCK_STRINGIFY_PORT - print port number

  • MG_SOCK_STRINGIFY_REMOTE - print remote peer’s IP/port, not local address

If both port number and IP address are printed, they are separated by :. If compiled with -DMG_ENABLE_IPV6, IPv6 addresses are supported.

mg_sock_addr_to_str()

void mg_sock_addr_to_str(const union socket_address *sa, char *buf, size_t len,
  int flags);

Convert socket’s address into string.

flags is MG_SOCK_STRINGIFY_IP and/or MG_SOCK_STRINGIFY_PORT.

mg_hexdump()

int mg_hexdump(const void *buf, int len, char *dst, int dst_len);

Generates human-readable hexdump of memory chunk.

Takes a memory buffer buf of length len and creates a hex dump of that buffer in dst. Generated output is a-la hexdump(1). Return length of generated string, excluding terminating \0. If returned length is bigger than dst_len, overflow bytes are discarded.

mg_hexdump_connection()

void mg_hexdump_connection(struct mg_connection *nc, const char *path,
  int num_bytes, int ev);

Generates human-readable hexdump of the data sent or received by connection. path is a file name where hexdump should be written. num_bytes is a number of bytes sent/received. ev is one of the MG_* events sent to an event handler. This function is supposed to be called from the event handler.

mg_avprintf()

int mg_avprintf(char **buf, size_t size, const char *fmt, va_list ap);

Print message to buffer. If buffer is large enough to hold the message, return buffer. If buffer is to small, allocate large enough buffer on heap, and return allocated buffer. This is a supposed use case:

char buf[5], *p = buf;
p = mg_avprintf(&p, sizeof(buf), "%s", "hi there");
use_p_somehow(p);
if (p != buf) {
  free(p);
}

The purpose of this is to avoid malloc-ing if generated strings are small.

mg_is_big_endian()

int mg_is_big_endian(void);

Return true if target platform is big endian.

mg_next_comma_list_entry()

const char *mg_next_comma_list_entry(const char *list, struct mg_str *val,
  struct mg_str *eq_val);

A helper function for traversing a comma separated list of values. It returns a list pointer shifted to the next value, or NULL if the end of the list found. Value is stored in val vector. If value has form "x=y", then eq_val vector is initialized to point to the "y" part, and val vector length is adjusted to point only to "x". If list is just a comma separated list of entries, like "aa,bb,cc" then eq_val will contain zero-length string.

The purpose of this function is to parse comma separated string without any copying/memory allocation.

mg_match_prefix()

int mg_match_prefix(const char *pattern, int pattern_len, const char *str);

Match 0-terminated string against a glob pattern. Match is case-insensitive. Return number of bytes matched, or -1 if no match.