Core API

The Core API is the heart of Mongoose. It contains the fundamental data structures, event loop, and networking primitives used to build servers, clients, and embedded network applications. These functions power everything in Mongoose - handling connections, processing events, sending data, and running the event-driven networking engine.

struct mg_addr

struct mg_addr {
  uint8_t ip[16];    // Holds IPv4 or IPv6 address, in network byte order
  uint16_t port;     // TCP or UDP port in network byte order
  uint8_t scope_id;  // IPv6 scope ID
  bool is_ip6;       // True when address is IPv6 address
};

This structure contains network address; it can be considered as a Mongoose equivalent for sockets sockaddr structure.

struct mg_mgr

struct mg_mgr {
  struct mg_connection *conns;  // List of active connections
  struct mg_dns dns4;           // DNS for IPv4
  struct mg_dns dns6;           // DNS for IPv6
  int dnstimeout;               // DNS resolve timeout in milliseconds
  unsigned long nextid;         // Next connection ID
  void *userdata;               // Arbitrary user data pointer
  ...
  struct mg_tcpip_if *ifp;      // Builtin TCP/IP stack only. Interface pointer
};

Event management structure that holds a list of active connections, together with some housekeeping information.

struct mg_connection

struct mg_connection {
  struct mg_connection *next;  // Linkage in struct mg_mgr :: connections
  struct mg_mgr *mgr;          // Our container
  struct mg_addr loc;          // Local address
  struct mg_addr rem;          // Remote address
  void *fd;                    // Connected socket, or LWIP data
  unsigned long id;            // Auto-incrementing unique connection ID
  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-specified function parameter
  mg_event_handler_t pfn;      // Protocol-specific handler function
  void *pfn_data;              // Protocol-specific function parameter
  char data[MG_DATA_SIZE];     // Arbitrary connection data, MG_DATA_SIZE defaults to 32 bytes
  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 resolve 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_full : 1;        // Stop reads, until cleared
  unsigned is_resp : 1;        // Response is still being generated
  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 outbound connection.

mg_mgr_init()

void mg_mgr_init(struct mg_mgr *mgr);

Initialize event manager structure:

  • Set a list of active connections to NULL
  • Set default DNS servers for IPv4 and IPv6
  • Set default DNS lookup timeout

Parameters:

  • mgr - a pointer to mg_mgr structure that needs to be initialized

Return value: none

Usage example:

struct mg_mgr mgr;
mg_mgr_init(&mgr);

mg_mgr_poll()

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 there is, read it into the c->recv buffer, send MG_EV_READ 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

Parameters:

  • mgr - an event manager to use
  • ms - a timeout in milliseconds

Return value: none

Usage example:

while (running == true) mg_mgr_poll(&mgr, 1000 /* 1 sec */);

mg_mgr_free()

void mg_mgr_free(struct mg_mgr *mgr);

Close all connections, and free all resources.

Parameters:

  • mgr - an event manager to cleanup

Return value: none

Usage example:

struct mg_mgr mgr;
mg_mgr_init(&mgr);
while (running == true) mg_mgr_poll(&mgr, 1000);   // Event loop
mg_mgr_free(&mgr);

mg_listen()

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.

Parameters:

  • mgr - an event manager to use
  • url - a 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. If this URL is a known TLS URL, the is_tls flag will be set
  • fn - an event handler function
  • fn_data - an arbitrary pointer, which will be stored in the connection structure as c->fn_data, so the event handler can use it when called.

Return value: created connection, or NULL on error.

Usage example:

struct mg_connection *c = mg_listen(&mgr, "tcp://127.0.0.1:8080", fn, NULL);

mg_connect()

struct mg_connection *mg_connect(struct mg_mgr *mgr, const char *url,
                                 mg_event_handler_t fn, void *fn_data);

Create an outbound connection, append this connection to mgr->conns.

Parameters:

  • mgr - An event manager to use
  • url - A URL, specifies remote IP address/port to connect to, e.g. http://a.com. If this URL is a known TLS URL, the is_tls flag will be set
  • fn - An event handler function
  • fn_data - an arbitrary pointer, which will be stored in the connection structure as c->fn_data, so the event handler can use it when called.

Return value: created connection, or NULL on error. Possible errors are: not enough memory, a NULL URL, or, in the case of our built-in TCP/IP stack, the network not being ready.

Note: This function does not connect to the requested peer, it allocates required resources and starts the connection process. Once our peer is really connected, an MG_EV_CONNECT event is sent to the connection event handler.

Usage example:

struct mg_connection *c = mg_connect(&mgr, "http://example.org", fn, NULL);

mg_send()

bool mg_send(struct mg_connection *c, const void *data, size_t size);

Append data of size size to the c->send buffer. Return success / failure.

Note: Except when using UDP on the Mongoose TCP/IP stack, this function does not push data to the network. It only appends data to the output buffer. Data is sent when mg_mgr_poll() is called. If mg_send() is called multiple times, the output buffer grows. When calling this function to send UDP on the Mongoose TCP/IP stack, an Ethernet frame gets sent immediately, the c->send buffer is bypassed.

Parameters:

  • c - A connection pointer
  • data - A pointer to data to append to the send buffer
  • size - A data size

Return value: true if data appended successfully and false otherwise

Usage example:

mg_send(c, "hi", 2);  // Append string "hi" to the output buffer

mg_wakeup()

void mg_wakeup(struct mg_mgr *mgr, unsigned long id, const void *data, size_t size);

Any thread/task can send data, size to Mongoose manager executing in another thread. This is the only Mongoose function that can be called from a different task/thread. Calling this function wakes up the event manager and generates an MG_EV_WAKEUP event in the respective event handler. Call mg_wakeup_init() in the event manager thread before first using it.

The data could be anything. It could be a structure. Or it could be a pointer. The receiving connection gets MG_EV_WAKEUP, and gets that data as a chunk of memory: struct mg_str *data = ev_data. Note that the sent data should be small, ideally less than 512 bytes. If you need to send a large piece of data, allocate it and send a pointer instead - see examples below.

Parameters:

  • mgr - An event manager
  • id - A destination connection ID
  • data - A pointer to data to append to the send buffer
  • size - A data size

Usage example:

Sending small data

// Sender side:
struct foo foo = {0};                   // Small structure, size < 512 bytes
mg_wakeup(mgr, id, &foo, sizeof(foo));  // Send a structure

// Receiver side:
if (ev == MG_EV_WAKEUP) {
  struct mg_str *data = (struct mg_str *) ev_data;
  struct foo *foo = (struct foo *) data->buf;
}

Sending large data. Sender allocates it, receiver deallocates

// Sender side:
struct foo *foo = malloc(sizeof(*foo));  // Big structure, allocate it
mg_wakeup(mgr, id, &foo, sizeof(foo));   // Send a pointer to structure

// Receiver side:
if (ev == MG_EV_WAKEUP) {
  struct mg_str *data = (struct mg_str *) ev_data;
  struct foo *foo = * (struct foo **) data->buf;
  // Do something with foo ...
  free(foo);   // Deallocate foo
}

mg_wakeup_init()

void mg_wakeup_init(struct mg_mgr *mgr);

Initialize the wakeup scheme used by mg_wakeup()

Parameters:

  • mgr - An event manager

Usage example:

mg_wakeup_init(&mgr);  // Initialise wakeup socket pai

mg_printf(), mg_vprintf()

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

Same as mg_send(), but formats data using printf() semantics. Return number of bytes appended to the output buffer.

NOTE: See mg_snprintf for the list of supported format specifiers

Parameters:

  • c - a connection pointer
  • fmt - a format string in printf semantics

Return value: number of bytes appended to the output buffer.

Usage example:

mg_printf(c, "Hello, %s!", "world"); // Add "Hello, world!" to output buffer

mg_wrapfd()

struct mg_connection *mg_wrapfd(struct mg_mgr *mgr, int fd,
                                mg_event_handler_t fn, void *fn_data);

Wrap a given file descriptor fd into a connection, and add that connection to the event manager. An fd descriptor must support send(), recv(), select() syscalls, and be non-blocking. Mongoose will treat it as a TCP socket. The c->rem and c->loc addresses will be empty.

Parameters:

  • fd - A file descriptor to wrap
  • mgr - An event manager
  • fn - A pointer to event handler function
  • fn_data - an arbitrary pointer, which will be stored in the connection structure as c->fn_data, so the event handler can use it when called.

Return value: Pointer to the created connection or NULL in case of error