/* * File: net/modem.hpp * Purpose: Modem concept in modern C++ * Author: Amlal El Mahrouss (amlal@nekernel.org) * Copyright 2025, Amlal El Mahrouss */ #ifndef _OCL_NET_NETWORK_HPP #define _OCL_NET_NETWORK_HPP #include #include #include #include #include #include #define OCL_MODEM_INTERFACE : public ocl::net::basic_modem namespace ocl::net { class basic_modem; typedef int64_t socket_type; /// @brief Modem container concept, a container to read and write on a network stream. class basic_modem { private: socket_type fd_{}; bool server_fd_{false}; bool bad_{true}; public: const bool& bad{bad_}; explicit basic_modem() = default; virtual ~basic_modem() { this->destroy(); } basic_modem& operator=(const basic_modem&) = delete; basic_modem(const basic_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; bool is_valid() const noexcept { return this->fd_ != -1 && !this->bad_; } template bool receive(ptr_type& out, std::size_t len) noexcept { static_assert(std::is_pointer::value, "ptr_type is not a pointer!"); if (!out) return false; if (!len) return false; socket_type cl_{fd_}; if (this->server_fd_) cl_ = ::accept(fd_, nullptr, nullptr); auto ret = ::recv(cl_, out, len, 0); return ret > 0L; } template bool transmit(ptr_type& out, std::size_t len) noexcept { static_assert(std::is_pointer::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 bool transmit(const std::basic_string& out) noexcept { if (out.empty()) return false; auto ret = ::send(fd_, out.data(), out.size(), 0); bad_ = !(ret >= 0L); return ret >= 0L; } template bool construct(const char* addr = basic_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"); fd_ = ::socket(af, kind, 0); server_fd_ = 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(&addr_), sizeof(addr_)); return ret == 0L; } ::bind(fd_, (struct sockaddr*)&addr_, sizeof(addr_)); ::listen(fd_, basic_modem::backlog_count); bad_ = false; return true; } bool destroy() noexcept { if (!fd_) return false; ::shutdown(fd_, SHUT_RDWR); ::close(fd_); fd_ = 0L; return true; } }; } // namespace ocl::net #endif // ifndef _OCL_NET_NETWORK_HPP