Better error handling - report from iotest

This commit is contained in:
Sergey Lyubka 2022-06-29 17:02:37 +01:00
parent 6a8b5b06d0
commit 017c7290d6
6 changed files with 1358 additions and 2556 deletions

View File

@ -26,10 +26,9 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install packages
run: sudo apt-get install libmbedtls-dev libpcap-dev
- name: examples
run: make clean examples
- run: sudo apt-get install libmbedtls-dev libpcap-dev
- run: make clean examples
- run: make clean test IPV6=0 MG_ENABLE_POLL=1
macos:
runs-on: macos-latest
steps:
@ -51,26 +50,21 @@ jobs:
sudo curl -F "file=@sntp.cap" https://file.io/?expires=1w
- name: openssl
run: make test SSL=OPENSSL IPV6=0 ASAN_OPTIONS= OPENSSL=`echo /usr/local/Cellar/openssl*/*`
- name: exports
run: make mg_prefix
- run: make mg_prefix
windows:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: vc98
run: make vc98
- name: vc2017
run: make vc2017
- name: mingw
run: make mingw
- name: mingw++
run: make mingw++
- run: make vc98
- run: make vc2017
- run: make vc22
- run: make mingw
- run: make mingw++
arm:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: arm
run: make arm
- run: make arm
matrix_examples:
runs-on: ubuntu-latest
strategy:

View File

@ -8,7 +8,8 @@ VALGRIND_OPTS ?= -O0 -g3
INCS ?= -Isrc -I.
SSL ?= MBEDTLS
CWD ?= $(realpath $(CURDIR))
DOCKER ?= docker run --rm -e Tmp=. -e WINEDEBUG=-all -v $(CWD):$(CWD) -w $(CWD)
ENV ?= -e Tmp=. -e WINEDEBUG=-all
DOCKER ?= docker run --rm $(ENV) -v $(CWD):$(CWD) -w $(CWD)
VCFLAGS = /nologo /W3 /O2 /MD /I. $(DEFS) $(TFLAGS)
IPV6 ?= 1
ASAN ?= -fsanitize=address,undefined -fno-sanitize-recover=all
@ -33,7 +34,7 @@ CFLAGS += -DMG_ENABLE_OPENSSL=1 -I$(OPENSSL)/include
LDFLAGS ?= -L$(OPENSSL)/lib -lssl -lcrypto
endif
all: mg_prefix unamalgamated unpacked test test++ valgrind arm examples vc98 vc2017 mingw mingw++ linux linux++ fuzz
all: mg_prefix unamalgamated unpacked test test++ valgrind arm examples vc98 vc2017 vc22 mingw mingw++ linux linux++ fuzz
examples:
@for X in $(EXAMPLES); do test -f $$X/Makefile || continue; $(MAKE) -C $$X example || exit 1; done

File diff suppressed because it is too large Load Diff

View File

@ -4193,7 +4193,7 @@ void mg_connect_resolved(struct mg_connection *c) {
if ((rc = connect(FD(c), &usa.sa, slen)) == 0) {
mg_call(c, MG_EV_CONNECT, NULL);
} else if (mg_sock_would_block()) {
MG_DEBUG(("%lu %p connect in progress...", c->id, c->fd));
MG_DEBUG(("%lu %p -> %x:%hu pend", c->id, c->fd, c->rem.ip, c->rem.port));
c->is_connecting = 1;
} else {
mg_error(c, "connect: %d", MG_SOCK_ERRNO);
@ -4355,7 +4355,8 @@ static void mg_iotest(struct mg_mgr *mgr, int ms) {
// Socket not valid, ignore
} else {
fds[n].fd = FD(c);
if (can_read(c)) fds[n].events = POLLIN;
fds[n].events = POLLERR;
if (can_read(c)) fds[n].events |= POLLIN;
if (can_write(c)) fds[n].events |= POLLOUT;
n++;
if (mg_tls_pending(c) > 0) ms = 0; // Don't wait if TLS is ready
@ -4367,72 +4368,56 @@ static void mg_iotest(struct mg_mgr *mgr, int ms) {
} else {
n = 0;
for (struct mg_connection *c = mgr->conns; c != NULL; c = c->next) {
if (skip_iotest(c)) {
// Socket not valid, ignore
if (skip_iotest(c)) continue;
if (fds[n].revents & POLLERR) {
mg_error(c, "socket error");
} else {
c->is_readable = (unsigned) (fds[n].revents & POLLIN ? 1 : 0);
c->is_writable = (unsigned) (fds[n].revents & POLLOUT ? 1 : 0);
if (mg_tls_pending(c) > 0) c->is_readable = 1;
fds[n].revents = 0;
n++;
}
n++;
}
}
#else
struct timeval tv = {ms / 1000, (ms % 1000) * 1000}, tv_zero = {0, 0};
struct mg_connection *c;
fd_set rset, wset;
fd_set rset, wset, eset;
SOCKET maxfd = 0;
int rc;
FD_ZERO(&rset);
FD_ZERO(&wset);
FD_ZERO(&rset), FD_ZERO(&wset), FD_ZERO(&eset);
for (c = mgr->conns; c != NULL; c = c->next) {
c->is_readable = c->is_writable = 0;
if (skip_iotest(c)) continue;
FD_SET(FD(c), &eset);
if (can_read(c)) FD_SET(FD(c), &rset);
if (can_write(c)) FD_SET(FD(c), &wset);
if (mg_tls_pending(c) > 0) tv = tv_zero;
if (FD(c) > maxfd) maxfd = FD(c);
}
if ((rc = select((int) maxfd + 1, &rset, &wset, NULL, &tv)) < 0) {
if ((rc = select((int) maxfd + 1, &rset, &wset, &eset, &tv)) < 0) {
#if MG_ARCH == MG_ARCH_WIN32
if (maxfd == 0) Sleep(ms); // On Windows, select fails if no sockets
#else
MG_ERROR(("select: %d %d", rc, MG_SOCK_ERRNO));
#endif
FD_ZERO(&rset);
FD_ZERO(&wset);
FD_ZERO(&rset), FD_ZERO(&wset), FD_ZERO(&eset);
}
for (c = mgr->conns; c != NULL; c = c->next) {
c->is_readable = FD(c) != INVALID_SOCKET && FD_ISSET(FD(c), &rset);
c->is_writable = FD(c) != INVALID_SOCKET && FD_ISSET(FD(c), &wset);
if (mg_tls_pending(c) > 0) c->is_readable = 1;
if (FD(c) != INVALID_SOCKET && FD_ISSET(FD(c), &eset)) {
mg_error(c, "socket error");
} else {
c->is_readable = FD(c) != INVALID_SOCKET && FD_ISSET(FD(c), &rset);
c->is_writable = FD(c) != INVALID_SOCKET && FD_ISSET(FD(c), &wset);
if (mg_tls_pending(c) > 0) c->is_readable = 1;
}
}
#endif
}
static void connect_conn(struct mg_connection *c) {
int rc = 0;
#if (MG_ARCH != MG_ARCH_FREERTOS_TCP) && (MG_ARCH != MG_ARCH_RTX)
socklen_t len = sizeof(rc);
if (getsockopt(FD(c), SOL_SOCKET, SO_ERROR, (char *) &rc, &len)) rc = 1;
#endif
if (rc == EAGAIN || rc == EWOULDBLOCK) rc = 0;
c->is_connecting = 0;
if (rc) {
char buf[50];
mg_error(c, "error connecting to %s",
mg_straddr(&c->rem, buf, sizeof(buf)));
} else {
if (c->is_tls_hs) mg_tls_handshake(c);
mg_call(c, MG_EV_CONNECT, NULL);
}
}
void mg_mgr_poll(struct mg_mgr *mgr, int ms) {
struct mg_connection *c, *tmp;
uint64_t now;
@ -4453,7 +4438,11 @@ void mg_mgr_poll(struct mg_mgr *mgr, int ms) {
} else if (c->is_listening && c->is_udp == 0) {
if (c->is_readable) accept_conn(mgr, c);
} else if (c->is_connecting) {
if (c->is_readable || c->is_writable) connect_conn(c);
if (c->is_readable || c->is_writable) {
c->is_connecting = 0;
mg_call(c, MG_EV_CONNECT, NULL);
if (c->is_tls_hs) mg_tls_handshake(c);
}
} else if (c->is_tls_hs) {
if ((c->is_readable || c->is_writable)) mg_tls_handshake(c);
} else {

View File

@ -351,7 +351,7 @@ void mg_connect_resolved(struct mg_connection *c) {
if ((rc = connect(FD(c), &usa.sa, slen)) == 0) {
mg_call(c, MG_EV_CONNECT, NULL);
} else if (mg_sock_would_block()) {
MG_DEBUG(("%lu %p connect in progress...", c->id, c->fd));
MG_DEBUG(("%lu %p -> %x:%hu pend", c->id, c->fd, c->rem.ip, c->rem.port));
c->is_connecting = 1;
} else {
mg_error(c, "connect: %d", MG_SOCK_ERRNO);
@ -513,7 +513,8 @@ static void mg_iotest(struct mg_mgr *mgr, int ms) {
// Socket not valid, ignore
} else {
fds[n].fd = FD(c);
if (can_read(c)) fds[n].events = POLLIN;
fds[n].events = POLLERR;
if (can_read(c)) fds[n].events |= POLLIN;
if (can_write(c)) fds[n].events |= POLLOUT;
n++;
if (mg_tls_pending(c) > 0) ms = 0; // Don't wait if TLS is ready
@ -525,72 +526,56 @@ static void mg_iotest(struct mg_mgr *mgr, int ms) {
} else {
n = 0;
for (struct mg_connection *c = mgr->conns; c != NULL; c = c->next) {
if (skip_iotest(c)) {
// Socket not valid, ignore
if (skip_iotest(c)) continue;
if (fds[n].revents & POLLERR) {
mg_error(c, "socket error");
} else {
c->is_readable = (unsigned) (fds[n].revents & POLLIN ? 1 : 0);
c->is_writable = (unsigned) (fds[n].revents & POLLOUT ? 1 : 0);
if (mg_tls_pending(c) > 0) c->is_readable = 1;
fds[n].revents = 0;
n++;
}
n++;
}
}
#else
struct timeval tv = {ms / 1000, (ms % 1000) * 1000}, tv_zero = {0, 0};
struct mg_connection *c;
fd_set rset, wset;
fd_set rset, wset, eset;
SOCKET maxfd = 0;
int rc;
FD_ZERO(&rset);
FD_ZERO(&wset);
FD_ZERO(&rset), FD_ZERO(&wset), FD_ZERO(&eset);
for (c = mgr->conns; c != NULL; c = c->next) {
c->is_readable = c->is_writable = 0;
if (skip_iotest(c)) continue;
FD_SET(FD(c), &eset);
if (can_read(c)) FD_SET(FD(c), &rset);
if (can_write(c)) FD_SET(FD(c), &wset);
if (mg_tls_pending(c) > 0) tv = tv_zero;
if (FD(c) > maxfd) maxfd = FD(c);
}
if ((rc = select((int) maxfd + 1, &rset, &wset, NULL, &tv)) < 0) {
if ((rc = select((int) maxfd + 1, &rset, &wset, &eset, &tv)) < 0) {
#if MG_ARCH == MG_ARCH_WIN32
if (maxfd == 0) Sleep(ms); // On Windows, select fails if no sockets
#else
MG_ERROR(("select: %d %d", rc, MG_SOCK_ERRNO));
#endif
FD_ZERO(&rset);
FD_ZERO(&wset);
FD_ZERO(&rset), FD_ZERO(&wset), FD_ZERO(&eset);
}
for (c = mgr->conns; c != NULL; c = c->next) {
c->is_readable = FD(c) != INVALID_SOCKET && FD_ISSET(FD(c), &rset);
c->is_writable = FD(c) != INVALID_SOCKET && FD_ISSET(FD(c), &wset);
if (mg_tls_pending(c) > 0) c->is_readable = 1;
if (FD(c) != INVALID_SOCKET && FD_ISSET(FD(c), &eset)) {
mg_error(c, "socket error");
} else {
c->is_readable = FD(c) != INVALID_SOCKET && FD_ISSET(FD(c), &rset);
c->is_writable = FD(c) != INVALID_SOCKET && FD_ISSET(FD(c), &wset);
if (mg_tls_pending(c) > 0) c->is_readable = 1;
}
}
#endif
}
static void connect_conn(struct mg_connection *c) {
int rc = 0;
#if (MG_ARCH != MG_ARCH_FREERTOS_TCP) && (MG_ARCH != MG_ARCH_RTX)
socklen_t len = sizeof(rc);
if (getsockopt(FD(c), SOL_SOCKET, SO_ERROR, (char *) &rc, &len)) rc = 1;
#endif
if (rc == EAGAIN || rc == EWOULDBLOCK) rc = 0;
c->is_connecting = 0;
if (rc) {
char buf[50];
mg_error(c, "error connecting to %s",
mg_straddr(&c->rem, buf, sizeof(buf)));
} else {
if (c->is_tls_hs) mg_tls_handshake(c);
mg_call(c, MG_EV_CONNECT, NULL);
}
}
void mg_mgr_poll(struct mg_mgr *mgr, int ms) {
struct mg_connection *c, *tmp;
uint64_t now;
@ -611,7 +596,11 @@ void mg_mgr_poll(struct mg_mgr *mgr, int ms) {
} else if (c->is_listening && c->is_udp == 0) {
if (c->is_readable) accept_conn(mgr, c);
} else if (c->is_connecting) {
if (c->is_readable || c->is_writable) connect_conn(c);
if (c->is_readable || c->is_writable) {
c->is_connecting = 0;
mg_call(c, MG_EV_CONNECT, NULL);
if (c->is_tls_hs) mg_tls_handshake(c);
}
} else if (c->is_tls_hs) {
if ((c->is_readable || c->is_writable)) mg_tls_handshake(c);
} else {

View File

@ -1,6 +1,7 @@
#include "mongoose.h"
#include "float.h" // For DBL_EPSILON and HUGE_VAL
#include "math.h"
#include "mongoose.h"
static int s_num_tests = 0;
@ -606,7 +607,7 @@ static void test_ws(void) {
static void eh9(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
if (ev == MG_EV_ERROR) {
ASSERT(!strcmp((char *) ev_data, "error connecting to 127.0.0.1:55117"));
ASSERT(!strcmp((char *) ev_data, "socket error"));
*(int *) fn_data = 7;
}
(void) c;