Added server support for 'admin-control' protocol, added parsing of IP4/6/unix addresses, fixed some bugs, moved to C++17, config["server"] now actually does something
This commit is contained in:
		
							parent
							
								
									1aa95ad87e
								
							
						
					
					
						commit
						4d18d13a93
					
				
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -13,4 +13,4 @@ compile_commands.json | |||||||
| local.sh | local.sh | ||||||
| 
 | 
 | ||||||
| iu9-ca-web-chat.db | iu9-ca-web-chat.db | ||||||
| log | log/ | ||||||
|  | |||||||
| @ -1,13 +1,13 @@ | |||||||
| {% ELDEF main JSON pres %} | {% ELDEF main JSON pres %} | ||||||
| <!DOCTYPE html> |     <!DOCTYPE html> | ||||||
| <html lang="ru"> |     <html lang="ru"> | ||||||
| <head> |     <head> | ||||||
|         <meta charset="UTF-8"> |         <meta charset="UTF-8"> | ||||||
|         <meta name="viewport" content="width=device-width, initial-scale=1.0"> |         <meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||||||
|         <title>{% WRITE pres.phr.decl.list-of-chat-rooms %}</title> |         <title>{% WRITE pres.phr.decl.list-of-chat-rooms %}</title> | ||||||
|         <link rel="stylesheet" href="/assets/css/list-rooms.css"> |         <link rel="stylesheet" href="/assets/css/list-rooms.css"> | ||||||
| </head> |     </head> | ||||||
| <body> |     <body> | ||||||
|         <div class="container"> |         <div class="container"> | ||||||
|             <h1 style="color: white;">{% WRITE pres.phr.decl.select-chat-room %}</h1> |             <h1 style="color: white;">{% WRITE pres.phr.decl.select-chat-room %}</h1> | ||||||
|             <ul class="room-list"> |             <ul class="room-list"> | ||||||
| @ -49,6 +49,6 @@ | |||||||
|         </div> |         </div> | ||||||
| 
 | 
 | ||||||
|         <script src="/assets/js/list-rooms.js"></script> |         <script src="/assets/js/list-rooms.js"></script> | ||||||
| </body> |     </body> | ||||||
| </html> |     </html> | ||||||
| {% ENDELDEF %} | {% ENDELDEF %} | ||||||
|  | |||||||
| @ -29,7 +29,7 @@ struct CAWebChat { | |||||||
| 
 | 
 | ||||||
|     std::vector<std::string> warning_flags = {"-Wall", "-Wno-unused-variable", "-Werror=return-type","-pedantic", |     std::vector<std::string> warning_flags = {"-Wall", "-Wno-unused-variable", "-Werror=return-type","-pedantic", | ||||||
|         "-Wno-unused-but-set-variable", "-Wno-reorder"}; |         "-Wno-unused-but-set-variable", "-Wno-reorder"}; | ||||||
|     std::vector<std::string> version_flags = {"--std", "c++14", "-D", "_POSIX_C_SOURCE=200809L"}; |     std::vector<std::string> version_flags = {"--std", "c++17", "-D", "_POSIX_C_SOURCE=200809L"}; | ||||||
|     std::vector<std::string> debug_defines_release = {"_GLIBCXX_DEBUG"}; |     std::vector<std::string> debug_defines_release = {"_GLIBCXX_DEBUG"}; | ||||||
|     std::vector<std::string> debug_defines_debug = {"_GLIBCXX_DEBUG", "DEBUG_ALLOW_LOUD"}; |     std::vector<std::string> debug_defines_debug = {"_GLIBCXX_DEBUG", "DEBUG_ALLOW_LOUD"}; | ||||||
|     std::vector<std::string> opt_flags_release = {"-g", "-O2"}; |     std::vector<std::string> opt_flags_release = {"-g", "-O2"}; | ||||||
| @ -78,6 +78,7 @@ struct CAWebChat { | |||||||
|                 "connecting_assets/static_asset_manager.cpp", |                 "connecting_assets/static_asset_manager.cpp", | ||||||
|                 "running_mainloop.cpp", |                 "running_mainloop.cpp", | ||||||
|                 "form_data_structure/urlencoded_query.cpp", |                 "form_data_structure/urlencoded_query.cpp", | ||||||
|  |                 "socket_address.cpp", | ||||||
|             }; |             }; | ||||||
|             for (std::string& u: T.units) |             for (std::string& u: T.units) | ||||||
|                 u = "http_server/engine_engine_number_9/" + u; |                 u = "http_server/engine_engine_number_9/" + u; | ||||||
| @ -93,6 +94,8 @@ struct CAWebChat { | |||||||
|                 "http_structures/response_gen.h", |                 "http_structures/response_gen.h", | ||||||
|                 "running_mainloop.h", |                 "running_mainloop.h", | ||||||
|                 "form_data_structure/urlencoded_query.h", |                 "form_data_structure/urlencoded_query.h", | ||||||
|  |                 "socket_address.h", | ||||||
|  |                 "admin_control.h", | ||||||
|             }; |             }; | ||||||
|             for (std::string& u: T.exported_headers) |             for (std::string& u: T.exported_headers) | ||||||
|                 u = "engine_engine_number_9/" + u; |                 u = "engine_engine_number_9/" + u; | ||||||
|  | |||||||
| @ -31,6 +31,6 @@ | |||||||
|   "server": { |   "server": { | ||||||
|     "workers": 8, |     "workers": 8, | ||||||
|     "http-listen": ["127.0.0.1:1025"], |     "http-listen": ["127.0.0.1:1025"], | ||||||
|     "command-listen": [] |     "admin-command-listen": ["127.0.0.1:1026"] | ||||||
|   } |   } | ||||||
| } | } | ||||||
							
								
								
									
										62
									
								
								src/http_server/engine_engine_number_9/admin_control.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								src/http_server/engine_engine_number_9/admin_control.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,62 @@ | |||||||
|  | #include "admin_control.h" | ||||||
|  | #include <string.h> | ||||||
|  | #include <assert.h> | ||||||
|  | 
 | ||||||
|  | namespace een9 { | ||||||
|  |     static const char* admin_to_server_ms = "a6m1n 2 server request ~~~"; | ||||||
|  |     static const char* server_to_admin_ms = "server to 4dm1n r3sponse ~~~"; | ||||||
|  | 
 | ||||||
|  |     AdminControlProtMsgRecvCtx::AdminControlProtMsgRecvCtx(const char *ms): magic_string(ms) { | ||||||
|  |         ms_size = strlen(ms); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     int AdminControlProtMsgRecvCtx::feedCharacter(char ch) { | ||||||
|  |         assert(status == 0); | ||||||
|  |         if (magic_string_progress < ms_size) { | ||||||
|  |             if (magic_string[magic_string_progress] != ch) { | ||||||
|  |                 status = -1; | ||||||
|  |                 return status; | ||||||
|  |             } | ||||||
|  |             magic_string_progress++; | ||||||
|  |         } else if (body_size_progress < 8) { | ||||||
|  |             uint64_t bt = (uint64_t)(uint8_t)ch; | ||||||
|  |             b_sz = ((b_sz << 8) | bt); | ||||||
|  |             body_size_progress++; | ||||||
|  |             if (body_size_progress == 8 && b_sz > 100000000) { | ||||||
|  |                 status = -1; | ||||||
|  |                 return status; | ||||||
|  |             } | ||||||
|  |             body.reserve(b_sz); | ||||||
|  |         } else if (body.size() < b_sz) { | ||||||
|  |             body += ch; | ||||||
|  |         } else { | ||||||
|  |             status = 1; | ||||||
|  |         } | ||||||
|  |         return status; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     AdminControlRequestRCtx::AdminControlRequestRCtx(): AdminControlProtMsgRecvCtx(admin_to_server_ms) { | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     AdminControlResponseRCtx::AdminControlResponseRCtx(): AdminControlProtMsgRecvCtx(server_to_admin_ms) { | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     std::string generate_ac_msg_gen_case(const std::string& content, const char* ms) { | ||||||
|  |         std::string result; | ||||||
|  |         uint64_t N = content.size(); | ||||||
|  |         for (int i = 0; i < 8; i++) { | ||||||
|  |             result += (char)(uint8_t)((N & 0xff00000000000000) >> 56); | ||||||
|  |             N <<= 8; | ||||||
|  |         } | ||||||
|  |         result += content; | ||||||
|  |         return result; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     std::string generate_admin_control_request(const std::string &content) { | ||||||
|  |         return generate_ac_msg_gen_case(content, admin_to_server_ms); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     std::string generate_admin_control_response(const std::string &content) { | ||||||
|  |         return generate_ac_msg_gen_case(content, server_to_admin_ms); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										37
									
								
								src/http_server/engine_engine_number_9/admin_control.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								src/http_server/engine_engine_number_9/admin_control.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,37 @@ | |||||||
|  | #ifndef ENGINE_ENGINE_NUMBER_9_ADMIN_CONTROL_H | ||||||
|  | #define ENGINE_ENGINE_NUMBER_9_ADMIN_CONTROL_H | ||||||
|  | 
 | ||||||
|  | #include <string> | ||||||
|  | #include <stdint.h> | ||||||
|  | 
 | ||||||
|  | namespace een9 { | ||||||
|  |     struct AdminControlProtMsgRecvCtx { | ||||||
|  |         const char* magic_string; | ||||||
|  |         size_t ms_size; | ||||||
|  |         size_t magic_string_progress = 0; | ||||||
|  |         size_t body_size_progress = 0; | ||||||
|  |         uint64_t b_sz = 0; | ||||||
|  |         std::string body; | ||||||
|  |         int status = 0; | ||||||
|  | 
 | ||||||
|  |         explicit AdminControlProtMsgRecvCtx(const char* ms); | ||||||
|  | 
 | ||||||
|  |         int feedCharacter(char ch); | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     struct AdminControlRequestRCtx: public AdminControlProtMsgRecvCtx { | ||||||
|  |         AdminControlRequestRCtx(); | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     struct AdminControlResponseRCtx: public AdminControlProtMsgRecvCtx { | ||||||
|  |         AdminControlResponseRCtx(); | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     /* From ADMIN to server (will begin with admin_to_server_ms)*/ | ||||||
|  |     std::string generate_admin_control_request(const std::string& content); | ||||||
|  | 
 | ||||||
|  |     /* From SERVER to admin (will begin with server_to_admin_ms).*/ | ||||||
|  |     std::string generate_admin_control_response(const std::string& content); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #endif | ||||||
| @ -28,14 +28,30 @@ namespace een9 { | |||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     bool endsIn(const std::string &a, const std::string &b) { |     bool endsWith(const std::string &a, const std::string &b) { | ||||||
|         if (b.size() > a.size()) |         if (b.size() > a.size()) | ||||||
|             return false; |             return false; | ||||||
|         return std::equal(a.end() - (ssize_t)b.size(), a.end(), b.begin()); |         return std::equal(a.end() - (ssize_t)b.size(), a.end(), b.begin()); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     bool beginsWith(const std::string &a, const std::string &b) { | ||||||
|  |         if (b.size() > a.size()) | ||||||
|  |             return false; | ||||||
|  |         return std::equal(a.begin(), a.begin() + (ssize_t)b.size(), b.begin()); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     std::string getSubstring(const std::string &str, size_t A, size_t B) { |     std::string getSubstring(const std::string &str, size_t A, size_t B) { | ||||||
|         ASSERT(A <= B && B <= str.size(), "Incorrect substring segment"); |         ASSERT(A <= B && B <= str.size(), "Incorrect substring segment"); | ||||||
|         return str.substr(A, B - A); |         return str.substr(A, B - A); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     std::string make_uppercase(const std::string &source) { | ||||||
|  |         std::string result(source); | ||||||
|  |         for (size_t i = 0; i < source.size(); i++) { | ||||||
|  |             char ch = source[i]; | ||||||
|  |             if ('a' <= ch && ch <= 'z') | ||||||
|  |                 result[i] = (char)(ch - 'a' + 'A'); | ||||||
|  |         } | ||||||
|  |         return result; | ||||||
|  |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -18,11 +18,17 @@ namespace een9 { | |||||||
| 
 | 
 | ||||||
|     bool strIn(const std::string& str, const char* arr[]); |     bool strIn(const std::string& str, const char* arr[]); | ||||||
| 
 | 
 | ||||||
|     bool endsIn(const std::string& a, const std::string& b); |     // b is postfix of a
 | ||||||
|  |     bool endsWith(const std::string& a, const std::string& b); | ||||||
|  | 
 | ||||||
|  |     // b is prefix of a
 | ||||||
|  |     bool beginsWith(const std::string& a, const std::string& b); | ||||||
| 
 | 
 | ||||||
|     /* In case of error, throws een9::ServerError */ |     /* In case of error, throws een9::ServerError */ | ||||||
|     std::string getSubstring(const std::string& str, size_t A, size_t B); |     std::string getSubstring(const std::string& str, size_t A, size_t B); | ||||||
| 
 | 
 | ||||||
|  |     std::string make_uppercase(const std::string &source); | ||||||
|  | 
 | ||||||
|     template<typename T> |     template<typename T> | ||||||
|     using uptr = std::unique_ptr<T>; |     using uptr = std::unique_ptr<T>; | ||||||
| } | } | ||||||
|  | |||||||
| @ -53,7 +53,7 @@ namespace een9 { | |||||||
|             std::vector<std::string> c_files = detour_over_regular_folder(dir_rule.directory); |             std::vector<std::string> c_files = detour_over_regular_folder(dir_rule.directory); | ||||||
|             for (const std::string& file: c_files) { |             for (const std::string& file: c_files) { | ||||||
|                 for (const StaticAssetManagerRulePostfixFilter& ext: dir_rule.postfix_rules_type_assign) { |                 for (const StaticAssetManagerRulePostfixFilter& ext: dir_rule.postfix_rules_type_assign) { | ||||||
|                     if (endsIn(file, ext.required_postfix)) { |                     if (endsWith(file, ext.required_postfix)) { | ||||||
|                         /* Found it! */ |                         /* Found it! */ | ||||||
|                         StaticAsset etot{ext.assigned_type, }; |                         StaticAsset etot{ext.assigned_type, }; | ||||||
|                         readFile(dir_rule.directory + "/" + file, etot.content); |                         readFile(dir_rule.directory + "/" + file, etot.content); | ||||||
|  | |||||||
| @ -5,11 +5,12 @@ | |||||||
| #include <assert.h> | #include <assert.h> | ||||||
| // Used for debug
 | // Used for debug
 | ||||||
| 
 | 
 | ||||||
|  | #ifdef DEBUG_ALLOW_LOUD | ||||||
| #include "unistd.h" | #include "unistd.h" | ||||||
| #include <sys/stat.h> | #include <sys/stat.h> | ||||||
| #include "sys/dir.h" | #include "sys/dir.h" | ||||||
| #include "../os_utils.h" | #include "../os_utils.h" | ||||||
| 
 | #endif | ||||||
| 
 | 
 | ||||||
| namespace een9 { | namespace een9 { | ||||||
|     ClientRequestParser_CommonPrograms::ClientRequestParser_CommonPrograms() { |     ClientRequestParser_CommonPrograms::ClientRequestParser_CommonPrograms() { | ||||||
| @ -106,8 +107,10 @@ namespace een9 { | |||||||
|                     if (p.first == "Content-Length") { |                     if (p.first == "Content-Length") { | ||||||
|                         collecting_body = res.has_body = true; |                         collecting_body = res.has_body = true; | ||||||
|                         body_size = std::stoull(p.second); |                         body_size = std::stoull(p.second); | ||||||
|                         if (body_size > 100000000) |                         if (body_size > 100000000) { | ||||||
|                             THROW("Message content is too big"); |                             status = -1; | ||||||
|  |                             return status; | ||||||
|  |                         } | ||||||
|                         res.body.reserve(body_size); |                         res.body.reserve(body_size); | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
| @ -121,7 +124,6 @@ namespace een9 { | |||||||
|                 writeFile("log/req", header); |                 writeFile("log/req", header); | ||||||
| #endif | #endif | ||||||
|                 status = -1; |                 status = -1; | ||||||
|                 THROW("bad request"); |  | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         return status; |         return status; | ||||||
|  | |||||||
| @ -37,7 +37,6 @@ namespace een9 { | |||||||
|         explicit ClientRequestParser_WorkerBuffers(const ClientRequestParser_CommonPrograms& common_comp_program); |         explicit ClientRequestParser_WorkerBuffers(const ClientRequestParser_CommonPrograms& common_comp_program); | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     /* Ou yeah, baby, it's time for more OOP */ |  | ||||||
|     struct ClientHttpRequestParser_Ctx { |     struct ClientHttpRequestParser_Ctx { | ||||||
|         ClientRequest& res; |         ClientRequest& res; | ||||||
|         regexis024::VirtualMachine& vm; |         regexis024::VirtualMachine& vm; | ||||||
|  | |||||||
| @ -25,7 +25,6 @@ namespace een9 { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     UniqueFdWrapper::~UniqueFdWrapper() { |     UniqueFdWrapper::~UniqueFdWrapper() { | ||||||
|         // printf("DEBUG!!! Closing fd = %d\n", fd);
 |  | ||||||
|         if (fd >= 0) |         if (fd >= 0) | ||||||
|             close(fd); |             close(fd); | ||||||
|     } |     } | ||||||
| @ -55,7 +54,7 @@ namespace een9 { | |||||||
|         while ((ret = (int)read(fd, buf, 2048)) > 0) { |         while ((ret = (int)read(fd, buf, 2048)) > 0) { | ||||||
|             size_t oldN = result.size(); |             size_t oldN = result.size(); | ||||||
|             result.resize(oldN + ret); |             result.resize(oldN + ret); | ||||||
|             memcpy((void*)&result.c_str()[oldN], buf, ret); |             memcpy(result.data() + oldN, buf, ret); | ||||||
|         } |         } | ||||||
|         ASSERT_on_iret(ret, "Reading from " + description); |         ASSERT_on_iret(ret, "Reading from " + description); | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -13,6 +13,7 @@ | |||||||
| #include "http_structures/client_request_parse.h" | #include "http_structures/client_request_parse.h" | ||||||
| #include "http_structures/response_gen.h" | #include "http_structures/response_gen.h" | ||||||
| #include "baza_inter.h" | #include "baza_inter.h" | ||||||
|  | #include "admin_control.h" | ||||||
| 
 | 
 | ||||||
| namespace een9 { | namespace een9 { | ||||||
|     struct QElementHttpConnections { |     struct QElementHttpConnections { | ||||||
| @ -73,11 +74,13 @@ namespace een9 { | |||||||
|         WorkersTaskQueue queue; |         WorkersTaskQueue queue; | ||||||
|         bool& termination; |         bool& termination; | ||||||
|         guest_core_t guest_core; |         guest_core_t guest_core; | ||||||
|  |         guest_core_admin_control_t guest_core_admin_control; | ||||||
| 
 | 
 | ||||||
|         /* Parser programs */ |         /* Parser programs */ | ||||||
|         ClientRequestParser_CommonPrograms parser_programs; |         ClientRequestParser_CommonPrograms parser_programs; | ||||||
| 
 | 
 | ||||||
|         WorkersEnvCommon(bool& term, guest_core_t g_c): termination(term), guest_core(std::move(g_c)){} |         WorkersEnvCommon(bool& term, const MainloopParameters& params): termination(term), | ||||||
|  |         guest_core(params.guest_core), guest_core_admin_control(params.guest_core_admin_control){} | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     struct WorkersEnv { |     struct WorkersEnv { | ||||||
| @ -89,25 +92,22 @@ namespace een9 { | |||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     // todo: add timeout for multiple bytes, add more settings
 |     // todo: add timeout for multiple bytes, add more settings
 | ||||||
|     ClientRequest process_connection_input(int fd, const EEN9_ServerTips& s_tips, WorkersEnv& wte) { |     ClientRequest process_http_connection_input(int fd, const EEN9_ServerTips& s_tips, WorkersEnv& wte) { | ||||||
|         ClientRequest res; |         ClientRequest res; | ||||||
|         ClientHttpRequestParser_Ctx parser(res, wte.personal_parser_buffer, wte.wtec.parser_programs); |         ClientHttpRequestParser_Ctx parser(res, wte.personal_parser_buffer, wte.wtec.parser_programs); | ||||||
|         int ret; |         int ret; | ||||||
|         char buf[2048]; |         char buf[2048]; | ||||||
|         ASSERT_pl(parser.status == 0); |         assert(parser.status == 0); | ||||||
|         while ((ret = (int)recv(fd, buf, 2048, 0)) > 0) { |         while ((ret = (int)recv(fd, buf, 2048, 0)) > 0) { | ||||||
|             for (size_t i = 0; i < ret; i++) { |             for (size_t i = 0; i < ret; i++) { | ||||||
|                 /* Throws ServerError on bad input */ |                 if (parser.feedCharacter(buf[i]) > 0) | ||||||
|                 if (parser.feedCharacter(buf[i]) > 0) { |  | ||||||
|                     break; |                     break; | ||||||
|             } |             } | ||||||
|             } |  | ||||||
|             if (parser.status > 0) |             if (parser.status > 0) | ||||||
|                 break; |                 break; | ||||||
|         } |         } | ||||||
|         ASSERT_on_iret(ret, "recv"); |         ASSERT_on_iret(ret, "recv"); | ||||||
|         ASSERT_pl(parser.status == 1); |         assert(parser.status == 1); | ||||||
|         // printf("Log: worker received clients request\n%s\n", client_request.toString().c_str());
 |  | ||||||
|         return res; |         return res; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -123,10 +123,35 @@ namespace een9 { | |||||||
|         printf("Log: worker: succesfully asnwered with response\n"); |         printf("Log: worker: succesfully asnwered with response\n"); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     std::string process_admin_control_connection_input(int fd, const EEN9_ServerTips& s_tips, WorkersEnv& wte) { | ||||||
|  |         AdminControlRequestRCtx pctx; | ||||||
|  |         int ret; | ||||||
|  |         char buf[2048]; | ||||||
|  |         assert(pctx.status == 0); | ||||||
|  |         while ((ret = (int)recv(fd, buf, 2048, 0)) > 0) { | ||||||
|  |             for (size_t i = 0; i < ret; i++) { | ||||||
|  |                 if (pctx.feedCharacter(buf[i]) > 0) | ||||||
|  |                     break; | ||||||
|  |             } | ||||||
|  |             if (pctx.status > 0) | ||||||
|  |                 break; | ||||||
|  |         } | ||||||
|  |         ASSERT_on_iret(ret, "recv"); | ||||||
|  |         assert(pctx.status == 1); | ||||||
|  |         return pctx.body; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     void process_connection(const SlaveTask& task, WorkersEnv& wte) { |     void process_connection(const SlaveTask& task, WorkersEnv& wte) { | ||||||
|         ClientRequest client_request = process_connection_input(task.fd(), task.s_tips, wte); |         if (task.conn_info.type == 0) { | ||||||
|  |             ClientRequest client_request = process_http_connection_input(task.fd(), task.s_tips, wte); | ||||||
|             std::string server_response = wte.wtec.guest_core(task, client_request, wte.id); |             std::string server_response = wte.wtec.guest_core(task, client_request, wte.id); | ||||||
|             process_connection_output(task.fd(), server_response); |             process_connection_output(task.fd(), server_response); | ||||||
|  |         } else if (task.conn_info.type == 1) { | ||||||
|  |             std::string admin_request = process_admin_control_connection_input(task.fd(), task.s_tips, wte); | ||||||
|  |             std::string server_response_content = wte.wtec.guest_core_admin_control(task, admin_request, wte.id); | ||||||
|  |             std::string server_response = generate_admin_control_response(server_response_content); | ||||||
|  |             process_connection_output(task.fd(), server_response); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     void* worker_func(void* wte_ptr) { |     void* worker_func(void* wte_ptr) { | ||||||
| @ -156,13 +181,13 @@ namespace een9 { | |||||||
|         return NULL; |         return NULL; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // todo: retrieve address of connected client
 |  | ||||||
| 
 |  | ||||||
|     void electric_boogaloo(const MainloopParameters& params, bool& termination_trigger) { |     void electric_boogaloo(const MainloopParameters& params, bool& termination_trigger) { | ||||||
|         WorkersEnvCommon wtec(termination_trigger, params.guest_core); |         WorkersEnvCommon wtec(termination_trigger, params); | ||||||
|         ASSERT(params.slave_number > 0, "No workers spawned"); |         ASSERT(params.slave_number > 0, "No workers spawned"); | ||||||
|         size_t Nip = params.ports_to_listen.size(); |         size_t CRL_Nip = params.client_regular_listened.size(); | ||||||
|         ASSERT(Nip > 0, "No open listeting addresses"); |         ASSERT(CRL_Nip > 0, "No open listeting addresses (http)"); | ||||||
|  |         size_t ACL_Nip = params.admin_control_listened.size(); | ||||||
|  |         size_t Nip = CRL_Nip + ACL_Nip; | ||||||
| 
 | 
 | ||||||
|         std::vector<pthread_t> workers(params.slave_number); |         std::vector<pthread_t> workers(params.slave_number); | ||||||
|         std::vector<uptr<WorkersEnv>> wtes(params.slave_number); |         std::vector<uptr<WorkersEnv>> wtes(params.slave_number); | ||||||
| @ -173,44 +198,49 @@ namespace een9 { | |||||||
|             pthread_create(&workers[i], NULL, worker_func, wtes[i].get()); |             pthread_create(&workers[i], NULL, worker_func, wtes[i].get()); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         // todo: move this try block inside the loop
 | ||||||
|         try { |         try { | ||||||
|             int ret; |             int ret; | ||||||
|             std::vector<UniqueFdWrapper> listening_socks(Nip); |             struct Ear { | ||||||
|  |                 /* A copy from params */ | ||||||
|  |                 SocketAddress my_addr; | ||||||
|  |                 UniqueFdWrapper listening_sock; | ||||||
|  |                 /* type 0 is for http protocol
 | ||||||
|  |                  * type 1 is for admin-cmd protocol */ | ||||||
|  |                 int type; | ||||||
|  |             }; | ||||||
|  |             std::vector<Ear> ears(Nip); | ||||||
|  |             for (size_t i = 0; i < CRL_Nip; i++) { | ||||||
|  |                 ears[i].my_addr = params.client_regular_listened[i]; | ||||||
|  |                 ears[i].type = 0; | ||||||
|  |             } | ||||||
|  |             for (size_t i = 0; i < ACL_Nip; i++) { | ||||||
|  |                 ears[i + CRL_Nip].my_addr = params.admin_control_listened[i]; | ||||||
|  |                 ears[i + CRL_Nip].type = 1; | ||||||
|  |             } | ||||||
|             for (size_t i = 0; i < Nip; i++) { |             for (size_t i = 0; i < Nip; i++) { | ||||||
|                 printf("Creating listening socket\n"); |  | ||||||
|                 uint16_t port = params.ports_to_listen[i]; |  | ||||||
|                 int listening_socket_fd = socket(AF_INET, SOCK_STREAM, 0); |                 int listening_socket_fd = socket(AF_INET, SOCK_STREAM, 0); | ||||||
|                 ASSERT_on_iret(listening_socket_fd, "Listening socket creation"); |                 ASSERT_on_iret(listening_socket_fd, "'Listening socket' creation"); | ||||||
|                 UniqueFdWrapper listening_socket(listening_socket_fd); |                 UniqueFdWrapper listening_socket(listening_socket_fd); | ||||||
|                 printf("Listening socket created\n"); |  | ||||||
|                 sockaddr_in listening_address; |  | ||||||
|                 listening_address.sin_family = AF_INET; |  | ||||||
|                 listening_address.sin_port = htons(port); |  | ||||||
|                 uint32_t lca = (127u << 24) | 1; |  | ||||||
|                 listening_address.sin_addr.s_addr = htonl(lca); |  | ||||||
|                 int reuseaddr_nozero_option_value = 1; |                 int reuseaddr_nozero_option_value = 1; | ||||||
|                 ret = setsockopt(listening_socket_fd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr_nozero_option_value, sizeof(int)); |                 ret = setsockopt(listening_socket_fd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr_nozero_option_value, sizeof(int)); | ||||||
|                 ASSERT_on_iret(ret, "setting SO_REUSEADDR befire binding to address"); |                 ASSERT_on_iret(ret, "Can't set SO_REUSEADDR"); | ||||||
|                 ret = bind(listening_socket(), (const sockaddr*)&listening_address, sizeof(listening_address)); |                 bind_to_socket_address(listening_socket_fd, ears[i].my_addr); | ||||||
|                 ASSERT_on_iret(ret, "binding to INADDR_ANY:" + std::to_string(port)); |  | ||||||
|                 printf("Binded socket to address\n"); |  | ||||||
|                 ret = listen(listening_socket(), 128); |                 ret = listen(listening_socket(), 128); | ||||||
|                 ASSERT_on_iret(ret, "listening for connections"); |                 ASSERT_on_iret(ret, "listen() listening for connections"); | ||||||
|                 printf("Listening socket succesfully started listening\n"); |                 ears[i].listening_sock = std::move(listening_socket); | ||||||
|                 listening_socks[i] = std::move(listening_socket); |  | ||||||
|             } |             } | ||||||
|             std::vector<pollfd> pollfds(Nip); |             std::vector<pollfd> pollfds(Nip); | ||||||
|             for (size_t i = 0; i < Nip; i++) { |             for (size_t i = 0; i < Nip; i++) { | ||||||
|                 pollfds[i].fd = listening_socks[i](); |                 pollfds[i].fd = ears[i].listening_sock(); | ||||||
|                 pollfds[i].events = POLLRDNORM; |                 pollfds[i].events = POLLRDNORM; | ||||||
|             } |             } | ||||||
|             printf("Entering mainloop\n"); |  | ||||||
|             ASSERT(params.mainloop_recheck_interval_us > 0, "Incorrect poll timeout"); |             ASSERT(params.mainloop_recheck_interval_us > 0, "Incorrect poll timeout"); | ||||||
|             while (true) { |             while (true) { | ||||||
|                 MutexLockGuard lg1(wtec.corvee_bed, "poller termination check"); |                 // MutexLockGuard lg1(wtec.corvee_bed, "poller termination check");
 | ||||||
|                 if (wtec.termination) |                 if (wtec.termination) | ||||||
|                     break; |                     break; | ||||||
|                 lg1.unlock(); |                 // lg1.unlock();
 | ||||||
|                 for (size_t i = 0; i < Nip; i++) { |                 for (size_t i = 0; i < Nip; i++) { | ||||||
|                     pollfds[i].revents = 0; |                     pollfds[i].revents = 0; | ||||||
|                 } |                 } | ||||||
| @ -218,21 +248,24 @@ namespace een9 { | |||||||
|                 ret = poll(pollfds.data(), Nip, params.mainloop_recheck_interval_us); |                 ret = poll(pollfds.data(), Nip, params.mainloop_recheck_interval_us); | ||||||
|                 if (errno == EINTR) |                 if (errno == EINTR) | ||||||
|                     break; |                     break; | ||||||
|                 ASSERT_on_iret(ret, "polling"); |                 // todo: do not end program here (in the loop. Nothing in the loop should be able to end program)
 | ||||||
|  |                 ASSERT_on_iret(ret, "poll()"); | ||||||
|                 for (size_t i = 0; i < Nip; i++) { |                 for (size_t i = 0; i < Nip; i++) { | ||||||
|                     if ((pollfds[i].revents & POLLRDNORM)) { |                     if ((pollfds[i].revents & POLLRDNORM)) { | ||||||
|                         try { |                         try { | ||||||
|                             sockaddr client_address; |                             int session_sock = accept(pollfds[i].fd, NULL, NULL); | ||||||
|                             socklen_t client_addr_len = sizeof(client_address); |  | ||||||
|                             int session_sock = accept(pollfds[i].fd, &client_address, &client_addr_len); |  | ||||||
|                             ASSERT_on_iret(session_sock, "Failed to accept incoming connection"); |                             ASSERT_on_iret(session_sock, "Failed to accept incoming connection"); | ||||||
|                             printf("Log: successful connection\n"); |  | ||||||
|                             UniqueFdWrapper session_sock_fdw(session_sock); |                             UniqueFdWrapper session_sock_fdw(session_sock); | ||||||
|                             configure_socket_rcvsndtimeo(session_sock_fdw(), params.s_conf.request_timeout); |                             configure_socket_rcvsndtimeo(session_sock_fdw(), params.s_conf.request_timeout); | ||||||
|  |                             SocketAddress peer_addr; | ||||||
|  |                             get_peer_name_as_socket_address(session_sock, peer_addr); | ||||||
|                             { MutexLockGuard lg2(wtec.corvee_bed, "poller adds connection"); |                             { MutexLockGuard lg2(wtec.corvee_bed, "poller adds connection"); | ||||||
|                                 SlaveTask task{ConnectionInfo{}, std::move(session_sock_fdw), |                                 SlaveTask task{ | ||||||
|  |                                     ConnectionInfo{ears[i].my_addr, peer_addr, ears[i].type}, | ||||||
|  |                                     std::move(session_sock_fdw), | ||||||
|                                     EEN9_ServerTips{wtec.queue.size(), |                                     EEN9_ServerTips{wtec.queue.size(), | ||||||
|                                         params.s_conf.critical_load_1, params.s_conf.request_timeout}}; |                                         params.s_conf.critical_load_1, params.s_conf.request_timeout} | ||||||
|  |                                 }; | ||||||
|                                 if (wtec.queue.size() < params.s_conf.critical_load_2) |                                 if (wtec.queue.size() < params.s_conf.critical_load_2) | ||||||
|                                     wtec.queue.push_back(std::move(task)); |                                     wtec.queue.push_back(std::move(task)); | ||||||
|                             } |                             } | ||||||
|  | |||||||
| @ -7,12 +7,14 @@ | |||||||
| #include "os_utils.h" | #include "os_utils.h" | ||||||
| #include "http_structures/client_request.h" | #include "http_structures/client_request.h" | ||||||
| #include <stdint.h> | #include <stdint.h> | ||||||
|  | #include "socket_address.h" | ||||||
| 
 | 
 | ||||||
| namespace een9 { | namespace een9 { | ||||||
|     struct ConnectionInfo { |     struct ConnectionInfo { | ||||||
|         // todo: add server address field
 |         SocketAddress server_name; | ||||||
|         // todo: add client address field
 |         SocketAddress client_name; | ||||||
|         int type; // O_o why??
 |         /* 0 - http, 1 - 'een9::admin-control' protocol  */ | ||||||
|  |         int type; | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     /* This structure is passed to guest function. It contains server info that might be or might be not used
 |     /* This structure is passed to guest function. It contains server info that might be or might be not used
 | ||||||
| @ -33,6 +35,8 @@ namespace een9 { | |||||||
| 
 | 
 | ||||||
|     /* guest_core function must not throw anything that is not derived from std::exception */ |     /* guest_core function must not throw anything that is not derived from std::exception */ | ||||||
|     typedef std::function<std::string(const SlaveTask&, const ClientRequest&, worker_id_t worker_id)> guest_core_t; |     typedef std::function<std::string(const SlaveTask&, const ClientRequest&, worker_id_t worker_id)> guest_core_t; | ||||||
|  |     /* same as gurst_core_t, but it used not for http, but for een9 specific "admin-cmd" protocol */ | ||||||
|  |     typedef std::function<std::string(const SlaveTask&, const std::string&, worker_id_t)> guest_core_admin_control_t; | ||||||
| 
 | 
 | ||||||
|     struct ServersConfiguration { |     struct ServersConfiguration { | ||||||
|         size_t critical_load_1 = 90; |         size_t critical_load_1 = 90; | ||||||
| @ -42,15 +46,19 @@ namespace een9 { | |||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     struct MainloopParameters { |     struct MainloopParameters { | ||||||
|  |         /* On which addresses should I listed for incoming HTTP connections */ | ||||||
|  |         std::vector<SocketAddress> client_regular_listened; | ||||||
|  |         /* On which addresses should I listen for incoming administrative commands */ | ||||||
|  |         std::vector<SocketAddress> admin_control_listened; | ||||||
|         bool do_logging = true; |         bool do_logging = true; | ||||||
|         bool open_admin_listener = true; |  | ||||||
|         // todo: add support for unix socket address
 |  | ||||||
|         uint16_t admin_listener_port = 12345; |  | ||||||
|         guest_core_t guest_core; |  | ||||||
|         size_t slave_number = 2; |         size_t slave_number = 2; | ||||||
|         std::vector<uint16_t> ports_to_listen; |  | ||||||
|         int mainloop_recheck_interval_us = 100; |         int mainloop_recheck_interval_us = 100; | ||||||
| 
 | 
 | ||||||
|  |         /* Takes parsed http request object. Should return fully-prepared http response */ | ||||||
|  |         guest_core_t guest_core; | ||||||
|  |         /* Takes admin input. Returns only desired output message (without protocol header) */ | ||||||
|  |         guest_core_admin_control_t guest_core_admin_control; | ||||||
|  | 
 | ||||||
|         ServersConfiguration s_conf; |         ServersConfiguration s_conf; | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|  | |||||||
							
								
								
									
										276
									
								
								src/http_server/engine_engine_number_9/socket_address.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										276
									
								
								src/http_server/engine_engine_number_9/socket_address.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,276 @@ | |||||||
|  | #include "socket_address.h" | ||||||
|  | #include <stddef.h> | ||||||
|  | #include "baza.h" | ||||||
|  | #include "baza_inter.h" | ||||||
|  | #include <libregexis024tools/delayed_matching.h> | ||||||
|  | #include <libregexis024tools/stringmatching.h> | ||||||
|  | #include <libregexis024vm/libregexis024vm_interface.h> | ||||||
|  | #include <vector> | ||||||
|  | #include <assert.h> | ||||||
|  | #include <algorithm> | ||||||
|  | 
 | ||||||
|  | namespace een9 { | ||||||
|  |     struct regexp_cmp_out{ | ||||||
|  |         std::vector<uint8_t> prg; | ||||||
|  |         regexis024::track_var_list vars; | ||||||
|  |     }; | ||||||
|  |     regexp_cmp_out compile_regexp(const char* expr) { | ||||||
|  |         regexp_cmp_out res; | ||||||
|  |         std::string problem; | ||||||
|  |         int ret = regexis024::compile(expr, res.vars, res.prg, problem); | ||||||
|  |         ASSERT(ret == 0, "Can't compile regexp"); | ||||||
|  |         return res; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     struct SocketAddressParser_Inner { | ||||||
|  |         regexp_cmp_out prg; | ||||||
|  |         regexis024::VirtualMachine vm; | ||||||
|  |         regexis024::tai_t tdiff_k; | ||||||
|  |         std::pair<regexis024::tai_t, regexis024::tai_t> i4_k; | ||||||
|  |         std::pair<regexis024::tai_t, regexis024::tai_t> i6_k; | ||||||
|  |         std::pair<regexis024::tai_t, regexis024::tai_t> ip_k; | ||||||
|  |         regexis024::tai_t skip_k; | ||||||
|  | 
 | ||||||
|  | #define reg_int4 "#4(0|[1-9][0-9]!r{0;2})" | ||||||
|  | #define reg_int6 "#6(0|[1-9a-fA-F][0-9a-fA-F]!r{0;3})" | ||||||
|  | #define reg_6RHT_rep(mt) "(:|(:" reg_int6 ")!r{1;" #mt "})" | ||||||
|  | #define reg_6LFT_rep(ea) "(" reg_int6 ":)!r{" #ea "}" | ||||||
|  | #define reg_6zs "#s:0;" | ||||||
|  | #define reg_intp "#p(0|[1-9][0-9]!r{0;4})" | ||||||
|  | #define reg_addr_in4 "(#t:1;" reg_int4 "." reg_int4 "." reg_int4 "." reg_int4 ":" reg_intp ")" | ||||||
|  | #define reg_addr_in6_core "(" reg_6LFT_rep(7) reg_int6 "|" ":" reg_6zs reg_6RHT_rep(6) "|" \ | ||||||
|  |     reg_6LFT_rep(1) reg_6zs reg_6RHT_rep(5) "|" \ | ||||||
|  |     reg_6LFT_rep(2) reg_6zs reg_6RHT_rep(4) "|" \ | ||||||
|  |     reg_6LFT_rep(3) reg_6zs reg_6RHT_rep(3) "|" \ | ||||||
|  |     reg_6LFT_rep(4) reg_6zs reg_6RHT_rep(2) "|" \ | ||||||
|  |     reg_6LFT_rep(5) reg_6zs reg_6RHT_rep(1) "|" \ | ||||||
|  |     reg_6LFT_rep(6) reg_6zs ":" ")" | ||||||
|  | #define reg_addr_in6 "(#t:2;\\["  reg_addr_in6_core "\\]:" reg_intp ")" | ||||||
|  |         SocketAddressParser_Inner(): prg(compile_regexp( | ||||||
|  |             reg_addr_in4 "|" reg_addr_in6 | ||||||
|  |         )), vm(prg.prg.size(), prg.prg.data(), UINT64_MAX, UINT16_MAX, UINT32_MAX, UINT32_MAX, UINT64_MAX) | ||||||
|  |         { | ||||||
|  |             ASSERT_pl(vm.initialize() == 0); | ||||||
|  |             tdiff_k = prg.vars.at("t").colarr_first; | ||||||
|  |             skip_k = prg.vars.at("s").colarr_first; | ||||||
|  |             auto obtain_range = [&](const std::string& name) -> std::pair<regexis024::tai_t, regexis024::tai_t> { | ||||||
|  |                 const regexis024::TrackingVariableInfo& vi = prg.vars.at(name); | ||||||
|  |                 assert(vi.colarr_first > 0 && vi.colarr_second > 0); | ||||||
|  |                 return {(regexis024::tai_t)vi.colarr_first, (regexis024::tai_t)vi.colarr_second}; | ||||||
|  |             }; | ||||||
|  |             i4_k = obtain_range("4"); | ||||||
|  |             i6_k = obtain_range("6"); | ||||||
|  |             ip_k = obtain_range("p"); | ||||||
|  |         } | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     SocketAddressParser::SocketAddressParser() { | ||||||
|  |         opaque = new SocketAddressParser_Inner(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     SocketAddressParser::~SocketAddressParser() { | ||||||
|  |         delete (SocketAddressParser_Inner*)opaque; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     int parse_socket_address(const std::string& addr, SocketAddress& res, SocketAddressParser& pdata) { | ||||||
|  | #define reveal (*(SocketAddressParser_Inner*)pdata.opaque) | ||||||
|  |         reveal.vm.wipeToInit(); | ||||||
|  |         ASSERT_pl(reveal.vm.addNewMatchingThread() == 0); | ||||||
|  |         int ret; | ||||||
|  |         for (size_t i = 0; i < addr.size(); i++) { | ||||||
|  |             ret = reveal.vm.feedCharacter((uint64_t)addr[i], 1); | ||||||
|  |             // if (!reveal.vm.haveSurvivors()) {
 | ||||||
|  |                 // printf("DEBUG: died on %s\n", addr.substr(0, i + 1).c_str());
 | ||||||
|  |                 // break;
 | ||||||
|  |             // }
 | ||||||
|  |         } | ||||||
|  |         if (reveal.vm.isMatched()) { | ||||||
|  |             std::vector<regexis024::CAEvent> ca = reveal.vm.getMatchedThreadCABranchReverse(); | ||||||
|  |             std::reverse(ca.begin(), ca.end()); | ||||||
|  |             size_t ci = 0; | ||||||
|  | #define curKey() ca[ci].key | ||||||
|  | #define curValue() ca[ci].value | ||||||
|  |             auto extractRange = [&](std::pair<regexis024::tai_t, regexis024::tai_t> rk) -> std::string { | ||||||
|  |                 assert(ca[ci].key == rk.first && ca[ci + 1].key == rk.second); | ||||||
|  |                 size_t oci = ci; | ||||||
|  |                 ci += 2; | ||||||
|  |                 return getSubstring(addr, ca[oci].value, ca[oci + 1].value); | ||||||
|  |             }; | ||||||
|  |             assert(curKey() == reveal.tdiff_k); | ||||||
|  |             if (curValue() == 1) { | ||||||
|  |                 ci++; | ||||||
|  |                 uint32_t res_addr = 0; | ||||||
|  |                 for (int i = 0; i < 4; i++) { | ||||||
|  |                     std::string h = extractRange(reveal.i4_k); | ||||||
|  |                     uint32_t p = std::stoul(h); | ||||||
|  |                     if (p > 255) | ||||||
|  |                         return -1; | ||||||
|  |                     res_addr = ((res_addr << 8) | p); | ||||||
|  |                 } | ||||||
|  |                 uint32_t res_port = std::stoul(extractRange(reveal.ip_k)); | ||||||
|  |                 if (res_port > 65535) | ||||||
|  |                     return -1; | ||||||
|  |                 res.v.gen.sa_family = AF_INET; | ||||||
|  |                 res.v.sin.sin_port = htons(res_port);  // host to network short
 | ||||||
|  |                 res.v.sin.sin_addr.s_addr = htonl(res_addr); // host to network long
 | ||||||
|  |                 res.addrLen = sizeof(sockaddr_in); | ||||||
|  |             } else if (curValue() == 2){ | ||||||
|  |                 ci++; | ||||||
|  |                 int skipped = 8; | ||||||
|  |                 for (const regexis024::CAEvent& ev: ca) { | ||||||
|  |                     if (ev.key == reveal.i6_k.first) | ||||||
|  |                         skipped--; | ||||||
|  |                 } | ||||||
|  |                 assert(skipped == 0 || skipped >= 2); | ||||||
|  |                 uint16_t res_u6_addr16[8]; | ||||||
|  |                 size_t bi = 0; | ||||||
|  |                 std::string h; | ||||||
|  |                 while (bi < 8) { | ||||||
|  |                     if (curKey() == reveal.i6_k.first) { | ||||||
|  |                         h = extractRange(reveal.i6_k); | ||||||
|  |                         assert(h.size() <= 4); | ||||||
|  |                         uint32_t v = 0; | ||||||
|  |                         for (char ch: h) { | ||||||
|  |                             v <<= 4; | ||||||
|  |                             if ('0' <= ch && ch <= '9') { | ||||||
|  |                                 v |= (uint32_t)(ch - '0'); | ||||||
|  |                             } else if ('a' <= ch && ch <= 'z') { | ||||||
|  |                                 v |= (uint32_t)(ch - 'a' + 10); | ||||||
|  |                             } else if ('A' <= ch && ch <= 'Z') { | ||||||
|  |                                 v |= (uint32_t)(ch - 'A' + 10); | ||||||
|  |                             } else | ||||||
|  |                                 assert(false); | ||||||
|  |                         } | ||||||
|  |                         assert(v <= UINT16_MAX); | ||||||
|  |                         res_u6_addr16[bi++] = (uint16_t)v; | ||||||
|  |                     } else if (curKey() == reveal.skip_k) { | ||||||
|  |                         ci++; | ||||||
|  |                         for (int j = 0; j < skipped; j++) | ||||||
|  |                             res_u6_addr16[bi++] = 0; | ||||||
|  |                     } else | ||||||
|  |                         assert(false); | ||||||
|  |                 } | ||||||
|  |                 assert(bi == 8); | ||||||
|  |                 uint32_t res_port = std::stoul(extractRange(reveal.ip_k)); | ||||||
|  |                 if (res_port > 65535) | ||||||
|  |                     return -1; | ||||||
|  |                 res.v.gen.sa_family = AF_INET6; | ||||||
|  |                 res.v.sin6.sin6_port = htons(res_port); | ||||||
|  |                 for (int i = 0; i < 8; i++) | ||||||
|  |                     res.v.sin6.sin6_addr.__in6_u.__u6_addr16[i] = htons(res_u6_addr16[i]); | ||||||
|  |                 res.addrLen = sizeof(sockaddr_in6); | ||||||
|  |             } else | ||||||
|  |                 assert(false); | ||||||
|  |             assert(ci == ca.size()); | ||||||
|  |             return 0; | ||||||
|  |         } | ||||||
|  |         const std::string& up = "unix:"; | ||||||
|  |         if (beginsWith(addr, up)) { | ||||||
|  |             std::string path = addr.substr(up.size()); | ||||||
|  |             if (path.empty()) | ||||||
|  |                 return -1; | ||||||
|  |             if (path.back() == '/') | ||||||
|  |                 return -1; | ||||||
|  |             for (char ch: path) | ||||||
|  |                 if (ch == 0) | ||||||
|  |                     return -1; | ||||||
|  |             res.v.gen.sa_family = AF_UNIX; | ||||||
|  |             if (sizeof(res.v.sun.sun_path) > path.size()) | ||||||
|  |                 THROW("path is too big"); | ||||||
|  |             memcpy(res.v.sun.sun_path, path.c_str(), path.size()); | ||||||
|  |             res.addrLen = offsetof(sockaddr_un, sun_path) + path.size(); | ||||||
|  |             return 0; | ||||||
|  |         } | ||||||
|  |         return -1; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     std::string short2hex(uint16_t v) { | ||||||
|  |         if (v == 0) | ||||||
|  |             return "0"; | ||||||
|  |         std::string result; | ||||||
|  |         while (v) { | ||||||
|  |             result += (char)((v & 0xf) > 9 ? (v & 0xf) - 10 + 'a' : (v & 0xf) + '0'); | ||||||
|  |             v >>= 4; | ||||||
|  |         } | ||||||
|  |         std::reverse(result.begin(), result.end()); | ||||||
|  |         return result; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     std::string stringify_socket_address(const SocketAddress &addr) { | ||||||
|  |         if (addr.v.gen.sa_family == AF_INET) { | ||||||
|  |             char buf[22]; | ||||||
|  |             uint32_t IP = ntohl(addr.v.sin.sin_addr.s_addr); | ||||||
|  |             uint16_t port = ntohs(addr.v.sin.sin_port); | ||||||
|  |             snprintf(buf, 22, "%u.%u.%u.%u:%hu", (IP >> 24) & 0xff, (IP >> 16) & 0xff, (IP >> 8) & 0xff, | ||||||
|  |                 (IP >> 0) & 0xff, port); | ||||||
|  |             return buf; | ||||||
|  |         } else if (addr.v.gen.sa_family == AF_INET6) { | ||||||
|  |             uint16_t IP[8]; | ||||||
|  |             for (int i = 0; i < 8; i++) | ||||||
|  |                 IP[i] = ntohs(addr.v.sin6.sin6_addr.__in6_u.__u6_addr16[i]); | ||||||
|  |             uint16_t port = ntohs(addr.v.sin6.sin6_port); | ||||||
|  |             int largest_sz = 0; | ||||||
|  |             int largest_start = 0; | ||||||
|  |             int cur_sz = 0; | ||||||
|  |             for (int i = 0; i < 8; i++) { | ||||||
|  |                 if (IP[i] == 0) { | ||||||
|  |                     cur_sz++; | ||||||
|  |                     if (largest_sz < cur_sz) { | ||||||
|  |                         largest_sz = cur_sz; | ||||||
|  |                         largest_start = i + 1 - cur_sz; | ||||||
|  |                     } | ||||||
|  |                 } else { | ||||||
|  |                     cur_sz = 0; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             std::string core; | ||||||
|  |             for (int i = 0; i < 8;) { | ||||||
|  |                 if (largest_sz >= 2 && largest_start == i) { | ||||||
|  |                     i += largest_sz; | ||||||
|  |                     if (i == 8) | ||||||
|  |                         core += "::"; | ||||||
|  |                     else | ||||||
|  |                         core += ":"; | ||||||
|  |                 } else { | ||||||
|  |                     if (i > 0) | ||||||
|  |                         core += ":"; | ||||||
|  |                     core += short2hex(IP[i]); | ||||||
|  |                     i++; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             assert(core.size() <= 39); | ||||||
|  |             char buf[48]; | ||||||
|  |             snprintf(buf, 48, "[%s]:%hu", core.c_str(), port); | ||||||
|  |             return buf; | ||||||
|  |         } else if (addr.v.gen.sa_family == AF_UNIX) { | ||||||
|  |             assert(addr.addrLen > offsetof(sockaddr_un, sun_path)); | ||||||
|  |             size_t path_len = addr.addrLen - offsetof(sockaddr_un, sun_path); | ||||||
|  |             assert(path_len <= sizeof(addr.v.sun.sun_path)); | ||||||
|  |             std::string path(path_len, ')'); | ||||||
|  |             memcpy(path.data(), addr.v.sun.sun_path, path_len); | ||||||
|  |             return "unix:" + path; | ||||||
|  |         } else | ||||||
|  |             return "Socket address of unknown domain"; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     void bind_to_socket_address(int sockfd, const SocketAddress &addr) { | ||||||
|  |         int ret; | ||||||
|  |         if (addr.v.gen.sa_family == AF_INET) { | ||||||
|  |             ret = bind(sockfd, (const sockaddr*)&addr.v.sin, addr.addrLen); | ||||||
|  |         } else if (addr.v.gen.sa_family == AF_INET6) { | ||||||
|  |             ret = bind(sockfd, (const sockaddr*)&addr.v.sin6, addr.addrLen); | ||||||
|  |         } else if (addr.v.gen.sa_family == AF_INET) { | ||||||
|  |             ret = bind(sockfd, (const sockaddr*)&addr.v.sun, addr.addrLen); | ||||||
|  |         } else | ||||||
|  |             THROW("binding socket to address of unsupported domain"); | ||||||
|  |         ASSERT_on_iret(ret, "binding socket"); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     void get_peer_name_as_socket_address(int sockfd, SocketAddress &res) { | ||||||
|  |         socklen_t willbecome = sizeof(res.v); | ||||||
|  |         int ret = getpeername(sockfd, &res.v.gen, &willbecome); | ||||||
|  |         ASSERT_on_iret(ret, "getpeername"); | ||||||
|  |         assert(willbecome <= sizeof(res.v)); | ||||||
|  |         res.addrLen = willbecome; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										51
									
								
								src/http_server/engine_engine_number_9/socket_address.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								src/http_server/engine_engine_number_9/socket_address.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,51 @@ | |||||||
|  | #ifndef ENGINE_ENGINE_NUMBER_9_SOCKET_ADDRESS_H | ||||||
|  | #define ENGINE_ENGINE_NUMBER_9_SOCKET_ADDRESS_H | ||||||
|  | 
 | ||||||
|  | #if defined(SOLARIS) | ||||||
|  | #include <netinet/in.h> | ||||||
|  | #endif | ||||||
|  | #include <netdb.h> | ||||||
|  | #include <arpa/inet.h> | ||||||
|  | #if defined(BSD) | ||||||
|  | #include <sys/socket.h> | ||||||
|  | #include <netinet/in.h> | ||||||
|  | #endif | ||||||
|  | #include <sys/un.h> | ||||||
|  | #include <string> | ||||||
|  | 
 | ||||||
|  | namespace een9 { | ||||||
|  |     /* Right now een9 supports only IP4, IP6, unix domain. System service querying is not implemented yet *
 | ||||||
|  |      * */ | ||||||
|  | 
 | ||||||
|  |     struct SocketAddress { | ||||||
|  |         union { | ||||||
|  |             sockaddr gen; | ||||||
|  |             sockaddr_in sin; | ||||||
|  |             sockaddr_in6 sin6; | ||||||
|  |             sockaddr_un sun; | ||||||
|  |         } v; | ||||||
|  |         size_t addrLen = sizeof(sockaddr_in); | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     /* Not thread-safe. Use only from one thread (at a time) */ | ||||||
|  |     struct SocketAddressParser { | ||||||
|  |         void* opaque = NULL; | ||||||
|  | 
 | ||||||
|  |         SocketAddressParser(); | ||||||
|  |         SocketAddressParser(const SocketAddressParser&) = default; | ||||||
|  |         SocketAddressParser& operator=(const SocketAddressParser&) = default; | ||||||
|  |         ~SocketAddressParser(); | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     int parse_socket_address(const std::string& addr, SocketAddress& res, SocketAddressParser& pdata); | ||||||
|  | 
 | ||||||
|  |     std::string stringify_socket_address(const SocketAddress& addr); | ||||||
|  | 
 | ||||||
|  |     /* Throws ServerError on error */ | ||||||
|  |     void bind_to_socket_address(int sockfd, const SocketAddress& addr); | ||||||
|  | 
 | ||||||
|  |     /* Throws ServerError on error */ | ||||||
|  |     void get_peer_name_as_socket_address(int sockfd, SocketAddress& res); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #endif | ||||||
							
								
								
									
										72
									
								
								src/http_server/misc_tests/sockaddr_parse_test.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								src/http_server/misc_tests/sockaddr_parse_test.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,72 @@ | |||||||
|  | #include <engine_engine_number_9/socket_address.h> | ||||||
|  | #include <engine_engine_number_9/baza.h> | ||||||
|  | 
 | ||||||
|  | using namespace een9; | ||||||
|  | 
 | ||||||
|  | void test(const std::string& test, bool is_correct, SocketAddressParser& parser) { | ||||||
|  | #define fup printf("Test failed\n"); fflush(stdout); abort(); return; | ||||||
|  |     SocketAddress addr; | ||||||
|  |     int ret = parse_socket_address(test, addr, parser); | ||||||
|  |     if ((ret == 0) != is_correct) { | ||||||
|  |         fup | ||||||
|  |     } | ||||||
|  |     if (is_correct) { | ||||||
|  |         std::string back = stringify_socket_address(addr); | ||||||
|  |         if (make_uppercase(test) != make_uppercase(back)){ | ||||||
|  |             fup | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     printf("Test passed\n"); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void test_dcs(const std::string& test, const std::string& need, SocketAddressParser& parser) { | ||||||
|  |     SocketAddress addr; | ||||||
|  |     int ret = parse_socket_address(test, addr, parser); | ||||||
|  |     if (ret != 0) { | ||||||
|  |         fup | ||||||
|  |     } | ||||||
|  |     std::string right = stringify_socket_address(addr); | ||||||
|  |     if (right != need) { | ||||||
|  |         fup | ||||||
|  |     } | ||||||
|  |     printf("Test passed\n"); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int main() { | ||||||
|  |     SocketAddressParser parser; | ||||||
|  |     test("[12::12:0:0:0]:600", true, parser); | ||||||
|  |     test("[12::12:0:FFFF:0]:600", true, parser); | ||||||
|  |     test("[12::11:1]:600", true, parser); | ||||||
|  |     test("[::a::]:600", false, parser); | ||||||
|  |     test("[FFd:1:1:1:1:FFd:1:f]:65535", true, parser); | ||||||
|  |     test("[f:f:f:f:f:0:1:f]:65535", true, parser); | ||||||
|  |     test("[1:1:1:1:1:0:1:0]:11212", true, parser); | ||||||
|  |     test("[1:1:1:1:1:1:1:1]:1", true, parser); | ||||||
|  |     test("[1:1:1:1:1:0:1:0]:65536", false, parser); | ||||||
|  |     test("[1:1:1:1:1:0:1:0]:65535", true, parser); | ||||||
|  |     test("[1:H:1:1:1:FFd:1:f]:65535", false, parser); | ||||||
|  | 
 | ||||||
|  |     test("[::]:1", true, parser); | ||||||
|  |     test("12.11.11.123:312", true, parser); | ||||||
|  |     test("0.1.111.123:31212", true, parser); | ||||||
|  |     test("0.1.111.123:65536", false, parser); | ||||||
|  |     test("0.1.111.123:65535", true, parser); | ||||||
|  |     test("0.1.111.255:65535", true, parser); | ||||||
|  |     test("255.0.255.255:65535", true, parser); | ||||||
|  |     test("255.0.256.0:65535", false, parser); | ||||||
|  |     test("255.0.1000.0:65535", false, parser); | ||||||
|  |     test("255.0.01.0:65535", false, parser); | ||||||
|  |     test("255.0.1.0:605535", false, parser); | ||||||
|  |     test("2.0.1.0:05535", false, parser); | ||||||
|  |     test("255.0.1.0::65535", false, parser); | ||||||
|  |     test(".255.0.1.0::65535", false, parser); | ||||||
|  |     test("..0.1.0::65535", false, parser); | ||||||
|  |     test("[FFFF0::]:0", false, parser); | ||||||
|  |     test("[0::01:]:0", false, parser); | ||||||
|  |     test("[0:fa:ffff::]:0", true, parser); | ||||||
|  |     test("[::a:a:a:a:a:a:b]:10", false, parser); | ||||||
|  |     test_dcs("[0:0:0:0:0:0:0:0]:413", "[::]:413", parser); | ||||||
|  |     test_dcs("[::0:0:0:0]:413", "[::]:413", parser); | ||||||
|  |     test_dcs("[::0:0:0:0:0:0]:413", "[::]:413", parser); | ||||||
|  |     test_dcs("[::a:a:0:0:0:0]:413", "[0:0:a:a::]:413", parser); | ||||||
|  | } | ||||||
| @ -100,7 +100,7 @@ namespace nytl { | |||||||
|         while ((ret = (int)read(fd, buf, 2048)) > 0) { |         while ((ret = (int)read(fd, buf, 2048)) > 0) { | ||||||
|             size_t oldN = result.size(); |             size_t oldN = result.size(); | ||||||
|             result.resize(oldN + ret); |             result.resize(oldN + ret); | ||||||
|             memcpy((void*)&result.c_str()[oldN], buf, ret); |             memcpy(result.data() + oldN, buf, ret); | ||||||
|         } |         } | ||||||
|         if (ret < 0) { |         if (ret < 0) { | ||||||
|             close(fd); |             close(fd); | ||||||
|  | |||||||
| @ -1,4 +0,0 @@ | |||||||
|     AAA |  | ||||||
|         {% FOR _:val IN cba %} |  | ||||||
|           TUTUTUTUTUTUTUTUN {% PUT jesccomp val %} |  | ||||||
|         {% ENDFOR %} |  | ||||||
| @ -57,7 +57,7 @@ void sqlite_single_statement(sqlite3* db_hand, const std::string& req_statement) | |||||||
|                 printf("NULL | "); |                 printf("NULL | "); | ||||||
|             } else { |             } else { | ||||||
|                 const unsigned char* text = sqlite3_column_text(stmt_obj, i); |                 const unsigned char* text = sqlite3_column_text(stmt_obj, i); | ||||||
|                 een9_ASSERT(sqlite3_errcode(db_hand) != SQLITE_NOMEM, "oom in sqlite3_column_text"); |                 een9_ASSERT(text, "oom in sqlite3_column_text"); | ||||||
|                 printf("%s | ", (const char*)text); |                 printf("%s | ", (const char*)text); | ||||||
|                 // todo: THIS F. B.S. IS NOT SAFE
 |                 // todo: THIS F. B.S. IS NOT SAFE
 | ||||||
|             } |             } | ||||||
|  | |||||||
| @ -16,7 +16,7 @@ int main(int argc, char** argv){ | |||||||
|         if (argc != 1 + 2) |         if (argc != 1 + 2) | ||||||
|             usage(argv); |             usage(argv); | ||||||
|         std::string config_file = argv[1]; |         std::string config_file = argv[1]; | ||||||
|         if (!een9::isRegularFile(config_file) || !een9::endsIn(config_file, ".json")) { |         if (!een9::isRegularFile(config_file) || !een9::endsWith(config_file, ".json")) { | ||||||
|             printf("\"%s\" is not a json file\n", argv[1]); |             printf("\"%s\" is not a json file\n", argv[1]); | ||||||
|             usage(argv); |             usage(argv); | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -9,7 +9,7 @@ | |||||||
| #include <engine_engine_number_9/form_data_structure/urlencoded_query.h> | #include <engine_engine_number_9/form_data_structure/urlencoded_query.h> | ||||||
| #include <new_york_transit_line/templater.h> | #include <new_york_transit_line/templater.h> | ||||||
| #include <sqlite3.h> | #include <sqlite3.h> | ||||||
| 
 | #include <engine_engine_number_9/socket_address.h> | ||||||
| 
 | 
 | ||||||
| bool termination = false; | bool termination = false; | ||||||
| 
 | 
 | ||||||
| @ -17,19 +17,8 @@ void sigterm_action(int) { | |||||||
|     termination = true; |     termination = true; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| std::string unsafe_client_request_stringification(const een9::ClientRequest& req) { |  | ||||||
|     std::string text = "\n\nGot some cool stuff\n"; |  | ||||||
|     text += (req.method + " " + req.uri_path + " " + req.http_version + "\n"); |  | ||||||
|     for (auto& p: req.headers) { |  | ||||||
|         text += p.first; text += ": "; text += p.second; text += "\n"; |  | ||||||
|     } |  | ||||||
|     text += "Body\n"; text += req.body; text += "\n"; |  | ||||||
|     return text; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| void run_website(const json::JSON& config) { | void run_website(const json::JSON& config) { | ||||||
|     een9_ASSERT(config["assets"].g().isString(), "config[\"\assets\"] is not string"); |     een9_ASSERT(config["assets"].g().isString(), "config[\"assets\"] is not string"); | ||||||
|     std::string assets_dir = config["assets"].g().asString(); |     std::string assets_dir = config["assets"].g().asString(); | ||||||
|     een9_ASSERT(een9::isDirectory(assets_dir), "\"" + assets_dir + "\" is not a directory"); |     een9_ASSERT(een9::isDirectory(assets_dir), "\"" + assets_dir + "\" is not a directory"); | ||||||
| 
 | 
 | ||||||
| @ -43,30 +32,27 @@ void run_website(const json::JSON& config) { | |||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|     const json::JSON& config_presentation = config["presentation"].g(); |     const json::JSON& config_presentation = config["presentation"].g(); | ||||||
|  |     int64_t slave_number = config["server"]["workers"].g().asInteger().get_int(); | ||||||
|  |     een9_ASSERT(slave_number > 0 && slave_number <= 200, "E"); | ||||||
| 
 | 
 | ||||||
|  |     struct WorkerGuestData { | ||||||
|         /* Because templaters use libjsonincpp, they can't be READ by two thread simultaneously */ |         /* Because templaters use libjsonincpp, they can't be READ by two thread simultaneously */ | ||||||
|         std::vector<std::unique_ptr<nytl::Templater>> templaters_copies(8); |         een9::uptr<nytl::Templater> templater; | ||||||
|         for (int i = 0; i < 8; i++) { |     }; | ||||||
|             templaters_copies[i] = std::make_unique<nytl::Templater>( |     std::vector<WorkerGuestData> worker_guest_data; | ||||||
|  |     for (int i = 0; i < slave_number; i++) { | ||||||
|  |         worker_guest_data[i].templater = std::make_unique<nytl::Templater>( | ||||||
|             nytl::TemplaterSettings{nytl::TemplaterDetourRules{assets_dir + "/HypertextPages"}}); |             nytl::TemplaterSettings{nytl::TemplaterDetourRules{assets_dir + "/HypertextPages"}}); | ||||||
|             templaters_copies[i]->update(); |         worker_guest_data[i].templater->update(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|         // printf("%s\n", templaters_copies[0]->render("list-rooms", {&config_presentation}).c_str());
 |  | ||||||
|         // return 0;
 |  | ||||||
| 
 |  | ||||||
|     een9::MainloopParameters params; |     een9::MainloopParameters params; | ||||||
|         params.guest_core = [&samI, &templaters_copies, config_presentation] |     params.guest_core = [&samI, &worker_guest_data, config_presentation] | ||||||
|     (const een9::SlaveTask& task, const een9::ClientRequest& req, een9::worker_id_t worker_id) -> std::string { |     (const een9::SlaveTask& task, const een9::ClientRequest& req, een9::worker_id_t worker_id) -> std::string { | ||||||
|             een9_ASSERT_pl(0 <= worker_id && worker_id < templaters_copies.size()); |         een9_ASSERT_pl(0 <= worker_id && worker_id < worker_guest_data.size()); | ||||||
|             nytl::Templater& templater = *templaters_copies[worker_id]; |         nytl::Templater& templater = *worker_guest_data[worker_id].templater; | ||||||
|         een9::StaticAsset sa; |         een9::StaticAsset sa; | ||||||
|         int ret; |         int ret; | ||||||
|             // printf("%s", unsafe_client_request_stringification(req).c_str());
 |  | ||||||
|             // if (req.uri_path == "/output") {
 |  | ||||||
|             //     std::string text = unsafe_client_request_stringification(req);
 |  | ||||||
|             //     return een9::form_http_server_response_200("text/plain", text);
 |  | ||||||
|             // }
 |  | ||||||
|         auto rteee = [&](const std::string& el_name, bool pass_phr) -> std::string { |         auto rteee = [&](const std::string& el_name, bool pass_phr) -> std::string { | ||||||
|             std::string page = templater.render(el_name, |             std::string page = templater.render(el_name, | ||||||
|                 pass_phr ? std::vector<const json::JSON*>{&config_presentation} : std::vector<const json::JSON*>{}); |                 pass_phr ? std::vector<const json::JSON*>{&config_presentation} : std::vector<const json::JSON*>{}); | ||||||
| @ -92,9 +78,29 @@ void run_website(const json::JSON& config) { | |||||||
|         return een9::form_http_server_response_404("text/html", "<h1> Not found! </h1>"); |         return een9::form_http_server_response_404("text/html", "<h1> Not found! </h1>"); | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|         params.ports_to_listen = {1025}; |     params.guest_core_admin_control = [] | ||||||
|         params.slave_number = 8; |     (const een9::SlaveTask& task, const std::string& req, een9::worker_id_t) -> std::string { | ||||||
|         params.open_admin_listener = false; |         if (req == "hello") { | ||||||
|  |             return ":0 omg! hiii!! Hewwou :3 !!!!"; | ||||||
|  |         } if (req == "8") { | ||||||
|  |             termination = true; | ||||||
|  |             return "Bye"; | ||||||
|  |         } else { | ||||||
|  |             return "Incorrect command"; | ||||||
|  |         } | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     params.slave_number = slave_number; | ||||||
|  | 
 | ||||||
|  |     een9::SocketAddressParser sap; | ||||||
|  |     auto translate_addr_list_conf = [&sap](std::vector<een9::SocketAddress>& dest, const std::vector<json::JSON>& source) { | ||||||
|  |         size_t N = source.size(); | ||||||
|  |         dest.resize(N); | ||||||
|  |         for (size_t i = 0; i < N; i++) | ||||||
|  |             een9::parse_socket_address(source[i].asString(), dest[i], sap); | ||||||
|  |     }; | ||||||
|  |     translate_addr_list_conf(params.client_regular_listened, config["server"]["http-listen"].g().asArray()); | ||||||
|  |     translate_addr_list_conf(params.admin_control_listened, config["server"]["admin-command-listen"].g().asArray()); | ||||||
| 
 | 
 | ||||||
|     signal(SIGINT, sigterm_action); |     signal(SIGINT, sigterm_action); | ||||||
|     signal(SIGTERM, sigterm_action); |     signal(SIGTERM, sigterm_action); | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user