diff --git a/CHANGELOG b/CHANGELOG index 63d11980..ba0847f8 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -19,6 +19,10 @@ HISTORY ++ New features: + 2010-01-29: Simon Goldschmidt (patch by Laura Garrett) + * api.h, api_msg.c, sockets.c: Added except set support in select + (patch #6860) + 2010-01-29: Simon Goldschmidt (patch by Laura Garrett) * api.h, sockets.h, err.h, api_lib.c, api_msg.c, sockets.c, err.c: Add non-blocking support for connect (partly from patch #6860), diff --git a/src/api/api_msg.c b/src/api/api_msg.c index da1abc23..d6dbed06 100644 --- a/src/api/api_msg.c +++ b/src/api/api_msg.c @@ -330,7 +330,7 @@ err_tcp(void *arg, err_t err) conn->pcb.tcp = NULL; - /* no check since this is always fatal */ + /* no check since this is always fatal! */ SYS_ARCH_PROTECT(lev); conn->last_err = err; SYS_ARCH_UNPROTECT(lev); @@ -339,18 +339,25 @@ err_tcp(void *arg, err_t err) old_state = conn->state; conn->state = NETCONN_NONE; + /* Notify the user layer about a connection error. Used to signal + select. */ + API_EVENT(conn, NETCONN_EVT_ERROR, 0); + /* Try to release selects pending on 'read' or 'write', too. + They will get an error if they actually try to read or write. */ + API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); + API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0); + + /* pass NULL-message to recvmbox to wake up pending recv */ if (conn->recvmbox != SYS_MBOX_NULL) { - /* Register event with callback */ - API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); - /* use trypot to preven deadlock */ + /* use trypost to prevent deadlock */ sys_mbox_trypost(conn->recvmbox, NULL); } + /* pass NULL-message to acceptmbox to wake up pending accept */ if (conn->acceptmbox != SYS_MBOX_NULL) { - /* Register event with callback */ - API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); - /* use trypot to preven deadlock */ + /* use trypost to preven deadlock */ sys_mbox_trypost(conn->acceptmbox, NULL); } + if ((old_state == NETCONN_WRITE) || (old_state == NETCONN_CLOSE) || (old_state == NETCONN_CONNECT)) { /* calling do_writemore/do_close_internal is not necessary @@ -721,8 +728,9 @@ do_close_internal(struct netconn *conn) conn->state = NETCONN_NONE; /* Set back some callback pointers as conn is going away */ conn->pcb.tcp = NULL; - /* @todo: this lets select make the socket readable and writable, - which is wrong! errfd instead? */ + /* Trigger select() in socket layer. Make sure everybody notices activity + on the connection, error first! */ + API_EVENT(conn, NETCONN_EVT_ERROR, 0); API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0); /* wake up the application task */ diff --git a/src/api/sockets.c b/src/api/sockets.c index 8ab51371..3c1a4656 100644 --- a/src/api/sockets.c +++ b/src/api/sockets.c @@ -70,6 +70,8 @@ struct lwip_socket { /** number of times data was ACKed (free send buffer), set by event_callback(), tested by select */ u16_t sendevent; + /** error happened for this socket, set by event_callback(), tested by select */ + u16_t errevent; /** last error that occurred on this socket */ int err; }; @@ -227,6 +229,7 @@ alloc_socket(struct netconn *newconn) sockets[i].rcvevent = 0; /* TCP sendbuf is empty, but not connected yet, so not yet writable */ sockets[i].sendevent = (newconn->type == NETCONN_TCP ? 0 : 1); + sockets[i].errevent = 0; sockets[i].err = 0; sys_sem_signal(socksem); return i; @@ -872,10 +875,19 @@ lwip_selscan(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset) nready++; } } + if (FD_ISSET(i, exceptset)) { + /* See if netconn of this socket had an error */ + p_sock = get_socket(i); + if (p_sock && p_sock->errevent) { + FD_SET(i, &lexceptset); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for exception\n", i)); + nready++; + } + } } *readset = lreadset; *writeset = lwriteset; - FD_ZERO(exceptset); + *exceptset = lexceptset; return nready; } @@ -1087,6 +1099,9 @@ event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len) case NETCONN_EVT_SENDMINUS: sock->sendevent = 0; break; + case NETCONN_EVT_ERROR: + sock->errevent = 1; + break; default: LWIP_ASSERT("unknown event", 0); break; @@ -1111,6 +1126,9 @@ event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len) if (scb->writeset && FD_ISSET(s, scb->writeset)) if (sock->sendevent) break; + if (scb->exceptset && FD_ISSET(s, scb->exceptset)) + if (sock->errevent != 0) + break; } } if (scb) { diff --git a/src/include/lwip/api.h b/src/include/lwip/api.h index 3957b39b..a611c91c 100644 --- a/src/include/lwip/api.h +++ b/src/include/lwip/api.h @@ -89,7 +89,8 @@ enum netconn_evt { NETCONN_EVT_RCVPLUS, NETCONN_EVT_RCVMINUS, NETCONN_EVT_SENDPLUS, - NETCONN_EVT_SENDMINUS + NETCONN_EVT_SENDMINUS, + NETCONN_EVT_ERROR }; #if LWIP_IGMP