diff --git a/docs/README.md b/docs/README.md
index 60582f66..2670eb42 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -1835,6 +1835,40 @@ mg_tls_init(c, &opts);
## Timer
+### mg\_timer\_add()
+
+```c
+struct timer *mg_timer_add(struct mg_mgr *mgr,
+ uint64_t period_ms, unsigned flags,
+ void (*fn)(void *), void *fn_data);
+```
+
+Setup a timer. This is a high-level timer API that allows to add a software
+timer to the event manager. This function `calloc()`s a new timer and
+adds it to the `mgr->timers` list. All added timers are polled when
+`mg_mgr_poll()` is called, and called if expired.
+
+NOTE: Make sure that the timer
+interval is equal or more to the `mg_mgr_poll()` timeout.
+
+Parameters:
+- `mgr` - Pointer to `mg_mgr` event manager structure
+- `ms` - An interval in milliseconds
+- `flags` - Timer flags bitmask, `MG_TIMER_REPEAT` and `MG_TIMER_RUN_NOW`
+- `fn` - Function to invoke
+- `fn_data` - Function argument
+
+Return value: None
+
+Usage example:
+```c
+void timer_fn(void *data) {
+ // ...
+}
+
+mg_timer_add(mgr, 1000, MG_TIMER_REPEAT, timer_fn, NULL);
+```
+
### struct mg\_timer
```c
@@ -1856,13 +1890,15 @@ as the `mg_mgr_poll()` timeout argument in the main event loop.
### mg\_timer\_init()
```c
-void mg_timer_init(struct mg_timer *t, uint64_t period_ms, unsigned flags,
+void mg_timer_init(struct mg_timer **head,
+ struct mg_timer *t, uint64_t period_ms, unsigned flags,
void (*fn)(void *), void *fn_data);
```
Setup a timer.
Parameters:
+- `head` - Pointer to `mg_timer` list head
- `t` - Pointer to `mg_timer` that should be initialized
- `ms` - An interval in milliseconds
- `flags` - Timer flags bitmask, `MG_TIMER_REPEAT` and `MG_TIMER_RUN_NOW`
@@ -1877,19 +1913,19 @@ void timer_fn(void *data) {
// ...
}
-struct mg_timer timer;
-mg_timer_init(&timer, 1000 /* 1sec */, MG_TIMER_REPEAT, timer_fn, NULL);
-// A timer gets initialized and linked into the internal timers list
+struct mg_timer timer, *head = NULL;
+mg_timer_init(&head, &timer, 1000, MG_TIMER_REPEAT, timer_fn, NULL);
```
### mg\_timer\_free()
```c
-void mg_timer_free(struct mg_timer *t);
+void mg_timer_free(struct mg_timer **head, struct mg_timer *t);
```
Free timer, remove it from the internal timers list.
Parameters:
+- `head` - Pointer to `mg_timer` list head
- `t` - Timer to free
Return value: None
@@ -1904,7 +1940,7 @@ mg_timer_free(&timer);
### mg\_timer\_poll()
```c
-void mg_timer_poll(uint64_t uptime_ms);
+void mg_timer_poll(struct mg_timer **head, uint64_t uptime_ms);
```
Traverse list of timers and call them if current timestamp `uptime_ms` is
@@ -1914,6 +1950,7 @@ Note, that `mg_mgr_poll` function internally calls `mg_timer_poll`; therefore,
in most cases it is unnecessary to call it explicitly.
Parameters:
+- `head` - Pointer to `mg_timer` list head
- `uptime_ms` - current timestamp
Return value: None
diff --git a/examples/complete/main.c b/examples/complete/main.c
index a1a89741..c875dd12 100644
--- a/examples/complete/main.c
+++ b/examples/complete/main.c
@@ -192,15 +192,12 @@ static void log_cb(void *arg) {
int main(void) {
struct mg_mgr mgr;
- struct mg_timer t1, t2;
mg_mgr_init(&mgr);
mg_http_listen(&mgr, "http://localhost:8000", cb, &mgr);
- mg_timer_init(&t1, 500, MG_TIMER_REPEAT, mjpeg_cb, &mgr);
- mg_timer_init(&t2, 1000, MG_TIMER_REPEAT, log_cb, &mgr);
+ mg_timer_add(&mgr, 500, MG_TIMER_REPEAT, mjpeg_cb, &mgr);
+ mg_timer_add(&mgr, 1000, MG_TIMER_REPEAT, log_cb, &mgr);
for (;;) mg_mgr_poll(&mgr, 50);
- mg_timer_free(&t1);
- mg_timer_free(&t2);
mg_mgr_free(&mgr);
return 0;
diff --git a/examples/form-upload/main.c b/examples/form-upload/main.c
index 98c02cdf..0f8153a8 100644
--- a/examples/form-upload/main.c
+++ b/examples/form-upload/main.c
@@ -39,7 +39,6 @@ static void cb(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
int main(void) {
struct mg_mgr mgr;
- struct mg_timer t1;
mg_mgr_init(&mgr);
mg_log_set("3");
diff --git a/examples/http-client/main.c b/examples/http-client/main.c
index 535c699e..2ff3ca8a 100644
--- a/examples/http-client/main.c
+++ b/examples/http-client/main.c
@@ -13,16 +13,16 @@
// The very first web page in history. You can replace it from command line
static const char *s_url = "http://info.cern.ch/";
-static const char *s_post_data = NULL; // POST data
-static const int64_t s_timeout_ms = 1500; // Connect timeout in milliseconds
+static const char *s_post_data = NULL; // POST data
+static const uint64_t s_timeout_ms = 1500; // Connect timeout in milliseconds
// Print HTTP response and signal that we're done
static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
if (ev == MG_EV_OPEN) {
// Connection created. Store connect expiration time in c->label
- *(int64_t *) c->label = mg_millis() + s_timeout_ms;
+ *(uint64_t *) c->label = mg_millis() + s_timeout_ms;
} else if (ev == MG_EV_POLL) {
- if (mg_millis() > *(int64_t *) c->label &&
+ if (mg_millis() > *(uint64_t *) c->label &&
(c->is_connecting || c->is_resolving)) {
mg_error(c, "Connect timeout");
}
diff --git a/examples/huge-response/main.c b/examples/huge-response/main.c
index 01fcea96..3e1c1f14 100644
--- a/examples/huge-response/main.c
+++ b/examples/huge-response/main.c
@@ -76,14 +76,12 @@ static void timer_fn(void *arg) {
int main(void) {
struct mg_mgr mgr;
- struct mg_timer t1;
mg_mgr_init(&mgr);
srand(time(NULL));
- mg_timer_init(&t1, 1000, MG_TIMER_REPEAT | MG_TIMER_RUN_NOW, timer_fn, NULL);
+ mg_timer_add(&mgr, 1000, MG_TIMER_REPEAT | MG_TIMER_RUN_NOW, timer_fn, NULL);
mg_http_listen(&mgr, s_listen_on, fn, NULL);
MG_INFO(("Listening on %s", s_listen_on));
for (;;) mg_mgr_poll(&mgr, 1000);
- mg_timer_free(&t1);
mg_mgr_free(&mgr);
return 0;
}
diff --git a/examples/json-rpc-over-websocket/main.c b/examples/json-rpc-over-websocket/main.c
index 7ad1be1b..24afa2ac 100644
--- a/examples/json-rpc-over-websocket/main.c
+++ b/examples/json-rpc-over-websocket/main.c
@@ -67,11 +67,10 @@ static void timer_fn(void *arg) {
}
int main(void) {
- struct mg_mgr mgr; // Event manager
- struct mg_timer t1; // Timer
+ struct mg_mgr mgr; // Event manager
mg_mgr_init(&mgr); // Init event manager
- mg_timer_init(&t1, 5000, MG_TIMER_REPEAT, timer_fn, &mgr); // Init timer
+ mg_timer_add(&mgr, 5000, MG_TIMER_REPEAT, timer_fn, &mgr); // Init timer
jsonrpc_init(NULL, NULL); // Init JSON-RPC instance
jsonrpc_export("sum", sum); // And export a couple
@@ -80,7 +79,6 @@ int main(void) {
printf("Starting WS listener on %s/websocket\n", s_listen_on);
mg_http_listen(&mgr, s_listen_on, fn, NULL); // Create HTTP listener
for (;;) mg_mgr_poll(&mgr, 1000); // Infinite event loop
- mg_timer_free(&t1); // Free timer resources
mg_mgr_free(&mgr); // Deallocate event manager
return 0;
}
diff --git a/examples/live-log/main.c b/examples/live-log/main.c
index b8ab2aaf..235a5c53 100644
--- a/examples/live-log/main.c
+++ b/examples/live-log/main.c
@@ -49,14 +49,12 @@ static void timer_fn(void *arg) {
int main(void) {
struct mg_mgr mgr;
- struct mg_timer t1;
mg_mgr_init(&mgr);
mg_http_listen(&mgr, "http://localhost:8000", cb, NULL);
- mg_timer_init(&t1, 1000, MG_TIMER_REPEAT, timer_fn, &mgr);
+ mg_timer_add(&mgr, 1000, MG_TIMER_REPEAT, timer_fn, &mgr);
for (;;) mg_mgr_poll(&mgr, 50);
- mg_timer_free(&t1);
mg_mgr_free(&mgr);
return 0;
diff --git a/examples/mqtt-client/main.c b/examples/mqtt-client/main.c
index 6e22bd79..38978bc8 100644
--- a/examples/mqtt-client/main.c
+++ b/examples/mqtt-client/main.c
@@ -74,17 +74,15 @@ static void timer_fn(void *arg) {
int main(void) {
struct mg_mgr mgr;
- struct mg_timer timer;
int topts = MG_TIMER_REPEAT | MG_TIMER_RUN_NOW;
signal(SIGINT, signal_handler); // Setup signal handlers - exist event
signal(SIGTERM, signal_handler); // manager loop on SIGINT and SIGTERM
- mg_mgr_init(&mgr); // Init event manager
- mg_timer_init(&timer, 3000, topts, timer_fn, &mgr); // Init timer
- while (s_signo == 0) mg_mgr_poll(&mgr, 1000); // Event loop, 1s timeout
- mg_mgr_free(&mgr); // Finished, cleanup
- mg_timer_free(&timer); // Free timer resources
+ mg_mgr_init(&mgr); // Init event manager
+ mg_timer_add(&mgr, 3000, topts, timer_fn, &mgr); // Init timer
+ while (s_signo == 0) mg_mgr_poll(&mgr, 1000); // Event loop, 1s timeout
+ mg_mgr_free(&mgr); // Finished, cleanup
return 0;
}
diff --git a/examples/timers/main.c b/examples/timers/main.c
index 88a21f0f..686d9611 100644
--- a/examples/timers/main.c
+++ b/examples/timers/main.c
@@ -40,13 +40,11 @@ static void timer_fn(void *arg) {
}
int main(void) {
- struct mg_mgr mgr; // Event manager
- struct mg_timer t1; // Timer
- mg_mgr_init(&mgr); // Initialise event manager
- mg_timer_init(&t1, 300, MG_TIMER_REPEAT, timer_fn, &mgr); // Init timer
+ struct mg_mgr mgr; // Event manager
+ mg_mgr_init(&mgr); // Initialise event manager
+ mg_timer_add(&mgr, 300, MG_TIMER_REPEAT, timer_fn, &mgr); // Init timer
mg_http_listen(&mgr, s_listen_on, fn, NULL); // Create HTTP listener
for (;;) mg_mgr_poll(&mgr, 1000); // Infinite event loop
- mg_timer_free(&t1); // Free timer resources
mg_mgr_free(&mgr); // Free manager resources
return 0;
}
diff --git a/examples/udp-ssdp-search/main.c b/examples/udp-ssdp-search/main.c
index 90a0291f..35bb2b09 100644
--- a/examples/udp-ssdp-search/main.c
+++ b/examples/udp-ssdp-search/main.c
@@ -36,11 +36,10 @@ static void tfn(void *param) {
int main(void) {
struct mg_mgr mgr;
- struct mg_timer timer;
static struct mg_connection *c;
mg_mgr_init(&mgr);
c = mg_connect(&mgr, s_ssdp_url, fn, NULL);
- mg_timer_init(&timer, 2000, MG_TIMER_REPEAT | MG_TIMER_RUN_NOW, tfn, c);
+ mg_timer_add(&mgr, 2000, MG_TIMER_REPEAT | MG_TIMER_RUN_NOW, tfn, c);
while (true) mg_mgr_poll(&mgr, 200);
mg_mgr_free(&mgr);
return 0;
diff --git a/examples/video-stream/main.c b/examples/video-stream/main.c
index 9c6be6fa..ba076cd8 100644
--- a/examples/video-stream/main.c
+++ b/examples/video-stream/main.c
@@ -54,13 +54,11 @@ static void timer_callback(void *arg) {
int main(void) {
struct mg_mgr mgr;
- struct mg_timer t1;
mg_mgr_init(&mgr);
mg_http_listen(&mgr, "http://localhost:8000", cb, NULL);
- mg_timer_init(&t1, 500, MG_TIMER_REPEAT, timer_callback, &mgr);
+ mg_timer_add(&mgr, 500, MG_TIMER_REPEAT, timer_callback, &mgr);
for (;;) mg_mgr_poll(&mgr, 50);
- mg_timer_free(&t1);
mg_mgr_free(&mgr);
return 0;
diff --git a/examples/zephyr/http-server/src/main.c b/examples/zephyr/http-server/src/main.c
index 2d0f620c..b4c9a199 100644
--- a/examples/zephyr/http-server/src/main.c
+++ b/examples/zephyr/http-server/src/main.c
@@ -72,8 +72,7 @@ int main(int argc, char *argv[]) {
mg_http_listen(&mgr, s_http_addr, wcb, NULL);
mg_http_listen(&mgr, s_https_addr, wcb, &mgr);
- struct mg_timer t;
- mg_timer_init(&t, 5000, MG_TIMER_REPEAT | MG_TIMER_RUN_NOW, timer_fn, &mgr);
+ mg_timer_add(&mgr, 5000, MG_TIMER_REPEAT | MG_TIMER_RUN_NOW, timer_fn, &mgr);
// Start infinite event loop
MG_INFO(("Mongoose version : v%s", MG_VERSION));
diff --git a/mongoose.c b/mongoose.c
index 870fc3ef..0e228959 100644
--- a/mongoose.c
+++ b/mongoose.c
@@ -124,21 +124,20 @@ struct dns_data {
uint16_t txnid;
};
-static struct dns_data *s_reqs; // Active DNS requests
-
static void mg_sendnsreq(struct mg_connection *, struct mg_str *, int,
struct mg_dns *, bool);
-static void mg_dns_free(struct dns_data *d) {
- LIST_DELETE(struct dns_data, &s_reqs, d);
+static void mg_dns_free(struct mg_connection *c, struct dns_data *d) {
+ LIST_DELETE(struct dns_data,
+ (struct dns_data **) &c->mgr->active_dns_requests, d);
free(d);
}
void mg_resolve_cancel(struct mg_connection *c) {
- struct dns_data *tmp, *d;
- for (d = s_reqs; d != NULL; d = tmp) {
+ struct dns_data *tmp, *d = (struct dns_data *) c->mgr->active_dns_requests;
+ for (; d != NULL; d = tmp) {
tmp = d->next;
- if (d->c == c) mg_dns_free(d);
+ if (d->c == c) mg_dns_free(c, d);
}
}
@@ -251,7 +250,8 @@ static void dns_cb(struct mg_connection *c, int ev, void *ev_data,
struct dns_data *d, *tmp;
if (ev == MG_EV_POLL) {
uint64_t now = *(uint64_t *) ev_data;
- for (d = s_reqs; d != NULL; d = tmp) {
+ for (d = (struct dns_data *) c->mgr->active_dns_requests; d != NULL;
+ d = tmp) {
tmp = d->next;
// MG_DEBUG ("%lu %lu dns poll", d->expire, now));
if (now > d->expire) mg_error(d->c, "DNS timeout");
@@ -265,7 +265,8 @@ static void dns_cb(struct mg_connection *c, int ev, void *ev_data,
free(s);
} else {
MG_VERBOSE(("%s %d", dm.name, dm.resolved));
- for (d = s_reqs; d != NULL; d = tmp) {
+ for (d = (struct dns_data *) c->mgr->active_dns_requests; d != NULL;
+ d = tmp) {
tmp = d->next;
// MG_INFO(("d %p %hu %hu", d, d->txnid, dm.txnid));
if (dm.txnid != d->txnid) continue;
@@ -288,17 +289,18 @@ static void dns_cb(struct mg_connection *c, int ev, void *ev_data,
} else {
MG_ERROR(("%lu already resolved", d->c->id));
}
- mg_dns_free(d);
+ mg_dns_free(c, d);
resolved = 1;
}
}
if (!resolved) MG_ERROR(("stray DNS reply"));
c->recv.len = 0;
} else if (ev == MG_EV_CLOSE) {
- for (d = s_reqs; d != NULL; d = tmp) {
+ for (d = (struct dns_data *) c->mgr->active_dns_requests; d != NULL;
+ d = tmp) {
tmp = d->next;
mg_error(d->c, "DNS error");
- mg_dns_free(d);
+ mg_dns_free(c, d);
}
}
(void) fn_data;
@@ -348,10 +350,11 @@ static void mg_sendnsreq(struct mg_connection *c, struct mg_str *name, int ms,
} else if ((d = (struct dns_data *) calloc(1, sizeof(*d))) == NULL) {
mg_error(c, "resolve OOM");
} else {
+ struct dns_data *reqs = (struct dns_data *) c->mgr->active_dns_requests;
char buf[100];
- d->txnid = s_reqs ? (uint16_t) (s_reqs->txnid + 1) : 1;
- d->next = s_reqs;
- s_reqs = d;
+ d->txnid = reqs ? (uint16_t) (reqs->txnid + 1) : 1;
+ d->next = (struct dns_data *) c->mgr->active_dns_requests;
+ c->mgr->active_dns_requests = d;
d->expire = mg_millis() + (uint64_t) ms;
d->c = c;
c->is_resolving = 1;
@@ -1279,68 +1282,20 @@ void mg_http_write_chunk(struct mg_connection *c, const char *buf, size_t len) {
static const char *mg_http_status_code_str(int status_code) {
switch (status_code) {
case 100: return "Continue";
- case 101: return "Switching Protocols";
- case 102: return "Processing";
- case 200: return "OK";
case 201: return "Created";
case 202: return "Accepted";
- case 203: return "Non-authoritative Information";
case 204: return "No Content";
- case 205: return "Reset Content";
case 206: return "Partial Content";
- case 207: return "Multi-Status";
- case 208: return "Already Reported";
- case 226: return "IM Used";
- case 300: return "Multiple Choices";
case 301: return "Moved Permanently";
case 302: return "Found";
- case 303: return "See Other";
case 304: return "Not Modified";
- case 305: return "Use Proxy";
- case 307: return "Temporary Redirect";
- case 308: return "Permanent Redirect";
case 400: return "Bad Request";
case 401: return "Unauthorized";
- case 402: return "Payment Required";
case 403: return "Forbidden";
case 404: return "Not Found";
- case 405: return "Method Not Allowed";
- case 406: return "Not Acceptable";
- case 407: return "Proxy Authentication Required";
- case 408: return "Request Timeout";
- case 409: return "Conflict";
- case 410: return "Gone";
- case 411: return "Length Required";
- case 412: return "Precondition Failed";
- case 413: return "Payload Too Large";
- case 414: return "Request-URI Too Long";
- case 415: return "Unsupported Media Type";
- case 416: return "Requested Range Not Satisfiable";
- case 417: return "Expectation Failed";
case 418: return "I'm a teapot";
- case 421: return "Misdirected Request";
- case 422: return "Unprocessable Entity";
- case 423: return "Locked";
- case 424: return "Failed Dependency";
- case 426: return "Upgrade Required";
- case 428: return "Precondition Required";
- case 429: return "Too Many Requests";
- case 431: return "Request Header Fields Too Large";
- case 444: return "Connection Closed Without Response";
- case 451: return "Unavailable For Legal Reasons";
- case 499: return "Client Closed Request";
case 500: return "Internal Server Error";
case 501: return "Not Implemented";
- case 502: return "Bad Gateway";
- case 503: return "Service Unavailable";
- case 504: return "Gateway Timeout";
- case 505: return "HTTP Version Not Supported";
- case 506: return "Variant Also Negotiates";
- case 507: return "Insufficient Storage";
- case 508: return "Loop Detected";
- case 510: return "Not Extended";
- case 511: return "Network Authentication Required";
- case 599: return "Network Connect Timeout Error";
default: return "OK";
}
}
@@ -1572,7 +1527,7 @@ static void printdirentry(const char *name, void *userdata) {
static void listdir(struct mg_connection *c, struct mg_http_message *hm,
const struct mg_http_serve_opts *opts, char *dir) {
- static const char *sort_js_code =
+ const char *sort_js_code =
"