22#include "lwip/sockets.h"
23#include "lwip/netdb.h"
34static constexpr const char*
TAG =
"SOCK";
36constexpr size_t MAX_SOCKET_SLOTS = 4;
37constexpr uint32_t kDefaultTimeoutMs = 5000;
41 void* owner =
nullptr;
54SocketSlot* slotFor(
int handle) {
return s_slots.
lookup(handle); }
56void closeSlot(SocketSlot& slot)
58 if (slot.fd >= 0) ::close(slot.fd);
63void applyTimeout(
int fd,
int optname, uint32_t to_ms)
66 tv.tv_sec =
static_cast<time_t
>(to_ms / 1000);
67 tv.tv_usec =
static_cast<suseconds_t
>((to_ms % 1000) * 1000);
68 ::setsockopt(fd, SOL_SOCKET, optname, &tv,
sizeof(tv));
73int connectEndpoint(
int fd,
const struct sockaddr* addr, socklen_t addrlen,
74 uint8_t proto, uint32_t to_ms)
80 int flags = ::fcntl(fd, F_GETFL, 0);
82 ::fcntl(fd, F_SETFL,
flags | O_NONBLOCK);
84 int rc = ::connect(fd, addr, addrlen);
92 tv.tv_sec =
static_cast<time_t
>(to_ms / 1000);
93 tv.tv_usec =
static_cast<suseconds_t
>((to_ms % 1000) * 1000);
94 int sel = ::select(fd + 1,
nullptr, &wset,
nullptr, &tv);
99 socklen_t len =
sizeof(soerr);
100 if (::getsockopt(fd, SOL_SOCKET, SO_ERROR, &soerr, &len) != 0 || soerr != 0) {
105 ::fcntl(fd, F_SETFL,
flags);
119 const int socktype = (proto ==
HOST_SOCK_UDP) ? SOCK_DGRAM : SOCK_STREAM;
120 const uint32_t to_ms = timeout_ms ? timeout_ms : kDefaultTimeoutMs;
123 SocketSlot* slot = s_slots.
allocate(slot_id);
125 *slot = SocketSlot{};
130 std::snprintf(port_str,
sizeof(port_str),
"%u",
static_cast<unsigned>(port));
132 struct addrinfo hints{};
133 hints.ai_family = AF_UNSPEC;
134 hints.ai_socktype = socktype;
135 struct addrinfo* res =
nullptr;
136 if (::getaddrinfo(host, port_str, &hints, &res) != 0 || !res) {
137 LOG_W(
TAG,
"resolve failed for '%s'", host);
138 *slot = SocketSlot{};
142 int fd = ::socket(res->ai_family, res->ai_socktype, res->ai_protocol);
145 *slot = SocketSlot{};
149 int rc = connectEndpoint(fd, res->ai_addr, res->ai_addrlen, proto, to_ms);
153 *slot = SocketSlot{};
165 auto* slot = slotFor(handle);
167 if (len == 0)
return 0;
170 applyTimeout(slot->fd, SO_SNDTIMEO, timeout_ms ? timeout_ms : kDefaultTimeoutMs);
171 int n =
static_cast<int>(::send(slot->fd, data, len, 0));
182 auto* slot = slotFor(handle);
184 if (cap == 0)
return 0;
187 applyTimeout(slot->fd, SO_RCVTIMEO, timeout_ms ? timeout_ms : kDefaultTimeoutMs);
188 int n =
static_cast<int>(::recv(slot->fd, out, cap, 0));
198 auto* slot = slotFor(handle);
207 for (
size_t i = 0; i < MAX_SOCKET_SLOTS; ++i) {
208 SocketSlot& slot = s_slots.
slots[i];
209 if (!slot.used || slot.owner != plugin)
continue;
210 LOG_W(
TAG,
"force-closing leaked socket slot %u",
static_cast<unsigned>(i + 1));
Owned WAMR module instance + per-plugin state.
Fixed-capacity, 1-based slot table for host-API resources.
CDC Log: logging over TinyUSB CDC and UART.
#define LOG_W(tag, fmt,...)
const PluginManifest & manifest() const noexcept
int host_socket_read(int handle, uint8_t *out, size_t cap, uint32_t timeout_ms)
Read bytes from the stream / receive a datagram from the connected peer.
#define HOST_SOCK_TCP
Protocol selector for host_socket_open.
int host_socket_close(int handle)
Close a socket handle.
int host_socket_write(int handle, const uint8_t *data, size_t len, uint32_t timeout_ms)
Write bytes to the stream / send a datagram to the connected peer.
int host_socket_open(uint8_t proto, const char *host, uint16_t port, uint32_t timeout_ms)
Open an outbound connection to a single remote endpoint.
CDC Badge OS plugin host API - canonical C ABI contract.
#define HOST_ERR_NO_CAPABILITY
#define HOST_ERR_INVALID_ARG
#define HOST_ERR_NO_MEMORY
#define HOST_ERR_NOT_FOUND
void * plg_get_active_plugin(void)
void plg_socket_on_unload(void *plugin)
PluginCapabilities capabilities
T * lookup(int id)
1-based lookup. Returns nullptr if id is out of range or slot unused.
T * allocate(int &out_id)