Finally fix bug #50088 (socket/netconn: data before RST should be readable) and added a unit test for it

This commit is contained in:
goldsimon
2017-08-03 22:28:22 +02:00
parent 4cec20230e
commit 47f55b02bf
2 changed files with 160 additions and 9 deletions

View File

@@ -8,6 +8,7 @@
#include "lwip/tcpip.h"
#include "lwip/priv/tcp_priv.h"
#include "lwip/api.h"
static int
@@ -641,6 +642,149 @@ START_TEST(test_sockets_select)
}
END_TEST
START_TEST(test_sockets_recv_after_rst)
{
int sl, sact;
int spass = -1;
int ret;
struct sockaddr_in sa_listen;
const u16_t port = 1234;
int arg;
const char txbuf[] = "something";
char rxbuf[16];
struct lwip_sock *sact_sock;
int err;
LWIP_UNUSED_ARG(_i);
fail_unless(test_sockets_get_used_count() == 0);
memset(&sa_listen, 0, sizeof(sa_listen));
sa_listen.sin_family = AF_INET;
sa_listen.sin_port = PP_HTONS(port);
sa_listen.sin_addr.s_addr = PP_HTONL(INADDR_LOOPBACK);
/* set up the listener */
sl = lwip_socket(AF_INET, SOCK_STREAM, 0);
fail_unless(sl >= 0);
fail_unless(test_sockets_get_used_count() == 0);
ret = lwip_bind(sl, (struct sockaddr *)&sa_listen, sizeof(sa_listen));
fail_unless(ret == 0);
ret = lwip_listen(sl, 0);
fail_unless(ret == 0);
/* set up the client */
sact = lwip_socket(AF_INET, SOCK_STREAM, 0);
fail_unless(sact >= 0);
fail_unless(test_sockets_get_used_count() == 0);
/* set the client to nonblocking to simplify this test */
arg = 1;
ret = lwip_ioctl(sact, FIONBIO, &arg);
fail_unless(ret == 0);
/* connect */
do {
ret = lwip_connect(sact, (struct sockaddr *)&sa_listen, sizeof(sa_listen));
err = errno;
fail_unless((ret == 0) || (ret == -1));
if (ret != 0) {
if (err == EISCONN) {
/* Although this is not valid, use EISCONN as an indicator for successful connection.
This marks us as "connect phase is done". On error, we would either have a different
errno code or "send" fails later... -> good enough for this test. */
ret = 0;
} else {
fail_unless(err == EINPROGRESS);
if (err != EINPROGRESS) {
goto cleanup;
}
/* we're in progress: little side check: test for EALREADY */
ret = lwip_connect(sact, (struct sockaddr *)&sa_listen, sizeof(sa_listen));
err = errno;
fail_unless(ret == -1);
fail_unless(err == EALREADY);
if ((ret != -1) || (err != EALREADY)) {
goto cleanup;
}
}
tcpip_thread_poll_one();
tcpip_thread_poll_one();
tcpip_thread_poll_one();
tcpip_thread_poll_one();
}
} while (ret != 0);
fail_unless(ret == 0);
/* accept the server connection part */
spass = lwip_accept(sl, NULL, NULL);
fail_unless(spass >= 0);
/* write data from client */
ret = lwip_send(sact, txbuf, sizeof(txbuf), 0);
fail_unless(ret == sizeof(txbuf));
tcpip_thread_poll_one();
tcpip_thread_poll_one();
/* issue RST (This is a HACK, don't try this in your own app!) */
sact_sock = lwip_socket_dbg_get_socket(sact);
fail_unless(sact_sock != NULL);
if (sact_sock != NULL) {
struct netconn *sact_conn = sact_sock->conn;
fail_unless(sact_conn != NULL);
if (sact_conn != NULL) {
struct tcp_pcb *pcb = sact_conn->pcb.tcp;
fail_unless(pcb != NULL);
if (pcb != NULL) {
tcp_rst(pcb, pcb->snd_nxt, pcb->rcv_nxt, &pcb->local_ip, &pcb->remote_ip,
pcb->local_port, pcb->remote_port);
}
}
}
tcpip_thread_poll_one();
tcpip_thread_poll_one();
/* expect to receive data first */
ret = lwip_recv(spass, rxbuf, sizeof(rxbuf), 0);
fail_unless(ret > 0);
tcpip_thread_poll_one();
tcpip_thread_poll_one();
/* expect to receive RST indication */
ret = lwip_recv(spass, rxbuf, sizeof(rxbuf), 0);
fail_unless(ret == -1);
err = errno;
fail_unless(err == ECONNRESET);
tcpip_thread_poll_one();
tcpip_thread_poll_one();
/* expect to receive ENOTCONN indication */
ret = lwip_recv(spass, rxbuf, sizeof(rxbuf), 0);
fail_unless(ret == -1);
err = errno;
fail_unless(err == ENOTCONN);
tcpip_thread_poll_one();
tcpip_thread_poll_one();
/* expect to receive ENOTCONN indication */
ret = lwip_recv(spass, rxbuf, sizeof(rxbuf), 0);
fail_unless(ret == -1);
err = errno;
fail_unless(err == ENOTCONN);
tcpip_thread_poll_one();
tcpip_thread_poll_one();
cleanup:
ret = lwip_close(sl);
fail_unless(ret == 0);
ret = lwip_close(sact);
fail_unless(ret == 0);
if (spass >= 0) {
ret = lwip_close(spass);
fail_unless(ret == 0);
}
}
END_TEST
/** Create the suite including all tests for this module */
Suite *
sockets_suite(void)
@@ -650,6 +794,7 @@ sockets_suite(void)
TESTFUNC(test_sockets_allfunctions_basic),
TESTFUNC(test_sockets_msgapis),
TESTFUNC(test_sockets_select),
TESTFUNC(test_sockets_recv_after_rst),
};
return create_suite("SOCKETS", tests, sizeof(tests)/sizeof(testfunc), sockets_setup, sockets_teardown);
}