115 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			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)
 |