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 tomg_mgrstructure 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->recvbuffer, sendMG_EV_READevent - See if there is data in the
c->sendbuffer, and write it, sendMG_EV_WRITEevent - If a connection is listening, accept an incoming connection if any, and send
MG_EV_ACCEPTevent to it - Send
MG_EV_POLLevent
Parameters:
mgr- an event manager to usems- 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 useurl- a URL. Specifies local IP address and port to listen on, e.g.tcp://127.0.0.1:1234orudp://0.0.0.0:9000. If this URL is a known TLS URL, theis_tlsflag will be setfn- an event handler functionfn_data- an arbitrary pointer, which will be stored in the connection structure asc->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 useurl- A URL, specifies remote IP address/port to connect to, e.g.http://a.com. If this URL is a known TLS URL, theis_tlsflag will be setfn- An event handler functionfn_data- an arbitrary pointer, which will be stored in the connection structure asc->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 pointerdata- A pointer to data to append to the send buffersize- 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 managerid- A destination connection IDdata- A pointer to data to append to the send buffersize- 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 pointerfmt- a format string inprintfsemantics
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 wrapmgr- An event managerfn- A pointer to event handler functionfn_data- an arbitrary pointer, which will be stored in the connection structure asc->fn_data, so the event handler can use it when called.
Return value: Pointer to the created connection or NULL in case of error