├── logs └── .logs_here ├── res └── wait.gif ├── src ├── silgy.bat ├── t.bat ├── silgy ├── m.bat ├── m_vc.bat ├── m ├── silgy_app.h ├── silgy_svc.cpp └── silgy_app.cpp ├── README.md ├── bin ├── silgystart ├── silgystop └── silgydep ├── resmin ├── silgy.css ├── style.css └── silgy.js ├── LICENSE └── lib ├── users.sql ├── silgy_watcher.c ├── silgy_usr.h ├── silgy_lib.h └── silgy.h /logs/.logs_here: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /res/wait.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rekmus/IoT_configurator/master/res/wait.gif -------------------------------------------------------------------------------- /src/silgy.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | set SILGYDIR=.. 4 | 5 | ..\bin\silgy_app 8080 6 | -------------------------------------------------------------------------------- /src/t.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | set SILGYDIR=.. 4 | 5 | ..\bin\silgy_app 8080 6 | -------------------------------------------------------------------------------- /src/silgy: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | export SILGYDIR=.. 4 | 5 | $SILGYDIR/bin/silgy_app 8080 6 | -------------------------------------------------------------------------------- /src/m.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | echo Making silgy_app... 4 | 5 | g++ silgy_app.cpp ^ 6 | ..\lib\silgy_eng.c ..\lib\silgy_lib.c ..\lib\silgy_usr.c ^ 7 | -I . -I ..\lib ^ 8 | -lws2_32 -lpsapi ^ 9 | -s -O3 ^ 10 | -o ..\bin\silgy_app ^ 11 | -static 12 | -------------------------------------------------------------------------------- /src/m_vc.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | echo Making silgy_app using Microsoft compiler... 4 | 5 | cl silgy_app.cpp ^ 6 | ..\lib\silgy_eng.c ..\lib\silgy_lib.c ..\lib\silgy_usr.c ^ 7 | /EHsc ^ 8 | -I . -I ..\lib ^ 9 | /Fe..\bin\silgy_app 10 | 11 | echo. 12 | 13 | echo Make sure you have dirent.h from https://github.com/tronkko/dirent/tree/master/include 14 | 15 | echo Remember to set the environment with vcvars32 (path: C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin) 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This is a self-contained web application allowing browser access to your IoT device. 2 | 3 | It stores configuration in a single JSON file. Its path is in `silgy_app.h`. 4 | 5 | It should take about 9 MB of memory and less than 0.1% of the CPU time. 6 | 7 | Settings list is defined in `M_settings` array at the top of `silgy_app.cpp`. 8 | 9 | Authentication is based on clear-text password stored in a configuration file. User name is not checked, however you can easily add the check in `do_login()`. 10 | 11 | Random, at least 8 character long password should be generated for each device and written into initial configuration. 12 | -------------------------------------------------------------------------------- /src/m: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | 4 | echo Making silgy_app... 5 | 6 | g++ silgy_app.cpp \ 7 | ../lib/silgy_eng.c ../lib/silgy_lib.c ../lib/silgy_usr.c \ 8 | -I. -I../lib \ 9 | -lrt -lz \ 10 | -s -O3 \ 11 | -o ../bin/silgy_app 12 | 13 | 14 | echo Making silgy_svc... 15 | 16 | g++ silgy_svc.cpp \ 17 | ../lib/silgy_eng.c ../lib/silgy_lib.c ../lib/silgy_usr.c \ 18 | -D SILGY_SVC \ 19 | -I. -I../lib \ 20 | -lrt \ 21 | -s -O3 \ 22 | -o ../bin/silgy_svc 23 | 24 | 25 | echo Making silgy_watcher... 26 | 27 | gcc ../lib/silgy_watcher.c \ 28 | ../lib/silgy_lib.c \ 29 | -D SILGY_WATCHER \ 30 | -I. -I../lib \ 31 | -s -O3 \ 32 | -o ../bin/silgy_watcher 33 | -------------------------------------------------------------------------------- /bin/silgystart: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | export SILGYDIR=/home/ec2-user/live 4 | 5 | export SILGY_SVC_PROCESSES=0 6 | 7 | # --------------------------------------------------------------------- 8 | 9 | echo "Starting Silgy App..." 10 | 11 | # --------------------------------------------------------------------- 12 | # Main app 13 | 14 | nohup $SILGYDIR/bin/silgy_app > /dev/null 2>&1 & 15 | 16 | sleep 1 17 | 18 | # --------------------------------------------------------------------- 19 | # Services 20 | 21 | for i in `seq 1 $SILGY_SVC_PROCESSES` 22 | do 23 | nohup $SILGYDIR/bin/silgy_svc > /dev/null 2>&1 & 24 | done 25 | 26 | sleep 1 # return to prompt 27 | -------------------------------------------------------------------------------- /bin/silgystop: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | export SILGYDIR=/home/ec2-user/live 4 | 5 | # --------------------------------------------------------------------- 6 | 7 | echo "Stopping Silgy App..." 8 | 9 | # --------------------------------------------------------------------- 10 | # Services 11 | 12 | if [ -n "$(find $SILGYDIR/bin -name 's_*.pid' | head -1)" ] 13 | then 14 | for f in $SILGYDIR/bin/s_*.pid 15 | do 16 | kill `cat ${f}` 17 | done 18 | 19 | sleep 1 20 | fi 21 | 22 | # --------------------------------------------------------------------- 23 | # Main app 24 | 25 | if [ -f $SILGYDIR/bin/silgy_app.pid ] 26 | then 27 | kill `cat $SILGYDIR/bin/silgy_app.pid` 28 | fi 29 | 30 | # --------------------------------------------------------------------- 31 | -------------------------------------------------------------------------------- /resmin/silgy.css: -------------------------------------------------------------------------------- 1 | // ---------------------------------------- 2 | // wait animation 3 | .wt 4 | { 5 | display: none; 6 | position: fixed; 7 | top: 0; 8 | left: 0; 9 | width: 100%; 10 | height: 100%; 11 | z-index: 900; 12 | background: url(wait.gif) 50% 50% no-repeat; 13 | background-size: 52px; 14 | } 15 | 16 | 17 | // ---------------------------------------- 18 | // modal window 19 | .mw 20 | { 21 | font-size: 12pt; 22 | background-color: white; 23 | padding: 3px 12px 13px 14px; 24 | box-shadow: 4px 4px 16px 0px rgba(0,0,0,0.2); 25 | border: 1px solid #bbbbbb; 26 | z-index: 1000; 27 | } 28 | 29 | 30 | // ---------------------------------------- 31 | // yes/no buttons 32 | .ynb 33 | { 34 | width: 80px; 35 | height: 32px; 36 | margin-top: 20px; 37 | } 38 | -------------------------------------------------------------------------------- /bin/silgydep: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | export SILGYDEV=/home/ec2-user/dev 4 | export SILGYLIVE=/home/ec2-user/live 5 | 6 | # --------------------------------------------------------------------- 7 | 8 | echo "Deploying new Silgy App..." 9 | 10 | # --------------------------------------------------------------------- 11 | 12 | cp -p $SILGYDEV/bin/silgy_app $SILGYLIVE/bin 13 | cp -p $SILGYDEV/bin/silgy_svc $SILGYLIVE/bin 14 | cp -p $SILGYDEV/bin/silgy_watcher $SILGYLIVE/bin 15 | cp -p $SILGYDEV/bin/silgydep $SILGYLIVE/bin 16 | cp -p $SILGYDEV/bin/silgystart $SILGYLIVE/bin 17 | cp -p $SILGYDEV/bin/silgystop $SILGYLIVE/bin 18 | cp -p $SILGYDEV/bin/strings.* $SILGYLIVE/bin 2>/dev/null 19 | cp -p $SILGYDEV/bin/passwords.* $SILGYLIVE/bin 2>/dev/null 20 | 21 | cp -pr $SILGYDEV/res/* $SILGYLIVE/res 2>/dev/null 22 | cp -pr $SILGYDEV/resmin/* $SILGYLIVE/resmin 2>/dev/null 23 | cp -pr $SILGYDEV/snippets/* $SILGYLIVE/snippets 2>/dev/null 24 | -------------------------------------------------------------------------------- /resmin/style.css: -------------------------------------------------------------------------------- 1 | input[type="date"]::-webkit-inner-spin-button{display:none;}::-webkit-clear-button{display:none;} 2 | input[type="number"]::-webkit-inner-spin-button{display:none;} 3 | 4 | .m05 {margin-top:0.5em;} 5 | .m10 {margin-top:1em;} 6 | .m15 {margin-top:1.5em;} 7 | .m20 {margin-top:2em;} 8 | .m25 {margin-top:2.5em;} 9 | .m30 {margin-top:3em;} 10 | .m40 {margin-top:4em;} 11 | .m50 {margin-top:5em;} 12 | .ct {text-align:center;} 13 | .rt {text-align:right;} 14 | .red {color:#b40000;} 15 | .ylw {color:#b09000;} 16 | .grn {color:#00a000;} 17 | .msg {color:#b40000; margin-bottom:12px; display:none; border:1px solid #b40000; padding:6px 10px;} 18 | .brd {margin-left:25%; length:50%; margin-right:25%; border:1px solid black; padding:6px 10px;} 19 | .brd_red {margin-left:25%; length:50%; margin-right:25%; border:1px solid #b40000; padding:6px 10px;} 20 | .brd_ylw {margin-left:25%; length:50%; margin-right:25%; border:1px solid #b09000; padding:6px 10px;} 21 | .brd_grn {margin-left:25%; length:50%; margin-right:25%; border:1px solid #00a000; padding:6px 10px;} 22 | .w100p {width:100%;} 23 | .pt {padding-top: 8px;} 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Jurek Muszynski 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/silgy_app.h: -------------------------------------------------------------------------------- 1 | /* -------------------------------------------------------------------------- 2 | Silgy Web App 3 | Jurek Muszynski 4 | silgy.com 5 | ----------------------------------------------------------------------------- 6 | Device configuration example 7 | Extra care for limited resources 8 | -------------------------------------------------------------------------- */ 9 | 10 | #ifndef SILGY_APP_H 11 | #define SILGY_APP_H 12 | 13 | 14 | #define APP_WEBSITE "Device Configurator" 15 | #define APP_DOMAIN "example.com" 16 | 17 | #define DEF_RES_AUTH_LEVEL AUTH_LEVEL_ANONYMOUS 18 | 19 | #define MEM_TINY 20 | #define ASYNC_EXCLUDE_AUSES 21 | 22 | #define DUMP 23 | 24 | 25 | #define SETTINGS_FILE "/cpp/iot/settings.json" 26 | #define PASSWORD_FILE "/cpp/iot/passwd.txt" 27 | 28 | 29 | #define MSG_SETTINGS_SAVED 1201 30 | 31 | 32 | #define PASSWORD_LEN 255 33 | #define SET_STRING1_LEN 255 34 | 35 | 36 | 37 | /* app user session */ 38 | 39 | typedef struct { 40 | char login[LOGIN_LEN+1]; 41 | char password[PASSWORD_LEN+1]; 42 | bool authenticated; 43 | } ausession_t; 44 | 45 | 46 | #endif /* SILGY_APP_H */ 47 | -------------------------------------------------------------------------------- /src/silgy_svc.cpp: -------------------------------------------------------------------------------- 1 | /* -------------------------------------------------------------------------- 2 | Silgy Web App 3 | Jurek Muszynski 4 | silgy.com 5 | ----------------------------------------------------------------------------- 6 | Sample service module 7 | -------------------------------------------------------------------------- */ 8 | 9 | 10 | #include 11 | 12 | 13 | /* ======================================================================= */ 14 | /* =============================== SERVICES ============================== */ 15 | /* ======================================================================= */ 16 | 17 | 18 | /* -------------------------------------------------------------------------- 19 | Service 20 | -------------------------------------------------------------------------- */ 21 | void getCustomer(int ci) 22 | { 23 | OUT_HTML_HEADER; 24 | OUT("

%s

", APP_WEBSITE); 25 | OUT("

Hello from getCustomer service!

"); 26 | OUT_HTML_FOOTER; 27 | } 28 | 29 | 30 | /* -------------------------------------------------------------------------- 31 | Service 32 | -------------------------------------------------------------------------- */ 33 | void getAccounts(int ci) 34 | { 35 | OUT_HTML_HEADER; 36 | OUT("

%s

", APP_WEBSITE); 37 | OUT("

Hello from getAccounts service!

"); 38 | OUT_HTML_FOOTER; 39 | } 40 | 41 | 42 | /* ======================================================================= */ 43 | /* ========================== END OF SERVICES ============================ */ 44 | /* ======================================================================= */ 45 | 46 | 47 | 48 | /* -------------------------------------------------------------------------- 49 | Entry point 50 | -------------------------------------------------------------------------- */ 51 | void silgy_svc_main(int ci) 52 | { 53 | if ( SVC("getCustomer") ) 54 | getCustomer(ci); 55 | else if ( SVC("getAccounts") ) 56 | getAccounts(ci); 57 | } 58 | 59 | 60 | /* -------------------------------------------------------------------------- 61 | Server start 62 | Return true if successful 63 | -------------------------------------------------------------------------- */ 64 | bool silgy_svc_init() 65 | { 66 | return true; 67 | } 68 | 69 | 70 | /* -------------------------------------------------------------------------- 71 | Server stop 72 | -------------------------------------------------------------------------- */ 73 | void silgy_svc_done() 74 | { 75 | } 76 | -------------------------------------------------------------------------------- /lib/users.sql: -------------------------------------------------------------------------------- 1 | -- ---------------------------------------------------------------------------- 2 | -- Silgy user tables -- MySQL version 3 | -- ---------------------------------------------------------------------------- 4 | 5 | -- users 6 | 7 | create table users ( 8 | id int auto_increment primary key, 9 | login char(30), 10 | login_u char(30), -- uppercase version 11 | email char(120), 12 | email_u char(120), -- uppercase version 13 | name varchar(120), 14 | phone varchar(30), 15 | passwd1 char(30), -- base64 of SHA1 hash 16 | passwd2 char(30), -- base64 of SHA1 hash 17 | lang char(5), 18 | tz char(5), 19 | about varchar(250), 20 | avatar_name varchar(60), 21 | avatar_data blob, -- 64 kB 22 | group_id int, 23 | auth_level tinyint, -- 10 = user, 20 = customer, 30 = staff, 40 = moderator, 50 = admin, 100 = root 24 | status tinyint, -- 0 = inactive, 1 = active, 2 = locked, 3 = requires password change, 9 = deleted 25 | created datetime, 26 | last_login datetime, 27 | visits int, 28 | ula_cnt int, -- unsuccessful login attempt count 29 | ula_time datetime -- and time 30 | ); 31 | 32 | create index users_login on users (login_u); 33 | create index users_email on users (email_u); 34 | create index users_last_login on users (last_login); 35 | 36 | 37 | -- groups 38 | 39 | create table users_groups ( 40 | id int auto_increment primary key, 41 | name varchar(120), 42 | about varchar(250), 43 | auth_level tinyint 44 | ); 45 | 46 | 47 | -- user settings 48 | 49 | create table users_settings ( 50 | user_id int, 51 | us_key char(30), 52 | us_val varchar(250), 53 | primary key (user_id, us_key) 54 | ); 55 | 56 | 57 | -- user logins 58 | 59 | create table users_logins ( 60 | sesid char(15) primary key, 61 | uagent varchar(250), 62 | ip char(15), 63 | user_id int, 64 | csrft char(7), 65 | created datetime, 66 | last_used datetime 67 | ); 68 | 69 | create index users_logins_uid on users_logins (user_id); 70 | 71 | 72 | -- account activations 73 | 74 | create table users_activations ( 75 | linkkey char(30) primary key, 76 | user_id int, 77 | created datetime, 78 | activated datetime 79 | ); 80 | 81 | 82 | -- password resets 83 | 84 | create table users_p_resets ( 85 | linkkey char(20) primary key, 86 | user_id int, 87 | created datetime, 88 | tries smallint 89 | ); 90 | 91 | create index users_p_resets_uid on users_p_resets (user_id); 92 | 93 | 94 | -- messages 95 | 96 | create table users_messages ( 97 | user_id int, 98 | msg_id int, 99 | email varchar(120), 100 | message text, -- 64 kB limit 101 | created datetime, 102 | primary key (user_id, msg_id) 103 | ); 104 | -------------------------------------------------------------------------------- /lib/silgy_watcher.c: -------------------------------------------------------------------------------- 1 | /* -------------------------------------------------------------------------- 2 | Restart Silgy app if dead 3 | Jurek Muszynski 4 | -------------------------------------------------------------------------- */ 5 | 6 | 7 | #include "silgy.h" 8 | 9 | 10 | #define STOP_COMMAND "$SILGYDIR/bin/silgystop" 11 | #define START_COMMAND "$SILGYDIR/bin/silgystart" 12 | 13 | 14 | int G_httpPort; 15 | bool G_initialized=0; 16 | 17 | 18 | static char M_watcherStopCmd[256]; 19 | static char M_watcherStartCmd[256]; 20 | static int M_watcherWait; 21 | static int M_watcherLogRestart; 22 | 23 | 24 | /* -------------------------------------------------------------------------- 25 | Restart 26 | -------------------------------------------------------------------------- */ 27 | static void restart() 28 | { 29 | if ( M_watcherLogRestart > 0 ) 30 | { 31 | G_logLevel = M_watcherLogRestart; 32 | log_start("watcher", FALSE); 33 | } 34 | 35 | ALWAYS_T("Restarting..."); 36 | 37 | INF_T("Stopping..."); 38 | INF_T(M_watcherStopCmd); 39 | system(M_watcherStopCmd); 40 | 41 | lib_update_time_globals(); 42 | 43 | INF_T("Waiting %d second(s)...", M_watcherWait); 44 | sleep(M_watcherWait); 45 | 46 | lib_update_time_globals(); 47 | 48 | INF_T("Starting..."); 49 | INF_T(M_watcherStartCmd); 50 | system(M_watcherStartCmd); 51 | 52 | #ifdef APP_ADMIN_EMAIL 53 | if ( strlen(APP_ADMIN_EMAIL) ) 54 | { 55 | char message[1024]; 56 | strcpy(message, "Silgy Watcher had to restart web server."); 57 | silgy_email(APP_ADMIN_EMAIL, "Silgy restart", message); 58 | } 59 | #endif 60 | } 61 | 62 | 63 | /* -------------------------------------------------------------------------- 64 | main 65 | -------------------------------------------------------------------------- */ 66 | int main(int argc, char *argv[]) 67 | { 68 | char config[256]; 69 | 70 | /* library init ------------------------------------------------------ */ 71 | 72 | silgy_lib_init(); 73 | 74 | sort_messages(); 75 | 76 | G_initialized = 1; 77 | 78 | /* read the config file or set defaults ------------------------------ */ 79 | 80 | if ( G_appdir[0] ) 81 | { 82 | sprintf(config, "%s/bin/silgy.conf", G_appdir); 83 | if ( !lib_read_conf(config) ) /* no config file there */ 84 | { 85 | strcpy(config, "silgy.conf"); 86 | lib_read_conf(config); 87 | } 88 | } 89 | else /* no SILGYDIR -- try current dir */ 90 | { 91 | strcpy(config, "silgy.conf"); 92 | lib_read_conf(config); 93 | } 94 | 95 | /* ------------------------------------------------------------------- */ 96 | 97 | if ( !silgy_read_param_int("watcherLogLevel", &G_logLevel) ) 98 | G_logLevel = 0; /* don't create log file */ 99 | 100 | if ( !silgy_read_param_int("watcherLogToStdout", &G_logToStdout) ) 101 | G_logToStdout = 0; 102 | 103 | if ( !silgy_read_param_int("httpPort", &G_httpPort) ) 104 | G_httpPort = 80; 105 | 106 | if ( !silgy_read_param_str("watcherStopCmd", M_watcherStopCmd) ) 107 | strcpy(M_watcherStopCmd, STOP_COMMAND); 108 | 109 | if ( !silgy_read_param_str("watcherStartCmd", M_watcherStartCmd) ) 110 | strcpy(M_watcherStartCmd, START_COMMAND); 111 | 112 | if ( !silgy_read_param_int("watcherWait", &M_watcherWait) ) 113 | M_watcherWait = 10; 114 | 115 | if ( !silgy_read_param_int("watcherLogRestart", &M_watcherLogRestart) ) 116 | M_watcherLogRestart = 3; 117 | 118 | /* start log --------------------------------------------------------- */ 119 | 120 | if ( !log_start("watcher", FALSE) ) 121 | return EXIT_FAILURE; 122 | 123 | /* ------------------------------------------------------------------- */ 124 | 125 | INF_T("Trying to connect..."); 126 | 127 | G_RESTTimeout = 60000; /* 60 seconds */ 128 | 129 | char url[1024]; 130 | 131 | sprintf(url, "127.0.0.1:%d", G_httpPort); 132 | 133 | REST_HEADER_SET("User-Agent", "Silgy Watcher Bot"); 134 | 135 | if ( !CALL_REST_HTTP(NULL, NULL, "GET", url, 0) ) 136 | { 137 | lib_update_time_globals(); 138 | ERR_T("Couldn't connect"); 139 | restart(); 140 | } 141 | 142 | /* ------------------------------------------------------------------- */ 143 | 144 | lib_update_time_globals(); 145 | 146 | INF_T("silgy_watcher ended"); 147 | 148 | log_finish(); 149 | 150 | return EXIT_SUCCESS; 151 | } 152 | -------------------------------------------------------------------------------- /resmin/silgy.js: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------------- 2 | // Show wait animation 3 | // -------------------------------------------------------------------------- 4 | function wait() 5 | { 6 | if ( !document.getElementById("wait") ) 7 | { 8 | let w = document.createElement("div"); 9 | w.id = "wait"; 10 | w.className = "wt"; // see silgy.css 11 | w.style.display = "block"; 12 | document.body.appendChild(w); 13 | } 14 | else 15 | document.getElementById("wait").style.display = "block"; 16 | } 17 | 18 | 19 | // -------------------------------------------------------------------------- 20 | // Turn the spinning wheel off 21 | // -------------------------------------------------------------------------- 22 | function wait_off() 23 | { 24 | document.getElementById("wait").style.display = "none"; 25 | } 26 | 27 | 28 | // -------------------------------------------------------------------------- 29 | // Go to link 30 | // l = url 31 | // -------------------------------------------------------------------------- 32 | function gt(l) 33 | { 34 | wait(); 35 | window.location.href = l; 36 | } 37 | 38 | 39 | // -------------------------------------------------------------------------- 40 | // Append a paragraph to the page 41 | // -------------------------------------------------------------------------- 42 | function p(t) 43 | { 44 | let p = document.createElement("p"); 45 | if ( t ) p.innerHTML = t; 46 | document.body.appendChild(p); 47 | return p; 48 | } 49 | 50 | 51 | // -------------------------------------------------------------------------- 52 | // Enter or Esc key hit 53 | // -------------------------------------------------------------------------- 54 | function ent(e) 55 | { 56 | if (e.keyCode==13) // Enter 57 | { 58 | document.getElementById("sbm").click(); // submit 59 | return false; 60 | } 61 | else if (e.keyCode==27) // Esc 62 | { 63 | document.getElementById("cnc").click(); // cancel 64 | return false; 65 | } 66 | 67 | return true; 68 | } 69 | 70 | 71 | // -------------------------------------------------------------------------- 72 | // Return true if cookies are enabled 73 | // -------------------------------------------------------------------------- 74 | function cookies() 75 | { 76 | try 77 | { 78 | document.cookie = "ct=1"; 79 | let enabled = document.cookie.indexOf("ct=") !== -1; 80 | document.cookie = "ct=1; expires=Thu, 01-Jan-1970 00:00:01 GMT"; 81 | return enabled; 82 | } 83 | catch (e) 84 | { 85 | return false; 86 | } 87 | } 88 | 89 | 90 | // -------------------------------------------------------------------------- 91 | // Center div 92 | // Call after appendChild 93 | // d = div handle 94 | // -------------------------------------------------------------------------- 95 | function center(d) 96 | { 97 | d.style.position = "fixed"; 98 | d.style.top = "50%"; 99 | d.style.left = "50%"; 100 | d.style.marginTop = -d.offsetTop/2 + "px"; 101 | d.style.marginLeft = -d.offsetWidth/2 + "px"; 102 | } 103 | 104 | 105 | // -------------------------------------------------------------------------- 106 | // Create modal window 107 | // l1 = first line 108 | // l2 = second line 109 | // w = width (em) 110 | // -------------------------------------------------------------------------- 111 | function mw(l1, l2, w) 112 | { 113 | let d = document.createElement("div"); 114 | 115 | if ( w ) 116 | d.style.width = w + "em"; 117 | else 118 | d.style.width = "20em"; 119 | 120 | d.className = "mw"; 121 | d.id = "mw"; 122 | 123 | let s1 = document.createElement("span"); 124 | 125 | s1.innerHTML = "
" 126 | + "" + l1 + "" 127 | + "
" 128 | + "

"; 129 | 130 | d.appendChild(s1); 131 | 132 | if ( l2 ) 133 | { 134 | let s2 = document.createElement("span"); 135 | s2.innerHTML = l2; 136 | d.appendChild(s2); 137 | } 138 | 139 | document.body.appendChild(d); 140 | center(d); 141 | 142 | window.addEventListener("keydown", mw_off); // allow keyboard escape 143 | } 144 | 145 | 146 | // -------------------------------------------------------------------------- 147 | // Remove modal window 148 | // -------------------------------------------------------------------------- 149 | function mw_off(e) 150 | { 151 | if ( e && e.keyCode!=27 ) return; 152 | window.removeEventListener("keydown", mw_off); 153 | let d = document.getElementById("mw"); 154 | d.parentNode.removeChild(d); 155 | } 156 | 157 | 158 | // -------------------------------------------------------------------------- 159 | // Create Yes/No modal window 160 | // t = text to display 161 | // a = action if Yes 162 | // w = width (em) 163 | // -------------------------------------------------------------------------- 164 | function yn(t, a, w) 165 | { 166 | mw(t, "
 
", w); 167 | } 168 | -------------------------------------------------------------------------------- /lib/silgy_usr.h: -------------------------------------------------------------------------------- 1 | /* -------------------------------------------------------------------------- 2 | Silgy Web App Engine 3 | Jurek Muszynski 4 | silgy.com 5 | ----------------------------------------------------------------------------- 6 | Logged in users' functions 7 | -------------------------------------------------------------------------- */ 8 | 9 | #ifndef SILGY_USR_H 10 | #define SILGY_USR_H 11 | 12 | 13 | #define DB_UAGENT_LEN 250 /* User-Agent length stored in ulogins table */ 14 | #define PASSWD_RESET_KEY_LEN 20 /* password reset key length */ 15 | 16 | #ifdef APP_MIN_USERNAME_LEN /* minimum user name length */ 17 | #define MIN_USERNAME_LEN APP_MIN_USERNAME_LEN 18 | #else 19 | #define MIN_USERNAME_LEN 2 20 | #endif 21 | 22 | #ifdef APP_MIN_PASSWORD_LEN /* minimum password length */ 23 | #define MIN_PASSWORD_LEN APP_MIN_PASSWORD_LEN 24 | #else 25 | #define MIN_PASSWORD_LEN 5 /* default minimal password length */ 26 | #endif 27 | 28 | #ifndef MAX_ULA_BEFORE_FIRST_SLOW /* maximum unsuccessful login tries before slowing down to 1 per minute */ 29 | #define MAX_ULA_BEFORE_FIRST_SLOW 10 30 | #endif 31 | 32 | #ifndef MAX_ULA_BEFORE_SECOND_SLOW /* maximum unsuccessful login tries before slowing down to 1 per hour */ 33 | #define MAX_ULA_BEFORE_SECOND_SLOW 25 34 | #endif 35 | 36 | #ifndef MAX_ULA_BEFORE_THIRD_SLOW /* maximum unsuccessful login tries before slowing down to 1 per day */ 37 | #define MAX_ULA_BEFORE_THIRD_SLOW 100 38 | #endif 39 | 40 | #ifndef MAX_ULA_BEFORE_LOCK /* maximum unsuccessful login tries before user lockout */ 41 | #define MAX_ULA_BEFORE_LOCK 1000 42 | #endif 43 | 44 | 45 | /* user status */ 46 | 47 | #define USER_STATUS_INACTIVE 0 48 | #define USER_STATUS_ACTIVE 1 49 | #define USER_STATUS_LOCKED 2 50 | #define USER_STATUS_PASSWORD_CHANGE 3 51 | #define USER_STATUS_DELETED 9 52 | 53 | 54 | /* configurable parameters */ 55 | 56 | #ifndef DEF_USER_AUTH_LEVEL 57 | #define DEF_USER_AUTH_LEVEL AUTH_LEVEL_USER /* default user authorization level */ 58 | #endif 59 | 60 | #ifndef USER_ACTIVATION_HOURS 61 | #define USER_ACTIVATION_HOURS 24 /* activate user account within */ 62 | #endif 63 | 64 | #ifndef USER_KEEP_LOGGED_DAYS 65 | #define USER_KEEP_LOGGED_DAYS 30 /* ls cookie validity period */ 66 | #endif 67 | 68 | 69 | #define COMMON_PASSWORDS_FILE "passwords.txt" 70 | 71 | 72 | #ifndef REFUSE_10_COMMON_PASSWORDS 73 | #ifndef REFUSE_100_COMMON_PASSWORDS 74 | #ifndef REFUSE_1000_COMMON_PASSWORDS 75 | #ifndef REFUSE_10000_COMMON_PASSWORDS 76 | #ifndef DONT_REFUSE_COMMON_PASSWORDS 77 | #define DONT_REFUSE_COMMON_PASSWORDS 78 | #endif 79 | #endif 80 | #endif 81 | #endif 82 | #endif 83 | 84 | 85 | /* Silgy engine errors are 0 ... 99 */ 86 | 87 | /* ------------------------------------- */ 88 | /* errors -- red */ 89 | 90 | /* login */ 91 | #define ERR_INVALID_LOGIN 101 92 | #define ERR_USERNAME_TOO_SHORT 102 93 | #define ERR_USERNAME_CHARS 103 94 | #define ERR_USERNAME_TAKEN 104 95 | /* ------------------------------------- */ 96 | #define ERR_MAX_USR_LOGIN_ERROR 110 97 | /* ------------------------------------- */ 98 | /* email */ 99 | #define ERR_EMAIL_EMPTY 111 100 | #define ERR_EMAIL_FORMAT 112 101 | #define ERR_EMAIL_FORMAT_OR_EMPTY 113 102 | #define ERR_EMAIL_TAKEN 114 103 | /* ------------------------------------- */ 104 | #define ERR_MAX_USR_EMAIL_ERROR 120 105 | /* ------------------------------------- */ 106 | /* password */ 107 | #define ERR_INVALID_PASSWORD 121 108 | #define ERR_PASSWORD_TOO_SHORT 122 109 | #define ERR_IN_10_COMMON_PASSWORDS 123 110 | #define ERR_IN_100_COMMON_PASSWORDS 124 111 | #define ERR_IN_1000_COMMON_PASSWORDS 125 112 | #define ERR_IN_10000_COMMON_PASSWORDS 126 113 | /* ------------------------------------- */ 114 | #define ERR_MAX_USR_PASSWORD_ERROR 130 115 | /* ------------------------------------- */ 116 | /* repeat password */ 117 | #define ERR_PASSWORD_DIFFERENT 131 118 | /* ------------------------------------- */ 119 | #define ERR_MAX_USR_REPEAT_PASSWORD_ERROR 140 120 | /* ------------------------------------- */ 121 | /* old password */ 122 | #define ERR_OLD_PASSWORD 141 123 | /* ------------------------------------- */ 124 | #define ERR_MAX_USR_OLD_PASSWORD_ERROR 150 125 | /* ------------------------------------- */ 126 | /* session / link / other */ 127 | #define ERR_SESSION_EXPIRED 151 128 | #define ERR_LINK_BROKEN 152 129 | #define ERR_LINK_MAY_BE_EXPIRED 153 130 | #define ERR_LINK_EXPIRED 154 131 | #define ERR_LINK_TOO_MANY_TRIES 155 132 | #define ERR_ROBOT 156 133 | #define ERR_WEBSITE_FIRST_LETTER 157 134 | #define ERR_NOT_ACTIVATED 158 135 | /* ------------------------------------- */ 136 | #define ERR_MAX_USR_ERROR 199 137 | /* ------------------------------------- */ 138 | 139 | /* ------------------------------------- */ 140 | /* warnings -- yellow */ 141 | 142 | #define WAR_NO_EMAIL 201 143 | #define WAR_BEFORE_DELETE 202 144 | #define WAR_ULA_FIRST 203 145 | #define WAR_ULA_SECOND 204 146 | #define WAR_ULA_THIRD 205 147 | #define WAR_PASSWORD_CHANGE 206 148 | /* ------------------------------------- */ 149 | #define WAR_MAX_USR_WARNING 299 150 | /* ------------------------------------- */ 151 | 152 | /* ------------------------------------- */ 153 | /* messages -- green */ 154 | 155 | #define MSG_WELCOME_NO_ACTIVATION 301 156 | #define MSG_WELCOME_NEED_ACTIVATION 302 157 | #define MSG_WELCOME_AFTER_ACTIVATION 303 158 | #define MSG_USER_LOGGED_OUT 304 159 | #define MSG_CHANGES_SAVED 305 160 | #define MSG_REQUEST_SENT 306 161 | #define MSG_PASSWORD_CHANGED 307 162 | #define MSG_MESSAGE_SENT 308 163 | #define MSG_PROVIDE_FEEDBACK 309 164 | #define MSG_FEEDBACK_SENT 310 165 | #define MSG_USER_ALREADY_ACTIVATED 311 166 | #define MSG_ACCOUNT_DELETED 312 167 | /* ------------------------------------- */ 168 | #define MSG_MAX_USR_MESSAGE 399 169 | /* ------------------------------------- */ 170 | 171 | 172 | #define MSG_CAT_USR_LOGIN "msgLogin" 173 | #define MSG_CAT_USR_EMAIL "msgEmail" 174 | #define MSG_CAT_USR_PASSWORD "msgPassword" 175 | #define MSG_CAT_USR_REPEAT_PASSWORD "msgPasswordRepeat" 176 | #define MSG_CAT_USR_OLD_PASSWORD "msgPasswordOld" 177 | 178 | 179 | #ifndef LUSES_TIMEOUT 180 | #define LUSES_TIMEOUT 1800 /* logged in user session timeout in seconds (120 for tests / 1800 live) */ 181 | #endif /* it's now how long it stays in cache */ 182 | 183 | /* user authentication */ 184 | 185 | #ifndef USERSBYEMAIL 186 | #ifndef USERSBYLOGIN 187 | #define USERSBYLOGIN 188 | #endif 189 | #endif 190 | 191 | /* passwords' hashing padding */ 192 | 193 | #ifndef STR_001 194 | #define STR_001 "abcde" 195 | #endif 196 | #ifndef STR_002 197 | #define STR_002 "fghij" 198 | #endif 199 | #ifndef STR_003 200 | #define STR_003 "klmno" 201 | #endif 202 | #ifndef STR_004 203 | #define STR_004 "pqrst" 204 | #endif 205 | #ifndef STR_005 206 | #define STR_005 "uvwxy" 207 | #endif 208 | 209 | 210 | #define MAX_AVATAR_SIZE 65536 /* MySQL's BLOB size */ 211 | 212 | 213 | #define SET_USER_STR(key, val) silgy_usr_set_str(ci, key, val) 214 | #define SET_USR_STR(key, val) silgy_usr_set_str(ci, key, val) 215 | 216 | #define GET_USER_STR(key, val) silgy_usr_get_str(ci, key, val) 217 | #define GET_USR_STR(key, val) silgy_usr_get_str(ci, key, val) 218 | 219 | #define SET_USER_INT(key, val) silgy_usr_set_int(ci, key, val) 220 | #define SET_USR_INT(key, val) silgy_usr_set_int(ci, key, val) 221 | 222 | #define GET_USER_INT(key, val) silgy_usr_get_int(ci, key, val) 223 | #define GET_USR_INT(key, val) silgy_usr_get_int(ci, key, val) 224 | 225 | 226 | /* 227 | Brute-force ls cookie attack protection. 228 | It essentially defines how many different IPs can take part in a botnet attack. 229 | */ 230 | 231 | #ifdef MEM_TINY 232 | #define FAILED_LOGIN_CNT_SIZE 100 233 | #elif defined MEM_MEDIUM 234 | #define FAILED_LOGIN_CNT_SIZE 1000 235 | #elif defined MEM_LARGE 236 | #define FAILED_LOGIN_CNT_SIZE 10000 237 | #elif defined MEM_XLARGE 238 | #define FAILED_LOGIN_CNT_SIZE 10000 239 | #elif defined MEM_XXLARGE 240 | #define FAILED_LOGIN_CNT_SIZE 100000 241 | #elif defined MEM_XXXLARGE 242 | #define FAILED_LOGIN_CNT_SIZE 100000 243 | #elif defined MEM_XXXXLARGE 244 | #define FAILED_LOGIN_CNT_SIZE 100000 245 | #else /* MEM_SMALL -- default */ 246 | #define FAILED_LOGIN_CNT_SIZE 1000 247 | #endif 248 | 249 | typedef struct { 250 | char ip[INET_ADDRSTRLEN]; 251 | int cnt; 252 | time_t when; 253 | } failed_login_cnt_t; 254 | 255 | 256 | #ifdef __cplusplus 257 | extern "C" { 258 | #endif 259 | int silgy_usr_login(int ci); 260 | int silgy_usr_password_quality(const char *passwd); 261 | int silgy_usr_create_account(int ci); 262 | int silgy_usr_add_user(int ci, bool use_qs, const char *login, const char *email, const char *name, const char *passwd, const char *phone, const char *lang, const char *tz, const char *about, char group_id, char auth_level, char status); 263 | int silgy_usr_send_message(int ci); 264 | int silgy_usr_save_account(int ci); 265 | int silgy_usr_email_registered(int ci); 266 | char *silgy_usr_name(const char *login, const char *email, const char *name, int uid); 267 | int silgy_usr_send_passwd_reset_email(int ci); 268 | int silgy_usr_verify_passwd_reset_key(int ci, char *linkkey, int *uid); 269 | int silgy_usr_activate(int ci); 270 | int silgy_usr_save_avatar(int ci, int uid); 271 | int silgy_usr_get_avatar(int ci, int uid); 272 | int silgy_usr_change_password(int ci); 273 | int silgy_usr_reset_password(int ci); 274 | void silgy_usr_logout(int ci); 275 | int silgy_usr_set_str(int ci, const char *us_key, const char *us_val); 276 | int silgy_usr_get_str(int ci, const char *us_key, char *us_val); 277 | int silgy_usr_set_int(int ci, const char *us_key, int us_val); 278 | int silgy_usr_get_int(int ci, const char *us_key, int *us_val); 279 | /* for the engine */ 280 | void libusr_init(void); 281 | int libusr_luses_ok(int ci); 282 | void libusr_luses_close_timeouted(void); 283 | void libusr_luses_save_csrft(void); 284 | void libusr_luses_downgrade(int usi, int ci, bool usr_logout); 285 | #ifdef __cplusplus 286 | } // extern "C" 287 | #endif 288 | 289 | 290 | #endif /* SILGY_USR_H */ 291 | -------------------------------------------------------------------------------- /src/silgy_app.cpp: -------------------------------------------------------------------------------- 1 | /* -------------------------------------------------------------------------- 2 | Silgy Web App 3 | Jurek Muszynski 4 | silgy.com 5 | ----------------------------------------------------------------------------- 6 | Hello World Sample Silgy Web Application 7 | -------------------------------------------------------------------------- */ 8 | 9 | 10 | #include 11 | 12 | 13 | #define TYPE_STRING 's' 14 | #define TYPE_INT 'i' 15 | #define TYPE_FLOAT 'f' 16 | #define TYPE_DOUBLE 'd' 17 | #define TYPE_BOOL 'b' 18 | 19 | /* 20 | Add settings to the array below. 21 | len is for strings only. 22 | Do not remove the last line with empty values. 23 | */ 24 | 25 | static struct { 26 | char label[64]; 27 | char name[64]; 28 | char type; 29 | short len; 30 | char *value; 31 | } M_settings[] = { 32 | {"Some string", "some_string", TYPE_STRING, 255, NULL}, 33 | {"Some number", "some_number", TYPE_INT, 0, NULL}, 34 | {"Some float", "some_float", TYPE_FLOAT, 0, NULL}, 35 | {"Some bool", "some_bool", TYPE_BOOL, 0, NULL}, 36 | {"", "", 0, 0, NULL} 37 | }; 38 | 39 | 40 | /* -------------------------------------------------------------------------------- 41 | Render main menu 42 | -------------------------------------------------------------------------------- */ 43 | static void main_menu(int ci) 44 | { 45 | char lnk_home[256]="Home"; 46 | char lnk_settings[256]="Settings"; 47 | char lnk_website[256]; 48 | snprintf(lnk_website, 255, "Website", APP_DOMAIN); 49 | char lnk_logout[256]="Logout"; 50 | 51 | if ( REQ("") ) 52 | COPY(lnk_home, "Home", 255); 53 | else if ( REQ("settings") ) 54 | COPY(lnk_settings, "Settings", 255); 55 | 56 | OUT("

"); 57 | 58 | OUT(lnk_home); 59 | OUT(" | "); 60 | OUT(lnk_settings); 61 | OUT(" | "); 62 | OUT(lnk_website); 63 | 64 | if ( AUS.authenticated ) 65 | { 66 | OUT(" | "); 67 | OUT(lnk_logout); 68 | } 69 | 70 | OUT("

"); 71 | } 72 | 73 | 74 | /* -------------------------------------------------------------------------------- 75 | Render HTML header 76 | -------------------------------------------------------------------------------- */ 77 | static void header(int ci) 78 | { 79 | OUT(""); 80 | OUT(""); 81 | OUT(""); 82 | OUT(""); 83 | OUT("%s", APP_WEBSITE); 84 | // OUT("", APP_DESCRIPTION); 85 | // OUT("", APP_KEYWORDS); 86 | OUT(""); 87 | // OUT(""); 88 | OUT(""); 89 | OUT(""); 90 | // OUT(""); 91 | OUT(""); 92 | 93 | OUT(""); 94 | OUT("

%s

", APP_WEBSITE); 95 | 96 | main_menu(ci); 97 | } 98 | 99 | 100 | /* -------------------------------------------------------------------------------- 101 | Render HTML footer 102 | -------------------------------------------------------------------------------- */ 103 | static void footer(int ci) 104 | { 105 | OUT_HTML_FOOTER; 106 | } 107 | 108 | 109 | /* -------------------------------------------------------------------------- 110 | Show error message if present in URI 111 | -------------------------------------------------------------------------- */ 112 | static int check_error_msg(int ci) 113 | { 114 | int msg; 115 | 116 | if ( !QSI("msg", &msg) || msg==OK ) return OK; 117 | 118 | OUT("

%s

", silgy_message(msg)); 119 | 120 | return msg; 121 | } 122 | 123 | 124 | /* -------------------------------------------------------------------------------- 125 | Render landing page 126 | -------------------------------------------------------------------------------- */ 127 | static void render_landing(int ci) 128 | { 129 | header(ci); 130 | OUT("

Welcome to %s!

", APP_WEBSITE); 131 | footer(ci); 132 | } 133 | 134 | 135 | /* -------------------------------------------------------------------------- 136 | Render page 137 | -------------------------------------------------------------------------- */ 138 | static void render_login(int ci) 139 | { 140 | header(ci); 141 | OUT("

Login

"); 142 | check_error_msg(ci); 143 | 144 | OUT("
"); 145 | 146 | OUT("", REQ_DSK?"":" class=w100p"); 147 | 148 | if ( REQ_DSK ) 149 | { 150 | OUT("Login:"); 151 | OUT("Password:"); 152 | OUT(" "); 153 | OUT(""); 154 | } 155 | else /* phone */ 156 | { 157 | OUT("Login:"); 158 | OUT(""); 159 | OUT("Password:"); 160 | OUT(""); 161 | OUT(" "); 162 | OUT(""); 163 | } 164 | 165 | OUT(""); 166 | 167 | OUT(""); 168 | 169 | footer(ci); 170 | } 171 | 172 | 173 | /* -------------------------------------------------------------------------- 174 | Login 175 | -------------------------------------------------------------------------- */ 176 | static int do_login(int ci) 177 | { 178 | QSVAL qsval; 179 | char passwd[PASSWORD_LEN+1]; 180 | 181 | if ( QS("passwd", qsval) ) 182 | COPY(passwd, qsval, PASSWORD_LEN); 183 | 184 | if ( 0==strcmp(passwd, AUS.password) ) 185 | { 186 | AUS.authenticated = true; 187 | return OK; 188 | } 189 | 190 | return ERR_UNAUTHORIZED; 191 | } 192 | 193 | 194 | /* -------------------------------------------------------------------------------- 195 | Render settings page 196 | -------------------------------------------------------------------------------- */ 197 | static void render_settings(int ci) 198 | { 199 | header(ci); 200 | OUT("

Settings

"); 201 | check_error_msg(ci); 202 | 203 | OUT("
"); 204 | 205 | OUT("", REQ_DSK?"":" class=w100p"); 206 | 207 | if ( REQ_DSK ) 208 | { 209 | OUT("Password:", AUS.password); 210 | 211 | for ( int i=0; M_settings[i].type!=0; ++i ) 212 | { 213 | if ( M_settings[i].type == TYPE_STRING ) 214 | OUT("%s:", M_settings[i].label, M_settings[i].name, M_settings[i].value); 215 | else if ( M_settings[i].type == TYPE_INT ) 216 | OUT("%s:", M_settings[i].label, M_settings[i].name, *(int*)M_settings[i].value); 217 | else if ( M_settings[i].type == TYPE_FLOAT ) 218 | OUT("%s:", M_settings[i].label, M_settings[i].name, *(float*)M_settings[i].value); 219 | else if ( M_settings[i].type == TYPE_DOUBLE ) 220 | OUT("%s:", M_settings[i].label, M_settings[i].name, *(double*)M_settings[i].value); 221 | else if ( M_settings[i].type == TYPE_BOOL ) 222 | OUT("%s:", M_settings[i].label, M_settings[i].name, *(bool*)M_settings[i].value); 223 | } 224 | 225 | OUT(" "); 226 | OUT(""); 227 | } 228 | else /* phone */ 229 | { 230 | OUT("Password:"); 231 | OUT("", AUS.password); 232 | 233 | for ( int i=0; M_settings[i].type!=0; ++i ) 234 | { 235 | if ( M_settings[i].type == TYPE_STRING ) 236 | { 237 | OUT("%s:", M_settings[i].label); 238 | OUT("", M_settings[i].name, M_settings[i].value); 239 | } 240 | else if ( M_settings[i].type == TYPE_INT ) 241 | { 242 | OUT("%s:", M_settings[i].label); 243 | OUT("", M_settings[i].name, *(int*)M_settings[i].value); 244 | } 245 | else if ( M_settings[i].type == TYPE_FLOAT ) 246 | { 247 | OUT("%s:", M_settings[i].label); 248 | OUT("", M_settings[i].name, *(float*)M_settings[i].value); 249 | } 250 | else if ( M_settings[i].type == TYPE_DOUBLE ) 251 | { 252 | OUT("%s:", M_settings[i].label); 253 | OUT("", M_settings[i].name, *(double*)M_settings[i].value); 254 | } 255 | else if ( M_settings[i].type == TYPE_BOOL ) 256 | { 257 | OUT("%s:", M_settings[i].label); 258 | OUT("", M_settings[i].name, *(bool*)M_settings[i].value); 259 | } 260 | } 261 | 262 | OUT(" "); 263 | OUT(""); 264 | } 265 | 266 | OUT(""); 267 | 268 | OUT(""); 269 | 270 | footer(ci); 271 | } 272 | 273 | 274 | /* -------------------------------------------------------------------------------- 275 | Save settings to a file 276 | -------------------------------------------------------------------------------- */ 277 | static int save_settings(int ci) 278 | { 279 | // read query string values 280 | 281 | QSVAL qsval; 282 | 283 | if ( QS("password", qsval) ) 284 | COPY(AUS.password, qsval, PASSWORD_LEN); 285 | 286 | for ( int i=0; M_settings[i].type!=0; ++i ) 287 | { 288 | if ( M_settings[i].type == TYPE_STRING ) 289 | { 290 | if ( QS(M_settings[i].name, qsval) ) 291 | COPY(M_settings[i].value, qsval, M_settings[i].len); 292 | } 293 | else if ( M_settings[i].type == TYPE_INT ) 294 | { 295 | QSI(M_settings[i].name, (int*)M_settings[i].value); 296 | } 297 | else if ( M_settings[i].type == TYPE_FLOAT ) 298 | { 299 | QSF(M_settings[i].name, (float*)M_settings[i].value); 300 | } 301 | else if ( M_settings[i].type == TYPE_DOUBLE ) 302 | { 303 | QSD(M_settings[i].name, (double*)M_settings[i].value); 304 | } 305 | else if ( M_settings[i].type == TYPE_BOOL ) 306 | { 307 | QSB(M_settings[i].name, (bool*)M_settings[i].value); 308 | } 309 | } 310 | 311 | // DBG("some_float = %f", *(float*)M_settings[2].value); 312 | 313 | // render JSON 314 | 315 | JSON j={0}; 316 | 317 | JSON_ADD_STR(j, "password", AUS.password); 318 | 319 | for ( int i=0; M_settings[i].type!=0; ++i ) 320 | { 321 | if ( M_settings[i].type == TYPE_STRING ) 322 | JSON_ADD_STR(j, M_settings[i].name, M_settings[i].value); 323 | else if ( M_settings[i].type == TYPE_INT ) 324 | JSON_ADD_INT(j, M_settings[i].name, *(int*)M_settings[i].value); 325 | else if ( M_settings[i].type == TYPE_FLOAT ) 326 | JSON_ADD_FLOAT(j, M_settings[i].name, *(float*)M_settings[i].value); 327 | else if ( M_settings[i].type == TYPE_DOUBLE ) 328 | JSON_ADD_DOUBLE(j, M_settings[i].name, *(double*)M_settings[i].value); 329 | else if ( M_settings[i].type == TYPE_BOOL ) 330 | JSON_ADD_BOOL(j, M_settings[i].name, *(bool*)M_settings[i].value); 331 | } 332 | 333 | char data[JSON_BUFSIZE]; 334 | 335 | COPY(data, JSON_TO_STRING_PRETTY(j), JSON_BUFSIZE-1); 336 | 337 | // save JSON to a file 338 | 339 | FILE *fd; 340 | 341 | if ( NULL == (fd=fopen(SETTINGS_FILE, "w")) ) 342 | { 343 | WAR("Couldn't open %s\n", SETTINGS_FILE); 344 | return ERR_INT_SERVER_ERROR; 345 | } 346 | else /* OK */ 347 | { 348 | fwrite(data, strlen(data), 1, fd); 349 | } 350 | 351 | fclose(fd); 352 | 353 | return OK; 354 | } 355 | 356 | 357 | /* -------------------------------------------------------------------------------- 358 | Called after parsing HTTP request header 359 | ------------------------------ 360 | This is the main entry point for a request 361 | ------------------------------ 362 | Response status will be 200 by default 363 | Use RES_STATUS() if you want to change it 364 | -------------------------------------------------------------------------------- */ 365 | void silgy_app_main(int ci) 366 | { 367 | int ret=OK; 368 | 369 | if ( REQ("login") ) 370 | { 371 | render_login(ci); 372 | } 373 | else if ( REQ("do_login") ) 374 | { 375 | ret = do_login(ci); 376 | 377 | if ( ret == OK ) 378 | RES_LOCATION("/settings"); 379 | else 380 | RES_LOCATION("/login?msg=%d", ret); 381 | } 382 | else if ( REQ("settings") ) 383 | { 384 | if ( AUS.authenticated ) 385 | render_settings(ci); 386 | else 387 | RES_LOCATION("/login"); 388 | } 389 | else if ( REQ("save_settings") ) 390 | { 391 | if ( AUS.authenticated ) 392 | { 393 | ret = save_settings(ci); 394 | RES_LOCATION("/settings?msg=%d", ret==OK?MSG_SETTINGS_SAVED:ret); 395 | } 396 | else 397 | RES_LOCATION("/login"); 398 | } 399 | else if ( REQ("logout") ) 400 | { 401 | AUS.authenticated = false; 402 | RES_LOCATION("/"); 403 | } 404 | else 405 | { 406 | render_landing(ci); 407 | } 408 | 409 | RES_DONT_CACHE; 410 | } 411 | 412 | 413 | /* -------------------------------------------------------------------------------- 414 | Called when application starts 415 | ------------------------------ 416 | Return true if everything OK 417 | ------------------------------ 418 | Returning false will stop booting process, 419 | silgy_app_done() will be called and application will be terminated 420 | -------------------------------------------------------------------------------- */ 421 | bool silgy_app_init(int argc, char *argv[]) 422 | { 423 | silgy_add_message(MSG_SETTINGS_SAVED, "EN-US", "Settings have been saved"); 424 | 425 | return true; 426 | } 427 | 428 | 429 | /* -------------------------------------------------------------------------------- 430 | Called when new anonymous user session starts 431 | ------------------------------ 432 | Return true if everything OK 433 | ------------------------------ 434 | Returning false will cause the session to be closed 435 | and silgy_app_session_done() will be called 436 | Response status will be set to 500 437 | -------------------------------------------------------------------------------- */ 438 | bool silgy_app_session_init(int ci) 439 | { 440 | // read settings from a file 441 | 442 | FILE *fd; 443 | 444 | if ( NULL == (fd=fopen(SETTINGS_FILE, "r")) ) 445 | { 446 | WAR("Couldn't open %s\n", SETTINGS_FILE); 447 | // return false; 448 | return true; 449 | } 450 | 451 | fseek(fd, 0, SEEK_END); /* determine the file size */ 452 | unsigned len = ftell(fd); 453 | rewind(fd); 454 | 455 | char *data; 456 | 457 | if ( NULL == (data=(char*)malloc(len+1)) ) 458 | { 459 | ERR("Couldn't allocate %u bytes for %s", len+1, SETTINGS_FILE); 460 | fclose(fd); 461 | return false; 462 | } 463 | 464 | fread(data, len, 1, fd); 465 | *(data+len) = EOS; 466 | 467 | fclose(fd); 468 | 469 | JSON j={0}; 470 | JSON_FROM_STRING(j, data); 471 | 472 | free(data); 473 | 474 | COPY(AUS.password, JSON_GET_STR(j, "password"), PASSWORD_LEN); 475 | 476 | for ( int i=0; M_settings[i].type!=0; ++i ) 477 | { 478 | if ( M_settings[i].type == TYPE_STRING ) 479 | { 480 | if ( NULL == (M_settings[i].value=(char*)malloc(M_settings[i].len+1)) ) 481 | { 482 | ERR("Couldn't allocate %d bytes for %s", M_settings[i].len+1, M_settings[i].name); 483 | return false; 484 | } 485 | 486 | COPY(M_settings[i].value, JSON_GET_STR(j, M_settings[i].name), M_settings[i].len); 487 | } 488 | else if ( M_settings[i].type == TYPE_INT ) 489 | { 490 | if ( NULL == (M_settings[i].value=(char*)malloc(sizeof(int))) ) 491 | { 492 | ERR("Couldn't allocate %d bytes for %s", sizeof(int), M_settings[i].name); 493 | return false; 494 | } 495 | 496 | int tmp = JSON_GET_INT(j, M_settings[i].name); 497 | memcpy(M_settings[i].value, (char*)&tmp, sizeof(int)); 498 | } 499 | else if ( M_settings[i].type == TYPE_FLOAT ) 500 | { 501 | if ( NULL == (M_settings[i].value=(char*)malloc(sizeof(float))) ) 502 | { 503 | ERR("Couldn't allocate %d bytes for %s", sizeof(float), M_settings[i].name); 504 | return false; 505 | } 506 | 507 | float tmp = JSON_GET_FLOAT(j, M_settings[i].name); 508 | memcpy(M_settings[i].value, (char*)&tmp, sizeof(float)); 509 | } 510 | else if ( M_settings[i].type == TYPE_DOUBLE ) 511 | { 512 | if ( NULL == (M_settings[i].value=(char*)malloc(sizeof(double))) ) 513 | { 514 | ERR("Couldn't allocate %d bytes for %s", sizeof(double), M_settings[i].name); 515 | return false; 516 | } 517 | 518 | double tmp = JSON_GET_DOUBLE(j, M_settings[i].name); 519 | memcpy(M_settings[i].value, (char*)&tmp, sizeof(double)); 520 | } 521 | else if ( M_settings[i].type == TYPE_BOOL ) 522 | { 523 | if ( NULL == (M_settings[i].value=(char*)malloc(sizeof(bool))) ) 524 | { 525 | ERR("Couldn't allocate %d bytes for %s", sizeof(bool), M_settings[i].name); 526 | return false; 527 | } 528 | 529 | bool tmp = JSON_GET_BOOL(j, M_settings[i].name); 530 | memcpy(M_settings[i].value, (char*)&tmp, sizeof(bool)); 531 | } 532 | } 533 | 534 | return true; 535 | } 536 | 537 | 538 | /* -------------------------------------------------------------------------------- 539 | ******* Only for USERS ******* 540 | ------------------------------ 541 | Called after successful authentication (using password or cookie) 542 | when user session is upgraded from anonymous to logged in 543 | ------------------------------ 544 | Return true if everything OK 545 | ------------------------------ 546 | Returning false will cause the session to be downgraded back to anonymous 547 | and silgy_app_user_logout() will be called 548 | -------------------------------------------------------------------------------- */ 549 | bool silgy_app_user_login(int ci) 550 | { 551 | return true; 552 | } 553 | 554 | 555 | /* -------------------------------------------------------------------------------- 556 | ******* Only for USERS ******* 557 | ------------------------------ 558 | Called when downgrading logged in user session to anonymous 559 | -------------------------------------------------------------------------------- */ 560 | void silgy_app_user_logout(int ci) 561 | { 562 | } 563 | 564 | 565 | /* -------------------------------------------------------------------------------- 566 | Called when closing anonymous user session 567 | After calling this the session memory will be zero-ed 568 | -------------------------------------------------------------------------------- */ 569 | void silgy_app_session_done(int ci) 570 | { 571 | } 572 | 573 | 574 | /* -------------------------------------------------------------------------------- 575 | Called when application shuts down 576 | -------------------------------------------------------------------------------- */ 577 | void silgy_app_done() 578 | { 579 | } 580 | -------------------------------------------------------------------------------- /lib/silgy_lib.h: -------------------------------------------------------------------------------- 1 | /* -------------------------------------------------------------------------- 2 | Silgy Web App Engine 3 | Jurek Muszynski 4 | silgy.com 5 | ----------------------------------------------------------------------------- 6 | General purpose library 7 | -------------------------------------------------------------------------- */ 8 | 9 | #ifndef SILGY_LIB_H 10 | #define SILGY_LIB_H 11 | 12 | 13 | #define ALWAYS(str, ...) log_write(LOG_ALWAYS, str, ##__VA_ARGS__) 14 | #define ERR(str, ...) log_write(LOG_ERR, str, ##__VA_ARGS__) 15 | #define WAR(str, ...) log_write(LOG_WAR, str, ##__VA_ARGS__) 16 | #define INF(str, ...) log_write(LOG_INF, str, ##__VA_ARGS__) 17 | #define DBG(str, ...) log_write(LOG_DBG, str, ##__VA_ARGS__) 18 | 19 | #define ALWAYS_T(str, ...) log_write_time(LOG_ALWAYS, str, ##__VA_ARGS__) 20 | #define ERR_T(str, ...) log_write_time(LOG_ERR, str, ##__VA_ARGS__) 21 | #define WAR_T(str, ...) log_write_time(LOG_WAR, str, ##__VA_ARGS__) 22 | #define INF_T(str, ...) log_write_time(LOG_INF, str, ##__VA_ARGS__) 23 | #define DBG_T(str, ...) log_write_time(LOG_DBG, str, ##__VA_ARGS__) 24 | 25 | #define LOG_LINE "--------------------------------------------------" 26 | #define LOG_LINE_N "--------------------------------------------------\n" 27 | #define LOG_LINE_NN "--------------------------------------------------\n\n" 28 | #define ALWAYS_LINE ALWAYS(LOG_LINE) 29 | #define INF_LINE INF(LOG_LINE) 30 | #define DBG_LINE DBG(LOG_LINE) 31 | 32 | #define LOG_LINE_LONG "--------------------------------------------------------------------------------------------------" 33 | #define LOG_LINE_LONG_N "--------------------------------------------------------------------------------------------------\n" 34 | #define LOG_LINE_LONG_NN "--------------------------------------------------------------------------------------------------\n\n" 35 | #define ALWAYS_LINE_LONG ALWAYS(LOG_LINE_LONG) 36 | #define INF_LINE_LONG INF(LOG_LINE_LONG) 37 | #define DBG_LINE_LONG DBG(LOG_LINE_LONG) 38 | 39 | #define LOREM_IPSUM "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum." 40 | 41 | #define PARAM(param) (0==strcmp(label, param)) 42 | 43 | #define UTF8_ANY(c) (((unsigned char)c & 0x80) == 0x80) 44 | #define UTF8_START(c) (UTF8_ANY(c) && ((unsigned char)c & 0x40) == 0x40) 45 | 46 | #define COPY(dst, src, dst_len) silgy_safe_copy(dst, src, dst_len) 47 | 48 | 49 | /* Query String Value */ 50 | 51 | typedef char QSVAL[QSBUF]; 52 | //typedef struct QSVAL { char x[QSBUF]; } QSVAL; 53 | 54 | typedef char QSVAL1K[1024]; 55 | typedef char QSVAL2K[2048]; 56 | typedef char QSVAL4K[4096]; 57 | typedef char QSVAL8K[8192]; 58 | typedef char QSVAL16K[16384]; 59 | typedef char QSVAL32K[32768]; 60 | typedef char QSVAL64K[65536]; 61 | typedef char QSVAL_TEXT[65536]; 62 | 63 | 64 | #define RES_HEADER(key, val) lib_res_header(ci, key, val) 65 | 66 | 67 | #ifdef APP_EMAIL_FROM_USER 68 | #define EMAIL_FROM_USER APP_EMAIL_FROM_USER 69 | #else 70 | #define EMAIL_FROM_USER "noreply" 71 | #endif 72 | 73 | 74 | #define CONNECT 0 75 | #define READ 1 76 | #define WRITE 2 77 | #define SHUTDOWN 3 78 | 79 | 80 | #define MAX_SHM_SEGMENTS 100 81 | 82 | 83 | /* API authorization system */ 84 | 85 | #define AUTH_NONE 0x00 86 | #define AUTH_CREATE 0x01 87 | #define AUTH_READ 0x02 88 | #define AUTH_UPDATE 0x04 89 | #define AUTH_DELETE 0x08 90 | #define AUTH_FULL 0xFF 91 | 92 | #define IS_AUTH_CREATE(flags) ((flags & AUTH_CREATE) == AUTH_CREATE) 93 | #define IS_AUTH_READ(flags) ((flags & AUTH_READ) == AUTH_READ) 94 | #define IS_AUTH_UPDATE(flags) ((flags & AUTH_UPDATE) == AUTH_UPDATE) 95 | #define IS_AUTH_DELETE(flags) ((flags & AUTH_DELETE) == AUTH_DELETE) 96 | 97 | 98 | 99 | /* languages */ 100 | 101 | #ifndef MAX_LANGUAGES 102 | #define MAX_LANGUAGES 250 103 | #endif 104 | 105 | typedef struct { 106 | char lang[LANG_LEN+1]; 107 | int first_index; 108 | int next_lang_index; 109 | } lang_t; 110 | 111 | 112 | 113 | /* messages */ 114 | 115 | #ifndef MAX_MSG_LEN 116 | #define MAX_MSG_LEN 255 117 | #endif 118 | 119 | #ifndef MAX_MESSAGES 120 | #define MAX_MESSAGES 1000 121 | #endif 122 | 123 | typedef struct { 124 | int code; 125 | char lang[LANG_LEN+1]; 126 | char message[MAX_MSG_LEN+1]; 127 | } message_t; 128 | 129 | 130 | #define silgy_message(code) lib_get_message(ci, code) 131 | #define MSG(code) lib_get_message(ci, code) 132 | #define MSG_CAT_GREEN(code) silgy_is_msg_main_cat(code, MSG_CAT_MESSAGE) 133 | #define MSG_CAT_ORANGE(code) silgy_is_msg_main_cat(code, MSG_CAT_WARNING) 134 | #define MSG_CAT_RED(code) silgy_is_msg_main_cat(code, MSG_CAT_ERROR) 135 | 136 | #define OUT_MSG_DESCRIPTION(code) lib_send_msg_description(ci, code) 137 | 138 | #define OUT_HTML_HEADER lib_out_html_header(ci) 139 | #define OUT_HTML_FOOTER lib_out_html_footer(ci) 140 | #define OUT_SNIPPET(name) lib_out_snippet(ci, name) 141 | 142 | 143 | /* strings */ 144 | 145 | #ifndef STRINGS_SEP 146 | #define STRINGS_SEP '|' 147 | #endif 148 | 149 | #ifndef STRINGS_LANG 150 | #define STRINGS_LANG "EN-US" 151 | #endif 152 | 153 | #ifndef MAX_STR_LEN 154 | #define MAX_STR_LEN 255 155 | #endif 156 | 157 | #ifndef MAX_STRINGS 158 | #define MAX_STRINGS 1000 159 | #endif 160 | 161 | typedef struct { 162 | char lang[LANG_LEN+1]; 163 | char string_upper[MAX_STR_LEN+1]; 164 | char string_in_lang[MAX_STR_LEN+1]; 165 | } string_t; 166 | 167 | 168 | 169 | /* format amount */ 170 | 171 | #define AMT(val) silgy_amt(val) 172 | 173 | 174 | 175 | /* REST calls */ 176 | 177 | #define REST_HEADER_KEY_LEN 255 178 | #define REST_HEADER_VAL_LEN 1023 179 | 180 | typedef struct { 181 | char key[REST_HEADER_KEY_LEN+1]; 182 | char value[REST_HEADER_VAL_LEN+1]; 183 | } rest_header_t; 184 | 185 | 186 | #define REST_MAX_HEADERS 100 187 | #define REST_HEADERS_RESET lib_rest_headers_reset() 188 | #define REST_HEADER_SET(key, val) lib_rest_header_set(key, val) 189 | #define REST_HEADER_UNSET(key) lib_rest_header_unset(key) 190 | 191 | 192 | #ifdef JSON_NO_AUTO_AMPERSANDS 193 | #define CALL_REST_HTTP(req, res, method, url, keep) lib_rest_req(req, res, method, url, FALSE, keep) 194 | #define CALL_REST_JSON(req, res, method, url, keep) lib_rest_req(req, res, method, url, TRUE, keep) 195 | #else 196 | #define CALL_REST_HTTP(req, res, method, url, keep) lib_rest_req((char*)req, (char*)res, method, url, FALSE, keep) 197 | #define CALL_REST_JSON(req, res, method, url, keep) lib_rest_req(&req, &res, method, url, TRUE, keep) 198 | #endif 199 | 200 | /* aliases -- highest level -- 'keep' always TRUE */ 201 | #define CALL_REST_RAW(req, res, method, url) CALL_REST_HTTP(req, res, method, url, TRUE) 202 | #define CALL_HTTP(req, res, method, url) CALL_REST_HTTP(req, res, method, url, TRUE) 203 | #define CALL_REST(req, res, method, url) CALL_REST_JSON(req, res, method, url, TRUE) 204 | 205 | 206 | #define CALL_REST_DEFAULT_TIMEOUT 10000 /* in ms -- to avoid blocking forever */ 207 | 208 | #define REST_RES_HEADER_LEN 4095 209 | #define REST_ADDRESSES_CACHE_SIZE 100 210 | 211 | 212 | #define CALL_HTTP_STATUS G_rest_status 213 | #define CALL_REST_STATUS CALL_HTTP_STATUS 214 | #define CALL_HTTP_CONTENT_TYPE G_rest_content_type 215 | #define CALL_REST_CONTENT_TYPE CALL_HTTP_CONTENT_TYPE 216 | #define CALL_HTTP_STATUS_OK (G_rest_status>=200 && G_rest_status<=204) 217 | #define CALL_REST_STATUS_OK CALL_HTTP_STATUS_OK 218 | 219 | 220 | /* JSON */ 221 | 222 | #define JSON_STRING 0 223 | #define JSON_INTEGER 1 224 | #define JSON_FLOAT 2 225 | #define JSON_DOUBLE 3 226 | #define JSON_BOOL 4 227 | #define JSON_RECORD 5 228 | #define JSON_ARRAY 6 229 | 230 | #ifndef JSON_KEY_LEN 231 | #define JSON_KEY_LEN 31 232 | #endif 233 | #ifndef JSON_VAL_LEN 234 | #define JSON_VAL_LEN 255 235 | #endif 236 | 237 | #ifdef APP_JSON_MAX_ELEMS /* in one JSON struct */ 238 | #define JSON_MAX_ELEMS APP_JSON_MAX_ELEMS 239 | #else 240 | #define JSON_MAX_ELEMS 10 241 | #endif 242 | 243 | #ifdef APP_JSON_MAX_LEVELS 244 | #define JSON_MAX_LEVELS APP_JSON_MAX_LEVELS 245 | #else 246 | #ifdef MEM_TINY 247 | #define JSON_MAX_LEVELS 2 248 | #else 249 | #define JSON_MAX_LEVELS 4 250 | #endif 251 | #endif /* APP_JSON_MAX_LEVELS */ 252 | 253 | #ifdef MEM_TINY 254 | #define JSON_POOL_SIZE 100 /* for storing sub-JSONs */ 255 | #else 256 | #define JSON_POOL_SIZE 1000 /* for storing sub-JSONs */ 257 | #endif 258 | 259 | 260 | /* single JSON element */ 261 | 262 | typedef struct { 263 | char name[JSON_KEY_LEN+1]; 264 | char value[JSON_VAL_LEN+1]; 265 | char type; 266 | } json_elem_t; 267 | 268 | /* JSON object */ 269 | 270 | typedef struct { 271 | int cnt; 272 | char array; 273 | json_elem_t rec[JSON_MAX_ELEMS]; 274 | } json_t; 275 | 276 | typedef json_t JSON; 277 | 278 | 279 | #define JSON_MAX_FLOAT_LEN 8 280 | 281 | 282 | #ifdef APP_JSON_BUFSIZE 283 | #define JSON_BUFSIZE APP_JSON_BUFSIZE 284 | #else 285 | #define JSON_BUFSIZE 65568 286 | #endif 287 | 288 | 289 | #ifdef JSON_NO_AUTO_AMPERSANDS 290 | 291 | #define JSON_TO_STRING(json) lib_json_to_string(json) 292 | #define JSON_TO_STRING_PRETTY(json) lib_json_to_string_pretty(json) 293 | #define JSON_FROM_STRING(json, str) lib_json_from_string(json, str, 0, 0) 294 | 295 | 296 | #define JSON_ADD_STR(json, name, val) lib_json_add(json, name, val, 0, 0, 0, JSON_STRING, -1) 297 | #define JSON_ADD_STR_A(json, i, val) lib_json_add(json, NULL, val, 0, 0, 0, JSON_STRING, i) 298 | #define JSON_ADD_INT(json, name, val) lib_json_add(json, name, NULL, val, 0, 0, JSON_INTEGER, -1) 299 | #define JSON_ADD_INT_A(json, i, val) lib_json_add(json, NULL, NULL, val, 0, 0, JSON_INTEGER, i) 300 | #define JSON_ADD_FLOAT(json, name, val) lib_json_add(json, name, NULL, 0, val, 0, JSON_FLOAT, -1) 301 | #define JSON_ADD_FLOAT_A(json, i, val) lib_json_add(json, NULL, NULL, 0, val, 0, JSON_FLOAT, i) 302 | #define JSON_ADD_DOUBLE(json, name, val) lib_json_add(json, name, NULL, 0, 0, val, JSON_DOUBLE, -1) 303 | #define JSON_ADD_DOUBLE_A(json, i, val) lib_json_add(json, NULL, NULL, 0, 0, val, JSON_DOUBLE, i) 304 | #define JSON_ADD_BOOL(json, name, val) lib_json_add(json, name, NULL, val, 0, 0, JSON_BOOL, -1) 305 | #define JSON_ADD_BOOL_A(json, i, val) lib_json_add(json, NULL, NULL, val, 0, 0, JSON_BOOL, i) 306 | 307 | #define JSON_ADD_RECORD(json, name, val) lib_json_add_record(json, name, val, FALSE, -1) 308 | #define JSON_ADD_RECORD_A(json, i ,val) lib_json_add_record(json, NULL, val, FALSE, i) 309 | 310 | #define JSON_ADD_ARRAY(json, name, val) lib_json_add_record(json, name, val, TRUE, -1) 311 | #define JSON_ADD_ARRAY_A(json, i, val) lib_json_add_record(json, NULL, val, TRUE, i) 312 | 313 | #define JSON_PRESENT(json, name) lib_json_present(json, name) 314 | 315 | #define JSON_GET_STR(json, name) lib_json_get_str(json, name, -1) 316 | #define JSON_GET_STR_A(json, i) lib_json_get_str(json, NULL, i) 317 | #define JSON_GET_INT(json, name) lib_json_get_int(json, name, -1) 318 | #define JSON_GET_INT_A(json, i) lib_json_get_int(json, NULL, i) 319 | #define JSON_GET_FLOAT(json, name) lib_json_get_float(json, name, -1) 320 | #define JSON_GET_FLOAT_A(json, i) lib_json_get_float(json, NULL, i) 321 | #define JSON_GET_DOUBLE(json, name) lib_json_get_double(json, name, -1) 322 | #define JSON_GET_DOUBLE_A(json, i) lib_json_get_double(json, NULL, i) 323 | #define JSON_GET_BOOL(json, name) lib_json_get_bool(json, name, -1) 324 | #define JSON_GET_BOOL_A(json, i) lib_json_get_bool(json, NULL, i) 325 | 326 | #define JSON_GET_RECORD(json, name, val) lib_json_get_record(json, name, val, -1) 327 | #define JSON_GET_RECORD_A(json, i, val) lib_json_get_record(json, NULL, val, i) 328 | 329 | #define JSON_GET_ARRAY(json, name, val) lib_json_get_record(json, name, val, -1) 330 | #define JSON_GET_ARRAY_A(json, i, val) lib_json_get_record(json, NULL, val, i) 331 | 332 | 333 | #define JSON_RESET(json) lib_json_reset(json) 334 | #define JSON_COUNT(json) json.cnt 335 | 336 | #define JSON_LOG_DBG(json, name) lib_json_log_dbg(json, name) 337 | #define JSON_LOG_INF(json, name) lib_json_log_inf(json, name) 338 | 339 | #else /* JSON_NO_AUTO_AMPERSANDS not defined */ 340 | 341 | #define JSON_TO_STRING(json) lib_json_to_string(&json) 342 | #define JSON_TO_STRING_PRETTY(json) lib_json_to_string_pretty(&json) 343 | #define JSON_FROM_STRING(json, str) lib_json_from_string(&json, str, 0, 0) 344 | 345 | 346 | #define JSON_ADD_STR(json, name, val) lib_json_add(&json, name, val, 0, 0, 0, JSON_STRING, -1) 347 | #define JSON_ADD_STR_A(json, i, val) lib_json_add(&json, NULL, val, 0, 0, 0, JSON_STRING, i) 348 | #define JSON_ADD_INT(json, name, val) lib_json_add(&json, name, NULL, val, 0, 0, JSON_INTEGER, -1) 349 | #define JSON_ADD_INT_A(json, i, val) lib_json_add(&json, NULL, NULL, val, 0, 0, JSON_INTEGER, i) 350 | #define JSON_ADD_FLOAT(json, name, val) lib_json_add(&json, name, NULL, 0, val, 0, JSON_FLOAT, -1) 351 | #define JSON_ADD_FLOAT_A(json, i, val) lib_json_add(&json, NULL, NULL, 0, val, 0, JSON_FLOAT, i) 352 | #define JSON_ADD_DOUBLE(json, name, val) lib_json_add(&json, name, NULL, 0, 0, val, JSON_DOUBLE, -1) 353 | #define JSON_ADD_DOUBLE_A(json, i, val) lib_json_add(&json, NULL, NULL, 0, 0, val, JSON_DOUBLE, i) 354 | #define JSON_ADD_BOOL(json, name, val) lib_json_add(&json, name, NULL, val, 0, 0, JSON_BOOL, -1) 355 | #define JSON_ADD_BOOL_A(json, i, val) lib_json_add(&json, NULL, NULL, val, 0, 0, JSON_BOOL, i) 356 | 357 | #define JSON_ADD_RECORD(json, name, val) lib_json_add_record(&json, name, &val, FALSE, -1) 358 | #define JSON_ADD_RECORD_A(json, i, val) lib_json_add_record(&json, NULL, &val, FALSE, i) 359 | 360 | #define JSON_ADD_ARRAY(json, name, val) lib_json_add_record(&json, name, &val, TRUE, -1) 361 | #define JSON_ADD_ARRAY_A(json, i, val) lib_json_add_record(&json, NULL, &val, TRUE, i) 362 | 363 | #define JSON_PRESENT(json, name) lib_json_present(&json, name) 364 | 365 | #define JSON_GET_STR(json, name) lib_json_get_str(&json, name, -1) 366 | #define JSON_GET_STR_A(json, i) lib_json_get_str(&json, NULL, i) 367 | #define JSON_GET_INT(json, name) lib_json_get_int(&json, name, -1) 368 | #define JSON_GET_INT_A(json, i) lib_json_get_int(&json, NULL, i) 369 | #define JSON_GET_FLOAT(json, name) lib_json_get_float(&json, name, -1) 370 | #define JSON_GET_FLOAT_A(json, i) lib_json_get_float(&json, NULL, i) 371 | #define JSON_GET_DOUBLE(json, name) lib_json_get_double(&json, name, -1) 372 | #define JSON_GET_DOUBLE_A(json, i) lib_json_get_double(&json, NULL, i) 373 | #define JSON_GET_BOOL(json, name) lib_json_get_bool(&json, name, -1) 374 | #define JSON_GET_BOOL_A(json, i) lib_json_get_bool(&json, NULL, i) 375 | 376 | #define JSON_GET_RECORD(json, name, val) lib_json_get_record(&json, name, &val, -1) 377 | #define JSON_GET_RECORD_A(json, i, val) lib_json_get_record(&json, NULL, &val, i) 378 | 379 | #define JSON_GET_ARRAY(json, name, val) lib_json_get_record(&json, name, &val, -1) 380 | #define JSON_GET_ARRAY_A(json, i, val) lib_json_get_record(&json, NULL, &val, i) 381 | 382 | 383 | #define JSON_RESET(json) lib_json_reset(&json) 384 | #define JSON_COUNT(json) json.cnt 385 | 386 | #define JSON_LOG_DBG(json, name) lib_json_log_dbg(&json, name) 387 | #define JSON_LOG_INF(json, name) lib_json_log_inf(&json, name) 388 | 389 | #endif /* JSON_NO_AUTO_AMPERSANDS */ 390 | 391 | 392 | /* for backward compatibility */ 393 | #define silgy_read_param(param, val) silgy_read_param_str(param, val) 394 | 395 | 396 | #define AI_USERS_ALL 0 /* all users */ 397 | #define AI_USERS_YAU 1 /* yearly active */ 398 | #define AI_USERS_MAU 2 /* monthly active */ 399 | #define AI_USERS_DAU 3 /* daily active */ 400 | 401 | 402 | #ifdef __cplusplus 403 | extern "C" { 404 | #endif 405 | void silgy_lib_init(void); 406 | void silgy_lib_done(void); 407 | void silgy_safe_copy(char *dst, const char *src, size_t dst_len); 408 | char *silgy_render_md(char *dest, const char *src, size_t len); 409 | char *silgy_json_enc(const char *src); 410 | bool lib_csrft_ok(int ci); 411 | void silgy_add_message(int code, const char *lang, const char *message, ...); 412 | int compare_messages(const void *a, const void *b); 413 | void sort_messages(void); 414 | char *lib_get_message(int ci, int code); 415 | bool silgy_is_msg_main_cat(int code, const char *cat); 416 | void silgy_add_string(const char *lang, const char *str, const char *str_lang); 417 | const char *lib_get_string(int ci, const char *str); 418 | char *urlencode(const char *src); 419 | bool lib_open_db(void); 420 | void lib_close_db(void); 421 | bool lib_file_exists(const char *fname); 422 | void lib_get_exec_name(char *dst, const char *path); 423 | void lib_update_time_globals(void); 424 | bool read_snippets(bool first_scan, const char *path); 425 | void lib_out_snippet(int ci, const char *name); 426 | void lib_setnonblocking(int sock); 427 | void lib_out_html_header(int ci); 428 | void lib_out_html_footer(int ci); 429 | void lib_append_css(int ci, const char *fname, bool first); 430 | void lib_append_script(int ci, const char *fname, bool first); 431 | char *uri_decode(char *src, int srclen, char *dest, int maxlen); 432 | bool get_qs_param(int ci, const char *fieldname, char *retbuf, int maxlen, char esc_type); 433 | bool get_qs_param_raw(int ci, const char *fieldname, char *retbuf, int maxlen); 434 | char *get_qs_param_multipart(int ci, const char *fieldname, unsigned *retlen, char *retfname); 435 | bool lib_qsi(int ci, const char *fieldname, int *retbuf); 436 | bool lib_qsf(int ci, const char *fieldname, float *retbuf); 437 | bool lib_qsd(int ci, const char *fieldname, double *retbuf); 438 | bool lib_qsb(int ci, const char *fieldname, bool *retbuf); 439 | void lib_set_res_status(int ci, int status); 440 | void lib_res_header(int ci, const char *hdr, const char *val); 441 | void lib_set_res_content_type(int ci, const char *str); 442 | void lib_set_res_location(int ci, const char *str, ...); 443 | void lib_set_res_content_disposition(int ci, const char *str, ...); 444 | void lib_send_msg_description(int ci, int code); 445 | void silgy_admin_info(int ci, int users, admin_info_t ai[], int ai_cnt, bool header_n_footer); 446 | void lib_rest_headers_reset(void); 447 | void lib_rest_header_set(const char *key, const char *value); 448 | void lib_rest_header_unset(const char *key); 449 | bool lib_rest_req(const void *req, void *res, const char *method, const char *url, bool json, bool keep); 450 | int lib_finish_with_timeout(int sock, char oper, char readwrite, char *buffer, int len, int *msec, void *ssl, int level); 451 | void log_ssl_error(int ssl_err); 452 | void lib_get_app_dir(void); 453 | double lib_elapsed(struct timespec *start); 454 | int lib_get_memory(void); 455 | void lib_log_memory(void); 456 | char *silgy_filter_strict(const char *src); 457 | char *lib_add_spaces(const char *src, int len); 458 | char *lib_add_lspaces(const char *src, int len); 459 | char *get_file_ext(const char *fname); 460 | char get_res_type(const char *fname); 461 | void date_str2rec(const char *str, date_t *rec); 462 | void date_rec2str(char *str, date_t *rec); 463 | time_t time_http2epoch(const char *str); 464 | time_t time_db2epoch(const char *str); 465 | char *time_epoch2http(time_t epoch); 466 | void lib_set_datetime_formats(const char *lang); 467 | char *silgy_amt(double val); 468 | void amt(char *stramt, long long in_amt); 469 | void amtd(char *stramt, double in_amt); 470 | void lib_amt(char *stramt, long in_amt); 471 | void lib_amtd(char *stramt, double in_amt); 472 | void samts(char *stramt, const char *in_amt); 473 | void lib_normalize_float(char *str); 474 | void ftm(char *strtm, long in_tm); 475 | char *fmt_date(short year, short month, short day); 476 | char const *san(const char *str); 477 | char *san_long(const char *str); 478 | char *silgy_sql_esc(const char *str); 479 | char *silgy_html_esc(const char *str); 480 | void sanitize_sql(char *dst, const char *str, int len); 481 | void sanitize_html(char *dst, const char *str, int len); 482 | char *silgy_html_unesc(const char *str); 483 | char *uri_encode(const char *str); 484 | char *upper(const char *str); 485 | char *stp_right(char *str); 486 | bool strdigits(const char *src); 487 | char *nospaces(char *dst, const char *src); 488 | void init_random_numbers(void); 489 | void silgy_random(char *dest, int len); 490 | void msleep(int msec); 491 | void lib_json_reset(JSON *json); 492 | char *lib_json_to_string(JSON *json); 493 | char *lib_json_to_string_pretty(JSON *json); 494 | bool lib_json_from_string(JSON *json, const char *src, int len, int level); 495 | bool lib_json_add(JSON *json, const char *name, const char *str_value, int int_value, float flo_value, double dbl_value, char type, int i); 496 | bool lib_json_add_record(JSON *json, const char *name, JSON *json_sub, bool is_array, int i); 497 | bool lib_json_get(JSON *json, const char *name, char *str_value, int *num_value, char type); 498 | bool lib_json_present(JSON *json, const char *name); 499 | char *lib_json_get_str(JSON *json, const char *name, int i); 500 | int lib_json_get_int(JSON *json, const char *name, int i); 501 | float lib_json_get_float(JSON *json, const char *name, int i); 502 | double lib_json_get_double(JSON *json, const char *name, int i); 503 | bool lib_json_get_bool(JSON *json, const char *name, int i); 504 | bool lib_json_get_record(JSON *json, const char *name, JSON *json_sub, int i); 505 | void lib_json_log_dbg(JSON *json, const char *name); 506 | void lib_json_log_inf(JSON *json, const char *name); 507 | void get_byteorder(void); 508 | time_t db2epoch(const char *str); 509 | bool silgy_email(const char *to, const char *subject, const char *message); 510 | bool silgy_email_attach(const char *to, const char *subject, const char *message, const char *att_name, const char *att_data, int att_data_len); 511 | int silgy_minify(char *dest, const char *src); 512 | void date_inc(char *str, int days, int *dow); 513 | int date_cmp(const char *str1, const char *str2); 514 | bool lib_read_conf(const char *file); 515 | bool silgy_read_param_str(const char *param, char *dest); 516 | bool silgy_read_param_int(const char *param, int *dest); 517 | char *lib_create_pid_file(const char *name); 518 | char *lib_shm_create(unsigned bytes, int index); 519 | void lib_shm_delete(int index); 520 | bool log_start(const char *prefix, bool test); 521 | void log_write_time(int level, const char *message, ...); 522 | void log_write(int level, const char *message, ...); 523 | void log_long(const char *str, int len, const char *desc); 524 | void log_flush(void); 525 | void log_finish(void); 526 | #ifdef ICONV 527 | char *silgy_convert(const char *src, const char *cp_from, const char *cp_to); 528 | #endif 529 | 530 | char *md5(const char* str); 531 | 532 | int Base64encode_len(int len); 533 | int Base64encode(char *coded_dst, const char *plain_src, int len_plain_src); 534 | int Base64decode_len(const char *coded_src); 535 | int Base64decode(char *plain_dst, const char *coded_src); 536 | 537 | #ifdef _WIN32 /* Windows */ 538 | int getpid(void); 539 | int clock_gettime_win(struct timespec *spec); 540 | char *stpcpy(char *dest, const char *src); 541 | char *stpncpy(char *dest, const char *src, size_t len); 542 | #endif /* _WIN32 */ 543 | 544 | #ifndef strnstr 545 | char *strnstr(const char *haystack, const char *needle, size_t len); 546 | #endif 547 | 548 | #ifdef __cplusplus 549 | } // extern "C" 550 | #endif 551 | 552 | 553 | #include 554 | 555 | #ifdef __cplusplus 556 | extern "C" { 557 | #endif 558 | 559 | typedef struct { 560 | uint32_t state[5]; 561 | uint32_t count[2]; 562 | uint8_t buffer[64]; 563 | } SHA1_CTX; 564 | 565 | #define SHA1_DIGEST_SIZE 20 566 | 567 | void libSHA1(unsigned char *ptr, unsigned int size, unsigned char *outbuf); 568 | 569 | void digest_to_hex(const uint8_t digest[SHA1_DIGEST_SIZE], char *output); 570 | 571 | 572 | #ifdef __cplusplus 573 | } 574 | #endif 575 | 576 | #endif /* SILGY_LIB_H */ 577 | -------------------------------------------------------------------------------- /lib/silgy.h: -------------------------------------------------------------------------------- 1 | /* -------------------------------------------------------------------------- 2 | Silgy Web App Engine 3 | Jurek Muszynski 4 | silgy.com 5 | Started: August 2015 6 | -------------------------------------------------------------------------- */ 7 | 8 | #ifndef SILGY_H 9 | #define SILGY_H 10 | 11 | #ifdef _WIN32 /* Windows */ 12 | #ifdef _MSC_VER /* Microsoft compiler */ 13 | /* libraries */ 14 | #pragma comment(lib, "ws2_32.lib") 15 | #pragma comment(lib, "psapi.lib") /* GetProcessMemoryInfo */ 16 | /* __VA_ARGS__ issue */ 17 | #define EXPAND_VA(x) x 18 | /* access function */ 19 | #define F_OK 0 /* test for existence of file */ 20 | #define X_OK 0x01 /* test for execute or search permission */ 21 | #define W_OK 0x02 /* test for write permission */ 22 | #define R_OK 0x04 /* test for read permission */ 23 | #endif /* _MSC_VER */ 24 | #undef _WIN32_WINNT 25 | #define _WIN32_WINNT 0x0501 /* Windows XP or higher required */ 26 | #include 27 | #include 28 | #include 29 | #define CLOCK_MONOTONIC 0 /* dummy */ 30 | #undef OUT 31 | #endif /* _WIN32 */ 32 | 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | 41 | #ifndef _WIN32 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #endif /* _WIN32 */ 50 | 51 | #include 52 | #include 53 | #include 54 | 55 | #ifdef __cplusplus 56 | #include 57 | #include 58 | #else /* C */ 59 | #include 60 | typedef char bool; 61 | #define false ((char)0) 62 | #define true ((char)1) 63 | #endif /* __cplusplus */ 64 | 65 | 66 | #define WEB_SERVER_VERSION "4.5.6" 67 | /* alias */ 68 | #define SILGY_VERSION WEB_SERVER_VERSION 69 | 70 | 71 | #ifndef FALSE 72 | #define FALSE false 73 | #endif 74 | #ifndef TRUE 75 | #define TRUE true 76 | #endif 77 | 78 | 79 | /* pure C string type */ 80 | 81 | typedef char str1k[1024]; 82 | typedef char str2k[1024*2]; 83 | typedef char str4k[1024*4]; 84 | typedef char str8k[1024*8]; 85 | typedef char str16k[1024*16]; 86 | typedef char str32k[1024*32]; 87 | typedef char str64k[1024*64]; 88 | typedef char str128k[1024*128]; 89 | typedef char str256k[1024*256]; 90 | 91 | 92 | #define OK 0 93 | #define SUCCEED OK 94 | #define FAIL -1 95 | 96 | #define EOS ((char)0) /* End Of String */ 97 | 98 | 99 | /* log levels */ 100 | 101 | #define LOG_ALWAYS 0 /* print always */ 102 | #define LOG_ERR 1 /* print errors only */ 103 | #define LOG_WAR 2 /* print errors and warnings */ 104 | #define LOG_INF 3 /* print errors and warnings and info */ 105 | #define LOG_DBG 4 /* for debug mode -- most detailed */ 106 | 107 | 108 | #define MAX_URI_VAL_LEN 255 /* max value length received in URI -- sufficient for 99% cases */ 109 | #define MAX_LONG_URI_VAL_LEN 65535 /* max long value length received in URI -- 64 kB - 1 B */ 110 | 111 | #define QSBUF MAX_URI_VAL_LEN+1 112 | #define QS_BUF QSBUF 113 | 114 | #define WEBSITE_LEN 63 115 | #define CONTENT_TYPE_LEN 63 116 | #define CONTENT_DISP_LEN 127 117 | 118 | #define LOGIN_LEN 30 119 | #define EMAIL_LEN 120 120 | #define UNAME_LEN 120 121 | #define PHONE_LEN 30 122 | #define ABOUT_LEN 250 123 | 124 | 125 | #define VIEW_DEFAULT '0' 126 | #define VIEW_DESKTOP '1' 127 | #define VIEW_MOBILE '2' 128 | 129 | 130 | #define SQLBUF 4096 /* SQL query buffer size */ 131 | 132 | 133 | 134 | /* UTF-8 */ 135 | 136 | #define CHAR_POUND "£" 137 | #define CHAR_COPYRIGHT "©" 138 | #define CHAR_N_ACUTE "ń" 139 | #define CHAR_DOWN_ARROWHEAD1 "˅" 140 | #define CHAR_LONG_DASH "—" 141 | #define CHAR_EURO "€" 142 | #define CHAR_UP "↑" 143 | #define CHAR_DOWN "↓" 144 | #define CHAR_MINUS "−" 145 | #define CHAR_VEL "∨" 146 | #define CHAR_VERTICAL_ELLIPSIS "⋮" 147 | #define CHAR_COUNTERSINK "⌵" 148 | #define CHAR_DOUBLE_TRIANGLE_U "⏫" 149 | #define CHAR_DOUBLE_TRIANGLE_D "⏬" 150 | #define CHAR_DOWN_TRIANGLE_B "▼" 151 | #define CHAR_DOWN_TRIANGLE_W "▽" 152 | #define CHAR_CLOSE "✕" 153 | #define CHAR_HEAVY_PLUS "➕" 154 | #define CHAR_HEAVY_MINUS "➖" 155 | #define CHAR_DOWN_ARROWHEAD2 "﹀" 156 | #define CHAR_FULLW_PLUS "+" 157 | #define CHAR_LESS_EQUAL "≤" 158 | #define CHAR_GREATER_EQUAL "≥" 159 | 160 | 161 | 162 | #include "silgy_app.h" 163 | 164 | 165 | /* select() vs poll() vs epoll() */ 166 | 167 | #ifdef _WIN32 168 | #define FD_MON_SELECT /* WSAPoll doesn't seem to be a reliable alternative */ 169 | #undef FD_MON_POLL 170 | #undef FD_MON_EPOLL 171 | #ifdef ASYNC 172 | #undef ASYNC 173 | #endif 174 | #else 175 | #ifndef FD_MON_SELECT 176 | #define FD_MON_POLL 177 | #endif 178 | #endif /* _WIN32 */ 179 | 180 | 181 | #ifdef SILGY_WATCHER 182 | #ifdef DBMYSQL 183 | #undef DBMYSQL 184 | #endif 185 | #ifdef USERS 186 | #undef USERS 187 | #endif 188 | #ifdef HTTPS 189 | #undef HTTPS 190 | #endif 191 | #endif /* SILGY_WATCHER */ 192 | 193 | 194 | #ifdef DBMYSQL 195 | #include 196 | #include 197 | #endif 198 | 199 | #ifdef HTTPS 200 | #include 201 | #include 202 | #endif 203 | 204 | 205 | /* request macros */ 206 | 207 | #define REQ_METHOD conn[ci].method 208 | #define REQ_GET (0==strcmp(conn[ci].method, "GET")) 209 | #define REQ_POST (0==strcmp(conn[ci].method, "POST")) 210 | #define REQ_PUT (0==strcmp(conn[ci].method, "PUT")) 211 | #define REQ_DELETE (0==strcmp(conn[ci].method, "DELETE")) 212 | #define REQ_OPTIONS (0==strcmp(conn[ci].method, "OPTIONS")) 213 | #define REQ_URI conn[ci].uri 214 | #define REQ_CONTENT_TYPE conn[ci].in_ctypestr 215 | #define REQ_DSK !conn[ci].mobile 216 | #define REQ_MOB conn[ci].mobile 217 | #define REQ_BOT conn[ci].bot 218 | #define REQ_LANG conn[ci].lang 219 | 220 | #define PROTOCOL (conn[ci].secure?"https":"http") 221 | #define COLON_POSITION (conn[ci].secure?5:4) 222 | 223 | 224 | /* defaults */ 225 | 226 | #ifndef MEM_TINY 227 | #ifndef MEM_MEDIUM 228 | #ifndef MEM_LARGE 229 | #ifndef MEM_XLARGE 230 | #ifndef MEM_XXLARGE 231 | #ifndef MEM_XXXLARGE 232 | #ifndef MEM_XXXXLARGE 233 | #ifndef MEM_SMALL 234 | #define MEM_SMALL /* default memory model */ 235 | #endif 236 | #endif 237 | #endif 238 | #endif 239 | #endif 240 | #endif 241 | #endif 242 | #endif 243 | 244 | #ifndef OUTFAST 245 | #ifndef OUTCHECK 246 | #define OUTCHECKREALLOC /* default output type */ 247 | #endif 248 | #endif 249 | 250 | #ifndef QS_DEF_SQL_ESCAPE 251 | #ifndef QS_DEF_DONT_ESCAPE 252 | #define QS_DEF_HTML_ESCAPE /* default query string security */ 253 | #endif 254 | #endif 255 | 256 | /* generate output as fast as possible */ 257 | 258 | #ifdef SILGY_SVC 259 | 260 | #ifdef OUTFAST 261 | #define OUTSS(str) (p_content = stpcpy(p_content, str)) 262 | #define OUT_BIN(data, len) (len=(len>G_async_res_data_size?G_async_res_data_size:len), memcpy(p_content, data, len), p_content += len) 263 | #elif defined (OUTCHECK) 264 | #define OUTSS(str) svc_out_check(str) 265 | #define OUT_BIN(data, len) (len=(len>G_async_res_data_size?G_async_res_data_size:len), memcpy(p_content, data, len), p_content += len) 266 | #else /* OUTCHECKREALLOC */ 267 | #define OUTSS(str) svc_out_check_realloc(str) 268 | #define OUT_BIN(data, len) svc_out_check_realloc_bin(data, len) 269 | #endif 270 | 271 | #else /* SILGY_APP */ 272 | 273 | #define HOUT(str) (conn[ci].p_header = stpcpy(conn[ci].p_header, str)) 274 | 275 | #ifdef OUTFAST 276 | #define OUTSS(str) (conn[ci].p_content = stpcpy(conn[ci].p_content, str)) 277 | #define OUT_BIN(data, len) (len=(len>OUT_BUFSIZE-OUT_HEADER_BUFSIZE?OUT_BUFSIZE-OUT_HEADER_BUFSIZE:len), memcpy(conn[ci].p_content, data, len), conn[ci].p_content += len) 278 | #else 279 | #ifdef OUTCHECK 280 | #define OUTSS(str) eng_out_check(ci, str) 281 | #define OUT_BIN(data, len) (len=(len>OUT_BUFSIZE-OUT_HEADER_BUFSIZE?OUT_BUFSIZE-OUT_HEADER_BUFSIZE:len), memcpy(conn[ci].p_content, data, len), conn[ci].p_content += len) 282 | #else /* OUTCHECKREALLOC */ 283 | #define OUTSS(str) eng_out_check_realloc(ci, str) 284 | #define OUT_BIN(data, len) eng_out_check_realloc_bin(ci, data, len) 285 | #endif 286 | #endif /* OUTFAST */ 287 | 288 | #endif /* SILGY_SVC */ 289 | 290 | #ifdef _MSC_VER /* Microsoft compiler */ 291 | #define OUT(...) (sprintf(G_tmp, EXPAND_VA(__VA_ARGS__)), OUTSS(G_tmp)) 292 | #else /* GCC */ 293 | #define OUTM(str, ...) (sprintf(G_tmp, str, __VA_ARGS__), OUTSS(G_tmp)) /* OUT with multiple args */ 294 | #define CHOOSE_OUT(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, NAME, ...) NAME /* single or multiple? */ 295 | #define OUT(...) CHOOSE_OUT(__VA_ARGS__, OUTM, OUTM, OUTM, OUTM, OUTM, OUTM, OUTM, OUTM, OUTM, OUTM, OUTM, OUTM, OUTM, OUTSS)(__VA_ARGS__) 296 | #endif /* _MSC_VER */ 297 | 298 | 299 | /* convenient & fast string building */ 300 | 301 | #define OUTP_BEGIN(buf) char *p4outp=buf 302 | 303 | #define OUTPS(str) (p4outp = stpcpy(p4outp, str)) 304 | 305 | #ifdef _MSC_VER /* Microsoft compiler */ 306 | #define OUTP(...) (sprintf(G_tmp, EXPAND_VA(__VA_ARGS__)), OUTPS(G_tmp)) 307 | #else /* GCC */ 308 | #define OUTPM(str, ...) (sprintf(G_tmp, str, __VA_ARGS__), OUTPS(G_tmp)) /* OUTP with multiple args */ 309 | #define CHOOSE_OUTP(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, NAME, ...) NAME /* single or multiple? */ 310 | #define OUTP(...) CHOOSE_OUTP(__VA_ARGS__, OUTPM, OUTPM, OUTPM, OUTPM, OUTPM, OUTPM, OUTPM, OUTPM, OUTPM, OUTPM, OUTPM, OUTPM, OUTPM, OUTPS)(__VA_ARGS__) 311 | #endif /* _MSC_VER */ 312 | 313 | #define OUTP_END *p4outp = EOS 314 | 315 | 316 | 317 | /* HTTP header -- resets respbuf! */ 318 | #define PRINT_HTTP_STATUS(val) (sprintf(G_tmp, "HTTP/1.1 %d %s\r\n", val, get_http_descr(val)), HOUT(G_tmp)) 319 | 320 | /* date */ 321 | #define PRINT_HTTP_DATE (sprintf(G_tmp, "Date: %s\r\n", M_resp_date), HOUT(G_tmp)) 322 | 323 | /* cache control */ 324 | #define PRINT_HTTP_CACHE_PUBLIC HOUT("Cache-Control: public, max-age=31536000\r\n") 325 | #define PRINT_HTTP_NO_CACHE HOUT("Cache-Control: private, must-revalidate, no-store, no-cache, max-age=0\r\n") 326 | #define PRINT_HTTP_EXPIRES_STATICS (sprintf(G_tmp, "Expires: %s\r\n", M_expires_stat), HOUT(G_tmp)) 327 | #define PRINT_HTTP_EXPIRES_GENERATED (sprintf(G_tmp, "Expires: %s\r\n", M_expires_gen), HOUT(G_tmp)) 328 | #define PRINT_HTTP_LAST_MODIFIED(str) (sprintf(G_tmp, "Last-Modified: %s\r\n", str), HOUT(G_tmp)) 329 | 330 | /* connection */ 331 | #define PRINT_HTTP_CONNECTION(ci) (sprintf(G_tmp, "Connection: %s\r\n", conn[ci].keep_alive?"keep-alive":"close"), HOUT(G_tmp)) 332 | 333 | /* vary */ 334 | #define PRINT_HTTP_VARY_DYN HOUT("Vary: Accept-Encoding, User-Agent\r\n") 335 | #define PRINT_HTTP_VARY_STAT HOUT("Vary: Accept-Encoding\r\n") 336 | #define PRINT_HTTP_VARY_UIR HOUT("Vary: Upgrade-Insecure-Requests\r\n") 337 | 338 | /* content language */ 339 | #define PRINT_HTTP_LANGUAGE HOUT("Content-Language: en-us\r\n") 340 | 341 | /* content length */ 342 | #define PRINT_HTTP_CONTENT_LEN(len) (sprintf(G_tmp, "Content-Length: %u\r\n", len), HOUT(G_tmp)) 343 | 344 | /* content encoding */ 345 | #define PRINT_HTTP_CONTENT_ENCODING_DEFLATE HOUT("Content-Encoding: deflate\r\n") 346 | 347 | /* Security ------------------------------------------------------------------ */ 348 | 349 | /* HSTS */ 350 | #ifndef HSTS_MAX_AGE 351 | #define HSTS_MAX_AGE 31536000 /* a year */ 352 | #endif 353 | #ifdef HSTS_INCLUDE_SUBDOMAINS 354 | #define PRINT_HTTP_HSTS (sprintf(G_tmp, "Strict-Transport-Security: max-age=%d; includeSubDomains\r\n", HSTS_MAX_AGE), HOUT(G_tmp)) 355 | #else 356 | #define PRINT_HTTP_HSTS (sprintf(G_tmp, "Strict-Transport-Security: max-age=%d\r\n", HSTS_MAX_AGE), HOUT(G_tmp)) 357 | #endif 358 | 359 | #ifdef HTTPS 360 | #ifndef NO_HSTS 361 | #if HSTS_MAX_AGE > 0 362 | #define HSTS_ON 363 | #endif 364 | #endif 365 | #endif 366 | 367 | /* cookie */ 368 | #ifdef HSTS_ON 369 | #define PRINT_HTTP_COOKIE_A(ci) (sprintf(G_tmp, "Set-Cookie: as=%s; %sHttpOnly\r\n", conn[ci].cookie_out_a, G_test?"":"secure; "), HOUT(G_tmp)) 370 | #define PRINT_HTTP_COOKIE_L(ci) (sprintf(G_tmp, "Set-Cookie: ls=%s; %sHttpOnly\r\n", conn[ci].cookie_out_l, G_test?"":"secure; "), HOUT(G_tmp)) 371 | #define PRINT_HTTP_COOKIE_A_EXP(ci) (sprintf(G_tmp, "Set-Cookie: as=%s; expires=%s; %sHttpOnly\r\n", conn[ci].cookie_out_a, conn[ci].cookie_out_a_exp, G_test?"":"secure; "), HOUT(G_tmp)) 372 | #define PRINT_HTTP_COOKIE_L_EXP(ci) (sprintf(G_tmp, "Set-Cookie: ls=%s; expires=%s; %sHttpOnly\r\n", conn[ci].cookie_out_l, conn[ci].cookie_out_l_exp, G_test?"":"secure; "), HOUT(G_tmp)) 373 | #else 374 | #define PRINT_HTTP_COOKIE_A(ci) (sprintf(G_tmp, "Set-Cookie: as=%s; HttpOnly\r\n", conn[ci].cookie_out_a), HOUT(G_tmp)) 375 | #define PRINT_HTTP_COOKIE_L(ci) (sprintf(G_tmp, "Set-Cookie: ls=%s; HttpOnly\r\n", conn[ci].cookie_out_l), HOUT(G_tmp)) 376 | #define PRINT_HTTP_COOKIE_A_EXP(ci) (sprintf(G_tmp, "Set-Cookie: as=%s; expires=%s; HttpOnly\r\n", conn[ci].cookie_out_a, conn[ci].cookie_out_a_exp), HOUT(G_tmp)) 377 | #define PRINT_HTTP_COOKIE_L_EXP(ci) (sprintf(G_tmp, "Set-Cookie: ls=%s; expires=%s; HttpOnly\r\n", conn[ci].cookie_out_l, conn[ci].cookie_out_l_exp), HOUT(G_tmp)) 378 | #endif 379 | 380 | /* framing */ 381 | #define PRINT_HTTP_SAMEORIGIN HOUT("X-Frame-Options: SAMEORIGIN\r\n") 382 | 383 | /* content type guessing */ 384 | #define PRINT_HTTP_NOSNIFF HOUT("X-Content-Type-Options: nosniff\r\n") 385 | 386 | /* identity */ 387 | #define PRINT_HTTP_SERVER HOUT("Server: Silgy\r\n") 388 | 389 | /* must be last! */ 390 | #define PRINT_HTTP_END_OF_HEADER HOUT("\r\n") 391 | 392 | 393 | #define OUT_HEADER_BUFSIZE 4096 /* response header buffer length */ 394 | 395 | 396 | #ifndef CUST_HDR_LEN 397 | #define CUST_HDR_LEN 255 398 | #endif 399 | 400 | #ifndef MAX_HOSTS /* M_hosts size */ 401 | #define MAX_HOSTS 10 402 | #endif 403 | 404 | #ifndef MAX_PAYLOAD_SIZE /* max incoming POST data length (16 MB) */ 405 | #define MAX_PAYLOAD_SIZE 16777216 406 | #endif 407 | 408 | #define MAX_LOG_STR_LEN 4095 /* max log string length */ 409 | #define MAX_METHOD_LEN 7 /* method length */ 410 | #define MAX_URI_LEN 2047 /* max request URI length */ 411 | #define MAX_LABEL_LEN 255 /* max request label length */ 412 | #define MAX_VALUE_LEN 255 /* max request value length */ 413 | #define MAX_RESOURCE_LEN 127 /* max resource's name length -- as a first part of URI */ 414 | #define MAX_RESOURCES 10000 /* for M_auth_levels */ 415 | 416 | /* mainly memory usage */ 417 | 418 | #ifdef MEM_TINY 419 | #define IN_BUFSIZE 4096 /* incoming request buffer length (4 kB) */ 420 | #define OUT_BUFSIZE 65536 /* initial HTTP response buffer length (64 kB) */ 421 | #define MAX_CONNECTIONS 10 /* max TCP connections */ 422 | #define MAX_SESSIONS 5 /* max user sessions */ 423 | #elif defined MEM_MEDIUM 424 | #define IN_BUFSIZE 8192 /* incoming request buffer length (8 kB) */ 425 | #define OUT_BUFSIZE 262144 /* initial HTTP response buffer length (256 kB) */ 426 | #define MAX_CONNECTIONS 200 /* max TCP connections (2 per user session) */ 427 | #define MAX_SESSIONS 100 /* max user sessions */ 428 | #elif defined MEM_LARGE 429 | #define IN_BUFSIZE 8192 /* incoming request buffer length (8 kB) */ 430 | #define OUT_BUFSIZE 262144 /* initial HTTP response buffer length (256 kB) */ 431 | #define MAX_CONNECTIONS 1000 /* max TCP connections */ 432 | #define MAX_SESSIONS 500 /* max user sessions */ 433 | #elif defined MEM_XLARGE 434 | #define IN_BUFSIZE 8192 /* incoming request buffer length (8 kB) */ 435 | #define OUT_BUFSIZE 262144 /* initial HTTP response buffer length (256 kB) */ 436 | #define MAX_CONNECTIONS 5000 /* max TCP connections */ 437 | #define MAX_SESSIONS 2500 /* max user sessions */ 438 | #elif defined MEM_XXLARGE 439 | #define IN_BUFSIZE 8192 /* incoming request buffer length (8 kB) */ 440 | #define OUT_BUFSIZE 262144 /* initial HTTP response buffer length (256 kB) */ 441 | #define MAX_CONNECTIONS 10000 /* max TCP connections */ 442 | #define MAX_SESSIONS 5000 /* max user sessions */ 443 | #elif defined MEM_XXXLARGE 444 | #define IN_BUFSIZE 8192 /* incoming request buffer length (8 kB) */ 445 | #define OUT_BUFSIZE 262144 /* initial HTTP response buffer length (256 kB) */ 446 | #define MAX_CONNECTIONS 20000 /* max TCP connections */ 447 | #define MAX_SESSIONS 10000 /* max user sessions */ 448 | #elif defined MEM_XXXXLARGE 449 | #define IN_BUFSIZE 8192 /* incoming request buffer length (8 kB) */ 450 | #define OUT_BUFSIZE 262144 /* initial HTTP response buffer length (256 kB) */ 451 | #define MAX_CONNECTIONS 50000 /* max TCP connections */ 452 | #define MAX_SESSIONS 25000 /* max user sessions */ 453 | #else /* MEM_SMALL -- default */ 454 | #define IN_BUFSIZE 8192 /* incoming request buffer length (8 kB) */ 455 | #define OUT_BUFSIZE 131072 /* initial HTTP response buffer length (128 kB) */ 456 | #define MAX_CONNECTIONS 20 /* max TCP connections */ 457 | #define MAX_SESSIONS 10 /* max user sessions */ 458 | #endif 459 | 460 | #ifndef TMP_BUFSIZE /* temporary string buffer size */ 461 | #define TMP_BUFSIZE OUT_BUFSIZE 462 | #endif 463 | 464 | #ifdef SILGY_SVC 465 | #undef MAX_CONNECTIONS 466 | #define MAX_CONNECTIONS 1 /* conn, uses & auses still as arrays to keep the same macros */ 467 | #undef MAX_SESSIONS 468 | #define MAX_SESSIONS 1 469 | #endif /* SILGY_SVC */ 470 | 471 | #ifdef FD_MON_SELECT 472 | #if MAX_CONNECTIONS > FD_SETSIZE-2 473 | #undef MAX_CONNECTIONS 474 | #define MAX_CONNECTIONS FD_SETSIZE-2 475 | #endif 476 | #endif /* FD_MON_SELECT */ 477 | 478 | #define CLOSING_SESSION_CI MAX_CONNECTIONS 479 | 480 | #ifndef CONN_TIMEOUT 481 | #define CONN_TIMEOUT 180 /* idle connection timeout in seconds */ 482 | #endif 483 | 484 | #ifndef USES_TIMEOUT 485 | #define USES_TIMEOUT 300 /* anonymous user session timeout in seconds */ 486 | #endif 487 | 488 | #define NOT_CONNECTED -1 489 | 490 | #define CONN_STATE_DISCONNECTED '0' 491 | #define CONN_STATE_ACCEPTING 'a' 492 | #define CONN_STATE_CONNECTED '1' 493 | #define CONN_STATE_READY_FOR_PARSE 'p' 494 | #define CONN_STATE_READY_FOR_PROCESS 'P' 495 | #define CONN_STATE_READING_DATA 'd' 496 | #define CONN_STATE_WAITING_FOR_ASYNC 'A' 497 | #define CONN_STATE_READY_TO_SEND_HEADER 'H' 498 | #define CONN_STATE_READY_TO_SEND_BODY 'B' 499 | #define CONN_STATE_SENDING_BODY 'S' 500 | 501 | #ifdef __linux__ 502 | #define MONOTONIC_CLOCK_NAME CLOCK_MONOTONIC_RAW 503 | #else 504 | #define MONOTONIC_CLOCK_NAME CLOCK_MONOTONIC 505 | #endif 506 | 507 | #define STR(str) lib_get_string(ci, str) 508 | 509 | #ifndef MAX_BLACKLIST 510 | #define MAX_BLACKLIST 10000 511 | #endif 512 | #ifndef MAX_WHITELIST 513 | #define MAX_WHITELIST 10000 514 | #endif 515 | 516 | #ifndef APP_WEBSITE 517 | #define APP_WEBSITE "Silgy Web Application" 518 | #endif 519 | #ifndef APP_DOMAIN 520 | #define APP_DOMAIN "" 521 | #endif 522 | #ifndef APP_VERSION 523 | #define APP_VERSION "1.0" 524 | #endif 525 | #ifndef APP_LOGIN_URI 526 | #define APP_LOGIN_URI "/login" 527 | #endif 528 | 529 | 530 | /* compression settings */ 531 | 532 | #ifndef COMPRESS_TRESHOLD 533 | #define COMPRESS_TRESHOLD 500 534 | #endif 535 | 536 | #ifndef COMPRESS_LEVEL 537 | #define COMPRESS_LEVEL Z_BEST_SPEED 538 | #endif 539 | 540 | #define SHOULD_BE_COMPRESSED(len, type) (len > COMPRESS_TRESHOLD && (type==RES_HTML || type==RES_TEXT || type==RES_JSON || type==RES_CSS || type==RES_JS || type==RES_SVG || type==RES_EXE || type==RES_BMP)) 541 | 542 | 543 | #ifdef APP_SESID_LEN 544 | #define SESID_LEN APP_SESID_LEN 545 | #else 546 | #define SESID_LEN 15 /* ~ 89 bits of entropy */ 547 | #endif 548 | 549 | #ifndef CSRFT_LEN 550 | #define CSRFT_LEN 7 551 | #endif 552 | 553 | #define LANG_LEN 5 554 | 555 | 556 | /* response caching */ 557 | 558 | #ifndef EXPIRES_STATICS 559 | #define EXPIRES_STATICS 90 /* days */ 560 | #endif 561 | 562 | #ifndef EXPIRES_GENERATED 563 | #define EXPIRES_GENERATED 30 /* days */ 564 | #endif 565 | 566 | 567 | /* authorization levels */ 568 | 569 | #define AUTH_LEVEL_NONE 0 /* no session */ 570 | #define AUTH_LEVEL_ANONYMOUS 1 /* anonymous session */ 571 | #define AUTH_LEVEL_LOGGED 2 /* logged in session with lowest authorization level */ 572 | #define AUTH_LEVEL_LOGGEDIN 2 573 | #define AUTH_LEVEL_USER 10 574 | #define AUTH_LEVEL_CUSTOMER 20 575 | #define AUTH_LEVEL_STAFF 30 576 | #define AUTH_LEVEL_MODERATOR 40 577 | #define AUTH_LEVEL_ADMIN 50 578 | #define AUTH_LEVEL_ROOT 100 579 | #define AUTH_LEVEL_NOBODY 125 /* for resources' whitelisting */ 580 | 581 | #ifndef DEF_RES_AUTH_LEVEL 582 | #define DEF_RES_AUTH_LEVEL AUTH_LEVEL_NONE /* default resource authorization level */ 583 | #endif 584 | 585 | 586 | /* errors */ 587 | 588 | /* 0 always means OK */ 589 | #define ERR_INVALID_REQUEST 1 590 | #define ERR_UNAUTHORIZED 2 591 | #define ERR_FORBIDDEN 3 592 | #define ERR_NOT_FOUND 4 593 | #define ERR_METHOD 5 594 | #define ERR_INT_SERVER_ERROR 6 595 | #define ERR_SERVER_TOOBUSY 7 596 | #define ERR_FILE_TOO_BIG 8 597 | #define ERR_REDIRECTION 9 598 | #define ERR_ASYNC_NO_SUCH_SERVICE 10 599 | #define ERR_ASYNC_TIMEOUT 11 600 | #define ERR_REMOTE_CALL 12 601 | #define ERR_REMOTE_CALL_STATUS 13 602 | #define ERR_REMOTE_CALL_DATA 14 603 | #define ERR_CSRFT 15 604 | #define ERR_RECORD_NOT_FOUND 16 605 | /* ------------------------------------- */ 606 | #define ERR_MAX_ENGINE_ERROR 99 607 | /* ------------------------------------- */ 608 | 609 | 610 | #define MSG_CAT_OK "OK" 611 | #define MSG_CAT_ERROR "err" 612 | #define MSG_CAT_WARNING "war" 613 | #define MSG_CAT_MESSAGE "msg" 614 | 615 | 616 | /* statics */ 617 | 618 | #define NOT_STATIC -1 619 | #ifdef APP_MAX_STATICS /* max static resources */ 620 | #define MAX_STATICS APP_MAX_STATICS 621 | #else 622 | #define MAX_STATICS 1000 623 | #endif 624 | 625 | #define STATIC_PATH_LEN 1024 626 | 627 | #define STATIC_SOURCE_INTERNAL 0 628 | #define STATIC_SOURCE_RES 1 629 | #define STATIC_SOURCE_RESMIN 2 630 | #define STATIC_SOURCE_SNIPPET 3 631 | 632 | #ifndef MAX_SNIPPETS 633 | #define MAX_SNIPPETS 1000 634 | #endif 635 | 636 | 637 | /* asynchronous calls */ 638 | 639 | #define ASYNC_STATE_FREE '0' 640 | #define ASYNC_STATE_SENT '1' 641 | #define ASYNC_STATE_RECEIVED '2' 642 | #define ASYNC_STATE_TIMEOUTED '3' 643 | 644 | 645 | #ifndef ASYNC_MQ_MAXMSG 646 | #define ASYNC_MQ_MAXMSG 10 /* max messages in a message queue */ 647 | #endif 648 | 649 | #ifndef MAX_ASYNC_REQS 650 | #define MAX_ASYNC_REQS MAX_SESSIONS /* max simultaneous async requests */ 651 | #endif 652 | 653 | #ifndef ASYNC_REQ_MSG_SIZE 654 | #define ASYNC_REQ_MSG_SIZE 8192 /* request message size */ 655 | #endif 656 | 657 | #ifndef ASYNC_RES_MSG_SIZE 658 | #define ASYNC_RES_MSG_SIZE 8192 /* response message size */ 659 | #endif 660 | 661 | #define ASYNC_REQ_QUEUE "/silgy_req" /* request queue name */ 662 | #define ASYNC_RES_QUEUE "/silgy_res" /* response queue name */ 663 | #define ASYNC_DEF_TIMEOUT 60 /* in seconds */ 664 | #define ASYNC_MAX_TIMEOUT 1800 /* in seconds ==> 30 minutes */ 665 | 666 | #define ASYNC_PAYLOAD_MSG 0 667 | #define ASYNC_PAYLOAD_SHM 1 668 | 669 | #define ASYNC_SHM_SIZE MAX_PAYLOAD_SIZE 670 | 671 | /* these are flags */ 672 | #define ASYNC_CHUNK_FIRST 0x040000 673 | #define ASYNC_CHUNK_LAST 0x080000 674 | #define ASYNC_CHUNK_IS_FIRST(n) ((n & ASYNC_CHUNK_FIRST) == ASYNC_CHUNK_FIRST) 675 | #define ASYNC_CHUNK_IS_LAST(n) ((n & ASYNC_CHUNK_LAST) == ASYNC_CHUNK_LAST) 676 | 677 | #ifdef SILGY_SVC 678 | #define SVC(svc) (0==strcmp(G_service, svc)) 679 | #define ASYNC_ERR_CODE G_error_code 680 | #else 681 | #define SVC(svc) (0==strcmp(conn[ci].service, svc)) 682 | #define ASYNC_ERR_CODE conn[ci].async_err_code 683 | #endif /* SILGY_SVC */ 684 | 685 | #ifdef ASYNC_USE_APP_CONTINUE /* the old way (temporarily) */ 686 | #define CALL_ASYNC(svc, data) eng_async_req(ci, svc, data, TRUE, G_ASYNCDefTimeout, 0) 687 | #define CALL_ASYNC_TM(svc, data, tmout) eng_async_req(ci, svc, data, TRUE, tmout, 0) 688 | #define CALL_ASYNC_NR(svc, data) eng_async_req(ci, svc, data, FALSE, 0, 0) 689 | #else 690 | #define CALL_ASYNC(svc) eng_async_req(ci, svc, NULL, TRUE, G_ASYNCDefTimeout, 0) 691 | #define CALL_ASYNC_TM(svc, tmout) eng_async_req(ci, svc, NULL, TRUE, tmout, 0) 692 | #define CALL_ASYNC_NR(svc) eng_async_req(ci, svc, NULL, FALSE, 0, 0) 693 | #endif /* ASYNC_USE_APP_CONTINUE */ 694 | 695 | #define CALL_ASYNC_BIN(svc, data, size) eng_async_req(ci, svc, data, TRUE, G_ASYNCDefTimeout, size) 696 | 697 | 698 | /* resource / content types */ 699 | 700 | /* incoming */ 701 | 702 | #define CONTENT_TYPE_URLENCODED 'U' 703 | #define CONTENT_TYPE_JSON 'J' 704 | #define CONTENT_TYPE_MULTIPART 'M' 705 | #define CONTENT_TYPE_OCTET_STREAM 'O' 706 | 707 | /* outgoing */ 708 | 709 | #define CONTENT_TYPE_UNSET '-' 710 | #define CONTENT_TYPE_USER '+' 711 | #define RES_TEXT 'T' 712 | #define RES_HTML 'H' 713 | #define RES_CSS 'C' 714 | #define RES_JS 'S' 715 | #define RES_GIF 'G' 716 | #define RES_JPG 'J' 717 | #define RES_ICO 'I' 718 | #define RES_PNG 'P' 719 | #define RES_BMP 'B' 720 | #define RES_SVG 'V' 721 | #define RES_JSON 'O' 722 | #define RES_PDF 'A' 723 | #define RES_AMPEG 'M' 724 | #define RES_EXE 'X' 725 | #define RES_ZIP 'Z' 726 | 727 | 728 | #define URI(uri) eng_is_uri(ci, uri) 729 | #define REQ(res) (0==strcmp(conn[ci].resource, res)) 730 | #define REQ0(res) (0==strcmp(conn[ci].resource, res)) 731 | #define REQ1(res) (0==strcmp(conn[ci].req1, res)) 732 | #define REQ2(res) (0==strcmp(conn[ci].req2, res)) 733 | #define REQ3(res) (0==strcmp(conn[ci].req3, res)) 734 | #define ID conn[ci].id 735 | #define US uses[conn[ci].usi] 736 | #define AUS auses[conn[ci].usi] 737 | #define HOST(str) (0==strcmp(conn[ci].host_normalized, upper(str))) 738 | #define REQ_GET_HEADER(header) eng_get_header(ci, header) 739 | 740 | #define REQ_DATA conn[ci].in_data 741 | 742 | #define REST_HEADER_PASS(header) eng_rest_header_pass(ci, header) 743 | 744 | 745 | /* response macros */ 746 | 747 | #define RES_STATUS(val) lib_set_res_status(ci, val) 748 | #define RES_CONTENT_TYPE(str) lib_set_res_content_type(ci, str) 749 | #define RES_LOCATION(str, ...) lib_set_res_location(ci, str, ##__VA_ARGS__) 750 | #define RES_REDIRECT(str, ...) RES_LOCATION(str, ##__VA_ARGS__) 751 | #define RES_DONT_CACHE conn[ci].dont_cache=TRUE 752 | #define RES_KEEP_CONTENT conn[ci].keep_content=TRUE 753 | #define RES_CONTENT_DISPOSITION(str, ...) lib_set_res_content_disposition(ci, str, ##__VA_ARGS__) 754 | 755 | #define REDIRECT_TO_LANDING sprintf(conn[ci].location, "%s://%s", PROTOCOL, conn[ci].host) 756 | 757 | #define APPEND_CSS(name, first) lib_append_css(ci, name, first) 758 | #define APPEND_SCRIPT(name, first) lib_append_script(ci, name, first) 759 | 760 | 761 | /* query string values' retrieval */ 762 | 763 | #define ESC_NONE (char)0 764 | #define ESC_SQL (char)1 765 | #define ESC_HTML (char)2 766 | 767 | #define QS_DONT_ESCAPE(param, val) get_qs_param(ci, param, val, MAX_URI_VAL_LEN, ESC_NONE) 768 | #define QS_SQL_ESCAPE(param, val) get_qs_param(ci, param, val, MAX_URI_VAL_LEN, ESC_SQL) 769 | #define QS_HTML_ESCAPE(param, val) get_qs_param(ci, param, val, MAX_URI_VAL_LEN, ESC_HTML) 770 | 771 | #define QS_TEXT_DONT_ESCAPE(param, val) get_qs_param(ci, param, val, 65535, ESC_NONE) 772 | #define QS_TEXT_SQL_ESCAPE(param, val) get_qs_param(ci, param, val, 65535, ESC_SQL) 773 | #define QS_TEXT_HTML_ESCAPE(param, val) get_qs_param(ci, param, val, 65535, ESC_HTML) 774 | 775 | #ifdef QS_DEF_HTML_ESCAPE 776 | #define QS(param, val) get_qs_param(ci, param, val, MAX_URI_VAL_LEN, ESC_HTML) 777 | #define QS1K(param, val) get_qs_param(ci, param, val, 1023, ESC_HTML) 778 | #define QS2K(param, val) get_qs_param(ci, param, val, 2047, ESC_HTML) 779 | #define QS4K(param, val) get_qs_param(ci, param, val, 4095, ESC_HTML) 780 | #define QS8K(param, val) get_qs_param(ci, param, val, 8191, ESC_HTML) 781 | #define QS16K(param, val) get_qs_param(ci, param, val, 16383, ESC_HTML) 782 | #define QS32K(param, val) get_qs_param(ci, param, val, 32767, ESC_HTML) 783 | #define QS64K(param, val) get_qs_param(ci, param, val, 65535, ESC_HTML) 784 | #define QS_TEXT(param, val) get_qs_param(ci, param, val, 65535, ESC_HTML) 785 | #endif 786 | #ifdef QS_DEF_SQL_ESCAPE 787 | #define QS(param, val) get_qs_param(ci, param, val, MAX_URI_VAL_LEN, ESC_SQL) 788 | #define QS1K(param, val) get_qs_param(ci, param, val, 1023, ESC_SQL) 789 | #define QS2K(param, val) get_qs_param(ci, param, val, 2047, ESC_SQL) 790 | #define QS4K(param, val) get_qs_param(ci, param, val, 4095, ESC_SQL) 791 | #define QS8K(param, val) get_qs_param(ci, param, val, 8191, ESC_SQL) 792 | #define QS16K(param, val) get_qs_param(ci, param, val, 16383, ESC_SQL) 793 | #define QS32K(param, val) get_qs_param(ci, param, val, 32767, ESC_SQL) 794 | #define QS64K(param, val) get_qs_param(ci, param, val, 65535, ESC_SQL) 795 | #define QS_TEXT(param, val) get_qs_param(ci, param, val, 65535, ESC_SQL) 796 | #endif 797 | #ifdef QS_DEF_DONT_ESCAPE 798 | #define QS(param, val) get_qs_param(ci, param, val, MAX_URI_VAL_LEN, ESC_NONE) 799 | #define QS1K(param, val) get_qs_param(ci, param, val, 1023, ESC_NONE) 800 | #define QS2K(param, val) get_qs_param(ci, param, val, 2047, ESC_NONE) 801 | #define QS4K(param, val) get_qs_param(ci, param, val, 4095, ESC_NONE) 802 | #define QS8K(param, val) get_qs_param(ci, param, val, 8191, ESC_NONE) 803 | #define QS16K(param, val) get_qs_param(ci, param, val, 16383, ESC_NONE) 804 | #define QS32K(param, val) get_qs_param(ci, param, val, 32767, ESC_NONE) 805 | #define QS64K(param, val) get_qs_param(ci, param, val, 65535, ESC_NONE) 806 | #define QS_TEXT(param, val) get_qs_param(ci, param, val, 65535, ESC_NONE) 807 | #endif 808 | 809 | #define QSI(param, val) lib_qsi(ci, param, val) 810 | #define QSF(param, val) lib_qsf(ci, param, val) 811 | #define QSD(param, val) lib_qsd(ci, param, val) 812 | #define QSB(param, val) lib_qsb(ci, param, val) 813 | 814 | 815 | #define SVC_NAME_LEN 63 /* async service name length */ 816 | 817 | 818 | //#define UA_IE (0==strcmp(conn[ci].uagent, "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko") || 0==strcmp(conn[ci].uagent, "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko")) 819 | #define UA_IE (0==strncmp(conn[ci].uagent, "Mozilla/5.0 (Windows NT ", 24) && strstr(conn[ci].uagent, "; WOW64; Trident/7.0; rv:11.0) like Gecko")) 820 | 821 | 822 | /* Date-Time */ 823 | 824 | //#define DT_NULL "2000-01-01 00:00:00" 825 | #define DT_NULL "0000-00-00 00:00:00" 826 | #define DT_NOW G_dt 827 | #define IS_DT_NULL(dt) (0==strcmp(dt, DT_NULL)) 828 | 829 | 830 | 831 | /* HTTP status */ 832 | 833 | typedef struct { 834 | int status; 835 | char description[128]; 836 | } http_status_t; 837 | 838 | 839 | /* date */ 840 | 841 | typedef struct { 842 | short year; 843 | char month; 844 | char day; 845 | } date_t; 846 | 847 | 848 | /* user session */ 849 | 850 | typedef struct { 851 | /* id */ 852 | char sesid[SESID_LEN+1]; 853 | /* connection data */ 854 | char ip[INET_ADDRSTRLEN]; 855 | char uagent[MAX_VALUE_LEN+1]; 856 | char referer[MAX_VALUE_LEN+1]; 857 | char lang[LANG_LEN+1]; 858 | bool logged; 859 | /* users table record */ 860 | int uid; 861 | char login[LOGIN_LEN+1]; 862 | char email[EMAIL_LEN+1]; 863 | char name[UNAME_LEN+1]; 864 | char phone[PHONE_LEN+1]; 865 | char tz[6]; 866 | char about[ABOUT_LEN+1]; 867 | int group_id; 868 | char auth_level; 869 | /* CSRF token */ 870 | char csrft[CSRFT_LEN+1]; 871 | /* internal */ 872 | time_t last_activity; 873 | } usession_t; 874 | 875 | 876 | #define CUSTOMER (US.auth_level==AUTH_LEVEL_CUSTOMER) 877 | #define STAFF (US.auth_level==AUTH_LEVEL_STAFF) 878 | #define MODERATOR (US.auth_level==AUTH_LEVEL_MODERATOR) 879 | #define ADMIN (US.auth_level==AUTH_LEVEL_ADMIN) 880 | #define ROOT (US.auth_level==AUTH_LEVEL_ROOT) 881 | 882 | #define LOGGED US.logged 883 | #define UID US.uid 884 | 885 | 886 | #define CSRFT_REFRESH silgy_random(US.csrft, CSRFT_LEN) 887 | #define CSRFT_OUT_INPUT OUT("", US.csrft) 888 | #define OUT_CSRFT CSRFT_OUT_INPUT 889 | #define CSRFT_OK lib_csrft_ok(ci) 890 | 891 | 892 | 893 | /* counters */ 894 | 895 | typedef struct { 896 | unsigned req; /* all parsed requests */ 897 | unsigned req_dsk; /* all requests with desktop UA */ 898 | unsigned req_mob; /* all requests with mobile UA */ 899 | unsigned req_bot; /* all requests with HTTP header indicating well-known search-engine bots */ 900 | unsigned visits; /* all visits to domain (Host=APP_DOMAIN) landing page (no action/resource), excl. bots that got 200 */ 901 | unsigned visits_dsk; /* like visits -- desktop only */ 902 | unsigned visits_mob; /* like visits -- mobile only */ 903 | unsigned blocked; /* attempts from blocked IP */ 904 | double elapsed; /* sum of elapsed time of all requests for calculating average */ 905 | double average; /* average request elapsed */ 906 | } counters_t; 907 | 908 | 909 | /* asynchorous processing */ 910 | 911 | /* request */ 912 | 913 | typedef struct { 914 | unsigned call_id; 915 | int ai; 916 | int ci; 917 | char service[SVC_NAME_LEN+1]; 918 | /* pass some request details over */ 919 | bool secure; 920 | char ip[INET_ADDRSTRLEN]; 921 | char method[MAX_METHOD_LEN+1]; 922 | bool post; 923 | char payload_location; 924 | char uri[MAX_URI_LEN+1]; 925 | char resource[MAX_RESOURCE_LEN+1]; 926 | char req1[MAX_RESOURCE_LEN+1]; 927 | char req2[MAX_RESOURCE_LEN+1]; 928 | char req3[MAX_RESOURCE_LEN+1]; 929 | char id[MAX_RESOURCE_LEN+1]; 930 | char uagent[MAX_VALUE_LEN+1]; 931 | bool mobile; 932 | char referer[MAX_VALUE_LEN+1]; 933 | unsigned clen; 934 | char host[MAX_VALUE_LEN+1]; 935 | char website[WEBSITE_LEN+1]; 936 | char lang[LANG_LEN+1]; 937 | char in_ctype; 938 | char boundary[MAX_VALUE_LEN+1]; 939 | char response; 940 | int status; 941 | char cust_headers[CUST_HDR_LEN+1]; 942 | char ctype; 943 | char ctypestr[CONTENT_TYPE_LEN+1]; 944 | char cdisp[CONTENT_DISP_LEN+1]; 945 | char cookie_out_a[SESID_LEN+1]; 946 | char cookie_out_a_exp[32]; 947 | char cookie_out_l[SESID_LEN+1]; 948 | char cookie_out_l_exp[32]; 949 | char location[MAX_URI_LEN+1]; 950 | bool dont_cache; 951 | bool keep_content; 952 | usession_t uses; 953 | #ifndef ASYNC_EXCLUDE_AUSES 954 | ausession_t auses; 955 | #endif 956 | counters_t cnts_today; 957 | counters_t cnts_yesterday; 958 | counters_t cnts_day_before; 959 | int days_up; 960 | int open_conn; 961 | int open_conn_hwm; 962 | int sessions; 963 | int sessions_hwm; 964 | char last_modified[32]; 965 | int blacklist_cnt; 966 | } async_req_hdr_t; 967 | 968 | typedef struct { 969 | async_req_hdr_t hdr; 970 | char data[ASYNC_REQ_MSG_SIZE-sizeof(async_req_hdr_t)]; 971 | } async_req_t; 972 | 973 | 974 | /* async requests stored on the silgy_app's side */ 975 | 976 | typedef struct { 977 | int ci; 978 | char state; 979 | time_t sent; 980 | int timeout; 981 | } areq_t; 982 | 983 | 984 | /* response -- the first chunk */ 985 | 986 | typedef struct { 987 | int err_code; 988 | int status; 989 | char cust_headers[CUST_HDR_LEN+1]; 990 | char ctype; 991 | char ctypestr[CONTENT_TYPE_LEN+1]; 992 | char cdisp[CONTENT_DISP_LEN+1]; 993 | char cookie_out_a[SESID_LEN+1]; 994 | char cookie_out_a_exp[32]; 995 | char cookie_out_l[SESID_LEN+1]; 996 | char cookie_out_l_exp[32]; 997 | char location[MAX_URI_LEN+1]; 998 | bool dont_cache; 999 | bool keep_content; 1000 | int rest_status; 1001 | unsigned rest_req; 1002 | double rest_elapsed; 1003 | usession_t uses; 1004 | #ifndef ASYNC_EXCLUDE_AUSES 1005 | ausession_t auses; 1006 | #endif 1007 | int invalidate_uid; 1008 | int invalidate_ci; 1009 | } async_res_hdr_t; 1010 | 1011 | typedef struct { 1012 | int ai; 1013 | int chunk; 1014 | int ci; 1015 | int len; 1016 | async_res_hdr_t hdr; 1017 | char data[ASYNC_RES_MSG_SIZE-sizeof(async_res_hdr_t)-sizeof(int)*4]; 1018 | } async_res_t; 1019 | 1020 | 1021 | /* response -- the second type for the chunks > 1 */ 1022 | 1023 | typedef struct { 1024 | int ai; 1025 | int chunk; 1026 | int ci; 1027 | int len; 1028 | char data[ASYNC_RES_MSG_SIZE-sizeof(int)*4]; 1029 | } async_res_data_t; 1030 | 1031 | 1032 | 1033 | /* connection */ 1034 | 1035 | #ifdef SILGY_SVC 1036 | typedef struct { /* request details for silgy_svc */ 1037 | bool secure; 1038 | char ip[INET_ADDRSTRLEN]; 1039 | char method[MAX_METHOD_LEN+1]; 1040 | bool post; 1041 | char uri[MAX_URI_LEN+1]; 1042 | char resource[MAX_RESOURCE_LEN+1]; 1043 | char req1[MAX_RESOURCE_LEN+1]; 1044 | char req2[MAX_RESOURCE_LEN+1]; 1045 | char req3[MAX_RESOURCE_LEN+1]; 1046 | char id[MAX_RESOURCE_LEN+1]; 1047 | char uagent[MAX_VALUE_LEN+1]; 1048 | bool mobile; 1049 | char referer[MAX_VALUE_LEN+1]; 1050 | unsigned clen; 1051 | char *in_data; 1052 | unsigned in_data_allocated; 1053 | char host[MAX_VALUE_LEN+1]; 1054 | char website[WEBSITE_LEN+1]; 1055 | char lang[LANG_LEN+1]; 1056 | char in_ctype; 1057 | char boundary[MAX_VALUE_LEN+1]; 1058 | int usi; 1059 | int status; 1060 | char cust_headers[CUST_HDR_LEN+1]; 1061 | char ctype; 1062 | char ctypestr[CONTENT_TYPE_LEN+1]; 1063 | char cdisp[CONTENT_DISP_LEN+1]; 1064 | char cookie_out_a[SESID_LEN+1]; 1065 | char cookie_out_a_exp[32]; 1066 | char cookie_out_l[SESID_LEN+1]; 1067 | char cookie_out_l_exp[32]; 1068 | char location[MAX_URI_LEN+1]; 1069 | bool dont_cache; 1070 | bool keep_content; 1071 | } conn_t; 1072 | #else /* not SILGY_SVC */ 1073 | typedef struct { 1074 | /* what comes in */ 1075 | #ifdef _WIN32 /* Windows */ 1076 | SOCKET fd; /* file descriptor */ 1077 | #else 1078 | int fd; /* file descriptor */ 1079 | #endif /* _WIN32 */ 1080 | bool secure; /* https? */ 1081 | char ip[INET_ADDRSTRLEN]; /* client IP */ 1082 | char pip[INET_ADDRSTRLEN]; /* proxy IP */ 1083 | char in[IN_BUFSIZE]; /* the whole incoming request */ 1084 | char method[MAX_METHOD_LEN+1]; /* HTTP method */ 1085 | unsigned was_read; /* request bytes read so far */ 1086 | bool upgrade2https; /* Upgrade-Insecure-Requests = 1 */ 1087 | /* parsed HTTP request starts here */ 1088 | bool head_only; /* request method = HEAD */ 1089 | bool post; /* request method = POST */ 1090 | char uri[MAX_URI_LEN+1]; /* requested URI string */ 1091 | char resource[MAX_RESOURCE_LEN+1]; /* from URI (REQ0) */ 1092 | char req1[MAX_RESOURCE_LEN+1]; /* from URI -- level 1 */ 1093 | char req2[MAX_RESOURCE_LEN+1]; /* from URI -- level 2 */ 1094 | char req3[MAX_RESOURCE_LEN+1]; /* from URI -- level 3 */ 1095 | char id[MAX_RESOURCE_LEN+1]; /* from URI -- last part */ 1096 | char proto[16]; /* HTTP request version */ 1097 | char uagent[MAX_VALUE_LEN+1]; /* user agent string */ 1098 | bool mobile; 1099 | bool keep_alive; 1100 | char referer[MAX_VALUE_LEN+1]; 1101 | unsigned clen; /* incoming & outgoing content length */ 1102 | char *in_data; /* POST data */ 1103 | char cookie_in_a[SESID_LEN+1]; /* anonymous */ 1104 | char cookie_in_l[SESID_LEN+1]; /* logged in */ 1105 | char host[MAX_VALUE_LEN+1]; 1106 | char host_normalized[MAX_VALUE_LEN+1]; 1107 | char website[WEBSITE_LEN+1]; 1108 | char lang[LANG_LEN+1]; 1109 | time_t if_mod_since; 1110 | char in_ctypestr[MAX_VALUE_LEN+1]; /* content type as an original string */ 1111 | char in_ctype; /* content type */ 1112 | char boundary[MAX_VALUE_LEN+1]; /* for POST multipart/form-data type */ 1113 | char authorization[MAX_VALUE_LEN+1]; /* Authorization */ 1114 | bool accept_deflate; 1115 | int host_id; 1116 | /* what goes out */ 1117 | unsigned out_hlen; /* outgoing header length */ 1118 | unsigned out_len; /* outgoing length (all) */ 1119 | char *out_start; 1120 | #ifdef OUTCHECKREALLOC 1121 | char *out_data_alloc; /* allocated space for rendered content */ 1122 | #else 1123 | char out_data_alloc[OUT_BUFSIZE]; 1124 | #endif 1125 | unsigned out_data_allocated; /* number of allocated bytes */ 1126 | char *out_data; /* pointer to the data to send */ 1127 | int status; /* HTTP status */ 1128 | char cust_headers[CUST_HDR_LEN+1]; 1129 | unsigned data_sent; /* how many content bytes have been sent */ 1130 | char ctype; /* content type */ 1131 | char ctypestr[CONTENT_TYPE_LEN+1]; /* user (custom) content type */ 1132 | char cdisp[CONTENT_DISP_LEN+1]; /* content disposition */ 1133 | time_t modified; 1134 | char cookie_out_a[SESID_LEN+1]; 1135 | char cookie_out_a_exp[32]; /* cookie expires */ 1136 | char cookie_out_l[SESID_LEN+1]; 1137 | char cookie_out_l_exp[32]; /* cookie expires */ 1138 | char location[MAX_URI_LEN+1]; /* redirection */ 1139 | /* internal stuff */ 1140 | unsigned req; /* request count */ 1141 | struct timespec proc_start; /* start processing time */ 1142 | double elapsed; /* processing time in ms */ 1143 | char conn_state; /* connection state (STATE_XXX) */ 1144 | char *p_header; /* current header pointer */ 1145 | char *p_content; /* current content pointer */ 1146 | #ifdef HTTPS 1147 | SSL *ssl; 1148 | #endif 1149 | int ssl_err; 1150 | char required_auth_level; /* required authorization level */ 1151 | int usi; /* user session index */ 1152 | int static_res; /* static resource index in M_stat */ 1153 | time_t last_activity; 1154 | bool bot; 1155 | bool expect100; 1156 | bool dont_cache; 1157 | bool keep_content; /* don't reset already rendered content on error */ 1158 | #ifdef FD_MON_POLL 1159 | int pi; /* pollfds array index */ 1160 | #endif 1161 | #ifdef ASYNC 1162 | char service[SVC_NAME_LEN+1]; 1163 | int async_err_code; 1164 | // int ai; /* async responses array index */ 1165 | #endif 1166 | } conn_t; 1167 | #endif /* SILGY_SVC */ 1168 | 1169 | 1170 | /* static resources */ 1171 | 1172 | typedef struct { 1173 | char host[MAX_VALUE_LEN+1]; 1174 | char name[STATIC_PATH_LEN]; 1175 | char type; 1176 | char *data; 1177 | unsigned len; 1178 | char *data_deflated; 1179 | unsigned len_deflated; 1180 | time_t modified; 1181 | char source; 1182 | } stat_res_t; 1183 | 1184 | 1185 | /* admin info */ 1186 | 1187 | typedef struct { 1188 | char sql[1024]; 1189 | char th[256]; 1190 | char type[32]; 1191 | } admin_info_t; 1192 | 1193 | 1194 | /* counters formatted */ 1195 | 1196 | typedef struct { 1197 | char req[64]; 1198 | char req_dsk[64]; 1199 | char req_mob[64]; 1200 | char req_bot[64]; 1201 | char visits[64]; 1202 | char visits_dsk[64]; 1203 | char visits_mob[64]; 1204 | char blocked[64]; 1205 | char average[64]; 1206 | } counters_fmt_t; 1207 | 1208 | 1209 | 1210 | #include 1211 | 1212 | #ifdef USERS 1213 | #include 1214 | #endif 1215 | 1216 | 1217 | 1218 | #ifdef __cplusplus 1219 | extern "C" { 1220 | #endif 1221 | 1222 | /* read from the config file */ 1223 | 1224 | extern int G_logLevel; 1225 | extern int G_logToStdout; 1226 | extern int G_logCombined; 1227 | extern int G_httpPort; 1228 | extern int G_httpsPort; 1229 | extern char G_cipherList[1024]; 1230 | extern char G_certFile[256]; 1231 | extern char G_certChainFile[256]; 1232 | extern char G_keyFile[256]; 1233 | extern char G_dbHost[128]; 1234 | extern int G_dbPort; 1235 | extern char G_dbName[128]; 1236 | extern char G_dbUser[128]; 1237 | extern char G_dbPassword[128]; 1238 | extern int G_usersRequireAccountActivation; 1239 | extern char G_blockedIPList[256]; 1240 | extern char G_whiteList[256]; 1241 | extern int G_ASYNCId; 1242 | extern int G_ASYNCDefTimeout; 1243 | extern int G_RESTTimeout; 1244 | extern int G_test; 1245 | 1246 | /* end of config params */ 1247 | 1248 | extern int G_pid; /* pid */ 1249 | extern char G_appdir[256]; /* application root dir */ 1250 | extern int G_days_up; /* web server's days up */ 1251 | extern conn_t conn[MAX_CONNECTIONS+1]; /* HTTP connections & requests -- by far the most important structure around */ 1252 | extern int G_open_conn; /* number of open connections */ 1253 | extern int G_open_conn_hwm; /* highest number of open connections (high water mark) */ 1254 | extern char G_tmp[TMP_BUFSIZE]; /* temporary string buffer */ 1255 | extern usession_t uses[MAX_SESSIONS+1]; /* engine user sessions -- they start from 1 */ 1256 | extern ausession_t auses[MAX_SESSIONS+1]; /* app user sessions, using the same index (usi) */ 1257 | extern int G_sessions; /* number of active user sessions */ 1258 | extern int G_sessions_hwm; /* highest number of active user sessions (high water mark) */ 1259 | extern time_t G_now; /* current time */ 1260 | extern struct tm *G_ptm; /* human readable current time */ 1261 | extern char G_last_modified[32]; /* response header field with server's start time */ 1262 | extern bool G_initialized; 1263 | 1264 | /* messages */ 1265 | extern message_t G_messages[MAX_MESSAGES]; 1266 | extern int G_next_msg; 1267 | extern lang_t G_msg_lang[MAX_LANGUAGES]; 1268 | extern int G_next_msg_lang; 1269 | 1270 | /* strings */ 1271 | extern string_t G_strings[MAX_STRINGS]; 1272 | extern int G_next_str; 1273 | extern lang_t G_str_lang[MAX_LANGUAGES]; 1274 | extern int G_next_str_lang; 1275 | 1276 | /* snippets */ 1277 | extern stat_res_t G_snippets[MAX_SNIPPETS]; 1278 | extern int G_snippets_cnt; 1279 | 1280 | #ifdef HTTPS 1281 | extern bool G_ssl_lib_initialized; 1282 | #endif 1283 | 1284 | #ifdef DBMYSQL 1285 | extern MYSQL *G_dbconn; /* database connection */ 1286 | #endif 1287 | 1288 | /* asynchorous processing */ 1289 | #ifndef _WIN32 1290 | extern char G_req_queue_name[256]; 1291 | extern char G_res_queue_name[256]; 1292 | extern mqd_t G_queue_req; /* request queue */ 1293 | extern mqd_t G_queue_res; /* response queue */ 1294 | #endif /* _WIN32 */ 1295 | extern int G_async_req_data_size; /* how many bytes are left for data */ 1296 | extern int G_async_res_data_size; /* how many bytes are left for data */ 1297 | 1298 | extern char G_dt[20]; /* datetime for database or log (YYYY-MM-DD hh:mm:ss) */ 1299 | extern bool G_index_present; /* index.html present in res? */ 1300 | 1301 | #ifdef SILGY_SVC 1302 | extern async_req_t req; 1303 | extern async_res_t res; 1304 | #ifdef OUTCHECKREALLOC 1305 | extern char *out_data; 1306 | #endif 1307 | extern char *p_content; 1308 | extern char G_service[SVC_NAME_LEN+1]; 1309 | extern int G_error_code; 1310 | //extern int ci; 1311 | #endif /* SILGY_SVC */ 1312 | 1313 | extern char G_blacklist[MAX_BLACKLIST+1][INET_ADDRSTRLEN]; 1314 | extern int G_blacklist_cnt; /* G_blacklist length */ 1315 | 1316 | extern char G_whitelist[MAX_WHITELIST+1][INET_ADDRSTRLEN]; 1317 | extern int G_whitelist_cnt; /* G_whitelist length */ 1318 | /* counters */ 1319 | extern counters_t G_cnts_today; /* today's counters */ 1320 | extern counters_t G_cnts_yesterday; /* yesterday's counters */ 1321 | extern counters_t G_cnts_day_before; /* day before's counters */ 1322 | /* REST */ 1323 | extern int G_rest_status; /* last REST call response status */ 1324 | extern unsigned G_rest_req; /* REST calls counter */ 1325 | extern double G_rest_elapsed; /* REST calls elapsed for calculating average */ 1326 | extern double G_rest_average; /* REST calls average elapsed */ 1327 | extern char G_rest_content_type[MAX_VALUE_LEN+1]; 1328 | extern int G_rest_res_len; 1329 | extern int G_new_user_id; 1330 | extern int G_qs_len; 1331 | 1332 | 1333 | #ifdef __cplusplus 1334 | } /* extern "C" */ 1335 | #endif 1336 | 1337 | 1338 | 1339 | 1340 | /* prototypes */ 1341 | 1342 | #ifdef __cplusplus 1343 | extern "C" { 1344 | #endif 1345 | 1346 | /* public engine functions */ 1347 | 1348 | void silgy_set_auth_level(const char *path, char level); 1349 | int eng_uses_start(int ci, const char *sesid); 1350 | void eng_uses_downgrade_by_uid(int uid, int ci); 1351 | void eng_async_req(int ci, const char *service, const char *data, char response, int timeout, int size); 1352 | void silgy_add_to_static_res(const char *name, const char *src); 1353 | void eng_block_ip(const char *value, bool autoblocked); 1354 | bool eng_is_uri(int ci, const char *uri); 1355 | bool silgy_set_host_res(const char *host, const char *res, const char *resmin); 1356 | void eng_out_check(int ci, const char *str); 1357 | void eng_out_check_realloc(int ci, const char *str); 1358 | void eng_out_check_realloc_bin(int ci, const char *data, int len); 1359 | char *eng_get_header(int ci, const char *header); 1360 | void eng_rest_header_pass(int ci, const char *header); 1361 | 1362 | /* public app functions */ 1363 | 1364 | #ifdef SILGY_SVC 1365 | void svc_out_check(const char *str); 1366 | void svc_out_check_realloc(const char *str); 1367 | void svc_out_check_realloc_bin(const char *data, int len); 1368 | bool silgy_svc_init(void); 1369 | void silgy_svc_main(int ci); 1370 | void silgy_svc_done(void); 1371 | #else /* not SILGY_SVC */ 1372 | bool silgy_app_init(int argc, char *argv[]); 1373 | void silgy_app_done(void); 1374 | void silgy_app_main(int ci); 1375 | bool silgy_app_session_init(int ci); 1376 | void silgy_app_session_done(int ci); 1377 | #ifdef ASYNC 1378 | #ifdef ASYNC_USE_APP_CONTINUE /* depreciated */ 1379 | void silgy_app_continue(int ci, const char *data); 1380 | #endif 1381 | #endif 1382 | #ifdef APP_ERROR_PAGE 1383 | void silgy_app_error_page(int ci, int code); 1384 | #endif 1385 | #ifdef EVERY_SECOND 1386 | void app_every_second(void); 1387 | #endif 1388 | #endif /* SILGY_SVC */ 1389 | 1390 | #ifdef USERS 1391 | bool silgy_app_user_login(int ci); 1392 | void silgy_app_user_logout(int ci); 1393 | #endif 1394 | 1395 | #ifdef __cplusplus 1396 | } /* extern "C" */ 1397 | #endif 1398 | 1399 | 1400 | 1401 | #endif /* SILGY_H */ 1402 | --------------------------------------------------------------------------------