Add firmware download support

parent 0ecfd43a
...@@ -132,10 +132,12 @@ static int parse_range_header(const char *header, int64_t *a, int64_t *b) ...@@ -132,10 +132,12 @@ static int parse_range_header(const char *header, int64_t *a, int64_t *b)
return sscanf(header, "bytes=%lld-%lld", a, b); return sscanf(header, "bytes=%lld-%lld", a, b);
} }
void civetweb_send_file_data(struct mg_connection *conn, const uint8_t* data, int64_t len) void civetweb_send_file_data(struct mg_connection *conn, const uint8_t* data, int64_t len, int use_chunked_encoding)
{ {
char buf[MG_BUF_LEN]; char buf[MG_BUF_LEN];
int to_read, num_written; int to_read;
int to_write;
int num_written;
if (!data || !conn) { if (!data || !conn) {
return; return;
...@@ -147,17 +149,35 @@ void civetweb_send_file_data(struct mg_connection *conn, const uint8_t* data, in ...@@ -147,17 +149,35 @@ void civetweb_send_file_data(struct mg_connection *conn, const uint8_t* data, in
if ((int64_t)to_read > len) { if ((int64_t)to_read > len) {
to_read = (int)len; to_read = (int)len;
} }
if (use_chunked_encoding) {
/* Cap at a chunk size of 16k */
to_write = to_read;
if (to_write > 16384) {
to_write = 16384;
}
/* Send read bytes to the client, exit the loop on error */
if ((num_written = mg_send_chunk(conn, data, (size_t)to_write))
< to_write) {
break;
}
}
else {
/* Send read bytes to the client, exit the loop on error */ /* Send read bytes to the client, exit the loop on error */
if ((num_written = mg_write(conn, data, (size_t)to_read)) if ((num_written = mg_write(conn, data, (size_t)to_read))
!= to_read) { != to_read) {
break; break;
} }
}
data += num_written; data += num_written;
/* Both read and were successful, adjust counters */ /* Both read and were successful, adjust counters */
len -= num_written; len -= num_written;
} }
if (use_chunked_encoding) {
mg_send_chunk(conn, NULL, 0);
}
} }
void civetweb_send_file(struct mg_connection *conn, const char* content_type, const uint8_t* data, size_t length) void civetweb_send_file(struct mg_connection *conn, const char* content_type, const uint8_t* data, size_t length)
...@@ -166,18 +186,24 @@ void civetweb_send_file(struct mg_connection *conn, const char* content_type, co ...@@ -166,18 +186,24 @@ void civetweb_send_file(struct mg_connection *conn, const char* content_type, co
char range[128]; /* large enough, so there will be no overflow */ char range[128]; /* large enough, so there will be no overflow */
const char *range_hdr; const char *range_hdr;
int64_t cl, r1, r2; int64_t cl, r1, r2;
int n, truncated; int n;
const char *encoding = 0; const char *encoding = 0;
const char *origin_hdr; const char *origin_hdr;
const char *cors_orig_cfg; // const char *cors_orig_cfg;
const char *cors1, *cors2; const char *cors1;
// const char *cors2;
int status_code; int status_code;
int is_head_request; int is_head_request;
int use_chunked_encoding = 0;
const struct mg_request_info *request_info;
// FIXME // FIXME
// Set to some future date for images to avoid constant reloads from the overtaxed Kestrel web server... // Set to some future date for images to avoid constant reloads from the overtaxed Kestrel web server...
uint64_t last_modified = 0; uint64_t last_modified = 0;
request_info = mg_get_request_info(conn);
is_head_request = !strcmp(request_info->request_method, "HEAD");
cl = (int64_t)length; cl = (int64_t)length;
status_code = 200; status_code = 200;
range[0] = '\0'; range[0] = '\0';
...@@ -207,7 +233,7 @@ void civetweb_send_file(struct mg_connection *conn, const char* content_type, co ...@@ -207,7 +233,7 @@ void civetweb_send_file(struct mg_connection *conn, const char* content_type, co
/* Standard CORS header */ /* Standard CORS header */
origin_hdr = mg_get_header(conn, "Origin"); origin_hdr = mg_get_header(conn, "Origin");
cors1 = "Access-Control-Allow-Origin"; cors1 = "Access-Control-Allow-Origin";
cors2 = cors_orig_cfg; //cors2 = cors_orig_cfg;
/* Prepare Etag, and Last-Modified headers. */ /* Prepare Etag, and Last-Modified headers. */
gmt_time_string(lm, sizeof(lm), &last_modified); gmt_time_string(lm, sizeof(lm), &last_modified);
...@@ -227,9 +253,9 @@ void civetweb_send_file(struct mg_connection *conn, const char* content_type, co ...@@ -227,9 +253,9 @@ void civetweb_send_file(struct mg_connection *conn, const char* content_type, co
"Content-Type", "Content-Type",
content_type, content_type,
(int)strlen(content_type)); (int)strlen(content_type));
if (cors1[0] != 0) { // if (cors1[0] != 0) {
mg_response_header_add(conn, cors1, cors2, -1); // mg_response_header_add(conn, cors1, cors2, -1);
} // }
mg_response_header_add(conn, "Last-Modified", lm, -1); mg_response_header_add(conn, "Last-Modified", lm, -1);
mg_response_header_add(conn, "Etag", etag, -1); mg_response_header_add(conn, "Etag", etag, -1);
...@@ -240,11 +266,13 @@ void civetweb_send_file(struct mg_connection *conn, const char* content_type, co ...@@ -240,11 +266,13 @@ void civetweb_send_file(struct mg_connection *conn, const char* content_type, co
int trunc = 0; int trunc = 0;
mg_snprintf(conn, &trunc, len, sizeof(len), "%lld", cl); mg_snprintf(conn, &trunc, len, sizeof(len), "%lld", cl);
if (!trunc) { if ((!trunc) && (!use_chunked_encoding)) {
mg_response_header_add(conn, "Content-Length", len, -1); mg_response_header_add(conn, "Content-Length", len, -1);
} }
if (!use_chunked_encoding) {
mg_response_header_add(conn, "Accept-Ranges", "bytes", -1); mg_response_header_add(conn, "Accept-Ranges", "bytes", -1);
}
if (encoding) { if (encoding) {
mg_response_header_add(conn, "Content-Encoding", encoding, -1); mg_response_header_add(conn, "Content-Encoding", encoding, -1);
...@@ -252,11 +280,14 @@ void civetweb_send_file(struct mg_connection *conn, const char* content_type, co ...@@ -252,11 +280,14 @@ void civetweb_send_file(struct mg_connection *conn, const char* content_type, co
if (range[0] != 0) { if (range[0] != 0) {
mg_response_header_add(conn, "Content-Range", range, -1); mg_response_header_add(conn, "Content-Range", range, -1);
} }
if (use_chunked_encoding) {
mg_response_header_add(conn, "Transfer-Encoding", "chunked", -1);
}
/* Send all headers */ /* Send all headers */
mg_response_header_send(conn); mg_response_header_send(conn);
if (!is_head_request) { if (!is_head_request) {
civetweb_send_file_data(conn, data + r1, cl); civetweb_send_file_data(conn, data + r1, cl, use_chunked_encoding);
} }
} }
\ No newline at end of file
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
<div class="sidebar_nav"> <div class="sidebar_nav">
<a href="/info">Info</a> <a href="/info">Info</a>
<a href="/firmwareupload$">Firmware</a> <a href="/firmwareupload">Firmware</a>
</div> </div>
<div class="header"> <div class="header">
......
...@@ -18,6 +18,7 @@ LOG_MODULE_REGISTER(webportal, LOG_LEVEL_DBG); ...@@ -18,6 +18,7 @@ LOG_MODULE_REGISTER(webportal, LOG_LEVEL_DBG);
#define WITH_ZEPHYR 1 #define WITH_ZEPHYR 1
#include "kestrel.h" #include "kestrel.h"
#include <generated/mem.h>
#define STANDARD_HEADER(title) \ #define STANDARD_HEADER(title) \
"<head>" \ "<head>" \
...@@ -42,6 +43,13 @@ static int static_file_##name##_handler(struct mg_connection *conn, void *cbdata ...@@ -42,6 +43,13 @@ static int static_file_##name##_handler(struct mg_connection *conn, void *cbdata
return 200; \ return 200; \
} }
#define KESTREL_WEBSERVICE_DEFINE_PSEUDO_FILE_HANDLER(name, type) \
static int static_file_##name##_handler(struct mg_connection *conn, void *cbdata) \
{ \
civetweb_send_file(conn, type, embedded_file_##name##_pointer, embedded_file_##name##_length); \
return 200; \
}
#define KESTREL_WEBSERVICE_DEFINE_PAGE_HANDLER(name, type, title) \ #define KESTREL_WEBSERVICE_DEFINE_PAGE_HANDLER(name, type, title) \
static int static_file_##name##_handler(struct mg_connection *conn, void *cbdata) \ static int static_file_##name##_handler(struct mg_connection *conn, void *cbdata) \
{ \ { \
...@@ -58,17 +66,26 @@ static int static_file_##name##_handler(struct mg_connection *conn, void *cbdata ...@@ -58,17 +66,26 @@ static int static_file_##name##_handler(struct mg_connection *conn, void *cbdata
#define KESTREL_WEBSERVICE_REGISTER_FILE_HANDLER(name, path) \ #define KESTREL_WEBSERVICE_REGISTER_FILE_HANDLER(name, path) \
mg_set_request_handler(ctx, path, static_file_##name##_handler, (void *)0); mg_set_request_handler(ctx, path, static_file_##name##_handler, (void *)0);
// Set this as small as possible #define MAX_REQUEST_SIZE_BYTES 8192
#define MAX_REQUEST_SIZE_BYTES 1024
// Define ports // Define ports
#define HTTP_PORT 8080 #define HTTP_PORT 8080
#define HTTPS_PORT 4443 #define HTTPS_PORT 4443
uint8_t* embedded_file_fpga_firmware_raw_pointer = (uint8_t*)((uintptr_t)BMCSPIFLASH_BASE + 0x0);
size_t embedded_file_fpga_firmware_raw_length = 0x800000;
uint8_t* embedded_file_bmc_firmware_raw_pointer = (uint8_t*)((uintptr_t)BMCSPIFLASH_BASE + 0x800000);
size_t embedded_file_bmc_firmware_raw_length = 0x400000;
uint8_t* embedded_file_pnor_firmware_raw_pointer = (uint8_t*)((uintptr_t)HOSTSPIFLASH_BASE);
size_t embedded_file_pnor_firmware_raw_length = 0x400000;
KESTREL_WEBSERVICE_DEFINE_PAGE_HANDLER(index_html, "text/html", "Kestrel SoftBMC") KESTREL_WEBSERVICE_DEFINE_PAGE_HANDLER(index_html, "text/html", "Kestrel SoftBMC")
KESTREL_WEBSERVICE_DEFINE_FILE_HANDLER(style_css, "text/css") KESTREL_WEBSERVICE_DEFINE_FILE_HANDLER(style_css, "text/css")
KESTREL_WEBSERVICE_DEFINE_FILE_HANDLER(raptor_logo_jpg, "image/jpeg") KESTREL_WEBSERVICE_DEFINE_FILE_HANDLER(raptor_logo_jpg, "image/jpeg")
KESTREL_WEBSERVICE_DEFINE_FILE_HANDLER(kestrel_avatar_small_png, "image/png") KESTREL_WEBSERVICE_DEFINE_FILE_HANDLER(kestrel_avatar_small_png, "image/png")
KESTREL_WEBSERVICE_DEFINE_PSEUDO_FILE_HANDLER(fpga_firmware_raw, "application/octet-stream")
KESTREL_WEBSERVICE_DEFINE_PSEUDO_FILE_HANDLER(bmc_firmware_raw, "application/octet-stream")
KESTREL_WEBSERVICE_DEFINE_PSEUDO_FILE_HANDLER(pnor_firmware_raw, "application/octet-stream")
struct civetweb_info { struct civetweb_info {
const char *version; const char *version;
...@@ -137,7 +154,7 @@ int firmware_upload_form_handler(struct mg_connection *conn, void *cbdata) ...@@ -137,7 +154,7 @@ int firmware_upload_form_handler(struct mg_connection *conn, void *cbdata)
"HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: " "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: "
"close\r\n\r\n"); "close\r\n\r\n");
SEND_STANDARD_HEADER(conn, "Firmware Upload") SEND_STANDARD_HEADER(conn, "Firmware Management")
mg_printf(conn, "<h3>Firmware Upload</h3>"); mg_printf(conn, "<h3>Firmware Upload</h3>");
mg_printf(conn, mg_printf(conn,
...@@ -148,6 +165,12 @@ int firmware_upload_form_handler(struct mg_connection *conn, void *cbdata) ...@@ -148,6 +165,12 @@ int firmware_upload_form_handler(struct mg_connection *conn, void *cbdata)
mg_printf(conn, "<input type=\"submit\" value=\"Upload\">\n"); mg_printf(conn, "<input type=\"submit\" value=\"Upload\">\n");
mg_printf(conn, "</form>\n"); mg_printf(conn, "</form>\n");
mg_printf(conn, "<p>\n");
mg_printf(conn, "<h3>Firmware Download</h3>\n");
mg_printf(conn, "<a href=\"/firmware/fpga.img\">FPGA</a><br>\n");
mg_printf(conn, "<a href=\"/firmware/bmc.img\">BMC</a><br>\n");
mg_printf(conn, "<a href=\"/firmware/pnor.img\">PNOR</a><br>\n");
SEND_STANDARD_FOOTER(conn); SEND_STANDARD_FOOTER(conn);
return 200; return 200;
...@@ -237,7 +260,7 @@ void *web_portal_pthread(void *arg) ...@@ -237,7 +260,7 @@ void *web_portal_pthread(void *arg)
"listening_ports", "listening_ports",
STRINGIFY(HTTP_PORT), STRINGIFY(HTTP_PORT),
"num_threads", "num_threads",
"1", "16",
"max_request_size", "max_request_size",
STRINGIFY(MAX_REQUEST_SIZE_BYTES), STRINGIFY(MAX_REQUEST_SIZE_BYTES),
NULL NULL
...@@ -263,6 +286,9 @@ void *web_portal_pthread(void *arg) ...@@ -263,6 +286,9 @@ void *web_portal_pthread(void *arg)
// Static files // Static files
KESTREL_WEBSERVICE_REGISTER_FILE_HANDLER(raptor_logo_jpg, "/raptor_logo.jpg$") KESTREL_WEBSERVICE_REGISTER_FILE_HANDLER(raptor_logo_jpg, "/raptor_logo.jpg$")
KESTREL_WEBSERVICE_REGISTER_FILE_HANDLER(kestrel_avatar_small_png, "/kestrel_avatar_small.png$") KESTREL_WEBSERVICE_REGISTER_FILE_HANDLER(kestrel_avatar_small_png, "/kestrel_avatar_small.png$")
KESTREL_WEBSERVICE_REGISTER_FILE_HANDLER(fpga_firmware_raw, "/firmware/fpga.img$")
KESTREL_WEBSERVICE_REGISTER_FILE_HANDLER(bmc_firmware_raw, "/firmware/bmc.img$")
KESTREL_WEBSERVICE_REGISTER_FILE_HANDLER(pnor_firmware_raw, "/firmware/pnor.img$")
// Dynamic pages // Dynamic pages
mg_set_request_handler(ctx, "/info$", system_info_handler, (void *)0); mg_set_request_handler(ctx, "/info$", system_info_handler, (void *)0);
......
...@@ -52,7 +52,8 @@ CONFIG_LOG_PRINTK=n ...@@ -52,7 +52,8 @@ CONFIG_LOG_PRINTK=n
CONFIG_LOG_PROCESS_TRIGGER_THRESHOLD=0 CONFIG_LOG_PROCESS_TRIGGER_THRESHOLD=0
# POSIX options # POSIX options
CONFIG_POSIX_MAX_FDS=20 CONFIG_POSIX_MAX_FDS=32
CONFIG_MAX_PTHREAD_COUNT=64
CONFIG_POSIX_API=y CONFIG_POSIX_API=y
CONFIG_PTHREAD_IPC=y CONFIG_PTHREAD_IPC=y
CONFIG_POSIX_MQUEUE=y CONFIG_POSIX_MQUEUE=y
...@@ -73,18 +74,20 @@ CONFIG_NET_IPV6=y ...@@ -73,18 +74,20 @@ CONFIG_NET_IPV6=y
CONFIG_NET_TCP=y CONFIG_NET_TCP=y
CONFIG_NET_UDP=y CONFIG_NET_UDP=y
CONFIG_NET_SOCKETS=y CONFIG_NET_SOCKETS=y
CONFIG_NET_MAX_CONN=20 CONFIG_NET_MAX_CONN=32
CONFIG_NET_MAX_CONTEXTS=20 CONFIG_NET_MAX_CONTEXTS=32
CONFIG_NET_STATISTICS=y CONFIG_NET_STATISTICS=y
CONFIG_NET_CONNECTION_MANAGER=y CONFIG_NET_CONNECTION_MANAGER=y
CONFIG_NET_MGMT=y CONFIG_NET_MGMT=y
CONFIG_NET_MGMT_EVENT=y CONFIG_NET_MGMT_EVENT=y
CONFIG_NET_TCP_BACKLOG_SIZE=16
# Network buffers # Network buffers
CONFIG_NET_PKT_RX_COUNT=4096 CONFIG_NET_PKT_RX_COUNT=4096
CONFIG_NET_PKT_TX_COUNT=4096 CONFIG_NET_PKT_TX_COUNT=4096
CONFIG_NET_BUF_RX_COUNT=4096 CONFIG_NET_BUF_RX_COUNT=32768
CONFIG_NET_BUF_TX_COUNT=4096 CONFIG_NET_BUF_TX_COUNT=32768
CONFIG_NET_BUF_DATA_SIZE=128
CONFIG_NET_CONTEXT_NET_PKT_POOL=y CONFIG_NET_CONTEXT_NET_PKT_POOL=y
CONFIG_NET_BUF_POOL_USAGE=y CONFIG_NET_BUF_POOL_USAGE=y
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment