mirror of
https://github.com/cesanta/mongoose.git
synced 2025-01-02 03:27:52 +08:00
f443c64341
Until I read the doc and find how to limit the retention, otherwise it just eats all my ram and cpu and things start to fall apart. PUBLISHED_FROM=eb33fb44736f07b992270689217aca4af70513ff
500 lines
15 KiB
Plaintext
500 lines
15 KiB
Plaintext
=== 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
|
|
|
|
[source,c]
|
|
----
|
|
struct mg_str {
|
|
const char *p; /* Memory chunk pointer */
|
|
size_t len; /* Memory chunk length */
|
|
};
|
|
----
|
|
Describes chunk of memory
|
|
|
|
==== struct mg_mgr
|
|
|
|
[source,c]
|
|
----
|
|
struct mg_mgr {
|
|
struct mg_connection *active_connections;
|
|
const char *hexdump_file; /* Debug hexdump file path */
|
|
#ifndef MG_DISABLE_SOCKETPAIR
|
|
sock_t ctl[2]; /* Socketpair for mg_wakeup() */
|
|
#endif
|
|
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
|
|
|
|
[source,c]
|
|
----
|
|
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 */
|
|
int err;
|
|
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 */
|
|
double ev_timer_time; /* Timestamp of the future MG_EV_TIMER */
|
|
mg_event_handler_t proto_handler; /* Protocol-specific event handler */
|
|
void *proto_data; /* Protocol-specific data */
|
|
void (*proto_data_destructor)(void *proto_data);
|
|
mg_event_handler_t handler; /* Event handler function */
|
|
void *user_data; /* User-specific data */
|
|
union {
|
|
void *v;
|
|
/*
|
|
* the C standard is fussy about fitting function pointers into
|
|
* void pointers, since some archs might have fat pointers for functions.
|
|
*/
|
|
mg_event_handler_t f;
|
|
} 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_CLOSE_IMMEDIATELY (1 << 11) /* Disconnect */
|
|
#define MG_F_WEBSOCKET_NO_DEFRAG (1 << 12) /* Websocket specific */
|
|
#define MG_F_DELETE_CHUNK (1 << 13) /* 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
|
|
|
|
[source,c]
|
|
----
|
|
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
|
|
|
|
[source,c]
|
|
----
|
|
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 */
|
|
#ifdef MG_ENABLE_SSL
|
|
/* SSL settings. */
|
|
const char *ssl_cert; /* Server certificate to present to clients */
|
|
const char *ssl_ca_cert; /* Verify client certificates with this CA bundle */
|
|
#endif
|
|
};
|
|
----
|
|
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
|
|
|
|
[source,c]
|
|
----
|
|
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 */
|
|
#ifdef MG_ENABLE_SSL
|
|
/* SSL settings. */
|
|
const char *ssl_cert; /* Client certificate to present to the server */
|
|
const char *ssl_ca_cert; /* Verify server certificate using this CA bundle */
|
|
|
|
/*
|
|
* Server name verification. If ssl_ca_cert is set and the certificate has
|
|
* passed verification, its subject will be verified against this string.
|
|
* By default (if ssl_server_name is NULL) hostname part of the address will
|
|
* be used. Wildcard matching is supported. A special value of "*" disables
|
|
* name verification.
|
|
*/
|
|
const char *ssl_server_name;
|
|
#endif
|
|
};
|
|
----
|
|
Optional parameters to `mg_connect_opt()`
|
|
|
|
==== mg_mgr_init()
|
|
|
|
[source,c]
|
|
----
|
|
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()
|
|
|
|
[source,c]
|
|
----
|
|
void mg_mgr_free(struct mg_mgr *);
|
|
----
|
|
De-initializes Mongoose manager.
|
|
|
|
Close and deallocate all active connections.
|
|
|
|
==== mg_mgr_poll()
|
|
|
|
[source,c]
|
|
----
|
|
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()
|
|
|
|
[source,c]
|
|
----
|
|
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()
|
|
|
|
[source,c]
|
|
----
|
|
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:
|
|
|
|
```c
|
|
for (c = mg_next(srv, NULL); c != NULL; c = mg_next(srv, c)) {
|
|
// Do something with connection `c`
|
|
}
|
|
```
|
|
|
|
==== mg_add_sock()
|
|
|
|
[source,c]
|
|
----
|
|
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()
|
|
|
|
[source,c]
|
|
----
|
|
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()
|
|
|
|
[source,c]
|
|
----
|
|
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()
|
|
|
|
[source,c]
|
|
----
|
|
struct mg_connection *mg_bind_opt(struct mg_mgr *mgr, const char *address,
|
|
mg_event_handler_t handler,
|
|
struct mg_bind_opts 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()
|
|
|
|
[source,c]
|
|
----
|
|
struct mg_connection *mg_connect(struct mg_mgr *mgr, const char *address,
|
|
mg_event_handler_t handler);
|
|
----
|
|
Connect to a remote host.
|
|
|
|
See `mg_connect_opt()` for full documentation.
|
|
|
|
==== mg_connect_opt()
|
|
|
|
[source,c]
|
|
----
|
|
struct mg_connection *mg_connect_opt(struct mg_mgr *mgr, const char *address,
|
|
mg_event_handler_t handler,
|
|
struct mg_connect_opts 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:
|
|
|
|
```c
|
|
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()
|
|
|
|
[source,c]
|
|
----
|
|
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()
|
|
|
|
[source,c]
|
|
----
|
|
void mg_send(struct mg_connection *, const void *buf, int len);
|
|
----
|
|
Send data to the connection.
|
|
|
|
Note that sending functions do not actually push data to the socket.
|
|
They just append data to the output buffer. MG_EV_SEND will be delivered when
|
|
the data has actually been pushed out.
|
|
|
|
==== mg_printf()
|
|
|
|
[source,c]
|
|
----
|
|
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()
|
|
|
|
[source,c]
|
|
----
|
|
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()
|
|
|
|
[source,c]
|
|
----
|
|
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_check_ip_acl()
|
|
|
|
[source,c]
|
|
----
|
|
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
|
|
link:https://en.wikipedia.org/wiki/Subnetwork[Wikipedia page on Subnetwork]
|
|
|
|
Return -1 if ACL is malformed, 0 if address is disallowed, 1 if allowed.
|
|
|
|
==== mg_enable_multithreading()
|
|
|
|
[source,c]
|
|
----
|
|
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()
|
|
|
|
[source,c]
|
|
----
|
|
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.
|
|
|
|
==== mg_set_timer()
|
|
|
|
[source,c]
|
|
----
|
|
double mg_set_timer(struct mg_connection *c, double timestamp);
|
|
----
|
|
Schedule MG_EV_TIMER event to be delivered at `timestamp` time.
|
|
`timestamp` is a UNIX time (a number of seconds since Epoch). It is
|
|
`double` instead of `time_t` to allow for sub-second precision.
|
|
Return the old timer value.
|
|
|
|
Example: set connect timeout to 1.5 seconds:
|
|
|
|
```
|
|
c = mg_connect(&mgr, "cesanta.com", ev_handler);
|
|
mg_set_timer(c, mg_time() + 1.5);
|
|
...
|
|
|
|
void ev_handler(struct mg_connection *c, int ev, void *ev_data) {
|
|
switch (ev) {
|
|
case MG_EV_CONNECT:
|
|
mg_set_timer(c, 0); // Clear connect timer
|
|
break;
|
|
case MG_EV_TIMER:
|
|
log("Connect timeout");
|
|
c->flags |= MG_F_CLOSE_IMMEDIATELY;
|
|
break;
|
|
```
|
|
|
|
==== mg_time()
|
|
|
|
[source,c]
|
|
----
|
|
double mg_time();
|
|
----
|
|
A sub-second precision version of time().
|
|
|