137 lines
4.8 KiB
C++
137 lines
4.8 KiB
C++
#pragma once
|
||
|
||
#ifndef PLANTSUNCAT_ERRC_H
|
||
#define PLANTSUNCAT_ERRC_H
|
||
#include "Core/Base/export.h"
|
||
|
||
namespace Psc::socket {
|
||
|
||
|
||
enum class NetError : unsigned char {
|
||
// ===== 通用 / 取消 / 参数 =====
|
||
unknown_error, // 被信号/中断打断(EINTR / WSAEINTR)
|
||
interrupted, // 被信号/中断打断(EINTR / WSAEINTR)
|
||
operation_canceled, // 取消(ECANCELED / WSAECANCELLED)
|
||
invalid_argument, // 参数非法(EINVAL / WSAEINVAL)
|
||
not_supported, // 不支持(EOPNOTSUPP/ENOTSUP 等)
|
||
permission_denied, // 权限不足(EACCES)
|
||
out_of_memory, // 内存不足(ENOMEM)
|
||
resource_exhausted, // 资源耗尽(EMFILE/ENFILE/ENOBUFS 等)
|
||
|
||
// ===== I/O / 系统 =====
|
||
io_error, // 其他 I/O 错误(EIO 等)
|
||
bad_file_descriptor, // fd 无效(EBADF)
|
||
not_a_socket, // 不是 socket(ENOTSOCK / WSAENOTSOCK)
|
||
|
||
// ===== 非阻塞 / 状态 =====
|
||
would_block, // 非阻塞下暂时无数据/不可写(EAGAIN/EWOULDBLOCK / WSAEWOULDBLOCK)
|
||
in_progress, // 操作进行中(EINPROGRESS / WSAEINPROGRESS)
|
||
already_in_progress, // 已经在进行(EALREADY / WSAEALREADY)
|
||
|
||
// ===== 地址 / 协议 =====
|
||
address_in_use, // 地址端口被占用(EADDRINUSE / WSAEADDRINUSE)
|
||
address_not_available, // 地址不可用(EADDRNOTAVAIL / WSAEADDRNOTAVAIL)
|
||
network_down, // 网络子系统 down(ENETDOWN / WSAENETDOWN)
|
||
network_unreachable, // 网络不可达(ENETUNREACH / WSAENETUNREACH)
|
||
host_unreachable, // 主机不可达(EHOSTUNREACH / WSAEHOSTUNREACH)
|
||
protocol_error, // 协议/选项错误(EPROTO/EPROTOTYPE/ENOPROTOOPT...)
|
||
|
||
// ===== 连接语义(TCP 核心)=====
|
||
not_connected, // 未连接(ENOTCONN / WSAENOTCONN)
|
||
already_connected, // 已连接(EISCONN / WSAEISCONN)
|
||
connection_refused, // 连接被拒绝(ECONNREFUSED / WSAECONNREFUSED)
|
||
connection_reset, // 连接被重置(ECONNRESET / WSAECONNRESET)
|
||
connection_aborted, // 连接被中止(ECONNABORTED / WSAECONNABORTED)
|
||
connection_closed, // 对端正常关闭/EOF(recv 返回 0 的语义)
|
||
timed_out, // 超时(ETIMEDOUT / WSAETIMEDOUT)
|
||
broken_pipe, // 写入已关闭连接(EPIPE;Windows 近似用 shutdown/notconn/reset)
|
||
|
||
// ===== DNS / 名称解析(可选但建议)=====
|
||
dns_not_found, // host 不存在/找不到(HOST_NOT_FOUND)
|
||
dns_temporary_failure, // 临时失败(TRY_AGAIN)
|
||
dns_failure, // 其他解析失败(NO_RECOVERY / 语义较泛)
|
||
};
|
||
|
||
class NetErrorCategory final : public std::error_category {
|
||
public:
|
||
[[nodiscard]] const char* name() const noexcept override {
|
||
// enum_type_name 返回 string_view,静态存储即可
|
||
static constexpr auto name_sv = magic_enum::enum_type_name<NetError>();
|
||
return name_sv.data();
|
||
}
|
||
|
||
[[nodiscard]] std::string message(int ev) const override {
|
||
auto opt = magic_enum::enum_name(static_cast<NetError>(ev));
|
||
if (!opt.empty())
|
||
return std::string(opt);
|
||
return "unknown enum error";
|
||
}
|
||
|
||
[[nodiscard]] bool equivalent(const std::error_code& ec, int cond) const noexcept override {
|
||
if (ec.category() != std::system_category()) return false;
|
||
return map_system_error(ec.value()) == static_cast<NetError>(cond);
|
||
}
|
||
|
||
static NetError map_system_error(int e) noexcept;
|
||
};
|
||
|
||
inline const std::error_category& net_category() {
|
||
static NetErrorCategory cat;
|
||
return cat;
|
||
}
|
||
ERROR_CODE_TYPE last_socket_ec();
|
||
|
||
|
||
|
||
|
||
template <typename T> using Ret = expected<T, Enum_Err<NetError>>;
|
||
|
||
|
||
|
||
|
||
extern BaseLogger *socket_logger;
|
||
#if WIN32
|
||
using Socket_FD = unsigned long long;
|
||
#else
|
||
using Socket_FD = int;
|
||
#endif
|
||
|
||
// 默认IPV4 TCP
|
||
enum class Socket_Type { TCP, UDP, Null };
|
||
struct Sockaddr_In {
|
||
std::string ip;
|
||
std::uint32_t port{};
|
||
[[nodiscard]] std::string to_string() const;
|
||
Sockaddr_In() = default;
|
||
Sockaddr_In(const std::string &ip, std::uint32_t port) {
|
||
this->ip = ip;
|
||
this->port = port;
|
||
}
|
||
// 定义小于运算符,便于存入 std::set
|
||
bool operator<(const Sockaddr_In &other) const {
|
||
// 先比较 IP 地址
|
||
if (ip != other.ip) {
|
||
return ip < other.ip;
|
||
}
|
||
// 如果 IP 地址相同,再比较端口号
|
||
return port < other.port;
|
||
}
|
||
bool operator==(const Sockaddr_In &other) const noexcept {
|
||
return ip == other.ip && port == other.port;
|
||
}
|
||
|
||
bool operator!=(const Sockaddr_In &other) const noexcept {
|
||
return !(*this == other);
|
||
}
|
||
};
|
||
struct Accept_Info {
|
||
Sockaddr_In sockaddr;
|
||
Socket_FD fd{};
|
||
[[nodiscard]] std::string to_string() const {
|
||
return "fd:" + std::to_string(fd) + ":[" + sockaddr.to_string() + "]";
|
||
}
|
||
};
|
||
}
|
||
|
||
#endif
|