#pragma once #if !defined(MIJIN_NET_SOCKET_HPP_INCLUDED) #define MIJIN_NET_SOCKET_HPP_INCLUDED 1 #include "./ip.hpp" #include "../detect.hpp" #include "../async/coroutine.hpp" #include "../container/optional.hpp" #include "../io/stream.hpp" namespace mijin { // // public types // #if MIJIN_TARGET_OS == MIJIN_OS_WINDOWS using socket_handle_t = std::uintptr_t; inline constexpr socket_handle_t INVALID_SOCKET_HANDLE = static_cast(-1); #else using socket_handle_t = int; inline constexpr socket_handle_t INVALID_SOCKET_HANDLE = -1; #endif class Socket { protected: Socket() MIJIN_NOEXCEPT = default; Socket(const Socket&) MIJIN_NOEXCEPT = default; Socket(Socket&&) MIJIN_NOEXCEPT = default; Socket& operator=(const Socket&) MIJIN_NOEXCEPT = default; Socket& operator=(Socket&&) MIJIN_NOEXCEPT = default; public: virtual ~Socket() MIJIN_NOEXCEPT = default; virtual void close() MIJIN_NOEXCEPT = 0; virtual Stream& getStream() MIJIN_NOEXCEPT = 0; }; class TCPStream : public Stream { private: socket_handle_t handle_ = INVALID_SOCKET_HANDLE; bool async_ = false; public: StreamError readRaw(std::span buffer, const ReadOptions& options, std::size_t* outBytesRead) override; StreamError writeRaw(std::span buffer) override; mijin::Task c_readRaw(std::span buffer, const ReadOptions& options, std::size_t *outBytesRead) override; mijin::Task c_writeRaw(std::span buffer) override; std::size_t tell() override; StreamError seek(std::intptr_t pos, SeekMode seekMode = SeekMode::ABSOLUTE) override; void flush() override; bool isAtEnd() override; StreamFeatures getFeatures() override; StreamError open(ip_address_t address, std::uint16_t port) MIJIN_NOEXCEPT; void close() MIJIN_NOEXCEPT; [[nodiscard]] bool isOpen() const MIJIN_NOEXCEPT { return handle_ != INVALID_SOCKET_HANDLE; } private: void setNoblock(bool async); friend class TCPServerSocket; }; class TCPSocket : public Socket { private: TCPStream stream_; public: TCPStream& getStream() MIJIN_NOEXCEPT override; StreamError open(ip_address_t address, std::uint16_t port) MIJIN_NOEXCEPT { return stream_.open(address, port); } StreamError open(std::string_view addressText, std::uint16_t port) MIJIN_NOEXCEPT { if (Optional address = ipAddressFromString(addressText); !address.empty()) { return open(*address, port); } return StreamError::UNKNOWN_ERROR; } void close() MIJIN_NOEXCEPT override { stream_.close(); } [[nodiscard]] bool isOpen() const MIJIN_NOEXCEPT { return stream_.isOpen(); } friend class TCPServerSocket; }; class TCPServerSocket { private: socket_handle_t handle_ = INVALID_SOCKET_HANDLE; public: StreamError setup(ip_address_t address, std::uint16_t port) MIJIN_NOEXCEPT; StreamError setup(std::string_view addressText, std::uint16_t port) MIJIN_NOEXCEPT { if (Optional address = ipAddressFromString(addressText); !address.empty()) { return setup(*address, port); } return StreamError::UNKNOWN_ERROR; } void close() MIJIN_NOEXCEPT; [[nodiscard]] bool isListening() const MIJIN_NOEXCEPT { return handle_ != INVALID_SOCKET_HANDLE; } Task>> c_waitForConnection() MIJIN_NOEXCEPT; }; } #endif // !defined(MIJIN_NET_SOCKET_HPP_INCLUDED)