|
|
|
|
@ -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); |
|
|
|
|
|