//-----------------------------------------------------------------------------
//(c) 2007-2024 pavel.pimenov@gmail.com
//-----------------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fstream>
#include <iostream>
#include <map>
//============================================================================================
#include <ctime>
#ifndef _WIN32 // Only in linux
#include <sys/time.h>
#include <unistd.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <cerrno>
#else
#include <direct.h>
#define snprintf _snprintf
#endif // _WIN32
#ifdef _WIN32 // Only in WIN32
#ifdef _DEBUG
// #define VLD_DEFAULT_MAX_DATA_DUMP 1
// #define VLD_FORCE_ENABLE // Uncoment this define to enable VLD in release
// #include "C:\Program Files (x86)\Visual Leak Detector\include\vld.h" // VLD ������ ��� http://vld.codeplex.com/
#endif
#endif
#include "CDBManager.h"
#ifndef _WIN32
#ifdef USE_LIBUNWIND
#define UNW_LOCAL_ONLY
#include <libunwind.h>
void show_backtrace (void) {
unw_cursor_t cursor; unw_context_t uc;
unw_word_t ip, sp;
unw_getcontext(&uc);
unw_init_local(&cursor, &uc);
while (unw_step(&cursor) > 0) {
unw_get_reg(&cursor, UNW_REG_IP, &ip);
unw_get_reg(&cursor, UNW_REG_SP, &sp);
printf ("ip = %lx, sp = %lx\n", (long) ip, (long) sp);
}
}
#endif //
#endif // _WIN32
//==========================================================================
CDBManager g_DB;
//==========================================================================
unsigned long long g_count_query = 0;
unsigned long long g_sum_out_size = 0;
unsigned long long g_sum_in_size = 0;
unsigned long long g_z_sum_out_size = 0;
unsigned long long g_z_sum_in_size = 0;
//==========================================================================
struct CFlyFloodCommand
{
sqlite_int64 m_start_tick;
sqlite_int64 m_tick;
unsigned m_count;
void init()
{
m_start_tick = 0;
m_tick = 0;
m_count = 0;
}
bool isCheckPoint() const
{
return (m_tick - m_start_tick) / 100 > 10;
}
bool isBan() const
{
return m_count > 100 && isCheckPoint();
}
CFlyFloodCommand()
{
init();
}
};
//==========================================================================
static std::map<std::string, CFlyFloodCommand> g_ip_counter;
//==========================================================================
static void check_ip_flood(const std::string& p_remote_ip, const int64_t p_tick)
{
CFlyFloodCommand& l_ip_stat = g_ip_counter[p_remote_ip];
if (l_ip_stat.m_count == 0)
{
l_ip_stat.m_start_tick = p_tick;
}
l_ip_stat.m_tick = p_tick;
l_ip_stat.m_count++;
if (l_ip_stat.isBan())
{
std::cout << "IP Flood IP = " << p_remote_ip << " count = " << l_ip_stat.m_count << std::endl;
#ifndef _WIN32
syslog(LOG_ERR, "IP Flood %s count = %d", p_remote_ip.c_str(), l_ip_stat.m_count);
#endif
// return MG_FALSE;
}
if (l_ip_stat.isCheckPoint())
{
l_ip_stat.init(); // �� 10 ��� �� ������� ����� ���������
}
}
//==========================================================================
static const char *g_html_form =
"<html><body>Error fly-server-test-port - contact: pavel.pimenov@gmail.com query</body></html>";
//==========================================================================
static const char* g_badRequestReply = "HTTP/1.1 400 Bad Request\r\n";
//==========================================================================
#if 0
//==========================================================================
static int begin_request_handler(struct mg_connection *conn, enum mg_event ev)
{
if (ev == MG_AUTH)
{
//dcassert(0);
return MG_TRUE;
}
if (ev == MG_REQUEST)
{
check_ip_flood(conn->remote_ip, get_tick_count());
CFlyServerContext l_flyserver_cntx;
l_flyserver_cntx.init_uri(conn->uri, mg_get_header(conn, "User-Agent"), mg_get_header(conn, "X-fly-response"));
l_flyserver_cntx.m_remote_ip = conn->remote_ip;
l_flyserver_cntx.m_content_len = conn->content_len;
if (l_flyserver_cntx.m_query_type != FLY_POST_QUERY_UNKNOWN)
{
if (conn->content_len <= 0)
{
mg_printf(conn, "%s", g_badRequestReply);
mg_printf(conn, "Error: no content\n");
std::cout << "Error: no content." << std::endl;
#ifndef _WIN32
syslog(LOG_ERR, "Error: no content");
#endif
return MG_TRUE;
}
l_flyserver_cntx.run_db_query(conn->content, conn->content_len, g_DB);
const int l_result_mg_printf = mg_printf(conn, "HTTP/1.1 200 OK\r\n" // TODO - HTTP/1.1 ?
"Content-Length: %lu\r\n\r\n",
l_flyserver_cntx.get_http_len());
/*
TODO - http://www.rsdn.ru/forum/network/5060321.1
const int l_result_mg_printf = mg_printf_dynamic(conn, l_http_len + 300, "HTTP/1.1 200 OK\r\n"
"Content-Length: %u\r\n"
"Content-Type: application/json\r\n"
"%s",
l_http_len,
l_is_zlib ? "Content-Encoding: deflate\r\n\r\n" : "\r\n"
);
*/
const int l_result_mg_write = mg_write(conn, l_flyserver_cntx.get_result_content(), l_flyserver_cntx.get_http_len());
g_sum_out_size += l_flyserver_cntx.m_res_stat.size();
g_sum_in_size += l_flyserver_cntx.get_real_query_size();
g_z_sum_out_size += l_flyserver_cntx.get_http_len();
g_z_sum_in_size += conn->content_len;
l_flyserver_cntx.send_syslog();
++g_count_query;
#ifdef _DEBUG
std::cout << "[DEBUG] l_result_mg_write = " << l_result_mg_write << " l_http_len = " << l_flyserver_cntx.get_http_len() << " l_result_mg_printf = " << l_result_mg_printf << std::endl;
#endif
return MG_TRUE;
}
else
{
// Show HTML form.
mg_printf(conn, "HTTP/1.1 200 OK\r\n"
"Content-Length: %d\r\n"
"Content-Type: text/html\r\n\r\n%s",
(int) strlen(g_html_form), g_html_form);
return MG_TRUE;
}
// Mark as processed
}
return MG_FALSE;
}
#endif
int g_test_port_exit_flag = 0;
//======================================================================================
class FlyServerHandler : public CivetHandler
{
private:
bool
handleAll(const char *method,
CivetServer *server,
struct mg_connection *conn)
{
/* Handler may access the request info using mg_get_request_info */
const struct mg_request_info *req_info = mg_get_request_info(conn);
CFlyServerContext l_flyserver_cntx;
l_flyserver_cntx.init_uri(req_info->request_uri,
mg_get_header(conn, "User-Agent"),
mg_get_header(conn, "X-fly-response"));
const char* l_real_ip = mg_get_header(conn, "X-Real-IP");
if (l_real_ip)
{
l_flyserver_cntx.m_remote_ip = l_real_ip;
//std::cout << "X-Real-IP = " << l_flyserver_cntx.m_remote_ip << std::endl;
}
else
{
l_flyserver_cntx.m_remote_ip = req_info->remote_addr;
}
l_flyserver_cntx.m_content_len = req_info->content_length;
if (l_flyserver_cntx.m_query_type != FLY_POST_QUERY_UNKNOWN)
{
if (req_info->content_length <= 0)
{
mg_printf(conn, "%s", g_badRequestReply);
mg_printf(conn, "Error: no content\n");
std::cout << "Error: no content." << std::endl;
#ifndef _WIN32
syslog(LOG_NOTICE, "Error: no content");
#endif
return true;
}
std::vector<char> buf; // TODO unique_ptr[]
buf.resize(l_flyserver_cntx.m_content_len+1);
buf[l_flyserver_cntx.m_content_len - 1] = 0;
long long rlen;
long long nlen = 0;
const long long tlen = req_info->content_length;
while (nlen < tlen) {
rlen = tlen - nlen;
rlen = mg_read(conn, buf.data()+ nlen, (size_t)rlen);
if (rlen <= 0) {
break;
}
#ifdef _DEBUG
std::cout << "[DEBUG] mg_read = " << rlen << std::endl;
#endif
nlen += rlen;
}
l_flyserver_cntx.run_db_query(buf.data(), l_flyserver_cntx.m_content_len, g_DB);
const int l_result_mg_printf = mg_printf(conn, "HTTP/1.1 200 OK\r\n" // TODO - HTTP/1.1 ?
"Content-Length: %lu\r\n\r\n",
l_flyserver_cntx.get_http_len());
const int l_result_mg_write = mg_write(conn, l_flyserver_cntx.get_result_content(), l_flyserver_cntx.get_http_len());
g_sum_out_size += l_flyserver_cntx.m_res_stat.size();
g_sum_in_size += l_flyserver_cntx.get_real_query_size();
g_z_sum_out_size += l_flyserver_cntx.get_http_len();
g_z_sum_in_size += l_flyserver_cntx.m_content_len;
l_flyserver_cntx.send_syslog();
++g_count_query;
#ifdef _DEBUG
std::cout << "[DEBUG] l_result_mg_write = " << l_result_mg_write <<
" l_http_len = " << l_flyserver_cntx.get_http_len() << " l_result_mg_printf = " << l_result_mg_printf << std::endl;
#endif
return true;
}
else
{
// Show HTML form.
mg_printf(conn, "HTTP/1.1 200 OK\r\n"
"Content-Length: %d\r\n"
"Content-Type: text/html\r\n\r\n%s",
(int)strlen(g_html_form), g_html_form);
return true;
}
// Mark as processed
return false; //TODO ?
}
public:
bool
handlePost(CivetServer *server, struct mg_connection *conn)
{
return handleAll("POST", server, conn);
}
};
//======================================================================================
void* run_fly_server_test_port(void*)
{
std::cout << std::endl << "* FlylinkDC++ server for test port (c) 2012-2024 pavel.pimenov@gmail.com " << std::endl
<< " - civetweb " << CIVETWEB_VERSION << " (c) https://github.com/civetweb/civetweb" << std::endl;
// << std::endl << "Usage: fly-server-test-port [-disable-syslog] [-disable-log-test-port]"
// << std::endl << std::endl;
g_setup_log_disable_test_port = true;
g_setup_syslog_disable = true;
/*
for (int i = 1; i < argc; i++)
{
const std::string l_argv = argv[i];
std::cout << "* try: " << l_argv << std::endl;
if (l_argv == "-disable-log-test-port")
{
g_setup_log_disable_test_port = true;
std::cout << "*[+] " << l_argv << std::endl;
}
if (l_argv == "-disable-syslog")
{
std::cout << "*[+] " << l_argv << std::endl;
}
}
*/
#ifndef _WIN32 // Only in linux
if (!g_setup_log_disable_test_port)
mkdir("log-test-port", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
#else
if (!g_setup_log_disable_test_port)
mkdir("log-test-port");
#endif
g_DB.init();
const char *options[] = {
// "document_root", ".",
"listening_ports", "37015",
"num_threads", "10",
"enable_directory_listing", "no",
0 };
std::vector<std::string> cpp_options;
for (int i = 0; i < (sizeof(options) / sizeof(options[0]) - 1); i++) {
cpp_options.push_back(options[i]);
std::cout << options[i];
std::cout << std::endl;
}
try
{
CivetServer server(cpp_options);
FlyServerHandler h_a;
server.addHandler("/", h_a);
while (g_test_port_exit_flag == 0)
{
#ifdef _WIN32
Sleep(10);
#else
sleep(1);
#endif
}
}
catch (CivetException& e)
{
std::cout << "CivetException:" << e.what() << std::endl;
}
CFlyServerContext::flush_log_array(true);
g_DB.shutdown();
std::cout << std::endl << "* fly-server-test-port shutdown!" << std::endl;
return NULL;
}
↑ V712 Be advised that compiler may delete this cycle or make it infinity. Use volatile variable(s) or synchronization primitives to avoid this.
↑ V547 Expression '!g_setup_log_disable_test_port' is always false.
↑ V776 Potentially infinite loop. The variable in the loop exit condition 'g_test_port_exit_flag == 0' does not change its value between iterations.