22#include "lwip/sockets.h"
23#include "lwip/netdb.h"
34static constexpr const char*
TAG =
"SOCK";
36constexpr size_t MAX_SOCKET_SLOTS = 8;
37constexpr uint32_t kDefaultTimeoutMs = 5000;
41 void* owner =
nullptr;
60 return p && (p->manifest().capabilities.socket || p->manifest().capabilities.net_listen);
63SocketSlot* slotFor(
int handle) {
return s_slots.
lookup(handle); }
65void closeSlot(SocketSlot& slot)
67 if (slot.fd >= 0) ::close(slot.fd);
72void applyTimeout(
int fd,
int optname, uint32_t to_ms)
75 tv.tv_sec =
static_cast<time_t
>(to_ms / 1000);
76 tv.tv_usec =
static_cast<suseconds_t
>((to_ms % 1000) * 1000);
77 ::setsockopt(fd, SOL_SOCKET, optname, &tv,
sizeof(tv));
82int connectEndpoint(
int fd,
const struct sockaddr* addr, socklen_t addrlen,
83 uint8_t proto, uint32_t to_ms)
89 int flags = ::fcntl(fd, F_GETFL, 0);
91 ::fcntl(fd, F_SETFL,
flags | O_NONBLOCK);
93 int rc = ::connect(fd, addr, addrlen);
101 tv.tv_sec =
static_cast<time_t
>(to_ms / 1000);
102 tv.tv_usec =
static_cast<suseconds_t
>((to_ms % 1000) * 1000);
103 int sel = ::select(fd + 1,
nullptr, &wset,
nullptr, &tv);
108 socklen_t len =
sizeof(soerr);
109 if (::getsockopt(fd, SOL_SOCKET, SO_ERROR, &soerr, &len) != 0 || soerr != 0) {
114 ::fcntl(fd, F_SETFL,
flags);
128 const int socktype = (proto ==
HOST_SOCK_UDP) ? SOCK_DGRAM : SOCK_STREAM;
129 const uint32_t to_ms = timeout_ms ? timeout_ms : kDefaultTimeoutMs;
132 SocketSlot* slot = s_slots.
allocate(slot_id);
134 *slot = SocketSlot{};
139 std::snprintf(port_str,
sizeof(port_str),
"%u",
static_cast<unsigned>(port));
141 struct addrinfo hints{};
142 hints.ai_family = AF_UNSPEC;
143 hints.ai_socktype = socktype;
144 struct addrinfo* res =
nullptr;
145 if (::getaddrinfo(host, port_str, &hints, &res) != 0 || !res) {
146 LOG_W(
TAG,
"resolve failed for '%s'", host);
147 *slot = SocketSlot{};
151 int fd = ::socket(res->ai_family, res->ai_socktype, res->ai_protocol);
154 *slot = SocketSlot{};
158 int rc = connectEndpoint(fd, res->ai_addr, res->ai_addrlen, proto, to_ms);
162 *slot = SocketSlot{};
174 auto* slot = slotFor(handle);
176 if (len == 0)
return 0;
179 applyTimeout(slot->fd, SO_SNDTIMEO, timeout_ms ? timeout_ms : kDefaultTimeoutMs);
180 int n =
static_cast<int>(::send(slot->fd, data, len, 0));
191 auto* slot = slotFor(handle);
193 if (cap == 0)
return 0;
196 applyTimeout(slot->fd, SO_RCVTIMEO, timeout_ms ? timeout_ms : kDefaultTimeoutMs);
197 int n =
static_cast<int>(::recv(slot->fd, out, cap, 0));
207 auto* slot = slotFor(handle);
220 SocketSlot* slot = s_slots.
allocate(slot_id);
222 *slot = SocketSlot{};
233 for (
size_t i = 0; i < MAX_SOCKET_SLOTS; ++i) {
234 SocketSlot& slot = s_slots.
slots[i];
235 if (!slot.used || slot.owner != plugin)
continue;
236 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)
int plg_socket_adopt(int fd, void *owner)
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)