task #10102: "netconn: clean up conn->err threading issues" by adding error return value to struct api_msg_msg

This commit is contained in:
goldsimon 2010-01-17 18:28:56 +00:00
parent 3e1cca65bd
commit 34139606ca
5 changed files with 277 additions and 179 deletions

View File

@ -52,7 +52,8 @@ HISTORY
2010-01-17: Simon Goldschmidt 2010-01-17: Simon Goldschmidt
* api_lib.c, api_msg.c, (api_msg.h, api.h, sockets.c, tcpip.c): * api_lib.c, api_msg.c, (api_msg.h, api.h, sockets.c, tcpip.c):
task #10102: Netconn: clean up conn->err threading issues task #10102: "netconn: clean up conn->err threading issues" by adding
error return value to struct api_msg_msg
2010-01-17: Simon Goldschmidt 2010-01-17: Simon Goldschmidt
* api.h, api_lib.c, sockets.c: Changed netconn_recv() and netconn_accept() * api.h, api_lib.c, sockets.c: Changed netconn_recv() and netconn_accept()

View File

@ -71,13 +71,11 @@ netconn_new_with_proto_and_callback(enum netconn_type t, u8_t proto, netconn_cal
struct api_msg msg; struct api_msg msg;
conn = netconn_alloc(t, callback); conn = netconn_alloc(t, callback);
if (conn != NULL ) { if (conn != NULL) {
msg.function = do_newconn; msg.function = do_newconn;
msg.msg.msg.n.proto = proto; msg.msg.msg.n.proto = proto;
msg.msg.conn = conn; msg.msg.conn = conn;
TCPIP_APIMSG(&msg); if (TCPIP_APIMSG(&msg) != ERR_OK) {
if (conn->err != ERR_OK) {
LWIP_ASSERT("freeing conn without freeing pcb", conn->pcb.tcp == NULL); LWIP_ASSERT("freeing conn without freeing pcb", conn->pcb.tcp == NULL);
LWIP_ASSERT("conn has no op_completed", conn->op_completed != SYS_SEM_NULL); LWIP_ASSERT("conn has no op_completed", conn->op_completed != SYS_SEM_NULL);
LWIP_ASSERT("conn has no recvmbox", conn->recvmbox != SYS_MBOX_NULL); LWIP_ASSERT("conn has no recvmbox", conn->recvmbox != SYS_MBOX_NULL);
@ -116,6 +114,8 @@ netconn_delete(struct netconn *conn)
conn->pcb.tcp = NULL; conn->pcb.tcp = NULL;
netconn_free(conn); netconn_free(conn);
/* don't care for return value of do_delconn since it only calls void functions */
return ERR_OK; return ERR_OK;
} }
@ -134,6 +134,7 @@ err_t
netconn_getaddr(struct netconn *conn, struct ip_addr *addr, u16_t *port, u8_t local) netconn_getaddr(struct netconn *conn, struct ip_addr *addr, u16_t *port, u8_t local)
{ {
struct api_msg msg; struct api_msg msg;
err_t err;
LWIP_ERROR("netconn_getaddr: invalid conn", (conn != NULL), return ERR_ARG;); LWIP_ERROR("netconn_getaddr: invalid conn", (conn != NULL), return ERR_ARG;);
LWIP_ERROR("netconn_getaddr: invalid addr", (addr != NULL), return ERR_ARG;); LWIP_ERROR("netconn_getaddr: invalid addr", (addr != NULL), return ERR_ARG;);
@ -144,9 +145,10 @@ netconn_getaddr(struct netconn *conn, struct ip_addr *addr, u16_t *port, u8_t lo
msg.msg.msg.ad.ipaddr = addr; msg.msg.msg.ad.ipaddr = addr;
msg.msg.msg.ad.port = port; msg.msg.msg.ad.port = port;
msg.msg.msg.ad.local = local; msg.msg.msg.ad.local = local;
TCPIP_APIMSG(&msg); err = TCPIP_APIMSG(&msg);
return conn->err; NETCONN_SET_SAFE_ERR(conn, err);
return err;
} }
/** /**
@ -163,6 +165,7 @@ err_t
netconn_bind(struct netconn *conn, struct ip_addr *addr, u16_t port) netconn_bind(struct netconn *conn, struct ip_addr *addr, u16_t port)
{ {
struct api_msg msg; struct api_msg msg;
err_t err;
LWIP_ERROR("netconn_bind: invalid conn", (conn != NULL), return ERR_ARG;); LWIP_ERROR("netconn_bind: invalid conn", (conn != NULL), return ERR_ARG;);
@ -170,8 +173,10 @@ netconn_bind(struct netconn *conn, struct ip_addr *addr, u16_t port)
msg.msg.conn = conn; msg.msg.conn = conn;
msg.msg.msg.bc.ipaddr = addr; msg.msg.msg.bc.ipaddr = addr;
msg.msg.msg.bc.port = port; msg.msg.msg.bc.port = port;
TCPIP_APIMSG(&msg); err = TCPIP_APIMSG(&msg);
return conn->err;
NETCONN_SET_SAFE_ERR(conn, err);
return err;
} }
/** /**
@ -186,6 +191,7 @@ err_t
netconn_connect(struct netconn *conn, struct ip_addr *addr, u16_t port) netconn_connect(struct netconn *conn, struct ip_addr *addr, u16_t port)
{ {
struct api_msg msg; struct api_msg msg;
err_t err;
LWIP_ERROR("netconn_connect: invalid conn", (conn != NULL), return ERR_ARG;); LWIP_ERROR("netconn_connect: invalid conn", (conn != NULL), return ERR_ARG;);
@ -194,8 +200,10 @@ netconn_connect(struct netconn *conn, struct ip_addr *addr, u16_t port)
msg.msg.msg.bc.ipaddr = addr; msg.msg.msg.bc.ipaddr = addr;
msg.msg.msg.bc.port = port; msg.msg.msg.bc.port = port;
/* This is the only function which need to not block tcpip_thread */ /* This is the only function which need to not block tcpip_thread */
tcpip_apimsg(&msg); err = tcpip_apimsg(&msg);
return conn->err;
NETCONN_SET_SAFE_ERR(conn, err);
return err;
} }
/** /**
@ -208,13 +216,16 @@ err_t
netconn_disconnect(struct netconn *conn) netconn_disconnect(struct netconn *conn)
{ {
struct api_msg msg; struct api_msg msg;
err_t err;
LWIP_ERROR("netconn_disconnect: invalid conn", (conn != NULL), return ERR_ARG;); LWIP_ERROR("netconn_disconnect: invalid conn", (conn != NULL), return ERR_ARG;);
msg.function = do_disconnect; msg.function = do_disconnect;
msg.msg.conn = conn; msg.msg.conn = conn;
TCPIP_APIMSG(&msg); err = TCPIP_APIMSG(&msg);
return conn->err;
NETCONN_SET_SAFE_ERR(conn, err);
return err;
} }
/** /**
@ -229,6 +240,7 @@ err_t
netconn_listen_with_backlog(struct netconn *conn, u8_t backlog) netconn_listen_with_backlog(struct netconn *conn, u8_t backlog)
{ {
struct api_msg msg; struct api_msg msg;
err_t err;
/* This does no harm. If TCP_LISTEN_BACKLOG is off, backlog is unused. */ /* This does no harm. If TCP_LISTEN_BACKLOG is off, backlog is unused. */
LWIP_UNUSED_ARG(backlog); LWIP_UNUSED_ARG(backlog);
@ -240,8 +252,10 @@ netconn_listen_with_backlog(struct netconn *conn, u8_t backlog)
#if TCP_LISTEN_BACKLOG #if TCP_LISTEN_BACKLOG
msg.msg.msg.lb.backlog = backlog; msg.msg.msg.lb.backlog = backlog;
#endif /* TCP_LISTEN_BACKLOG */ #endif /* TCP_LISTEN_BACKLOG */
TCPIP_APIMSG(&msg); err = TCPIP_APIMSG(&msg);
return conn->err;
NETCONN_SET_SAFE_ERR(conn, err);
return err;
} }
/** /**
@ -256,17 +270,26 @@ err_t
netconn_accept(struct netconn *conn, struct netconn **new_conn) netconn_accept(struct netconn *conn, struct netconn **new_conn)
{ {
struct netconn *newconn; struct netconn *newconn;
err_t err;
#if TCP_LISTEN_BACKLOG #if TCP_LISTEN_BACKLOG
struct api_msg msg; struct api_msg msg;
#endif /* TCP_LISTEN_BACKLOG */ #endif /* TCP_LISTEN_BACKLOG */
LWIP_ERROR("netconn_accept: invalid pointer", (new_conn != NULL), return ERR_ARG;);
*new_conn = NULL;
LWIP_ERROR("netconn_accept: invalid conn", (conn != NULL), return ERR_ARG;); LWIP_ERROR("netconn_accept: invalid conn", (conn != NULL), return ERR_ARG;);
LWIP_ERROR("netconn_accept: invalid acceptmbox", (conn->acceptmbox != SYS_MBOX_NULL), return ERR_ARG;); LWIP_ERROR("netconn_accept: invalid acceptmbox", (conn->acceptmbox != SYS_MBOX_NULL), return ERR_ARG;);
LWIP_ERROR("netconn_accept: invalid pointer", (new_conn != NULL), return ERR_ARG;);
*new_conn = NULL; err = conn->last_err;
if (ERR_IS_FATAL(err)) {
/* don't recv on fatal errors: this might block the application task
waiting on acceptmbox forever! */
return err;
}
#if LWIP_SO_RCVTIMEO #if LWIP_SO_RCVTIMEO
if (sys_arch_mbox_fetch(conn->acceptmbox, (void *)&newconn, conn->recv_timeout) == SYS_ARCH_TIMEOUT) { if (sys_arch_mbox_fetch(conn->acceptmbox, (void *)&newconn, conn->recv_timeout) == SYS_ARCH_TIMEOUT) {
NETCONN_SET_SAFE_ERR(conn, ERR_TIMEOUT);
return ERR_TIMEOUT; return ERR_TIMEOUT;
} }
#else #else
@ -277,16 +300,19 @@ netconn_accept(struct netconn *conn, struct netconn **new_conn)
if (newconn == NULL) { if (newconn == NULL) {
/* connection has been closed */ /* connection has been closed */
NETCONN_SET_SAFE_ERR(conn, ERR_CLSD);
return ERR_CLSD; return ERR_CLSD;
} }
#if TCP_LISTEN_BACKLOG #if TCP_LISTEN_BACKLOG
/* Let the stack know that we have accepted the connection. */ /* Let the stack know that we have accepted the connection. */
msg.function = do_recv; msg.function = do_recv;
msg.msg.conn = conn; msg.msg.conn = conn;
/* don't care for the return value of do_recv */
TCPIP_APIMSG(&msg); TCPIP_APIMSG(&msg);
#endif /* TCP_LISTEN_BACKLOG */ #endif /* TCP_LISTEN_BACKLOG */
*new_conn = newconn; *new_conn = newconn;
/* don't set conn->last_err: it's only ERR_OK, anyway */
return ERR_OK; return ERR_OK;
} }
@ -305,18 +331,18 @@ netconn_recv(struct netconn *conn, struct netbuf **new_buf)
struct netbuf *buf = NULL; struct netbuf *buf = NULL;
struct pbuf *p; struct pbuf *p;
u16_t len; u16_t len;
err_t err;
LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL), return ERR_ARG;);
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;
if (conn->recvmbox == SYS_MBOX_NULL) { LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL), return ERR_ARG;);
/* TCP listen conns don't have a recvmbox! */ LWIP_ERROR("netconn_accept: invalid recvmbox", (conn->recvmbox != SYS_MBOX_NULL), return ERR_CONN;);
return ERR_CONN;
}
if (ERR_IS_FATAL(conn->err)) { err = conn->last_err;
return conn->err; if (ERR_IS_FATAL(err)) {
/* don't recv on fatal errors: this might block the application task
waiting on recvmbox forever! */
return err;
} }
if (conn->type == NETCONN_TCP) { if (conn->type == NETCONN_TCP) {
@ -325,14 +351,14 @@ netconn_recv(struct netconn *conn, struct netbuf **new_buf)
buf = memp_malloc(MEMP_NETBUF); buf = memp_malloc(MEMP_NETBUF);
if (buf == NULL) { if (buf == NULL) {
conn->err = ERR_MEM; NETCONN_SET_SAFE_ERR(conn, ERR_MEM);
return ERR_MEM; return ERR_MEM;
} }
#if LWIP_SO_RCVTIMEO #if LWIP_SO_RCVTIMEO
if (sys_arch_mbox_fetch(conn->recvmbox, (void *)&p, conn->recv_timeout)==SYS_ARCH_TIMEOUT) { if (sys_arch_mbox_fetch(conn->recvmbox, (void *)&p, conn->recv_timeout)==SYS_ARCH_TIMEOUT) {
memp_free(MEMP_NETBUF, buf); memp_free(MEMP_NETBUF, buf);
conn->err = ERR_TIMEOUT; NETCONN_SET_SAFE_ERR(conn, ERR_TIMEOUT);
return ERR_TIMEOUT; return ERR_TIMEOUT;
} }
#else #else
@ -354,9 +380,7 @@ netconn_recv(struct netconn *conn, struct netbuf **new_buf)
if (p == NULL) { if (p == NULL) {
memp_free(MEMP_NETBUF, buf); memp_free(MEMP_NETBUF, buf);
/* Avoid to lose any previous error code */ /* Avoid to lose any previous error code */
if (conn->err == ERR_OK) { NETCONN_SET_SAFE_ERR(conn, ERR_CLSD);
conn->err = ERR_CLSD;
}
return ERR_CLSD; return ERR_CLSD;
} }
@ -375,13 +399,14 @@ netconn_recv(struct netconn *conn, struct netbuf **new_buf)
} else { } else {
msg.msg.msg.r.len = 1; msg.msg.msg.r.len = 1;
} }
/* don't care for the return value of do_recv */
TCPIP_APIMSG(&msg); TCPIP_APIMSG(&msg);
#endif /* LWIP_TCP */ #endif /* LWIP_TCP */
} else { } else {
#if (LWIP_UDP || LWIP_RAW) #if (LWIP_UDP || LWIP_RAW)
#if LWIP_SO_RCVTIMEO #if LWIP_SO_RCVTIMEO
if (sys_arch_mbox_fetch(conn->recvmbox, (void *)&buf, conn->recv_timeout)==SYS_ARCH_TIMEOUT) { if (sys_arch_mbox_fetch(conn->recvmbox, (void *)&buf, conn->recv_timeout)==SYS_ARCH_TIMEOUT) {
conn->err = ERR_TIMEOUT; NETCONN_SET_SAFE_ERR(conn, ERR_TIMEOUT);
return ERR_TIMEOUT; return ERR_TIMEOUT;
} }
#else #else
@ -399,6 +424,7 @@ netconn_recv(struct netconn *conn, struct netbuf **new_buf)
LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_recv: received %p\n", (void *)buf)); LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_recv: received %p\n", (void *)buf));
*new_buf = buf; *new_buf = buf;
/* don't set conn->last_err: it's only ERR_OK, anyway */
return ERR_OK; return ERR_OK;
} }
@ -434,6 +460,7 @@ err_t
netconn_send(struct netconn *conn, struct netbuf *buf) netconn_send(struct netconn *conn, struct netbuf *buf)
{ {
struct api_msg msg; struct api_msg msg;
err_t err;
LWIP_ERROR("netconn_send: invalid conn", (conn != NULL), return ERR_ARG;); LWIP_ERROR("netconn_send: invalid conn", (conn != NULL), return ERR_ARG;);
@ -441,8 +468,10 @@ netconn_send(struct netconn *conn, struct netbuf *buf)
msg.function = do_send; msg.function = do_send;
msg.msg.conn = conn; msg.msg.conn = conn;
msg.msg.msg.b = buf; msg.msg.msg.b = buf;
TCPIP_APIMSG(&msg); err = TCPIP_APIMSG(&msg);
return conn->err;
NETCONN_SET_SAFE_ERR(conn, err);
return err;
} }
/** /**
@ -460,6 +489,7 @@ err_t
netconn_write(struct netconn *conn, const void *dataptr, size_t size, u8_t apiflags) netconn_write(struct netconn *conn, const void *dataptr, size_t size, u8_t apiflags)
{ {
struct api_msg msg; struct api_msg msg;
err_t err;
LWIP_ERROR("netconn_write: invalid conn", (conn != NULL), return ERR_ARG;); LWIP_ERROR("netconn_write: invalid conn", (conn != NULL), return ERR_ARG;);
LWIP_ERROR("netconn_write: invalid conn->type", (conn->type == NETCONN_TCP), return ERR_VAL;); LWIP_ERROR("netconn_write: invalid conn->type", (conn->type == NETCONN_TCP), return ERR_VAL;);
@ -472,8 +502,10 @@ netconn_write(struct netconn *conn, const void *dataptr, size_t size, u8_t apifl
/* For locking the core: this _can_ be delayed on low memory/low send buffer, /* For locking the core: this _can_ be delayed on low memory/low send buffer,
but if it is, this is done inside api_msg.c:do_write(), so we can use the but if it is, this is done inside api_msg.c:do_write(), so we can use the
non-blocking version here. */ non-blocking version here. */
TCPIP_APIMSG(&msg); err = TCPIP_APIMSG(&msg);
return conn->err;
NETCONN_SET_SAFE_ERR(conn, err);
return err;
} }
/** /**
@ -486,13 +518,18 @@ err_t
netconn_close(struct netconn *conn) netconn_close(struct netconn *conn)
{ {
struct api_msg msg; struct api_msg msg;
err_t err;
LWIP_ERROR("netconn_close: invalid conn", (conn != NULL), return ERR_ARG;); LWIP_ERROR("netconn_close: invalid conn", (conn != NULL), return ERR_ARG;);
msg.function = do_close; msg.function = do_close;
msg.msg.conn = conn; msg.msg.conn = conn;
tcpip_apimsg(&msg); /* because of the LWIP_TCPIP_CORE_LOCKING implementation of do_close,
return conn->err; don't use TCPIP_APIMSG here */
err = tcpip_apimsg(&msg);
NETCONN_SET_SAFE_ERR(conn, err);
return err;
} }
#if LWIP_IGMP #if LWIP_IGMP
@ -513,6 +550,7 @@ netconn_join_leave_group(struct netconn *conn,
enum netconn_igmp join_or_leave) enum netconn_igmp join_or_leave)
{ {
struct api_msg msg; struct api_msg msg;
err_t err;
LWIP_ERROR("netconn_join_leave_group: invalid conn", (conn != NULL), return ERR_ARG;); LWIP_ERROR("netconn_join_leave_group: invalid conn", (conn != NULL), return ERR_ARG;);
@ -521,8 +559,10 @@ netconn_join_leave_group(struct netconn *conn,
msg.msg.msg.jl.multiaddr = multiaddr; msg.msg.msg.jl.multiaddr = multiaddr;
msg.msg.msg.jl.interface = interface; msg.msg.msg.jl.interface = interface;
msg.msg.msg.jl.join_or_leave = join_or_leave; msg.msg.msg.jl.join_or_leave = join_or_leave;
TCPIP_APIMSG(&msg); err = TCPIP_APIMSG(&msg);
return conn->err;
NETCONN_SET_SAFE_ERR(conn, err);
return err;
} }
#endif /* LWIP_IGMP */ #endif /* LWIP_IGMP */

View File

@ -221,7 +221,9 @@ recv_tcp(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
return ERR_OK; return ERR_OK;
} }
conn->err = err; /* don't overwrite fatal errors! */
NETCONN_SET_SAFE_ERR(conn, err);
if (p != NULL) { if (p != NULL) {
len = p->tot_len; len = p->tot_len;
SYS_ARCH_INC(conn->recv_avail, len); SYS_ARCH_INC(conn->recv_avail, len);
@ -309,33 +311,43 @@ static void
err_tcp(void *arg, err_t err) err_tcp(void *arg, err_t err)
{ {
struct netconn *conn; struct netconn *conn;
enum netconn_state old_state;
conn = arg; conn = arg;
LWIP_ASSERT("conn != NULL", (conn != NULL)); LWIP_ASSERT("conn != NULL", (conn != NULL));
conn->pcb.tcp = NULL; conn->pcb.tcp = NULL;
conn->err = err; /* no protection since this is always fatal */
conn->last_err = err;
/* API_EVENT might call tcp_tmr, so reset conn->state now */
old_state = conn->state;
conn->state = NETCONN_NONE;
if (conn->recvmbox != SYS_MBOX_NULL) { if (conn->recvmbox != SYS_MBOX_NULL) {
/* Register event with callback */ /* Register event with callback */
API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
sys_mbox_post(conn->recvmbox, NULL); sys_mbox_post(conn->recvmbox, NULL);
} }
if (conn->op_completed != SYS_SEM_NULL && conn->state == NETCONN_CONNECT) {
conn->state = NETCONN_NONE;
sys_sem_signal(conn->op_completed);
}
if (conn->acceptmbox != SYS_MBOX_NULL) { if (conn->acceptmbox != SYS_MBOX_NULL) {
/* Register event with callback */ /* Register event with callback */
API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
sys_mbox_post(conn->acceptmbox, NULL); sys_mbox_post(conn->acceptmbox, NULL);
} }
if ((conn->state == NETCONN_WRITE) || (conn->state == NETCONN_CLOSE)) { if ((old_state == NETCONN_WRITE) || (old_state == NETCONN_CLOSE) ||
(old_state == NETCONN_CONNECT)) {
/* calling do_writemore/do_close_internal is not necessary /* calling do_writemore/do_close_internal is not necessary
since the pcb has already been deleted! */ since the pcb has already been deleted! */
conn->state = NETCONN_NONE;
/* 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 */ /* wake up the waiting task */
sys_sem_signal(conn->op_completed); sys_sem_signal(conn->op_completed);
} else {
LWIP_ASSERT("conn->current_msg == NULL", conn->current_msg == NULL);
} }
} }
@ -390,7 +402,9 @@ accept_function(void *arg, struct tcp_pcb *newpcb, err_t err)
} }
newconn->pcb.tcp = newpcb; newconn->pcb.tcp = newpcb;
setup_tcp(newconn); setup_tcp(newconn);
newconn->err = err; /* no protection: when creating the pcb, the netconn is not yet known
to the application thread */
newconn->last_err = err;
if (sys_mbox_trypost(conn->acceptmbox, newconn) != ERR_OK) { if (sys_mbox_trypost(conn->acceptmbox, newconn) != ERR_OK) {
/* When returning != ERR_OK, the connection is aborted in tcp_process(), /* When returning != ERR_OK, the connection is aborted in tcp_process(),
@ -417,60 +431,56 @@ accept_function(void *arg, struct tcp_pcb *newpcb, err_t err)
* @param msg the api_msg_msg describing the connection type * @param msg the api_msg_msg describing the connection type
* @return msg->conn->err, but the return value is currently ignored * @return msg->conn->err, but the return value is currently ignored
*/ */
static err_t static void
pcb_new(struct api_msg_msg *msg) pcb_new(struct api_msg_msg *msg)
{ {
msg->conn->err = ERR_OK; LWIP_ASSERT("pcb_new: pcb already allocated", msg->conn->pcb.tcp == NULL);
LWIP_ASSERT("pcb_new: pcb already allocated", msg->conn->pcb.tcp == NULL); /* Allocate a PCB for this connection */
switch(NETCONNTYPE_GROUP(msg->conn->type)) {
/* Allocate a PCB for this connection */
switch(NETCONNTYPE_GROUP(msg->conn->type)) {
#if LWIP_RAW #if LWIP_RAW
case NETCONN_RAW: case NETCONN_RAW:
msg->conn->pcb.raw = raw_new(msg->msg.n.proto); msg->conn->pcb.raw = raw_new(msg->msg.n.proto);
if(msg->conn->pcb.raw == NULL) { if(msg->conn->pcb.raw == NULL) {
msg->conn->err = ERR_MEM; msg->err = ERR_MEM;
break; break;
} }
raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn); raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn);
break; break;
#endif /* LWIP_RAW */ #endif /* LWIP_RAW */
#if LWIP_UDP #if LWIP_UDP
case NETCONN_UDP: case NETCONN_UDP:
msg->conn->pcb.udp = udp_new(); msg->conn->pcb.udp = udp_new();
if(msg->conn->pcb.udp == NULL) { if(msg->conn->pcb.udp == NULL) {
msg->conn->err = ERR_MEM; msg->err = ERR_MEM;
break; break;
} }
#if LWIP_UDPLITE #if LWIP_UDPLITE
if (msg->conn->type==NETCONN_UDPLITE) { if (msg->conn->type==NETCONN_UDPLITE) {
udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE); udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE);
} }
#endif /* LWIP_UDPLITE */ #endif /* LWIP_UDPLITE */
if (msg->conn->type==NETCONN_UDPNOCHKSUM) { if (msg->conn->type==NETCONN_UDPNOCHKSUM) {
udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM); udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM);
} }
udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn); udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
break; break;
#endif /* LWIP_UDP */ #endif /* LWIP_UDP */
#if LWIP_TCP #if LWIP_TCP
case NETCONN_TCP: case NETCONN_TCP:
msg->conn->pcb.tcp = tcp_new(); msg->conn->pcb.tcp = tcp_new();
if(msg->conn->pcb.tcp == NULL) { if(msg->conn->pcb.tcp == NULL) {
msg->conn->err = ERR_MEM; msg->err = ERR_MEM;
break; break;
} }
setup_tcp(msg->conn); setup_tcp(msg->conn);
break; break;
#endif /* LWIP_TCP */ #endif /* LWIP_TCP */
default: default:
/* Unsupported netconn type, e.g. protocol disabled */ /* Unsupported netconn type, e.g. protocol disabled */
msg->conn->err = ERR_VAL; msg->err = ERR_VAL;
break; break;
} }
return msg->conn->err;
} }
/** /**
@ -482,14 +492,15 @@ pcb_new(struct api_msg_msg *msg)
void void
do_newconn(struct api_msg_msg *msg) do_newconn(struct api_msg_msg *msg)
{ {
if(msg->conn->pcb.tcp == NULL) { msg->err = ERR_OK;
pcb_new(msg); if(msg->conn->pcb.tcp == NULL) {
} pcb_new(msg);
/* Else? This "new" connection already has a PCB allocated. */ }
/* Is this an error condition? Should it be deleted? */ /* Else? This "new" connection already has a PCB allocated. */
/* We currently just are happy and return. */ /* Is this an error condition? Should it be deleted? */
/* We currently just are happy and return. */
TCPIP_APIMSG_ACK(msg); TCPIP_APIMSG_ACK(msg);
} }
/** /**
@ -513,7 +524,7 @@ netconn_alloc(enum netconn_type t, netconn_callback callback)
return NULL; return NULL;
} }
conn->err = ERR_OK; conn->last_err = ERR_OK;
conn->type = t; conn->type = t;
conn->pcb.tcp = NULL; conn->pcb.tcp = NULL;
@ -560,7 +571,7 @@ netconn_alloc(enum netconn_type t, netconn_callback callback)
conn->callback = callback; conn->callback = callback;
conn->recv_avail = 0; conn->recv_avail = 0;
#if LWIP_TCP #if LWIP_TCP
conn->write_msg = NULL; conn->current_msg = NULL;
conn->write_offset = 0; conn->write_offset = 0;
#if LWIP_TCPIP_CORE_LOCKING #if LWIP_TCPIP_CORE_LOCKING
conn->write_delayed = 0; conn->write_delayed = 0;
@ -665,6 +676,7 @@ do_close_internal(struct netconn *conn)
LWIP_ASSERT("this is for tcp netconns only", (conn->type == NETCONN_TCP)); LWIP_ASSERT("this is for tcp netconns only", (conn->type == NETCONN_TCP));
LWIP_ASSERT("conn must be in state NETCONN_CLOSE", (conn->state == NETCONN_CLOSE)); LWIP_ASSERT("conn must be in state NETCONN_CLOSE", (conn->state == NETCONN_CLOSE));
LWIP_ASSERT("pcb already closed", (conn->pcb.tcp != NULL)); LWIP_ASSERT("pcb already closed", (conn->pcb.tcp != NULL));
LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL);
/* Set back some callback pointers */ /* Set back some callback pointers */
tcp_arg(conn->pcb.tcp, NULL); tcp_arg(conn->pcb.tcp, NULL);
@ -682,10 +694,11 @@ do_close_internal(struct netconn *conn)
err = tcp_close(conn->pcb.tcp); err = tcp_close(conn->pcb.tcp);
if (err == ERR_OK) { if (err == ERR_OK) {
/* Closing succeeded */ /* Closing succeeded */
conn->current_msg->err = ERR_OK;
conn->current_msg = NULL;
conn->state = NETCONN_NONE; conn->state = NETCONN_NONE;
/* Set back some callback pointers as conn is going away */ /* Set back some callback pointers as conn is going away */
conn->pcb.tcp = NULL; conn->pcb.tcp = NULL;
conn->err = ERR_OK;
/* Trigger select() in socket layer. This send should something else so the /* Trigger select() in socket layer. This send should something else so the
errorfd is set, not the read and write fd! */ errorfd is set, not the read and write fd! */
API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
@ -734,8 +747,11 @@ do_delconn(struct api_msg_msg *msg)
#endif /* LWIP_UDP */ #endif /* LWIP_UDP */
#if LWIP_TCP #if LWIP_TCP
case NETCONN_TCP: case NETCONN_TCP:
msg->conn->state = NETCONN_CLOSE; LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL &&
do_close_internal(msg->conn); msg->conn->write_offset == 0);
msg->conn->state = NETCONN_CLOSE;
msg->conn->current_msg = msg;
do_close_internal(msg->conn);
/* API_EVENT is called inside do_close_internal, before releasing /* API_EVENT is called inside do_close_internal, before releasing
the application thread, so we can return at this point! */ the application thread, so we can return at this point! */
return; return;
@ -766,30 +782,30 @@ do_delconn(struct api_msg_msg *msg)
void void
do_bind(struct api_msg_msg *msg) do_bind(struct api_msg_msg *msg)
{ {
if (!ERR_IS_FATAL(msg->conn->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) { if (msg->conn->pcb.tcp != NULL) {
switch (NETCONNTYPE_GROUP(msg->conn->type)) { switch (NETCONNTYPE_GROUP(msg->conn->type)) {
#if LWIP_RAW #if LWIP_RAW
case NETCONN_RAW: case NETCONN_RAW:
msg->conn->err = raw_bind(msg->conn->pcb.raw, msg->msg.bc.ipaddr); msg->err = raw_bind(msg->conn->pcb.raw, msg->msg.bc.ipaddr);
break; break;
#endif /* LWIP_RAW */ #endif /* LWIP_RAW */
#if LWIP_UDP #if LWIP_UDP
case NETCONN_UDP: case NETCONN_UDP:
msg->conn->err = udp_bind(msg->conn->pcb.udp, msg->msg.bc.ipaddr, msg->msg.bc.port); msg->err = udp_bind(msg->conn->pcb.udp, msg->msg.bc.ipaddr, msg->msg.bc.port);
break; break;
#endif /* LWIP_UDP */ #endif /* LWIP_UDP */
#if LWIP_TCP #if LWIP_TCP
case NETCONN_TCP: case NETCONN_TCP:
msg->conn->err = tcp_bind(msg->conn->pcb.tcp, msg->msg.bc.ipaddr, msg->msg.bc.port); msg->err = tcp_bind(msg->conn->pcb.tcp, msg->msg.bc.ipaddr, msg->msg.bc.port);
break; break;
#endif /* LWIP_TCP */ #endif /* LWIP_TCP */
default: default:
break; break;
} }
} else {
/* msg->conn->pcb is NULL */
msg->conn->err = ERR_VAL;
} }
} }
TCPIP_APIMSG_ACK(msg); TCPIP_APIMSG_ACK(msg);
@ -815,10 +831,14 @@ do_connected(void *arg, struct tcp_pcb *pcb, err_t err)
return ERR_VAL; return ERR_VAL;
} }
conn->err = err; LWIP_ASSERT("conn->state == NETCONN_CONNECT", conn->state == NETCONN_CONNECT);
LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL);
conn->current_msg->err = err;
if ((conn->type == NETCONN_TCP) && (err == ERR_OK)) { if ((conn->type == NETCONN_TCP) && (err == ERR_OK)) {
setup_tcp(conn); setup_tcp(conn);
} }
conn->current_msg = NULL;
conn->state = NETCONN_NONE; conn->state = NETCONN_NONE;
sys_sem_signal(conn->op_completed); sys_sem_signal(conn->op_completed);
return ERR_OK; return ERR_OK;
@ -837,7 +857,7 @@ do_connect(struct api_msg_msg *msg)
{ {
if (msg->conn->pcb.tcp == NULL) { if (msg->conn->pcb.tcp == NULL) {
/* This may happen when calling netconn_connect() a second time */ /* This may happen when calling netconn_connect() a second time */
msg->conn->err = ERR_CLSD; msg->err = ERR_CLSD;
sys_sem_signal(msg->conn->op_completed); sys_sem_signal(msg->conn->op_completed);
return; return;
} }
@ -845,28 +865,29 @@ do_connect(struct api_msg_msg *msg)
switch (NETCONNTYPE_GROUP(msg->conn->type)) { switch (NETCONNTYPE_GROUP(msg->conn->type)) {
#if LWIP_RAW #if LWIP_RAW
case NETCONN_RAW: case NETCONN_RAW:
msg->conn->err = raw_connect(msg->conn->pcb.raw, msg->msg.bc.ipaddr); msg->err = raw_connect(msg->conn->pcb.raw, msg->msg.bc.ipaddr);
sys_sem_signal(msg->conn->op_completed); sys_sem_signal(msg->conn->op_completed);
break; break;
#endif /* LWIP_RAW */ #endif /* LWIP_RAW */
#if LWIP_UDP #if LWIP_UDP
case NETCONN_UDP: case NETCONN_UDP:
msg->conn->err = udp_connect(msg->conn->pcb.udp, msg->msg.bc.ipaddr, msg->msg.bc.port); msg->err = udp_connect(msg->conn->pcb.udp, msg->msg.bc.ipaddr, msg->msg.bc.port);
sys_sem_signal(msg->conn->op_completed); sys_sem_signal(msg->conn->op_completed);
break; break;
#endif /* LWIP_UDP */ #endif /* LWIP_UDP */
#if LWIP_TCP #if LWIP_TCP
case NETCONN_TCP: case NETCONN_TCP:
msg->conn->state = NETCONN_CONNECT; msg->conn->state = NETCONN_CONNECT;
msg->conn->current_msg = msg;
setup_tcp(msg->conn); setup_tcp(msg->conn);
msg->conn->err = tcp_connect(msg->conn->pcb.tcp, msg->msg.bc.ipaddr, msg->msg.bc.port, msg->err = tcp_connect(msg->conn->pcb.tcp, msg->msg.bc.ipaddr, msg->msg.bc.port,
do_connected); do_connected);
/* sys_sem_signal() is called from do_connected (or err_tcp()), /* sys_sem_signal() is called from do_connected (or err_tcp()),
* when the connection is established! */ * when the connection is established! */
break; break;
#endif /* LWIP_TCP */ #endif /* LWIP_TCP */
default: default:
LWIP_ERROR("Invalid netconn type", 0, do{ msg->conn->err = ERR_VAL; LWIP_ERROR("Invalid netconn type", 0, do{ msg->err = ERR_VAL;
sys_sem_signal(msg->conn->op_completed); }while(0)); sys_sem_signal(msg->conn->op_completed); }while(0));
break; break;
} }
@ -885,8 +906,12 @@ do_disconnect(struct api_msg_msg *msg)
#if LWIP_UDP #if LWIP_UDP
if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) { if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) {
udp_disconnect(msg->conn->pcb.udp); udp_disconnect(msg->conn->pcb.udp);
} msg->err = ERR_OK;
} else
#endif /* LWIP_UDP */ #endif /* LWIP_UDP */
{
msg->err = ERR_VAL;
}
TCPIP_APIMSG_ACK(msg); TCPIP_APIMSG_ACK(msg);
} }
@ -900,7 +925,10 @@ void
do_listen(struct api_msg_msg *msg) do_listen(struct api_msg_msg *msg)
{ {
#if LWIP_TCP #if LWIP_TCP
if (!ERR_IS_FATAL(msg->conn->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 (msg->conn->pcb.tcp != NULL) {
if (msg->conn->type == NETCONN_TCP) { if (msg->conn->type == NETCONN_TCP) {
if (msg->conn->pcb.tcp->state == CLOSED) { if (msg->conn->pcb.tcp->state == CLOSED) {
@ -910,7 +938,7 @@ do_listen(struct api_msg_msg *msg)
struct tcp_pcb* lpcb = tcp_listen(msg->conn->pcb.tcp); struct tcp_pcb* lpcb = tcp_listen(msg->conn->pcb.tcp);
#endif /* TCP_LISTEN_BACKLOG */ #endif /* TCP_LISTEN_BACKLOG */
if (lpcb == NULL) { if (lpcb == NULL) {
msg->conn->err = ERR_MEM; msg->err = ERR_MEM;
} else { } else {
/* delete the recvmbox and allocate the acceptmbox */ /* delete the recvmbox and allocate the acceptmbox */
if (msg->conn->recvmbox != SYS_MBOX_NULL) { if (msg->conn->recvmbox != SYS_MBOX_NULL) {
@ -918,20 +946,19 @@ do_listen(struct api_msg_msg *msg)
sys_mbox_free(msg->conn->recvmbox); sys_mbox_free(msg->conn->recvmbox);
msg->conn->recvmbox = SYS_MBOX_NULL; msg->conn->recvmbox = SYS_MBOX_NULL;
} }
msg->err = ERR_OK;
if (msg->conn->acceptmbox == SYS_MBOX_NULL) { if (msg->conn->acceptmbox == SYS_MBOX_NULL) {
if ((msg->conn->acceptmbox = sys_mbox_new(DEFAULT_ACCEPTMBOX_SIZE)) == SYS_MBOX_NULL) { if ((msg->conn->acceptmbox = sys_mbox_new(DEFAULT_ACCEPTMBOX_SIZE)) == SYS_MBOX_NULL) {
msg->conn->err = ERR_MEM; msg->err = ERR_MEM;
} }
} }
if (msg->conn->err == ERR_OK) { if (msg->err == ERR_OK) {
msg->conn->state = NETCONN_LISTEN; msg->conn->state = NETCONN_LISTEN;
msg->conn->pcb.tcp = lpcb; msg->conn->pcb.tcp = lpcb;
tcp_arg(msg->conn->pcb.tcp, msg->conn); tcp_arg(msg->conn->pcb.tcp, msg->conn);
tcp_accept(msg->conn->pcb.tcp, accept_function); tcp_accept(msg->conn->pcb.tcp, accept_function);
} }
} }
} else {
msg->conn->err = ERR_CONN;
} }
} }
} }
@ -949,24 +976,27 @@ do_listen(struct api_msg_msg *msg)
void void
do_send(struct api_msg_msg *msg) do_send(struct api_msg_msg *msg)
{ {
if (!ERR_IS_FATAL(msg->conn->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 (msg->conn->pcb.tcp != NULL) {
switch (NETCONNTYPE_GROUP(msg->conn->type)) { switch (NETCONNTYPE_GROUP(msg->conn->type)) {
#if LWIP_RAW #if LWIP_RAW
case NETCONN_RAW: case NETCONN_RAW:
if (msg->msg.b->addr == NULL) { if (msg->msg.b->addr == NULL) {
msg->conn->err = raw_send(msg->conn->pcb.raw, msg->msg.b->p); msg->err = raw_send(msg->conn->pcb.raw, msg->msg.b->p);
} else { } else {
msg->conn->err = raw_sendto(msg->conn->pcb.raw, msg->msg.b->p, msg->msg.b->addr); msg->err = raw_sendto(msg->conn->pcb.raw, msg->msg.b->p, msg->msg.b->addr);
} }
break; break;
#endif #endif
#if LWIP_UDP #if LWIP_UDP
case NETCONN_UDP: case NETCONN_UDP:
if (msg->msg.b->addr == NULL) { if (msg->msg.b->addr == NULL) {
msg->conn->err = udp_send(msg->conn->pcb.udp, msg->msg.b->p); msg->err = udp_send(msg->conn->pcb.udp, msg->msg.b->p);
} else { } else {
msg->conn->err = udp_sendto(msg->conn->pcb.udp, msg->msg.b->p, msg->msg.b->addr, msg->msg.b->port); msg->err = udp_sendto(msg->conn->pcb.udp, msg->msg.b->p, msg->msg.b->addr, msg->msg.b->port);
} }
break; break;
#endif /* LWIP_UDP */ #endif /* LWIP_UDP */
@ -988,17 +1018,16 @@ void
do_recv(struct api_msg_msg *msg) do_recv(struct api_msg_msg *msg)
{ {
#if LWIP_TCP #if LWIP_TCP
if (!ERR_IS_FATAL(msg->conn->err)) { msg->err = ERR_OK;
if (msg->conn->pcb.tcp != NULL) { if (msg->conn->pcb.tcp != NULL) {
if (msg->conn->type == NETCONN_TCP) { if (msg->conn->type == NETCONN_TCP) {
#if TCP_LISTEN_BACKLOG #if TCP_LISTEN_BACKLOG
if (msg->conn->pcb.tcp->state == LISTEN) { if (msg->conn->pcb.tcp->state == LISTEN) {
tcp_accepted(msg->conn->pcb.tcp); tcp_accepted(msg->conn->pcb.tcp);
} else } else
#endif /* TCP_LISTEN_BACKLOG */ #endif /* TCP_LISTEN_BACKLOG */
{ {
tcp_recved(msg->conn->pcb.tcp, msg->msg.r.len); tcp_recved(msg->conn->pcb.tcp, msg->msg.r.len);
}
} }
} }
} }
@ -1027,10 +1056,12 @@ do_writemore(struct netconn *conn)
u8_t write_finished = 0; u8_t write_finished = 0;
size_t diff; size_t diff;
LWIP_ASSERT("conn != NULL", conn != NULL);
LWIP_ASSERT("conn->state == NETCONN_WRITE", (conn->state == NETCONN_WRITE)); LWIP_ASSERT("conn->state == NETCONN_WRITE", (conn->state == NETCONN_WRITE));
LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL);
dataptr = (u8_t*)conn->write_msg->msg.w.dataptr + conn->write_offset; dataptr = (u8_t*)conn->current_msg->msg.w.dataptr + conn->write_offset;
diff = conn->write_msg->msg.w.len - conn->write_offset; diff = conn->current_msg->msg.w.len - conn->write_offset;
if (diff > 0xffffUL) { /* max_u16_t */ if (diff > 0xffffUL) { /* max_u16_t */
len = 0xffff; len = 0xffff;
#if LWIP_TCPIP_CORE_LOCKING #if LWIP_TCPIP_CORE_LOCKING
@ -1048,20 +1079,18 @@ do_writemore(struct netconn *conn)
#endif #endif
} }
err = tcp_write(conn->pcb.tcp, dataptr, len, conn->write_msg->msg.w.apiflags); err = tcp_write(conn->pcb.tcp, dataptr, len, conn->current_msg->msg.w.apiflags);
LWIP_ASSERT("do_writemore: invalid length!", ((conn->write_offset + len) <= conn->write_msg->msg.w.len)); LWIP_ASSERT("do_writemore: invalid length!", ((conn->write_offset + len) <= conn->current_msg->msg.w.len));
if (err == ERR_OK) { if (err == ERR_OK) {
conn->write_offset += len; conn->write_offset += len;
if (conn->write_offset == conn->write_msg->msg.w.len) { if (conn->write_offset == conn->current_msg->msg.w.len) {
/* everything was written */ /* everything was written */
write_finished = 1; write_finished = 1;
conn->write_msg = NULL;
conn->write_offset = 0; conn->write_offset = 0;
/* API_EVENT might call tcp_tmr, so reset conn->state now */ /* API_EVENT might call tcp_tmr, so reset conn->state now */
conn->state = NETCONN_NONE; conn->state = NETCONN_NONE;
} }
err = tcp_output_nagle(conn->pcb.tcp); err = tcp_output_nagle(conn->pcb.tcp);
conn->err = err;
if ((err == ERR_OK) && (tcp_sndbuf(conn->pcb.tcp) <= TCP_SNDLOWAT)) { if ((err == ERR_OK) && (tcp_sndbuf(conn->pcb.tcp) <= TCP_SNDLOWAT)) {
API_EVENT(conn, NETCONN_EVT_SENDMINUS, len); API_EVENT(conn, NETCONN_EVT_SENDMINUS, len);
} }
@ -1079,13 +1108,14 @@ do_writemore(struct netconn *conn)
} else { } else {
/* On errors != ERR_MEM, we don't try writing any more but return /* On errors != ERR_MEM, we don't try writing any more but return
the error to the application thread. */ the error to the application thread. */
conn->err = err;
write_finished = 1; write_finished = 1;
} }
if (write_finished) { if (write_finished) {
/* everything was written: set back connection state /* everything was written: set back connection state
and back to application task */ and back to application task */
conn->current_msg->err = err;
conn->current_msg = NULL;
conn->state = NETCONN_NONE; conn->state = NETCONN_NONE;
#if LWIP_TCPIP_CORE_LOCKING #if LWIP_TCPIP_CORE_LOCKING
if (conn->write_delayed != 0) if (conn->write_delayed != 0)
@ -1111,33 +1141,42 @@ do_writemore(struct netconn *conn)
void void
do_write(struct api_msg_msg *msg) do_write(struct api_msg_msg *msg)
{ {
if (!ERR_IS_FATAL(msg->conn->err)) { if (ERR_IS_FATAL(msg->conn->last_err)) {
if ((msg->conn->pcb.tcp != NULL) && (msg->conn->type == NETCONN_TCP)) { msg->err = msg->conn->last_err;
} else {
if (msg->conn->type == NETCONN_TCP) {
#if LWIP_TCP #if LWIP_TCP
msg->conn->state = NETCONN_WRITE; if (msg->conn->pcb.tcp != NULL) {
/* set all the variables used by do_writemore */ msg->conn->state = NETCONN_WRITE;
LWIP_ASSERT("already writing", msg->conn->write_msg == NULL && /* set all the variables used by do_writemore */
msg->conn->write_offset == 0); LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL &&
msg->conn->write_msg = msg; msg->conn->write_offset == 0);
msg->conn->write_offset = 0; msg->conn->current_msg = msg;
msg->conn->write_offset = 0;
#if LWIP_TCPIP_CORE_LOCKING #if LWIP_TCPIP_CORE_LOCKING
msg->conn->write_delayed = 0; msg->conn->write_delayed = 0;
if (do_writemore(msg->conn) != ERR_OK) { if (do_writemore(msg->conn) != ERR_OK) {
LWIP_ASSERT("state!", msg->conn->state == NETCONN_WRITE); LWIP_ASSERT("state!", msg->conn->state == NETCONN_WRITE);
UNLOCK_TCPIP_CORE(); UNLOCK_TCPIP_CORE();
sys_arch_sem_wait(msg->conn->op_completed, 0); sys_arch_sem_wait(msg->conn->op_completed, 0);
LOCK_TCPIP_CORE(); LOCK_TCPIP_CORE();
LWIP_ASSERT("state!", msg->conn->state == NETCONN_NONE); LWIP_ASSERT("state!", msg->conn->state == NETCONN_NONE);
}
#else /* LWIP_TCPIP_CORE_LOCKING */
do_writemore(msg->conn);
#endif /* LWIP_TCPIP_CORE_LOCKING */
/* for both cases: if do_writemore was called, don't ACK the APIMSG
since do_writemore ACKs it! */
return;
} else {
msg->err = ERR_CONN;
} }
#else #else /* LWIP_TCP */
do_writemore(msg->conn); msg->err = ERR_VAL;
#endif
/* for both cases: if do_writemore was called, don't ACK the APIMSG! */
return;
#endif /* LWIP_TCP */ #endif /* LWIP_TCP */
#if (LWIP_UDP || LWIP_RAW) #if (LWIP_UDP || LWIP_RAW)
} else { } else {
msg->conn->err = ERR_VAL; msg->err = ERR_VAL;
#endif /* (LWIP_UDP || LWIP_RAW) */ #endif /* (LWIP_UDP || LWIP_RAW) */
} }
} }
@ -1156,6 +1195,7 @@ do_getaddr(struct api_msg_msg *msg)
if (msg->conn->pcb.ip != NULL) { if (msg->conn->pcb.ip != NULL) {
*(msg->msg.ad.ipaddr) = (msg->msg.ad.local?msg->conn->pcb.ip->local_ip:msg->conn->pcb.ip->remote_ip); *(msg->msg.ad.ipaddr) = (msg->msg.ad.local?msg->conn->pcb.ip->local_ip:msg->conn->pcb.ip->remote_ip);
msg->err = ERR_OK;
switch (NETCONNTYPE_GROUP(msg->conn->type)) { switch (NETCONNTYPE_GROUP(msg->conn->type)) {
#if LWIP_RAW #if LWIP_RAW
case NETCONN_RAW: case NETCONN_RAW:
@ -1163,7 +1203,7 @@ do_getaddr(struct api_msg_msg *msg)
*(msg->msg.ad.port) = msg->conn->pcb.raw->protocol; *(msg->msg.ad.port) = msg->conn->pcb.raw->protocol;
} else { } else {
/* return an error as connecting is only a helper for upper layers */ /* return an error as connecting is only a helper for upper layers */
msg->conn->err = ERR_CONN; msg->err = ERR_CONN;
} }
break; break;
#endif /* LWIP_RAW */ #endif /* LWIP_RAW */
@ -1173,7 +1213,7 @@ do_getaddr(struct api_msg_msg *msg)
*(msg->msg.ad.port) = msg->conn->pcb.udp->local_port; *(msg->msg.ad.port) = msg->conn->pcb.udp->local_port;
} else { } else {
if ((msg->conn->pcb.udp->flags & UDP_FLAGS_CONNECTED) == 0) { if ((msg->conn->pcb.udp->flags & UDP_FLAGS_CONNECTED) == 0) {
msg->conn->err = ERR_CONN; msg->err = ERR_CONN;
} else { } else {
*(msg->msg.ad.port) = msg->conn->pcb.udp->remote_port; *(msg->msg.ad.port) = msg->conn->pcb.udp->remote_port;
} }
@ -1187,7 +1227,7 @@ do_getaddr(struct api_msg_msg *msg)
#endif /* LWIP_TCP */ #endif /* LWIP_TCP */
} }
} else { } else {
msg->conn->err = ERR_CONN; msg->err = ERR_CONN;
} }
TCPIP_APIMSG_ACK(msg); TCPIP_APIMSG_ACK(msg);
} }
@ -1204,13 +1244,16 @@ do_close(struct api_msg_msg *msg)
#if LWIP_TCP #if LWIP_TCP
if ((msg->conn->pcb.tcp != NULL) && (msg->conn->type == NETCONN_TCP)) { if ((msg->conn->pcb.tcp != NULL) && (msg->conn->type == NETCONN_TCP)) {
netconn_drain(msg->conn); netconn_drain(msg->conn);
LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL &&
msg->conn->write_offset == 0);
msg->conn->state = NETCONN_CLOSE; msg->conn->state = NETCONN_CLOSE;
msg->conn->current_msg = msg;
do_close_internal(msg->conn); do_close_internal(msg->conn);
/* for tcp netconns, do_close_internal ACKs the message */ /* for tcp netconns, do_close_internal ACKs the message */
} else } else
#endif /* LWIP_TCP */ #endif /* LWIP_TCP */
{ {
msg->conn->err = ERR_VAL; msg->err = ERR_VAL;
sys_sem_signal(msg->conn->op_completed); sys_sem_signal(msg->conn->op_completed);
} }
} }
@ -1225,21 +1268,25 @@ do_close(struct api_msg_msg *msg)
void void
do_join_leave_group(struct api_msg_msg *msg) do_join_leave_group(struct api_msg_msg *msg)
{ {
if (!ERR_IS_FATAL(msg->conn->err)) { if (ERR_IS_FATAL(msg->conn->last_err)) {
msg->err = msg->conn->last_err;
} else {
if (msg->conn->pcb.tcp != NULL) { if (msg->conn->pcb.tcp != NULL) {
if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) { if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) {
#if LWIP_UDP #if LWIP_UDP
if (msg->msg.jl.join_or_leave == NETCONN_JOIN) { if (msg->msg.jl.join_or_leave == NETCONN_JOIN) {
msg->conn->err = igmp_joingroup(msg->msg.jl.interface, msg->msg.jl.multiaddr); msg->err = igmp_joingroup(msg->msg.jl.interface, msg->msg.jl.multiaddr);
} else { } else {
msg->conn->err = igmp_leavegroup(msg->msg.jl.interface, msg->msg.jl.multiaddr); msg->err = igmp_leavegroup(msg->msg.jl.interface, msg->msg.jl.multiaddr);
} }
#endif /* LWIP_UDP */ #endif /* LWIP_UDP */
#if (LWIP_TCP || LWIP_RAW) #if (LWIP_TCP || LWIP_RAW)
} else { } else {
msg->conn->err = ERR_VAL; msg->err = ERR_VAL;
#endif /* (LWIP_TCP || LWIP_RAW) */ #endif /* (LWIP_TCP || LWIP_RAW) */
} }
} else {
msg->err = ERR_CONN;
} }
} }
TCPIP_APIMSG_ACK(msg); TCPIP_APIMSG_ACK(msg);

View File

@ -1440,8 +1440,9 @@ lwip_getsockopt_internal(void *arg)
break; break;
case SO_ERROR: case SO_ERROR:
/* only overwrite if ERR_OK before */
if (sock->err == 0) { if (sock->err == 0) {
sock_set_errno(sock, err_to_errno(sock->conn->err)); sock_set_errno(sock, err_to_errno(sock->conn->last_err));
} }
*(int *)optval = sock->err; *(int *)optval = sock->err;
sock->err = 0; sock->err = 0;

View File

@ -274,13 +274,17 @@ err_t
tcpip_apimsg(struct api_msg *apimsg) tcpip_apimsg(struct api_msg *apimsg)
{ {
struct tcpip_msg msg; struct tcpip_msg msg;
#ifdef LWIP_DEBUG
/* catch functions that don't set err */
apimsg->msg.err = ERR_VAL;
#endif
if (mbox != SYS_MBOX_NULL) { if (mbox != SYS_MBOX_NULL) {
msg.type = TCPIP_MSG_API; msg.type = TCPIP_MSG_API;
msg.msg.apimsg = apimsg; msg.msg.apimsg = apimsg;
sys_mbox_post(mbox, &msg); sys_mbox_post(mbox, &msg);
sys_arch_sem_wait(apimsg->msg.conn->op_completed, 0); sys_arch_sem_wait(apimsg->msg.conn->op_completed, 0);
return ERR_OK; return apimsg->msg.err;
} }
return ERR_VAL; return ERR_VAL;
} }
@ -297,10 +301,15 @@ tcpip_apimsg(struct api_msg *apimsg)
err_t err_t
tcpip_apimsg_lock(struct api_msg *apimsg) tcpip_apimsg_lock(struct api_msg *apimsg)
{ {
#ifdef LWIP_DEBUG
/* catch functions that don't set err */
apimsg->msg.err = ERR_VAL;
#endif
LOCK_TCPIP_CORE(); LOCK_TCPIP_CORE();
apimsg->function(&(apimsg->msg)); apimsg->function(&(apimsg->msg));
UNLOCK_TCPIP_CORE(); UNLOCK_TCPIP_CORE();
return ERR_OK; return apimsg->msg.err;
} }
#endif /* LWIP_TCPIP_CORE_LOCKING */ #endif /* LWIP_TCPIP_CORE_LOCKING */