mijin2/source/mijin/net/socket.hpp

115 lines
3.5 KiB
C++

#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<socket_handle_t>(-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<std::uint8_t> buffer, const ReadOptions& options, std::size_t* outBytesRead) override;
StreamError writeRaw(std::span<const std::uint8_t> buffer) override;
mijin::Task<StreamError> c_readRaw(std::span<std::uint8_t> buffer, const ReadOptions& options, std::size_t *outBytesRead) override;
mijin::Task<StreamError> c_writeRaw(std::span<const std::uint8_t> 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<ip_address_t> 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<ip_address_t> 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<StreamResult<std::unique_ptr<TCPSocket>>> c_waitForConnection() MIJIN_NOEXCEPT;
};
}
#endif // !defined(MIJIN_NET_SOCKET_HPP_INCLUDED)