Add missing BSD functions

This commit is contained in:
Sergio R. Caprile committed 2026-11-04 13:35:49 -03:00
1 parent 7886a73807
commit 66afa5e551
6 files changed
+646 -39

No files matched your search

+237 -15
View File
@@ -32,8 +32,9 @@ static struct mg_mgr *s_mgr;
enum bsd_op {
BSD_OP_NONE, BSD_OP_SOCKET, BSD_OP_BIND, BSD_OP_LISTEN, BSD_OP_FCNTL,
BSD_OP_ACCEPT, BSD_OP_CONNECT, BSD_OP_RECV, BSD_OP_SEND, BSD_OP_SENDTO,
BSD_OP_RECVFROM, BSD_OP_CLOSE, BSD_OP_POLL, BSD_OP_SELECT,
BSD_OP_GETHOSTBYNAME,
BSD_OP_RECVFROM, BSD_OP_CLOSE, BSD_OP_SHUTDOWN, BSD_OP_SETSOCKOPT,
BSD_OP_GETSOCKOPT, BSD_OP_GETSOCKNAME, BSD_OP_GETPEERNAME, BSD_OP_POLL,
BSD_OP_SELECT, BSD_OP_GETHOSTBYNAME,
};
// A BSD API request from a user task. Gets sent via the RTOS queue, and
@@ -50,6 +51,7 @@ struct mg_bsd_cmd {
struct { int fd, backlog; } op_listen;
struct { int fd, cmd, arg; } op_fcntl;
struct { int fd; } op_close;
struct { int fd, how; } op_shutdown;
struct { int fd; const struct sockaddr *addr; socklen_t len; } op_bind;
struct { int fd; const struct sockaddr *addr; socklen_t len; } op_connect;
struct { int fd; struct sockaddr *addr; socklen_t *addrlen; } op_accept;
@@ -57,6 +59,9 @@ struct mg_bsd_cmd {
struct { int fd; const void *buf; size_t len; int flags; } op_send;
struct { int fd; const void *buf; size_t len; int flags; const struct sockaddr *addr; socklen_t addrlen; } op_sendto;
struct { int fd; void *buf; size_t len; int flags; struct sockaddr *src; socklen_t *addrlen; } op_recvfrom;
struct { int fd, level, optname; const void *optval; socklen_t optlen; } op_setsockopt;
struct { int fd, level, optname; void *optval; socklen_t *optlen; } op_getsockopt;
struct { int fd; struct sockaddr *addr; socklen_t *addrlen; } op_getname;
struct { struct pollfd *fds; nfds_t nfds; uint64_t deadline; } op_poll;
struct { int nfds; fd_set *r, *w, *e; uint64_t deadline; } op_select;
struct { const char *name; struct hostent *result; } op_gethostbyname;
@@ -73,6 +78,7 @@ struct mg_bsd_sock {
struct mg_connection *c;
struct mg_bsd_sock *listener;
bool used, bound, closed, nonblock, is_udp, orphan; // closed: c was closed
bool error_pending, is_shut_rd, is_shut_wr;
};
static struct mg_bsd_sock s_socks[MG_BSD_MAX_SOCKETS > 0 ?
@@ -93,6 +99,21 @@ static struct mg_bsd_sock *bsd_get(int fd) {
return s;
}
static int bsd_addr4(const struct sockaddr *addr, socklen_t len) {
if (addr == NULL || len < sizeof(struct sockaddr_in)) return EINVAL;
return addr->sa_family == AF_INET ? 0 : EAFNOSUPPORT;
}
static bool bsd_aton4(const char *str, in_addr_t *ip) {
struct mg_addr addr;
size_t len = strlen(str);
if (len == 0 || !mg_aton(mg_str_n(str, len), &addr) || addr.is_ip6)
return false;
memcpy(ip, addr.addr.ip, sizeof(*ip));
return true;
}
static void bsd_attach(struct mg_bsd_sock *s, struct mg_connection *c) {
s->c = c;
c->fn = bsd_ev;
@@ -178,8 +199,10 @@ static void bsd_ev(struct mg_connection *c, int ev, void *ev_data) {
c->is_bsd = 1;
c->is_udp = child->is_udp;
}
} else if (ev == MG_EV_READ && s->is_shut_rd) {
mg_iobuf_del(&c->recv, 0, c->recv.len);
} else if (ev == MG_EV_ERROR) {
if (s->err == 0) s->err = EIO;
if (s->err == 0) s->err = EIO, s->error_pending = true;
#if MG_ENABLE_FREERTOS
bsd_finish_waiters(s, true);
#endif
@@ -289,9 +312,11 @@ static int bsd_ready(struct mg_bsd_sock *s) {
}
return 0;
}
if (s->c->recv.len > 0 || s->c->is_draining) ready |= BSD_READ;
if (!s->is_udp && !s->c->is_connecting && !s->c->is_closing &&
!s->c->is_draining)
if (s->is_shut_rd || s->c->recv.len > 0 || s->c->is_draining)
ready |= BSD_READ;
if (s->is_shut_wr) ready |= BSD_ERROR;
if (!s->is_shut_wr && !s->is_udp && !s->c->is_connecting &&
!s->c->is_closing && !s->c->is_draining)
ready |= BSD_WRITE; // Established TCP socket
return ready;
}
@@ -368,9 +393,13 @@ static bool bsd_run(struct mg_bsd_cmd *cmd) {
}
}
return true;
case BSD_OP_BIND:
case BSD_OP_BIND: {
int err;
if ((s = bsd_get(cmd->op_bind.fd)) == NULL) {
cmd->result = -1, cmd->err = EBADF;
} else if ((err = bsd_addr4(cmd->op_bind.addr, cmd->op_bind.len)) != 0) {
cmd->result = -1, cmd->err = err;
} else {
const struct sockaddr_in *sa =
(const struct sockaddr_in *) cmd->op_bind.addr;
@@ -389,6 +418,7 @@ static bool bsd_run(struct mg_bsd_cmd *cmd) {
}
}
return true;
}
case BSD_OP_LISTEN: {
char url[32];
@@ -464,11 +494,17 @@ static bool bsd_run(struct mg_bsd_cmd *cmd) {
return true;
#endif
}
case BSD_OP_CONNECT:
case BSD_OP_CONNECT: {
int err;
if ((s = bsd_get(cmd->op_connect.fd)) == NULL) {
cmd->result = -1, cmd->err = EBADF;
return true;
}
if ((err = bsd_addr4(cmd->op_connect.addr, cmd->op_connect.len)) != 0) {
cmd->result = -1, cmd->err = err;
return true;
}
if (!cmd->started && s->c == NULL) {
if (s->closed || (c = bsd_new_conn(s)) == NULL) {
cmd->result = -1, cmd->err = s->closed ? EIO : ENOMEM;
@@ -507,6 +543,7 @@ static bool bsd_run(struct mg_bsd_cmd *cmd) {
cmd->result = -1, cmd->err = EINPROGRESS;
return true;
#endif
}
case BSD_OP_RECV:
if ((s = bsd_get(cmd->op_recv.fd)) == NULL) {
cmd->result = -1, cmd->err = EBADF;
@@ -529,7 +566,7 @@ static bool bsd_run(struct mg_bsd_cmd *cmd) {
cmd->result = -1, cmd->err = s->err;
return true;
}
if (c->is_draining) { // Orderly shutdown by peer
if (s->is_shut_rd || c->is_draining) { // Local or peer shutdown
cmd->result = 0;
return true;
}
@@ -543,8 +580,8 @@ static bool bsd_run(struct mg_bsd_cmd *cmd) {
case BSD_OP_SEND:
if ((s = bsd_get(cmd->op_send.fd)) == NULL) {
cmd->result = -1, cmd->err = EBADF;
} else if ((c = s->c) == NULL || s->err != 0 || c->is_closing ||
c->is_draining) {
} else if (s->is_shut_wr || (c = s->c) == NULL || s->err != 0 ||
c->is_closing || c->is_draining) {
cmd->result = -1, cmd->err = EPIPE;
} else if (mg_send(c, cmd->op_send.buf, cmd->op_send.len)) {
cmd->result = (int) cmd->op_send.len;
@@ -558,11 +595,16 @@ static bool bsd_run(struct mg_bsd_cmd *cmd) {
#endif
}
return true;
case BSD_OP_SENDTO:
case BSD_OP_SENDTO: {
int err;
if ((s = bsd_get(cmd->op_sendto.fd)) == NULL) {
cmd->result = -1, cmd->err = EBADF;
} else if ((c = s->c) == NULL || s->err != 0 || c->is_closing ||
c->is_draining) {
} else if ((err = bsd_addr4(cmd->op_sendto.addr,
cmd->op_sendto.addrlen)) != 0) {
cmd->result = -1, cmd->err = err;
} else if (s->is_shut_wr || (c = s->c) == NULL || s->err != 0 ||
c->is_closing || c->is_draining) {
cmd->result = -1, cmd->err = EPIPE;
} else {
const struct sockaddr_in *sa =
@@ -583,11 +625,16 @@ static bool bsd_run(struct mg_bsd_cmd *cmd) {
}
}
return true;
}
case BSD_OP_RECVFROM:
if ((s = bsd_get(cmd->op_recvfrom.fd)) == NULL) {
cmd->result = -1, cmd->err = EBADF;
return true;
}
if (s->is_shut_rd) {
cmd->result = 0;
return true;
}
if ((c = s->c) == NULL) {
cmd->result = s->closed && s->err == 0 ? 0 : -1;
cmd->err = s->closed ? s->err : ENOTCONN;
@@ -595,6 +642,13 @@ static bool bsd_run(struct mg_bsd_cmd *cmd) {
}
if (c->recv.len > 0) {
size_t n = cmd->op_recvfrom.len;
if (cmd->op_recvfrom.src != NULL &&
(cmd->op_recvfrom.addrlen == NULL ||
*cmd->op_recvfrom.addrlen < sizeof(struct sockaddr_in))) {
cmd->result = -1, cmd->err = EINVAL;
return true;
}
if (c->recv.len < n) n = c->recv.len;
memcpy(cmd->op_recvfrom.buf, c->recv.buf, n);
if (!(cmd->op_recvfrom.flags & MSG_PEEK)) mg_iobuf_del(&c->recv, 0, n);
@@ -627,6 +681,95 @@ static bool bsd_run(struct mg_bsd_cmd *cmd) {
cmd->result = 0;
}
return true;
case BSD_OP_SHUTDOWN:
if ((s = bsd_get(cmd->op_shutdown.fd)) == NULL) {
cmd->result = -1, cmd->err = EBADF;
} else if (cmd->op_shutdown.how != SHUT_RD &&
cmd->op_shutdown.how != SHUT_WR &&
cmd->op_shutdown.how != SHUT_RDWR) {
cmd->result = -1, cmd->err = EINVAL;
} else if ((c = s->c) == NULL || c->is_listening || c->is_closing ||
(s->is_udp && !c->is_client)) {
cmd->result = -1, cmd->err = ENOTCONN;
} else {
if (cmd->op_shutdown.how != SHUT_WR) {
s->is_shut_rd = true;
mg_iobuf_del(&c->recv, 0, c->recv.len);
}
if (cmd->op_shutdown.how != SHUT_RD) s->is_shut_wr = true;
cmd->result = 0;
}
return true;
case BSD_OP_SETSOCKOPT:
if ((s = bsd_get(cmd->op_setsockopt.fd)) == NULL) {
cmd->result = -1, cmd->err = EBADF;
} else if (cmd->op_setsockopt.optval == NULL ||
cmd->op_setsockopt.optlen != sizeof(int)) {
cmd->result = -1, cmd->err = EINVAL;
} else if ((cmd->op_setsockopt.level == SOL_SOCKET &&
(cmd->op_setsockopt.optname == SO_REUSEADDR ||
cmd->op_setsockopt.optname == SO_NOSIGPIPE)) ||
(!s->is_udp && cmd->op_setsockopt.level == IPPROTO_TCP &&
cmd->op_setsockopt.optname == TCP_NODELAY)) {
cmd->result = 0;
} else {
cmd->result = -1, cmd->err = ENOPROTOOPT;
}
return true;
case BSD_OP_GETSOCKOPT:
if ((s = bsd_get(cmd->op_getsockopt.fd)) == NULL) {
cmd->result = -1, cmd->err = EBADF;
} else if (cmd->op_getsockopt.level != SOL_SOCKET ||
cmd->op_getsockopt.optname != SO_ERROR) {
cmd->result = -1, cmd->err = ENOPROTOOPT;
} else if (cmd->op_getsockopt.optval == NULL ||
cmd->op_getsockopt.optlen == NULL ||
*cmd->op_getsockopt.optlen < sizeof(int)) {
cmd->result = -1, cmd->err = EINVAL;
} else {
*(int *) cmd->op_getsockopt.optval =
s->error_pending ? s->err : 0;
s->error_pending = false;
*cmd->op_getsockopt.optlen = sizeof(int);
cmd->result = 0;
}
return true;
case BSD_OP_GETSOCKNAME:
case BSD_OP_GETPEERNAME:
if ((s = bsd_get(cmd->op_getname.fd)) == NULL) {
cmd->result = -1, cmd->err = EBADF;
} else if (cmd->op_getname.addr == NULL ||
cmd->op_getname.addrlen == NULL ||
*cmd->op_getname.addrlen < sizeof(struct sockaddr_in)) {
cmd->result = -1, cmd->err = EINVAL;
} else if ((c = s->c) == NULL &&
(cmd->op == BSD_OP_GETPEERNAME || s->closed)) {
cmd->result = -1, cmd->err = ENOTCONN;
} else if (cmd->op == BSD_OP_GETPEERNAME &&
(c->is_listening || (s->is_udp && !c->is_client))) {
cmd->result = -1, cmd->err = ENOTCONN;
} else if (c != NULL &&
((cmd->op == BSD_OP_GETSOCKNAME && c->loc.is_ip6) ||
(cmd->op == BSD_OP_GETPEERNAME && c->rem.is_ip6))) {
cmd->result = -1, cmd->err = EAFNOSUPPORT;
} else {
struct sockaddr_in *sa = (struct sockaddr_in *) cmd->op_getname.addr;
if (c == NULL) {
*sa = s->addr;
sa->sin_family = AF_INET;
} else {
const struct mg_addr *addr = cmd->op == BSD_OP_GETSOCKNAME
? &c->loc
: &c->rem;
sa->sin_family = AF_INET;
sa->sin_port = addr->port;
sa->sin_addr.s_addr = addr->addr.ip4;
}
*cmd->op_getname.addrlen = sizeof(*sa);
cmd->result = 0;
}
return true;
case BSD_OP_POLL: {
struct pollfd *p;
int i, n = 0, ready;
@@ -643,7 +786,7 @@ static bool bsd_run(struct mg_bsd_cmd *cmd) {
p->revents |= POLLIN;
if ((p->events & POLLOUT) && (ready & BSD_WRITE))
p->revents |= POLLOUT;
if (s->err != 0) p->revents |= POLLERR;
if (s->err != 0 || s->is_shut_wr) p->revents |= POLLERR;
if (s->closed) p->revents |= POLLHUP;
}
if (p->revents != 0) n++;
@@ -895,6 +1038,55 @@ int close(int fd) {
return cmd.result;
}
int shutdown(int fd, int how) {
struct mg_bsd_cmd cmd = BSD_CMD_EMPTY;
cmd.op = BSD_OP_SHUTDOWN, cmd.op_shutdown.fd = fd,
cmd.op_shutdown.how = how;
bsd_dispatch(&cmd);
errno = cmd.err;
return cmd.result;
}
int setsockopt(int fd, int level, int optname, const void *optval,
socklen_t optlen) {
struct mg_bsd_cmd cmd = BSD_CMD_EMPTY;
cmd.op = BSD_OP_SETSOCKOPT, cmd.op_setsockopt.fd = fd,
cmd.op_setsockopt.level = level, cmd.op_setsockopt.optname = optname,
cmd.op_setsockopt.optval = optval, cmd.op_setsockopt.optlen = optlen;
bsd_dispatch(&cmd);
errno = cmd.err;
return cmd.result;
}
int getsockopt(int fd, int level, int optname, void *optval,
socklen_t *optlen) {
struct mg_bsd_cmd cmd = BSD_CMD_EMPTY;
cmd.op = BSD_OP_GETSOCKOPT, cmd.op_getsockopt.fd = fd,
cmd.op_getsockopt.level = level, cmd.op_getsockopt.optname = optname,
cmd.op_getsockopt.optval = optval, cmd.op_getsockopt.optlen = optlen;
bsd_dispatch(&cmd);
errno = cmd.err;
return cmd.result;
}
int getsockname(int fd, struct sockaddr *addr, socklen_t *addrlen) {
struct mg_bsd_cmd cmd = BSD_CMD_EMPTY;
cmd.op = BSD_OP_GETSOCKNAME, cmd.op_getname.fd = fd,
cmd.op_getname.addr = addr, cmd.op_getname.addrlen = addrlen;
bsd_dispatch(&cmd);
errno = cmd.err;
return cmd.result;
}
int getpeername(int fd, struct sockaddr *addr, socklen_t *addrlen) {
struct mg_bsd_cmd cmd = BSD_CMD_EMPTY;
cmd.op = BSD_OP_GETPEERNAME, cmd.op_getname.fd = fd,
cmd.op_getname.addr = addr, cmd.op_getname.addrlen = addrlen;
bsd_dispatch(&cmd);
errno = cmd.err;
return cmd.result;
}
int poll(struct pollfd *fds, nfds_t nfds, int timeout) {
struct mg_bsd_cmd cmd = BSD_CMD_EMPTY;
uint64_t deadline = timeout < 0 ? (uint64_t) ~0
@@ -926,6 +1118,36 @@ struct hostent *gethostbyname(const char *name) {
return cmd.op_gethostbyname.result;
}
int inet_pton(int af, const char *src, void *dst) {
if (af != AF_INET) {
errno = EAFNOSUPPORT;
return -1;
}
return bsd_aton4(src, dst) ? 1 : 0;
}
const char *inet_ntop(int af, const void *src, char *dst, socklen_t size) {
if (af != AF_INET) {
errno = EAFNOSUPPORT;
return NULL;
}
if (mg_snprintf(dst, size, "%M", mg_print_ip4, (void *) src) >= size) {
errno = ENOSPC;
return NULL;
}
return dst;
}
in_addr_t inet_addr(const char *src) {
in_addr_t addr;
return bsd_aton4(src, &addr) ? addr : INADDR_NONE;
}
char *inet_ntoa(struct in_addr addr) {
static char buf[INET_ADDRSTRLEN];
return (char *) inet_ntop(AF_INET, &addr, buf, sizeof(buf));
}
#endif // MG_ENABLE_BSD_SOCKETS
#if MG_ENABLE_BSD_SOCKETS
+11
View File
@@ -55,6 +55,15 @@ void mg_bsd_poll(struct mg_mgr *);
#ifndef EPIPE
#define EPIPE 32
#endif
#ifndef EAFNOSUPPORT
#define EAFNOSUPPORT 97
#endif
#ifndef ENOPROTOOPT
#define ENOPROTOOPT 92
#endif
#ifndef ENOSPC
#define ENOSPC 28
#endif
#ifndef EPROTONOSUPPORT
#define EPROTONOSUPPORT 93
#endif
@@ -136,7 +145,9 @@ typedef struct fd_set {
#define IPPROTO_UDP 17
#define INADDR_ANY 0
#define INADDR_LOOPBACK 0x7f000001
#define INADDR_NONE ((in_addr_t) -1)
#define INET_ADDRSTRLEN 16
#define INET6_ADDRSTRLEN 46
#define SOL_SOCKET 0xffff
#define SO_REUSEADDR 2
#define SO_REUSEPORT 15