diff --git a/.gitignore b/.gitignore index 1e1bd5f..427dda9 100644 --- a/.gitignore +++ b/.gitignore @@ -34,3 +34,5 @@ tmp/* bin/* +pkg/* + diff --git a/dist/uce_0.1.1.deb b/dist/uce_0.1.1.deb new file mode 100644 index 0000000..5fa24f9 Binary files /dev/null and b/dist/uce_0.1.1.deb differ diff --git a/build_linux.sh b/scripts/build_linux.sh similarity index 80% rename from build_linux.sh rename to scripts/build_linux.sh index 5ebb078..7f0cc9c 100755 --- a/build_linux.sh +++ b/scripts/build_linux.sh @@ -1,15 +1,11 @@ #!/bin/bash cd "$(dirname "$0")" +cd .. BUILDMODE=${2:-"debug"} -OPT_FLAG="O2" +OPT_FLAG="O3" GF="uce_fastcgi" -if [ "$BUILDMODE" == "debug" ]; then - OPT_FLAG="O0" -fi -echo "Build mode: $BUILDMODE" - mkdir bin > /dev/null 2>&1 mkdir bin/tmp > /dev/null 2>&1 mkdir bin/assets > /dev/null 2>&1 @@ -22,7 +18,7 @@ LIBS="-ldl -lm -lpthread `mysql_config --cflags --libs`" SRCFLAGS="-D EXEC_NAME=\"$GF\" -D PLATFORM_NAME=\"linux\"" echo "Compliling executable..." -time -p $COMPILER src/linux_fastcgi.cpp $SRCFLAGS $FLAGS $LIBS -o bin/$GF.$BUILDMODE.linux.bin 2>&1 +time -p $COMPILER src/linux_fastcgi.cpp $SRCFLAGS $FLAGS $LIBS -o bin/$GF.linux.bin 2>&1 if [ $? -eq 0 ] then diff --git a/scripts/compile b/scripts/compile index 0fba5f6..f828412 100755 --- a/scripts/compile +++ b/scripts/compile @@ -28,7 +28,7 @@ COMPILER="clang++" #COMPILER="g++" FLAGS="-shared -g -rdynamic -w -Wall -$OPT_FLAG -std=c++14 -fpermissive -ffast-math -fPIC" -LIBS="-ldl -lm -lpthread " +LIBS="-ldl -lm -lpthread" SRCFLAGS="-D PLATFORM_NAME=\"linux\"" # echo "Compliling executable..." diff --git a/scripts/control b/scripts/control new file mode 100644 index 0000000..fa9ece3 --- /dev/null +++ b/scripts/control @@ -0,0 +1,7 @@ +Package: uce +Section: web +Priority: optional +Architecture: amd64 +Depends: clang (>= 1:13.0) +Maintainer: Udo Schroeter +Description: Write server-side web stuff in C++ diff --git a/scripts/make_deb.sh b/scripts/make_deb.sh new file mode 100755 index 0000000..e12c549 --- /dev/null +++ b/scripts/make_deb.sh @@ -0,0 +1,45 @@ +#!/bin/bash +cd "$(dirname "$0")" +cd .. + +if [ -z "$1" ] + then + echo "Usage: make_deb.sh VERSION" + exit +fi + +VERSION=$1 +REV=1 +PROJECT="uce" + +PKG_NAME="${PROJECT}_$VERSION.$REV" + +echo "Making package $PKG_NAME" +echo "===================================" + +scripts/build_linux.sh + +rm -r "pkg/$PKG_NAME" +mkdir -p "pkg/$PKG_NAME/opt/uce/" +mkdir -p "pkg/$PKG_NAME/DEBIAN/" +mkdir -p "pkg/$PKG_NAME/etc/uce/" +mkdir -p "dist" + +cp scripts/control "pkg/$PKG_NAME/DEBIAN/" +echo "Version: $VERSION" >> "pkg/$PKG_NAME/DEBIAN/control" +echo "" >> "pkg/$PKG_NAME/DEBIAN/control" + +cp -r bin "pkg/$PKG_NAME/opt/" +cp -r doc "pkg/$PKG_NAME/opt/" +cp -r examples "pkg/$PKG_NAME/opt/" +cp -r scripts "pkg/$PKG_NAME/opt/" +cp -r test "pkg/$PKG_NAME/opt/" + +du -sh "pkg/$PKG_NAME/"* + +cd pkg +dpkg-deb --build "$PKG_NAME" +mv "$PKG_NAME.deb" "../dist/" +cd .. + +ls -lh "dist/" | grep "$PKG_NAME" diff --git a/scripts/start.sh b/scripts/start.sh new file mode 100755 index 0000000..9b00dcd --- /dev/null +++ b/scripts/start.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +rm -r /tmp/uce/work/* ; scripts/build_linux.sh && bin/uce_fastcgi.linux.bin diff --git a/src/lib/compiler.cpp b/src/lib/compiler.cpp index 4be7395..b96c2bd 100644 --- a/src/lib/compiler.cpp +++ b/src/lib/compiler.cpp @@ -201,8 +201,8 @@ void setup_unit_paths(Request* context, SharedUnit* su, String file_name) return; su->src_path = dirname(file_name); - su->bin_path = context->server->config.BIN_DIRECTORY + su->src_path; - su->pre_path = context->server->config.BIN_DIRECTORY + su->src_path; + su->bin_path = context->server->config["BIN_DIRECTORY"] + su->src_path; + su->pre_path = context->server->config["BIN_DIRECTORY"] + su->src_path; su->src_file_name = basename(file_name); su->bin_file_name = su->src_file_name + ".so"; @@ -253,8 +253,8 @@ String compile_setup_file(Request* context, SharedUnit* su) String result = String("#ifndef UCE_LIB_INCLUDED\n") + "#define UCE_LIB_INCLUDED\n" + - ("#include \"")+context->server->config.COMPILER_SYS_PATH +"/src/lib/uce_lib.h\" \n"+ - file_get_contents(context->server->config.COMPILER_SYS_PATH + "/" + context->server->config.SETUP_TEMPLATE) + + ("#include \"")+context->server->config["COMPILER_SYS_PATH"] +"/src/lib/uce_lib.h\" \n"+ + file_get_contents(context->server->config["COMPILER_SYS_PATH"] + "/" + context->server->config["SETUP_TEMPLATE"]) + "#endif \n"; StringList declarations; StringList load_units; @@ -279,10 +279,8 @@ void compile_shared_unit(Request* context, SharedUnit* su, String file_name) file_put_contents(su->setup_file_name, compile_setup_file(context, su)); file_put_contents(su->api_file_name, join(su->api_declarations, "\n")); - //printf("Config.COMPILE_SCRIPT %s\n", String(su->pre_path + "/" + su->pre_file_name).c_str()); - if(!su->opt_so_optional) - su->compiler_messages = trim(shell_exec(context->server->config.COMPILE_SCRIPT+" "+ + su->compiler_messages = trim(shell_exec(context->server->config["COMPILE_SCRIPT"]+" "+ shell_escape(su->src_path)+" "+ shell_escape(su->bin_path)+" "+ shell_escape(su->file_name)+" "+ diff --git a/src/lib/functionlib.cpp b/src/lib/functionlib.cpp index fb2d63b..a97a207 100644 --- a/src/lib/functionlib.cpp +++ b/src/lib/functionlib.cpp @@ -140,6 +140,41 @@ StringList split(String str, String delim) return(result); } +StringMap split_kv(String s, char separator, bool trim_whitespace) +{ + StringMap result; + String k; + String v; + for(auto s : split(s, "\n")) + { + u8 mode = 0; + k = ""; + v = ""; + for(auto c : s) + { + if(mode == 0) + { + if(c == separator) + mode = 1; + else + k.append(1, c); + } + else + { + v.append(1, c); + } + } + if(k != "") + { + if(trim_whitespace) + result[trim(k)] = trim(v); + else + result[k] = v; + } + } + return(result); +} + String join(StringList l, String delim) { String result; diff --git a/src/lib/functionlib.h b/src/lib/functionlib.h index 857d9c4..436bc55 100644 --- a/src/lib/functionlib.h +++ b/src/lib/functionlib.h @@ -10,6 +10,7 @@ String trim(String raw); StringList split_space(String str); StringList split(String str, String delim); StringList split_utf8(String s, bool compound_characters = false); +StringMap split_kv(String s, char separator = '=', bool trim_whitespace = true); String join(StringList l, String delim = "\n"); String nibble(String& haystack, String delim); void json_consume_space(String s, u32& i); diff --git a/src/lib/sys.cpp b/src/lib/sys.cpp index 050e095..ae2d66c 100644 --- a/src/lib/sys.cpp +++ b/src/lib/sys.cpp @@ -440,7 +440,7 @@ void spawn_subprocess(std::function exec_after_spawn) pid_t task_pid(String key) { - String status_file_name = context->server->config.BIN_DIRECTORY + "/task-" + key; + String status_file_name = context->server->config["BIN_DIRECTORY"] + "/task-" + key; String status_file = file_get_contents(status_file_name); pid_t p = 0; if(status_file != "") @@ -455,7 +455,7 @@ pid_t task_pid(String key) pid_t task(String key, std::function exec_after_spawn, u64 timeout) { - String status_file_name = context->server->config.BIN_DIRECTORY + "/task-" + key; + String status_file_name = context->server->config["BIN_DIRECTORY"] + "/task-" + key; String status_file = file_get_contents(status_file_name); pid_t p; if(status_file != "") @@ -510,3 +510,31 @@ StringList ls(String dir) { return(split(trim(shell_exec("ls -1 "+shell_escape(dir))), "\n")); } + +StringMap make_server_settings() +{ + StringMap cfg; + + cfg["BIN_DIRECTORY"] = "/tmp/uce/work"; + cfg["COMPILE_SCRIPT"] = "scripts/compile"; + cfg["SETUP_TEMPLATE"] = "scripts/setup.h.template"; + cfg["LIT_ESC"] = "3d5b5_1"; + cfg["CONTENT_TYPE"] = "text/html; charset=utf-8"; + cfg["SOCKET_PATH"] = "/run/uce.sock"; + cfg["TMP_UPLOAD_PATH"] = "/tmp/uce/uploads"; + cfg["SESSION_PATH"] = "/tmp/uce/sessions"; + cfg["COMPILER_SYS_PATH"] = "."; + cfg["PRECOMPILE_FILES_IN"] = "."; + + cfg["LISTEN_PORT"] = std::to_string(9993); + cfg["SESSION_TIME"] = std::to_string(60*60*24*30); + cfg["WORKER_COUNT"] = std::to_string(4); + cfg["MAX_MEMORY"] = std::to_string(1024*1024*16); + + for(auto& it : split_kv(file_get_contents("/etc/uce/settings.cfg"))) + { + cfg[it.first] = it.second; + } + + return(cfg); +} diff --git a/src/lib/types.cpp b/src/lib/types.cpp index 855c8e4..ef97efa 100644 --- a/src/lib/types.cpp +++ b/src/lib/types.cpp @@ -39,20 +39,6 @@ String nibble(String div, String& haystack) } } -/* -void Request::invoke(String file_name) -{ - DTree call_param; - compiler_invoke(this, file_name, call_param); -} - -void Request::invoke(String file_name, DTree& call_param) -{ - compiler_invoke(this, file_name, call_param); -} - -*/ - void Request::ob_start() { ob_stack.push_back(new std::ostringstream()); diff --git a/src/lib/types.h b/src/lib/types.h index 732a6ba..04f848b 100644 --- a/src/lib/types.h +++ b/src/lib/types.h @@ -146,7 +146,7 @@ typedef void (*request_handler)(Request* request); String to_string(s64 v) { return(std::to_string(v)); } -struct ServerSettings { +/*struct ServerSettings { String BIN_DIRECTORY = "/tmp/uce/work"; String COMPILE_SCRIPT = "scripts/compile"; @@ -164,7 +164,7 @@ struct ServerSettings { u32 WORKER_COUNT = 4; u32 MAX_MEMORY = 1024*1024*16; -}; +};*/ struct SharedUnit { @@ -204,7 +204,7 @@ struct UploadedFile { struct ServerState { std::map units; - ServerSettings config; + StringMap config; u32 request_count = 0; }; diff --git a/src/lib/uri.cpp b/src/lib/uri.cpp index 8f258c4..75a1572 100644 --- a/src/lib/uri.cpp +++ b/src/lib/uri.cpp @@ -124,7 +124,7 @@ StringMap parse_multipart(String q, String boundary, std::vector& { nibble("=\"", field); UploadedFile f; - f.tmp_name = context->server->config.TMP_UPLOAD_PATH + std::to_string(rand()); + f.tmp_name = context->server->config["TMP_UPLOAD_PATH"] + std::to_string(rand()); f.file_name = nibble("\"", field); String bin = field.substr(4, field.length()-6); f.size = bin.length(); @@ -289,19 +289,19 @@ String make_session_id() StringMap load_session_data(String session_id) { - return(parse_query(file_get_contents(context->server->config.SESSION_PATH + "/" + session_id))); + return(parse_query(file_get_contents(context->server->config["SESSION_PATH"] + "/" + session_id))); } void save_session_data(String session_id, StringMap data) { - file_put_contents(context->server->config.SESSION_PATH + "/" + session_id, encode_query(data)); + file_put_contents(context->server->config["SESSION_PATH"] + "/" + session_id, encode_query(data)); } String session_start(String session_name) { if(context->cookies[session_name].length() == 0) { - set_cookie(session_name, make_session_id(), time() + context->server->config.SESSION_TIME); + set_cookie(session_name, make_session_id(), time() + int_val(context->server->config["SESSION_TIME"])); } context->session_id = context->cookies[session_name]; context->session_name = session_name; @@ -313,7 +313,7 @@ void session_destroy(String session_name) { if(context->cookies[session_name].length() > 0) { - set_cookie(session_name, "", time() - context->server->config.SESSION_TIME); + set_cookie(session_name, "", time() - int_val(context->server->config["SESSION_TIME"])); context->session.clear(); save_session_data(context->session_id, context->session); context->session_id = ""; diff --git a/src/linux_fastcgi.cpp b/src/linux_fastcgi.cpp index d16d7a3..7c7b597 100644 --- a/src/linux_fastcgi.cpp +++ b/src/linux_fastcgi.cpp @@ -1,7 +1,7 @@ #include "lib/uce_lib.cpp" ServerState server_state; -MemoryArena* request_arena = new MemoryArena(server_state.config.MAX_MEMORY, "request"); +MemoryArena* request_arena = 0; #include "fastcgi/src/fcgicc.cc" @@ -44,7 +44,7 @@ int handle_complete(FastCGIRequest& request) { server_state.request_count += 1; request.server = &server_state; request.stats.time_start = microtime(); - request.header["Content-Type"] = context->server->config.CONTENT_TYPE; + request.header["Content-Type"] = context->server->config["CONTENT_TYPE"]; request.get = parse_query(request.params["QUERY_STRING"]); request.random_index = 0; request.random_seed = gen_noise64(*reinterpret_cast(&request.stats.time_start)); @@ -115,66 +115,68 @@ void listen_for_connections() } } +void init_base_process() +{ + printf("(P) Starting parent server PID:%i\n", getpid()); + + server_state.config = make_server_settings(); + server_state.config["COMPILER_SYS_PATH"] = get_cwd(); + printf("Compiler base path: %s\n", server_state.config["COMPILER_SYS_PATH"].c_str()); + + server_state.config["COMPILE_SCRIPT"] = + server_state.config["COMPILER_SYS_PATH"] + "/" + server_state.config["COMPILE_SCRIPT"]; + if(server_state.config["LISTEN_PORT"] != "") + server.listen(int_val(server_state.config["LISTEN_PORT"])); + + printf("%s\n", var_dump(server_state.config).c_str()); + + if(server_state.config["SOCKET_PATH"] != "") + { + server.listen(server_state.config["SOCKET_PATH"]); + chmod(server_state.config["SOCKET_PATH"].c_str(), S_IRWXU | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); + } + + //dirname(server_state.config.COMPILER_SYS_PATH); + //basename(server_state.config.COMPILER_SYS_PATH); + + mkdir(server_state.config["BIN_DIRECTORY"]); + mkdir(server_state.config["TMP_UPLOAD_PATH"]); + mkdir(server_state.config["SESSION_PATH"]); + + request_arena = new MemoryArena(int_val(server_state.config["MAX_MEMORY"]), "request"); + signal(SIGCHLD, on_child_exit); + srand(time()); +} + +StringList init_precompile(u32& precompile_jobs_per_worker) +{ + StringList precompile_jobs_pending; + if(server_state.config["PRECOMPILE_FILES_IN"] != "" && int_val(server_state.config["WORKER_COUNT"]) >= 2) + { + if(server_state.config["PRECOMPILE_FILES_IN"][0] != '/') + server_state.config["PRECOMPILE_FILES_IN"] = expand_path(server_state.config["PRECOMPILE_FILES_IN"]); + precompile_jobs_pending = split(trim(shell_exec( + "find " + + shell_escape(server_state.config["PRECOMPILE_FILES_IN"]) + + " -iname '*.uce' ")), "\n"); + precompile_jobs_per_worker = 1 + (precompile_jobs_pending.size() / (int_val(server_state.config["WORKER_COUNT"]) -1)); + } + return(precompile_jobs_pending); +} + int main(int argc, char** argv) { StringList precompile_jobs_pending; u32 precompile_jobs_per_worker = 1; - printf("(P) Starting parent server PID:%i\n", getpid()); - - signal(SIGCHLD, on_child_exit); - srand(time()); - - //if(server_state.config.COMPILER_SYS_PATH == "") - server_state.config.COMPILER_SYS_PATH = get_cwd(); - - // printf("MySQL client version: %s\n", mysql_get_client_info()); - - printf("Compiler base path: %s\n", server_state.config.COMPILER_SYS_PATH.c_str()); - - server_state.config.COMPILE_SCRIPT = - server_state.config.COMPILER_SYS_PATH + "/" + server_state.config.COMPILE_SCRIPT; - if(server_state.config.LISTEN_PORT) - server.listen(server_state.config.LISTEN_PORT); - if(server_state.config.SOCKET_PATH != "") - server.listen(server_state.config.SOCKET_PATH); - chmod(server_state.config.SOCKET_PATH.c_str(), S_IRWXU | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); - - dirname(server_state.config.COMPILER_SYS_PATH); - basename(server_state.config.COMPILER_SYS_PATH); - - mkdir(server_state.config.BIN_DIRECTORY); - mkdir(server_state.config.TMP_UPLOAD_PATH); - mkdir(server_state.config.SESSION_PATH); - - //server.process(100); - //server.process(); - /*try - { - server.process_forever(); - } - catch (const std::runtime_error& e) - { - std::cout << e.what(); - }*/ - if(server_state.config.PRECOMPILE_FILES_IN != "" && server_state.config.WORKER_COUNT >= 2) - { - if(server_state.config.PRECOMPILE_FILES_IN != "/") - server_state.config.PRECOMPILE_FILES_IN = expand_path(server_state.config.PRECOMPILE_FILES_IN); - precompile_jobs_pending = split(trim(shell_exec( - "find " + - shell_escape(server_state.config.PRECOMPILE_FILES_IN) + - " -iname '*.uce' ")), "\n"); - precompile_jobs_per_worker = 1 + (precompile_jobs_pending.size() / (server_state.config.WORKER_COUNT -1)); - /* - */ - } + init_base_process(); + precompile_jobs_pending = init_precompile(precompile_jobs_per_worker); s32 worker_spawn_count = 0; for(;;) { - while(workers.size() < server_state.config.WORKER_COUNT) + while(workers.size() < int_val(server_state.config["WORKER_COUNT"])) { worker_spawn_count++; precompile_jobs.clear(); diff --git a/start.sh b/start.sh deleted file mode 100755 index 1c10d67..0000000 --- a/start.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -rm -r /tmp/uce/work/* ; ./build_linux.sh && bin/uce_fastcgi.debug.linux.bin