mirror of
https://github.com/cesanta/mongoose.git
synced 2026-11-06 15:51:25 +00:00
Add missing BSD functions
This commit is contained in:
1 parent
7886a73807
commit
66afa5e551
6 files changed
+646
-39
No files matched your search
+11
-2
@@ -92,7 +92,7 @@ fail:
|
||||
exit(1);
|
||||
}
|
||||
|
||||
enum wait_mode { WAIT_ABORT, WAIT_DRAIN, WAIT_HOLD, WAIT_CLOSE };
|
||||
enum wait_mode { WAIT_ABORT, WAIT_DRAIN, WAIT_HOLD, WAIT_CLOSE, WAIT_SEND };
|
||||
|
||||
// Wait for output, optionally draining through the final marker.
|
||||
static int wait_data(const char *host, enum wait_mode mode) {
|
||||
@@ -117,6 +117,13 @@ static int wait_data(const char *host, enum wait_mode mode) {
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
if (mode == WAIT_SEND) {
|
||||
usleep(100000); // Let the server shut down its read side
|
||||
n = send(fd, "x", 1, 0);
|
||||
usleep(500000); // Keep peer connected for server SHUT_WR
|
||||
close(fd);
|
||||
return n == 1 ? 0 : 1;
|
||||
}
|
||||
if (mode == WAIT_CLOSE) {
|
||||
n = recv(fd, buf, sizeof(buf), 0);
|
||||
close(fd);
|
||||
@@ -151,10 +158,12 @@ int main(int argc, char *argv[]) {
|
||||
return wait_data(argv[1], WAIT_HOLD);
|
||||
if (argc == 3 && strcmp(argv[2], "expectclose") == 0)
|
||||
return wait_data(argv[1], WAIT_CLOSE);
|
||||
if (argc == 3 && strcmp(argv[2], "sendlater") == 0)
|
||||
return wait_data(argv[1], WAIT_SEND);
|
||||
if (argc == 3) connections = atoi(argv[2]);
|
||||
if ((argc != 2 && argc != 3) || connections < 1 ||
|
||||
connections > NUM_CONNECTIONS) {
|
||||
fprintf(stderr, "usage: %s IP [connections|waitandabort|waitanddrain|hold|expectclose]\n",
|
||||
fprintf(stderr, "usage: %s IP [connections|waitandabort|waitanddrain|hold|expectclose|sendlater]\n",
|
||||
argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
+139
-7
@@ -91,6 +91,22 @@ static void wait_ready(struct mg_mgr *mgr) {
|
||||
MG_INFO(("Interface started, starting main loop"));
|
||||
}
|
||||
|
||||
static void test_inet(void) {
|
||||
struct in_addr addr;
|
||||
char buf[INET_ADDRSTRLEN];
|
||||
char *str;
|
||||
|
||||
ASSERT(inet_pton(AF_INET, "192.0.2.1", &addr) == 1);
|
||||
ASSERT(inet_ntop(AF_INET, &addr, buf, sizeof(buf)) != NULL);
|
||||
ASSERT(strcmp(buf, "192.0.2.1") == 0);
|
||||
str = inet_ntoa(addr);
|
||||
ASSERT(str != NULL);
|
||||
ASSERT(strcmp(str, "192.0.2.1") == 0);
|
||||
ASSERT(inet_addr("192.0.2.1") == addr.s_addr);
|
||||
ASSERT(inet_pton(AF_INET, "not-an-ip", &addr) == 0);
|
||||
ASSERT(inet_pton(AF_INET6, "::1", &addr) < 0 && errno == EAFNOSUPPORT);
|
||||
}
|
||||
|
||||
#if !MG_ENABLE_FREERTOS
|
||||
static bool s_fail_alloc;
|
||||
|
||||
@@ -132,9 +148,10 @@ static volatile bool s_ready_waiting, s_ready_done;
|
||||
static volatile bool s_backlog_ready, s_backlog_full, s_backlog_accept;
|
||||
static volatile bool s_tx_held, s_tx_waits, s_tx_fail, s_tx_error;
|
||||
static volatile bool s_send_waiting;
|
||||
static volatile bool s_send_done, s_send_expect_error;
|
||||
static volatile bool s_send_done, s_send_expect_error, s_send_expect_shutdown;
|
||||
static volatile bool s_recv_start, s_recv_waiting, s_recv_done;
|
||||
static volatile bool s_recv_expect_error;
|
||||
static volatile bool s_shutdown_waiting, s_shutdown_done;
|
||||
static size_t (*s_tx)(const void *, size_t, struct mg_tcpip_if *);
|
||||
|
||||
struct client_data {
|
||||
@@ -152,6 +169,7 @@ static void select_task(void *args);
|
||||
static void readiness_task(void *args);
|
||||
static void backlog_task(void *args);
|
||||
static void tx_gate_task(void *args);
|
||||
static void shutdown_task(void *args);
|
||||
|
||||
struct atask_args {
|
||||
bool listener_nonblock;
|
||||
@@ -300,8 +318,13 @@ static void tx_gate_task(void *args) {
|
||||
// receiver/sender > network task > gate: final send is waiting
|
||||
while (!s_send_waiting) vTaskDelay(1);
|
||||
ASSERT(!s_send_done);
|
||||
if (s_send_expect_error) s_tx_error = s_tx_fail = true;
|
||||
else s_tx_held = false;
|
||||
if (s_send_expect_shutdown) {
|
||||
ASSERT(shutdown((int) (uintptr_t) args, SHUT_WR) == 0);
|
||||
} else if (s_send_expect_error) {
|
||||
s_tx_error = s_tx_fail = true;
|
||||
} else {
|
||||
s_tx_held = false;
|
||||
}
|
||||
vTaskDelete(NULL);
|
||||
(void) args;
|
||||
}
|
||||
@@ -342,15 +365,19 @@ static void send_task(void *args) {
|
||||
n = send(fd, buf, sizeof(buf), MSG_DONTWAIT);
|
||||
ASSERT(n < 0 && errno == EAGAIN); // Same full c->send: MSG_DONTWAIT
|
||||
|
||||
if (!s_send_expect_error) {
|
||||
if (!s_send_expect_error && !s_send_expect_shutdown) {
|
||||
s_recv_start = true; // O_NONBLOCK is per socket; now start the receiver
|
||||
while (!s_recv_waiting) vTaskDelay(1);
|
||||
}
|
||||
s_send_waiting = true; // Gate task releases TX after this send blocks
|
||||
n = send(fd, &marker, sizeof(marker), 0);
|
||||
if (s_send_expect_error) ASSERT(n < 0 && errno == EPIPE);
|
||||
else ASSERT(n == (ssize_t) sizeof(marker));
|
||||
if (s_send_expect_error || s_send_expect_shutdown) {
|
||||
ASSERT(n < 0 && errno == EPIPE);
|
||||
} else {
|
||||
ASSERT(n == (ssize_t) sizeof(marker));
|
||||
}
|
||||
s_send_done = true;
|
||||
if (s_send_expect_shutdown) close(fd);
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
@@ -388,7 +415,7 @@ static void atask(void *args) {
|
||||
ASSERT(result == pdPASS);
|
||||
}
|
||||
if (cfg->gate != NULL) {
|
||||
result = xTaskCreate(cfg->gate, "gate", 256, NULL,
|
||||
result = xTaskCreate(cfg->gate, "gate", 256, (void *) (uintptr_t) fd,
|
||||
configMAX_PRIORITIES - 3, NULL);
|
||||
ASSERT(result == pdPASS);
|
||||
}
|
||||
@@ -514,6 +541,59 @@ static void backlog_task(void *args) {
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
static void shutdown_task(void *args) {
|
||||
struct sockaddr_in local, peer;
|
||||
struct timeval zero = {0, 0};
|
||||
struct pollfd p;
|
||||
fd_set e;
|
||||
socklen_t len;
|
||||
char buf;
|
||||
int fd, lfd;
|
||||
|
||||
(void) args;
|
||||
lfd = open_listener(5, true);
|
||||
s_shutdown_waiting = true;
|
||||
while ((fd = accept(lfd, NULL, NULL)) < 0) {
|
||||
ASSERT(errno == EAGAIN);
|
||||
vTaskDelay(1);
|
||||
}
|
||||
len = sizeof(local);
|
||||
ASSERT(getsockname(lfd, (struct sockaddr *) &local, &len) == 0);
|
||||
ASSERT(len == sizeof(local) && local.sin_family == AF_INET &&
|
||||
local.sin_port == htons(1234) &&
|
||||
local.sin_addr.s_addr == INADDR_ANY);
|
||||
len = sizeof(peer);
|
||||
ASSERT(getpeername(lfd, (struct sockaddr *) &peer, &len) < 0 &&
|
||||
errno == ENOTCONN);
|
||||
len = sizeof(local);
|
||||
ASSERT(getsockname(fd, (struct sockaddr *) &local, &len) == 0);
|
||||
ASSERT(len == sizeof(local) && local.sin_family == AF_INET &&
|
||||
local.sin_port == htons(1234));
|
||||
len = sizeof(peer);
|
||||
ASSERT(getpeername(fd, (struct sockaddr *) &peer, &len) == 0);
|
||||
ASSERT(len == sizeof(peer) && peer.sin_family == AF_INET &&
|
||||
peer.sin_port != 0);
|
||||
ASSERT(shutdown(lfd, SHUT_RDWR) < 0 && errno == ENOTCONN);
|
||||
ASSERT(shutdown(fd, -1) < 0 && errno == EINVAL);
|
||||
ASSERT(shutdown(fd, SHUT_RD) == 0);
|
||||
ASSERT(recv(fd, &buf, sizeof(buf), 0) == 0);
|
||||
vTaskDelay(pdMS_TO_TICKS(200)); // Delayed client write must be discarded
|
||||
ASSERT(recv(fd, &buf, sizeof(buf), 0) == 0);
|
||||
ASSERT(shutdown(fd, SHUT_WR) == 0);
|
||||
ASSERT(send(fd, &buf, sizeof(buf), 0) < 0 && errno == EPIPE);
|
||||
FD_ZERO(&e);
|
||||
FD_SET(fd, &e);
|
||||
ASSERT(select(fd + 1, NULL, NULL, &e, &zero) == 1);
|
||||
ASSERT(FD_ISSET(fd, &e));
|
||||
p.fd = fd, p.events = POLLOUT, p.revents = 0;
|
||||
ASSERT(poll(&p, 1, 0) == 1);
|
||||
ASSERT(p.revents == POLLERR);
|
||||
ASSERT(close(fd) == 0);
|
||||
ASSERT(close(lfd) == 0);
|
||||
s_shutdown_done = true;
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
// task2: tests owner.
|
||||
static void task2(void *args) {
|
||||
struct mg_mgr *mgr = (struct mg_mgr *)args; // Event manager
|
||||
@@ -555,6 +635,16 @@ static void task2(void *args) {
|
||||
DASHBOARD("select_child_write");
|
||||
DASHBOARD("poll_child_write");
|
||||
|
||||
s_error = false;
|
||||
s_shutdown_waiting = s_shutdown_done = false;
|
||||
ASSERT(xTaskCreate(shutdown_task, "shutdown", 512, NULL,
|
||||
configMAX_PRIORITIES - 1, NULL) == pdPASS);
|
||||
while (!s_shutdown_waiting) vTaskDelay(1);
|
||||
run_client(ip, "sendlater");
|
||||
while (!s_shutdown_done) vTaskDelay(1);
|
||||
DASHBOARD("shutdown_read");
|
||||
DASHBOARD("shutdown_write");
|
||||
|
||||
s_error = false;
|
||||
s_backlog_ready = s_backlog_full = s_backlog_accept = false;
|
||||
ASSERT(xTaskCreate(backlog_task, "backlog", 512, NULL,
|
||||
@@ -669,12 +759,27 @@ static void task2(void *args) {
|
||||
while (s_wait) vTaskDelay(pdMS_TO_TICKS(10));
|
||||
s_tx_held = s_tx_fail = s_tx_error = s_send_expect_error = false;
|
||||
|
||||
s_error = false;
|
||||
s_wait = s_tx_held = s_tx_waits = s_tx_fail = s_tx_error = false;
|
||||
s_send_waiting = s_send_done = s_send_expect_error = false;
|
||||
s_send_expect_shutdown = true;
|
||||
ASSERT(xTaskCreate(atask, "atask", 256, (void *) &s_send_error_server,
|
||||
configMAX_PRIORITIES - 1, NULL) == pdPASS);
|
||||
run_client(ip, "hold");
|
||||
ASSERT(s_send_done);
|
||||
DASHBOARD("shutdown_send_wakeup");
|
||||
s_wait = true;
|
||||
while (s_wait) vTaskDelay(pdMS_TO_TICKS(10));
|
||||
s_tx_held = s_send_expect_shutdown = false;
|
||||
|
||||
mg_free(ip);
|
||||
|
||||
s_error = false;
|
||||
{
|
||||
fd_set e;
|
||||
struct pollfd p;
|
||||
socklen_t len;
|
||||
int err;
|
||||
int fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
struct sockaddr_in sa;
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
@@ -694,6 +799,12 @@ static void task2(void *args) {
|
||||
ASSERT(poll(&p, 1, 0) == 1);
|
||||
ASSERT((p.revents & POLLERR) != 0);
|
||||
ASSERT((p.revents & POLLOUT) == 0);
|
||||
len = sizeof(err);
|
||||
ASSERT(getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &len) == 0);
|
||||
ASSERT(len == sizeof(err) && err == EIO);
|
||||
len = sizeof(err), err = -1;
|
||||
ASSERT(getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &len) == 0);
|
||||
ASSERT(len == sizeof(err) && err == 0);
|
||||
ASSERT(close(fd) == 0);
|
||||
}
|
||||
DASHBOARD("select_error");
|
||||
@@ -943,6 +1054,25 @@ static void nortos_test(struct mg_mgr *mgr) {
|
||||
DASHBOARD("nortos_poll_children");
|
||||
DASHBOARD("nortos_echo");
|
||||
|
||||
lfd = open_listener(5, true);
|
||||
pid = start_client(ip, "hold");
|
||||
fd = nortos_accept(mgr, lfd);
|
||||
ASSERT(shutdown(fd, SHUT_RD) == 0);
|
||||
ASSERT(recv(fd, &buf, sizeof(buf), 0) == 0);
|
||||
ASSERT(shutdown(fd, SHUT_WR) == 0);
|
||||
ASSERT(send(fd, &buf, sizeof(buf), 0) < 0 && errno == EPIPE);
|
||||
FD_ZERO(&e);
|
||||
FD_SET(fd, &e);
|
||||
ASSERT(select(fd + 1, NULL, NULL, &e, &zero) == 1);
|
||||
ASSERT(FD_ISSET(fd, &e));
|
||||
p.fd = fd, p.events = POLLOUT, p.revents = 0;
|
||||
ASSERT(poll(&p, 1, 0) == 1);
|
||||
ASSERT(p.revents == POLLERR);
|
||||
nortos_wait_client(mgr, pid);
|
||||
ASSERT(close(fd) == 0);
|
||||
ASSERT(close(lfd) == 0);
|
||||
DASHBOARD("nortos_shutdown");
|
||||
|
||||
fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sa.sin_family = AF_INET;
|
||||
@@ -983,6 +1113,8 @@ static bool bsd_x_test(struct mg_tcpip_driver *driver, void *driver_data, const
|
||||
|
||||
mg_tcpip_init(&mgr, &mif);
|
||||
ASSERT(mgr.ifp != NULL); // driver init succeeded
|
||||
test_inet();
|
||||
DASHBOARD("inet");
|
||||
MG_INFO(("Init done, starting interface"));
|
||||
usleep(200000); // 200 ms
|
||||
|
||||
|
||||
Reference in new issue
Block a user