@@ -507,8 +507,8 @@ Command line parameters
| | | will not stop until a valid software is |
| | | loaded. |
+-------------+----------+--------------------------------------------+
-| -t <timeout>| integer | Timeout for connection lost when |
-| | | downloading |
+| -t <timeout>| integer | Timeout for connection lost |
+| | | downloader or Webserver |
+-------------+----------+--------------------------------------------+
| -a <usr:pwd>| string | Send user and password for Basic Auth |
+-------------+----------+--------------------------------------------+
@@ -26,12 +26,17 @@
#include <parselib.h>
#include <progress_ipc.h>
#include <swupdate_settings.h>
+#include <time.h>
#include "mongoose.h"
+#include "util.h"
#define MG_PORT "8080"
#define MG_ROOT "."
+/* in seconds. If no packet is received with this timeout, connection is broken */
+#define MG_TIMEOUT 120
+
enum MONGOOSE_API_VERSION {
MONGOOSE_API_V1 = 1,
MONGOOSE_API_V2
@@ -56,6 +61,7 @@ struct file_upload_state {
};
static bool run_postupdate;
+static unsigned int watchdog_conn = 0;
static struct mg_serve_http_opts s_http_server_opts;
static void upload_handler(struct mg_connection *nc, int ev, void *p);
@@ -306,6 +312,18 @@ static void upload_handler(struct mg_connection *nc, int ev, void *p)
mp->user_data = fus;
+ /*
+ * There is no user data for connection.
+ * Set the user data to the same structure to make it available
+ * to the MG_TIMER event
+ */
+ nc->user_data = mp->user_data;
+
+ if (watchdog_conn > 0) {
+ TRACE("Setting Webserver Watchdog Timer to %d", watchdog_conn);
+ mg_set_timer(nc, mg_time() + watchdog_conn);
+ }
+
break;
case MG_EV_HTTP_PART_DATA:
@@ -337,6 +355,7 @@ static void upload_handler(struct mg_connection *nc, int ev, void *p)
nc->flags |= MG_F_SEND_AND_CLOSE;
mp->user_data = NULL;
+ nc->user_data = mp->user_data;
free(fus);
break;
}
@@ -344,8 +363,31 @@ static void upload_handler(struct mg_connection *nc, int ev, void *p)
static void ev_handler(struct mg_connection *nc, int ev, void *ev_data)
{
- if (ev == MG_EV_HTTP_REQUEST) {
+ time_t now;
+
+ switch (ev) {
+ case MG_EV_HTTP_REQUEST:
mg_serve_http(nc, ev_data, s_http_server_opts);
+ break;
+ case MG_EV_TIMER:
+ now = (time_t) mg_time();
+ /*
+ * Check if a multi-part was initiated
+ */
+ if (nc->user_data && (watchdog_conn > 0) &&
+ (difftime(now, nc->last_io_time) > 2 * watchdog_conn)) {
+ struct file_upload_state *fus;
+
+ /* Connection lost, drop data */
+ ERROR("Connection lost, no data since %ld now %ld, closing...",
+ nc->last_io_time, now);
+ fus = (struct file_upload_state *) nc->user_data;
+ ipc_end(fus->fd);
+ nc->user_data = NULL;
+ nc->flags |= MG_F_CLOSE_IMMEDIATELY;
+ } else
+ mg_set_timer(nc, mg_time() + watchdog_conn); // Send us timer event again after 0.5 seconds
+ break;
}
}
@@ -399,6 +441,8 @@ static int mongoose_settings(void *elem, void __attribute__ ((__unused__)) *dat
}
get_field(LIBCFG_PARSER, elem, "run-postupdate", &run_postupdate);
+ get_field(LIBCFG_PARSER, elem, "timeout", &watchdog_conn);
+
return 0;
}
@@ -413,6 +457,7 @@ static struct option long_options[] = {
#endif
{"document-root", required_argument, NULL, 'r'},
{"api-version", required_argument, NULL, 'a'},
+ {"timeout", required_argument, NULL, 't'},
{"auth-domain", required_argument, NULL, '0'},
{"global-auth-file", required_argument, NULL, '1'},
{NULL, 0, NULL, 0}
@@ -431,6 +476,7 @@ void mongoose_print_help(void)
"\t -K, --ssl-key <key> : key corresponding to the ssl certificate\n"
#endif
"\t -r, --document-root <path> : path to document root directory (default: %s)\n"
+ "\t -t, --timeout : timeout to check if connection is lost (default: check disabled)\n"
"\t -a, --api-version [1|2] : set Web protocol API to v1 (legacy) or v2 (default v2)\n"
"\t --auth-domain : set authentication domain if any (default: none)\n"
"\t --global-auth-file : set authentication file if any (default: none)\n",
@@ -462,12 +508,17 @@ int start_mongoose(const char *cfgfname, int argc, char *argv[])
*/
run_postupdate = true;
+ /*
+ * Default no monitor of connection
+ */
+ watchdog_conn = 0;
+
if (cfgfname) {
read_module_settings(cfgfname, "webserver", mongoose_settings, &opts);
}
optind = 1;
- while ((choice = getopt_long(argc, argv, "lp:sC:K:r:a:",
+ while ((choice = getopt_long(argc, argv, "lp:sC:K:r:a:t:",
long_options, NULL)) != -1) {
switch (choice) {
case '0':
@@ -485,6 +536,9 @@ int start_mongoose(const char *cfgfname, int argc, char *argv[])
free(opts.port);
opts.port = strdup(optarg);
break;
+ case 't':
+ watchdog_conn = strtoul(optarg, NULL, 10);
+ break;
#if MG_ENABLE_SSL
case 's':
ssl = true;
This solves the following issue: - Update is initiated by the Webserver - SWupdate has started and data flows into IPC - Connection is lost In this case, the WebBrowser is often restarted by the user via the refresh button. The old connection is not living anymore, but SWUpdate does not detect it and waits for data. But when the browser initiates a new upload, SWUpdate returns with an error due to the running update. This adds a timer to the webserver connection. As default, connection monitor is disabled to be compatible with past. Value for the timer can be passed to the Webserver using the "-t" parameter, as it is already done for the downloader. Example: swupdate -w "-r /www -t 20" Timeout value can be also passed via the configuration file. The Webserver sets a timer and checks if some data were transfer since the last time the timer elapses. If no data is received in an interval equal to two times the timeout, connection is declared lost and the ipc is closed. A browser can then initiate a new upload. Signed-off-by: Stefano Babic <sbabic@denx.de> --- doc/source/swupdate.rst | 4 +-- mongoose/mongoose_interface.c | 58 +++++++++++++++++++++++++++++++++-- 2 files changed, 58 insertions(+), 4 deletions(-)