mirror of
https://github.com/lwip-tcpip/lwip.git
synced 2024-08-23 06:35:57 +00:00
Finally fix bug #50088 (socket/netconn: data before RST should be readable) and added a unit test for it
This commit is contained in:
parent
4cec20230e
commit
47f55b02bf
|
@ -524,25 +524,30 @@ netconn_recv_data(struct netconn *conn, void **new_buf, u8_t apiflags)
|
||||||
{
|
{
|
||||||
void *buf = NULL;
|
void *buf = NULL;
|
||||||
u16_t len;
|
u16_t len;
|
||||||
err_t err;
|
|
||||||
|
|
||||||
LWIP_ERROR("netconn_recv: invalid pointer", (new_buf != NULL), return ERR_ARG;);
|
LWIP_ERROR("netconn_recv: invalid pointer", (new_buf != NULL), return ERR_ARG;);
|
||||||
*new_buf = NULL;
|
*new_buf = NULL;
|
||||||
LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL), return ERR_ARG;);
|
LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL), return ERR_ARG;);
|
||||||
|
|
||||||
err = netconn_err(conn);
|
|
||||||
if (err != ERR_OK) {
|
|
||||||
/* return pending error */
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
if (!sys_mbox_valid(&conn->recvmbox)) {
|
if (!sys_mbox_valid(&conn->recvmbox)) {
|
||||||
return ERR_CLSD;
|
err_t err = netconn_err(conn);
|
||||||
|
if (err != ERR_OK) {
|
||||||
|
/* return pending error */
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
return ERR_CONN;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (netconn_is_nonblocking(conn) || (apiflags & NETCONN_DONTBLOCK) || (conn->flags & NETCONN_FLAG_MBOXCLOSED)) {
|
if (netconn_is_nonblocking(conn) || (apiflags & NETCONN_DONTBLOCK) ||
|
||||||
|
(conn->flags & NETCONN_FLAG_MBOXCLOSED) || (conn->pending_err != ERR_OK)) {
|
||||||
if (sys_arch_mbox_tryfetch(&conn->recvmbox, &buf) == SYS_ARCH_TIMEOUT) {
|
if (sys_arch_mbox_tryfetch(&conn->recvmbox, &buf) == SYS_ARCH_TIMEOUT) {
|
||||||
|
err_t err = netconn_err(conn);
|
||||||
|
if (err != ERR_OK) {
|
||||||
|
/* return pending error */
|
||||||
|
return err;
|
||||||
|
}
|
||||||
if (conn->flags & NETCONN_FLAG_MBOXCLOSED) {
|
if (conn->flags & NETCONN_FLAG_MBOXCLOSED) {
|
||||||
return ERR_CLSD;
|
return ERR_CONN;
|
||||||
}
|
}
|
||||||
return ERR_WOULDBLOCK;
|
return ERR_WOULDBLOCK;
|
||||||
}
|
}
|
||||||
|
@ -561,6 +566,7 @@ netconn_recv_data(struct netconn *conn, void **new_buf, u8_t apiflags)
|
||||||
if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP)
|
if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP)
|
||||||
#endif /* (LWIP_UDP || LWIP_RAW) */
|
#endif /* (LWIP_UDP || LWIP_RAW) */
|
||||||
{
|
{
|
||||||
|
err_t err;
|
||||||
/* Check if this is an error message or a pbuf */
|
/* Check if this is an error message or a pbuf */
|
||||||
if (lwip_netconn_is_err_msg(buf, &err)) {
|
if (lwip_netconn_is_err_msg(buf, &err)) {
|
||||||
/* new_buf has been zeroed above already */
|
/* new_buf has been zeroed above already */
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
#include "lwip/tcpip.h"
|
#include "lwip/tcpip.h"
|
||||||
#include "lwip/priv/tcp_priv.h"
|
#include "lwip/priv/tcp_priv.h"
|
||||||
|
#include "lwip/api.h"
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -641,6 +642,149 @@ START_TEST(test_sockets_select)
|
||||||
}
|
}
|
||||||
END_TEST
|
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 */
|
/** Create the suite including all tests for this module */
|
||||||
Suite *
|
Suite *
|
||||||
sockets_suite(void)
|
sockets_suite(void)
|
||||||
|
@ -650,6 +794,7 @@ sockets_suite(void)
|
||||||
TESTFUNC(test_sockets_allfunctions_basic),
|
TESTFUNC(test_sockets_allfunctions_basic),
|
||||||
TESTFUNC(test_sockets_msgapis),
|
TESTFUNC(test_sockets_msgapis),
|
||||||
TESTFUNC(test_sockets_select),
|
TESTFUNC(test_sockets_select),
|
||||||
|
TESTFUNC(test_sockets_recv_after_rst),
|
||||||
};
|
};
|
||||||
return create_suite("SOCKETS", tests, sizeof(tests)/sizeof(testfunc), sockets_setup, sockets_teardown);
|
return create_suite("SOCKETS", tests, sizeof(tests)/sizeof(testfunc), sockets_setup, sockets_teardown);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user