输入/输出 IO 抽象
当 Sandwich 库需要传输数据流时,它通过通用的 I/O 接口实现。换句话说,Sandwich 不会强制隧道对等体之间数据传输的方式。
该 I/O 接口提供了三个由用户定义的高级别 API 调用:
read:读取底层传输的指定字节数 write:将缓冲区写入底层传输 它还包含一个通用对象的视图,可以表示实际传输所需的任何状态。I/O 对象始终由隧道拥有,使 I/O API 能够访问其父隧道,例如获取隧道的当前状态。
I/O 接口还支持异步操作,并且可以为此类目的返回特定的错误代码。
C API
I/O 接口通过 SandwichCIOSettings 结构在 C API 中进行描述。
以下是在 C++ 中将数据转发到套接字的 I/O 结构的示例:
/// \brief Read from a socket.////// This method is a SandwichCIOReadFunction.auto SandwichReadFromSocket(void *uarg, void *buf, const size_t count,[[maybe_unused]] const enum ::SandwichTunnelState state,enum ::SandwichIOError *err) -> size_t {*err = SANDWICH_IOERROR_OK;const auto fd = static_cast<int>(reinterpret_cast<uintptr_t>(uarg));ssize_t r{0};do {if (r = ::read(fd, buf, count); r > -1) {return static_cast<size_t>(r);}} while ((r == -1) && (errno == EINTR));switch (errno) {case 0: {return *err = SANDWICH_IOERROR_OK, 0;}case EINPROGRESS:case EINTR: {return *err = SANDWICH_IOERROR_IN_PROGRESS, 0;}case EWOULDBLOCK:#if EWOULDBLOCK != EAGAINcase EAGAIN:#endif{return *err = SANDWICH_IOERROR_WOULD_BLOCK, 0;}case ENOTSOCK:case EPROTOTYPE:case EBADF: {return *err = SANDWICH_IOERROR_INVALID, 0;}case EACCES:case EPERM:case ETIMEDOUT:case ENETUNREACH:case ECONNREFUSED: {return *err = SANDWICH_IOERROR_REFUSED, 0;}default: {return *err = SANDWICH_IOERROR_UNKNOWN, 0;}}}/// \brief Write to a socket.////// This method is a SandwichCIOWriteFunction.auto SandwichWriteToSocket(void *uarg, const void *buf, const size_t count,[[maybe_unused]] const enum ::SandwichTunnelState state,enum ::SandwichIOError *err) -> size_t {*err = SANDWICH_IOERROR_OK;const auto fd = static_cast<int>(reinterpret_cast<uintptr_t>(uarg));ssize_t w{0};do {if (w = ::write(fd, buf, count); w > -1) {return static_cast<size_t>(w);}} while ((w == -1) && (errno == EINTR));switch (errno) {case 0: {return *err = SANDWICH_IOERROR_OK, 0;}case EINPROGRESS:case EINTR: {return *err = SANDWICH_IOERROR_WOULD_BLOCK, 0;}case ENOTSOCK:case EPROTOTYPE:case EBADF: {return *err = SANDWICH_IOERROR_INVALID, 0;}case EACCES:case EPERM:case ETIMEDOUT:case ENETUNREACH:case ECONNREFUSED: {return *err = SANDWICH_IOERROR_REFUSED, 0;}default: {return *err = SANDWICH_IOERROR_UNKNOWN, 0;}}}/// \brief Close a socket.////// This method is a SandwichCIOCloseFunction.void CloseSocket(void *uarg) {const auto fd = static_cast<int>(reinterpret_cast<uintptr_t>(uarg));::close(fd);}/// \brief Global CIO settings structure for sockets.constexpr struct ::SandwichCIOSettings SandwichSocketCIOSettings = {.read = SandwichReadFromSocket,.write = SandwichWriteToSocket,.uarg = nullptr};
