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) {
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) {
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) {
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) {
60 return fl::recv(fd, buf, len, flags);
62 return ::recv(fd, buf, len, flags);
66int plat_close(
int fd) {
74int plat_shutdown(
int fd,
int how) {
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) {
93 return fl::bind(fd, addr, addrlen);
95 return ::bind(fd, addr, addrlen);
99int plat_listen(
int fd,
int backlog) {
101 return fl::listen(fd, backlog);
103 return ::listen(fd, backlog);
107int plat_accept(
int fd,
struct sockaddr *addr, socklen_t *addrlen) {
109 return fl::accept(fd, addr, addrlen);
111 return ::accept(fd, addr, addrlen);
115bool set_nonblocking(
int fd,
bool enabled) {
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;
131bool is_would_block() {
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) {
143 return fl::getsockname(fd, addr, addrlen);
145 return ::getsockname(fd, addr, addrlen);
155socket::socket() : mFd(-1), mNonBlocking(false) {}
159socket::socket(socket &&other) : mFd(other.mFd), mNonBlocking(other.mNonBlocking) {
161 other.mNonBlocking =
false;
164socket &socket::operator=(socket &&other)
FL_NOEXCEPT {
165 if (
this != &other) {
168 mNonBlocking = other.mNonBlocking;
170 other.mNonBlocking =
false;
175bool socket::is_open()
const {
return mFd != -1; }
177error_code socket::connect(
const endpoint &ep) {
182 if (!initialize_winsock()) {
183 return error_code(errc::unknown,
"winsock init failed");
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) {
200 return error_code(errc::host_not_found,
"getaddrinfo failed");
203 error_code ec(errc::connection_refused,
"no addresses succeeded");
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);
236 freeaddrinfo(result);
240void socket::close() { close_fd(); }
242void socket::shutdown() {
244 plat_shutdown(mFd, SHUT_RDWR);
248size_t socket::read_some(
fl::span<u8> buffer, error_code &ec) {
251 ec = error_code(errc::operation_aborted,
"socket not open");
256 plat_recv(mFd, (
char *)buffer.
data(), buffer.
size(), 0);
259 if (is_would_block()) {
260 ec = error_code(errc::would_block);
264 ec = error_code(errc::unknown,
"recv failed");
266 ec = error_code::from_errno(errno);
272 ec = error_code(errc::eof,
"connection closed by peer");
276 return static_cast<size_t>(
result);
282 ec = error_code(errc::operation_aborted,
"socket not open");
286 ssize_t
result = plat_send(mFd, (
const char *)buffer.
data(),
287 buffer.
size(), MSG_NOSIGNAL);
290 if (is_would_block()) {
291 ec = error_code(errc::would_block);
295 ec = error_code(errc::unknown,
"send failed");
297 ec = error_code::from_errno(errno);
302 return static_cast<size_t>(
result);
305void socket::async_read_some(
fl::span<u8> buffer, io_handler handler) {
307 size_t n = read_some(buffer, ec);
315 size_t n = write_some(buffer, ec);
321void socket::async_connect(
const endpoint &ep, connect_handler handler) {
322 error_code ec = connect(ep);
328void socket::set_non_blocking(
bool mode) {
330 set_nonblocking(mFd, mode);
335bool socket::is_non_blocking()
const {
return mNonBlocking; }
337int socket::native_handle()
const {
return mFd; }
339void socket::assign(
int fd) {
344void socket::close_fd() {
349 mNonBlocking =
false;
356acceptor::acceptor() : mFd(-1), mPort(0) {}
360error_code acceptor::open(u16 port) {
364 if (!initialize_winsock()) {
365 return error_code(errc::unknown,
"winsock init failed");
369 int sock = plat_socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
371 return error_code(errc::unknown,
"socket creation failed");
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));
390 return error_code(errc::address_in_use,
"bind failed");
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);
414error_code acceptor::listen(
int backlog) {
416 return error_code(errc::operation_aborted,
"acceptor not open");
419 int ret = plat_listen(mFd, backlog);
421 return error_code(errc::unknown,
"listen failed");
427error_code acceptor::accept(socket &peer) {
429 return error_code(errc::operation_aborted,
"acceptor not open");
432 struct sockaddr_in clientAddr {};
433 socklen_t addrLen =
sizeof(clientAddr);
435 plat_accept(mFd, (
struct sockaddr *)&clientAddr, &addrLen);
438 if (is_would_block()) {
439 return error_code(errc::would_block);
442 return error_code(errc::unknown,
"accept failed");
444 return error_code::from_errno(errno);
449 set_nonblocking(clientFd,
true);
450 peer.assign(clientFd);
455void acceptor::async_accept(socket &peer, connect_handler handler) {
456 error_code ec = accept(peer);
462void acceptor::close() {
470bool acceptor::is_open()
const {
return mFd != -1; }
472int acceptor::native_handle()
const {
return mFd; }
474u16 acceptor::port()
const {
return mPort; }
const T * data() const FL_NOEXCEPT
constexpr fl::size size() const FL_NOEXCEPT
int snprintf(char *buffer, fl::size size, const char *format, const Args &... args) FL_NOEXCEPT
Snprintf-like formatting function that writes to a buffer.
expected< T, E > result
Alias for expected (Rust-style naming)
Base definition for an LED controller.