Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions examples/multithread/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,8 @@ multithread_CPPFLAGS = \
MAINTAINERCLEANFILES = \
Makefile.in

EXTRA_DIST = \
basic_rules.conf \
inspectfile_rules.conf \
inspectfile_helper.sh

10 changes: 10 additions & 0 deletions examples/multithread/inspectfile_helper.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/bin/sh

# deterministic helper for @inspectFile stress runs
if [ "$1" = "herewego" ]; then
echo 0
exit 0
fi

echo 1
exit 0
7 changes: 7 additions & 0 deletions examples/multithread/inspectfile_rules.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
SecDebugLog debug.log
SecDebugLogLevel 3

SecRuleEngine On

# ensure each transaction executes @inspectFile
SecRule ARGS:foo "@inspectFile ./inspectfile_helper.sh" "id:101,phase:2,pass,nolog,noauditlog,t:none"
84 changes: 74 additions & 10 deletions examples/multithread/multithread.cc
Original file line number Diff line number Diff line change
@@ -1,15 +1,24 @@
#include <iostream>
#include <thread>
#include <array>
#include <atomic>
#include <chrono>
#include <cstdlib>
#include <vector>

#ifndef WIN32
#include <dirent.h>
#endif

#include <modsecurity/modsecurity.h>
#include <modsecurity/transaction.h>
#include <modsecurity/rules_set.h>

static void process_request(modsecurity::ModSecurity *modsec, modsecurity::RulesSet *rules, int tid) {
static void process_request(modsecurity::ModSecurity *modsec,
modsecurity::RulesSet *rules, int tid, int iterations,
std::atomic<int> *completed_threads) {
std::cout << "Hello World! It's me, thread #" << tid << std::endl;

for(int i = 0; i != 1'000; i++) {
for (int i = 0; i != iterations; i++) {
auto modsecTransaction = std::make_unique<modsecurity::Transaction>(modsec, rules, nullptr);

modsecTransaction->processConnection("127.0.0.1", 12345, "127.0.0.1", 80);
Expand All @@ -32,29 +41,73 @@ static void process_request(modsecurity::ModSecurity *modsec, modsecurity::Rules
std::this_thread::sleep_for(std::chrono::microseconds(100));
}

completed_threads->fetch_add(1);
std::cout << "Thread #" << tid << " exits" << std::endl;
}

int main (int argc, char *argv[]) {
#ifndef WIN32
static int count_open_fds(void) {
int count = 0;
DIR *dir = opendir("/proc/self/fd");
if (dir == nullptr) {
return -1;
}

while (readdir(dir) != nullptr) {
count++;
}
closedir(dir);
return count;
}
#endif

int main (int argc, const char *argv[]) {
auto modsec = std::make_unique<modsecurity::ModSecurity>();
modsec->setConnectorInformation("ModSecurity-test v0.0.1-alpha (Simple " \
"example on how to use ModSecurity API");

const char main_rule_uri[] = "basic_rules.conf";
const char *main_rule_uri = "basic_rules.conf";
if (argc >= 2) {
main_rule_uri = argv[1];
}

int thread_count = 100;
if (argc >= 3) {
thread_count = std::atoi(argv[2]);
}

int iterations = 1000;
if (argc >= 4) {
iterations = std::atoi(argv[3]);
}

if (thread_count <= 0 || iterations <= 0) {
std::cerr << "Usage: ./multithread [rules.conf] [threads] [iterations]" << std::endl;
return 2;
}

auto rules = std::make_unique<modsecurity::RulesSet>();
if (rules->loadFromUri(main_rule_uri) < 0) {
std::cerr << "Problems loading the rules..." << std::endl;
std::cerr << rules->m_parserError.str() << std::endl;
return -1;
}

constexpr auto NUM_THREADS = 100;
std::array<std::thread, NUM_THREADS> threads;
std::vector<std::thread> threads;
threads.resize(thread_count);
std::atomic<int> completed_threads{0};

#ifndef WIN32
const int open_fds_before = count_open_fds();
std::cout << "open_fds_before=" << open_fds_before << std::endl;
#endif
auto start = std::chrono::steady_clock::now();

for (auto i = 0; i != threads.size(); ++i) {
threads[i] = std::thread(
[&modsec, &rules, i]() {
process_request(modsec.get(), rules.get(), i);
[&modsec, &rules, i, iterations, &completed_threads]() {
process_request(modsec.get(), rules.get(), static_cast<int>(i),
iterations, &completed_threads);
});
}

Expand All @@ -64,5 +117,16 @@ int main (int argc, char *argv[]) {
threads[i].join();
}

auto elapsed = std::chrono::steady_clock::now() - start;
std::cout << "completed_threads=" << completed_threads.load() << std::endl;
std::cout << "elapsed_ms="
<< std::chrono::duration_cast<std::chrono::milliseconds>(elapsed).count()
<< std::endl;

#ifndef WIN32
const int open_fds_after = count_open_fds();
std::cout << "open_fds_after=" << open_fds_after << std::endl;
#endif

return 0;
}
}
Loading
Loading