diff mbox series

[v2] mongoose: Allow WEB API v1 and v2 both be enabled

Message ID 1519918834-10861-1-git-send-email-sami.hartikainen@teleste.com
State Changes Requested
Headers show
Series [v2] mongoose: Allow WEB API v1 and v2 both be enabled | expand

Commit Message

Hartikainen, Sami March 1, 2018, 3:40 p.m. UTC
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(-)
diff mbox series

Patch

diff --git a/mongoose/Config.in b/mongoose/Config.in
index a001247..6751cf3 100644
--- a/mongoose/Config.in
+++ b/mongoose/Config.in
@@ -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"
diff --git a/mongoose/mongoose_interface.c b/mongoose/mongoose_interface.c
index 89a51f3..2bee6fa 100644
--- a/mongoose/mongoose_interface.c
+++ b/mongoose/mongoose_interface.c
@@ -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);