File net.h¶
Go to the documentation of this file.
#pragma once
#ifndef COROUTINE_NET_IO_H
#define COROUTINE_NET_IO_H
#include <gsl/gsl>
#include <coroutine/return.h>
#if __has_include(<WinSock2.h>) // use winsock
#include <WS2tcpip.h>
#include <WinSock2.h>
#include <ws2def.h>
static constexpr bool is_winsock = true;
static constexpr bool is_netinet = false;
using io_control_block = OVERLAPPED;
#elif __has_include(<netinet/in.h>) // use netinet
#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <sys/socket.h>
#include <unistd.h>
static constexpr bool is_winsock = false;
static constexpr bool is_netinet = true;
struct io_control_block {
uint64_t internal; // uint32_t errc, int32_t flag
uint64_t internal_high; // int64_t len, socklen_t addrlen
union {
struct {
int32_t offset;
int32_t offset_high;
};
void* ptr; // sockaddr* addr;
};
int64_t handle; // int64_t sd;
};
#endif // winsock || netinet
namespace coro {
using io_buffer_t = gsl::span<std::byte>;
static_assert(sizeof(io_buffer_t) <= sizeof(void*) * 2);
class io_work_t : public io_control_block {
public:
coroutine_handle<void> task{};
io_buffer_t buffer{};
protected:
bool ready() const noexcept;
public:
uint32_t error() const noexcept;
};
static_assert(sizeof(io_work_t) <= 56);
class io_send_to final : public io_work_t {
private:
void suspend(coroutine_handle<void> t) noexcept(false);
int64_t resume() noexcept;
public:
bool await_ready() const noexcept {
return this->ready();
}
void await_suspend(coroutine_handle<void> t) noexcept(false) {
return this->suspend(t);
}
int64_t await_resume() noexcept {
return this->resume();
}
};
static_assert(sizeof(io_send_to) == sizeof(io_work_t));
class io_recv_from final : public io_work_t {
private:
void suspend(coroutine_handle<void> t) noexcept(false);
int64_t resume() noexcept;
public:
bool await_ready() const noexcept {
return this->ready();
}
void await_suspend(coroutine_handle<void> t) noexcept(false) {
return this->suspend(t);
}
int64_t await_resume() noexcept {
return this->resume();
}
};
static_assert(sizeof(io_recv_from) == sizeof(io_work_t));
class io_send final : public io_work_t {
private:
void suspend(coroutine_handle<void> t) noexcept(false);
int64_t resume() noexcept;
public:
bool await_ready() const noexcept {
return this->ready();
}
void await_suspend(coroutine_handle<void> t) noexcept(false) {
return this->suspend(t);
}
int64_t await_resume() noexcept {
return this->resume();
}
};
static_assert(sizeof(io_send) == sizeof(io_work_t));
class io_recv final : public io_work_t {
private:
void suspend(coroutine_handle<void> t) noexcept(false);
int64_t resume() noexcept;
public:
bool await_ready() const noexcept {
return this->ready();
}
void await_suspend(coroutine_handle<void> t) noexcept(false) {
return this->suspend(t);
}
int64_t await_resume() noexcept {
return this->resume();
}
};
static_assert(sizeof(io_recv) == sizeof(io_work_t));
auto send_to(uint64_t sd, const sockaddr_in& remote, io_buffer_t buf,
io_work_t& work) noexcept(false) -> io_send_to&;
auto send_to(uint64_t sd, const sockaddr_in6& remote, io_buffer_t buf,
io_work_t& work) noexcept(false) -> io_send_to&;
auto recv_from(uint64_t sd, sockaddr_in& remote, io_buffer_t buf,
io_work_t& work) noexcept(false) -> io_recv_from&;
auto recv_from(uint64_t sd, sockaddr_in6& remote, io_buffer_t buf,
io_work_t& work) noexcept(false) -> io_recv_from&;
auto send_stream(uint64_t sd, io_buffer_t buf, uint32_t flag,
io_work_t& work) noexcept(false) -> io_send&;
auto recv_stream(uint64_t sd, io_buffer_t buf, uint32_t flag,
io_work_t& work) noexcept(false) -> io_recv&;
void poll_net_tasks(uint64_t nano) noexcept(false);
uint32_t get_address(const addrinfo& hint, //
gsl::czstring<> host, gsl::czstring<> serv,
gsl::span<sockaddr_in> output) noexcept;
uint32_t get_address(const addrinfo& hint, //
gsl::czstring<> host, gsl::czstring<> serv,
gsl::span<sockaddr_in6> output) noexcept;
uint32_t get_name(const sockaddr_in& addr, //
gsl::zstring<NI_MAXHOST> name, gsl::zstring<NI_MAXSERV> serv,
int32_t flags = NI_NUMERICHOST | NI_NUMERICSERV) noexcept;
uint32_t get_name(const sockaddr_in6& addr, //
gsl::zstring<NI_MAXHOST> name, gsl::zstring<NI_MAXSERV> serv,
int32_t flags = NI_NUMERICHOST | NI_NUMERICSERV) noexcept;
} // namespace coro
#endif // COROUTINE_NET_IO_H