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
|
||||
|
||||
iu9-ca-web-chat.db
|
||||
log
|
||||
log/
|
||||
|
@ -29,7 +29,7 @@ struct CAWebChat {
|
||||
|
||||
std::vector<std::string> warning_flags = {"-Wall", "-Wno-unused-variable", "-Werror=return-type","-pedantic",
|
||||
"-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_debug = {"_GLIBCXX_DEBUG", "DEBUG_ALLOW_LOUD"};
|
||||
std::vector<std::string> opt_flags_release = {"-g", "-O2"};
|
||||
@ -78,6 +78,7 @@ struct CAWebChat {
|
||||
"connecting_assets/static_asset_manager.cpp",
|
||||
"running_mainloop.cpp",
|
||||
"form_data_structure/urlencoded_query.cpp",
|
||||
"socket_address.cpp",
|
||||
};
|
||||
for (std::string& u: T.units)
|
||||
u = "http_server/engine_engine_number_9/" + u;
|
||||
@ -93,6 +94,8 @@ struct CAWebChat {
|
||||
"http_structures/response_gen.h",
|
||||
"running_mainloop.h",
|
||||
"form_data_structure/urlencoded_query.h",
|
||||
"socket_address.h",
|
||||
"admin_control.h",
|
||||
};
|
||||
for (std::string& u: T.exported_headers)
|
||||
u = "engine_engine_number_9/" + u;
|
||||
|
@ -31,6 +31,6 @@
|
||||
"server": {
|
||||
"workers": 8,
|
||||
"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;
|
||||
}
|
||||
|
||||
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())
|
||||
return false;
|
||||
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) {
|
||||
ASSERT(A <= B && B <= str.size(), "Incorrect substring segment");
|
||||
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 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 */
|
||||
std::string getSubstring(const std::string& str, size_t A, size_t B);
|
||||
|
||||
std::string make_uppercase(const std::string &source);
|
||||
|
||||
template<typename 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);
|
||||
for (const std::string& file: c_files) {
|
||||
for (const StaticAssetManagerRulePostfixFilter& ext: dir_rule.postfix_rules_type_assign) {
|
||||
if (endsIn(file, ext.required_postfix)) {
|
||||
if (endsWith(file, ext.required_postfix)) {
|
||||
/* Found it! */
|
||||
StaticAsset etot{ext.assigned_type, };
|
||||
readFile(dir_rule.directory + "/" + file, etot.content);
|
||||
|
@ -5,11 +5,12 @@
|
||||
#include <assert.h>
|
||||
// Used for debug
|
||||
|
||||
#ifdef DEBUG_ALLOW_LOUD
|
||||
#include "unistd.h"
|
||||
#include <sys/stat.h>
|
||||
#include "sys/dir.h"
|
||||
#include "../os_utils.h"
|
||||
|
||||
#endif
|
||||
|
||||
namespace een9 {
|
||||
ClientRequestParser_CommonPrograms::ClientRequestParser_CommonPrograms() {
|
||||
@ -106,8 +107,10 @@ namespace een9 {
|
||||
if (p.first == "Content-Length") {
|
||||
collecting_body = res.has_body = true;
|
||||
body_size = std::stoull(p.second);
|
||||
if (body_size > 100000000)
|
||||
THROW("Message content is too big");
|
||||
if (body_size > 100000000) {
|
||||
status = -1;
|
||||
return status;
|
||||
}
|
||||
res.body.reserve(body_size);
|
||||
}
|
||||
}
|
||||
@ -121,7 +124,6 @@ namespace een9 {
|
||||
writeFile("log/req", header);
|
||||
#endif
|
||||
status = -1;
|
||||
THROW("bad request");
|
||||
}
|
||||
}
|
||||
return status;
|
||||
|
@ -37,7 +37,6 @@ namespace een9 {
|
||||
explicit ClientRequestParser_WorkerBuffers(const ClientRequestParser_CommonPrograms& common_comp_program);
|
||||
};
|
||||
|
||||
/* Ou yeah, baby, it's time for more OOP */
|
||||
struct ClientHttpRequestParser_Ctx {
|
||||
ClientRequest& res;
|
||||
regexis024::VirtualMachine& vm;
|
||||
|
@ -25,7 +25,6 @@ namespace een9 {
|
||||
}
|
||||
|
||||
UniqueFdWrapper::~UniqueFdWrapper() {
|
||||
// printf("DEBUG!!! Closing fd = %d\n", fd);
|
||||
if (fd >= 0)
|
||||
close(fd);
|
||||
}
|
||||
@ -55,7 +54,7 @@ namespace een9 {
|
||||
while ((ret = (int)read(fd, buf, 2048)) > 0) {
|
||||
size_t oldN = result.size();
|
||||
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);
|
||||
}
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "http_structures/client_request_parse.h"
|
||||
#include "http_structures/response_gen.h"
|
||||
#include "baza_inter.h"
|
||||
#include "admin_control.h"
|
||||
|
||||
namespace een9 {
|
||||
struct QElementHttpConnections {
|
||||
@ -73,11 +74,13 @@ namespace een9 {
|
||||
WorkersTaskQueue queue;
|
||||
bool& termination;
|
||||
guest_core_t guest_core;
|
||||
guest_core_admin_control_t guest_core_admin_control;
|
||||
|
||||
/* 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 {
|
||||
@ -89,25 +92,22 @@ namespace een9 {
|
||||
};
|
||||
|
||||
// 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;
|
||||
ClientHttpRequestParser_Ctx parser(res, wte.personal_parser_buffer, wte.wtec.parser_programs);
|
||||
int ret;
|
||||
char buf[2048];
|
||||
ASSERT_pl(parser.status == 0);
|
||||
assert(parser.status == 0);
|
||||
while ((ret = (int)recv(fd, buf, 2048, 0)) > 0) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
if (parser.status > 0)
|
||||
break;
|
||||
}
|
||||
ASSERT_on_iret(ret, "recv");
|
||||
ASSERT_pl(parser.status == 1);
|
||||
// printf("Log: worker received clients request\n%s\n", client_request.toString().c_str());
|
||||
assert(parser.status == 1);
|
||||
return res;
|
||||
}
|
||||
|
||||
@ -123,10 +123,35 @@ namespace een9 {
|
||||
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) {
|
||||
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);
|
||||
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) {
|
||||
@ -156,13 +181,13 @@ namespace een9 {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// todo: retrieve address of connected client
|
||||
|
||||
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");
|
||||
size_t Nip = params.ports_to_listen.size();
|
||||
ASSERT(Nip > 0, "No open listeting addresses");
|
||||
size_t CRL_Nip = params.client_regular_listened.size();
|
||||
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<uptr<WorkersEnv>> wtes(params.slave_number);
|
||||
@ -173,44 +198,49 @@ namespace een9 {
|
||||
pthread_create(&workers[i], NULL, worker_func, wtes[i].get());
|
||||
}
|
||||
|
||||
// todo: move this try block inside the loop
|
||||
try {
|
||||
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++) {
|
||||
printf("Creating listening socket\n");
|
||||
uint16_t port = params.ports_to_listen[i];
|
||||
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);
|
||||
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;
|
||||
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");
|
||||
ret = bind(listening_socket(), (const sockaddr*)&listening_address, sizeof(listening_address));
|
||||
ASSERT_on_iret(ret, "binding to INADDR_ANY:" + std::to_string(port));
|
||||
printf("Binded socket to address\n");
|
||||
ASSERT_on_iret(ret, "Can't set SO_REUSEADDR");
|
||||
bind_to_socket_address(listening_socket_fd, ears[i].my_addr);
|
||||
ret = listen(listening_socket(), 128);
|
||||
ASSERT_on_iret(ret, "listening for connections");
|
||||
printf("Listening socket succesfully started listening\n");
|
||||
listening_socks[i] = std::move(listening_socket);
|
||||
ASSERT_on_iret(ret, "listen() listening for connections");
|
||||
ears[i].listening_sock = std::move(listening_socket);
|
||||
}
|
||||
std::vector<pollfd> pollfds(Nip);
|
||||
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;
|
||||
}
|
||||
printf("Entering mainloop\n");
|
||||
ASSERT(params.mainloop_recheck_interval_us > 0, "Incorrect poll timeout");
|
||||
while (true) {
|
||||
MutexLockGuard lg1(wtec.corvee_bed, "poller termination check");
|
||||
// MutexLockGuard lg1(wtec.corvee_bed, "poller termination check");
|
||||
if (wtec.termination)
|
||||
break;
|
||||
lg1.unlock();
|
||||
// lg1.unlock();
|
||||
for (size_t i = 0; i < Nip; i++) {
|
||||
pollfds[i].revents = 0;
|
||||
}
|
||||
@ -218,21 +248,24 @@ namespace een9 {
|
||||
ret = poll(pollfds.data(), Nip, params.mainloop_recheck_interval_us);
|
||||
if (errno == EINTR)
|
||||
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++) {
|
||||
if ((pollfds[i].revents & POLLRDNORM)) {
|
||||
try {
|
||||
sockaddr client_address;
|
||||
socklen_t client_addr_len = sizeof(client_address);
|
||||
int session_sock = accept(pollfds[i].fd, &client_address, &client_addr_len);
|
||||
int session_sock = accept(pollfds[i].fd, NULL, NULL);
|
||||
ASSERT_on_iret(session_sock, "Failed to accept incoming connection");
|
||||
printf("Log: successful connection\n");
|
||||
UniqueFdWrapper session_sock_fdw(session_sock);
|
||||
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");
|
||||
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(),
|
||||
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)
|
||||
wtec.queue.push_back(std::move(task));
|
||||
}
|
||||
|
@ -7,12 +7,14 @@
|
||||
#include "os_utils.h"
|
||||
#include "http_structures/client_request.h"
|
||||
#include <stdint.h>
|
||||
#include "socket_address.h"
|
||||
|
||||
namespace een9 {
|
||||
struct ConnectionInfo {
|
||||
// todo: add server address field
|
||||
// todo: add client address field
|
||||
int type; // O_o why??
|
||||
SocketAddress server_name;
|
||||
SocketAddress client_name;
|
||||
/* 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
|
||||
@ -33,6 +35,8 @@ namespace een9 {
|
||||
|
||||
/* 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;
|
||||
/* 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 {
|
||||
size_t critical_load_1 = 90;
|
||||
@ -42,15 +46,19 @@ namespace een9 {
|
||||
};
|
||||
|
||||
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 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;
|
||||
std::vector<uint16_t> ports_to_listen;
|
||||
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;
|
||||
};
|
||||
|
||||
|
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) {
|
||||
size_t oldN = result.size();
|
||||
result.resize(oldN + ret);
|
||||
memcpy((void*)&result.c_str()[oldN], buf, ret);
|
||||
memcpy(result.data() + oldN, buf, ret);
|
||||
}
|
||||
if (ret < 0) {
|
||||
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 | ");
|
||||
} else {
|
||||
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);
|
||||
// todo: THIS F. B.S. IS NOT SAFE
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ int main(int argc, char** argv){
|
||||
if (argc != 1 + 2)
|
||||
usage(argv);
|
||||
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]);
|
||||
usage(argv);
|
||||
}
|
||||
|
@ -9,7 +9,7 @@
|
||||
#include <engine_engine_number_9/form_data_structure/urlencoded_query.h>
|
||||
#include <new_york_transit_line/templater.h>
|
||||
#include <sqlite3.h>
|
||||
|
||||
#include <engine_engine_number_9/socket_address.h>
|
||||
|
||||
bool termination = false;
|
||||
|
||||
@ -17,19 +17,8 @@ void sigterm_action(int) {
|
||||
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) {
|
||||
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();
|
||||
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();
|
||||
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 */
|
||||
std::vector<std::unique_ptr<nytl::Templater>> templaters_copies(8);
|
||||
for (int i = 0; i < 8; i++) {
|
||||
templaters_copies[i] = std::make_unique<nytl::Templater>(
|
||||
een9::uptr<nytl::Templater> 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"}});
|
||||
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;
|
||||
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 {
|
||||
een9_ASSERT_pl(0 <= worker_id && worker_id < templaters_copies.size());
|
||||
nytl::Templater& templater = *templaters_copies[worker_id];
|
||||
een9_ASSERT_pl(0 <= worker_id && worker_id < worker_guest_data.size());
|
||||
nytl::Templater& templater = *worker_guest_data[worker_id].templater;
|
||||
een9::StaticAsset sa;
|
||||
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 {
|
||||
std::string page = templater.render(el_name,
|
||||
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>");
|
||||
};
|
||||
|
||||
params.ports_to_listen = {1025};
|
||||
params.slave_number = 8;
|
||||
params.open_admin_listener = false;
|
||||
params.guest_core_admin_control = []
|
||||
(const een9::SlaveTask& task, const std::string& req, een9::worker_id_t) -> std::string {
|
||||
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(SIGTERM, sigterm_action);
|
||||
|
Loading…
Reference in New Issue
Block a user