From c31cc9d0ee8fbcd04ff3a76e8fc4ab8723127a84 Mon Sep 17 00:00:00 2001 From: WolverinDEV Date: Thu, 16 Apr 2020 14:05:56 +0200 Subject: [PATCH] Updated to 1.4.13 ;) --- CMakeLists.txt | 3 +- src/misc/net.cpp | 92 +++++++++++++++++++++++++++++++++++++++++++++++ src/misc/net.h | 78 ++++++++++++---------------------------- test/SQL2Test.cpp | 13 ++++++- 4 files changed, 129 insertions(+), 57 deletions(-) create mode 100644 src/misc/net.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 3aa8b58..8c8e98f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -94,6 +94,7 @@ set(SOURCE_FILES src/misc/memtracker.cpp src/misc/digest.cpp src/misc/base64.cpp + src/misc/net.cpp src/lock/rw_mutex.cpp @@ -278,7 +279,7 @@ if(BUILD_TESTS) #add_executable(SQLTest ${SOURCE_FILES} ${HEADER_FILES} test/SQLTest.cpp src/log/LogSinks.cpp src/log/LogSinks.h) #target_link_libraries(SQLTest ${TEST_LIBRARIES}) - add_executable(SQL2Test test/SQL2Test.cpp src/Variable.cpp) + add_executable(SQL2Test test/SQL2Test.cpp src/Variable.cpp src/misc/net.cpp) target_link_libraries(SQL2Test sqlite3) add_executable(ChannelTest ${SOURCE_FILES} ${HEADER_FILES} test/ChannelTest.cpp src/log/LogSinks.cpp src/log/LogSinks.h) diff --git a/src/misc/net.cpp b/src/misc/net.cpp new file mode 100644 index 0000000..626774f --- /dev/null +++ b/src/misc/net.cpp @@ -0,0 +1,92 @@ +// +// Created by WolverinDEV on 16/04/2020. +// + +#ifndef WIN32 +#include +#include +#endif + +#include "./net.h" + +namespace helpers { + inline void strip(std::string& message) { + while(!message.empty()) { + if(message[0] == ' ') + message = message.substr(1); + else if(message[message.length() - 1] == ' ') + message = message.substr(0, message.length() - 1); + else break; + } + } + + inline std::deque split(const std::string& message, char delimiter) { + std::deque result{}; + size_t found, index = 0; + do { + found = message.find(delimiter, index); + result.push_back(message.substr(index, found - index)); + index = found + 1; + } while(index != 0); + return result; + } +} + +std::vector> net::resolve_bindings(const std::string& bindings, uint16_t port) { + auto binding_list = helpers::split(bindings, ','); + std::vector> result; + result.reserve(binding_list.size()); + + for(auto& address : binding_list) { + helpers::strip(address); + + sockaddr_storage element{}; + memset(&element, 0, sizeof(element)); + if(!resolve_address(address, element)) { + result.emplace_back(address, element, "address resolve failed"); + continue; + } + + if(element.ss_family == AF_INET) { + ((sockaddr_in*) &element)->sin_port = htons(port); + } else if(element.ss_family == AF_INET6) { + ((sockaddr_in6*) &element)->sin6_port = htons(port); + } + result.emplace_back(address, element, ""); + } + return result; +} + +#ifndef WIN32 +net::binding_result net::address_available(const sockaddr_storage& address, binding_type type) { + int file_descriptor{0}; + net::binding_result result{binding_result::INTERNAL_ERROR}; + int disable{0}, enable{1}; + + file_descriptor = socket(address.ss_family, type == binding_type::TCP ? SOCK_STREAM : SOCK_DGRAM, 0); + if(file_descriptor <= 0) + goto cleanup_exit; + + fcntl(file_descriptor, F_SETFD, FD_CLOEXEC); /* just to ensure */ + setsockopt(file_descriptor, SOL_SOCKET, SO_REUSEADDR, &disable, sizeof(int)); + setsockopt(file_descriptor, SOL_SOCKET, SO_REUSEPORT, &disable, sizeof(int)); + if(type == binding_type::UDP && address.ss_family == AF_INET6) + setsockopt(file_descriptor, IPPROTO_IPV6, IPV6_V6ONLY, &enable, sizeof(int)); + + if(::bind(file_descriptor, (const sockaddr*) &address, net::address_size(address)) != 0) { + result = binding_result::ADDRESS_USED; + } else { + result = binding_result::ADDRESS_FREE; + } + + if(type == binding_type::TCP) { + if(::listen(file_descriptor, 1) != 0) + result = binding_result::ADDRESS_USED; + } + + cleanup_exit: + if(file_descriptor > 0) + ::close(file_descriptor); + return result; +} +#endif \ No newline at end of file diff --git a/src/misc/net.h b/src/misc/net.h index c46eba5..6d00544 100644 --- a/src/misc/net.h +++ b/src/misc/net.h @@ -4,6 +4,7 @@ #include #include #include +#include #ifdef WIN32 #include @@ -18,19 +19,19 @@ #endif namespace net { - inline std::string to_string(const in6_addr& address) { + [[nodiscard]] inline std::string to_string(const in6_addr& address) { char buffer[INET6_ADDRSTRLEN]; if(!inet_ntop(AF_INET6, (void*) &address, buffer, INET6_ADDRSTRLEN)) return ""; return std::string(buffer); } - inline std::string to_string(const in_addr& address) { + [[nodiscard]] inline std::string to_string(const in_addr& address) { char buffer[INET_ADDRSTRLEN]; if(!inet_ntop(AF_INET, (void*) &address, buffer, INET_ADDRSTRLEN)) return ""; return std::string(buffer); } - inline std::string to_string(const sockaddr_storage& address, bool port = true) { + [[nodiscard]] inline std::string to_string(const sockaddr_storage& address, bool port = true) { switch(address.ss_family) { case AF_INET: return to_string(((sockaddr_in*) &address)->sin_addr) + (port ? ":" + std::to_string(htons(((sockaddr_in*) &address)->sin_port)) : ""); @@ -41,7 +42,7 @@ namespace net { } } - inline uint16_t port(const sockaddr_storage& address) { + [[nodiscard]] inline uint16_t port(const sockaddr_storage& address) { switch(address.ss_family) { case AF_INET: return htons(((sockaddr_in*) &address)->sin_port); @@ -52,7 +53,7 @@ namespace net { } } - inline socklen_t address_size(const sockaddr_storage& address) { + [[nodiscard]] inline socklen_t address_size(const sockaddr_storage& address) { switch (address.ss_family) { case AF_INET: return sizeof(sockaddr_in); case AF_INET6: return sizeof(sockaddr_in6); @@ -60,7 +61,7 @@ namespace net { } } - inline bool address_equal(const sockaddr_storage& a, const sockaddr_storage& b) { + [[nodiscard]] inline bool address_equal(const sockaddr_storage& a, const sockaddr_storage& b) { if(a.ss_family != b.ss_family) return false; if(a.ss_family == AF_INET) return ((sockaddr_in*) &a)->sin_addr.s_addr == ((sockaddr_in*) &b)->sin_addr.s_addr; else if(a.ss_family == AF_INET6) { @@ -73,7 +74,7 @@ namespace net { return false; } - inline bool address_equal_ranged(const sockaddr_storage& a, const sockaddr_storage& b, uint8_t range) { + [[nodiscard]] inline bool address_equal_ranged(const sockaddr_storage& a, const sockaddr_storage& b, uint8_t range) { if(a.ss_family != b.ss_family) return false; if(a.ss_family == AF_INET) { auto address_a = ((sockaddr_in*) &a)->sin_addr.s_addr; @@ -130,17 +131,17 @@ namespace net { } - inline bool is_ipv6(const std::string& str) { + [[nodiscard]] inline bool is_ipv6(const std::string& str) { sockaddr_in6 sa{}; return inet_pton(AF_INET6, str.c_str(), &(sa.sin6_addr)) != 0; } - inline bool is_ipv4(const std::string& str) { + [[nodiscard]] inline bool is_ipv4(const std::string& str) { sockaddr_in sa{}; return inet_pton(AF_INET, str.c_str(), &(sa.sin_addr)) != 0; } - inline bool is_anybind(sockaddr_storage& storage) { + [[nodiscard]] inline bool is_anybind(sockaddr_storage& storage) { if(storage.ss_family == AF_INET) { auto data = (sockaddr_in*) &storage; return data->sin_addr.s_addr == 0; @@ -165,7 +166,7 @@ namespace net { return false; } - inline bool resolve_address(const std::string& address, sockaddr_storage& result) { + [[nodiscard]] inline bool resolve_address(const std::string& address, sockaddr_storage& result) { if(is_ipv4(address)) { sockaddr_in s{}; s.sin_port = 0; @@ -210,51 +211,18 @@ namespace net { return false; } - namespace helpers { - inline void strip(std::string& message) { - while(!message.empty()) { - if(message[0] == ' ') - message = message.substr(1); - else if(message[message.length() - 1] == ' ') - message = message.substr(0, message.length() - 1); - else break; - } - } + [[nodiscard]] std::vector> resolve_bindings(const std::string& bindings, uint16_t port); - inline std::deque split(const std::string& message, char delimiter) { - std::deque result{}; - size_t found, index = 0; - do { - found = message.find(delimiter, index); - result.push_back(message.substr(index, found - index)); - index = found + 1; - } while(index != 0); - return result; - } - } + enum struct binding_result { + ADDRESS_FREE, + ADDRESS_USED, + INTERNAL_ERROR + }; - inline std::vector> resolve_bindings(const std::string& bindings, uint16_t port) { - auto binding_list = helpers::split(bindings, ','); - std::vector> result; - result.reserve(binding_list.size()); + enum struct binding_type { + TCP, + UDP + }; - for(auto& address : binding_list) { - helpers::strip(address); - - sockaddr_storage element{}; - memset(&element, 0, sizeof(element)); - if(!resolve_address(address, element)) { - result.emplace_back(address, element, "address resolve failed"); - continue; - } - - if(element.ss_family == AF_INET) { - ((sockaddr_in*) &element)->sin_port = htons(port); - } else if(element.ss_family == AF_INET6) { - ((sockaddr_in6*) &element)->sin6_port = htons(port); - } - result.emplace_back(address, element, ""); - } - return result; - } + [[nodiscard]] binding_result address_available(const sockaddr_storage& address, binding_type type); } \ No newline at end of file diff --git a/test/SQL2Test.cpp b/test/SQL2Test.cpp index 55fdd42..0b621a3 100644 --- a/test/SQL2Test.cpp +++ b/test/SQL2Test.cpp @@ -175,8 +175,11 @@ struct A { ~A() = default; }; -#include +#include +#include + int main() { +#if 0 std::set elements{}; if(!elements.empty()) { auto it = elements.begin(); @@ -186,4 +189,12 @@ int main() { const auto diff = last_element - now; } } +#endif + sockaddr_in addr{}; + addr.sin_addr.s_addr = INADDR_ANY; + addr.sin_family = AF_INET; + addr.sin_port = htons(9987); + + std::cout << "Result: " << (int) net::address_available(*(sockaddr_storage*) &addr, net::binding_type::TCP) << "\n"; + std::cout << strerror(errno) << "\n"; } \ No newline at end of file