diff --git a/docs/API.md b/docs/API.md index 3bd09c51..019f0c32 100644 --- a/docs/API.md +++ b/docs/API.md @@ -51,8 +51,8 @@ is serving, in between `mg_poll_server()` calls. void mg_poll_server(struct mg_server *server, int milliseconds); This function performs one iteration of IO loop by iterating over all -active connections, performing `select()` syscall on all sockets, and sleeping -for `milliseconds` number of milliseconds. When `select()` returns, Mongoose +active connections, performing `select()` syscall on all sockets with a timeout +of `milliseconds` number of milliseconds. When `select()` returns, Mongoose does an IO for each socket that has data to be sent or received. Application code must call `mg_poll_server()` in a loop. It is an error to have more then one thread calling `mg_poll_server()`, `mg_set_option()` or any other function diff --git a/docs/Internals.md b/docs/Internals.md index 891686dc..ee99f7b3 100644 --- a/docs/Internals.md +++ b/docs/Internals.md @@ -1,21 +1,42 @@ # Mongoose Internals Mongoose has single-threaded, event-driven, asynchronous, non-blocking core. -When mongoose server instance is created, it contains an information about -the configuration and the state of each connection: +`mg_create_server()` creates a web server instance. An instance is a container +for the config options and list of active connections. To do the actual +serving, user must call `mg_poll_server()`, which iterates over all +active connections, performing `select()` syscall on all sockets with a +timeout of specified number of milliseconds. When `select()` returns, Mongoose +does an IO for each socket that has data to be sent or received. Application +code must call `mg_poll_server()` in a loop. - struct mg_server { - sock_t listening_sock; // Listening socket - union socket_address lsa; // Listening socket address - struct linked_list_link active_connections; - struct linked_list_link uri_handlers; - char *config_options[NUM_OPTIONS]; - ... - }; +Mongoose server instance is designed to be used by a single thread. +It is an error to have more then +one thread calling `mg_poll_server()`, `mg_set_option()` or any other function +that take `struct mg_server *` parameter. Mongoose does not +mutex-protect `struct mg_server *`, therefore the best practice is +to call server management functions from the same thread (an IO thread). -A server instance is capable on listening on only one port. After creation, -a server instance has a list -of active connections, initially empty. It has a list of URI handlers, -initially empty, and configuration parameters. Configuration can be -altered by `mg_set_option()`, and new URI handlers could be added by -`mg_add_uri_handler()`. + +It is an error to pass and store `struct mg_connection *` pointers for +later use to send data. The reason is that they can be invalidated by the +next `mg_poll_server()` call. For such a task, +there is `mg_iterate_over_connections()` API +exists, which sends a callback function to the IO thread, then IO thread +calls specified function for all active connection. + +When mongoose buffers in HTTP request and successfully parses it, it calls +appropriate URI handler immediately for GET requests. For POST requests, +Mongoose delays the call until the whole POST request is buffered in memory. +POST data is available to the callback as `struct mg_connection::content`, +and POST data length is in `struct mg_connection::content_len`. + +Note that websocket connections are treated the same way. Mongoose buffers +websocket frame in memory, and calls URI handler when frame is fully +buffered. Frame data is available `struct mg_connection::content`, and +data length is in `struct mg_connection::content_len`, i.e. very similar to +the POST request. `struct mg_connection::is_websocket` flag indicates +whether the request is websocket or not. Also, for websocket requests, +there is `struct mg_connection::wsbits` field which contains first byte +of the websocket frame which URI handler can examine. Note that to +reply to the websocket client, `mg_websocket_write()` should be used. +To reply to the plain HTTP client, `mg_write()` should be used.