diff --git a/Makefile b/Makefile index a6377b0..21defe6 100644 --- a/Makefile +++ b/Makefile @@ -1,21 +1,14 @@ -PORT_SOURCES = lib/src/port/httpd-posix.c +.PHONY: all clean espfsbuilder demo lib -LIB_SOURCES = ${PORT_SOURCES} \ - lib/src/utils/base64.c \ - lib/src/utils/sha1.c \ - lib/espfs/espfs.c \ - lib/src/httpdespfs.c \ - lib/src/httpd.c \ - lib/src/httpd-loop.c \ - lib/src/cgiwebsocket.c \ - lib/heatshrink/heatshrink_decoder.c +all: demo espfsbuilder -LIB_INCLUDES = -Ilib/include -Ilib/heatshrink -Ilib/espfs +clean: + make -C ./spritehttpd clean + make -C ./demo clean + make -C ./espfsbuilder clean -DEMO_SOURCES = main.c +espfsbuilder: + make -C ./espfsbuilder - -all: demo - -demo: ${LIB_SOURCES} ${DEMO_SOURCES} - cc -g $^ -o $@ ${LIB_INCLUDES} +demo: + make -C ./demo diff --git a/demo/.gitignore b/demo/.gitignore new file mode 100644 index 0000000..9f12867 --- /dev/null +++ b/demo/.gitignore @@ -0,0 +1,7 @@ +demo +*.o +.idea/ +*.bin +*.a +staticfiles-embed.c +staticfiles.bin diff --git a/demo/Makefile b/demo/Makefile new file mode 100644 index 0000000..c822cd7 --- /dev/null +++ b/demo/Makefile @@ -0,0 +1,35 @@ +DEMO_SOURCES = server_demo.c staticfiles-embed.c + +FSBUILDER = ../espfsbuilder/mkespfsimage + +LIBFILE = ../spritehttpd/libspritehttpd.a + +STATIC_FILES = \ + staticfiles/index.html \ + staticfiles/kocour.jpg + +all: demo + +$(FSBUILDER): + make -C ../espfsbuilder + +staticfiles.bin: $(FSBUILDER) ${STATIC_FILES} + $(FSBUILDER) -c1 -g jpg --strip-path staticfiles -o $@ ${STATIC_FILES} + $(FSBUILDER) -p $@ + +staticfiles-embed.c: staticfiles.bin + xxd -i -n espfs_image $< $@ + +clean: + rm -f demo staticfiles.bin staticfiles-embed.c + make -C ../spritehttpd + +$(LIBFILE): + make -C ../spritehttpd PLATFORM=posix CFLAGS="-Og -g" + +demo: ${DEMO_SOURCES} $(LIBFILE) + cc -Og -g -Wall ${DEMO_SOURCES} \ + -o $@ \ + -I../spritehttpd/include \ + -lspritehttpd \ + -L../spritehttpd/ diff --git a/main.c b/demo/server_demo.c similarity index 65% rename from main.c rename to demo/server_demo.c index 8fa35b7..0d0ec14 100644 --- a/main.c +++ b/demo/server_demo.c @@ -3,14 +3,17 @@ #include "httpd-utils.h" #include "httpdespfs.h" - #include #include #include #include +#include #include "logging.h" +extern unsigned char espfs_image[]; +extern unsigned int espfs_image_len; + /** "About" page */ httpd_cgi_state tplIndex(HttpdConnData *connData, char *token, void **arg) { @@ -35,18 +38,26 @@ const HttpdBuiltInUrl routes[] = { // TODO password lock ... // --- Web pages --- - ROUTE_TPL_FILE("/", tplIndex, "/index.tpl"), +// ROUTE_TPL_FILE("/", tplIndex, "/index.tpl"), + ROUTE_FILE("/", "index.html"), ROUTE_FILESYSTEM(), ROUTE_END(), }; +void sigpipe_handler(int unused) +{ +} + int main() { printf("Hello, World!\n"); + // prevent abort on sigpipe + sigaction(SIGPIPE, &(struct sigaction) {sigpipe_handler}, NULL); + struct httpd_options opts = { - .port = 80, + .port = 8080, }; httpd_thread_handle_t *handle = httpdInit(routes, &opts); @@ -56,3 +67,13 @@ int main() return 0; } + +int httpdPlatEspfsRead(void *dest, uint32_t offset, size_t len) +{ + if (offset + len > espfs_image_len) { + return -1; + } + + memcpy(dest, &espfs_image[offset], len); + return 0; +} diff --git a/demo/staticfiles/index.html b/demo/staticfiles/index.html new file mode 100644 index 0000000..a297230 --- /dev/null +++ b/demo/staticfiles/index.html @@ -0,0 +1,10 @@ + + + + + SpriteHTTPD demo + + + + + diff --git a/demo/staticfiles/kocour.jpg b/demo/staticfiles/kocour.jpg new file mode 100644 index 0000000..4c5c20a Binary files /dev/null and b/demo/staticfiles/kocour.jpg differ diff --git a/espfsbuilder/Makefile b/espfsbuilder/Makefile index eafa4c6..e1790df 100644 --- a/espfsbuilder/Makefile +++ b/espfsbuilder/Makefile @@ -1,7 +1,14 @@ TARGET=mkespfsimage -SOURCES = main.c ../lib/heatshrink/heatshrink_encoder.c ../lib/heatshrink/heatshrink_decoder.c ../lib/espfs/espfs.c -CFLAGS = -I. -I../lib/heatshrink/ -I../lib/espfs/ +SOURCES = main.c parsing.c \ + ../spritehttpd/lib/heatshrink/heatshrink_encoder.c \ + ../spritehttpd/lib/heatshrink/heatshrink_decoder.c \ + ../spritehttpd/lib/espfs/espfs.c + +CFLAGS = -I. \ + -I../spritehttpd/lib/heatshrink/ \ + -I../spritehttpd/lib/espfs/ \ + -DZLIB_CONST all: $(TARGET) diff --git a/espfsbuilder/README.md b/espfsbuilder/README.md new file mode 100644 index 0000000..3d91ca5 --- /dev/null +++ b/espfsbuilder/README.md @@ -0,0 +1,7 @@ +This is a command-line utility that builds the binary espfs image. +The tool can also parse the espfs image file for verification. + +It uses heatshrink files & the config header from the main project. + +The binary can be embedded in the fileserver project e.g. using `xxd -i` to convert it to a C source file +that can be `#include`'d. diff --git a/espfsbuilder/main.c b/espfsbuilder/main.c index 07269db..d42592c 100644 --- a/espfsbuilder/main.c +++ b/espfsbuilder/main.c @@ -11,12 +11,10 @@ #include "espfsformat.h" #include "heatshrink_encoder.h" -#include "espfs.h" +#include "parsing.h" #define DEFAULT_GZIP_EXTS "html,css,js,svg,png,jpg,gif" -// static variables -static int s_outFd = 1; struct InputFileLinkedListEntry; struct InputFileLinkedListEntry { @@ -24,10 +22,16 @@ struct InputFileLinkedListEntry { struct InputFileLinkedListEntry *next; }; +/// two ends of a linked list with input files static struct InputFileLinkedListEntry *s_inputFiles = NULL; static struct InputFileLinkedListEntry *s_lastInputFile = NULL; +/// Output file FD +static int s_outFd = 1; + +/// Array of gzipped extensions, ends with a NULL pointer static char **s_gzipExtensions = NULL; +/// Gzip all files static bool s_gzipAll = false; // impls to satisfy defs in the config header @@ -41,9 +45,19 @@ void httpdPlatFree(void *ptr) free(ptr); } -size_t compressHeatshrink(uint8_t *in, size_t insize, uint8_t *out, size_t outcap, int level) +/** + * Compress a file using Heatshrink + * + * @param[in] in - pointer to the uncompressed input + * @param insize - len of the uncompressed input + * @param[out] out - destination buffer for the compressed data + * @param outcap - capacity of the output buffer + * @param level - compression level, 1-9; -1 for default. + * @return actual length of the compressed data + */ +size_t compressHeatshrink(const uint8_t *in, size_t insize, uint8_t *out, size_t outcap, int level) { - uint8_t *inp = in; + const uint8_t *inp = in; uint8_t *outp = out; size_t len; int ws[] = {5, 6, 8, 11, 13}; @@ -82,7 +96,7 @@ size_t compressHeatshrink(uint8_t *in, size_t insize, uint8_t *out, size_t outca } while (insize != 0); if (insize != 0) { - fprintf(stderr, "Heatshrink: Bug? insize is still %d. sres=%d pres=%d\n", (int)insize, sres, pres); + fprintf(stderr, "Heatshrink: Bug? insize is still %d. sres=%d pres=%d\n", (int) insize, sres, pres); exit(1); } @@ -90,7 +104,17 @@ size_t compressHeatshrink(uint8_t *in, size_t insize, uint8_t *out, size_t outca return r; } -size_t compressGzip(uint8_t *in, size_t insize, uint8_t *out, size_t outsize, int level) +/** + * Compress a file using Gzip + * + * @param[in] in - pointer to the uncompressed input + * @param insize - len of the uncompressed input + * @param[out] out - destination buffer for the compressed data + * @param outcap - capacity of the output buffer + * @param level - compression level, 1-9; -1 for default. + * @return actual length of the compressed data + */ +size_t compressGzip(const uint8_t *in, size_t insize, uint8_t *out, size_t outcap, int level) { z_stream stream; int zresult; @@ -101,7 +125,7 @@ size_t compressGzip(uint8_t *in, size_t insize, uint8_t *out, size_t outsize, in stream.next_in = in; stream.avail_in = insize; stream.next_out = out; - stream.avail_out = outsize; + stream.avail_out = outcap; // 31 -> 15 window bits + 16 for gzip zresult = deflateInit2(&stream, level, Z_DEFLATED, 31, 8, Z_DEFAULT_STRATEGY); if (zresult != Z_OK) { @@ -124,6 +148,12 @@ size_t compressGzip(uint8_t *in, size_t insize, uint8_t *out, size_t outsize, in return stream.total_out; } +/** + * Check if a file name should be compressed by gzip + * + * @param name - file name + * @return true if should compress + */ bool shouldCompressGzip(const char *name) { if (!s_gzipExtensions) { return false; } @@ -150,7 +180,13 @@ bool shouldCompressGzip(const char *name) return false; } -int parseGzipExtensions(char *input) +/** + * Parse a list of gzipped extensions + * + * @param input - list of comma-separated extensions, e.g. "jpg,png" + * @return + */ +void parseGzipExtensions(char *input) { char *token; char *extList = input; @@ -173,19 +209,17 @@ int parseGzipExtensions(char *input) } // terminate list s_gzipExtensions[count] = NULL; - - return 1; } /** * Process a file. * * @param fd - filedes - * @param name - filename to embed in the archive + * @param[in] name - filename to embed in the archive * @param compression_mode - compression mode * @param level - compression level for heatshrink, 1-9 * @param[out] compName - the used compression is output here (for debug print) - * @return + * @return - size of the output, in percent (100% = no compression) */ int handleFile(int fd, const char *name, int compression_mode, int level, const char **compName) { @@ -282,11 +316,13 @@ int handleFile(int fd, const char *name, int compression_mode, int level, const return size ? (int) ((csize * 100) / size) : 100; } -//Write final dummy header with FLAG_LASTFILE set. +/** + * Write final dummy header with FLAG_LASTFILE set. + */ void finishArchive() { EspFsHeader h; - h.magic = htole32(ESPFS_MAGIC); // ('E' << 0) + ('S' << 8) + ('f' << 16) + ('s' << 24); + h.magic = htole32(ESPFS_MAGIC); h.flags = FLAG_LASTFILE; h.compression = COMPRESS_NONE; h.nameLen = 0; @@ -295,62 +331,13 @@ void finishArchive() write(s_outFd, &h, sizeof(EspFsHeader)); } -static size_t espfs_parse_filesize = -1; -static int espfs_parse_fd = -1; - -void parseEspfsFileAndShowItsContents(const char *filename) -{ - int rv; - fprintf(stderr, "Parsing: %s\n", filename); - - FILE *f = fopen(filename, "r"); - if (!f) { - perror(filename); - exit(1); - } - int fd = fileno(f); - - espfs_parse_filesize = lseek(fd, 0, SEEK_END); - lseek(fd, 0, SEEK_SET); - - espfs_parse_fd = fd; - - rv = espFsInit(); - if (rv != 0) { - fprintf(stderr, "Fail to init FS\n"); - exit(1); - } - - EspFsWalk walk; - espFsWalkInit(&walk); - - EspFsHeader header; - uint32_t offset; - char namebuf[1024]; - - while (espFsWalkNext(&walk, &header, namebuf, 1024, &offset)) { - fprintf(stderr, "at %04x: \"%s\", flags: %02x, comp: %s, compLen: %d, plainLen: %d\n", offset, namebuf, header.flags, - header.compression == 1 ? "HS" : "None", header.fileLenComp, header.fileLenDecomp); - } - - fclose(f); -} - - -int httpdPlatEspfsRead(void *dest, uint32_t offset, size_t len) -{ - fprintf(stderr, "FS read @ %d, len %d\n", offset, len); - if (offset + len > espfs_parse_filesize) { - fprintf(stderr, "Read out fo range!\n"); - return -1; - } - lseek(espfs_parse_fd, offset, SEEK_SET); - read(espfs_parse_fd, dest, len); - return 0; -} - - -void queueInputFile(char *name) +/** + * Queue a file for adding to the archive. + * Appends it to the `s_inputFiles` linked list. + * + * @param name - file name to add + */ +void queueInputFile(const char *name) { fprintf(stderr, "INFILE: %s\n", name); @@ -385,20 +372,22 @@ int main(int argc, char **argv) int c; char *outfile = NULL; char *parseFile = NULL; + char *stripPath = NULL; while (1) { int option_index = 0; static struct option long_options[] = { - {"parse", required_argument, 0, 'p'}, - {"compress", required_argument, 0, 'c'}, - {"gzip", no_argument, 0, 'z'}, - {"gzip-all", no_argument, 0, 'G'}, - {"level", required_argument, 0, 'l'}, - {"gzip-exts", required_argument, 0, 'g'}, - {"input", required_argument, 0, 'i'}, - {"output", required_argument, 0, 'o'}, - {"help", no_argument, 0, 'h'}, - {0, 0, 0, 0} + {"parse", required_argument, 0, 'p'}, + {"compress", required_argument, 0, 'c'}, + {"gzip", no_argument, 0, 'z'}, + {"gzip-all", no_argument, 0, 'G'}, + {"level", required_argument, 0, 'l'}, + {"gzip-exts", required_argument, 0, 'g'}, + {"input", required_argument, 0, 'i'}, + {"output", required_argument, 0, 'o'}, + {"strip-path", required_argument, 0, 'S'}, + {"help", no_argument, 0, 'h'}, + {0, 0, 0, 0} }; c = getopt_long(argc, argv, "c:l:g:zGhp:i:o:0123456789", @@ -423,6 +412,10 @@ int main(int argc, char **argv) parseFile = strdup(optarg); break; + case 'S': + stripPath = strdup(optarg); + break; + case 'c': compType = atoi(optarg); break; @@ -434,11 +427,7 @@ int main(int argc, char **argv) case 'g': use_gzip = true; - if (!parseGzipExtensions(optarg)) { - fprintf(stderr, "Bad gzip extension list: %s\n", optarg); - err = 1; - goto show_help; - } + parseGzipExtensions(optarg); break; case 'l': @@ -473,7 +462,6 @@ int main(int argc, char **argv) exit(0); } - if (s_gzipExtensions == NULL && use_gzip) { parseGzipExtensions(strdup(DEFAULT_GZIP_EXTS)); } @@ -514,14 +502,24 @@ int main(int argc, char **argv) serr = stat(name, &statBuf); if ((serr == 0) && S_ISREG(statBuf.st_mode)) { //Strip off './' or '/' madness. - realName = name; - if (name[0] == '.' && name[1] == '/') { realName += 2; } - if (realName[0] == '/') { realName++; } + char *embeddedName = name; f = open(name, O_RDONLY); + + // relative path starting with ./, remove that + if (embeddedName[0] == '.' && embeddedName[1] == '/') { + embeddedName += 2; + } + // remove prefix + if (stripPath && 0 == strncmp(embeddedName, stripPath, strlen(stripPath))) { + embeddedName += strlen(stripPath); + } + // remove leading slash, if any + if (embeddedName[0] == '/') { embeddedName++; } + if (f > 0) { const char *compName = "unknown"; - rate = handleFile(f, realName, compType, compLvl, &compName); - fprintf(stderr, "%s (%d%%, %s)\n", realName, rate, compName); + rate = handleFile(f, embeddedName, compType, compLvl, &compName); + fprintf(stderr, "%s (%d%%, %s)\n", embeddedName, rate, compName); close(f); } else { perror(name); @@ -550,7 +548,7 @@ int main(int argc, char **argv) fprintf(stderr, "[-c|--compress COMPRESSOR]\n 0 - None, 1 - Heatshrink (default)\n"); fprintf(stderr, "[-l|--level LEVEL] or [-0 through -9]\n compression level 1-9, higher is better but uses more RAM\n"); fprintf(stderr, "[-z|--gzip]\n use gzip for files with extensions matching "DEFAULT_GZIP_EXTS"\n"); - fprintf(stderr, "[-Z|--gzip-all]\n use gzip for all files\n"); + fprintf(stderr, "[-G|--gzip-all]\n use gzip for all files\n"); fprintf(stderr, "[-g|--gzip-exts GZIPPED_EXTENSIONS]\n use gzip for files with custom extensions, comma-separated\n"); fprintf(stderr, "[-i|--input FILE]\n Input file, can be multiple. Files can also be passed at the end without -i, or as lines on stdin if not specified by args\n"); fprintf(stderr, "[-o|--output FILE]\n Output file name; if not specified, outputs to stdout\n"); diff --git a/espfsbuilder/parsing.c b/espfsbuilder/parsing.c new file mode 100644 index 0000000..c7f236e --- /dev/null +++ b/espfsbuilder/parsing.c @@ -0,0 +1,67 @@ +#include +#include +#include +#include + +#include "parsing.h" +#include "espfs.h" + +static size_t espfs_parse_filesize = -1; +static int espfs_parse_fd = -1; + +/** + * Parse an image file and show the files contained. + * This is a simple sanity test. + * + * @param[in] filename - image file to parse + */ +void parseEspfsFileAndShowItsContents(const char *filename) +{ + int rv; + fprintf(stderr, "Parsing: %s\n", filename); + + FILE *f = fopen(filename, "r"); + if (!f) { + perror(filename); + exit(1); + } + int fd = fileno(f); + + espfs_parse_filesize = lseek(fd, 0, SEEK_END); + lseek(fd, 0, SEEK_SET); + + espfs_parse_fd = fd; + + rv = espFsInit(); + if (rv != 0) { + fprintf(stderr, "Fail to init FS\n"); + exit(1); + } + + EspFsWalk walk; + espFsWalkInit(&walk); + + EspFsHeader header; + uint32_t offset; + char namebuf[1024]; + + while (espFsWalkNext(&walk, &header, namebuf, 1024, &offset)) { + fprintf(stderr, "at %04x: \"%s\", flags: %02x, comp: %s, compLen: %d, plainLen: %d\n", offset, namebuf, header.flags, + header.compression == 1 ? "HS" : "None", header.fileLenComp, header.fileLenDecomp); + } + + fclose(f); +} + + +int httpdPlatEspfsRead(void *dest, uint32_t offset, size_t len) +{ + // fprintf(stderr, "FS read @ %d, len %d\n", offset, (int) len); + if (offset + len > espfs_parse_filesize) { + // fprintf(stderr, "Read out fo range!\n"); + return -1; + } + lseek(espfs_parse_fd, offset, SEEK_SET); + read(espfs_parse_fd, dest, len); + return 0; +} diff --git a/espfsbuilder/parsing.h b/espfsbuilder/parsing.h new file mode 100644 index 0000000..5b56a61 --- /dev/null +++ b/espfsbuilder/parsing.h @@ -0,0 +1,7 @@ +/** + * The espfs archive parsing part of mkespfsimage + */ + +#pragma once + +void parseEspfsFileAndShowItsContents(const char *filename); diff --git a/spritehttpd/.gitignore b/spritehttpd/.gitignore new file mode 100644 index 0000000..97c272b --- /dev/null +++ b/spritehttpd/.gitignore @@ -0,0 +1,5 @@ +mkespfsimage +*.o +.idea/ +*.bin +*.a diff --git a/spritehttpd/Makefile b/spritehttpd/Makefile new file mode 100644 index 0000000..cc1dac0 --- /dev/null +++ b/spritehttpd/Makefile @@ -0,0 +1,51 @@ +# If building for posix: +ifeq ($(PLATFORM),arm-freertos) + CC ?= arm-none-eabi-gcc + AR ?= arm-none-eabi-ar + PORT_SOURCES = src/port/httpd-freertos.c +else + # Probably posix + CC ?= cc + AR ?= ar + PORT_SOURCES = src/port/httpd-posix.c +endif + +# additional C flags can be specified via the CFLAGS variable + + +LIB_FILE = libspritehttpd.a + +LIB_SOURCES = ${PORT_SOURCES} \ + lib/espfs/espfs.c \ + lib/heatshrink/heatshrink_decoder.c \ + src/utils/base64.c \ + src/utils/sha1.c \ + src/httpdespfs.c \ + src/httpd.c \ + src/httpd-loop.c \ + src/cgiwebsocket.c + +LIB_OBJS = ${LIB_SOURCES:.c=.o} + +LIB_INCLUDES = -Iinclude -Ilib/heatshrink -Ilib/espfs + +# TODO check what these mean +LIB_CFLAGS = -fPIC -Wall -Wextra -c + +OBJ_DIR=./obj + +OUT_DIR=. + +all: $(LIB_FILE) + +%.o: %.c + $(CC) -c $(LIB_INCLUDES) $(CFLAGS) $(LIB_CFLAGS) -o $@ $< + +$(LIB_FILE): ${LIB_OBJS} + $(AR) rcs $@ $^ + +clean: + find . -type f -name '*.o' -delete + find . -type f -name '*.d' -delete + find . -type f -name '*.a' -delete + find . -type f -name '*.elf' -delete diff --git a/lib/include/auth.h b/spritehttpd/include/auth.h similarity index 100% rename from lib/include/auth.h rename to spritehttpd/include/auth.h diff --git a/lib/include/cgiwebsocket.h b/spritehttpd/include/cgiwebsocket.h similarity index 100% rename from lib/include/cgiwebsocket.h rename to spritehttpd/include/cgiwebsocket.h diff --git a/lib/include/httpd-platform.h b/spritehttpd/include/httpd-platform.h similarity index 100% rename from lib/include/httpd-platform.h rename to spritehttpd/include/httpd-platform.h diff --git a/lib/include/httpd-utils.h b/spritehttpd/include/httpd-utils.h similarity index 100% rename from lib/include/httpd-utils.h rename to spritehttpd/include/httpd-utils.h diff --git a/lib/include/httpd.h b/spritehttpd/include/httpd.h similarity index 100% rename from lib/include/httpd.h rename to spritehttpd/include/httpd.h diff --git a/lib/include/httpdespfs.h b/spritehttpd/include/httpdespfs.h similarity index 100% rename from lib/include/httpdespfs.h rename to spritehttpd/include/httpdespfs.h diff --git a/lib/include/logging.h b/spritehttpd/include/logging.h similarity index 100% rename from lib/include/logging.h rename to spritehttpd/include/logging.h diff --git a/lib/espfs/espfs.c b/spritehttpd/lib/espfs/espfs.c similarity index 96% rename from lib/espfs/espfs.c rename to spritehttpd/lib/espfs/espfs.c index 60f9157..c890166 100644 --- a/lib/espfs/espfs.c +++ b/spritehttpd/lib/espfs/espfs.c @@ -17,6 +17,7 @@ It's written for use with httpd, but doesn't need to be used as such. #include #include #include +#include #include "espfsformat.h" #include "espfs.h" @@ -202,6 +203,12 @@ EspFsFile *espFsOpen(const char *fileName) return NULL; } + // Indians + h.magic = le32toh(h.magic); + h.nameLen = le16toh(h.nameLen); + h.fileLenComp = le32toh(h.fileLenComp); + h.fileLenDecomp = le32toh(h.fileLenDecomp); + if (h.magic != ESPFS_MAGIC) { espfs_error("[EspFS] Magic mismatch. EspFS image broken."); return NULL; @@ -220,6 +227,8 @@ EspFsFile *espFsOpen(const char *fileName) namebuf[h.nameLen] = 0; // ensure it's terminated if (strcmp(namebuf, fileName) == 0) { + espfs_dbg("[EspFS] Found matching file: name %s, len %d", namebuf, h.fileLenDecomp); + //Yay, this is the file we need! return espFsOpenFromHeader(&h, hpos); } diff --git a/lib/espfs/espfs.h b/spritehttpd/lib/espfs/espfs.h similarity index 98% rename from lib/espfs/espfs.h rename to spritehttpd/lib/espfs/espfs.h index 27ada64..e2b5e1e 100644 --- a/lib/espfs/espfs.h +++ b/spritehttpd/lib/espfs/espfs.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include "espfsformat.h" typedef enum { diff --git a/lib/espfs/espfsformat.h b/spritehttpd/lib/espfs/espfsformat.h similarity index 83% rename from lib/espfs/espfsformat.h rename to spritehttpd/lib/espfs/espfsformat.h index a3cc0a2..739867c 100644 --- a/lib/espfs/espfsformat.h +++ b/spritehttpd/lib/espfs/espfsformat.h @@ -12,7 +12,7 @@ with the FLAG_LASTFILE flag set. #define FLAG_GZIP (1<<1) #define COMPRESS_NONE 0 #define COMPRESS_HEATSHRINK 1 -#define ESPFS_MAGIC 0x73665345 /* ASCII ESfs - when read as little endian */ +#define ESPFS_MAGIC 0x73665345 /* ASCII sequence of bytes 'E' 'S' 'f' 's' interpreted as as little endian uint32_t */ /* 16 bytes long for alignment */ typedef struct { diff --git a/lib/heatshrink/heatshrink_common.h b/spritehttpd/lib/heatshrink/heatshrink_common.h similarity index 100% rename from lib/heatshrink/heatshrink_common.h rename to spritehttpd/lib/heatshrink/heatshrink_common.h diff --git a/lib/heatshrink/heatshrink_config.h b/spritehttpd/lib/heatshrink/heatshrink_config.h similarity index 100% rename from lib/heatshrink/heatshrink_config.h rename to spritehttpd/lib/heatshrink/heatshrink_config.h diff --git a/lib/heatshrink/heatshrink_decoder.c b/spritehttpd/lib/heatshrink/heatshrink_decoder.c similarity index 100% rename from lib/heatshrink/heatshrink_decoder.c rename to spritehttpd/lib/heatshrink/heatshrink_decoder.c diff --git a/lib/heatshrink/heatshrink_decoder.h b/spritehttpd/lib/heatshrink/heatshrink_decoder.h similarity index 100% rename from lib/heatshrink/heatshrink_decoder.h rename to spritehttpd/lib/heatshrink/heatshrink_decoder.h diff --git a/lib/heatshrink/heatshrink_encoder.c b/spritehttpd/lib/heatshrink/heatshrink_encoder.c similarity index 99% rename from lib/heatshrink/heatshrink_encoder.c rename to spritehttpd/lib/heatshrink/heatshrink_encoder.c index 21b52e7..1079b23 100644 --- a/lib/heatshrink/heatshrink_encoder.c +++ b/spritehttpd/lib/heatshrink/heatshrink_encoder.c @@ -75,7 +75,7 @@ heatshrink_encoder *heatshrink_encoder_alloc(uint8_t window_sz2, (lookahead_sz2 >= window_sz2)) { return NULL; } - + /* Note: 2 * the window size is used because the buffer needs to fit * (1 << window_sz2) bytes for the current input, and an additional * (1 << window_sz2) bytes for the previous buffer of input, which @@ -135,7 +135,7 @@ void heatshrink_encoder_reset(heatshrink_encoder *hse) { } HSE_sink_res heatshrink_encoder_sink(heatshrink_encoder *hse, - uint8_t *in_buf, size_t size, size_t *input_size) { + const uint8_t *in_buf, size_t size, size_t *input_size) { if ((hse == NULL) || (in_buf == NULL) || (input_size == NULL)) { return HSER_SINK_ERROR_NULL; } @@ -284,11 +284,11 @@ static HSE_state st_step_search(heatshrink_encoder *hse) { if (hse->input_size - msi < lookahead_sz) { max_possible = hse->input_size - msi; } - + uint16_t match_length = 0; uint16_t match_pos = find_longest_match(hse, start, end, max_possible, &match_length); - + if (match_pos == MATCH_NOT_FOUND) { LOG("ss Match not found\n"); hse->match_scan_index++; @@ -407,7 +407,7 @@ static void do_indexing(heatshrink_encoder *hse) { #if HEATSHRINK_USE_INDEX /* Build an index array I that contains flattened linked lists * for the previous instances of every byte in the buffer. - * + * * For example, if buf[200] == 'x', then index[200] will either * be an offset i such that buf[i] == 'x', or a negative offset * to indicate end-of-list. This significantly speeds up matching, @@ -416,7 +416,7 @@ static void do_indexing(heatshrink_encoder *hse) { * Future optimization options: * 1. Since any negative value represents end-of-list, the other * 15 bits could be used to improve the index dynamically. - * + * * 2. Likewise, the last lookahead_sz bytes of the index will * not be usable, so temporary data could be stored there to * dynamically improve the index. @@ -489,7 +489,7 @@ static uint16_t find_longest_match(heatshrink_encoder *hse, uint16_t start, } pos = hsi->index[pos]; } -#else +#else for (int16_t pos=end - 1; pos - (int16_t)start >= 0; pos--) { uint8_t * const pospoint = &buf[pos]; if ((pospoint[match_maxlen] == needlepoint[match_maxlen]) @@ -509,7 +509,7 @@ static uint16_t find_longest_match(heatshrink_encoder *hse, uint16_t start, } } #endif - + const size_t break_even_point = (1 + HEATSHRINK_ENCODER_WINDOW_BITS(hse) + HEATSHRINK_ENCODER_LOOKAHEAD_BITS(hse)); @@ -588,9 +588,9 @@ static void push_literal_byte(heatshrink_encoder *hse, output_info *oi) { static void save_backlog(heatshrink_encoder *hse) { size_t input_buf_sz = get_input_buffer_size(hse); - + uint16_t msi = hse->match_scan_index; - + /* Copy processed data to beginning of buffer, so it can be * used for future matches. Don't bother checking whether the * input is less than the maximum size, because if it isn't, @@ -601,7 +601,7 @@ static void save_backlog(heatshrink_encoder *hse) { memmove(&hse->buffer[0], &hse->buffer[input_buf_sz - rem], shift_sz); - + hse->match_scan_index = 0; hse->input_size -= (uint16_t)input_buf_sz - rem; } diff --git a/lib/heatshrink/heatshrink_encoder.h b/spritehttpd/lib/heatshrink/heatshrink_encoder.h similarity index 98% rename from lib/heatshrink/heatshrink_encoder.h rename to spritehttpd/lib/heatshrink/heatshrink_encoder.h index 1d9bb4f..f8e96e9 100644 --- a/lib/heatshrink/heatshrink_encoder.h +++ b/spritehttpd/lib/heatshrink/heatshrink_encoder.h @@ -93,7 +93,7 @@ void heatshrink_encoder_reset(heatshrink_encoder *hse); * INPUT_SIZE is set to the number of bytes actually sunk (in case a * buffer was filled.). */ HSE_sink_res heatshrink_encoder_sink(heatshrink_encoder *hse, - uint8_t *in_buf, size_t size, size_t *input_size); + const uint8_t *in_buf, size_t size, size_t *input_size); /* Poll for output from the encoder, copying at most OUT_BUF_SIZE bytes into * OUT_BUF (setting *OUTPUT_SIZE to the actual amount copied). */ diff --git a/lib/src/cgiwebsocket.c b/spritehttpd/src/cgiwebsocket.c similarity index 100% rename from lib/src/cgiwebsocket.c rename to spritehttpd/src/cgiwebsocket.c diff --git a/lib/src/httpd-loop.c b/spritehttpd/src/httpd-loop.c similarity index 95% rename from lib/src/httpd-loop.c rename to spritehttpd/src/httpd-loop.c index 857846d..e6739ad 100644 --- a/lib/src/httpd-loop.c +++ b/spritehttpd/src/httpd-loop.c @@ -12,6 +12,8 @@ Thanks to my collague at Espressif for writing the foundations of this code. #include #include #include +#include +#include #include "logging.h" static int httpPort; @@ -27,9 +29,17 @@ struct HttpdConnType { static HttpdConnType s_rconn[HTTPD_MAX_CONNECTIONS]; +static int fd_is_valid(int fd) +{ + return fcntl(fd, F_GETFD) != -1 || errno != EBADF; +} + int httpdConnSendData(ConnTypePtr conn, char *buff, int len) { conn->needWriteDoneNotif = 1; + if (!fd_is_valid(conn->fd)) { + return -1; + } return (write(conn->fd, buff, len) >= 0); } @@ -83,6 +93,12 @@ void platHttpServerTask(void *pvParameters) } } while (listenfd == -1); + /* https://stackoverflow.com/questions/5592747/bind-error-while-recreating-socket */ + int yes=1; + if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) == -1) { + perror("setsockopt"); + } + /* Bind to the local port */ do { ret = bind(listenfd, (struct sockaddr *) &server_addr, sizeof(server_addr)); diff --git a/lib/src/httpd.c b/spritehttpd/src/httpd.c similarity index 100% rename from lib/src/httpd.c rename to spritehttpd/src/httpd.c diff --git a/lib/src/httpdespfs.c b/spritehttpd/src/httpdespfs.c similarity index 99% rename from lib/src/httpdespfs.c rename to spritehttpd/src/httpdespfs.c index 5582b8b..65de77f 100644 --- a/lib/src/httpdespfs.c +++ b/spritehttpd/src/httpdespfs.c @@ -146,7 +146,10 @@ serveStaticFile(HttpdConnData *connData, const char *filepath) } len = espFsRead(file, buff, FILE_CHUNK_LEN); - if (len > 0) { httpdSend(connData, buff, len); } + if (len > 0) { + espfs_dbg("[EspFS] Read file chunk: %d bytes", len); + httpdSend(connData, buff, len); + } if (len != FILE_CHUNK_LEN) { //We're done. espFsClose(file); diff --git a/lib/src/port/httpd-freertos.c b/spritehttpd/src/port/httpd-freertos.c similarity index 100% rename from lib/src/port/httpd-freertos.c rename to spritehttpd/src/port/httpd-freertos.c diff --git a/lib/src/port/httpd-posix.c b/spritehttpd/src/port/httpd-posix.c similarity index 100% rename from lib/src/port/httpd-posix.c rename to spritehttpd/src/port/httpd-posix.c diff --git a/lib/src/utils/base64.c b/spritehttpd/src/utils/base64.c similarity index 100% rename from lib/src/utils/base64.c rename to spritehttpd/src/utils/base64.c diff --git a/lib/src/utils/base64.h b/spritehttpd/src/utils/base64.h similarity index 100% rename from lib/src/utils/base64.h rename to spritehttpd/src/utils/base64.h diff --git a/lib/src/utils/sha1.c b/spritehttpd/src/utils/sha1.c similarity index 100% rename from lib/src/utils/sha1.c rename to spritehttpd/src/utils/sha1.c diff --git a/lib/src/utils/sha1.h b/spritehttpd/src/utils/sha1.h similarity index 100% rename from lib/src/utils/sha1.h rename to spritehttpd/src/utils/sha1.h diff --git a/lib/todo/esphttpclient/LICENSE b/spritehttpd/todo/esphttpclient/LICENSE similarity index 100% rename from lib/todo/esphttpclient/LICENSE rename to spritehttpd/todo/esphttpclient/LICENSE diff --git a/lib/todo/esphttpclient/README.md b/spritehttpd/todo/esphttpclient/README.md similarity index 100% rename from lib/todo/esphttpclient/README.md rename to spritehttpd/todo/esphttpclient/README.md diff --git a/lib/todo/esphttpclient/httpclient.c b/spritehttpd/todo/esphttpclient/httpclient.c similarity index 100% rename from lib/todo/esphttpclient/httpclient.c rename to spritehttpd/todo/esphttpclient/httpclient.c diff --git a/lib/todo/httpclient.h b/spritehttpd/todo/httpclient.h similarity index 100% rename from lib/todo/httpclient.h rename to spritehttpd/todo/httpclient.h diff --git a/lib/todo/uptime.c b/spritehttpd/todo/uptime.c similarity index 100% rename from lib/todo/uptime.c rename to spritehttpd/todo/uptime.c diff --git a/lib/todo/uptime.h b/spritehttpd/todo/uptime.h similarity index 100% rename from lib/todo/uptime.h rename to spritehttpd/todo/uptime.h diff --git a/lib/todo/webpages-espfs.h b/spritehttpd/todo/webpages-espfs.h similarity index 100% rename from lib/todo/webpages-espfs.h rename to spritehttpd/todo/webpages-espfs.h diff --git a/lib/todo/webpages.espfs.ld b/spritehttpd/todo/webpages.espfs.ld similarity index 100% rename from lib/todo/webpages.espfs.ld rename to spritehttpd/todo/webpages.espfs.ld