summaryrefslogtreecommitdiffhomepage
path: root/include/ocl/net/unique_socket.hpp
diff options
context:
space:
mode:
authorAmlal El Mahrouss <amlal@nekernel.org>2025-11-30 00:42:50 -0500
committerAmlal El Mahrouss <amlal@nekernel.org>2025-11-30 00:42:50 -0500
commite6579534e7c64be652ffeb74be7c977564a3ddab (patch)
tree69b908f5b2d81f477d3cfe39ecc6c01fbdc89657 /include/ocl/net/unique_socket.hpp
parenta8e99f3a783069cf85b626c6cfb2fbe83ae4fd44 (diff)
chore & feat: final library changes to stabilize changes.
Signed-off-by: Amlal El Mahrouss <amlal@nekernel.org>
Diffstat (limited to 'include/ocl/net/unique_socket.hpp')
-rw-r--r--include/ocl/net/unique_socket.hpp177
1 files changed, 177 insertions, 0 deletions
diff --git a/include/ocl/net/unique_socket.hpp b/include/ocl/net/unique_socket.hpp
new file mode 100644
index 0000000..906853f
--- /dev/null
+++ b/include/ocl/net/unique_socket.hpp
@@ -0,0 +1,177 @@
+/*
+ * File: net/unique_socket.hpp
+ * Purpose: RAII socket 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 <core/config.hpp>
+
+#include <unistd.h>
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#include <string>
+#include <cstddef>
+#include <cstring>
+
+#ifdef _WIN32
+#error !!! "Windows is not supported yet for <socket>" !!!
+#endif // _WIN32
+
+namespace ocl::net
+{
+ class unique_socket;
+
+ /// =============================================================================
+ /// @brief Modem container concept, a container to read and write on a network stream.
+ /// =============================================================================
+ class unique_socket 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_};
+
+ unique_socket() = default;
+
+ ~unique_socket()
+ {
+ this->destroy();
+ }
+
+ unique_socket& operator=(const unique_socket&) = delete;
+ unique_socket(const unique_socket&) = default;
+
+ 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 unique_socket 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 <uint16_t af, uint16_t kind, uint16_t port>
+ bool construct(const char* addr = unique_socket::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);
+ 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_, unique_socket::backlog_count);
+
+ return bad_ == false;
+ }
+
+ bool destroy() noexcept
+ {
+ if (!fd_)
+ return false;
+
+ ::shutdown(fd_, SHUT_RDWR);
+ ::close(fd_);
+
+ fd_ = 0L;
+
+ return true;
+ }
+ };
+
+ template<typename char_type, uint16_t port>
+ inline unique_socket make_socket(const std::basic_string<char_type>& address, const bool is_server)
+ {
+ unique_socket sock;
+ sock.construct<AF_INET, SOCK_STREAM, port>(address.c_str(), is_server);
+
+ return sock;
+ }
+} // namespace ocl::net