mirror of
https://github.com/lwip-tcpip/lwip.git
synced 2024-11-04 23:29:25 +00:00
netconn/socket api: fixed bug #44225 "closing TCP socket should time out eventually", implemented task #6930 "Implement SO_LINGER": closing TCP sockets times out after 20 seconds or after the configured SND_TIMEOUT or depending on the linger settings; fixed that netconn_close/netconn_delete still used message passing for LWIP_TCPIP_CORE_LOCKING==1
This commit is contained in:
parent
ee833ea594
commit
6c3f6cfd89
10
CHANGELOG
10
CHANGELOG
@ -156,6 +156,16 @@ HISTORY
|
||||
|
||||
++ Bugfixes:
|
||||
|
||||
2014-02-10: Simon Goldschmidt
|
||||
* netconn API: fixed that netconn_close/netconn_delete still used message passing
|
||||
for LWIP_TCPIP_CORE_LOCKING==1
|
||||
|
||||
2014-02-10: Simon Goldschmidt
|
||||
* netconn/socket api: fixed bug #44225 "closing TCP socket should time out
|
||||
eventually", implemented task #6930 "Implement SO_LINGER": closing TCP sockets
|
||||
times out after 20 seconds or after the configured SND_TIMEOUT or depending
|
||||
on the linger settings.
|
||||
|
||||
2014-01-27: Simon Goldschmidt
|
||||
* api_msg.c: fixed that SHUT_RD followed by SHUT_WR was different to SHUT_RDWR,
|
||||
fixed return value of lwip_netconn_do_close on unconnected netconns
|
||||
|
@ -51,6 +51,7 @@
|
||||
#include "lwip/raw.h"
|
||||
#include "lwip/udp.h"
|
||||
#include "lwip/tcp.h"
|
||||
#include "lwip/tcp_impl.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
@ -122,9 +123,16 @@ netconn_delete(struct netconn *conn)
|
||||
}
|
||||
|
||||
API_MSG_VAR_ALLOC(msg);
|
||||
API_MSG_VAR_REF(msg).function = lwip_netconn_do_delconn;
|
||||
API_MSG_VAR_REF(msg).msg.conn = conn;
|
||||
err = tcpip_apimsg(&API_MSG_VAR_REF(msg));
|
||||
#if LWIP_SO_SNDTIMEO || LWIP_SO_LINGER
|
||||
/* get the time we started, which is later compared to
|
||||
sys_now() + conn->send_timeout */
|
||||
API_MSG_VAR_REF(msg).msg.msg.sd.time_started = sys_now();
|
||||
#else /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */
|
||||
API_MSG_VAR_REF(msg).msg.msg.sd.polls_left =
|
||||
((LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT + TCP_SLOW_INTERVAL - 1) / TCP_SLOW_INTERVAL) + 1;
|
||||
#endif /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */
|
||||
TCPIP_APIMSG(&API_MSG_VAR_REF(msg), lwip_netconn_do_delconn, err);
|
||||
API_MSG_VAR_FREE(msg);
|
||||
|
||||
if (err != ERR_OK) {
|
||||
@ -728,13 +736,18 @@ netconn_close_shutdown(struct netconn *conn, u8_t how)
|
||||
LWIP_ERROR("netconn_close: invalid conn", (conn != NULL), return ERR_ARG;);
|
||||
|
||||
API_MSG_VAR_ALLOC(msg);
|
||||
API_MSG_VAR_REF(msg).function = lwip_netconn_do_close;
|
||||
API_MSG_VAR_REF(msg).msg.conn = conn;
|
||||
/* shutting down both ends is the same as closing */
|
||||
API_MSG_VAR_REF(msg).msg.msg.sd.shut = how;
|
||||
/* because of the LWIP_TCPIP_CORE_LOCKING implementation of lwip_netconn_do_close,
|
||||
don't use TCPIP_APIMSG here */
|
||||
err = tcpip_apimsg(&API_MSG_VAR_REF(msg));
|
||||
#if LWIP_SO_SNDTIMEO || LWIP_SO_LINGER
|
||||
/* get the time we started, which is later compared to
|
||||
sys_now() + conn->send_timeout */
|
||||
API_MSG_VAR_REF(msg).msg.msg.sd.time_started = sys_now();
|
||||
#else /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */
|
||||
API_MSG_VAR_REF(msg).msg.msg.sd.polls_left =
|
||||
((LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT + TCP_SLOW_INTERVAL - 1) / TCP_SLOW_INTERVAL) + 1;
|
||||
#endif /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */
|
||||
TCPIP_APIMSG(&API_MSG_VAR_REF(msg), lwip_netconn_do_close, err);
|
||||
API_MSG_VAR_FREE(msg);
|
||||
|
||||
NETCONN_SET_SAFE_ERR(conn, err);
|
||||
|
@ -55,6 +55,9 @@
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/* netconns are polled once per second (e.g. continue write on memory error) */
|
||||
#define NETCONN_TCP_POLL_INTERVAL 2
|
||||
|
||||
#define SET_NONBLOCKING_CONNECT(conn, val) do { if(val) { \
|
||||
(conn)->flags |= NETCONN_FLAG_IN_NONBLOCKING_CONNECT; \
|
||||
} else { \
|
||||
@ -64,7 +67,7 @@
|
||||
/* forward declarations */
|
||||
#if LWIP_TCP
|
||||
static err_t lwip_netconn_do_writemore(struct netconn *conn);
|
||||
static void lwip_netconn_do_close_internal(struct netconn *conn);
|
||||
static err_t lwip_netconn_do_close_internal(struct netconn *conn);
|
||||
#endif
|
||||
|
||||
#if LWIP_RAW
|
||||
@ -285,6 +288,11 @@ poll_tcp(void *arg, struct tcp_pcb *pcb)
|
||||
if (conn->state == NETCONN_WRITE) {
|
||||
lwip_netconn_do_writemore(conn);
|
||||
} else if (conn->state == NETCONN_CLOSE) {
|
||||
#if !LWIP_SO_SNDTIMEO && !LWIP_SO_LINGER
|
||||
if (conn->current_msg && conn->current_msg->msg.sd.polls_left) {
|
||||
conn->current_msg->msg.sd.polls_left--;
|
||||
}
|
||||
#endif /* !LWIP_SO_SNDTIMEO && !LWIP_SO_LINGER */
|
||||
lwip_netconn_do_close_internal(conn);
|
||||
}
|
||||
/* @todo: implement connect timeout here? */
|
||||
@ -423,7 +431,7 @@ setup_tcp(struct netconn *conn)
|
||||
tcp_arg(pcb, conn);
|
||||
tcp_recv(pcb, recv_tcp);
|
||||
tcp_sent(pcb, sent_tcp);
|
||||
tcp_poll(pcb, poll_tcp, 4);
|
||||
tcp_poll(pcb, poll_tcp, NETCONN_TCP_POLL_INTERVAL);
|
||||
tcp_err(pcb, err_tcp);
|
||||
}
|
||||
|
||||
@ -466,7 +474,7 @@ accept_function(void *arg, struct tcp_pcb *newpcb, err_t err)
|
||||
tcp_arg(pcb, NULL);
|
||||
tcp_recv(pcb, NULL);
|
||||
tcp_sent(pcb, NULL);
|
||||
tcp_poll(pcb, NULL, 4);
|
||||
tcp_poll(pcb, NULL, 0);
|
||||
tcp_err(pcb, NULL);
|
||||
/* remove reference from to the pcb from this netconn */
|
||||
newconn->pcb.tcp = NULL;
|
||||
@ -647,6 +655,9 @@ netconn_alloc(enum netconn_type t, netconn_callback callback)
|
||||
conn->recv_bufsize = RECV_BUFSIZE_DEFAULT;
|
||||
conn->recv_avail = 0;
|
||||
#endif /* LWIP_SO_RCVBUF */
|
||||
#if LWIP_SO_LINGER
|
||||
conn->linger = -1;
|
||||
#endif /* LWIP_SO_LINGER */
|
||||
conn->flags = 0;
|
||||
return conn;
|
||||
free_and_return:
|
||||
@ -752,12 +763,16 @@ netconn_drain(struct netconn *conn)
|
||||
*
|
||||
* @param conn the TCP netconn to close
|
||||
*/
|
||||
static void
|
||||
static err_t
|
||||
lwip_netconn_do_close_internal(struct netconn *conn)
|
||||
{
|
||||
err_t err;
|
||||
u8_t shut, shut_rx, shut_tx, close;
|
||||
struct tcp_pcb* tpcb = conn->pcb.tcp;
|
||||
u8_t close_finished = 0;
|
||||
struct tcp_pcb* tpcb;
|
||||
#if LWIP_SO_LINGER
|
||||
u8_t linger_wait_required = 0;
|
||||
#endif /* LWIP_SO_LINGER */
|
||||
|
||||
LWIP_ASSERT("invalid conn", (conn != NULL));
|
||||
LWIP_ASSERT("this is for tcp netconns only", (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP));
|
||||
@ -765,6 +780,7 @@ lwip_netconn_do_close_internal(struct netconn *conn)
|
||||
LWIP_ASSERT("pcb already closed", (conn->pcb.tcp != NULL));
|
||||
LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL);
|
||||
|
||||
tpcb = conn->pcb.tcp;
|
||||
shut = conn->current_msg->msg.sd.shut;
|
||||
shut_rx = shut & NETCONN_SHUT_RD;
|
||||
shut_tx = shut & NETCONN_SHUT_WR;
|
||||
@ -799,22 +815,102 @@ lwip_netconn_do_close_internal(struct netconn *conn)
|
||||
tcp_sent(tpcb, NULL);
|
||||
}
|
||||
if (close) {
|
||||
tcp_poll(tpcb, NULL, 4);
|
||||
tcp_poll(tpcb, NULL, 0);
|
||||
tcp_err(tpcb, NULL);
|
||||
}
|
||||
}
|
||||
/* Try to close the connection */
|
||||
if (close) {
|
||||
#if LWIP_SO_LINGER
|
||||
/* check linger possibilites before calling tcp_close */
|
||||
err = ERR_OK;
|
||||
/* linger enabled/required at all? (i.e. is there untransmitted data left?) */
|
||||
if ((conn->linger >= 0) && (conn->pcb.tcp->unsent || conn->pcb.tcp->unacked)) {
|
||||
if ((conn->linger == 0)) {
|
||||
/* data left but linger prevents waiting */
|
||||
tcp_abort(tpcb);
|
||||
tpcb = NULL;
|
||||
} else if (conn->linger > 0) {
|
||||
/* data left and linger says we should wait */
|
||||
if (netconn_is_nonblocking(conn)) {
|
||||
/* data left on a nonblocking netconn -> cannot linger */
|
||||
err = ERR_WOULDBLOCK;
|
||||
} else if ((s32_t)(sys_now() - conn->current_msg->msg.sd.time_started) >=
|
||||
(conn->linger * 1000)) {
|
||||
/* data left but linger timeout has expired (this happens on further
|
||||
calls to this function through poll_tcp */
|
||||
tcp_abort(tpcb);
|
||||
tpcb = NULL;
|
||||
} else {
|
||||
/* data left -> need to wait for ACK after successful close */
|
||||
linger_wait_required = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((err == ERR_OK) && (tpcb != NULL))
|
||||
#endif /* LWIP_SO_LINGER */
|
||||
{
|
||||
err = tcp_close(tpcb);
|
||||
}
|
||||
} else {
|
||||
err = tcp_shutdown(tpcb, shut_rx, shut_tx);
|
||||
}
|
||||
if (err == ERR_OK) {
|
||||
/* Closing succeeded */
|
||||
close_finished = 1;
|
||||
#if LWIP_SO_LINGER
|
||||
if (linger_wait_required) {
|
||||
/* wait for ACK of all unsent/unacked data by just getting called again */
|
||||
close_finished = 0;
|
||||
}
|
||||
#endif /* LWIP_SO_LINGER */
|
||||
} else {
|
||||
if(err == ERR_MEM) {
|
||||
/* Closing failed because of memory shortage */
|
||||
if (netconn_is_nonblocking(conn)) {
|
||||
/* Nonblocking close failed */
|
||||
close_finished = 1;
|
||||
err = ERR_WOULDBLOCK;
|
||||
} else {
|
||||
/* Blocking close, check the timeout */
|
||||
#if LWIP_SO_SNDTIMEO || LWIP_SO_LINGER
|
||||
s32_t close_timeout = LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT;
|
||||
/* this is kind of an lwip addition to the standard sockets: we wait
|
||||
for some time when failing to allocate a segment for the FIN */
|
||||
#if LWIP_SO_SNDTIMEO
|
||||
if (conn->send_timeout >= 0) {
|
||||
close_timeout = conn->send_timeout;
|
||||
}
|
||||
#endif /* LWIP_SO_SNDTIMEO */
|
||||
#if LWIP_SO_LINGER
|
||||
if (conn->linger >= 0) {
|
||||
/* use linger timeout (seconds) */
|
||||
close_timeout = conn->linger * 1000U;
|
||||
}
|
||||
#endif
|
||||
if ((s32_t)(sys_now() - conn->current_msg->msg.sd.time_started) >= close_timeout) {
|
||||
#else /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */
|
||||
if (conn->current_msg->msg.sd.polls_left == 0) {
|
||||
#endif /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */
|
||||
close_finished = 1;
|
||||
if (close) {
|
||||
/* in this case, we want to RST the connection */
|
||||
tcp_abort(tpcb);
|
||||
err = ERR_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* Closing failed for a non-memory error: give up */
|
||||
close_finished = 1;
|
||||
}
|
||||
}
|
||||
if (close_finished) {
|
||||
/* Closing done (succeeded, non-memory error, nonblocking error or timeout) */
|
||||
sys_sem_t* op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg);
|
||||
conn->current_msg->err = ERR_OK;
|
||||
conn->current_msg->err = err;
|
||||
conn->current_msg = NULL;
|
||||
conn->state = NETCONN_NONE;
|
||||
if (err == ERR_OK) {
|
||||
if (close) {
|
||||
/* Set back some callback pointers as conn is going away */
|
||||
conn->pcb.tcp = NULL;
|
||||
@ -828,20 +924,27 @@ lwip_netconn_do_close_internal(struct netconn *conn)
|
||||
if (shut_tx) {
|
||||
API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
|
||||
}
|
||||
}
|
||||
/* wake up the application task */
|
||||
sys_sem_signal(op_completed_sem);
|
||||
} else {
|
||||
/* Closing failed, restore some of the callbacks */
|
||||
return ERR_OK;
|
||||
}
|
||||
if (!close_finished) {
|
||||
/* Closing failed and we want to wait: restore some of the callbacks */
|
||||
/* Closing of listen pcb will never fail! */
|
||||
LWIP_ASSERT("Closing a listen pcb may not fail!", (conn->pcb.tcp->state != LISTEN));
|
||||
tcp_sent(conn->pcb.tcp, sent_tcp);
|
||||
tcp_poll(conn->pcb.tcp, poll_tcp, 4);
|
||||
tcp_err(conn->pcb.tcp, err_tcp);
|
||||
tcp_arg(conn->pcb.tcp, conn);
|
||||
LWIP_ASSERT("Closing a listen pcb may not fail!", (tpcb->state != LISTEN));
|
||||
if (shut_tx) {
|
||||
tcp_sent(tpcb, sent_tcp);
|
||||
}
|
||||
/* when waiting for close, set up poll interval to 500ms */
|
||||
tcp_poll(tpcb, poll_tcp, 1);
|
||||
tcp_err(tpcb, err_tcp);
|
||||
tcp_arg(tpcb, conn);
|
||||
/* don't restore recv callback: we don't want to receive any more data */
|
||||
}
|
||||
/* If closing didn't succeed, we get called again either
|
||||
from poll_tcp or from sent_tcp */
|
||||
return err;
|
||||
}
|
||||
#endif /* LWIP_TCP */
|
||||
|
||||
@ -854,13 +957,12 @@ lwip_netconn_do_close_internal(struct netconn *conn)
|
||||
void
|
||||
lwip_netconn_do_delconn(struct api_msg_msg *msg)
|
||||
{
|
||||
/* @todo TCP: abort running write/connect? */
|
||||
enum netconn_state state = msg->conn->state;
|
||||
LWIP_ASSERT("netconn state error", /* this only happens for TCP netconns */
|
||||
(state == NETCONN_NONE) || (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP));
|
||||
if ((msg->conn->state != NETCONN_NONE) &&
|
||||
(msg->conn->state != NETCONN_LISTEN) &&
|
||||
(msg->conn->state != NETCONN_CONNECT)) {
|
||||
/* this only happens for TCP netconns */
|
||||
LWIP_ASSERT("NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP",
|
||||
NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP);
|
||||
msg->err = ERR_INPROGRESS;
|
||||
} else {
|
||||
LWIP_ASSERT("blocking connect in progress",
|
||||
@ -890,7 +992,17 @@ lwip_netconn_do_delconn(struct api_msg_msg *msg)
|
||||
msg->conn->state = NETCONN_CLOSE;
|
||||
msg->msg.sd.shut = NETCONN_SHUT_RDWR;
|
||||
msg->conn->current_msg = msg;
|
||||
#if LWIP_TCPIP_CORE_LOCKING
|
||||
if (lwip_netconn_do_close_internal(msg->conn) != ERR_OK) {
|
||||
LWIP_ASSERT("state!", msg->conn->state == NETCONN_CLOSE);
|
||||
UNLOCK_TCPIP_CORE();
|
||||
sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0);
|
||||
LOCK_TCPIP_CORE();
|
||||
LWIP_ASSERT("state!", msg->conn->state == NETCONN_NONE);
|
||||
}
|
||||
#else /* LWIP_TCPIP_CORE_LOCKING */
|
||||
lwip_netconn_do_close_internal(msg->conn);
|
||||
#endif /* LWIP_TCPIP_CORE_LOCKING */
|
||||
/* API_EVENT is called inside lwip_netconn_do_close_internal, before releasing
|
||||
the application thread, so we can return at this point! */
|
||||
return;
|
||||
@ -1524,16 +1636,14 @@ void
|
||||
lwip_netconn_do_close(struct api_msg_msg *msg)
|
||||
{
|
||||
#if LWIP_TCP
|
||||
/* @todo: abort running write/connect? */
|
||||
if ((msg->conn->state != NETCONN_NONE) && (msg->conn->state != NETCONN_LISTEN)) {
|
||||
/* this only happens for TCP netconns */
|
||||
LWIP_ASSERT("NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP",
|
||||
NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP);
|
||||
enum netconn_state state = msg->conn->state;
|
||||
/* First check if this is a TCP netconn and if it is in a correct state
|
||||
(LISTEN doesn't support half shutdown) */
|
||||
if ((msg->conn->pcb.tcp != NULL) &&
|
||||
(NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) &&
|
||||
((msg->msg.sd.shut == NETCONN_SHUT_RDWR) || (state != NETCONN_LISTEN))) {
|
||||
if ((state == NETCONN_CONNECT) || (state == NETCONN_WRITE)) {
|
||||
msg->err = ERR_INPROGRESS;
|
||||
} else if ((msg->conn->pcb.tcp != NULL) && (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP)) {
|
||||
if ((msg->msg.sd.shut != NETCONN_SHUT_RDWR) && (msg->conn->state == NETCONN_LISTEN)) {
|
||||
/* LISTEN doesn't support half shutdown */
|
||||
msg->err = ERR_CONN;
|
||||
} else {
|
||||
if (msg->msg.sd.shut & NETCONN_SHUT_RD) {
|
||||
/* Drain and delete mboxes */
|
||||
@ -1543,7 +1653,17 @@ lwip_netconn_do_close(struct api_msg_msg *msg)
|
||||
msg->conn->write_offset == 0);
|
||||
msg->conn->state = NETCONN_CLOSE;
|
||||
msg->conn->current_msg = msg;
|
||||
#if LWIP_TCPIP_CORE_LOCKING
|
||||
if (lwip_netconn_do_close_internal(msg->conn) != ERR_OK) {
|
||||
LWIP_ASSERT("state!", msg->conn->state == NETCONN_CLOSE);
|
||||
UNLOCK_TCPIP_CORE();
|
||||
sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0);
|
||||
LOCK_TCPIP_CORE();
|
||||
LWIP_ASSERT("state!", msg->conn->state == NETCONN_NONE);
|
||||
}
|
||||
#else /* LWIP_TCPIP_CORE_LOCKING */
|
||||
lwip_netconn_do_close_internal(msg->conn);
|
||||
#endif /* LWIP_TCPIP_CORE_LOCKING */
|
||||
/* for tcp netconns, lwip_netconn_do_close_internal ACKs the message */
|
||||
return;
|
||||
}
|
||||
|
@ -558,6 +558,7 @@ lwip_close(int s)
|
||||
{
|
||||
struct lwip_sock *sock;
|
||||
int is_tcp = 0;
|
||||
err_t err;
|
||||
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_close(%d)\n", s));
|
||||
|
||||
@ -572,7 +573,11 @@ lwip_close(int s)
|
||||
LWIP_ASSERT("sock->lastdata == NULL", sock->lastdata == NULL);
|
||||
}
|
||||
|
||||
netconn_delete(sock->conn);
|
||||
err = netconn_delete(sock->conn);
|
||||
if (err != ERR_OK) {
|
||||
sock_set_errno(sock, err_to_errno(err));
|
||||
return -1;
|
||||
}
|
||||
|
||||
free_socket(sock, is_tcp);
|
||||
set_errno(0);
|
||||
@ -1196,9 +1201,6 @@ lwip_selscan(int maxfdp1, fd_set *readset_in, fd_set *writeset_in, fd_set *excep
|
||||
return nready;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processing exceptset is not yet implemented.
|
||||
*/
|
||||
int
|
||||
lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,
|
||||
struct timeval *timeout)
|
||||
@ -1781,6 +1783,23 @@ lwip_getsockopt_impl(int s, int level, int optname, void *optval, socklen_t *opt
|
||||
*(int *)optval = netconn_get_recvbufsize(sock->conn);
|
||||
break;
|
||||
#endif /* LWIP_SO_RCVBUF */
|
||||
#if LWIP_SO_LINGER
|
||||
case SO_LINGER:
|
||||
{
|
||||
s16_t conn_linger;
|
||||
struct linger* linger = (struct linger*)optval;
|
||||
LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, struct linger);
|
||||
conn_linger = sock->conn->linger;
|
||||
if (conn_linger >= 0) {
|
||||
linger->l_onoff = 1;
|
||||
linger->l_linger = (int)conn_linger;
|
||||
} else {
|
||||
linger->l_onoff = 0;
|
||||
linger->l_linger = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif /* LWIP_SO_LINGER */
|
||||
#if LWIP_UDP
|
||||
case SO_NO_CHECK:
|
||||
LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, *optlen, int, NETCONN_UDP);
|
||||
@ -2117,6 +2136,26 @@ lwip_setsockopt_impl(int s, int level, int optname, const void *optval, socklen_
|
||||
netconn_set_recvbufsize(sock->conn, *(int*)optval);
|
||||
break;
|
||||
#endif /* LWIP_SO_RCVBUF */
|
||||
#if LWIP_SO_LINGER
|
||||
case SO_LINGER:
|
||||
{
|
||||
struct linger* linger = (struct linger*)optval;
|
||||
LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, struct linger);
|
||||
if (linger->l_onoff) {
|
||||
int lingersec = linger->l_linger;
|
||||
if (lingersec < 0) {
|
||||
return EINVAL;
|
||||
}
|
||||
if (lingersec > 0xFFFF) {
|
||||
lingersec = 0xFFFF;
|
||||
}
|
||||
sock->conn->linger = (s16_t)lingersec;
|
||||
} else {
|
||||
sock->conn->linger = -1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif /* LWIP_SO_LINGER */
|
||||
#if LWIP_UDP
|
||||
case SO_NO_CHECK:
|
||||
LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_UDP);
|
||||
|
@ -214,6 +214,10 @@ struct netconn {
|
||||
for UDP and RAW, used for FIONREAD */
|
||||
int recv_avail;
|
||||
#endif /* LWIP_SO_RCVBUF */
|
||||
#if LWIP_SO_LINGER
|
||||
/** values <0 mean linger is disabled, values > 0 are seconds to linger */
|
||||
s16_t linger;
|
||||
#endif /* LWIP_SO_LINGER */
|
||||
/** flags holding more netconn-internal state, see NETCONN_FLAG_* defines */
|
||||
u8_t flags;
|
||||
#if LWIP_TCP
|
||||
|
@ -113,6 +113,11 @@ struct api_msg_msg {
|
||||
/** used for lwip_netconn_do_close (/shutdown) */
|
||||
struct {
|
||||
u8_t shut;
|
||||
#if LWIP_SO_SNDTIMEO || LWIP_SO_LINGER
|
||||
u32_t time_started;
|
||||
#else /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */
|
||||
u8_t polls_left;
|
||||
#endif /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */
|
||||
} sd;
|
||||
#if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD)
|
||||
/** used for lwip_netconn_do_join_leave_group */
|
||||
|
@ -1573,6 +1573,13 @@
|
||||
#define LWIP_SO_RCVBUF 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* LWIP_SO_LINGER==1: Enable SO_LINGER processing.
|
||||
*/
|
||||
#ifndef LWIP_SO_LINGER
|
||||
#define LWIP_SO_LINGER 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* If LWIP_SO_RCVBUF is used, this is the default value for recv_bufsize.
|
||||
*/
|
||||
@ -1580,6 +1587,13 @@
|
||||
#define RECV_BUFSIZE_DEFAULT INT_MAX
|
||||
#endif
|
||||
|
||||
/**
|
||||
* By default, TCP socket/netconn close waits 20 seconds max to send the FIN
|
||||
*/
|
||||
#ifndef LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT
|
||||
#define LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT 20000
|
||||
#endif
|
||||
|
||||
/**
|
||||
* SO_REUSE==1: Enable SO_REUSEADDR option.
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user