5#ifdef FASTLED_HAS_NETWORKING
9#include "platforms/win/socket_win.h"
11#include "platforms/posix/socket_posix.h"
34int plat_socket(
int domain,
int type,
int protocol)
FL_NO_EXCEPT {
36 return fl::socket(domain, type, protocol);
38 return ::socket(domain, type, protocol);
42int plat_connect(
int fd,
const struct sockaddr *addr, socklen_t addrlen)
FL_NO_EXCEPT {
44 return fl::connect(fd, addr, addrlen);
46 return ::connect(fd, addr, addrlen);
50ssize_t plat_send(
int fd,
const void *buf,
size_t len,
int flags)
FL_NO_EXCEPT {
52 return fl::send(fd, buf, len, flags);
54 return ::send(fd, buf, len, flags);
58ssize_t plat_recv(
int fd,
void *buf,
size_t len,
int flags)
FL_NO_EXCEPT {
60 return fl::recv(fd, buf, len, flags);
62 return ::recv(fd, buf, len, flags);
76 return fl::shutdown(fd, how);
78 return ::shutdown(fd, how);
82int plat_setsockopt(
int fd,
int level,
int optname,
const void *optval,
85 return fl::setsockopt(fd, level, optname, optval, optlen);
87 return ::setsockopt(fd, level, optname, optval, optlen);
91int plat_bind(
int fd,
const struct sockaddr *addr, socklen_t addrlen)
FL_NO_EXCEPT {
93 return fl::bind(fd, addr, addrlen);
95 return ::bind(fd, addr, addrlen);
101 return fl::listen(fd, backlog);
103 return ::listen(fd, backlog);
107int plat_accept(
int fd,
struct sockaddr *addr, socklen_t *addrlen)
FL_NO_EXCEPT {
109 return fl::accept(fd, addr, addrlen);
111 return ::accept(fd, addr, addrlen);
115bool set_nonblocking(
int fd,
bool enabled)
FL_NO_EXCEPT {
117 u_long mode = enabled ? 1 : 0;
118 return ioctlsocket(fd, FIONBIO, &mode) == 0;
120 int flags = fcntl(fd, F_GETFL, 0);
124 return fcntl(fd, F_SETFL, flags | O_NONBLOCK) != -1;
126 return fcntl(fd, F_SETFL, flags & ~O_NONBLOCK) != -1;
133 int err = WSAGetLastError();
134 return err == WSAEWOULDBLOCK;
136 return errno == EWOULDBLOCK || errno == EAGAIN;
141int plat_getsockname(
int fd,
struct sockaddr *addr, socklen_t *addrlen)
FL_NO_EXCEPT {
143 return fl::getsockname(fd, addr, addrlen);
145 return ::getsockname(fd, addr, addrlen);
155socket::socket()
FL_NO_EXCEPT : mFd(-1), mNonBlocking(false) {}
159socket::socket(socket &&other)
FL_NO_EXCEPT : mFd(other.mFd), mNonBlocking(other.mNonBlocking) {
161 other.mNonBlocking =
false;
165 if (
this != &other) {
168 mNonBlocking = other.mNonBlocking;
170 other.mNonBlocking =
false;
175bool socket::is_open() const
FL_NO_EXCEPT {
return mFd != -1; }
182 if (!initialize_winsock()) {
188 struct addrinfo hints {};
189 struct addrinfo *
result =
nullptr;
191 hints.ai_family = AF_INET;
192 hints.ai_socktype = SOCK_STREAM;
193 hints.ai_protocol = IPPROTO_TCP;
198 int ret = getaddrinfo(ep.host.c_str(), portStr, &hints, &
result);
199 if (ret != 0 ||
result ==
nullptr) {
205 for (
struct addrinfo *addr =
result; addr !=
nullptr; addr = addr->ai_next) {
207 plat_socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
220 ret = plat_connect(mFd, addr->ai_addr,
221 static_cast<socklen_t
>(addr->ai_addrlen));
225 set_nonblocking(mFd,
true);
244 plat_shutdown(mFd, SHUT_RDWR);
248size_t socket::read_some(fl::span<u8> buffer, error_code &ec)
FL_NO_EXCEPT {
256 plat_recv(mFd, (
char *)buffer.data(), buffer.size(), 0);
259 if (is_would_block()) {
272 ec = error_code(
errc::eof,
"connection closed by peer");
276 return static_cast<size_t>(
result);
279size_t socket::write_some(fl::span<const u8> buffer, error_code &ec)
FL_NO_EXCEPT {
286 ssize_t
result = plat_send(mFd, (
const char *)buffer.data(),
287 buffer.size(), MSG_NOSIGNAL);
290 if (is_would_block()) {
302 return static_cast<size_t>(
result);
307 size_t n = read_some(buffer, ec);
315 size_t n = write_some(buffer, ec);
322 error_code ec = connect(ep);
330 set_nonblocking(mFd, mode);
335bool socket::is_non_blocking() const
FL_NO_EXCEPT {
return mNonBlocking; }
337int socket::native_handle() const
FL_NO_EXCEPT {
return mFd; }
349 mNonBlocking =
false;
364 if (!initialize_winsock()) {
369 int sock = plat_socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
376 plat_setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (
const char *)&reuse,
379 struct sockaddr_in addr {};
380 addr.sin_family = AF_INET;
381 addr.sin_port = htons(port);
384 addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
387 plat_bind(sock, (
struct sockaddr *)&addr,
sizeof(addr));
395 struct sockaddr_in boundAddr {};
396 socklen_t addrLen =
sizeof(boundAddr);
397 if (plat_getsockname(sock, (
struct sockaddr *)&boundAddr,
400 return error_code(
errc::unknown,
"getsockname failed - cannot resolve ephemeral port");
402 port = ntohs(boundAddr.sin_port);
409 set_nonblocking(mFd,
true);
419 int ret = plat_listen(mFd, backlog);
432 struct sockaddr_in clientAddr {};
433 socklen_t addrLen =
sizeof(clientAddr);
435 plat_accept(mFd, (
struct sockaddr *)&clientAddr, &addrLen);
438 if (is_would_block()) {
449 set_nonblocking(clientFd,
true);
450 peer.assign(clientFd);
456 error_code ec = accept(peer);
470bool acceptor::is_open() const
FL_NO_EXCEPT {
return mFd != -1; }
472int acceptor::native_handle() const
FL_NO_EXCEPT {
return mFd; }
474u16 acceptor::port() const
FL_NO_EXCEPT {
return mPort; }
fl::function< void(const error_code &ec, size_t bytes_transferred)> io_handler
Asio-style I/O completion handler signature.
fl::function< void(const error_code &ec)> connect_handler
Asio-style connect completion handler signature.
u8 u8 fract8 blur_amount FL_NO_EXCEPT
int snprintf(char *buffer, fl::size size, const char *format) FL_NO_EXCEPT
expected< T, E > result
Alias for expected (Rust-style naming)
Base definition for an LED controller.
static error_code from_errno(int platform_errno) FL_NO_EXCEPT
Convert from platform errno value.
Asio-compatible endpoint type: bundles host address + port.