Compare commits

..

No commits in common. "925c072039fb7e95e0d65b5f2916f82de6b4eb8a" and "06d5a334957eb4ceb424ea8c0d55931f15dad366" have entirely different histories.

36 changed files with 297 additions and 1181 deletions

1
.gitignore vendored
View File

@ -13,4 +13,3 @@ compile_commands.json
local.sh
iu9-ca-web-chat.db
log/

View File

@ -69,7 +69,9 @@ regexis024_build_system.sh
Зачем писать комментарии в коде, если можно их вынести в отдельные пдф-ки?
- [Документация для разработчиков](
- [API сервиса](
https://gitlab.yyyi.ru/collarbone-annihilation/iu9-ca-chat-api)
- [Доки New York Transit Line](
https://gitlab.yyyi.ru/collarbone-annihilation/new_york_transit_line_documentation_rus)
О том как работает всё остальное можно только догадываться.

View File

@ -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++17", "-D", "_POSIX_C_SOURCE=200809L"};
std::vector<std::string> version_flags = {"--std", "c++14", "-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,8 +78,6 @@ struct CAWebChat {
"connecting_assets/static_asset_manager.cpp",
"running_mainloop.cpp",
"form_data_structure/urlencoded_query.cpp",
"socket_address.cpp",
"admin_control.cpp",
};
for (std::string& u: T.units)
u = "http_server/engine_engine_number_9/" + u;
@ -95,12 +93,11 @@ 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;
T.installation_dir = "een9";
T.installation_dir = "";
my_targets.push_back(T);
}
{ CTarget T{"new_york_transit_line", "shared_library"};
@ -124,7 +121,6 @@ struct CAWebChat {
};
for (std::string& u: T.exported_headers)
u = "new_york_transit_line/" + u;
T.installation_dir = "nytl";
my_targets.push_back(T);
}
{ CTarget T{"iu9-ca-web-chat", "executable"};
@ -142,27 +138,13 @@ struct CAWebChat {
"run.cpp",
"str_fields_check.cpp",
"find_db.cpp",
"sqlite3_wrapper.cpp",
};
for (std::string& u: T.units)
u = "web_chat/iu9_ca_web_chat_service/" + u;
u = "web_chat/" + u;
T.include_pr = "web_chat";
T.installation_dir = "";
my_targets.push_back(T);
}
{ CTarget T{"iu9-ca-web-chat-admin-cli", "executable"};
T.additional_compilation_flags = getSomeRadFlags();
T.proj_deps = {
CTargetDependenceOnProjectsLibrary{"engine_engine_number_9"},
};
T.units = {
"cli.cpp", // Main file
};
for (std::string& u: T.units)
u = "web_chat/iu9_ca_web_chat_admin_cli/" + u;
T.include_pr = "web_chat";
my_targets.push_back(T);
}
regular_ctargets_to_2bus_conversion(ext_targets, my_targets, runlevel_1, runlevel_2,
cmd.project_root, cmd.installation_root);
}
@ -177,8 +159,8 @@ int main(int argc, char** argv) {
}
NormalCBuildSystemCommandMeaning cmd;
regular_bs_cli_cmd_interpret(args, cmd);
const char* BS_SCRIPT_TYPE = getenv("BSCRIPT_TYPE");
const char* BS_SCRIPT_TESTS = getenv("BSCRIPT_TESTS");
const char* BS_SCRIPT_TYPE = getenv("BS_SCRIPT_TYPE");
const char* BS_SCRIPT_TESTS = getenv("BS_SCRIPT_TESTS");
CAWebChat bs(BS_SCRIPT_TYPE ? BS_SCRIPT_TYPE : "release", (bool)BS_SCRIPT_TESTS, cmd);
if (cmd.need_to_build)
complete_tasks_of_build_units(bs.runlevel_1);

View File

@ -31,6 +31,6 @@
"server": {
"workers": 8,
"http-listen": ["127.0.0.1:1025"],
"admin-command-listen": ["127.0.0.1:1026"]
"command-listen": []
}
}

View File

@ -1,62 +0,0 @@
#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 {
body += ch;
if (body.size() >= b_sz)
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 = ms;
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);
}
}

View File

@ -1,37 +0,0 @@
#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

View File

@ -28,30 +28,14 @@ namespace een9 {
return false;
}
bool endsWith(const std::string &a, const std::string &b) {
bool endsIn(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;
}
}

View File

@ -18,17 +18,11 @@ namespace een9 {
bool strIn(const std::string& str, const char* arr[]);
// 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);
bool endsIn(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>;
}

View File

@ -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 (endsWith(file, ext.required_postfix)) {
if (endsIn(file, ext.required_postfix)) {
/* Found it! */
StaticAsset etot{ext.assigned_type, };
readFile(dir_rule.directory + "/" + file, etot.content);

View File

@ -3,14 +3,6 @@
#include <libregexis024tools/delayed_matching.h>
#include <algorithm>
#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() {
@ -107,10 +99,8 @@ namespace een9 {
if (p.first == "Content-Length") {
collecting_body = res.has_body = true;
body_size = std::stoull(p.second);
if (body_size > 100000000) {
status = -1;
return status;
}
if (body_size > 100000000)
THROW("Message content is too big");
res.body.reserve(body_size);
}
}
@ -119,11 +109,8 @@ namespace een9 {
}
/* We either finish now or we finish later */
} else if (!vm.haveSurvivors()) {
#ifdef DEBUG_ALLOW_LOUD
mkdir("log", 0750);
writeFile("log/req", header);
#endif
status = -1;
THROW("bad request");
}
}
return status;

View File

@ -37,6 +37,7 @@ 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;

View File

@ -25,6 +25,7 @@ namespace een9 {
}
UniqueFdWrapper::~UniqueFdWrapper() {
// printf("DEBUG!!! Closing fd = %d\n", fd);
if (fd >= 0)
close(fd);
}
@ -54,7 +55,7 @@ namespace een9 {
while ((ret = (int)read(fd, buf, 2048)) > 0) {
size_t oldN = result.size();
result.resize(oldN + ret);
memcpy(result.data() + oldN, buf, ret);
memcpy((void*)&result.c_str()[oldN], buf, ret);
}
ASSERT_on_iret(ret, "Reading from " + description);
}
@ -66,28 +67,6 @@ namespace een9 {
readFromFileDescriptor(fdw(), result, "file \"" + path + "\"");
}
/* write(fd, text); close(fd); */
void writeToFileDescriptor(int fd, const std::string& text, const std::string& description = "") {
size_t n = text.size();
size_t i = 0;
while (i < n) {
size_t block = std::min(2048lu, n - i);
int ret = write(fd, &text[i], block);
ASSERT_on_iret(ret, "Writing to" + description);
i += ret;
}
close(fd);
}
/* Truncational */
void writeFile(const std::string& path, const std::string& text) {
int fd = open(path.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0755);
ASSERT_on_iret(fd, "Opening \"" + path + "\"");
UniqueFdWrapper fdw(fd);
writeToFileDescriptor(fdw(), text, "file \"" + path + "\n");
}
void configure_socket_rcvsndtimeo(int fd, timeval tv) {
int ret;
ret = setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(timeval));

View File

@ -30,8 +30,6 @@ namespace een9 {
void readFile(const std::string& path, std::string& result);
void writeFile(const std::string& path, const std::string& text);
void configure_socket_rcvsndtimeo(int fd, timeval tv);
}

View File

@ -13,7 +13,6 @@
#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 {
@ -74,13 +73,11 @@ 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, const MainloopParameters& params): termination(term),
guest_core(params.guest_core), guest_core_admin_control(params.guest_core_admin_control){}
WorkersEnvCommon(bool& term, guest_core_t g_c): termination(term), guest_core(std::move(g_c)){}
};
struct WorkersEnv {
@ -92,22 +89,25 @@ namespace een9 {
};
// todo: add timeout for multiple bytes, add more settings
ClientRequest process_http_connection_input(int fd, const EEN9_ServerTips& s_tips, WorkersEnv& wte) {
ClientRequest process_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(parser.status == 0);
ASSERT_pl(parser.status == 0);
while ((ret = (int)recv(fd, buf, 2048, 0)) > 0) {
for (size_t i = 0; i < ret; i++) {
if (parser.feedCharacter(buf[i]) != 0)
/* Throws ServerError on bad input */
if (parser.feedCharacter(buf[i]) > 0) {
break;
}
if (parser.status != 0)
}
if (parser.status > 0)
break;
}
ASSERT(parser.status == 1, "Incorrect request"); // todo: do the same thing everywhere else
ASSERT_on_iret(ret, "recv");
ASSERT_pl(parser.status == 1);
// printf("Log: worker received clients request\n%s\n", client_request.toString().c_str());
return res;
}
@ -123,41 +123,10 @@ 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(pctx.status == 1, "Incorrect request");
ASSERT_on_iret(ret, "recv");
return pctx.body;
}
void process_connection(const SlaveTask& task, WorkersEnv& wte) {
if (task.conn_info.type == 0) {
printf("%d::Got http reuest\n", wte.id);
ClientRequest client_request = process_http_connection_input(task.fd(), task.s_tips, wte);
printf("%d::Http request has been read\n", wte.id);
ClientRequest client_request = process_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);
printf("%d::Http response has been sent\n", wte.id);
} else if (task.conn_info.type == 1) {
printf("%d::Got admin-cmd request\n", wte.id);
std::string admin_request = process_admin_control_connection_input(task.fd(), task.s_tips, wte);
printf("%d::Admin-cmd request has been read\n", wte.id);
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);
printf("%d::Admin-cmd response has been sent\n", wte.id);
}
}
void* worker_func(void* wte_ptr) {
@ -187,13 +156,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);
WorkersEnvCommon wtec(termination_trigger, params.guest_core);
ASSERT(params.slave_number > 0, "No workers spawned");
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;
size_t Nip = params.ports_to_listen.size();
ASSERT(Nip > 0, "No open listeting addresses");
std::vector<pthread_t> workers(params.slave_number);
std::vector<uptr<WorkersEnv>> wtes(params.slave_number);
@ -204,49 +173,44 @@ namespace een9 {
pthread_create(&workers[i], NULL, worker_func, wtes[i].get());
}
// todo: move this try block inside the loop
try {
int ret;
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;
}
std::vector<UniqueFdWrapper> listening_socks(Nip);
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, "Can't set SO_REUSEADDR");
bind_to_socket_address(listening_socket_fd, ears[i].my_addr);
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");
ret = listen(listening_socket(), 128);
ASSERT_on_iret(ret, "listen() listening for connections");
ears[i].listening_sock = std::move(listening_socket);
ASSERT_on_iret(ret, "listening for connections");
printf("Listening socket succesfully started listening\n");
listening_socks[i] = std::move(listening_socket);
}
std::vector<pollfd> pollfds(Nip);
for (size_t i = 0; i < Nip; i++) {
pollfds[i].fd = ears[i].listening_sock();
pollfds[i].fd = listening_socks[i]();
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;
}
@ -254,24 +218,21 @@ namespace een9 {
ret = poll(pollfds.data(), Nip, params.mainloop_recheck_interval_us);
if (errno == EINTR)
break;
// todo: do not end program here (in the loop. Nothing in the loop should be able to end program)
ASSERT_on_iret(ret, "poll()");
ASSERT_on_iret(ret, "polling");
for (size_t i = 0; i < Nip; i++) {
if ((pollfds[i].revents & POLLRDNORM)) {
try {
int session_sock = accept(pollfds[i].fd, NULL, NULL);
sockaddr client_address;
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");
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{ears[i].my_addr, peer_addr, ears[i].type},
std::move(session_sock_fdw),
SlaveTask task{ConnectionInfo{}, 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));
}

View File

@ -7,14 +7,12 @@
#include "os_utils.h"
#include "http_structures/client_request.h"
#include <stdint.h>
#include "socket_address.h"
namespace een9 {
struct ConnectionInfo {
SocketAddress server_name;
SocketAddress client_name;
/* 0 - http, 1 - 'een9::admin-control' protocol */
int type;
// todo: add server address field
// todo: add client address field
int type; // O_o why??
};
/* This structure is passed to guest function. It contains server info that might be or might be not used
@ -35,8 +33,6 @@ 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;
@ -46,18 +42,14 @@ 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;
size_t slave_number = 2;
int mainloop_recheck_interval_us = 100;
/* Takes parsed http request object. Should return fully-prepared http response */
bool open_admin_listener = true;
// todo: add support for unix socket address
uint16_t admin_listener_port = 12345;
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;
size_t slave_number = 2;
std::vector<uint16_t> ports_to_listen;
int mainloop_recheck_interval_us = 100;
ServersConfiguration s_conf;
};

View File

@ -1,277 +0,0 @@
#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) {
sa_family_t f = addr.v.gen.sa_family;
if (f == AF_INET || f == AF_INET6 || f == AF_UNIX) {
int ret = bind(sockfd, &addr.v.gen, addr.addrLen);
ASSERT_on_iret(ret, "binding socket");
} else
THROW("binding socket to address of unsupported domain");
}
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;
}
void connect_to_socket_address(int sockfd, const SocketAddress& targ) {
int ret = connect(sockfd, &targ.v.gen, targ.addrLen);
ASSERT_on_iret(ret, "connect socket to addr");
}
}

View File

@ -1,53 +0,0 @@
#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&) = delete;
SocketAddressParser& operator=(const SocketAddressParser&) = delete;
~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);
void connect_to_socket_address(int sockfd, const SocketAddress& targ);
}
#endif

View File

@ -1,73 +0,0 @@
#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("127:0:0:1:1026", false, 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);
}

View File

@ -100,7 +100,7 @@ namespace nytl {
while ((ret = (int)read(fd, buf, 2048)) > 0) {
size_t oldN = result.size();
result.resize(oldN + ret);
memcpy(result.data() + oldN, buf, ret);
memcpy((void*)&result.c_str()[oldN], buf, ret);
}
if (ret < 0) {
close(fd);

View File

@ -0,0 +1,4 @@
AAA
{% FOR _:val IN cba %}
TUTUTUTUTUTUTUTUN {% PUT jesccomp val %}
{% ENDFOR %}

View File

@ -0,0 +1,59 @@
#include "actions.h"
#include <engine_engine_number_9/baza_throw.h>
#include "str_fields_check.h"
#include <sqlite3.h>
#include <engine_engine_number_9/os_utils.h>
#include <find_db.h>
void sqlite_single_statement(sqlite3* db_hand, const std::string& req_statement) {
sqlite3_stmt* stmt_obj = NULL;
int ret = sqlite3_prepare16_v2(db_hand, req_statement.c_str(), -1, &stmt_obj, NULL);
een9_ASSERT(ret == 0, "Can't compile request expression");
struct Guard1{sqlite3_stmt*& r; ~Guard1(){if (sqlite3_finalize(r) != 0) {abort();}}} guard1{stmt_obj};
while (true) {
ret = sqlite3_step(stmt_obj);
if (ret == SQLITE_DONE)
break;
if (ret != SQLITE_ROW) {
printf("sqlite_row error!!!\n");
printf("%s\n", sqlite3_errmsg(db_hand));
break;
}
int cc = sqlite3_column_count(stmt_obj);
std::vector<int> types(cc);
for (int i = 0; i < cc; i++) {
types[i] = sqlite3_column_type(stmt_obj, i);
}
printf("Column: |");
for (int i = 0; i < cc; i++) {
switch (types[i]) {
#define ccase(tname) case SQLITE_ ## tname: printf(" " #tname " |"); break;
ccase(INTEGER)
ccase(FLOAT)
ccase(BLOB)
ccase(NULL)
case SQLITE3_TEXT:
printf(" TEXT |"); break;
}
}
printf("\n");
}
printf("Request steps are done\n");
}
void initialize_website(const json::JSON& config, const std::string& root_pw) {
printf("Initialization...\n");
een9_ASSERT(check_password(root_pw), "Bad root password");
std::string db_path;
int ret;
ret = find_db_sqlite_file_path(config, db_path);
een9_ASSERT(ret == 0, "Invalid settings[\"database\"] field");
een9_ASSERT(!een9::isRegularFile(db_path), "Database file exists prior to initialization. "
"Can't preceed withut harming existing data");
// sqlite3* db_hand = NULL;
// ret = sqlite3_open(db_path.c_str(), &db_hand);
// een9_ASSERT(ret == 0, "Can't open database");
// struct Guard1{sqlite3*& dhp; ~Guard1(){if (sqlite3_close(dhp) != 0) {abort();}}} guard1{db_hand};
// sqlite_single_statement(db_hand, "CREATE TABLE tb(a INT, b INT);");
// todo: actually write something
}

View File

@ -1,85 +0,0 @@
#include <engine_engine_number_9/admin_control.h>
#include <engine_engine_number_9/socket_address.h>
#include <engine_engine_number_9/baza_throw.h>
#include <assert.h>
#include <engine_engine_number_9/os_utils.h>
/* This so called 'een9::admin-control' protocol is very simple:
* Admin sends request to server:
* <Magic constant string> <8 byte field: size of body> <body (string of any characters)>
* Server reads it to the end and sents response to admin:
* <Magic constant string> <8 byte field: size of body> <body (string of any characters)>
* More can be found in src/http_server/engine_engine_number_9/admin_control.cpp
*/
void send_request_msg(int fd, const std::string& request_msg) {
std::string str = een9::generate_admin_control_request(request_msg);
size_t N = str.size(), i = 0;
while (i < N) {
int written = (int)send(fd, &str[i], std::min(2048lu, N - i), MSG_NOSIGNAL);
een9_ASSERT_on_iret(written, "sending");
een9_ASSERT_pl(written > 0);
i += written;
}
}
std::string receive_response_msg(int fd) {
een9::AdminControlResponseRCtx 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;
}
een9_ASSERT(pctx.status == 1, "Received incorrect response");
een9_ASSERT_on_iret(ret, "recv");
return pctx.body;
}
void usage(char* za) {
printf("%s <address of servers admin cmd listener> <message> [<other parts of message> ...]\n", za);
exit(1);
}
void funny_log_print(const char* str) {
printf("===\\\\\n -=| %s\n===//\n", str);
}
int main(int argc, char** argv) {
if (argc < 1)
return 134;
if (argc < 3) {
usage(argv[0]);
}
try {
std::string conn_addr_targ = argv[1];
std::string msg;
for (int i = 2; i < argc; i++) {
if (!msg.empty())
msg += '\n';
msg += argv[i];
}
int ret;
een9::SocketAddressParser sap;
een9::SocketAddress addr;
ret = een9::parse_socket_address(conn_addr_targ, addr, sap);
een9_ASSERT(ret == 0, "Incorrect address");
int sock = socket(addr.v.gen.sa_family, SOCK_STREAM, 0);
een9_ASSERT_on_iret(sock, "creating socket to target server");
een9::UniqueFdWrapper sockGuard(sock);
een9::connect_to_socket_address(sock, addr);
funny_log_print("Ready to send request");
send_request_msg(sock, msg);
funny_log_print("Admin-cmd request has been sent");
std::string answer = receive_response_msg(sock);
funny_log_print("Admin-cmd response has been read");
printf("Output:\n%s", answer.c_str());
} catch (const std::exception& e) {
printf("%s\n", e.what());
}
}

View File

@ -1,76 +0,0 @@
#include "actions.h"
#include <engine_engine_number_9/baza_throw.h>
#include "str_fields_check.h"
#include <sqlite3.h>
#include <engine_engine_number_9/os_utils.h>
#include "find_db.h"
#include <unistd.h>
#include <assert.h>
#include "sqlite3_wrapper.h"
void initialize_website(const json::JSON& config, const std::string& root_pw) {
printf("Initialization...\n");
een9_ASSERT(check_password(root_pw), "Bad root password");
std::string db_path;
int ret;
ret = find_db_sqlite_file_path(config, db_path);
een9_ASSERT(ret == 0, "Invalid settings[\"database\"] field");
if (een9::isRegularFile(db_path)) {
// todo: plaese, don't do this
ret = unlink(db_path.c_str());
een9_ASSERT_pl(ret == 0);
}
een9_ASSERT(!een9::isRegularFile(db_path), "Database file exists prior to initialization. "
"Can't preceed withut harming existing data");
SqliteConnection conn(db_path.c_str());
assert(sqlite3_errcode(conn.hand) == SQLITE_OK);
/* Role of memeber of chat:
* 1 - admin
* 2 - regular
* 3 - read-only member
* 4 - deleted (no longer a member)
*
* If user.id is 0, it is a root user
* If chat.lastMsgId is NULL, chat is empty
* If message.previous is NULL, this message is first in it's chat
*/
sqlite_single_statement(conn.hand, "PRAGMA foreign_keys = true");
sqlite_single_statement(conn.hand, "BEGIN");
sqlite_single_statement(conn.hand, "CREATE TABLE `nickname` (`it` TEXT PRIMARY KEY NOT NULL) WITHOUT ROWID");
sqlite_single_statement(conn.hand, "CREATE TABLE `user` ("
"`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,"
"`nickname` TEXT UNIQUE REFERENCES `nickname` NOT NULL,"
"`name` TEXT NOT NULL,"
"`chatList_HistoryId` INTEGER NOT NULL,"
"`password` TEXT NOT NULL"
")");
sqlite_single_statement(conn.hand, "CREATE TABLE `chat` ("
"`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,"
"`nickname` TEXT UNIQUE REFERENCES `nickname` NOT NULL,"
"`name` TEXT NOT NULL,"
"`it_HistoryId` INTEGER NOT NULL,"
"`lastMsgId` INTEGER REFERENCES `message`"
")");
sqlite_single_statement(conn.hand, "CREATE TABLE `user_chat_membership` ("
"`userId` INTEGER REFERENCES `user` NOT NULL,"
"`chatId` INTEGER REFERENCES `chat` NOT NULL,"
"`user_chatList_IncHistoryId` INTEGER NOT NULL,"
"`chat_IncHistoryId` INTEGER NOT NULL,"
"`role` INTEGER NOT NULL"
")");
sqlite_single_statement(conn.hand, "CREATE TABLE `message` ("
"`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,"
"`chatId` INTEGER REFERENCES `chat` NOT NULL,"
"`previous` INTEGER REFERENCES `message`,"
"`senderUserId` INTEGER REFERENCES `user` NOT NULL,"
"`exists` BOOLEAN NOT NULL,"
"`isSystem` BOOLEAN NOT NULL,"
"`text` TEXT NOT NULL,"
"`chat_IncHistoryId` INTEGER NOT NULL"
")");
sqlite_single_statement(conn.hand, "INSERT INTO `nickname` VALUES (?1)", {}, {{1, "root"}});
sqlite_single_statement(conn.hand, "INSERT INTO `user` (`id`, `nickname`, `name`, `chatList_HistoryId`, `password`) VALUES "
"(0, ?1, ?2, 0, ?3)", {},
{{1, "root"}, {2, "Rootov Root Rootovich"}, {3, root_pw}});
sqlite_single_statement(conn.hand, "END");
}

View File

@ -1,138 +0,0 @@
#include "actions.h"
#include <engine_engine_number_9/baza_throw.h>
#include <engine_engine_number_9/running_mainloop.h>
#include <engine_engine_number_9/http_structures/response_gen.h>
#include <signal.h>
#include <engine_engine_number_9/connecting_assets/static_asset_manager.h>
#include <assert.h>
#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>
#include "sqlite3_wrapper.h"
#include "str_fields_check.h"
#include "find_db.h"
bool termination = false;
void sigterm_action(int) {
termination = true;
}
void run_website(const json::JSON& config) {
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");
een9::StaticAssetManagerSlaveModule samI;
samI.update({
een9::StaticAssetManagerRule{assets_dir + "/css", "/assets/css", {{".css", "text/css"}} },
een9::StaticAssetManagerRule{assets_dir + "/js", "/assets/js", {{".js", "text/js"}} },
een9::StaticAssetManagerRule{assets_dir + "/img", "/assets/img", {
{".jpg", "image/jpg"}, {".png", "image/png"}, {".svg", "image/svg+xml"}
} },
});
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");
std::string sqlite_db_path;
int ret = find_db_sqlite_file_path(config, sqlite_db_path);
een9_ASSERT(ret == 0, "Can't find database file");
struct WorkerGuestData {
/* Because templaters use libjsonincpp, they can't be READ by two thread simultaneously */
std::unique_ptr<nytl::Templater> templater;
std::unique_ptr<SqliteConnection> db;
};
std::vector<WorkerGuestData> worker_guest_data(slave_number);
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"}});
worker_guest_data[i].templater->update();
worker_guest_data[i].db = std::make_unique<SqliteConnection>(sqlite_db_path);
}
een9::MainloopParameters params;
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 < worker_guest_data.size());
WorkerGuestData& wgd = worker_guest_data[worker_id];
nytl::Templater& templater = *wgd.templater;
een9::StaticAsset sa;
int ret;
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*>{});
return een9::form_http_server_response_200("text/html", page);
};
if (req.uri_path == "/" || req.uri_path == "/list-rooms") {
return rteee("list-rooms", true);
}
if (req.uri_path == "/chat") {
return rteee("chat", false);
}
if (req.uri_path == "/profile") {
return rteee("profile", false);
}
if (req.uri_path == "/registration") {
return rteee("registration", false);
}
/* Trying to interpret request as asset lookup */
ret = samI.get_asset(req.uri_path, sa);
if (ret >= 0) {
return een9::form_http_server_response_200(sa.type, sa.content);
}
return een9::form_http_server_response_404("text/html", "<h1> Not found! </h1>");
};
params.guest_core_admin_control = [&worker_guest_data]
(const een9::SlaveTask& task, const std::string& req, een9::worker_id_t worker_id) -> std::string {
een9_ASSERT_pl(0 <= worker_id && worker_id < worker_guest_data.size());
WorkerGuestData& wgd = worker_guest_data[worker_id];
try {
if (req == "hello") {
return ":0 omg! hiii!! Hewwou :3 !!!!";
}
if (req == "8") {
termination = true;
return "Bye";
}
std::string updaterootpw_pref = "updaterootpw";
if (een9::beginsWith(req, "updaterootpw")) {
size_t nid = updaterootpw_pref.size();
if (nid >= req.size() || !isSPACE(req[nid]))
return "Bad command syntax. Missing whitespace";
std::string new_password = req.substr(nid + 1);
if (!check_password(new_password))
een9_THROW("Bad password");
sqlite_single_statement(wgd.db->hand,
"UPDATE `user` SET `password` = ?1 WHERE `id` = 0 ",
{}, {{1, new_password}});
return "Successul update";
}
return "Incorrect command";
} catch (std::exception& e) {
return std::string("Server error\n") + e.what();
}
};
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);
een9::electric_boogaloo(params, termination);
}

View File

@ -1,92 +0,0 @@
#include "sqlite3_wrapper.h"
#include "str_fields_check.h"
#include <engine_engine_number_9/baza_throw.h>
#include <assert.h>
#include <limits.h>
SqliteConnection::SqliteConnection(const std::string &file_path) {
int ret = sqlite3_open(file_path.c_str(), &hand);
if (ret != 0) {
een9_THROW(std::string("Can't open sqlite3 database ") + sqlite3_errstr(ret));
}
}
SqliteConnection::~SqliteConnection() {
if (sqlite3_close(hand) != 0) {abort();}
}
void sqlite_single_statement(sqlite3* db_hand, const std::string& req_statement,
const std::vector<std::pair<int, int64_t>>& int64_binds,
const std::vector<std::pair<int, std::string>>& text8_binds) {
sqlite3_stmt* stmt_obj = NULL;
int ret = sqlite3_prepare_v2(db_hand, req_statement.c_str(), -1, &stmt_obj, NULL);
if (ret != 0) {
int err_pos = sqlite3_error_offset(db_hand);
een9_THROW("Compilation of request\n" + req_statement + "\nfailed" +
((err_pos >= 0) ? " with offset " + std::to_string(err_pos) : ""));
}
een9_ASSERT(ret == 0, "Can't compile request expression");
assert(sqlite3_errcode(db_hand) == SQLITE_OK);
struct Guard1{sqlite3_stmt*& r; ~Guard1(){if (sqlite3_finalize(r) != 0) {abort();}}} guard1{stmt_obj};
for (const std::pair<int, int64_t>& bv: int64_binds) {
ret = sqlite3_bind_int64(stmt_obj, bv.first, bv.second);
een9_ASSERT(ret, "Can't bind to parameter #" + std::to_string(bv.first));
}
for (const std::pair<int, std::string>& bv: text8_binds) {
een9_ASSERT(is_orthodox_string(bv.second), "Can't bind this string to parameter");
een9_ASSERT(bv.second.size() + 1 < INT_MAX, "Ah, oh, senpai, your string is toooo huge");
ret = sqlite3_bind_text(stmt_obj, bv.first, bv.second.c_str(), (int)bv.second.size(), SQLITE_STATIC);
}
while (true) {
ret = sqlite3_step(stmt_obj);
if (ret == SQLITE_DONE)
break;
if (ret != SQLITE_ROW) {
printf("sqlite_row error!!!\n");
printf("%s\n", sqlite3_errmsg(db_hand));
break;
}
int cc = sqlite3_column_count(stmt_obj);
std::vector<int> types(cc);
for (int i = 0; i < cc; i++) {
types[i] = sqlite3_column_type(stmt_obj, i);
}
printf("Column: |");
for (int i = 0; i < cc; i++) {
switch (types[i]) {
#define ccase(tname) case SQLITE_ ## tname: printf(" " #tname " |"); break;
ccase(INTEGER)
ccase(FLOAT)
ccase(BLOB)
ccase(NULL)
case SQLITE3_TEXT:
printf(" TEXT |"); break;
default:
een9_THROW("AAAAAA");
}
}
printf("\n");
printf("Values: | ");
for (int i = 0; i < cc; i++) {
if (types[i] == SQLITE_INTEGER) {
printf("%lld | ", sqlite3_column_int64(stmt_obj, i));
} else if (types[i] == SQLITE_FLOAT) {
printf("%lf | ", sqlite3_column_double(stmt_obj, i));
} else if (types[i] == SQLITE_BLOB) {
const void* blob = sqlite3_column_blob(stmt_obj, i);
een9_ASSERT(sqlite3_errcode(db_hand) == SQLITE_OK, "oom in sqlite3_column_blob");
size_t sz = sqlite3_column_bytes(stmt_obj, i);
printf("Blob of size %lu | ", sz);
} else if (types[i] == SQLITE_NULL) {
printf("NULL | ");
} else {
const unsigned char* text = sqlite3_column_text(stmt_obj, i);
een9_ASSERT(text, "oom in sqlite3_column_text");
printf("%s | ", (const char*)text);
// todo: THIS F. B.S. IS NOT SAFE
}
}
printf("\n");
}
printf("Request steps are done\n");
}

View File

@ -1,21 +0,0 @@
#ifndef IU9_CA_WEB_CHAT_SERVICE_SQLITE_WRAP_H
#define IU9_CA_WEB_CHAT_SERVICE_SQLITE_WRAP_H
#include <sqlite3.h>
#include <vector>
#include <string>
struct SqliteConnection {
sqlite3* hand = NULL;
SqliteConnection() = default;
explicit SqliteConnection(const std::string& file_path);
SqliteConnection (const SqliteConnection&) = delete;
SqliteConnection& operator= (const SqliteConnection&) = delete;
~SqliteConnection();
};
void sqlite_single_statement(sqlite3* db_hand, const std::string& req_statement,
const std::vector<std::pair<int, int64_t>>& int64_binds= {},
const std::vector<std::pair<int, std::string>>& text8_binds = {});
#endif

View File

@ -5,21 +5,20 @@
#include "actions.h"
#include <stdexcept>
void usage(char* argv0) {
printf("Usage: %s <file with settings> <run|initialize>\n", argv0);
void usage(char** argv) {
printf("Usage: %s <file with settings> <run|initialize>\n", argv[0]);
exit(1);
}
int main(int argc, char** argv){
try {
if (argc < 1)
return 111;
een9_ASSERT_pl(argc > 0);
if (argc != 1 + 2)
usage(argv[0]);
usage(argv);
std::string config_file = argv[1];
if (!een9::isRegularFile(config_file) || !een9::endsWith(config_file, ".json")) {
if (!een9::isRegularFile(config_file) || !een9::endsIn(config_file, ".json")) {
printf("\"%s\" is not a json file\n", argv[1]);
usage(argv[0]);
usage(argv);
}
std::string cmd = argv[2];
std::string config_text;

103
src/web_chat/run.cpp Normal file
View File

@ -0,0 +1,103 @@
#include "actions.h"
#include <engine_engine_number_9/baza_throw.h>
#include <engine_engine_number_9/running_mainloop.h>
#include <engine_engine_number_9/http_structures/response_gen.h>
#include <signal.h>
#include <engine_engine_number_9/connecting_assets/static_asset_manager.h>
#include <assert.h>
#include <engine_engine_number_9/form_data_structure/urlencoded_query.h>
#include <new_york_transit_line/templater.h>
#include <sqlite3.h>
bool termination = false;
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");
std::string assets_dir = config["assets"].g().asString();
een9_ASSERT(een9::isDirectory(assets_dir), "\"" + assets_dir + "\" is not a directory");
een9::StaticAssetManagerSlaveModule samI;
samI.update({
een9::StaticAssetManagerRule{assets_dir + "/css", "/assets/css", {{".css", "text/css"}} },
een9::StaticAssetManagerRule{assets_dir + "/js", "/assets/js", {{".js", "text/js"}} },
een9::StaticAssetManagerRule{assets_dir + "/img", "/assets/img", {
{".jpg", "image/jpg"}, {".png", "image/png"}, {".svg", "image/svg+xml"}
} },
});
const json::JSON& config_presentation = config["presentation"].g();
/* 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>(
nytl::TemplaterSettings{nytl::TemplaterDetourRules{assets_dir + "/HypertextPages"}});
templaters_copies[i]->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]
(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::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*>{});
return een9::form_http_server_response_200("text/html", page);
};
if (req.uri_path == "/" || req.uri_path == "/list-rooms") {
return rteee("list-rooms", true);
}
if (req.uri_path == "/chat") {
return rteee("chat", false);
}
if (req.uri_path == "/profile") {
return rteee("profile", false);
}
if (req.uri_path == "/registration") {
return rteee("registration", false);
}
/* Trying to interpret request as asset lookup */
ret = samI.get_asset(req.uri_path, sa);
if (ret >= 0) {
return een9::form_http_server_response_200(sa.type, sa.content);
}
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;
signal(SIGINT, sigterm_action);
signal(SIGTERM, sigterm_action);
een9::electric_boogaloo(params, termination);
}

View File

@ -18,19 +18,12 @@ bool isSPACE(char ch) {
}
bool is_orthodox_string(const std::string &str) {
for (char ch: str)
if (ch == 0)
return false;
return json::isUtf8String(str);
}
bool check_password(const std::string &pwd) {
return is_orthodox_string(pwd) && pwd.size() >= 8;
return isUtf8String(pwd) && pwd.size() >= 8;
}
bool check_name(const std::string &name) {
return is_orthodox_string(name);
return isUtf8String(name);
}
bool check_nickname(const std::string &nickname) {

View File

@ -3,13 +3,6 @@
#include <string>
bool isALPHA(char ch);
bool isNUM(char ch);
bool isUNCHAR(char ch);
bool isSPACE(char ch);
bool is_orthodox_string(const std::string& str);
bool check_password(const std::string& pwd);
bool check_name(const std::string& name);
bool check_nickname(const std::string& nickname);