Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Initial version of TCP_CLOSE_ALWAYS_RETURNS, TCP_DO_NOT_ADD_FIN_TO_RS…
…T, and LWIP_PCB_COMPLETED_BOOKKEEPING

Signed-off-by: Mike Stitt <mikes@spindance.com>
  • Loading branch information
mikes-spindance committed Nov 30, 2014
1 parent 36f4703 commit d2658f1
Show file tree
Hide file tree
Showing 9 changed files with 142 additions and 21 deletions.
1 change: 1 addition & 0 deletions src/api/api_lib.c
Expand Up @@ -81,6 +81,7 @@ netconn_new_with_proto_and_callback(enum netconn_type t, u8_t proto, netconn_cal
err_t err;
API_MSG_VAR_ALLOC_DONTFAIL(msg);
API_MSG_VAR_REF(msg).msg.msg.n.proto = proto;
conn_mark_op_initial(conn);
API_MSG_VAR_REF(msg).msg.conn = conn;
TCPIP_APIMSG(&API_MSG_VAR_REF(msg), lwip_netconn_do_newconn, err);
API_MSG_VAR_FREE(msg);
Expand Down
42 changes: 31 additions & 11 deletions src/api/api_msg.c
Expand Up @@ -397,8 +397,27 @@ err_tcp(void *arg, err_t err)
conn->current_msg->err = err;
conn->current_msg = NULL;
/* wake up the waiting task */
sys_sem_signal(&conn->op_completed);
conn_op_completed(conn);
}
#if LWIP_PCB_COMPLETED_BOOKKEEPING
else if (conn->to_be_completed) {
SET_NONBLOCKING_CONNECT(conn, 0);
/* set error return code */
LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL);
conn->current_msg->err = err;
conn->current_msg = NULL;
/* wake up the waiting task */
conn_op_completed(conn);
}
} else if (conn->to_be_completed) {
SET_NONBLOCKING_CONNECT(conn, 0);
/* set error return code */
LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL);
conn->current_msg->err = err;
conn->current_msg = NULL;
/* wake up the waiting task */
conn_op_completed(conn);
#endif
} else {
LWIP_ASSERT("conn->current_msg == NULL", conn->current_msg == NULL);
}
Expand Down Expand Up @@ -788,9 +807,10 @@ lwip_netconn_do_close_internal(struct netconn *conn)
} else {
err = tcp_shutdown(conn->pcb.tcp, shut_rx, shut_tx);
}
if (err == ERR_OK) {
if ((TCP_CLOSE_ALWAYS_RETURNS)||(err == ERR_OK)) {

/* Closing succeeded */
conn->current_msg->err = ERR_OK;
conn->current_msg->err = err;
conn->current_msg = NULL;
conn->state = NETCONN_NONE;
if (close) {
Expand All @@ -807,7 +827,7 @@ lwip_netconn_do_close_internal(struct netconn *conn)
API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
}
/* wake up the application task */
sys_sem_signal(&conn->op_completed);
conn_op_completed(conn);
} else {
/* Closing failed, restore some of the callbacks */
/* Closing of listen pcb will never fail! */
Expand Down Expand Up @@ -885,7 +905,7 @@ lwip_netconn_do_delconn(struct api_msg_msg *msg)
API_EVENT(msg->conn, NETCONN_EVT_SENDPLUS, 0);
}
if (sys_sem_valid(&msg->conn->op_completed)) {
sys_sem_signal(&msg->conn->op_completed);
conn_op_completed(msg->conn);
}
}

Expand Down Expand Up @@ -969,7 +989,7 @@ lwip_netconn_do_connected(void *arg, struct tcp_pcb *pcb, err_t err)
API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);

if (was_blocking) {
sys_sem_signal(&conn->op_completed);
conn_op_completed(conn);
}
return ERR_OK;
}
Expand All @@ -990,7 +1010,7 @@ lwip_netconn_do_connect(struct api_msg_msg *msg)
msg->err = ERR_CLSD;
if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) {
/* For TCP, netconn_connect() calls tcpip_apimsg(), so signal op_completed here. */
sys_sem_signal(&msg->conn->op_completed);
conn_op_completed(msg->conn);
return;
}
} else {
Expand Down Expand Up @@ -1029,7 +1049,7 @@ lwip_netconn_do_connect(struct api_msg_msg *msg)
}
}
/* For TCP, netconn_connect() calls tcpip_apimsg(), so signal op_completed here. */
sys_sem_signal(&msg->conn->op_completed);
conn_op_completed(msg->conn);
return;
#endif /* LWIP_TCP */
default:
Expand Down Expand Up @@ -1354,7 +1374,7 @@ lwip_netconn_do_writemore(struct netconn *conn)
if ((conn->flags & NETCONN_FLAG_WRITE_DELAYED) != 0)
#endif
{
sys_sem_signal(&conn->op_completed);
conn_op_completed(conn);
}
}
#if LWIP_TCPIP_CORE_LOCKING
Expand Down Expand Up @@ -1395,7 +1415,7 @@ lwip_netconn_do_write(struct api_msg_msg *msg)
if (lwip_netconn_do_writemore(msg->conn) != ERR_OK) {
LWIP_ASSERT("state!", msg->conn->state == NETCONN_WRITE);
UNLOCK_TCPIP_CORE();
sys_arch_sem_wait(&msg->conn->op_completed, 0);
conn_op_wait(msg->conn);
LOCK_TCPIP_CORE();
LWIP_ASSERT("state!", msg->conn->state == NETCONN_NONE);
}
Expand Down Expand Up @@ -1521,7 +1541,7 @@ lwip_netconn_do_close(struct api_msg_msg *msg)
{
msg->err = ERR_VAL;
}
sys_sem_signal(&msg->conn->op_completed);
conn_op_completed(msg->conn);
}

#if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD)
Expand Down
23 changes: 16 additions & 7 deletions src/api/sockets.c
Expand Up @@ -517,11 +517,18 @@ lwip_close(int s)
LWIP_ASSERT("sock->lastdata == NULL", sock->lastdata == NULL);
}

netconn_delete(sock->conn);
int result = netconn_delete(sock->conn);

free_socket(sock, is_tcp);
set_errno(0);
return 0;

#if TCP_CLOSE_ALWAYS_RETURNS
set_errno(result);
return result;
#else
(result);
set_errno(0);
return 0;
#endif
}

int
Expand Down Expand Up @@ -1743,7 +1750,7 @@ lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen)
LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optlen = optlen;
LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).err = err;
tcpip_callback(lwip_getsockopt_internal, &LWIP_SETGETSOCKOPT_DATA_VAR_REF(data));
sys_arch_sem_wait(&sock->conn->op_completed, 0);
conn_op_wait(sock->conn);
/* maybe lwip_getsockopt_internal has changed err */
err = LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).err;
LWIP_SETGETSOCKOPT_DATA_VAR_FREE(data);
Expand All @@ -1767,6 +1774,7 @@ lwip_getsockopt_internal(void *arg)

data = (struct lwip_setgetsockopt_data*)arg;
sock = data->sock;
conn_mark_op_started(sock->conn);
#ifdef LWIP_DEBUG
s = data->s;
#endif /* LWIP_DEBUG */
Expand Down Expand Up @@ -1993,7 +2001,7 @@ lwip_getsockopt_internal(void *arg)
LWIP_ASSERT("unhandled level", 0);
break;
} /* switch (level) */
sys_sem_signal(&sock->conn->op_completed);
conn_op_completed(sock->conn);
}

int
Expand Down Expand Up @@ -2254,7 +2262,7 @@ lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t opt
LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optlen = &optlen;
LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).err = err;
tcpip_callback(lwip_setsockopt_internal, &LWIP_SETGETSOCKOPT_DATA_VAR_REF(data));
sys_arch_sem_wait(&sock->conn->op_completed, 0);
conn_op_wait(sock->conn);
/* maybe lwip_setsockopt_internal has changed err */
err = LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).err;
LWIP_SETGETSOCKOPT_DATA_VAR_FREE(data);
Expand All @@ -2278,6 +2286,7 @@ lwip_setsockopt_internal(void *arg)

data = (struct lwip_setgetsockopt_data*)arg;
sock = data->sock;
conn_mark_op_started(sock->conn);
#ifdef LWIP_DEBUG
s = data->s;
#endif /* LWIP_DEBUG */
Expand Down Expand Up @@ -2510,7 +2519,7 @@ lwip_setsockopt_internal(void *arg)
LWIP_ASSERT("unhandled level", 0);
break;
} /* switch (level) */
sys_sem_signal(&sock->conn->op_completed);
conn_op_completed(sock->conn);
}

int
Expand Down
3 changes: 2 additions & 1 deletion src/api/tcpip.c
Expand Up @@ -102,6 +102,7 @@ tcpip_thread(void *arg)
#if LWIP_NETCONN
case TCPIP_MSG_API:
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: API message %p\n", (void *)msg));
conn_mark_op_started(msg->msg.apimsg->msg.conn);
msg->msg.apimsg->function(&(msg->msg.apimsg->msg));
break;
#endif /* LWIP_NETCONN */
Expand Down Expand Up @@ -339,7 +340,7 @@ tcpip_apimsg(struct api_msg *apimsg)
TCPIP_MSG_VAR_REF(msg).type = TCPIP_MSG_API;
TCPIP_MSG_VAR_REF(msg).msg.apimsg = apimsg;
sys_mbox_post(&mbox, &TCPIP_MSG_VAR_REF(msg));
sys_arch_sem_wait(&apimsg->msg.conn->op_completed, 0);
conn_op_wait(apimsg->msg.conn);
TCPIP_MSG_VAR_FREE(msg);
return apimsg->msg.err;
}
Expand Down
7 changes: 7 additions & 0 deletions src/core/tcp.c
Expand Up @@ -1078,9 +1078,16 @@ tcp_slowtmr(void)
LWIP_ASSERT("tcp_slowtmr: first pcb == tcp_tw_pcbs", tcp_tw_pcbs == pcb);
tcp_tw_pcbs = pcb->next;
}
#if LWIP_PCB_COMPLETED_BOOKKEEPING
tcp_err_fn err_fn = pcb->errf;
void *err_arg = pcb->callback_arg;
#endif
pcb2 = pcb;
pcb = pcb->next;
memp_free(MEMP_TCP_PCB, pcb2);
#if LWIP_PCB_COMPLETED_BOOKKEEPING
TCP_EVENT_ERR(err_fn, err_arg, ERR_ABRT);
#endif
} else {
prev = pcb;
pcb = pcb->next;
Expand Down
7 changes: 7 additions & 0 deletions src/core/tcp_out.c
Expand Up @@ -133,6 +133,13 @@ tcp_send_fin(struct tcp_pcb *pcb)
for (last_unsent = pcb->unsent; last_unsent->next != NULL;
last_unsent = last_unsent->next);

#if TCP_DO_NOT_ADD_FIN_TO_RST
if ((TCPH_FLAGS(last_unsent->tcphdr) & (TCP_RST)) != 0) {
/* already TCP_RST don't try to add a TCP_FIN */
return ERR_OK;
}
#endif

if ((TCPH_FLAGS(last_unsent->tcphdr) & (TCP_SYN | TCP_FIN | TCP_RST)) == 0) {
/* no SYN/FIN/RST flag in the header, we can add the FIN flag */
TCPH_SET_FLAG(last_unsent->tcphdr, TCP_FIN);
Expand Down
4 changes: 4 additions & 0 deletions src/include/lwip/api.h
Expand Up @@ -174,6 +174,10 @@ struct netconn {
err_t last_err;
/** sem that is used to synchronously execute functions in the core context */
sys_sem_t op_completed;
#if LWIP_PCB_COMPLETED_BOOKKEEPING
/** we need to respond back to the application to complete the op */
u8_t to_be_completed;
#endif
/** mbox where received packets are stored until they are fetched
by the netconn application thread (can grow quite big) */
sys_mbox_t recvmbox;
Expand Down
27 changes: 27 additions & 0 deletions src/include/lwip/opt.h
Expand Up @@ -2731,4 +2731,31 @@
#define IP6_DEBUG LWIP_DBG_OFF
#endif

/**
* TCP_CLOSE_ALWAYS_RETURNS==1: To force lwip_close and lwip_shutdown
* to always return. Otherwise lwIP can be deadlocked when it can not allocate
* the buffer space for the FIN to end a message.
*/
#ifndef TCP_CLOSE_ALWAYS_RETURNS
#define TCP_CLOSE_ALWAYS_RETURNS 1
#endif

/**
* TCP_DO_NOT_ADD_FIN_TO_RST==1: When trying to close a connection, if
* we have already set the RST flag don't expend the effort to try to allocate
* a segment to add a RST. Just hang up quietly.
*/
#ifndef TCP_DO_NOT_ADD_FIN_TO_RST
#define TCP_DO_NOT_ADD_FIN_TO_RST 1
#endif

/**
* LWIP should keep track of calling threads that are waiting on
* a call back and return an error to threads that are waiting when the
* pcb is purged.
*/
#ifndef LWIP_PCB_COMPLETED_BOOKKEEPING
#define LWIP_PCB_COMPLETED_BOOKKEEPING 1
#endif

#endif /* LWIP_HDR_OPT_H */
49 changes: 47 additions & 2 deletions src/include/lwip/tcpip.h
Expand Up @@ -55,6 +55,51 @@ extern "C" {
#define LWIP_TCPIP_THREAD_ALIVE()
#endif

static inline void conn_op_wait(struct netconn *conn)
{
sys_arch_sem_wait(&conn->op_completed, 0);
#if LWIP_PCB_COMPLETED_BOOKKEEPING
LWIP_ASSERT("!conn->to_be_completed", !conn->to_be_completed);
#endif
}

static inline void conn_mark_op_initial(struct netconn *conn)
{
#if LWIP_PCB_COMPLETED_BOOKKEEPING
conn->to_be_completed = 0;
#endif
}

static inline void conn_mark_op_started(struct netconn *conn)
{
#if LWIP_PCB_COMPLETED_BOOKKEEPING
LWIP_ASSERT("!conn->to_be_completed", !conn->to_be_completed);
conn->to_be_completed = 1;
#endif
}

static inline void conn_mark_op_completed(struct netconn *conn)
{
#if LWIP_PCB_COMPLETED_BOOKKEEPING
LWIP_ASSERT("conn->to_be_completed", conn->to_be_completed);
conn->to_be_completed = 0;
#endif
}

static inline void conn_op_completed(struct netconn *conn)
{
conn_mark_op_completed(conn);
sys_sem_signal(&conn->op_completed);
}

static inline void tcpip_apimsg_ack_fn(struct api_msg_msg *msg)
{
conn_mark_op_completed(msg->conn);
#if !LWIP_TCPIP_CORE_LOCKING
sys_sem_signal(&msg->conn->op_completed);
#endif
}

#if LWIP_TCPIP_CORE_LOCKING
/** The global semaphore to lock the stack. */
extern sys_mutex_t lock_tcpip_core;
Expand All @@ -75,7 +120,7 @@ extern sys_mutex_t lock_tcpip_core;
TCPIP_APIMSG_NOERR(m,f); \
(e) = (m)->msg.err; \
} while(0)
#define TCPIP_APIMSG_ACK(m)
#define TCPIP_APIMSG_ACK(m) tcpip_apimsg_ack_fn(m)
#define TCPIP_NETIFAPI(m) tcpip_netifapi_lock(m)
#define TCPIP_NETIFAPI_ACK(m)
#define TCPIP_PPPAPI(m) tcpip_pppapi_lock(m)
Expand All @@ -85,7 +130,7 @@ extern sys_mutex_t lock_tcpip_core;
#define UNLOCK_TCPIP_CORE()
#define TCPIP_APIMSG_NOERR(m,f) do { (m)->function = f; tcpip_apimsg(m); } while(0)
#define TCPIP_APIMSG(m,f,e) do { (m)->function = f; (e) = tcpip_apimsg(m); } while(0)
#define TCPIP_APIMSG_ACK(m) sys_sem_signal(&m->conn->op_completed)
#define TCPIP_APIMSG_ACK(m) tcpip_apimsg_ack_fn(m)
#define TCPIP_NETIFAPI(m) tcpip_netifapi(m)
#define TCPIP_NETIFAPI_ACK(m) sys_sem_signal(&m->sem)
#define TCPIP_PPPAPI(m) tcpip_pppapi(m)
Expand Down

0 comments on commit d2658f1

Please sign in to comment.