6 Commits

Author SHA1 Message Date
Ваше Имя 9ccabcd1eb refactor(common): reorganize type aliases and add application-specific types
Reorganize type aliases into dedicated directories and add application-specific
type definitions for chunk index, file size, frame length, and IDs. Improves
code clarity and type safety.
2025-10-09 23:12:25 +04:00
Ваше Имя aeeb22d351 refactor(aliases): replace std_cstdint with ByteBuffer alias 2025-10-09 15:23:38 +04:00
Ваше Имя a4f103d0c8 feat(boost_asio): add TcpResolver alias for Boost.Asio TCP resolver 2025-10-09 14:38:41 +04:00
Ваше Имя bb99d8d812 feat(aliases): add type aliases for fixed-width integers 2025-10-09 14:35:09 +04:00
Ваше Имя 1e6fecb7bd refactor(aliases): add Boost type aliases 2025-10-09 14:25:54 +04:00
Ваше Имя 88520915dc feat(utils/logger): add logging utility with console and file output 2025-10-08 20:24:17 +04:00
23 changed files with 78 additions and 391 deletions
-1
View File
@@ -2,4 +2,3 @@
.xmake
build
compile_commands.json
ignore
-26
View File
@@ -1,26 +0,0 @@
#include "portscan_cli.hpp"
#include <boost/program_options/value_semantic.hpp>
#include <cassert>
PortScanCli::PortScanCli()
: CliBase("Port Scanner Options")
, ip_("")
{
}
void PortScanCli::setupOptions()
{
// clang-format off
desc_.add_options()
("help,h", "Show help")
("ip,H", withDefault(ip_, "<IP>"), "Local IPv4 to scan");
// clang-format on
}
std::string PortScanCli::getIp() const
{
if (vm_["ip"].empty() == 0) {
return "127.0.0.1";
}
return vm_.at("ip").as<std::string>();
}
-19
View File
@@ -1,19 +0,0 @@
#pragma once
#include "cli_base.hpp"
#include "option_utils.hpp"
#include <string>
class PortScanCli : public CliBase, protected OptionUtils
{
public:
PortScanCli();
std::string getIp() const;
protected:
void setupOptions() override;
private:
std::string ip_;
};
-29
View File
@@ -1,29 +0,0 @@
#pragma once
#include <boost/asio.hpp>
#include <boost/asio/ip/address.hpp>
#include <boost/program_options.hpp>
#include <boost/system/error_code.hpp>
// --- Error handling ---
using ErrorCode = boost::system::error_code;
// --- Asio types ---
using IoContext = boost::asio::io_context;
using SteadyTimer = boost::asio::steady_timer;
// --- Ip types ---
using IpAddress = boost::asio::ip::address;
// --- TCP types ---
using TcpSocket = boost::asio::ip::tcp::socket;
using TcpAcceptor = boost::asio::ip::tcp::acceptor;
using TcpEndpoint = boost::asio::ip::tcp::endpoint;
// --- UDP types ---
using UdpSocket = boost::asio::ip::udp::socket;
using UdpEndpoint = boost::asio::ip::udp::endpoint;
// --- Program options ---
using OptionsDescription = boost::program_options::options_description;
using VariablesMap = boost::program_options::variables_map;
-34
View File
@@ -1,34 +0,0 @@
#include "cli_base.hpp"
#include <boost/program_options/parsers.hpp>
#include <iostream>
CliBase::CliBase(const std::string &title)
: desc_(title)
, help_(false)
{
}
void CliBase::parse(int argc, char *argv[])
{
using namespace boost::program_options;
setupOptions(); // must be first
parsed_options parsed = parse_command_line(argc, argv, desc_);
store(parsed, vm_);
notify(vm_);
if (vm_.count("help")) {
help_ = true;
}
}
bool CliBase::isHelp() const
{
return help_;
}
void CliBase::printHelp() const
{
std::cout << desc_ << "\n";
}
-27
View File
@@ -1,27 +0,0 @@
#pragma once
#include <boost/program_options/options_description.hpp>
#include <boost/program_options/variables_map.hpp>
#include <string>
class CliBase
{
public:
CliBase(const std::string &title);
virtual ~CliBase() = default;
// parse argc/argv
void parse(int argc, char *argv[]);
bool isHelp() const;
void printHelp() const;
protected:
// children add their specific options here
virtual void setupOptions() = 0;
boost::program_options::options_description desc_;
boost::program_options::variables_map vm_;
bool help_;
};
-20
View File
@@ -1,20 +0,0 @@
#pragma once
#include <boost/program_options.hpp>
class OptionUtils
{
public:
template <typename T>
using OptionValue = boost::program_options::typed_value<T> *;
template <typename T>
static OptionValue<T>
withDefault(const T &value, const char *name = nullptr);
protected:
OptionUtils() = default;
~OptionUtils() = default;
};
#include "option_utils.tpp"
-13
View File
@@ -1,13 +0,0 @@
#pragma once
#include "option_utils.hpp"
template <typename T>
OptionUtils::OptionValue<T>
OptionUtils::withDefault(const T &value, const char *name)
{
auto v = boost::program_options::value<T>()->default_value(value);
if (name) {
v->value_name(name); // Optional
}
return v;
}
+7
View File
@@ -0,0 +1,7 @@
#pragma once
#include <cstdint>
#include <vector>
// Alias for raw byte buffer
using ByteBuffer = std::vector<std::uint8_t>;
+6
View File
@@ -0,0 +1,6 @@
#pragma once
#include <cstdint>
// Sequential file chunk index
using ChunkIndex = std::uint32_t;
+6
View File
@@ -0,0 +1,6 @@
#pragma once
#include <cstdint>
// File total size in bytes
using FileSize = std::uint64_t;
+6
View File
@@ -0,0 +1,6 @@
#pragma once
#include <cstdint>
// Wire length prefix type for a single framed message (big-endian on the wire)
using FrameLength = std::uint32_t;
+6
View File
@@ -0,0 +1,6 @@
#pragma once
#include <cstdint>
// Client, group, or message ID
using Id = std::uint64_t;
+6
View File
@@ -0,0 +1,6 @@
#pragma once
#include <boost/asio/io_context.hpp>
// IO Context
using IoContext = boost::asio::io_context;
@@ -0,0 +1,9 @@
#pragma once
#include <boost/asio/ip/tcp.hpp>
// TCP
using TcpSocket = boost::asio::ip::tcp::socket;
using TcpAcceptor = boost::asio::ip::tcp::acceptor;
using TcpEndpoint = boost::asio::ip::tcp::endpoint;
using TcpResolver = boost::asio::ip::tcp::resolver;
@@ -0,0 +1,6 @@
#pragma once
#include <boost/asio/steady_timer.hpp>
// Timers
using SteadyTimer = boost::asio::steady_timer;
@@ -0,0 +1,6 @@
#pragma once
#include <boost/system/error_code.hpp>
// Error handling
using ErrorCode = boost::system::error_code;
-142
View File
@@ -1,142 +0,0 @@
#include "port_scanner.hpp"
#include "logger.hpp"
#include <boost/asio.hpp>
#include <string>
PortScanner::PortScanner(
const std::string &ip, const std::vector<uint16_t> &ports
)
: ports_(ports)
{
ErrorCode ec;
addr_ = boost::asio::ip::make_address(ip, ec);
ip_ok_ = !ec;
if (!ip_ok_) {
Logger::error(std::string("PortScanner: invalid IP: ") + ip);
} else {
Logger::debug(std::string("PortScanner: using IP: ") + ip);
}
}
void PortScanner::setTimeoutMs(int ms)
{
if (ms > 0) {
timeout_ms_ = ms;
Logger::debug(
std::string("PortScanner: timeout set to ")
+ std::to_string(timeout_ms_) + " ms"
);
}
}
void PortScanner::run()
{
if (!ip_ok_) {
Logger::error("PortScanner::run - aborting: ip not ok");
return;
}
for (uint16_t p : ports_) {
if (probe(p)) {
Logger::info(std::to_string(p));
}
}
}
bool PortScanner::probe(uint16_t port)
{
TcpSocket s(io_);
SteadyTimer t(io_);
auto ep = endpoint(port);
Logger::debug(
std::string("PortScanner::probe - probing port ") + std::to_string(port)
);
armTimer(t, s);
armConnect(s, ep);
runUntilDone();
cancelTimer(t);
drainLeftovers();
close(s);
if (ok_) {
Logger::debug(std::string("Port ") + std::to_string(port) + " is OPEN");
} else {
Logger::debug(
std::string("Port ") + std::to_string(port) + " is CLOSED/FILTERED"
);
}
return ok_;
}
TcpEndpoint PortScanner::endpoint(uint16_t port) const
{
return TcpEndpoint(addr_, port);
}
void PortScanner::armTimer(SteadyTimer &t, TcpSocket &s)
{
t.expires_after(std::chrono::milliseconds(timeout_ms_));
auto onTimeout = [&s](const ErrorCode &ec) {
if (!ec) {
Logger::debug("Timer expired -> cancelling socket");
s.cancel();
}
};
t.async_wait(onTimeout);
}
void PortScanner::armConnect(TcpSocket &s, const TcpEndpoint &ep)
{
ok_ = false;
done_ = false;
auto onConnect = [this](const ErrorCode &ec) {
if (!ec) {
ok_ = true;
Logger::debug("async_connect succeeded");
} else {
ok_ = false;
Logger::debug(std::string("async_connect failed: ") + ec.message());
}
done_ = true;
};
s.async_connect(ep, onConnect);
}
void PortScanner::runUntilDone()
{
io_.restart();
while (!done_ && io_.run_one()) {
}
}
void PortScanner::cancelTimer(SteadyTimer &t)
{
ErrorCode ec;
t.cancel();
if (ec) {
Logger::warn(std::string("cancelTimer: ") + ec.message());
}
}
void PortScanner::drainLeftovers()
{
io_.restart();
while (io_.run_one()) {
continue;
}
}
void PortScanner::close(TcpSocket &s)
{
ErrorCode ig;
if (s.close(ig)) {
Logger::warn(std::string("close socket failed: ") + ig.message());
}
}
-37
View File
@@ -1,37 +0,0 @@
#pragma once
#include "aliases.hpp"
#include <boost/asio.hpp>
#include <cstdint>
#include <string>
#include <vector>
class PortScanner
{
public:
PortScanner(const std::string &ip, const std::vector<uint16_t> &ports);
void setTimeoutMs(int ms);
void run();
private:
bool probe(uint16_t port);
TcpEndpoint endpoint(uint16_t port) const;
void armTimer(SteadyTimer &t, TcpSocket &s);
void armConnect(TcpSocket &s, const TcpEndpoint &ep);
void runUntilDone();
void cancelTimer(SteadyTimer &t);
void drainLeftovers();
void close(TcpSocket &s);
private:
IoContext io_;
IpAddress addr_;
std::vector<uint16_t> ports_;
int timeout_ms_{300};
bool ip_ok_{false};
bool ok_{false};
bool done_{false};
};
+10 -32
View File
@@ -1,38 +1,16 @@
#include "cli_base.hpp"
#include "logger.hpp"
#include "port_scanner.hpp"
#include "portscan_cli.hpp"
#include <boost/asio.hpp>
#include <iostream>
#include <string>
#include <vector>
static std::vector<uint16_t> allPorts()
int main()
{
std::vector<uint16_t> v;
v.reserve(65535);
for (uint32_t p = 1; p <= 65535; ++p) {
v.push_back(static_cast<uint16_t>(p));
}
return v;
}
std::cout << "Hello, Boost + C++23 + xmake!\n";
int main(int argc, char **argv)
{
Logger::init(true);
boost::asio::io_context io;
boost::asio::steady_timer timer(io, std::chrono::seconds(1));
timer.async_wait([](const boost::system::error_code &) {
std::cout << "Timer fired after 1 second!\n";
});
PortScanCli cli;
cli.parse(argc, argv);
if (cli.isHelp()) {
cli.printHelp();
return 0;
}
const std::string ip = cli.getIp();
auto ports = allPorts();
Logger::info("Starting full port scan (1..65535)...");
PortScanner scanner(ip, ports);
scanner.run();
Logger::info("Scan completed.");
io.run();
return 0;
}
@@ -1,4 +1,5 @@
#include "logger.hpp"
#include <boost/date_time/posix_time/posix_time_io.hpp>
void Logger::init(bool toConsole, const std::string_view filePath)
+8 -10
View File
@@ -2,18 +2,16 @@ set_languages "c++23"
add_rules("plugin.compile_commands.autoupdate", { outputdir = "." })
add_requires("cmake::Boost", {
alias = "boost",
system = true,
add_requires("boost", {
system = true, -- sudo pacman -S boost
configs = {
components = { "program_options", "log" },
all = false,
system = true, -- asio
},
})
target "port_scanner"
do
target "app"
set_kind "binary"
add_files("src/main.cpp", "src/cli/*.cpp", "src/common/*.cpp", "src/core/*.cpp")
add_includedirs("src", "src/cli", "src/common", "src/core", { public = true })
add_packages "boost"
end
add_files "src/*.cpp"
add_links "boost_system"