mirror of
https://github.com/diamante0018/master-tool.git
synced 2025-06-27 23:01:53 +00:00
init
This commit is contained in:
161
src/network/address.cpp
Normal file
161
src/network/address.cpp
Normal file
@ -0,0 +1,161 @@
|
||||
#include <std_include.hpp>
|
||||
|
||||
#include "network/address.hpp"
|
||||
|
||||
using namespace std::literals;
|
||||
|
||||
namespace network
|
||||
{
|
||||
address::address()
|
||||
{
|
||||
std::memset(&this->address_, 0, sizeof(this->address_));
|
||||
}
|
||||
|
||||
address::address(const std::string& addr)
|
||||
: address()
|
||||
{
|
||||
this->parse(addr);
|
||||
}
|
||||
|
||||
address::address(sockaddr_in& addr)
|
||||
{
|
||||
this->address_ = addr;
|
||||
}
|
||||
|
||||
bool address::operator==(const address& obj) const
|
||||
{
|
||||
return this->address_.sin_family == obj.address_.sin_family //
|
||||
&& this->address_.sin_addr.s_addr == obj.address_.sin_addr.s_addr //
|
||||
&& this->address_.sin_port == obj.address_.sin_port;
|
||||
}
|
||||
|
||||
void address::set_ipv4(const in_addr addr)
|
||||
{
|
||||
this->address_.sin_family = AF_INET;
|
||||
this->address_.sin_addr = addr;
|
||||
}
|
||||
|
||||
void address::set_port(const unsigned short port)
|
||||
{
|
||||
this->address_.sin_port = htons(port);
|
||||
}
|
||||
|
||||
unsigned short address::get_port() const
|
||||
{
|
||||
return ntohs(this->address_.sin_port);
|
||||
}
|
||||
|
||||
std::string address::to_string(bool with_port) const
|
||||
{
|
||||
char buffer[1000]{};
|
||||
inet_ntop(this->address_.sin_family, &this->address_.sin_addr, buffer, sizeof(buffer));
|
||||
|
||||
auto address = std::string(buffer);
|
||||
if (with_port)
|
||||
{
|
||||
address += ":"s + std::to_string(this->get_port());
|
||||
}
|
||||
|
||||
return address;
|
||||
}
|
||||
|
||||
bool address::is_local() const
|
||||
{
|
||||
// According to: https://en.wikipedia.org/wiki/Private_network
|
||||
|
||||
std::uint8_t bytes[4];
|
||||
*reinterpret_cast<uint32_t*>(&bytes) = this->address_.sin_addr.s_addr;
|
||||
|
||||
// 10.X.X.X
|
||||
if (bytes[0] == 10)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// 192.168.X.X
|
||||
if (bytes[0] == 192
|
||||
&& bytes[1] == 168)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// 172.16.X.X - 172.31.X.X
|
||||
if (bytes[0] == 172
|
||||
&& bytes[1] >= 16
|
||||
&& bytes[1] < 32)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// 127.0.0.1
|
||||
if (this->address_.sin_addr.s_addr == 0x0100007F)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
sockaddr& address::get_addr()
|
||||
{
|
||||
return reinterpret_cast<sockaddr&>(this->get_in_addr());
|
||||
}
|
||||
|
||||
const sockaddr& address::get_addr() const
|
||||
{
|
||||
return reinterpret_cast<const sockaddr&>(this->get_in_addr());
|
||||
}
|
||||
|
||||
sockaddr_in& address::get_in_addr()
|
||||
{
|
||||
return this->address_;
|
||||
}
|
||||
|
||||
const sockaddr_in& address::get_in_addr() const
|
||||
{
|
||||
return this->address_;
|
||||
}
|
||||
|
||||
void address::parse(std::string addr)
|
||||
{
|
||||
const auto pos = addr.find_last_of(':');
|
||||
if (pos != std::string::npos)
|
||||
{
|
||||
auto port = addr.substr(pos + 1);
|
||||
this->set_port(static_cast<std::uint16_t>(std::strtol(port.data(), nullptr, 10)));
|
||||
|
||||
addr = addr.substr(0, pos);
|
||||
}
|
||||
|
||||
this->resolve(addr);
|
||||
}
|
||||
|
||||
void address::resolve(const std::string& hostname)
|
||||
{
|
||||
addrinfo* result = nullptr;
|
||||
if (!getaddrinfo(hostname.data(), nullptr, nullptr, &result))
|
||||
{
|
||||
for (auto* i = result; i; i = i->ai_next)
|
||||
{
|
||||
if (i->ai_addr->sa_family == AF_INET)
|
||||
{
|
||||
const auto port = this->get_port();
|
||||
std::memcpy(&this->address_, i->ai_addr, sizeof(this->address_));
|
||||
this->set_port(port);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
freeaddrinfo(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::size_t std::hash<network::address>::operator()(const network::address& a) const noexcept
|
||||
{
|
||||
const auto h1 = std::hash<decltype(a.get_in_addr().sin_family)>{}(a.get_in_addr().sin_family);
|
||||
const auto h2 = std::hash<decltype(a.get_in_addr().sin_addr.s_addr)>{}(a.get_in_addr().sin_addr.s_addr);
|
||||
const auto h3 = std::hash<decltype(a.get_in_addr().sin_port)>{}(a.get_in_addr().sin_port);
|
||||
return h1 ^ (h2 << 1) ^ (h3 << 2);
|
||||
}
|
46
src/network/address.hpp
Normal file
46
src/network/address.hpp
Normal file
@ -0,0 +1,46 @@
|
||||
#pragma once
|
||||
|
||||
namespace network
|
||||
{
|
||||
class address
|
||||
{
|
||||
public:
|
||||
address();
|
||||
address(const std::string& addr);
|
||||
address(sockaddr_in& addr);
|
||||
|
||||
void set_ipv4(in_addr addr);
|
||||
void set_port(unsigned short port);
|
||||
[[nodiscard]] unsigned short get_port() const;
|
||||
|
||||
[[nodiscard]] sockaddr& get_addr();
|
||||
[[nodiscard]] const sockaddr& get_addr() const;
|
||||
[[nodiscard]] sockaddr_in& get_in_addr();
|
||||
[[nodiscard]] const sockaddr_in& get_in_addr() const;
|
||||
|
||||
[[nodiscard]] bool is_local() const;
|
||||
[[nodiscard]] std::string to_string(bool with_port = true) const;
|
||||
|
||||
bool operator==(const address& obj) const;
|
||||
|
||||
bool operator!=(const address& obj) const
|
||||
{
|
||||
return !(*this == obj);
|
||||
}
|
||||
|
||||
private:
|
||||
sockaddr_in address_{};
|
||||
|
||||
void parse(std::string addr);
|
||||
void resolve(const std::string& hostname);
|
||||
};
|
||||
}
|
||||
|
||||
namespace std
|
||||
{
|
||||
template <>
|
||||
struct hash<network::address>
|
||||
{
|
||||
std::size_t operator()(const network::address& a) const noexcept;
|
||||
};
|
||||
}
|
131
src/network/socket.cpp
Normal file
131
src/network/socket.cpp
Normal file
@ -0,0 +1,131 @@
|
||||
#include <std_include.hpp>
|
||||
|
||||
#include "address.hpp"
|
||||
#include "socket.hpp"
|
||||
|
||||
using namespace std::literals;
|
||||
|
||||
namespace network
|
||||
{
|
||||
namespace
|
||||
{
|
||||
#ifdef _WIN32
|
||||
[[maybe_unused]] class wsa_initializer
|
||||
{
|
||||
public:
|
||||
wsa_initializer()
|
||||
{
|
||||
WSADATA wsa_data;
|
||||
if (WSAStartup(MAKEWORD(2, 2), &wsa_data))
|
||||
{
|
||||
throw std::runtime_error("Unable to initialize WSA");
|
||||
}
|
||||
}
|
||||
|
||||
~wsa_initializer()
|
||||
{
|
||||
WSACleanup();
|
||||
}
|
||||
} _;
|
||||
#endif
|
||||
}
|
||||
|
||||
socket::socket()
|
||||
{
|
||||
this->socket_ = ::socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
}
|
||||
|
||||
socket::~socket()
|
||||
{
|
||||
if (this->socket_ != INVALID_SOCKET)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
closesocket(this->socket_);
|
||||
#else
|
||||
close(this->socket_);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
socket::socket(socket&& obj) noexcept
|
||||
{
|
||||
this->operator=(std::move(obj));
|
||||
}
|
||||
|
||||
socket& socket::operator=(socket&& obj) noexcept
|
||||
{
|
||||
if (this != &obj)
|
||||
{
|
||||
this->~socket();
|
||||
this->socket_ = obj.socket_;
|
||||
obj.socket_ = INVALID_SOCKET;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool socket::bind(const address& target)
|
||||
{
|
||||
return ::bind(this->socket_, &target.get_addr(), sizeof(target.get_addr())) == 0;
|
||||
}
|
||||
|
||||
void socket::send(const address& target, const std::string& data) const
|
||||
{
|
||||
::sendto(this->socket_, data.data(), static_cast<int>(data.size()), 0, &target.get_addr(), sizeof(target.get_addr()));
|
||||
}
|
||||
|
||||
bool socket::receive(address& source, std::string& data) const
|
||||
{
|
||||
char buffer[0x2000]{};
|
||||
socklen_t len = sizeof(source.get_in_addr());
|
||||
|
||||
const auto result = recvfrom(this->socket_, buffer, sizeof(buffer), 0, &source.get_addr(), &len);
|
||||
if (result == SOCKET_ERROR) // Probably WSAEWOULDBLOCK
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
data.assign(buffer, buffer + result);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool socket::set_blocking(const bool blocking)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
unsigned long mode = blocking ? 0 : 1;
|
||||
return ioctlsocket(this->socket_, FIONBIO, &mode) == 0;
|
||||
#else
|
||||
int flags = fcntl(this->socket_, F_GETFL, 0);
|
||||
if (flags == -1) return false;
|
||||
flags = blocking ? (flags & ~O_NONBLOCK) : (flags | O_NONBLOCK);
|
||||
return fcntl(this->socket_, F_SETFL, flags) == 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool socket::sleep(const std::chrono::milliseconds timeout) const
|
||||
{
|
||||
fd_set fdr;
|
||||
FD_ZERO(&fdr);
|
||||
FD_SET(this->socket_, &fdr);
|
||||
|
||||
const auto msec = timeout.count();
|
||||
|
||||
timeval tv{};
|
||||
tv.tv_sec = static_cast<long>(msec / 1000ll);
|
||||
tv.tv_usec = static_cast<long>((msec % 1000) * 1000);
|
||||
|
||||
const auto ret_val = select(static_cast<int>(this->socket_) + 1, &fdr, nullptr, nullptr, &tv);
|
||||
if (ret_val == SOCKET_ERROR)
|
||||
{
|
||||
std::this_thread::sleep_for(1ms);
|
||||
return socket_is_ready;
|
||||
}
|
||||
|
||||
if (ret_val > 0)
|
||||
{
|
||||
return socket_is_ready;
|
||||
}
|
||||
|
||||
return !socket_is_ready;
|
||||
}
|
||||
}
|
38
src/network/socket.hpp
Normal file
38
src/network/socket.hpp
Normal file
@ -0,0 +1,38 @@
|
||||
#pragma once
|
||||
|
||||
namespace network
|
||||
{
|
||||
class socket
|
||||
{
|
||||
public:
|
||||
socket();
|
||||
~socket();
|
||||
|
||||
socket(const socket& obj) = delete;
|
||||
socket& operator=(const socket& obj) = delete;
|
||||
|
||||
socket(socket&& obj) noexcept;
|
||||
socket& operator=(socket&& obj) noexcept;
|
||||
|
||||
bool bind(const address& target);
|
||||
|
||||
void send(const address& target, const std::string& data) const;
|
||||
bool receive(address& source, std::string& data) const;
|
||||
|
||||
bool set_blocking(bool blocking);
|
||||
|
||||
static const bool socket_is_ready = true;
|
||||
bool sleep(std::chrono::milliseconds timeout) const;
|
||||
|
||||
private:
|
||||
#ifdef _WIN32
|
||||
using socklen_t = int;
|
||||
#else
|
||||
using SOCKET = int;
|
||||
#define INVALID_SOCKET (SOCKET)(~0)
|
||||
#define SOCKET_ERROR (-1)
|
||||
#endif
|
||||
|
||||
SOCKET socket_ = INVALID_SOCKET;
|
||||
};
|
||||
}
|
Reference in New Issue
Block a user