Commit 34eb3f1e authored by Sergey Lyubka's avatar Sergey Lyubka Committed by GitHub

Merge pull request #855 from cesanta/dev

Mongoose 6.8
parents 7c049307 9d30e892
......@@ -8,7 +8,7 @@ used by vast number of open source and
commercial products - it even runs on the International Space station!
Mongoose makes embedded network programming fast, robust, and easy.
- [Download Mongoose Source Code here](https://www.cesanta.com)
- [Download Mongoose Source Code here](https://www.cesanta.com/download.html)
Looking for a complete IoT firmware solution?
......@@ -17,9 +17,9 @@ Check out [Mongoose OS](https://mongoose-os.com) - open source embedded operatin
# Support
- [Study mongoose example code](https://github.com/cesanta/mongoose/tree/master/examples)
- [Read User Guide and API reference](https://docs.cesanta.com/mongoose)
- [Support Forum - ask your technical questions here] (http://forum.cesanta.com/index.php?p=/categories/mongoose)
- [Commercial licensing and support available] (https://www.cesanta.com/services-support)
- [Check our latest releases] (https://github.com/cesanta/mongoose/releases)
- [Support Forum - ask your technical questions here](https://forum.mongoose-os.com/categories/mongoose)
- [Commercial licensing and support available](https://www.cesanta.com/licensing.html)
- [Check our latest releases](https://github.com/cesanta/mongoose/releases)
# Features
......@@ -47,7 +47,7 @@ Check out [Mongoose OS](https://mongoose-os.com) - open source embedded operatin
Mongoose is released under Commercial and [GNU GPL v.2](http://www.gnu.org/licenses/old-licenses/gpl-2.0.html) open source licenses.
Commercial Projects: [Contact us for commercial license.] (https://www.cesanta.com/contact)
Commercial Projects: [Contact us for commercial license.](https://www.cesanta.com/contact.html)
# Dashboard Example
......@@ -55,18 +55,14 @@ Mongoose is often used to implement device dashboards and real-time
data exchange over Websocket. Here is a dashboard example that illustrates
the functionality:
![](http://www.cesanta.com/hubfs/www.cesanta.com/diagrams/dash_mongoose_diagram.png)
![](http://www.cesanta.com/images/dashboard.png)
[Developing a new product? Contact us today to discuss how Mongoose can help.
](https://www.cesanta.com/contact)
[Developing a new product? Contact us today to discuss how Mongoose can help.](https://www.cesanta.com/contact.html)
# Contributions
To submit contributions, sign
[Cesanta CLA](https://docs.cesanta.com/contributors_la.shtml)
To submit contributions, sign [Cesanta CLA](https://cesanta.com/cla.html)
and send GitHub pull request. You retain the copyright on your contributions.
# Looking for a pre-compiled Mongoose web server Windows or Mac binary?
- [Download pre-compiled Mongoose web server binary.](https://www.cesanta.com/products/binary)
[![Analytics](https://ga-beacon.appspot.com/UA-42732794-5/project-page)](https://github.com/cesanta/mongoose)
- [Download pre-compiled Mongoose web server binary.](https://www.cesanta.com/binary.html)
......@@ -7,5 +7,5 @@ signature: |
---
Frees the memory allocated for options.
If the cm paramater doesn't contain any option it does nothing.
If the cm parameter doesn't contain any option it does nothing.
......@@ -21,5 +21,5 @@ 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.
Returns the number of bytes appened or -1 in case of error.
Returns the number of bytes appended or -1 in case of error.
......@@ -11,6 +11,7 @@ items:
- { name: mg_send_websocket_handshake.md }
- { name: mg_send_websocket_handshake2.md }
- { name: mg_send_websocket_handshake3.md }
- { name: mg_send_websocket_handshake3v.md }
- { name: mg_set_protocol_http_websocket.md }
- { name: mg_url_decode.md }
- { name: struct_http_message.md }
......
......@@ -4,9 +4,8 @@ decl_name: "mg_connect_ws"
symbol_kind: "func"
signature: |
struct mg_connection *mg_connect_ws(struct mg_mgr *mgr,
mg_event_handler_t event_handler,
const char *url, const char *protocol,
const char *extra_headers);
MG_CB(mg_event_handler_t event_handler,
void *user_data);
---
Helper function that creates an outbound WebSocket connection.
......
......@@ -3,11 +3,8 @@ title: "mg_connect_ws_opt()"
decl_name: "mg_connect_ws_opt"
symbol_kind: "func"
signature: |
struct mg_connection *mg_connect_ws_opt(struct mg_mgr *mgr,
mg_event_handler_t ev_handler,
struct mg_connect_opts opts,
const char *url, const char *protocol,
const char *extra_headers);
struct mg_connection *mg_connect_ws_opt(
struct mg_mgr *mgr, MG_CB(mg_event_handler_t ev_handler, void *user_data);
---
Helper function that creates an outbound WebSocket connection
......
......@@ -9,5 +9,6 @@ signature: |
Sends multiple websocket frames.
Like `mg_send_websocket_frame()`, but composes a frame from multiple buffers.
Like `mg_send_websocket_frame()`, but composes a frame from multiple
*buffers.
---
title: "mg_send_websocket_handshake3v()"
decl_name: "mg_send_websocket_handshake3v"
symbol_kind: "func"
signature: |
void mg_send_websocket_handshake3v(struct mg_connection *nc,
const struct mg_str path,
const struct mg_str host,
const struct mg_str protocol,
const struct mg_str extra_headers,
const struct mg_str user,
const struct mg_str pass);
---
Same as mg_send_websocket_handshake3 but with strings not necessarily
NUL-temrinated
......@@ -13,6 +13,7 @@ Source string is specified by (`src`, `src_len`), and destination is
(`dst`, `dst_len`). If `is_form_url_encoded` is non-zero, then
`+` character is decoded as a blank space character. This function
guarantees to NUL-terminate the destination. If destination is too small,
then the source string is partially decoded and `-1` is returned. Otherwise,
then the source string is partially decoded and `-1` is returned.
*Otherwise,
a length of the decoded string is returned, not counting final NUL.
......@@ -5,6 +5,7 @@ symbol_kind: "struct"
signature: |
struct http_message {
struct mg_str message; /* Whole message: request line + headers + body */
struct mg_str body; /* Message body. 0-length for requests with no body */
/* HTTP Request line (or HTTP response line) */
struct mg_str method; /* "GET" */
......@@ -28,9 +29,6 @@ signature: |
/* 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 */
};
---
......
......@@ -3,11 +3,9 @@ title: "mg_connect_http()"
decl_name: "mg_connect_http"
symbol_kind: "func"
signature: |
struct mg_connection *mg_connect_http(struct mg_mgr *mgr,
mg_event_handler_t event_handler,
const char *url,
const char *extra_headers,
const char *post_data);
struct mg_connection *mg_connect_http(
struct mg_mgr *mgr,
MG_CB(mg_event_handler_t event_handler, void *user_data);
---
Helper function that creates an outbound HTTP connection.
......
......@@ -3,12 +3,8 @@ title: "mg_connect_http_opt()"
decl_name: "mg_connect_http_opt"
symbol_kind: "func"
signature: |
struct mg_connection *mg_connect_http_opt(struct mg_mgr *mgr,
mg_event_handler_t ev_handler,
struct mg_connect_opts opts,
const char *url,
const char *extra_headers,
const char *post_data);
struct mg_connection *mg_connect_http_opt(
struct mg_mgr *mgr, MG_CB(mg_event_handler_t ev_handler, void *user_data);
---
Helper function that creates an outbound HTTP connection.
......
......@@ -3,6 +3,7 @@ title: "Server API reference"
symbol_kind: "intro"
decl_name: "http_server.h"
items:
- { name: mg_check_digest_auth.md }
- { name: mg_file_upload_handler.md }
- { name: mg_get_http_basic_auth.md }
- { name: mg_get_http_header.md }
......
---
title: "mg_check_digest_auth()"
decl_name: "mg_check_digest_auth"
symbol_kind: "func"
signature: |
int mg_check_digest_auth(struct mg_str method, struct mg_str uri,
struct mg_str username, struct mg_str cnonce,
struct mg_str response, struct mg_str qop,
struct mg_str nc, struct mg_str nonce,
struct mg_str auth_domain, FILE *fp);
---
Authenticates given response params against an opened password file.
Returns 1 if authenticated, 0 otherwise.
It's used by mg_http_check_digest_auth().
......@@ -4,7 +4,8 @@ decl_name: "mg_file_upload_handler"
symbol_kind: "func"
signature: |
void mg_file_upload_handler(struct mg_connection *nc, int ev, void *ev_data,
mg_fu_fname_fn local_name_fn);
mg_fu_fname_fn local_name_fn
MG_UD_ARG(void *user_data);
---
File upload handler.
......
......@@ -12,5 +12,6 @@ Fetches a HTTP form variable.
Fetches a variable `name` from a `buf` into a buffer specified by `dst`,
`dst_len`. The destination is always zero-terminated. Returns the 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.
url-encoded buffer. If destination is too small or an error occured,
negative number is returned.
......@@ -12,7 +12,7 @@ Sends a redirect response.
`status_code` should be either 301 or 302 and `location` point to the
new location.
If `extra_headers` is not empty, then `extra_headers` are also sent
after the reponse line. `extra_headers` must NOT end end with new line.
after the response line. `extra_headers` must NOT end end with new line.
Example:
......
......@@ -4,7 +4,8 @@ decl_name: "mg_register_http_endpoint"
symbol_kind: "func"
signature: |
void mg_register_http_endpoint(struct mg_connection *nc, const char *uri_path,
mg_event_handler_t handler);
MG_CB(mg_event_handler_t handler,
void *user_data);
---
Registers a callback for a specified http endpoint
......@@ -20,7 +21,7 @@ static void handle_hello1(struct mg_connection *nc, int ev, void *ev_data) {
nc->flags |= MG_F_SEND_AND_CLOSE;
}
static void handle_hello1(struct mg_connection *nc, int ev, void *ev_data) {
static void handle_hello2(struct mg_connection *nc, int ev, void *ev_data) {
(void) ev; (void) ev_data;
mg_printf(nc, "HTTP/1.0 200 OK\r\n\r\n[I am Hello2]");
nc->flags |= MG_F_SEND_AND_CLOSE;
......
......@@ -9,7 +9,7 @@ signature: |
Sends buffer `buf` of size `len` to the client using chunked HTTP encoding.
This function sends the buffer size as hex number + newline first, then
the buffer itself, then the newline. For example,
`mg_send_http_chunk(nc, "foo", 3)` whill append the `3\r\nfoo\r\n` string
`mg_send_http_chunk(nc, "foo", 3)` will append the `3\r\nfoo\r\n` string
to the `nc->send_mbuf` output IO buffer.
NOTE: The HTTP header "Transfer-Encoding: chunked" should be sent prior to
......
......@@ -9,7 +9,7 @@ signature: |
Sends the response status line.
If `extra_headers` is not NULL, then `extra_headers` are also sent
after the reponse line. `extra_headers` must NOT end end with new line.
after the response line. `extra_headers` must NOT end end with new line.
Example:
mg_send_response_line(nc, 200, "Access-Control-Allow-Origin: *");
......
......@@ -5,6 +5,7 @@ decl_name: "mqtt.h"
items:
- { name: mg_mqtt_connack.md }
- { name: mg_mqtt_disconnect.md }
- { name: mg_mqtt_match_topic_expression.md }
- { name: mg_mqtt_next_subscribe_topic.md }
- { name: mg_mqtt_ping.md }
- { name: mg_mqtt_pong.md }
......@@ -17,6 +18,7 @@ items:
- { name: mg_mqtt_subscribe.md }
- { name: mg_mqtt_unsuback.md }
- { name: mg_mqtt_unsubscribe.md }
- { name: mg_mqtt_vmatch_topic_expression.md }
- { name: mg_send_mqtt_handshake.md }
- { name: mg_send_mqtt_handshake_opt.md }
- { name: mg_set_protocol_mqtt.md }
......
---
title: "mg_mqtt_match_topic_expression()"
decl_name: "mg_mqtt_match_topic_expression"
symbol_kind: "func"
signature: |
int mg_mqtt_match_topic_expression(struct mg_str exp, struct mg_str topic);
---
Matches a topic against a topic expression
Returns 1 if it matches; 0 otherwise.
---
title: "mg_mqtt_vmatch_topic_expression()"
decl_name: "mg_mqtt_vmatch_topic_expression"
symbol_kind: "func"
signature: |
int mg_mqtt_vmatch_topic_expression(const char *exp, struct mg_str topic);
---
Same as `mg_mqtt_match_topic_expression()`, but takes `exp` as a
NULL-terminated string.
......@@ -5,6 +5,7 @@ symbol_kind: "struct"
signature: |
struct mg_mqtt_proto_data {
uint16_t keep_alive;
double last_control_time;
};
---
......
......@@ -11,7 +11,6 @@ items:
- { name: mg_check_ip_acl.md }
- { name: mg_connect.md }
- { name: mg_connect_opt.md }
- { name: mg_enable_javascript.md }
- { name: mg_mgr_free.md }
- { name: mg_mgr_init.md }
- { name: mg_mgr_init_opt.md }
......
......@@ -3,7 +3,9 @@ title: "mg_add_sock()"
decl_name: "mg_add_sock"
symbol_kind: "func"
signature: |
struct mg_connection *mg_add_sock(struct mg_mgr *, sock_t, mg_event_handler_t);
struct mg_connection *mg_add_sock(struct mg_mgr *mgr, sock_t sock,
MG_CB(mg_event_handler_t handler,
void *user_data);
---
Creates a connection, associates it with the given socket and event handler
......
......@@ -3,9 +3,9 @@ title: "mg_add_sock_opt()"
decl_name: "mg_add_sock_opt"
symbol_kind: "func"
signature: |
struct mg_connection *mg_add_sock_opt(struct mg_mgr *, sock_t,
mg_event_handler_t,
struct mg_add_sock_opts);
struct mg_connection *mg_add_sock_opt(struct mg_mgr *mgr, sock_t sock,
MG_CB(mg_event_handler_t handler,
void *user_data);
---
Creates a connection, associates it with the given socket and event handler
......
......@@ -3,8 +3,9 @@ title: "mg_bind()"
decl_name: "mg_bind"
symbol_kind: "func"
signature: |
struct mg_connection *mg_bind(struct mg_mgr *, const char *,
mg_event_handler_t);
struct mg_connection *mg_bind(struct mg_mgr *mgr, const char *address,
MG_CB(mg_event_handler_t handler,
void *user_data);
---
Creates a listening connection.
......
......@@ -4,8 +4,8 @@ decl_name: "mg_bind_opt"
symbol_kind: "func"
signature: |
struct mg_connection *mg_bind_opt(struct mg_mgr *mgr, const char *address,
mg_event_handler_t handler,
struct mg_bind_opts opts);
MG_CB(mg_event_handler_t handler,
void *user_data);
---
Creates a listening connection.
......@@ -15,7 +15,7 @@ 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
prefix, e.g. `udp://:8000`. To summarize, `address` parameter has following
format: `[PROTO://][IP_ADDRESS]:PORT`, where `PROTO` could be `tcp` or
`udp`.
......
......@@ -3,7 +3,8 @@ title: "mg_broadcast()"
decl_name: "mg_broadcast"
symbol_kind: "func"
signature: |
void mg_broadcast(struct mg_mgr *, mg_event_handler_t func, void *, size_t);
void mg_broadcast(struct mg_mgr *mgr, mg_event_handler_t cb, void *data,
size_t len);
---
Passes a message of a given length to all connections.
......
......@@ -18,7 +18,7 @@ Subnet masks may vary from 0 to 32, inclusive. The default setting
is to allow all access. 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
`-0.0.0.0/0,+192.168/16` - deny all accesses, only allow 192.168/16 subnet
To learn more about subnet masks, see this
link:https://en.wikipedia.org/wiki/Subnetwork[Wikipedia page on Subnetwork].
......
......@@ -4,7 +4,8 @@ decl_name: "mg_connect"
symbol_kind: "func"
signature: |
struct mg_connection *mg_connect(struct mg_mgr *mgr, const char *address,
mg_event_handler_t handler);
MG_CB(mg_event_handler_t handler,
void *user_data);
---
Connects to a remote host.
......
......@@ -4,8 +4,8 @@ decl_name: "mg_connect_opt"
symbol_kind: "func"
signature: |
struct mg_connection *mg_connect_opt(struct mg_mgr *mgr, const char *address,
mg_event_handler_t handler,
struct mg_connect_opts opts);
MG_CB(mg_event_handler_t handler,
void *user_data);
---
Connects to a remote host.
......
---
title: "mg_enable_javascript()"
decl_name: "mg_enable_javascript"
symbol_kind: "func"
signature: |
enum v7_err mg_enable_javascript(struct mg_mgr *m, struct v7 *v7,
const char *init_js_file_name);
---
Enables server-side JavaScript scripting.
Requires a `-DMG_ENABLE_JAVASCRIPT` compilation flag and V7 engine sources.
V7 instance must not be destroyed during manager's lifetime.
Returns a V7 error.
......@@ -4,7 +4,7 @@ decl_name: "mg_event_handler_t"
symbol_kind: "typedef"
signature: |
typedef void (*mg_event_handler_t)(struct mg_connection *nc, int ev,
void *ev_data);
void *ev_data MG_UD_ARG(void *user_data));
---
Callback function (event handler) prototype. Must be defined by the user.
......
......@@ -3,7 +3,7 @@ title: "mg_next()"
decl_name: "mg_next"
symbol_kind: "func"
signature: |
struct mg_connection *mg_next(struct mg_mgr *, struct mg_connection *);
struct mg_connection *mg_next(struct mg_mgr *mgr, struct mg_connection *c);
---
Iterates over all active connections.
......
......@@ -8,6 +8,7 @@ signature: |
unsigned int flags; /* Extra connection flags */
const char **error_string; /* Placeholder for the error string */
struct mg_iface *iface; /* Interface instance */
const char *nameserver; /* DNS server to use, NULL for default */
#if MG_ENABLE_SSL
/*
* SSL settings.
......
......@@ -14,9 +14,7 @@ signature: |
void *user_data; /* User data */
int num_ifaces;
struct mg_iface **ifaces; /* network interfaces */
#if MG_ENABLE_JAVASCRIPT
struct v7 *v7;
#endif
const char *nameserver; /* DNS server to use */
};
---
......
......@@ -4,9 +4,10 @@ decl_name: "struct mg_mgr_init_opts"
symbol_kind: "struct"
signature: |
struct mg_mgr_init_opts {
struct mg_iface_vtable *main_iface;
const struct mg_iface_vtable *main_iface;
int num_ifaces;
struct mg_iface_vtable **ifaces;
const struct mg_iface_vtable **ifaces;
const char *nameserver;
};
---
......
......@@ -6,6 +6,7 @@ items:
- { name: mg_resolve_async.md }
- { name: mg_resolve_async_opt.md }
- { name: mg_resolve_from_hosts_file.md }
- { name: mg_set_nameserver.md }
- { name: struct_mg_resolve_async_opts.md }
---
......
---
title: "mg_set_nameserver()"
decl_name: "mg_set_nameserver"
symbol_kind: "func"
signature: |
void mg_set_nameserver(struct mg_mgr *mgr, const char *nameserver);
---
Set default DNS server
......@@ -4,7 +4,7 @@ decl_name: "struct mg_resolve_async_opts"
symbol_kind: "struct"
signature: |
struct mg_resolve_async_opts {
const char *nameserver_url;
const char *nameserver;
int max_retries; /* defaults to 2 if zero */
int timeout; /* in seconds; defaults to 5 if zero */
int accept_literal; /* pseudo-resolve literal ipv4 and ipv6 addrs */
......
......@@ -3,6 +3,7 @@ title: "URI"
symbol_kind: "intro"
decl_name: "uri.h"
items:
- { name: mg_assemble_uri.md }
- { name: mg_parse_uri.md }
---
......
---
title: "mg_assemble_uri()"
decl_name: "mg_assemble_uri"
symbol_kind: "func"
signature: |
int mg_assemble_uri(const struct mg_str *scheme, const struct mg_str *user_info,
const struct mg_str *host, unsigned int port,
const struct mg_str *path, const struct mg_str *query,
const struct mg_str *fragment, int normalize_path,
struct mg_str *uri);
---
Assemble URI from parts. Any of the inputs can be NULL or zero-length mg_str.
If normalize_path is true, path is normalized by resolving relative refs.
Result is a heap-allocated string (uri->p must be free()d after use).
Returns 0 on success, -1 on error.
......@@ -3,7 +3,7 @@ title: "mg_parse_uri()"
decl_name: "mg_parse_uri"
symbol_kind: "func"
signature: |
int mg_parse_uri(struct mg_str uri, struct mg_str *scheme,
int mg_parse_uri(const struct mg_str uri, struct mg_str *scheme,
struct mg_str *user_info, struct mg_str *host,
unsigned int *port, struct mg_str *path, struct mg_str *query,
struct mg_str *fragment);
......
......@@ -8,20 +8,21 @@ items:
- { name: mg_basic_auth_header.md }
- { name: mg_conn_addr_to_str.md }
- { name: mg_fopen.md }
- { name: mg_fread.md }
- { name: mg_fwrite.md }
- { name: mg_hexdump.md }
- { name: mg_hexdump_connection.md }
- { name: mg_hexdumpf.md }
- { name: mg_is_big_endian.md }
- { name: mg_match_prefix.md }
- { name: mg_mbuf_append_base64.md }
- { name: mg_mbuf_append_base64_putc.md }
- { name: mg_next_comma_list_entry.md }
- { name: mg_open.md }
- { name: mg_skip.md }
- { name: mg_sock_addr_to_str.md }
- { name: mg_sock_to_str.md }
- { name: mg_start_thread.md }
- { name: mg_stat.md }
- { name: mg_url_encode.md }
---
......
......@@ -3,7 +3,8 @@ title: "mg_basic_auth_header()"
decl_name: "mg_basic_auth_header"
symbol_kind: "func"
signature: |
void mg_basic_auth_header(const char *user, const char *pass, struct mbuf *buf);
void mg_basic_auth_header(const struct mg_str user, const struct mg_str pass,
struct mbuf *buf);
---
Generate a Basic Auth header and appends it to buf.
......
......@@ -3,7 +3,7 @@ title: "mg_conn_addr_to_str()"
decl_name: "mg_conn_addr_to_str"
symbol_kind: "func"
signature: |
void mg_conn_addr_to_str(struct mg_connection *nc, char *buf, size_t len,
int mg_conn_addr_to_str(struct mg_connection *c, char *buf, size_t len,
int flags);
---
......@@ -18,4 +18,5 @@ see `MG_SOCK_STRINGIFY_*` definitions.
If both port number and IP address are printed, they are separated by `:`.
If compiled with `-DMG_ENABLE_IPV6`, IPv6 addresses are supported.
Return length of the stringified address.
---
title: "mg_fread()"
decl_name: "mg_fread"
symbol_kind: "func"
signature: |
size_t mg_fread(void *ptr, size_t size, size_t count, FILE *f);
---
Reads data from the given file stream.
Return value is a number of bytes readen.
---
title: "mg_fwrite()"
decl_name: "mg_fwrite"
symbol_kind: "func"
signature: |
size_t mg_fwrite(const void *ptr, size_t size, size_t count, FILE *f);
---
Writes data to the given file stream.
Return value is a number of bytes wtitten.
---
title: "mg_match_prefix()"
decl_name: "mg_match_prefix"
symbol_kind: "func"
signature: |
int mg_match_prefix(const char *pattern, int pattern_len, const char *str);
---
Matches 0-terminated string (mg_match_prefix) or string with given length
mg_match_prefix_n against a glob pattern.
Match is case-insensitive. Returns number of bytes matched, or -1 if no
match.
---
title: "mg_next_comma_list_entry()"
decl_name: "mg_next_comma_list_entry"
symbol_kind: "func"
signature: |
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.
The value is stored in a val vector. If the value has a form "x=y", then
eq_val vector is initialised to point to the "y" part, and val vector length
is adjusted to point only to "x".
If the 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.
......@@ -3,7 +3,7 @@ title: "mg_sock_addr_to_str()"
decl_name: "mg_sock_addr_to_str"
symbol_kind: "func"
signature: |
void mg_sock_addr_to_str(const union socket_address *sa, char *buf, size_t len,
int mg_sock_addr_to_str(const union socket_address *sa, char *buf, size_t len,
int flags);
---
......
---
title: "mg_url_encode()"
decl_name: "mg_url_encode"
symbol_kind: "func"
signature: |
struct mg_str mg_url_encode(const struct mg_str src);
---
URL-escape the specified string.
All non-printable characters are escaped, plus `._-$,;~()/`.
Input need not be NUL-terminated, but the returned string is.
Returned string is heap-allocated and must be free()'d.
......@@ -16,7 +16,7 @@ CGI file must be executable. Mongoose honours the shebang line - see
http://en.wikipedia.org/wiki/Shebang_(Unix).
For example, if both PHP and Perl CGIs are used, then
``#!/path/to/php-cgi.exe` and ``#!/path/to/perl.exe` must be the first lines
`#!/path/to/php-cgi.exe` and `#!/path/to/perl.exe` must be the first lines
of the respective CGI scripts.
It is possible to hardcode the path to the CGI interpreter for all
......@@ -29,3 +29,7 @@ Example:
```c
opts.cgi_interpreter = "C:\\ruby\\ruby.exe";
```
NOTE: In the CGI handler we don't use explicitly a system call waitpid() for
reaping zombie processes. Instead, we set the SIGCHLD handler to SIG_IGN.
It will cause zombie processes to be reaped automatically.
CAUTION: not all OSes (e.g. QNX) reap zombies if SIGCHLD is ignored.
\ No newline at end of file
......@@ -18,8 +18,9 @@ static int exit_flag = 0;
static void ev_handler(struct mg_connection *c, int ev, void *p) {
if (ev == MG_EV_HTTP_REPLY) {
struct http_message *hm = (struct http_message *)p;
c->flags |= MG_F_CLOSE_IMMEDIATELY;
fwrite(hm->message.p, 1, hm->message.len, stdout);
fwrite(hm->message.p, 1, (int)hm->message.len, stdout);
putchar('\n');
exit_flag = 1;
} else if (ev == MG_EV_CLOSE) {
......@@ -31,7 +32,7 @@ int main(void) {
struct mg_mgr mgr;
mg_mgr_init(&mgr, NULL);
mg_connect_http(mgr, ev_handler, url, NULL, NULL);
mg_connect_http(&mgr, ev_handler, url, NULL, NULL);
while (exit_flag == 0) {
......
......@@ -30,8 +30,8 @@ static void ev_handler(struct mg_connection *c, int ev, void *p) {
// We have received an HTTP request. Parsed request is contained in `hm`.
// Send HTTP reply to the client which shows full original request.
mg_send_head(c, 200, hm.message.len, "Content-Type: text/plain");
mg_printf(c, "%.*s", hm.message.len, hm.message.p);
mg_send_head(c, 200, hm->message.len, "Content-Type: text/plain");
mg_printf(c, "%.*s", (int)hm->message.len, hm->message.p);
}
}
......
......@@ -35,7 +35,7 @@ The exec directive is used to execute a command on a server,
and show command's output. Example: `<!--#exec "ls -l" -->`
The call directive is a way to invoke a C handler from the HTML page.
On each occurence of `<!--#call PARAMS -->` directive,
On each occurrence of `<!--#call PARAMS -->` directive,
Mongoose calls a registered event handler with `MG_EV_SSI_CALL` event.
Event parameter will point to the `PARAMS` string.
An event handler can output any text, for example by calling
......
......@@ -30,4 +30,4 @@ int main(void) {
}
```
For the full example, please see the [Simplest HTTPS server example](https://github.com/cesanta/dev/tree/master/mongoose/examples/simplest_web_server_ssl).
For the full example, please see the [Simplest HTTPS server example](https://github.com/cesanta/mongoose/tree/master/examples/simplest_web_server_ssl).
......@@ -3,6 +3,6 @@ title: Disabling flags
---
- `MG_DISABLE_HTTP_DIGEST_AUTH` disable HTTP Digest (MD5) authorisation support
- `MG_DISABLE_SHA1` disable SHA1 support (used by WebSocket)
- `MG_DISABLE_MD5` disable MD5 support (used by HTTP auth)
- `CS_DISABLE_SHA1` disable SHA1 support (used by WebSocket)
- `CS_DISABLE_MD5` disable MD5 support (used by HTTP auth)
- `MG_DISABLE_HTTP_KEEP_ALIVE` useful for embedded systems to save resources
......@@ -9,3 +9,4 @@ title: Tunables
- `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.
- `MG_USER_FILE_FUNCTIONS` allow you to use custom file operation, by defining you own `mg_stat`, `mg_fopen`, `mg_open`, `mg_fread` and `mg_fwrite` functions
\ No newline at end of file
......@@ -22,7 +22,7 @@ IPATH = . ../.. $(REPO_PATH)
VPATH = ../..
MONGOOSE_FEATURES = -DMG_ENABLE_SSL -DMG_ENABLE_HTTP_STREAMING_MULTIPART
MONGOOSE_FEATURES = -DMG_ENABLE_SSL -DMG_ENABLE_HTTP_STREAMING_MULTIPART -DMG_MODULE_LINES
SDK_FLAGS = -DUSE_FREERTOS -DSL_PLATFORM_MULTI_THREADED
# -DTARGET_IS_CC3200 would reduce code size by using functions in ROM
......@@ -58,11 +58,11 @@ $(FW_DIR):
$(FW_ZIP): $(FW_ELF) $(FW_BIN) $(SLFS_FILES)
@echo " Code size: $(shell ls -l $(FW_BIN) | awk '{print $$5}')"
@echo " GEN $(FW_MANIFEST)"
@fw_meta gen_build_info \
@fw_meta.py gen_build_info \
--json_output=$(BUILD_INFO_JSON)
@cp -v $(SLFS_FILES) out/
@cp $(CC3200_SP_FILE)* $(FW_DIR)
@fw_meta create_manifest \
@fw_meta.py create_manifest \
--name=$(PROG) --platform=$(PLATFORM) \
--build_info=$(BUILD_INFO_JSON) \
--output=$(FW_MANIFEST) \
......@@ -72,14 +72,14 @@ $(FW_ZIP): $(FW_ELF) $(FW_BIN) $(SLFS_FILES)
/sys/mcuimg.bin:type=app,src=$(notdir $(FW_BIN)) \
$(foreach f,$(SLFS_FILES), $(notdir $(f)):type=slfile,src=$(notdir $(f)))
@echo " ZIP $@"
@fw_meta create_fw \
@fw_meta.py create_fw \
--manifest=$(FW_MANIFEST) \
--src_dir=$(FW_DIR) \
--output=$@
FREERTOS_SRCS = timers.c list.c queue.c tasks.c port.c heap_3.c osi_freertos.c
DRIVER_SRCS = cpu.c gpio.c gpio_if.c i2c.c i2c_if.c interrupt.c pin.c prcm.c spi.c uart.c udma.c utils.c
SL_SRCS = socket.c wlan.c driver.c device.c netapp.c netcfg.c network_common.c cc_pal.c fs.c
SL_SRCS = socket.c wlan.c driver.c device.c netapp.c netcfg.c network_common.c timer.c cc_pal.c fs.c
SDK_SRCS = startup_gcc.c $(FREERTOS_SRCS) $(DRIVER_SRCS) $(SL_SRCS)
IPATH += $(SDK_PATH) $(SDK_PATH)/inc $(SDK_PATH)/driverlib \
$(SDK_PATH)/example/common $(SDK_PATH)/oslib \
......
......@@ -40,12 +40,12 @@ void cs_log_set_level(enum cs_log_level level);
void cs_log_set_file(FILE *file);
extern enum cs_log_level cs_log_level;
extern enum cs_log_level cs_log_threshold;
void cs_log_print_prefix(const char *func);
void cs_log_printf(const char *fmt, ...);
#define LOG(l, x) \
if (cs_log_level >= l) { \
if (cs_log_threshold >= l) { \
cs_log_print_prefix(__func__); \
cs_log_printf x; \
}
......@@ -53,7 +53,7 @@ void cs_log_printf(const char *fmt, ...);
#ifndef CS_NDEBUG
#define DBG(x) \
if (cs_log_level >= LL_VERBOSE_DEBUG) { \
if (cs_log_threshold >= LL_VERBOSE_DEBUG) { \
cs_log_print_prefix(__func__); \
cs_log_printf x; \
}
......
......@@ -294,3 +294,16 @@ void SimpleLinkGeneralEventHandler(SlDeviceEvent_t *e) {
LOG(LL_ERROR, ("status %d sender %d", e->EventData.deviceEvent.status,
e->EventData.deviceEvent.sender));
}
#ifndef __TI_COMPILER_VERSION__
int _gettimeofday_r(struct _reent *r, struct timeval *tp, void *tz) {
#else
int gettimeofday(struct timeval *tp, void *tz) {
#endif
unsigned long sec;
unsigned short msec;
MAP_PRCMRTCGet(&sec, &msec);
tp->tv_sec = sec;
tp->tv_usec = ((unsigned long) msec) * 1000;
return 0;
}
docker.cesanta.com/cc3200-build:1.2.0-r8
docker.cesanta.com/cc3200-build:1.3.0-r2
SDK_VER=$(shell cat sdk.version)
.PHONY: all
MG_PATH = $(realpath $(PWD)/../../)
all:
docker run --rm -it -v $(MG_PATH):/esp32_idf \
$(SDK_VER) \
bash -c "cd esp32_idf/examples/ESP32_IDF && \
make -f Makefile.build defconfig && make -f Makefile.build"
clean:
docker run --rm -it -v $(MG_PATH):/esp32_idf \
$(SDK_VER) \
bash -c "rm -rf esp32_idf/examples/ESP32_IDF/build"
#
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
# project subdirectory.
#
PROJECT_NAME := esp32_idf
include $(IDF_PATH)/make/project.mk
This is a Mongoose "Hello, world" that can be compiled under Espressif IoT Development Framework for ESP32
It connects to WiFi network and serves a "hello world" page.
Most of the the boilerplate comes from [project_template](https://github.com/espressif/esp-idf-template) with minimal changes.
For building the example, you need to have [Docker](https://www.docker.com/products/docker) and use our pre-built SDK container.
To build just run in the example directory
```
$ make
```
Note: before building, change `WIFI_SSID` and `WIFI_PASS` macros in main/main.c file
Once built, use [esptool](https://github.com/espressif/esptool) for flashing
```
$ python esptool.py --chip esp32 --port /dev/ttyUSB0 --baud 115200 --before default_reset --after hard_reset write_flash -u --flash_mode dio --flash_freq 40m --flash_size detect 0x1000 build/bootloader/bootloader.bin 0x10000 build/esp32_idf.bin 0x8000 build/partitions_singleapp.bin
```
#
# Main component makefile.
#
# This Makefile can be left empty. By default, it will take the sources in the
# src/ directory, compile them and link them into lib(subdirectory_name).a
# in the build directory. This behaviour is entirely configurable,
# please read the ESP-IDF documents if you need to do this.
#
COMPONENT_OBJS = main.o mongoose.o
mongoose.o: ../../../../mongoose.c
$(summary) "CC $@"
$(CC) $(CFLAGS) $(CPPFLAGS) \
$(addprefix -I ,$(COMPONENT_INCLUDES)) \
$(addprefix -I ,$(COMPONENT_EXTRA_INCLUDES)) \
-c $< -o $@
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "esp_event.h"
#include "esp_event_loop.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "nvs_flash.h"
#include "./../../../mongoose.h"
#define WIFI_SSID "ssid"
#define WIFI_PASS "pass"
#define MG_LISTEN_ADDR "80"
static esp_err_t event_handler(void *ctx, system_event_t *event) {
(void) ctx;
(void) event;
return ESP_OK;
}
static void mg_ev_handler(struct mg_connection *nc, int ev, void *p) {
static const char *reply_fmt =
"HTTP/1.0 200 OK\r\n"
"Connection: close\r\n"
"Content-Type: text/plain\r\n"
"\r\n"
"Hello %s\n";
switch (ev) {
case MG_EV_ACCEPT: {
char addr[32];
mg_sock_addr_to_str(&nc->sa, addr, sizeof(addr),
MG_SOCK_STRINGIFY_IP | MG_SOCK_STRINGIFY_PORT);
printf("Connection %p from %s\n", nc, addr);
break;
}
case MG_EV_HTTP_REQUEST: {
char addr[32];
struct http_message *hm = (struct http_message *) p;
mg_sock_addr_to_str(&nc->sa, addr, sizeof(addr),
MG_SOCK_STRINGIFY_IP | MG_SOCK_STRINGIFY_PORT);
printf("HTTP request from %s: %.*s %.*s\n", addr, (int) hm->method.len,
hm->method.p, (int) hm->uri.len, hm->uri.p);
mg_printf(nc, reply_fmt, addr);
nc->flags |= MG_F_SEND_AND_CLOSE;
break;
}
case MG_EV_CLOSE: {
printf("Connection %p closed\n", nc);
break;
}
}
}
void app_main(void) {
nvs_flash_init();
tcpip_adapter_init();
ESP_ERROR_CHECK(esp_event_loop_init(event_handler, NULL));
/* Initializing WiFi */
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM));
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
wifi_config_t sta_config = {
.sta = {.ssid = WIFI_SSID, .password = WIFI_PASS, .bssid_set = false}};
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &sta_config));
ESP_ERROR_CHECK(esp_wifi_start());
ESP_ERROR_CHECK(esp_wifi_connect());
/* Starting Mongoose */
struct mg_mgr mgr;
struct mg_connection *nc;
printf("Starting web-server on port %s\n", MG_LISTEN_ADDR);
mg_mgr_init(&mgr, NULL);
nc = mg_bind(&mgr, MG_LISTEN_ADDR, mg_ev_handler);
if (nc == NULL) {
printf("Error setting up listener!\n");
return;
}
mg_set_protocol_http_websocket(nc);
/* Processing events */
while (1) {
mg_mgr_poll(&mgr, 1000);
}
}
docker.cesanta.com/esp32-build:1.0-r13
#!/bin/bash
REPO=$(cd ../.. && pwd)
docker run \
--rm -i -v $(realpath ${PWD}/../..):/src \
--rm -i -v $REPO:/src \
--entrypoint=/bin/bash $(cat sdk.version) -l -c -x '
export SDK_PATH=/opt/Espressif/ESP8266_RTOS_SDK;
export BIN_PATH=./bin;
......
......@@ -3,7 +3,7 @@
# `wildcard ./*/` works in both linux and linux/wine, while `wildcard */` enumerates nothing under wine
SUBDIRS = $(sort $(dir $(wildcard ./*/)))
SUBDIRS:=$(filter-out ./ ./CC3200/ ./ESP8266_RTOS/ ./mbed/ ./MSP432/ ./nRF51/ ./nRF52/ ./NXP_K64/ ./NXP_LPC4088/ ./PIC32/ ./STM32F4_CC3100/ ./TM4C129/ ./WinCE/, $(SUBDIRS))
SUBDIRS:=$(filter-out ./ ./CC3200/ ./ESP32_IDF/ ./ESP8266_RTOS/ ./mbed/ ./MSP432/ ./nRF51/ ./nRF52/ ./NXP_K64/ ./NXP_LPC4088/ ./PIC32/ ./STM32F4_CC3100/ ./TM4C129/ ./WinCE/, $(SUBDIRS))
ifeq ($(OS), Windows_NT)
SUBDIRS:=$(filter-out ./netcat/ ./raspberry_pi_mjpeg_led/ ./captive_dns_server/, $(SUBDIRS))
......
......@@ -10,28 +10,13 @@
#include "mongoose.h"
static const char *s_http_port = "8000";
static struct mg_serve_http_opts s_http_server_opts;
struct file_writer_data {
FILE *fp;
size_t bytes_written;
};
static void handle_request(struct mg_connection *nc) {
// This handler gets for all endpoints but /upload
mg_printf(nc, "%s",
"HTTP/1.1 200 OK\r\n"
"Content-Type: text/html\r\n"
"Connection: close\r\n"
"\r\n"
"<html><body>Upload example."
"<form method=\"POST\" action=\"/upload\" "
" enctype=\"multipart/form-data\">"
"<input type=\"file\" name=\"file\" /> <br/>"
"<input type=\"submit\" value=\"Upload\" />"
"</form></body></html>");
nc->flags |= MG_F_SEND_AND_CLOSE;
}
static void handle_upload(struct mg_connection *nc, int ev, void *p) {
struct file_writer_data *data = (struct file_writer_data *) nc->user_data;
struct mg_http_multipart_part *mp = (struct mg_http_multipart_part *) p;
......@@ -82,25 +67,27 @@ static void handle_upload(struct mg_connection *nc, int ev, void *p) {
}
static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) {
(void) ev_data;
switch (ev) {
case MG_EV_HTTP_REQUEST:
// Invoked when the full HTTP request is in the buffer (including body).
handle_request(nc);
break;
if (ev == MG_EV_HTTP_REQUEST) {
mg_serve_http(nc, ev_data, s_http_server_opts);
}
}
int main(void) {
struct mg_mgr mgr;
struct mg_connection *nc;
struct mg_connection *c;
mg_mgr_init(&mgr, NULL);
nc = mg_bind(&mgr, s_http_port, ev_handler);
c = mg_bind(&mgr, s_http_port, ev_handler);
if (c == NULL) {
fprintf(stderr, "Cannot start server on port %s\n", s_http_port);
exit(EXIT_FAILURE);
}
s_http_server_opts.document_root = "."; // Serve current directory
mg_register_http_endpoint(c, "/upload", handle_upload MG_UD_ARG(NULL));
mg_register_http_endpoint(nc, "/upload", handle_upload);
// Set up HTTP server parameters
mg_set_protocol_http_websocket(nc);
mg_set_protocol_http_websocket(c);
printf("Starting web server on port %s\n", s_http_port);
for (;;) {
......
<!DOCTYPE html>
<html>
<head>
<title>AJAX Upload Example</title>
<script src="//code.jquery.com/jquery-1.9.1.js"></script>
<script type="text/javascript">
function updateProgress(evt) {
if (evt.lengthComputable) {
document.getElementById("output").textContent =
"Uploaded " + evt.loaded + " of " + evt.total + " bytes";
}
}
function uploadFile() {
var file_data = new FormData(document.getElementById('filename'));
$.ajax({
url: "/upload",
type: "POST",
data: file_data,
processData: false,
contentType: false,
cache: false,
xhr: function() {
myXhr = $.ajaxSettings.xhr();
if(myXhr.upload){
myXhr.upload.addEventListener('progress',updateProgress, false); // for handling the progress of the upload
}
return myXhr;
},
}).done(function(data) {
document.getElementById("output").textContent = "Result: " + data;
});
return false;
}
</script>
</head>
<body>
<h1>Upload file using standard form upload</h1>
<form method="POST" action="/upload" enctype="multipart/form-data">
<label>Select a file:</label><br>
<input type="file" name="file" />
<input type="submit" value="Upload" />
</form>
<h1>Upload file using Ajax - that also gives progress report</h1>
<form method="post" id="filename" name="filename" onsubmit="return uploadFile();">
<label>Select a file:</label><br>
<input type="file" id="file" name="file" required />
<input type="submit" value="Upload" />
</form>
<br><br><div id="output"></div>
</body>
</html>
PROG = mqtt_broker
MODULE_CFLAGS = -DMG_ENABLE_MQTT_BROKER -DMG_ENABLE_HTTP=0
SSL_LIB=openssl
#SSL_LIB=openssl
include ../examples.mk
......@@ -17,22 +17,31 @@
#include "../../mongoose.h"
static const char *s_listening_address = "0.0.0.0:1883";
static void ev_handler(struct mg_connection *c, int ev, void *ev_data) {
if (ev != MG_EV_POLL) printf("USER HANDLER GOT EVENT %d\n", ev);
/* Do your custom event processing here */
mg_mqtt_broker(c, ev, ev_data);
}
int main(void) {
struct mg_mgr mgr;
const char *address = "0.0.0.0:1883";
struct mg_connection *nc;
struct mg_connection *c;
struct mg_mqtt_broker brk;
mg_mgr_init(&mgr, NULL);
mg_mqtt_broker_init(&brk, NULL);
if ((nc = mg_bind(&mgr, address, mg_mqtt_broker)) == NULL) {
fprintf(stderr, "mg_bind(%s) failed\n", address);
if ((c = mg_bind(&mgr, s_listening_address, ev_handler)) == NULL) {
fprintf(stderr, "mg_bind(%s) failed\n", s_listening_address);
exit(EXIT_FAILURE);
}
nc->user_data = &brk;
mg_mqtt_broker_init(&brk, NULL);
c->user_data = &brk;
mg_set_protocol_mqtt(c);
printf("MQTT broker started on %s\n", address);
printf("MQTT broker started on %s\n", s_listening_address);
/*
* TODO: Add a HTTP status page that shows current sessions
......
......@@ -27,10 +27,7 @@ static void ev_handler(struct mg_connection *nc, int ev, void *p) {
struct mg_mqtt_message *msg = (struct mg_mqtt_message *) p;
(void) nc;
#if 0
if (ev != MG_EV_POLL)
printf("USER HANDLER GOT %d\n", ev);
#endif
if (ev != MG_EV_POLL) printf("USER HANDLER GOT EVENT %d\n", ev);
switch (ev) {
case MG_EV_CONNECT: {
......
PROG = mqtt_over_websocket_server
MODULE_CFLAGS = -DMG_ENABLE_MQTT_BROKER=1
#SSL_LIB=mbedtls
include ../examples.mk
/*
* Copyright (c) 2014 Cesanta Software Limited
* All rights reserved
* This software is dual-licensed: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. For the terms of this
* license, see <http://www.gnu.org/licenses/>.
*
* You are free to use this software under the terms of the GNU General
* Public License, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* Alternatively, you can license this software under a commercial
* license, as set out in <https://www.cesanta.com/license>.
*/
#include "mongoose.h"
static const char *s_mqtt_address = "0.0.0.0:1883";
static const char *s_http_address = "0.0.0.0:8080";
static void unproxy(struct mg_connection *c) {
struct mg_connection *pc = (struct mg_connection *) c->user_data;
if (pc != NULL) {
pc->flags |= MG_F_CLOSE_IMMEDIATELY;
pc->user_data = NULL;
c->user_data = NULL;
}
printf("Closing connection %p\n", c);
}
static void proxy_handler(struct mg_connection *c, int ev, void *ev_data) {
if (ev == MG_EV_POLL) return;
printf("%p %s EVENT %d %p\n", c, __func__, ev, ev_data);
switch (ev) {
case MG_EV_CLOSE: {
unproxy(c);
break;
}
case MG_EV_RECV: {
struct mg_connection *pc = (struct mg_connection *) c->user_data;
if (pc != NULL) {
mg_send_websocket_frame(pc, WEBSOCKET_OP_BINARY, c->recv_mbuf.buf,
c->recv_mbuf.len);
mbuf_remove(&c->recv_mbuf, c->recv_mbuf.len);
}
break;
}
}
}
static void http_handler(struct mg_connection *c, int ev, void *ev_data) {
struct mg_connection *pc = (struct mg_connection *) c->user_data;
if (ev == MG_EV_POLL) return;
printf("%p %s EVENT %d %p\n", c, __func__, ev, ev_data);
/* Do your custom event processing here */
switch (ev) {
case MG_EV_WEBSOCKET_HANDSHAKE_DONE: {
pc = mg_connect(c->mgr, s_mqtt_address, proxy_handler);
pc->user_data = c;
c->user_data = pc;
printf("Created proxy connection %p\n", pc);
break;
}
case MG_EV_WEBSOCKET_FRAME: {
struct websocket_message *wm = (struct websocket_message *) ev_data;
if (pc != NULL) {
printf("Forwarding %d bytes\n", (int) wm->size);
mg_send(pc, wm->data, wm->size);
}
break;
}
case MG_EV_CLOSE: {
unproxy(c);
break;
}
}
}
static void mqtt_handler(struct mg_connection *c, int ev, void *ev_data) {
if (ev == MG_EV_POLL) return;
printf("%p %s EVENT %d %p\n", c, __func__, ev, ev_data);
/* Do your custom event processing here */
switch (ev) {
case MG_EV_CLOSE:
printf("Closing MQTT connection %p\n", c);
break;
}
mg_mqtt_broker(c, ev, ev_data);
}
static void start_mqtt_server(struct mg_mgr *mgr, const char *addr) {
struct mg_connection *c;
static struct mg_mqtt_broker brk; // static is important - must not perish
if ((c = mg_bind(mgr, addr, mqtt_handler)) == NULL) {
fprintf(stderr, "Cannot start MQTT server on port [%s]\n", addr);
exit(EXIT_FAILURE);
}
mg_mqtt_broker_init(&brk, NULL);
c->user_data = &brk;
mg_set_protocol_mqtt(c);
printf("MQTT server started on %s\n", addr);
}
static void start_http_server(struct mg_mgr *mgr, const char *addr) {
struct mg_connection *c;
if ((c = mg_bind(mgr, addr, http_handler)) == NULL) {
fprintf(stderr, "Cannot start HTTP server on port [%s]\n", addr);
exit(EXIT_FAILURE);
}
mg_set_protocol_http_websocket(c);
printf("HTTP server started on %s\n", addr);
}
int main(void) {
struct mg_mgr mgr;
mg_mgr_init(&mgr, NULL);
start_http_server(&mgr, s_http_address);
start_mqtt_server(&mgr, s_mqtt_address);
for (;;) {
mg_mgr_poll(&mgr, 1000);
}
}
PROG = multithreaded
MODULE_CFLAGS=-DMG_ENABLE_THREADS
include ../examples.mk
/*
* Copyright (c) 2014-2017 Cesanta Software Limited
* All rights reserved
*/
#include "mongoose.h"
static sig_atomic_t s_received_signal = 0;
static const char *s_http_port = "8000";
static const int s_num_worker_threads = 5;
static unsigned long s_next_id = 0;
static void signal_handler(int sig_num) {
signal(sig_num, signal_handler);
s_received_signal = sig_num;
}
static struct mg_serve_http_opts s_http_server_opts;
static sock_t sock[2];
// This info is passed to the worker thread
struct work_request {
unsigned long conn_id; // needed to identify the connection where to send the reply
// optionally, more data that could be required by worker
};
// This info is passed by the worker thread to mg_broadcast
struct work_result {
unsigned long conn_id;
int sleep_time;
};
static void on_work_complete(struct mg_connection *nc, int ev, void *ev_data) {
(void) ev;
char s[32];
struct mg_connection *c;
for (c = mg_next(nc->mgr, NULL); c != NULL; c = mg_next(nc->mgr, c)) {
if (c->user_data != NULL) {
struct work_result *res = (struct work_result *)ev_data;
if ((unsigned long)c->user_data == res->conn_id) {
sprintf(s, "conn_id:%lu sleep:%d", res->conn_id, res->sleep_time);
mg_send_head(c, 200, strlen(s), "Content-Type: text/plain");
mg_printf(c, "%s", s);
}
}
}
}
void *worker_thread_proc(void *param) {
struct mg_mgr *mgr = (struct mg_mgr *) param;
struct work_request req = {0};
while (s_received_signal == 0) {
if (read(sock[1], &req, sizeof(req)) < 0)
perror("Reading worker sock");
int r = rand() % 10;
sleep(r);
struct work_result res = {req.conn_id, r};
mg_broadcast(mgr, on_work_complete, (void *)&res, sizeof(res));
}
return NULL;
}
static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) {
(void) nc;
(void) ev_data;
switch (ev) {
case MG_EV_ACCEPT:
nc->user_data = (void *)++s_next_id;
break;
case MG_EV_HTTP_REQUEST: {
struct work_request req = {(unsigned long)nc->user_data};
if (write(sock[0], &req, sizeof(req)) < 0)
perror("Writing worker sock");
break;
}
case MG_EV_CLOSE: {
if (nc->user_data) nc->user_data = NULL;
}
}
}
int main(void) {
struct mg_mgr mgr;
struct mg_connection *nc;
int i;
if (mg_socketpair(sock, SOCK_STREAM) == 0) {
perror("Opening socket pair");
exit(1);
}
signal(SIGTERM, signal_handler);
signal(SIGINT, signal_handler);
mg_mgr_init(&mgr, NULL);
nc = mg_bind(&mgr, s_http_port, ev_handler);
if (nc == NULL) {
printf("Failed to create listener\n");
return 1;
}
mg_set_protocol_http_websocket(nc);
s_http_server_opts.document_root = "."; // Serve current directory
s_http_server_opts.enable_directory_listing = "no";
for (i = 0; i < s_num_worker_threads; i++) {
mg_start_thread(worker_thread_proc, &mgr);
}
printf("Started on port %s\n", s_http_port);
while (s_received_signal == 0) {
mg_mgr_poll(&mgr, 200);
}
mg_mgr_free(&mgr);
closesocket(sock[0]);
closesocket(sock[1]);
return 0;
}
......@@ -118,7 +118,7 @@ BUILD_DIRECTORIES := $(sort $(OBJECT_DIRECTORY) $(OUTPUT_BINARY_DIRECTORY) $(LIS
# Mongoose features
MG_FEATURES_TINY = \
-DMG_DISABLE_HTTP_DIGEST_AUTH \
-DMG_DISABLE_MD5 \
-DCS_DISABLE_MD5 \
-DMG_DISABLE_HTTP_KEEP_ALIVE \
-DMG_ENABLE_HTTP_SSI=0 \
-DMG_ENABLE_HTTP_STREAMING_MULTIPART
......
......@@ -165,7 +165,7 @@ BUILD_DIRECTORIES := $(sort $(OBJECT_DIRECTORY) $(OUTPUT_BINARY_DIRECTORY) $(LIS
# Mongoose features
MG_FEATURES_TINY = \
-DMG_DISABLE_HTTP_DIGEST_AUTH \
-DMG_DISABLE_MD5 \
-DCS_DISABLE_MD5 \
-DMG_DISABLE_HTTP_KEEP_ALIVE \
-DMG_ENABLE_HTTP_SSI=0 \
-DMG_ENABLE_HTTP_STREAMING_MULTIPART
......
PROG = websocket_chat
MODULE_CFLAGS = -DMG_ENABLE_FILESYSTEM=0
MODULE_CFLAGS = -DMG_ENABLE_FILESYSTEM=1
include ../examples.mk
......@@ -7,6 +7,7 @@
static sig_atomic_t s_signal_received = 0;
static const char *s_http_port = "8000";
static struct mg_serve_http_opts s_http_server_opts;
static void signal_handler(int sig_num) {
signal(sig_num, signal_handler); // Reinstantiate signal handler
......@@ -46,6 +47,10 @@ static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) {
broadcast(nc, d);
break;
}
case MG_EV_HTTP_REQUEST: {
mg_serve_http(nc, (struct http_message *) ev_data, s_http_server_opts);
break;
}
case MG_EV_CLOSE: {
/* Disconnect. Tell everybody. */
if (is_websocket(nc)) {
......@@ -69,6 +74,8 @@ int main(void) {
nc = mg_bind(&mgr, s_http_port, ev_handler);
mg_set_protocol_http_websocket(nc);
s_http_server_opts.document_root = "."; // Serve current directory
s_http_server_opts.enable_directory_listing = "yes";
printf("Started on port %s\n", s_http_port);
while (s_signal_received == 0) {
......
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment