diff options
| author | Amlal El Mahrouss <amlal@nekernel.org> | 2025-11-23 20:16:02 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-11-23 20:16:02 -0500 |
| commit | 85f89ee4bb137100cbeffcbc10168eb8ea52e6cc (patch) | |
| tree | f6e2063319ceaaa02f523fb5c289e4f37411a2df /include/ocl/net | |
| parent | 9a70f32ddaec0eef99efbf7ff5597c2adf08f45a (diff) | |
| parent | 65a8349aa5526d071b18cd4d42586c46faaa3823 (diff) | |
Merge pull request #18 from amlel-el-mahrouss/developv1.0.48
OCL v1.0.48
Diffstat (limited to 'include/ocl/net')
| -rw-r--r-- | include/ocl/net/modem.hpp | 173 | ||||
| -rw-r--r-- | include/ocl/net/url.hpp | 123 |
2 files changed, 296 insertions, 0 deletions
diff --git a/include/ocl/net/modem.hpp b/include/ocl/net/modem.hpp new file mode 100644 index 0000000..08d5ca5 --- /dev/null +++ b/include/ocl/net/modem.hpp @@ -0,0 +1,173 @@ +/* + * File: net/modem.hpp + * Purpose: Modem concept in modern C++ + * Author: Amlal El Mahrouss (amlal@nekernel.org) + * Copyright 2025, Amlal El Mahrouss, licensed under the Boost Software License. + */ + +#pragma once + +#include <tests/hpptest.hpp> + +#include <unistd.h> +#include <arpa/inet.h> +#include <sys/socket.h> +#include <string> +#include <cstddef> + +#define OCL_MODEM_INTERFACE : public ocl::net::modem + +#ifdef _WIN32 +#error !!! "Windows is not supported yet for <modem>" !!! +#endif // _WIN32 + +namespace ocl::net +{ + class modem; + + /// ============================================================================= + /// @brief Modem container concept, a container to read and write on a network stream. + /// ============================================================================= + class modem final + { + public: + using socket_type = int64_t; + using error_type = bool; + using condition_type = bool; + + private: + socket_type fd_{}; + condition_type is_server_{false}; + error_type bad_{true}; + + public: + const error_type& bad{bad_}; + + explicit modem() = default; + + ~modem() + { + this->destroy(); + } + + modem& operator=(const modem&) = delete; + modem(const modem&) = delete; + + static constexpr auto local_address_ip4 = "127.0.0.1"; + static constexpr auto local_address_ip6 = "::1"; + static constexpr const auto backlog_count = 5U; + + /// ============================================================================= + /// @brief Check if the modem is valid. + /// @return true if valid, false otherwise. + /// ============================================================================= + + bool is_valid() const noexcept + { + return this->fd_ != -1 && !this->bad_; + } + + template <typename ptr_type> + bool receive(ptr_type& out, std::size_t len) noexcept + { + static_assert(std::is_pointer<ptr_type>::value, "ptr_type is not a pointer!"); + + if (!out) + return false; + + if (!len) + return false; + + socket_type cl_{fd_}; + + if (this->is_server_) + cl_ = ::accept(fd_, nullptr, nullptr); + + auto ret = ::recv(cl_, out, len, 0); + + return ret > 0L; + } + + template <typename ptr_type> + bool transmit(ptr_type& out, std::size_t len) noexcept + { + static_assert(std::is_pointer<ptr_type>::value, "ptr_type is not a pointer!"); + + if (!out) + return false; + + if (!len) + return false; + + auto ret = ::send(fd_, out, len, 0); + + bad_ = !(ret >= 0L); + + return ret >= 0L; + } + + template <typename char_type> + bool transmit(const std::basic_string<char_type>& out) noexcept + { + if (out.empty()) + return false; + + auto ret = ::send(fd_, out.data(), out.size(), 0); + + bad_ = !(ret >= 0L); + + return ret >= 0L; + } + + template <int32_t af, int32_t kind, int32_t port> + bool construct(const char* addr = modem::local_address_ip4, const bool& is_server = false) noexcept + { + static_assert(af != 0, "Address family is zero"); + static_assert(kind != 0, "Kind is zero"); + + must_pass<af == AF_INET || af == AF_INET6>(); + must_pass<kind == SOCK_STREAM || kind == SOCK_DGRAM>(); + must_pass<(port > 0) && (port < 65536)>(); + + fd_ = ::socket(af, kind, 0); + is_server_ = is_server; + + if (fd_ == -1) + return false; + + struct sockaddr_in addr_; + std::memset(&addr_, 0, sizeof(struct sockaddr_in)); + + addr_.sin_addr.s_addr = ::inet_addr(addr); + addr_.sin_port = htons(port); + addr_.sin_family = af; + + if (!is_server) + { + const auto ret = ::connect(fd_, reinterpret_cast<struct sockaddr*>(&addr_), sizeof(addr_)); + return ret == 0L; + } + + int ret = ::bind(fd_, (struct sockaddr*)&addr_, sizeof(addr_)); + + bad_ = ret == -1; + + ::listen(fd_, modem::backlog_count); + + return bad_ == false; + } + + bool destroy() noexcept + { + if (!fd_) + return false; + + ::shutdown(fd_, SHUT_RDWR); + ::close(fd_); + + fd_ = 0L; + + return true; + } + }; +} // namespace ocl::net diff --git a/include/ocl/net/url.hpp b/include/ocl/net/url.hpp new file mode 100644 index 0000000..ebfc57a --- /dev/null +++ b/include/ocl/net/url.hpp @@ -0,0 +1,123 @@ +/* + * File: net/url.hpp + * Purpose: URL container in modern C++ + * Author: Amlal El Mahrouss (amlal@nekernel.org) + * Copyright 2025, Amlal El Mahrouss, licensed under the Boost Software License. + */ + +#pragma once + +#include <string> +#include <sstream> + +/// @author Amlal El Mahrouss (amlal@nekernel.org) +/// @brief Parse URLs (in a non-standard way). + +namespace ocl::net +{ + template <typename char_type> + class basic_url; + + /// @brief Basic URL parser container. + template <typename char_type> + class basic_url final + { + public: + using reference = basic_url&; + + enum + { + invalid = 0, + http, + https, + mailto, + ftp, + tel, + bad = 0xff, + }; + + uint32_t m_protocol_{basic_url::invalid}; + std::basic_stringstream<char_type> m_ss_{}; + std::basic_string<char_type> m_port_{""}; + + public: + explicit basic_url(const std::basic_string<char_type>& protocol) + { + if (protocol.starts_with("https://")) + { + m_protocol_ = basic_url::https; + this->operator/=(protocol.substr(std::size("https://"))); + } + else if (protocol.starts_with("http://")) + { + m_protocol_ = basic_url::http; + this->operator/=(protocol.substr(std::size("http://"))); + } + else if (protocol.starts_with("mailto:")) + { + m_protocol_ = basic_url::mailto; + this->operator/=(protocol.substr(std::size("mailto:"))); + } + else if (protocol.starts_with("tel:")) + { + m_protocol_ = basic_url::tel; + this->operator/=(protocol.substr(std::size("tel:"))); + } + else if (protocol.starts_with("ftp:")) + { + m_protocol_ = basic_url::ftp; + this->operator/=(protocol.substr(std::size("ftp:"))); + } + } + + ~basic_url() = default; + + basic_url& operator=(const basic_url&) = default; + basic_url(const basic_url&) = default; + + private: + reference operator/=(const std::basic_string<char_type>& in) + { + if (in.empty()) + return *this; + + if (in.starts_with(":")) + { + m_port_ = in.substr(1); + return *this; + } + + m_ss_ += in; + return *this; + } + + reference operator/=(const char_type& in) + { + m_ss_ += in; + return *this; + } + + explicit operator bool() + { + return this->is_valid(); + } + + public: + uint32_t protocol() const noexcept + { + return this->m_protocol_; + } + + std::basic_string<char_type> port() const noexcept + { + return this->m_port_; + } + + bool is_valid() const noexcept + { + return m_ss_.size() > 0 && this->m_protocol_ != basic_url::bad || this->m_protocol_ != basic_url::invalid; + } + }; + + using url = basic_url<char>; +} // namespace ocl::net |
