netconn/sockets: remove fatal error handling, fix asynchronous error handling, ensure data before RST can be received

This commit is contained in:
goldsimon
2017-04-12 12:37:16 +02:00
parent 064044eeae
commit e0a2472706
7 changed files with 285 additions and 225 deletions

View File

@@ -79,15 +79,54 @@ static err_t lwip_netconn_do_close_internal(struct netconn *conn WRITE_DELAYED_
#endif
#if LWIP_TCPIP_CORE_LOCKING
#define TCPIP_APIMSG_ACK(m) NETCONN_SET_SAFE_ERR((m)->conn, (m)->err)
#define TCPIP_APIMSG_ACK(m)
#else /* LWIP_TCPIP_CORE_LOCKING */
#define TCPIP_APIMSG_ACK(m) do { NETCONN_SET_SAFE_ERR((m)->conn, (m)->err); sys_sem_signal(LWIP_API_MSG_SEM(m)); } while(0)
#define TCPIP_APIMSG_ACK(m) do { sys_sem_signal(LWIP_API_MSG_SEM(m)); } while(0)
#endif /* LWIP_TCPIP_CORE_LOCKING */
#if LWIP_TCP
u8_t netconn_aborted;
const u8_t netconn_aborted = 0;
const u8_t netconn_reset = 0;
const u8_t netconn_closed = 0;
#endif /* LWIP_TCP */
/** Translate an error to a unique void* passed via an mbox */
static void*
lwip_netconn_err_to_msg(err_t err)
{
switch(err)
{
case ERR_ABRT:
return LWIP_CONST_CAST(void*, &netconn_aborted);
case ERR_RST:
return LWIP_CONST_CAST(void*, &netconn_reset);
case ERR_CLSD:
return LWIP_CONST_CAST(void*, &netconn_closed);
default:
LWIP_ASSERT("unhandled error", err == ERR_OK);
return NULL;
}
}
int
lwip_netconn_is_err_msg(void *msg, err_t *err)
{
LWIP_ASSERT("err != NULL", err != NULL);
if (msg == &netconn_aborted) {
*err = ERR_ABRT;
return 1;
} else if (msg == &netconn_reset) {
*err = ERR_RST;
return 1;
} else if (msg == &netconn_closed) {
*err = ERR_CLSD;
return 1;
}
return 0;
}
#if LWIP_RAW
/**
* Receive callback function for RAW netconns.
@@ -244,10 +283,12 @@ recv_tcp(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
{
struct netconn *conn;
u16_t len;
void *msg;
LWIP_UNUSED_ARG(pcb);
LWIP_ASSERT("recv_tcp must have a pcb argument", pcb != NULL);
LWIP_ASSERT("recv_tcp must have an argument", arg != NULL);
LWIP_ASSERT("err != ERR_OK unhandled", err == ERR_OK);
conn = (struct netconn *)arg;
if (conn == NULL) {
@@ -267,18 +308,15 @@ recv_tcp(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
using recv_avail since that could break the connection
(data is already ACKed) */
/* don't overwrite fatal errors! */
if (err != ERR_OK) {
NETCONN_SET_SAFE_ERR(conn, err);
}
if (p != NULL) {
msg = p;
len = p->tot_len;
} else {
msg = LWIP_CONST_CAST(void*, &netconn_closed);
len = 0;
}
if (sys_mbox_trypost(&conn->recvmbox, p) != ERR_OK) {
if (sys_mbox_trypost(&conn->recvmbox, msg) != ERR_OK) {
/* don't deallocate p: it is presented to us later again from tcp_fasttmr! */
return ERR_MEM;
} else {
@@ -383,26 +421,26 @@ err_tcp(void *arg, err_t err)
{
struct netconn *conn;
enum netconn_state old_state;
void *mbox_msg;
SYS_ARCH_DECL_PROTECT(lev);
conn = (struct netconn *)arg;
LWIP_ASSERT("conn != NULL", (conn != NULL));
SYS_ARCH_PROTECT(lev);
/* when err is called, the pcb is deallocated, so delete the reference */
conn->pcb.tcp = NULL;
/* store pending error */
conn->pending_err = err;
/* prevent application threads from blocking on 'recvmbox'/'acceptmbox' */
conn->flags |= NETCONN_FLAG_MBOXCLOSED;
/* reset conn->state now before waking up other threads */
old_state = conn->state;
conn->state = NETCONN_NONE;
if (old_state == NETCONN_CLOSE) {
/* RST during close: let close return success & dealloc the netconn */
err = ERR_OK;
NETCONN_SET_SAFE_ERR(conn, ERR_OK);
} else {
/* no check since this is always fatal! */
SYS_ARCH_SET(conn->last_err, err);
}
/* @todo: the type of NETCONN_EVT created should depend on 'old_state' */
SYS_ARCH_UNPROTECT(lev);
/* Notify the user layer about a connection error. Used to signal select. */
API_EVENT(conn, NETCONN_EVT_ERROR, 0);
@@ -411,15 +449,16 @@ err_tcp(void *arg, err_t err)
API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
/* pass NULL-message to recvmbox to wake up pending recv */
mbox_msg = lwip_netconn_err_to_msg(err);
/* pass error message to recvmbox to wake up pending recv */
if (sys_mbox_valid(&conn->recvmbox)) {
/* use trypost to prevent deadlock */
sys_mbox_trypost(&conn->recvmbox, NULL);
sys_mbox_trypost(&conn->recvmbox, mbox_msg);
}
/* pass NULL-message to acceptmbox to wake up pending accept */
/* pass error message to acceptmbox to wake up pending accept */
if (sys_mbox_valid(&conn->acceptmbox)) {
/* use trypost to preven deadlock */
sys_mbox_trypost(&conn->acceptmbox, NULL);
sys_mbox_trypost(&conn->acceptmbox, mbox_msg);
}
if ((old_state == NETCONN_WRITE) || (old_state == NETCONN_CLOSE) ||
@@ -433,13 +472,20 @@ err_tcp(void *arg, err_t err)
sys_sem_t* op_completed_sem;
/* set error return code */
LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL);
conn->current_msg->err = err;
if (old_state == NETCONN_CLOSE) {
/* let close succeed: the connection is closed after all... */
conn->current_msg->err = ERR_OK;
} else {
/* Write and connect fail */
conn->current_msg->err = err;
}
op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg);
LWIP_ASSERT("inavlid op_completed_sem", sys_sem_valid(op_completed_sem));
conn->current_msg = NULL;
/* wake up the waiting task */
NETCONN_SET_SAFE_ERR(conn, err);
sys_sem_signal(op_completed_sem);
} else {
/* @todo: test what happens for error on nonblocking connect */
}
} else {
LWIP_ASSERT("conn->current_msg == NULL", conn->current_msg == NULL);
@@ -487,12 +533,14 @@ accept_function(void *arg, struct tcp_pcb *newpcb, err_t err)
if (newpcb == NULL) {
/* out-of-pcbs during connect: pass on this error to the application */
if (sys_mbox_trypost(&conn->acceptmbox, &netconn_aborted) == ERR_OK) {
if (sys_mbox_trypost(&conn->acceptmbox, lwip_netconn_err_to_msg(ERR_ABRT)) == ERR_OK) {
/* Register event with callback */
API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
}
return ERR_VAL;
}
LWIP_ASSERT("expect newpcb == NULL or err == ERR_OK", err == ERR_OK);
LWIP_UNUSED_ARG(err); /* for LWIP_NOASSERT */
LWIP_DEBUGF(API_MSG_DEBUG, ("accept_function: newpcb->state: %s\n", tcp_debug_state_str(newpcb->state)));
@@ -501,7 +549,7 @@ accept_function(void *arg, struct tcp_pcb *newpcb, err_t err)
newconn = netconn_alloc(conn->type, conn->callback);
if (newconn == NULL) {
/* outof netconns: pass on this error to the application */
if (sys_mbox_trypost(&conn->acceptmbox, &netconn_aborted) == ERR_OK) {
if (sys_mbox_trypost(&conn->acceptmbox, lwip_netconn_err_to_msg(ERR_ABRT)) == ERR_OK) {
/* Register event with callback */
API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
}
@@ -509,9 +557,6 @@ accept_function(void *arg, struct tcp_pcb *newpcb, err_t err)
}
newconn->pcb.tcp = newpcb;
setup_tcp(newconn);
/* no protection: when creating the pcb, the netconn is not yet known
to the application thread */
newconn->last_err = err;
/* handle backlog counter */
tcp_backlog_delayed(newpcb);
@@ -655,7 +700,7 @@ netconn_alloc(enum netconn_type t, netconn_callback callback)
return NULL;
}
conn->last_err = ERR_OK;
conn->pending_err = ERR_OK;
conn->type = t;
conn->pcb.tcp = NULL;
@@ -978,7 +1023,6 @@ lwip_netconn_do_close_internal(struct netconn *conn WRITE_DELAYED_PARAM)
API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
}
}
NETCONN_SET_SAFE_ERR(conn, err);
#if LWIP_TCPIP_CORE_LOCKING
if (delayed)
#endif
@@ -1034,7 +1078,6 @@ lwip_netconn_do_delconn(void *m)
msg->conn->current_msg->err = ERR_CLSD;
msg->conn->current_msg = NULL;
msg->conn->state = NETCONN_NONE;
NETCONN_SET_SAFE_ERR(msg->conn, ERR_CLSD);
sys_sem_signal(op_completed_sem);
}
}
@@ -1118,33 +1161,33 @@ void
lwip_netconn_do_bind(void *m)
{
struct api_msg *msg = (struct api_msg*)m;
err_t err;
if (ERR_IS_FATAL(msg->conn->last_err)) {
msg->err = msg->conn->last_err;
} else {
msg->err = ERR_VAL;
if (msg->conn->pcb.tcp != NULL) {
switch (NETCONNTYPE_GROUP(msg->conn->type)) {
if (msg->conn->pcb.tcp != NULL) {
switch (NETCONNTYPE_GROUP(msg->conn->type)) {
#if LWIP_RAW
case NETCONN_RAW:
msg->err = raw_bind(msg->conn->pcb.raw, API_EXPR_REF(msg->msg.bc.ipaddr));
break;
case NETCONN_RAW:
err = raw_bind(msg->conn->pcb.raw, API_EXPR_REF(msg->msg.bc.ipaddr));
break;
#endif /* LWIP_RAW */
#if LWIP_UDP
case NETCONN_UDP:
msg->err = udp_bind(msg->conn->pcb.udp, API_EXPR_REF(msg->msg.bc.ipaddr), msg->msg.bc.port);
break;
case NETCONN_UDP:
err = udp_bind(msg->conn->pcb.udp, API_EXPR_REF(msg->msg.bc.ipaddr), msg->msg.bc.port);
break;
#endif /* LWIP_UDP */
#if LWIP_TCP
case NETCONN_TCP:
msg->err = tcp_bind(msg->conn->pcb.tcp, API_EXPR_REF(msg->msg.bc.ipaddr), msg->msg.bc.port);
break;
case NETCONN_TCP:
err = tcp_bind(msg->conn->pcb.tcp, API_EXPR_REF(msg->msg.bc.ipaddr), msg->msg.bc.port);
break;
#endif /* LWIP_TCP */
default:
break;
}
default:
err = ERR_VAL;
break;
}
} else {
err = ERR_VAL;
}
msg->err = err;
TCPIP_APIMSG_ACK(msg);
}
@@ -1188,7 +1231,6 @@ lwip_netconn_do_connected(void *arg, struct tcp_pcb *pcb, err_t err)
(!was_blocking && op_completed_sem == NULL));
conn->current_msg = NULL;
conn->state = NETCONN_NONE;
NETCONN_SET_SAFE_ERR(conn, ERR_OK);
API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
if (was_blocking) {
@@ -1209,39 +1251,40 @@ void
lwip_netconn_do_connect(void *m)
{
struct api_msg *msg = (struct api_msg*)m;
err_t err;
if (msg->conn->pcb.tcp == NULL) {
/* This may happen when calling netconn_connect() a second time */
msg->err = ERR_CLSD;
err = ERR_CLSD;
} else {
switch (NETCONNTYPE_GROUP(msg->conn->type)) {
#if LWIP_RAW
case NETCONN_RAW:
msg->err = raw_connect(msg->conn->pcb.raw, API_EXPR_REF(msg->msg.bc.ipaddr));
err = raw_connect(msg->conn->pcb.raw, API_EXPR_REF(msg->msg.bc.ipaddr));
break;
#endif /* LWIP_RAW */
#if LWIP_UDP
case NETCONN_UDP:
msg->err = udp_connect(msg->conn->pcb.udp, API_EXPR_REF(msg->msg.bc.ipaddr), msg->msg.bc.port);
err = udp_connect(msg->conn->pcb.udp, API_EXPR_REF(msg->msg.bc.ipaddr), msg->msg.bc.port);
break;
#endif /* LWIP_UDP */
#if LWIP_TCP
case NETCONN_TCP:
/* Prevent connect while doing any other action. */
if (msg->conn->state == NETCONN_CONNECT) {
msg->err = ERR_ALREADY;
err = ERR_ALREADY;
} else if (msg->conn->state != NETCONN_NONE) {
msg->err = ERR_ISCONN;
err = ERR_ISCONN;
} else {
setup_tcp(msg->conn);
msg->err = tcp_connect(msg->conn->pcb.tcp, API_EXPR_REF(msg->msg.bc.ipaddr),
err = tcp_connect(msg->conn->pcb.tcp, API_EXPR_REF(msg->msg.bc.ipaddr),
msg->msg.bc.port, lwip_netconn_do_connected);
if (msg->err == ERR_OK) {
if (err == ERR_OK) {
u8_t non_blocking = netconn_is_nonblocking(msg->conn);
msg->conn->state = NETCONN_CONNECT;
SET_NONBLOCKING_CONNECT(msg->conn, non_blocking);
if (non_blocking) {
msg->err = ERR_INPROGRESS;
err = ERR_INPROGRESS;
} else {
msg->conn->current_msg = msg;
/* sys_sem_signal() is called from lwip_netconn_do_connected (or err_tcp()),
@@ -1260,10 +1303,11 @@ lwip_netconn_do_connect(void *m)
break;
#endif /* LWIP_TCP */
default:
LWIP_ERROR("Invalid netconn type", 0, do{ msg->err = ERR_VAL; }while(0));
LWIP_ERROR("Invalid netconn type", 0, do{ err = ERR_VAL; }while(0));
break;
}
}
msg->err = err;
/* For all other protocols, netconn_connect() calls TCPIP_APIMSG(),
so use TCPIP_APIMSG_ACK() here. */
TCPIP_APIMSG_ACK(msg);
@@ -1304,76 +1348,76 @@ void
lwip_netconn_do_listen(void *m)
{
struct api_msg *msg = (struct api_msg*)m;
err_t err;
if (ERR_IS_FATAL(msg->conn->last_err)) {
msg->err = msg->conn->last_err;
} else {
msg->err = ERR_CONN;
if (msg->conn->pcb.tcp != NULL) {
if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) {
if (msg->conn->state == NETCONN_NONE) {
struct tcp_pcb* lpcb;
if (msg->conn->pcb.tcp->state != CLOSED) {
/* connection is not closed, cannot listen */
msg->err = ERR_VAL;
} else {
err_t err;
u8_t backlog;
if (msg->conn->pcb.tcp != NULL) {
if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) {
if (msg->conn->state == NETCONN_NONE) {
struct tcp_pcb* lpcb;
if (msg->conn->pcb.tcp->state != CLOSED) {
/* connection is not closed, cannot listen */
err = ERR_VAL;
} else {
u8_t backlog;
#if TCP_LISTEN_BACKLOG
backlog = msg->msg.lb.backlog;
backlog = msg->msg.lb.backlog;
#else /* TCP_LISTEN_BACKLOG */
backlog = TCP_DEFAULT_LISTEN_BACKLOG;
backlog = TCP_DEFAULT_LISTEN_BACKLOG;
#endif /* TCP_LISTEN_BACKLOG */
#if LWIP_IPV4 && LWIP_IPV6
/* "Socket API like" dual-stack support: If IP to listen to is IP6_ADDR_ANY,
* and NETCONN_FLAG_IPV6_V6ONLY is NOT set, use IP_ANY_TYPE to listen
*/
if (ip_addr_cmp(&msg->conn->pcb.ip->local_ip, IP6_ADDR_ANY) &&
(netconn_get_ipv6only(msg->conn) == 0)) {
/* change PCB type to IPADDR_TYPE_ANY */
IP_SET_TYPE_VAL(msg->conn->pcb.tcp->local_ip, IPADDR_TYPE_ANY);
IP_SET_TYPE_VAL(msg->conn->pcb.tcp->remote_ip, IPADDR_TYPE_ANY);
}
/* "Socket API like" dual-stack support: If IP to listen to is IP6_ADDR_ANY,
* and NETCONN_FLAG_IPV6_V6ONLY is NOT set, use IP_ANY_TYPE to listen
*/
if (ip_addr_cmp(&msg->conn->pcb.ip->local_ip, IP6_ADDR_ANY) &&
(netconn_get_ipv6only(msg->conn) == 0)) {
/* change PCB type to IPADDR_TYPE_ANY */
IP_SET_TYPE_VAL(msg->conn->pcb.tcp->local_ip, IPADDR_TYPE_ANY);
IP_SET_TYPE_VAL(msg->conn->pcb.tcp->remote_ip, IPADDR_TYPE_ANY);
}
#endif /* LWIP_IPV4 && LWIP_IPV6 */
lpcb = tcp_listen_with_backlog_and_err(msg->conn->pcb.tcp, backlog, &err);
lpcb = tcp_listen_with_backlog_and_err(msg->conn->pcb.tcp, backlog, &err);
if (lpcb == NULL) {
/* in this case, the old pcb is still allocated */
msg->err = err;
if (lpcb == NULL) {
/* in this case, the old pcb is still allocated */
} else {
/* delete the recvmbox and allocate the acceptmbox */
if (sys_mbox_valid(&msg->conn->recvmbox)) {
/** @todo: should we drain the recvmbox here? */
sys_mbox_free(&msg->conn->recvmbox);
sys_mbox_set_invalid(&msg->conn->recvmbox);
}
err = ERR_OK;
if (!sys_mbox_valid(&msg->conn->acceptmbox)) {
err = sys_mbox_new(&msg->conn->acceptmbox, DEFAULT_ACCEPTMBOX_SIZE);
}
if (err == ERR_OK) {
msg->conn->state = NETCONN_LISTEN;
msg->conn->pcb.tcp = lpcb;
tcp_arg(msg->conn->pcb.tcp, msg->conn);
tcp_accept(msg->conn->pcb.tcp, accept_function);
} else {
/* delete the recvmbox and allocate the acceptmbox */
if (sys_mbox_valid(&msg->conn->recvmbox)) {
/** @todo: should we drain the recvmbox here? */
sys_mbox_free(&msg->conn->recvmbox);
sys_mbox_set_invalid(&msg->conn->recvmbox);
}
msg->err = ERR_OK;
if (!sys_mbox_valid(&msg->conn->acceptmbox)) {
msg->err = sys_mbox_new(&msg->conn->acceptmbox, DEFAULT_ACCEPTMBOX_SIZE);
}
if (msg->err == ERR_OK) {
msg->conn->state = NETCONN_LISTEN;
msg->conn->pcb.tcp = lpcb;
tcp_arg(msg->conn->pcb.tcp, msg->conn);
tcp_accept(msg->conn->pcb.tcp, accept_function);
} else {
/* since the old pcb is already deallocated, free lpcb now */
tcp_close(lpcb);
msg->conn->pcb.tcp = NULL;
}
/* since the old pcb is already deallocated, free lpcb now */
tcp_close(lpcb);
msg->conn->pcb.tcp = NULL;
}
}
} else if (msg->conn->state == NETCONN_LISTEN) {
/* already listening, allow updating of the backlog */
msg->err = ERR_OK;
tcp_backlog_set(msg->conn->pcb.tcp, msg->msg.lb.backlog);
}
} else {
msg->err = ERR_ARG;
} else if (msg->conn->state == NETCONN_LISTEN) {
/* already listening, allow updating of the backlog */
err = ERR_OK;
tcp_backlog_set(msg->conn->pcb.tcp, msg->msg.lb.backlog);
}
else {
err = ERR_CONN;
}
} else {
err = ERR_ARG;
}
} else {
err = ERR_CONN;
}
msg->err = err;
TCPIP_APIMSG_ACK(msg);
}
#endif /* LWIP_TCP */
@@ -1389,18 +1433,16 @@ lwip_netconn_do_send(void *m)
{
struct api_msg *msg = (struct api_msg*)m;
if (ERR_IS_FATAL(msg->conn->last_err)) {
msg->err = msg->conn->last_err;
} else {
msg->err = ERR_CONN;
err_t err = netconn_err(msg->conn);
if (err == ERR_OK) {
if (msg->conn->pcb.tcp != NULL) {
switch (NETCONNTYPE_GROUP(msg->conn->type)) {
#if LWIP_RAW
case NETCONN_RAW:
if (ip_addr_isany(&msg->msg.b->addr) || IP_IS_ANY_TYPE_VAL(msg->msg.b->addr)) {
msg->err = raw_send(msg->conn->pcb.raw, msg->msg.b->p);
err = raw_send(msg->conn->pcb.raw, msg->msg.b->p);
} else {
msg->err = raw_sendto(msg->conn->pcb.raw, msg->msg.b->p, &msg->msg.b->addr);
err = raw_sendto(msg->conn->pcb.raw, msg->msg.b->p, &msg->msg.b->addr);
}
break;
#endif
@@ -1408,27 +1450,31 @@ lwip_netconn_do_send(void *m)
case NETCONN_UDP:
#if LWIP_CHECKSUM_ON_COPY
if (ip_addr_isany(&msg->msg.b->addr) || IP_IS_ANY_TYPE_VAL(msg->msg.b->addr)) {
msg->err = udp_send_chksum(msg->conn->pcb.udp, msg->msg.b->p,
err = udp_send_chksum(msg->conn->pcb.udp, msg->msg.b->p,
msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum);
} else {
msg->err = udp_sendto_chksum(msg->conn->pcb.udp, msg->msg.b->p,
err = udp_sendto_chksum(msg->conn->pcb.udp, msg->msg.b->p,
&msg->msg.b->addr, msg->msg.b->port,
msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum);
}
#else /* LWIP_CHECKSUM_ON_COPY */
if (ip_addr_isany_val(msg->msg.b->addr) || IP_IS_ANY_TYPE_VAL(msg->msg.b->addr)) {
msg->err = udp_send(msg->conn->pcb.udp, msg->msg.b->p);
err = udp_send(msg->conn->pcb.udp, msg->msg.b->p);
} else {
msg->err = udp_sendto(msg->conn->pcb.udp, msg->msg.b->p, &msg->msg.b->addr, msg->msg.b->port);
err = udp_sendto(msg->conn->pcb.udp, msg->msg.b->p, &msg->msg.b->addr, msg->msg.b->port);
}
#endif /* LWIP_CHECKSUM_ON_COPY */
break;
#endif /* LWIP_UDP */
default:
err = ERR_CONN;
break;
}
} else {
err = ERR_CONN;
}
}
msg->err = err;
TCPIP_APIMSG_ACK(msg);
}
@@ -1601,8 +1647,8 @@ err_mem:
write_finished = 1;
}
out_err = tcp_output(conn->pcb.tcp);
if (ERR_IS_FATAL(out_err) || (out_err == ERR_RTE)) {
/* If tcp_output fails with fatal error or no route is found,
if (out_err == ERR_RTE) {
/* If tcp_output fails because no route is found,
don't try writing any more but return the error
to the application thread. */
err = out_err;
@@ -1616,8 +1662,8 @@ err_mem:
/* tcp_write returned ERR_MEM, try tcp_output anyway */
err_t out_err = tcp_output(conn->pcb.tcp);
if (ERR_IS_FATAL(out_err) || (out_err == ERR_RTE)) {
/* If tcp_output fails with fatal error or no route is found,
if (out_err == ERR_RTE) {
/* If tcp_output fails because no route is found,
don't try writing any more but return the error
to the application thread. */
err = out_err;
@@ -1641,7 +1687,6 @@ err_mem:
conn->current_msg->err = err;
conn->current_msg = NULL;
conn->state = NETCONN_NONE;
NETCONN_SET_SAFE_ERR(conn, err);
#if LWIP_TCPIP_CORE_LOCKING
if (delayed)
#endif
@@ -1669,14 +1714,13 @@ lwip_netconn_do_write(void *m)
{
struct api_msg *msg = (struct api_msg*)m;
if (ERR_IS_FATAL(msg->conn->last_err)) {
msg->err = msg->conn->last_err;
} else {
err_t err = netconn_err(msg->conn);
if (err == ERR_OK) {
if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) {
#if LWIP_TCP
if (msg->conn->state != NETCONN_NONE) {
/* netconn is connecting, closing or in blocking write */
msg->err = ERR_INPROGRESS;
err = ERR_INPROGRESS;
} else if (msg->conn->pcb.tcp != NULL) {
msg->conn->state = NETCONN_WRITE;
/* set all the variables used by lwip_netconn_do_writemore */
@@ -1698,17 +1742,18 @@ lwip_netconn_do_write(void *m)
since lwip_netconn_do_writemore ACKs it! */
return;
} else {
msg->err = ERR_CONN;
err = ERR_CONN;
}
#else /* LWIP_TCP */
msg->err = ERR_VAL;
err = ERR_VAL;
#endif /* LWIP_TCP */
#if (LWIP_UDP || LWIP_RAW)
} else {
msg->err = ERR_VAL;
err = ERR_VAL;
#endif /* (LWIP_UDP || LWIP_RAW) */
}
}
msg->err = err;
TCPIP_APIMSG_ACK(msg);
}
@@ -1812,7 +1857,6 @@ lwip_netconn_do_close(void *m)
msg->conn->current_msg = NULL;
msg->conn->state = NETCONN_NONE;
state = NETCONN_NONE;
NETCONN_SET_SAFE_ERR(msg->conn, ERR_CLSD);
sys_sem_signal(write_completed_sem);
} else {
LWIP_ASSERT("msg->msg.sd.shut == NETCONN_SHUT_RD", msg->msg.sd.shut == NETCONN_SHUT_RD);
@@ -1867,43 +1911,38 @@ lwip_netconn_do_join_leave_group(void *m)
{
struct api_msg *msg = (struct api_msg*)m;
if (ERR_IS_FATAL(msg->conn->last_err)) {
msg->err = msg->conn->last_err;
} else {
if (msg->conn->pcb.tcp != NULL) {
if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) {
msg->err = ERR_CONN;
if (msg->conn->pcb.tcp != NULL) {
if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) {
#if LWIP_UDP
#if LWIP_IPV6 && LWIP_IPV6_MLD
if (NETCONNTYPE_ISIPV6(msg->conn->type)) {
if (msg->msg.jl.join_or_leave == NETCONN_JOIN) {
msg->err = mld6_joingroup(ip_2_ip6(API_EXPR_REF(msg->msg.jl.netif_addr)),
ip_2_ip6(API_EXPR_REF(msg->msg.jl.multiaddr)));
} else {
msg->err = mld6_leavegroup(ip_2_ip6(API_EXPR_REF(msg->msg.jl.netif_addr)),
ip_2_ip6(API_EXPR_REF(msg->msg.jl.multiaddr)));
}
if (NETCONNTYPE_ISIPV6(msg->conn->type)) {
if (msg->msg.jl.join_or_leave == NETCONN_JOIN) {
msg->err = mld6_joingroup(ip_2_ip6(API_EXPR_REF(msg->msg.jl.netif_addr)),
ip_2_ip6(API_EXPR_REF(msg->msg.jl.multiaddr)));
} else {
msg->err = mld6_leavegroup(ip_2_ip6(API_EXPR_REF(msg->msg.jl.netif_addr)),
ip_2_ip6(API_EXPR_REF(msg->msg.jl.multiaddr)));
}
else
}
else
#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
{
{
#if LWIP_IGMP
if (msg->msg.jl.join_or_leave == NETCONN_JOIN) {
msg->err = igmp_joingroup(ip_2_ip4(API_EXPR_REF(msg->msg.jl.netif_addr)),
ip_2_ip4(API_EXPR_REF(msg->msg.jl.multiaddr)));
} else {
msg->err = igmp_leavegroup(ip_2_ip4(API_EXPR_REF(msg->msg.jl.netif_addr)),
ip_2_ip4(API_EXPR_REF(msg->msg.jl.multiaddr)));
}
#endif /* LWIP_IGMP */
if (msg->msg.jl.join_or_leave == NETCONN_JOIN) {
msg->err = igmp_joingroup(ip_2_ip4(API_EXPR_REF(msg->msg.jl.netif_addr)),
ip_2_ip4(API_EXPR_REF(msg->msg.jl.multiaddr)));
} else {
msg->err = igmp_leavegroup(ip_2_ip4(API_EXPR_REF(msg->msg.jl.netif_addr)),
ip_2_ip4(API_EXPR_REF(msg->msg.jl.multiaddr)));
}
#endif /* LWIP_IGMP */
}
#endif /* LWIP_UDP */
#if (LWIP_TCP || LWIP_RAW)
} else {
msg->err = ERR_VAL;
#endif /* (LWIP_TCP || LWIP_RAW) */
}
} else {
msg->err = ERR_CONN;
msg->err = ERR_VAL;
#endif /* (LWIP_TCP || LWIP_RAW) */
}
}
TCPIP_APIMSG_ACK(msg);