From patchwork Mon Mar 5 11:26:55 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefano Babic X-Patchwork-Id: 881410 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=googlegroups.com (client-ip=2a00:1450:400c:c0c::237; helo=mail-wr0-x237.google.com; envelope-from=swupdate+bncbcxploxj6ikrbb6t6tkakgqeg4vz2mi@googlegroups.com; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=denx.de Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=googlegroups.com header.i=@googlegroups.com header.b="bfJnmmli"; dkim-atps=neutral Received: from mail-wr0-x237.google.com (mail-wr0-x237.google.com [IPv6:2a00:1450:400c:c0c::237]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3zvyL22rgrz9sZh for ; Mon, 5 Mar 2018 22:27:06 +1100 (AEDT) Received: by mail-wr0-x237.google.com with SMTP id 65sf10980034wrn.7 for ; Mon, 05 Mar 2018 03:27:06 -0800 (PST) ARC-Seal: i=2; a=rsa-sha256; t=1520249223; cv=pass; d=google.com; s=arc-20160816; b=LXkwBujTBwm1+j5mPne4li6/kzcKgBehR7F9ME+qpspxNHvlK7OBgThR97Tv9zI9c9 encwdkrdIH5LxJvT5bwuUeV/h7lflrYxg1Bq42b0aQBzyOUzQU7EHszh+0E1yMzPaFso K3Ec/fHYNdno41DvWHm+cj//CGLyfHzyNFRdSsX5Q7ErEJSA1t7udTugL8Vm+FG3MPZy 1UZZ7EbW9NnUFnNPtf2yPPW+P8qlv0dhV1Yn84WHbg1g683gPlZB7qCbGVvscl9XoE2B rLvDlt7P372xkMwXHyuvlx6EPRSlRxdRIIaOWE6v+Kin5vxhKplyWTiuVq5A4FBojSEl zLpg== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:references:in-reply-to:message-id :date:subject:cc:to:from:arc-authentication-results :arc-message-signature:mime-version:sender:dkim-signature :arc-authentication-results; bh=lUptfjaKqxspMm1PH3QZLoeESzonBMnENk+S+p3j1Ps=; b=cZM2NNPCN09j+BHEadtBTOun1NHNDBUPDpZSqgVtRvzrORt1gp3xLSa/1x01X7RbjY D0fp71JyUGWeDL5Gp7KyQfuibGZgw7bcH8l8PfmqvTGUXePWm/wU2/JETgfI+iESeZvF JRegrQjQaE8DNbp3r+C4o+Th4j0cjr+d++WlS5CAeLg+bk3fltS1831uXpa+hSEjfdZ/ dkenSJczNnQ+riW0s5OGKOpEPklwmhlp/P0YqZmtrV5J2/IAUMmXYWNVG/Cruk44jwnO 1PPE7IRW79+6Qiy0C0Z54ph3HALzjb3Plr5TFc78Eoev8J+0TXgtrvT1w8pN++443y+D 1I2A== ARC-Authentication-Results: i=2; gmr-mx.google.com; spf=neutral (google.com: 212.18.0.10 is neither permitted nor denied by best guess record for domain of sbabic@denx.de) smtp.mailfrom=sbabic@denx.de DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlegroups.com; s=20161025; h=sender:mime-version:from:to:cc:subject:date:message-id:in-reply-to :references:x-original-sender:x-original-authentication-results :precedence:mailing-list:list-id:list-post:list-help:list-archive :list-subscribe:list-unsubscribe; bh=lUptfjaKqxspMm1PH3QZLoeESzonBMnENk+S+p3j1Ps=; b=bfJnmmliP78iiLKBWRp6CEaiNQeHyiEqOItEq0J14KqeBaaU8F7FWR9McsxpFkRx/u 0un72+xdFzGafBS2pMBlLB2ppr8iJcL3cB+Ktll8vvjiJa4xanXTOYIviFZlFByjOhyn F3OvwzUrtPvtZNXjAXym85z4XoP2LEN8zsHj0P3ylYsCRbVh4VA980VCImMDCcH9OR7Z BKCkXu17RQI4jOwsTQ25KP9waRPRRCq2rr2uunPCnbdjKOroV3SKt+2aiAxQXeWXYaYr 60bjkFb8I6CSDmjoui3Mc6uSErHdKGk76Du/pIOjCvh4iRdGmOIYB7YKGBkMRtXgLv7T zXHQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=sender:x-gm-message-state:mime-version:from:to:cc:subject:date :message-id:in-reply-to:references:x-original-sender :x-original-authentication-results:precedence:mailing-list:list-id :x-spam-checked-in-group:list-post:list-help:list-archive :list-subscribe:list-unsubscribe; bh=lUptfjaKqxspMm1PH3QZLoeESzonBMnENk+S+p3j1Ps=; b=Y28aZmFYtPUnnQMmVUCMAfYjeNx9krbGx06lKa3SQHEjNJY0bIJJMYm6u1rKt0jhzP HZiKF8uV9tNoWiO4lvuMs5bm/55uDV6ZEBIoM50mksgyzVj7H9l3rQpNq3d9jb0yW89A +i3nRfpuifKO5xdi/oPAV/tL+ptLBKWSLBRd0qCVy54XpcQoFFwtt/2cPOEuMbxavanz UvgE6LZXoc1j3x2B0D3MjC31qMUjEGTGo4HHHKlK75Lui6KKg0m7uPPdXhNA3lDGVcYq Ixa/yV5BU/cL5U+KqpW4XMewaMJlnvOd1zXq6oMnkbs5U5/xHdbZORsVV8FPlSYt+tX8 /b9A== Sender: swupdate@googlegroups.com X-Gm-Message-State: AElRT7HPMWc3zrNc1xDPIrlQlMvkcceYBXfyUb2VOn0aluqn6FNm/cyZ 4BdQaQwSIUR+CjVDFCSl/Ak= X-Google-Smtp-Source: AG47ELtjvq4ogidyVjIRKTYRrXhIcfUMUQImK975WDTnbMk4kBlpPJb/B9lPSTGhZl9ssesEjrHfDA== X-Received: by 10.28.122.4 with SMTP id v4mr55076wmc.6.1520249223653; Mon, 05 Mar 2018 03:27:03 -0800 (PST) MIME-Version: 1.0 X-BeenThere: swupdate@googlegroups.com Received: by 10.28.47.77 with SMTP id v74ls1430088wmv.7.canary-gmail; Mon, 05 Mar 2018 03:27:03 -0800 (PST) X-Received: by 10.28.170.145 with SMTP id t139mr1104908wme.2.1520249223072; Mon, 05 Mar 2018 03:27:03 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1520249223; cv=none; d=google.com; s=arc-20160816; b=s+iLk9rKEPTpFxpOnYCZFrcMlqq5YKJqesRCZGmjneIpmGJAtTEbLDD+Pr3MkOe/m4 S0n5by5R/cm5RBS3nooZB4oShn5dvrAVPamsJDq6CNS67xUmHe6n4AyATYh8WB9MFLVh hZtP6I+R/4c2yExUpYJMa/2f40skILXsT3zvPKSuWC0OELoTp3gh6oBqClm5XXKGPCkW lmWfCnA/5AmPzwSBQUbIEnxZwaX6IuFURvWxuMy9/Iyl7ymsc5prpKxWyIFz6Yt4Hu+A E70e2AZBrEEKayxXWEhJsej3VIOs9niKWZ2wGI1rvadEHvsyy/tVonNbGV0s9muHnw2/ jqwQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=references:in-reply-to:message-id:date:subject:cc:to:from :arc-authentication-results; bh=qfo1pwkvtjmBUQMbwS/92hSIJv4FjQTghNTXY2WKTp0=; b=YiofnkE1DOekw6saSAvl/9igMivbkCbV+prLztqA5+OO0I9yZ3plF5MhZRafm4v0+H 0B/MJWF5nmnVPu0tP6R0LLRXqjc4ynE9sELSKQQEn9HtwdV7XrVXkf3axCl4N3zGe6+b U1o8qGhzxvQfvWKQB6hOdPt+06vJiXhNIRiQ//dka72kXhAwXM2eP61wFlhwfETq94/1 3jp4ZJh+AN/MnBwiUemLKyFDSBxsEYIVPiCAN9Ohu8WAg2xeY33etSeHegqK/2CnF5CH zjRuQOHEthBjIL0uQKk0VojW6XVEezBigzBR9C8eb6UCtgHJ83UR0YoxJXhfD8GfvrrO HPuA== ARC-Authentication-Results: i=1; gmr-mx.google.com; spf=neutral (google.com: 212.18.0.10 is neither permitted nor denied by best guess record for domain of sbabic@denx.de) smtp.mailfrom=sbabic@denx.de Received: from mail-out.m-online.net (mail-out.m-online.net. [212.18.0.10]) by gmr-mx.google.com with ESMTPS id 51si685636wrw.0.2018.03.05.03.27.02 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 05 Mar 2018 03:27:03 -0800 (PST) Received-SPF: neutral (google.com: 212.18.0.10 is neither permitted nor denied by best guess record for domain of sbabic@denx.de) client-ip=212.18.0.10; Received: from frontend01.mail.m-online.net (unknown [192.168.8.182]) by mail-out.m-online.net (Postfix) with ESMTP id 3zvyKy62k6z1qvNk; Mon, 5 Mar 2018 12:27:02 +0100 (CET) Received: from localhost (dynscan1.mnet-online.de [192.168.6.70]) by mail.m-online.net (Postfix) with ESMTP id 3zvyKy5c2dz1sQwv; Mon, 5 Mar 2018 12:27:02 +0100 (CET) X-Virus-Scanned: amavisd-new at mnet-online.de Received: from mail.mnet-online.de ([192.168.8.182]) by localhost (dynscan1.mail.m-online.net [192.168.6.70]) (amavisd-new, port 10024) with ESMTP id y1ZfBkjdrY_8; Mon, 5 Mar 2018 12:27:01 +0100 (CET) Received: from babic.homelinux.org (host-88-217-136-221.customer.m-online.net [88.217.136.221]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.mnet-online.de (Postfix) with ESMTPS; Mon, 5 Mar 2018 12:27:01 +0100 (CET) Received: from localhost (mail.babic.homelinux.org [127.0.0.1]) by babic.homelinux.org (Postfix) with ESMTP id A93394540378; Mon, 5 Mar 2018 12:27:00 +0100 (CET) X-Virus-Scanned: Debian amavisd-new at babic.homelinux.org Received: from babic.homelinux.org ([127.0.0.1]) by localhost (mail.babic.homelinux.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id JHXAqudXET9o; Mon, 5 Mar 2018 12:26:58 +0100 (CET) Received: from papero.fritz.box (papero.fritz.box [192.168.178.132]) by babic.homelinux.org (Postfix) with ESMTP id E073C454057B; Mon, 5 Mar 2018 12:26:57 +0100 (CET) From: Stefano Babic To: swupdate@googlegroups.com Cc: Stefano Babic , Sami Hartikainen Subject: [swupdate] [PATCH V2 2/2] mongoose: set V1 or V2 at runtime Date: Mon, 5 Mar 2018 12:26:55 +0100 Message-Id: <1520249215-31082-2-git-send-email-sbabic@denx.de> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1520249215-31082-1-git-send-email-sbabic@denx.de> References: <1520249215-31082-1-git-send-email-sbabic@denx.de> X-Original-Sender: sbabic@denx.de X-Original-Authentication-Results: gmr-mx.google.com; spf=neutral (google.com: 212.18.0.10 is neither permitted nor denied by best guess record for domain of sbabic@denx.de) smtp.mailfrom=sbabic@denx.de Precedence: list Mailing-list: list swupdate@googlegroups.com; contact swupdate+owners@googlegroups.com List-ID: X-Spam-Checked-In-Group: swupdate@googlegroups.com X-Google-Group-Id: 605343134186 List-Post: , List-Help: , List-Archive: , List-Unsubscribe: , V1 version of REST-API is still more suitable for M2M updates together with the SWU forwarder handler. However, it is not currently possible to switch between them and the API must be selected at compile time, and this requires different binaries. Let the user decides which version of API should run with a command line parameter. Signed-off-by: Stefano Babic CC: Sami Hartikainen --- Changes since V1: - Drop MONGOOSE_WEB_API_V1 and MONGOOSE_WEB_API_V2 - Add help for "api" - Add "api" parameter to configuration file - "/upload" URL just in case of v2 - print API version when Webserver is started mongoose/Config.in | 18 -- mongoose/Makefile | 2 - mongoose/mongoose_interface.c | 464 ++++++++++++++++++++++-------------------- 3 files changed, 246 insertions(+), 238 deletions(-) diff --git a/mongoose/Config.in b/mongoose/Config.in index a001247..29cac90 100644 --- a/mongoose/Config.in +++ b/mongoose/Config.in @@ -18,24 +18,6 @@ config MONGOOSE endchoice -choice - prompt "Web Application Interface" - default MONGOOSE_WEB_API_V1 - help - Choose the bootloader - -config MONGOOSE_WEB_API_V1 - bool "Version 1 (deprecated)" - help - Support for version 1 - -config MONGOOSE_WEB_API_V2 - bool "Version 2" - help - Support for version 2 - -endchoice - config MONGOOSEIPV6 bool "IPv6 support" default y diff --git a/mongoose/Makefile b/mongoose/Makefile index 77a616c..dc2d3d3 100644 --- a/mongoose/Makefile +++ b/mongoose/Makefile @@ -1,9 +1,7 @@ ifneq ($(CONFIG_WEBSERVER),) ifneq ($(CONFIG_MONGOOSE),) KBUILD_CFLAGS += -DMG_ENABLE_HTTP_STREAMING_MULTIPART=1 -ifneq ($(CONFIG_MONGOOSE_WEB_API_V2),) KBUILD_CFLAGS += -DMG_ENABLE_HTTP_WEBSOCKET=1 -DMG_ENABLE_THREADS=1 -endif ifneq ($(CONFIG_MONGOOSEIPV6),) KBUILD_CFLAGS += -DMG_ENABLE_IPV6=1 endif diff --git a/mongoose/mongoose_interface.c b/mongoose/mongoose_interface.c index 0e22671..99f9fc4 100644 --- a/mongoose/mongoose_interface.c +++ b/mongoose/mongoose_interface.c @@ -32,6 +32,11 @@ #define MG_PORT "8080" #define MG_ROOT "." +enum MONGOOSE_API_VERSION { + MONGOOSE_API_V1, + MONGOOSE_API_V2 +}; + struct mongoose_options { char *root; char *listing; @@ -40,6 +45,7 @@ struct mongoose_options { char *ssl_cert; char *ssl_key; #endif + int api_version; }; struct file_upload_state { @@ -50,7 +56,9 @@ struct file_upload_state { static struct mg_serve_http_opts s_http_server_opts; static void upload_handler(struct mg_connection *nc, int ev, void *p); -#if defined(CONFIG_MONGOOSE_WEB_API_V2) +/* + * These functions are for V2 of the protocol + */ #define enum_string(x) [x] = #x static const char *get_status_string(unsigned int status) { @@ -111,9 +119,166 @@ static size_t snescape(char *dst, size_t n, const char *src) return len; } -#endif -#if defined(CONFIG_MONGOOSE_WEB_API_V1) +static void restart_handler(struct mg_connection *nc, int ev, void *ev_data) +{ + struct http_message *hm = (struct http_message *) ev_data; + ipc_message msg = {}; + + (void)ev; + + if(mg_vcasecmp(&hm->method, "POST") != 0) { + mg_http_send_error(nc, 405, "Method Not Allowed"); + return; + } + + int ret = ipc_postupdate(&msg); + if (ret) { + mg_http_send_error(nc, 500, "Failed to queue command"); + return; + } + + mg_http_send_error(nc, 201, "Device will reboot now."); +} + +static void broadcast_callback(struct mg_connection *nc, int ev, void *ev_data) +{ + char *buf = (char *) ev_data; + + if (ev != MG_EV_POLL) + return; + + if (!(nc->flags & MG_F_IS_WEBSOCKET)) + return; + + mg_send_websocket_frame(nc, WEBSOCKET_OP_TEXT, buf, strlen(buf)); +} + +static void broadcast(struct mg_mgr *mgr, char *str) +{ + mg_broadcast(mgr, broadcast_callback, str, strlen(str) + 1); +} + +static void *broadcast_message_thread(void *data) +{ + for (;;) { + ipc_message msg; + int ret = ipc_get_status(&msg); + + if (!ret && strlen(msg.data.status.desc) != 0) { + struct mg_mgr *mgr = (struct mg_mgr *) data; + char text[4096]; + char str[4160]; + + snescape(text, sizeof(text), msg.data.status.desc); + + snprintf(str, sizeof(str), + "{\r\n" + "\t\"type\": \"message\",\r\n" + "\t\"level\": \"%d\",\r\n" + "\t\"text\": \"%s\"\r\n" + "}\r\n", + (msg.data.status.error) ? 3 : 6, /* RFC 5424 */ + text); + + broadcast(mgr, str); + continue; + } + + usleep(50 * 1000); + } + + return NULL; +} + +static void *broadcast_progress_thread(void *data) +{ + int status = -1; + int source = -1; + int step = 0; + int percent = 0; + int fd = -1; + + for (;;) { + struct mg_mgr *mgr = (struct mg_mgr *) data; + struct progress_msg msg; + char str[512]; + int ret; + + if (fd < 0) + fd = progress_ipc_connect(true); + + ret = progress_ipc_receive(&fd, &msg); + if (ret != sizeof(msg)) + return NULL; + + if (msg.status != status || msg.status == FAILURE) { + status = msg.status; + + snprintf(str, sizeof(str), + "{\r\n" + "\t\"type\": \"status\",\r\n" + "\t\"status\": \"%s\"\r\n" + "}\r\n", + get_status_string(msg.status)); + broadcast(mgr, str); + } + + if (msg.source != source) { + source = msg.source; + + snprintf(str, sizeof(str), + "{\r\n" + "\t\"type\": \"source\",\r\n" + "\t\"source\": \"%s\"\r\n" + "}\r\n", + get_source_string(msg.source)); + broadcast(mgr, str); + } + + if (msg.status == SUCCESS && msg.source == SOURCE_WEBSERVER) { + ipc_message ipc = {}; + + ipc_postupdate(&ipc); + } + + if (msg.infolen) { + snprintf(str, sizeof(str), + "{\r\n" + "\t\"type\": \"info\",\r\n" + "\t\"source\": \"%s\"\r\n" + "}\r\n", + msg.info); + broadcast(mgr, str); + } + + if ((msg.cur_step != step || msg.cur_percent != percent) && + msg.cur_step) { + step = msg.cur_step; + percent = msg.cur_percent; + + snprintf(str, sizeof(str), + "{\r\n" + "\t\"type\": \"step\",\r\n" + "\t\"number\": \"%d\",\r\n" + "\t\"step\": \"%d\",\r\n" + "\t\"name\": \"%s\",\r\n" + "\t\"percent\": \"%d\"\r\n" + "}\r\n", + msg.nsteps, + msg.cur_step, + msg.cur_step ? msg.cur_image: "", + msg.cur_percent); + broadcast(mgr, str); + } + } + + return NULL; +} + +/* + * These functions are for V1 of the protocol + */ static void upload_handler_v1(struct mg_connection *nc, int ev, void *p) { struct mg_str *filename, *data; @@ -162,69 +327,7 @@ static void upload_handler_v1(struct mg_connection *nc, int ev, void *p) break; } } -#endif - -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 recovery_status(struct mg_connection *nc, int ev, void *ev_data) { ipc_message ipc; @@ -314,163 +417,70 @@ 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) -static void restart_handler(struct mg_connection *nc, int ev, void *ev_data) -{ - struct http_message *hm = (struct http_message *) ev_data; - ipc_message msg = {}; - - (void)ev; - - if(mg_vcasecmp(&hm->method, "POST") != 0) { - mg_http_send_error(nc, 405, "Method Not Allowed"); - return; - } - - int ret = ipc_postupdate(&msg); - if (ret) { - mg_http_send_error(nc, 500, "Failed to queue command"); - return; - } - - mg_http_send_error(nc, 201, "Device will reboot now."); -} - -static void broadcast_callback(struct mg_connection *nc, int ev, void *ev_data) -{ - char *buf = (char *) ev_data; - if (ev != MG_EV_POLL) - return; - if (!(nc->flags & MG_F_IS_WEBSOCKET)) - return; - - mg_send_websocket_frame(nc, WEBSOCKET_OP_TEXT, buf, strlen(buf)); -} - -static void broadcast(struct mg_mgr *mgr, char *str) -{ - mg_broadcast(mgr, broadcast_callback, str, strlen(str) + 1); -} - -static void *broadcast_message_thread(void *data) +/* + * Code common to V1 and V2 + */ +static void upload_handler(struct mg_connection *nc, int ev, void *p) { - for (;;) { - ipc_message msg; - int ret = ipc_get_status(&msg); - - if (!ret && strlen(msg.data.status.desc) != 0) { - struct mg_mgr *mgr = (struct mg_mgr *) data; - char text[4096]; - char str[4160]; - - snescape(text, sizeof(text), msg.data.status.desc); + struct mg_http_multipart_part *mp; + struct file_upload_state *fus; - snprintf(str, sizeof(str), - "{\r\n" - "\t\"type\": \"message\",\r\n" - "\t\"level\": \"%d\",\r\n" - "\t\"text\": \"%s\"\r\n" - "}\r\n", - (msg.data.status.error) ? 3 : 6, /* RFC 5424 */ - text); + switch (ev) { + case MG_EV_HTTP_PART_BEGIN: + mp = (struct mg_http_multipart_part *) p; - broadcast(mgr, str); - continue; + fus = (struct file_upload_state *) calloc(1, sizeof(*fus)); + if (fus == NULL) { + mg_http_send_error(nc, 500, "Out of memory"); + break; } - usleep(50 * 1000); - } - - return NULL; -} - -static void *broadcast_progress_thread(void *data) -{ - int status = -1; - int source = -1; - int step = 0; - int percent = 0; - int fd = -1; - - for (;;) { - struct mg_mgr *mgr = (struct mg_mgr *) data; - struct progress_msg msg; - char str[512]; - int ret; + 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; + } - if (fd < 0) - fd = progress_ipc_connect(true); + mp->user_data = fus; - ret = progress_ipc_receive(&fd, &msg); - if (ret != sizeof(msg)) - return NULL; + break; - if (msg.status != status || msg.status == FAILURE) { - status = msg.status; + case MG_EV_HTTP_PART_DATA: + mp = (struct mg_http_multipart_part *) p; + fus = (struct file_upload_state *) mp->user_data; - snprintf(str, sizeof(str), - "{\r\n" - "\t\"type\": \"status\",\r\n" - "\t\"status\": \"%s\"\r\n" - "}\r\n", - get_status_string(msg.status)); - broadcast(mgr, str); - } + if (!fus) + break; - if (msg.source != source) { - source = msg.source; + ipc_send_data(fus->fd, (char *) mp->data.p, mp->data.len); + fus->len += mp->data.len; - snprintf(str, sizeof(str), - "{\r\n" - "\t\"type\": \"source\",\r\n" - "\t\"source\": \"%s\"\r\n" - "}\r\n", - get_source_string(msg.source)); - broadcast(mgr, str); - } + break; - if (msg.status == SUCCESS && msg.source == SOURCE_WEBSERVER) { - ipc_message ipc = {}; + case MG_EV_HTTP_PART_END: + mp = (struct mg_http_multipart_part *) p; + fus = (struct file_upload_state *) mp->user_data; - ipc_postupdate(&ipc); - } + if (!fus) + break; - if (msg.infolen) { - snprintf(str, sizeof(str), - "{\r\n" - "\t\"type\": \"info\",\r\n" - "\t\"source\": \"%s\"\r\n" - "}\r\n", - msg.info); - broadcast(mgr, str); - } + ipc_end(fus->fd); - if ((msg.cur_step != step || msg.cur_percent != percent) && - msg.cur_step) { - step = msg.cur_step; - percent = msg.cur_percent; + 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; - snprintf(str, sizeof(str), - "{\r\n" - "\t\"type\": \"step\",\r\n" - "\t\"number\": \"%d\",\r\n" - "\t\"step\": \"%d\",\r\n" - "\t\"name\": \"%s\",\r\n" - "\t\"percent\": \"%d\"\r\n" - "}\r\n", - msg.nsteps, - msg.cur_step, - msg.cur_step ? msg.cur_image: "", - msg.cur_percent); - broadcast(mgr, str); - } + mp->user_data = NULL; + free(fus); + break; } - - return NULL; } -#endif static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) { @@ -510,6 +520,12 @@ static int mongoose_settings(void *elem, void __attribute__ ((__unused__)) *dat opts->ssl_key = strdup(tmp); } #endif + GET_FIELD_STRING_RESET(LIBCFG_PARSER, elem, "api", tmp); + if (strlen(tmp)) { + opts->api_version = (!strcmp(tmp, "v1")) ? + MONGOOSE_API_V1 : + MONGOOSE_API_V2; + } return 0; } @@ -523,6 +539,7 @@ static struct option long_options[] = { {"ssl-key", required_argument, NULL, 'K'}, #endif {"document-root", required_argument, NULL, 'r'}, + {"api", required_argument, NULL, 'a'}, {NULL, 0, NULL, 0} }; @@ -538,7 +555,8 @@ void mongoose_print_help(void) "\t -C, --ssl-cert : ssl certificate to present to clients\n" "\t -K, --ssl-key : key corresponding to the ssl certificate\n" #endif - "\t -r, --document-root : path to document root directory (default: %s)\n", + "\t -r, --document-root : path to document root directory (default: %s)\n" + "\t -a, --api [v1|v2] : set Web protocol API to v1 (legacy) or v2 (default v2)\n", MG_LISTING, MG_PORT, MG_ROOT); } @@ -556,12 +574,14 @@ int start_mongoose(const char *cfgfname, int argc, char *argv[]) int choice = 0; memset(&opts, 0, sizeof(opts)); + /* Set default API version */ + opts.api_version = MONGOOSE_API_V2; if (cfgfname) { read_module_settings(cfgfname, "webserver", mongoose_settings, &opts); } optind = 1; - while ((choice = getopt_long(argc, argv, "lp:sC:K:r:", + while ((choice = getopt_long(argc, argv, "lp:sC:K:r:a:", long_options, NULL)) != -1) { switch (choice) { case 'l': @@ -589,6 +609,11 @@ int start_mongoose(const char *cfgfname, int argc, char *argv[]) free(opts.root); opts.root = strdup(optarg); break; + case 'a': + opts.api_version = (!strcmp(optarg, "v1")) ? + MONGOOSE_API_V1 : + MONGOOSE_API_V2; + break; case '?': default: return -EINVAL; @@ -619,22 +644,25 @@ int start_mongoose(const char *cfgfname, int argc, char *argv[]) } mg_set_protocol_http_websocket(nc); - mg_register_http_endpoint(nc, "/upload", MG_CB(upload_handler, NULL)); -#if defined(CONFIG_MONGOOSE_WEB_API_V1) - 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)); -#endif -#if defined(CONFIG_MONGOOSE_WEB_API_V2) - mg_register_http_endpoint(nc, "/restart", restart_handler); - mg_start_thread(broadcast_message_thread, &mgr); - mg_start_thread(broadcast_progress_thread, &mgr); -#endif + switch (opts.api_version) { + case MONGOOSE_API_V1: + 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)); + break; + case MONGOOSE_API_V2: + mg_register_http_endpoint(nc, "/restart", restart_handler); + mg_register_http_endpoint(nc, "/upload", MG_CB(upload_handler, NULL)); + mg_start_thread(broadcast_message_thread, &mgr); + mg_start_thread(broadcast_progress_thread, &mgr); + break; + } - printf("Mongoose web server version %s with pid %d started on port(s) %s with web root [%s]\n", + printf("Mongoose web server version %s with pid %d started on port(s) %s with web root [%s] and API %s\n", MG_VERSION, getpid(), s_http_port, - s_http_server_opts.document_root); + s_http_server_opts.document_root, + (opts.api_version == MONGOOSE_API_V1) ? "v1" : "v2"); for (;;) { mg_mgr_poll(&mgr, 100);