@@ -14,27 +14,28 @@ choice
config MONGOOSE
bool "mongoose"
help
- Mongoose embeddded web server
+ Mongoose embedded web server
endchoice
-choice
- prompt "Web Application Interface"
- default MONGOOSE_WEB_API_V1
- help
- Choose the bootloader
+menu "Web Application Interface"
config MONGOOSE_WEB_API_V1
bool "Version 1 (deprecated)"
+ default y
help
Support for version 1
config MONGOOSE_WEB_API_V2
bool "Version 2"
+ default y
help
Support for version 2
-endchoice
+comment "Web API v1 or v2 or both required"
+ depends on !MONGOOSE_WEB_API_V1 && !MONGOOSE_WEB_API_V2
+
+endmenu
config MONGOOSEIPV6
bool "IPv6 support"
@@ -25,6 +25,7 @@
#include <parselib.h>
#include <progress_ipc.h>
#include <swupdate_settings.h>
+#include <util.h>
#include "mongoose.h"
@@ -49,6 +50,10 @@ struct file_upload_state {
static struct mg_serve_http_opts s_http_server_opts;
+#if !defined(CONFIG_MONGOOSE_WEB_API_V1) && !defined(CONFIG_MONGOOSE_WEB_API_V2)
+#error "WEB API v1 or v2 or both must be defined"
+#endif
+
#if defined(CONFIG_MONGOOSE_WEB_API_V2)
#define enum_string(x) [x] = #x
static const char *get_status_string(unsigned int status)
@@ -116,16 +121,72 @@ static void upload_handler(struct mg_connection *nc, int ev, void *p)
{
struct mg_http_multipart_part *mp;
struct file_upload_state *fus;
+
+ switch (ev) {
+ case MG_EV_HTTP_PART_BEGIN:
+ mp = (struct mg_http_multipart_part *) p;
+
+ fus = (struct file_upload_state *) calloc(1, sizeof(*fus));
+ if (fus == NULL) {
+ mg_http_send_error(nc, 500, "Out of memory");
+ break;
+ }
+
+ fus->fd = ipc_inst_start_ext(SOURCE_WEBSERVER, strlen(mp->file_name), mp->file_name);
+ if (fus->fd < 0) {
+ mg_http_send_error(nc, 500, "Failed to queue command");
+ free(fus);
+ break;
+ }
+
+ mp->user_data = fus;
+
+ break;
+
+ case MG_EV_HTTP_PART_DATA:
+ mp = (struct mg_http_multipart_part *) p;
+ fus = (struct file_upload_state *) mp->user_data;
+
+ if (!fus)
+ break;
+
+ ipc_send_data(fus->fd, (char *) mp->data.p, mp->data.len);
+ fus->len += mp->data.len;
+
+ break;
+
+ case MG_EV_HTTP_PART_END:
+ mp = (struct mg_http_multipart_part *) p;
+ fus = (struct file_upload_state *) mp->user_data;
+
+ if (!fus)
+ break;
+
+ ipc_end(fus->fd);
+
+ mg_send_response_line(nc, 200,
+ "Content-Type: text/plain\r\n"
+ "Connection: close");
+ mg_send(nc, "\r\n", 2);
+ mg_printf(nc, "Ok, %s - %d bytes.\r\n", mp->file_name, (int) fus->len);
+ nc->flags |= MG_F_SEND_AND_CLOSE;
+
+ mp->user_data = NULL;
+ free(fus);
+ break;
+ }
+}
+
#if defined(CONFIG_MONGOOSE_WEB_API_V1)
+static void upload_handler_v1(struct mg_connection *nc, int ev, void *p)
+{
struct mg_str *filename, *data;
struct http_message *hm;
size_t length;
char buf[16];
int fd;
-#endif
switch (ev) {
-#if defined(CONFIG_MONGOOSE_WEB_API_V1)
case MG_EV_HTTP_REQUEST:
hm = (struct http_message *) p;
@@ -161,62 +222,13 @@ static void upload_handler(struct mg_connection *nc, int ev, void *p)
nc->flags |= MG_F_SEND_AND_CLOSE;
break;
-#endif
- case MG_EV_HTTP_PART_BEGIN:
- mp = (struct mg_http_multipart_part *) p;
- fus = (struct file_upload_state *) calloc(1, sizeof(*fus));
- if (fus == NULL) {
- mg_http_send_error(nc, 500, "Out of memory");
- break;
- }
-
- fus->fd = ipc_inst_start_ext(SOURCE_WEBSERVER, strlen(mp->file_name), mp->file_name);
- if (fus->fd < 0) {
- mg_http_send_error(nc, 500, "Failed to queue command");
- free(fus);
- break;
- }
-
- mp->user_data = fus;
-
- break;
-
- case MG_EV_HTTP_PART_DATA:
- mp = (struct mg_http_multipart_part *) p;
- fus = (struct file_upload_state *) mp->user_data;
-
- if (!fus)
- break;
-
- ipc_send_data(fus->fd, (char *) mp->data.p, mp->data.len);
- fus->len += mp->data.len;
-
- break;
-
- case MG_EV_HTTP_PART_END:
- mp = (struct mg_http_multipart_part *) p;
- fus = (struct file_upload_state *) mp->user_data;
-
- if (!fus)
- break;
-
- ipc_end(fus->fd);
-
- mg_send_response_line(nc, 200,
- "Content-Type: text/plain\r\n"
- "Connection: close");
- mg_send(nc, "\r\n", 2);
- mg_printf(nc, "Ok, %s - %d bytes.\r\n", mp->file_name, (int) fus->len);
- nc->flags |= MG_F_SEND_AND_CLOSE;
-
- mp->user_data = NULL;
- free(fus);
+ default:
+ upload_handler(nc, ev, p);
break;
}
}
-#if defined(CONFIG_MONGOOSE_WEB_API_V1)
static void recovery_status(struct mg_connection *nc, int ev, void *ev_data)
{
ipc_message ipc;
@@ -306,7 +318,9 @@ static void post_update_cmd(struct mg_connection *nc, int ev, void *ev_data)
nc->flags |= MG_F_SEND_AND_CLOSE;
}
-#elif defined(CONFIG_MONGOOSE_WEB_API_V2)
+#endif
+
+#if defined(CONFIG_MONGOOSE_WEB_API_V2)
static void restart_handler(struct mg_connection *nc, int ev, void *ev_data)
{
struct http_message *hm = (struct http_message *) ev_data;
@@ -462,14 +476,54 @@ static void *broadcast_progress_thread(void *data)
return NULL;
}
+
+static int websocket_count(struct mg_mgr *mgr)
+{
+ struct mg_connection *c;
+ int result = 0;
+
+ for (c = mg_next(mgr, NULL); c != NULL; c = mg_next(mgr, c)) {
+ if ((c->flags & MG_F_IS_WEBSOCKET))
+ result++;
+ }
+
+ return result;
+}
#endif
static void ev_handler(struct mg_connection *nc, int ev, void *ev_data)
{
+#if defined(CONFIG_MONGOOSE_WEB_API_V2)
+ static pthread_t bcast_message_thread_id;
+ static pthread_t bcast_progress_thread_id;
+
+ switch (ev) {
+ case MG_EV_WEBSOCKET_HANDSHAKE_DONE:
+ if (websocket_count(nc->mgr) == 1) {
+ DEBUG("Creating websocket broadcast message/progress threads\n");
+ bcast_message_thread_id = (pthread_t)mg_start_thread(broadcast_message_thread, nc->mgr);
+ bcast_progress_thread_id = (pthread_t)mg_start_thread(broadcast_progress_thread, nc->mgr);
+ }
+ break;
+
+ case MG_EV_CLOSE:
+ if ((nc->flags & MG_F_IS_WEBSOCKET)
+ && websocket_count(nc->mgr) == 0) {
+ DEBUG("Canceling websocket broadcast message/progress threads\n");
+
+ pthread_cancel(bcast_message_thread_id);
+ pthread_cancel(bcast_progress_thread_id);
+
+ pthread_join(bcast_message_thread_id, NULL);
+ pthread_join(bcast_progress_thread_id, NULL);
+ }
+ break;
+ }
+#endif
+
if (ev == MG_EV_HTTP_REQUEST) {
mg_serve_http(nc, ev_data, s_http_server_opts);
}
-
}
static int mongoose_settings(void *elem, void __attribute__ ((__unused__)) *data)
@@ -505,7 +559,6 @@ static int mongoose_settings(void *elem, void __attribute__ ((__unused__)) *dat
return 0;
}
-
static struct option long_options[] = {
{"listing", no_argument, NULL, 'l'},
{"port", required_argument, NULL, 'p'},
@@ -611,21 +664,17 @@ int start_mongoose(const char *cfgfname, int argc, char *argv[])
}
#if defined(CONFIG_MONGOOSE_WEB_API_V1)
- mg_register_http_endpoint(nc, "/handle_post_request", MG_CB(upload_handler, NULL));
+ mg_register_http_endpoint(nc, "/handle_post_request", MG_CB(upload_handler_v1, NULL));
mg_register_http_endpoint(nc, "/getstatus.json", MG_CB(recovery_status, NULL));
mg_register_http_endpoint(nc, "/rebootTarget", MG_CB(reboot_target, NULL));
mg_register_http_endpoint(nc, "/postUpdateCommand", MG_CB(post_update_cmd, NULL));
-#elif defined(CONFIG_MONGOOSE_WEB_API_V2)
- mg_register_http_endpoint(nc, "/restart", restart_handler);
#endif
+#if defined(CONFIG_MONGOOSE_WEB_API_V2)
+ mg_register_http_endpoint(nc, "/restart", MG_CB(restart_handler, NULL));
mg_register_http_endpoint(nc, "/upload", MG_CB(upload_handler, NULL));
+#endif
mg_set_protocol_http_websocket(nc);
-#if defined(CONFIG_MONGOOSE_WEB_API_V2)
- mg_start_thread(broadcast_message_thread, &mgr);
- mg_start_thread(broadcast_progress_thread, &mgr);
-#endif
-
printf("Mongoose web server version %s with pid %d started on port(s) %s with web root [%s]\n",
MG_VERSION, getpid(), s_http_port,
s_http_server_opts.document_root);
To ease transition, or simply to enable the use of modern clients while still supporting the use of the swuforwarder handler (which only talks API v1), both the v1 and v2 API may be enabled. N.B. Clients for v1 and v2 should not connect at the *same time*, however. This restriction is due to having a simple queue for the status messages, consumed by the first reader. Signed-off-by: Sami Hartikainen <sami.hartikainen@teleste.com> --- mongoose/Config.in | 15 ++-- mongoose/mongoose_interface.c | 177 +++++++++++++++++++++++++++--------------- 2 files changed, 121 insertions(+), 71 deletions(-)