diff --git a/CMakeLists.txt b/CMakeLists.txt index 0b3b70a..491077c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,6 +30,9 @@ else() set(CMAKE_BUILD_TYPE RELEASE) endif() +#pthreads +find_package(Threads REQUIRED) + ###### pkgconfig ###### # pkg-config modules (for pkg-check-modules) set(MODULES usefull_macros sqlite3) @@ -62,7 +65,7 @@ add_definitions(${CFLAGS} -DLOCALEDIR=\"${LOCALEDIR}\" -DMAJOR_VERSION=\"${MAJOR_VESION}\") # -l -target_link_libraries(${PROJ} ${${PROJ}_LIBRARIES} -lm) +target_link_libraries(${PROJ} ${${PROJ}_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} -lm) # Installation of the program INSTALL(TARGETS ${PROJ} DESTINATION "bin") diff --git a/Readme b/Readme new file mode 100644 index 0000000..d142608 --- /dev/null +++ b/Readme @@ -0,0 +1,2 @@ +cleaning: +sqlite3 users.db "vacuum;" diff --git a/cmdlnopts.c b/cmdlnopts.c index 158a97c..29bfa8e 100644 --- a/cmdlnopts.c +++ b/cmdlnopts.c @@ -31,6 +31,7 @@ static int help; // global parameters (init with default): glob_pars G = { .port = "8080", + .wsport = "8081", .certfile = "cert.pem", .keyfile = "cert.key", }; @@ -46,7 +47,8 @@ static myoption cmdlnopts[] = { {"dumpusers", NO_ARGS, NULL, 'U', arg_int, APTR(&G.dumpUserDB),_("dump users database")}, {"dumpsess", NO_ARGS, NULL, 'S', arg_int, APTR(&G.dumpSessDB),_("dump session database")}, {"server", NO_ARGS, NULL, 'r', arg_int, APTR(&G.runServer), _("run server process")}, - {"port", NEED_ARG, NULL, 'p', arg_string, APTR(&G.port), _("port to listen")}, + {"port", NEED_ARG, NULL, 'p', arg_string, APTR(&G.port), _("server port to listen")}, + {"wsport", NEED_ARG, NULL, 'P', arg_string, APTR(&G.wsport), _("websocket port to listen (!= server port!)")}, {"certfile",NEED_ARG, NULL, 'c', arg_string, APTR(&G.certfile), _("file with SSL certificate")}, {"keyfile", NEED_ARG, NULL, 'k', arg_string, APTR(&G.keyfile), _("file with SSL key")}, {"usersdb", NEED_ARG, NULL, 'u', arg_string, APTR(&G.usersdb), _("users database filename")}, @@ -55,6 +57,7 @@ static myoption cmdlnopts[] = { {"useradd", NO_ARGS, NULL, 'a', arg_int, APTR(&G.useradd), _("add user[s] interactively")}, {"sdatime", NEED_ARG, NULL, 'A', arg_longlong,APTR(&G.delatime), _("minimal atime to delete sessions from DB (-1 for >year)")}, {"sessdel", NEED_ARG, NULL, 'l', arg_string, APTR(&G.delsession),_("delete session by sessID or sockID")}, + {"logfile", NEED_ARG, NULL, 'L', arg_string, APTR(&G.logfilename),_("log file name")}, end_option }; diff --git a/cmdlnopts.h b/cmdlnopts.h index 3b5d0c3..30afd6a 100644 --- a/cmdlnopts.h +++ b/cmdlnopts.h @@ -31,7 +31,8 @@ typedef struct{ int dumpSessDB; // dump session database int runServer; // run as server int useradd; // add user[s] - char *port; // port to listen + char *port; // server port to listen + char *wsport; // websocket port to listen (!= port !!!) char *certfile; // file with SSL certificate char *keyfile; // file with SSL key char *usersdb; // users database name @@ -39,6 +40,7 @@ typedef struct{ char **userdel; // user names to delete long long delatime; // minimal atime to delete sessions from DB char *delsession; // delete session by sessID or sockID + char *logfilename; // name of log file int rest_pars_num; // number of rest parameters char** rest_pars; // the rest parameters: array of char* } glob_pars; diff --git a/main.c b/main.c index 4bdbe2c..7c29b3b 100644 --- a/main.c +++ b/main.c @@ -32,6 +32,10 @@ #include "auth.h" #include "cmdlnopts.h" +#include "websockets.h" + +// temporary +#define putlog(...) onion_connection_status get(_U_ onion_handler *h, onion_request *req, onion_response *res){ sessinfo *session = qookieSession(req); @@ -52,36 +56,113 @@ onion_connection_status get(_U_ onion_handler *h, onion_request *req, onion_resp return OCS_CLOSE_CONNECTION; } -static onion *o = NULL; +static onion *os = NULL, *ow = NULL; void signals(int signo){ - if(o) onion_free(o); closeSQLite(); + if(os) onion_free(os); + if(ow) onion_free(ow); exit(signo); } -static void runServer(){ - o = onion_new(O_POOL); - if(!(onion_flags(o) & O_SSL_AVAILABLE)){ +// POST/GET server +static void *runPostGet(_U_ void *data){ + os = onion_new(O_THREADED); + if(!(onion_flags(os) & O_SSL_AVAILABLE)){ ONION_ERROR("SSL support is not available"); signals(1); } - int error = onion_set_certificate(o, O_SSL_CERTIFICATE_KEY, G.certfile, G.keyfile); + int error = onion_set_certificate(os, O_SSL_CERTIFICATE_KEY, G.certfile, G.keyfile); if(error){ ONION_ERROR("Cant set certificate and key files (%s, %s)", G.certfile, G.keyfile); signals(1); } - onion_set_port(o, G.port); - onion_url *url = onion_root_url(o); + onion_set_port(os, G.port); + onion_url *url = onion_root_url(os); onion_url_add_handler(url, "^static/", onion_handler_export_local_new("static")); onion_url_add_with_data(url, "", onion_shortcut_internal_redirect, "static/index.html", NULL); onion_url_add(url, "^auth/", auth); onion_url_add(url, "^get/", get); - signal(SIGTERM, signals); - error = onion_listen(o); - if(error){ - ONION_ERROR("Cant create the server: %s", strerror(errno)); + error = onion_listen(os); + if(error) ONION_ERROR("Cant create POST/GET server: %s", strerror(errno)); + onion_free(os); + return NULL; +} + +// Websocket server +static void *runWS(_U_ void *data){ + ow = onion_new(O_THREADED); + if(!(onion_flags(ow) & O_SSL_AVAILABLE)){ + ONION_ERROR("SSL support is not available"); + signals(1); } - onion_free(o); + int error = onion_set_certificate(ow, O_SSL_CERTIFICATE_KEY, G.certfile, G.keyfile); + if(error){ + ONION_ERROR("Cant set certificate and key files (%s, %s)", G.certfile, G.keyfile); + signals(1); + } + onion_set_port(ow, G.wsport); + onion_url *url = onion_root_url(ow); + onion_url_add(url, "", websocket_run); + DBG("Listen websocket"); + error = onion_listen(ow); + if(error) ONION_ERROR("Cant create POST/GET server: %s", strerror(errno)); + onion_free(ow); + return NULL; +} + +static void runServer(){ + // if(G.logfilename) Cl_createlog(); + signal(SIGTERM, signals); + signal(SIGINT, signals); + signal(SIGQUIT, signals); + signal(SIGTSTP, SIG_IGN); + signal(SIGHUP, SIG_IGN); + + pthread_t pg_thread, ws_thread; + if(pthread_create(&pg_thread, NULL, runPostGet, NULL)){ + ERR("pthread_create()"); + } + if(pthread_create(&ws_thread, NULL, runWS, NULL)){ + ERR("pthread_create()"); + } + do{ + if(pthread_kill(pg_thread, 0) == ESRCH){ // POST/GET died + WARNX("POST/GET server thread died"); + putlog("POST/GET server thread died"); + pthread_join(pg_thread, NULL); + if(pthread_create(&pg_thread, NULL, runPostGet, NULL)){ + putlog("pthread_create() failed"); + ERR("pthread_create()"); + } + } + if((pthread_kill(pg_thread, 0) == ESRCH) || (pthread_kill(ws_thread, 0) == ESRCH)){ // died + WARNX("Websocket server thread died"); + putlog("Websocket server thread died"); + pthread_join(ws_thread, NULL); + if(pthread_create(&ws_thread, NULL, runWS, NULL)){ + putlog("pthread_create() failed"); + ERR("pthread_create()"); + } + } +#if 0 + usleep(1000); // sleep a little or thread's won't be able to lock mutex + if(dtime() - tgot < T_INTERVAL) continue; + tgot = dtime(); + /* + * INSERT CODE HERE + * Gather data (poll_device) + */ + // copy temporary buffers to main + pthread_mutex_lock(&mutex); + /* + * INSERT CODE HERE + * fill global data buffers + */ + pthread_mutex_unlock(&mutex); +#endif + }while(1); + putlog("Unreaceable code reached!"); + ERRX("Unreaceable code reached!"); } static char *getl(char *msg, int noempty){ @@ -178,7 +259,10 @@ int main(int argc, char **argv){ if(!deleteOldSessions((int64_t)G.delatime)) green("All sessions with atime<%lld deleted\n", G.delatime); } - if(G.runServer) runServer(); + if(G.runServer){ + if(strcmp(G.port, G.wsport) == 0) ERRX("Server port ans websocket port should be different!"); + runServer(); + } closeSQLite(); return 0; } diff --git a/static/auth.js b/static/auth.js index e161c9e..7aabd33 100644 --- a/static/auth.js +++ b/static/auth.js @@ -10,8 +10,9 @@ auth = function(){ $("inout").onclick = auth.logout; } function _wsk(request){ - var wsKey = request.responseText; + wsKey = request.responseText; if(wsKey) console.log("Web key received: " + wsKey); + wsinit(); } function reqAuth(request){ var txt = request.responseText; @@ -62,10 +63,34 @@ auth = function(){ var str = "auth/?login=" + l + "&passwd=" + p; sendrequest(str, reqAuth); } + // websockets + var ws; + function wsinit(){ + delete(ws); + ws = new WebSocket('wss://localhost:8081'); + ws.onopen = function(){ws.send("Akey="+wsKey);}; // send key after init + ws.onclose = function(evt){ + var text = "WebSocket closed: "; + if(evt.wasClean) text += "by remote side"; + else text += "connection lost" + $('wsmsgs').innerHTML = text; + }; + ws.onmessage = function(evt){ + $('wsmsgs').innerHTML = evt.data; + } + ws.onerror = function(err){ + parseErr("WebSocket error " + err.message); + } + } + function wssend(txt){ + ws.send(txt); + } return{ init: init1, login: login1, logout: logout1, - send: sendlogpass + send: sendlogpass, + wssend: wssend, + wsinit: wsinit }; }(); diff --git a/static/index.html b/static/index.html index 6f3dc2c..625c76a 100644 --- a/static/index.html +++ b/static/index.html @@ -7,7 +7,11 @@
Text
More text +
+
++