@@ -348,8 +348,9 @@ typedef struct _lwip_socket_obj_t {
348348 #define STATE_LISTENING 1
349349 #define STATE_CONNECTING 2
350350 #define STATE_CONNECTED 3
351- #define STATE_PEER_CLOSED 4
352- #define STATE_ACTIVE_UDP 5
351+ #define STATE_ACTIVE_UDP 4
352+ #define STATE_PEER_CLOSED 5 // Values higher than this must also be closed by peer
353+ #define STATE_PEER_RST_HANDLED 6
353354 // Negative value is lwIP error
354355 int8_t state ;
355356} lwip_socket_obj_t ;
@@ -370,10 +371,10 @@ static struct tcp_pcb *volatile *lwip_socket_incoming_array(lwip_socket_obj_t *s
370371 }
371372}
372373
373- static void lwip_socket_free_incoming (lwip_socket_obj_t * socket ) {
374+ static void lwip_socket_free_incoming (lwip_socket_obj_t * socket , bool free_queued_stream_data ) {
374375 if (socket -> state != STATE_LISTENING ) {
375376 if (socket -> type == MOD_NETWORK_SOCK_STREAM ) {
376- if (socket -> incoming .tcp .pbuf != NULL ) {
377+ if (free_queued_stream_data && socket -> incoming .tcp .pbuf != NULL ) {
377378 pbuf_free (socket -> incoming .tcp .pbuf );
378379 socket -> incoming .tcp .pbuf = NULL ;
379380 }
@@ -399,6 +400,8 @@ static void lwip_socket_free_incoming(lwip_socket_obj_t *socket) {
399400 tcp_array [i ] = NULL ;
400401 }
401402 }
403+ // This socket is now a non-listening stream, so clear the relevant state.
404+ socket -> incoming .tcp .pbuf = NULL ;
402405 }
403406}
404407
@@ -487,8 +490,9 @@ static void _lwip_udp_incoming(void *arg, struct udp_pcb *upcb, struct pbuf *p,
487490static void _lwip_tcp_error (void * arg , err_t err ) {
488491 lwip_socket_obj_t * socket = (lwip_socket_obj_t * )arg ;
489492
490- // Free any incoming buffers or connections that are stored
491- lwip_socket_free_incoming (socket );
493+ // Free any incoming buffers or connections that are stored, but keep potential
494+ // queued TCP data in case it's read later. Will be freed by MP_STREAM_CLOSE.
495+ lwip_socket_free_incoming (socket , false);
492496 // Pass the error code back via the connection variable.
493497 socket -> state = err ;
494498 // If we got here, the lwIP stack either has deallocated or will deallocate the pcb.
@@ -818,20 +822,27 @@ static mp_uint_t lwip_tcp_send(lwip_socket_obj_t *socket, const byte *buf, mp_ui
818822
819823// Helper function for recv/recvfrom to handle TCP packets
820824static mp_uint_t lwip_tcp_receive (lwip_socket_obj_t * socket , byte * buf , mp_uint_t len , mp_int_t flags , int * _errno ) {
821- // Check for any pending errors
822- STREAM_ERROR_CHECK (socket );
823-
824825 if (socket -> state == STATE_LISTENING ) {
825826 // original socket in listening state, not the accepted connection.
826827 * _errno = MP_ENOTCONN ;
827828 return -1 ;
828829 }
829830
830831 if (socket -> incoming .tcp .pbuf == NULL ) {
832+ // Check for any pending errors that should propagate out on socket read.
833+ if (socket -> state < 0 ) {
834+ * _errno = error_lookup_table [- socket -> state ];
835+ if (* _errno == MP_ECONNRESET ) {
836+ socket -> state = STATE_PEER_RST_HANDLED ;
837+ } else {
838+ socket -> state = _ERR_BADF ;
839+ }
840+ return MP_STREAM_ERROR ;
841+ }
831842
832843 // Non-blocking socket or flag
833844 if (socket -> timeout == 0 || (flags & MSG_DONTWAIT )) {
834- if (socket -> state = = STATE_PEER_CLOSED ) {
845+ if (socket -> state > = STATE_PEER_CLOSED ) {
835846 return 0 ;
836847 }
837848 * _errno = MP_EAGAIN ;
@@ -847,7 +858,7 @@ static mp_uint_t lwip_tcp_receive(lwip_socket_obj_t *socket, byte *buf, mp_uint_
847858 poll_sockets ();
848859 }
849860
850- if (socket -> state = = STATE_PEER_CLOSED ) {
861+ if (socket -> state > = STATE_PEER_CLOSED ) {
851862 if (socket -> incoming .tcp .pbuf == NULL ) {
852863 // socket closed and no data left in buffer
853864 return 0 ;
@@ -864,8 +875,6 @@ static mp_uint_t lwip_tcp_receive(lwip_socket_obj_t *socket, byte *buf, mp_uint_
864875
865876 MICROPY_PY_LWIP_ENTER
866877
867- assert (socket -> pcb .tcp != NULL);
868-
869878 struct pbuf * p = socket -> incoming .tcp .pbuf ;
870879
871880 mp_uint_t remaining = p -> len - socket -> recv_offset ;
@@ -888,7 +897,9 @@ static mp_uint_t lwip_tcp_receive(lwip_socket_obj_t *socket, byte *buf, mp_uint_
888897 } else {
889898 socket -> recv_offset += len ;
890899 }
891- tcp_recved (socket -> pcb .tcp , len );
900+ if (socket -> pcb .tcp != NULL ) {
901+ tcp_recved (socket -> pcb .tcp , len );
902+ }
892903 }
893904
894905 MICROPY_PY_LWIP_EXIT
@@ -1292,8 +1303,6 @@ static mp_obj_t lwip_socket_recv_common(size_t n_args, const mp_obj_t *args, ip_
12921303 vstr_t vstr ;
12931304 mp_uint_t ret = 0 ;
12941305
1295- lwip_socket_check_connected (socket );
1296-
12971306 vstr_init_len (& vstr , len );
12981307
12991308 switch (socket -> type ) {
@@ -1308,6 +1317,7 @@ static mp_obj_t lwip_socket_recv_common(size_t n_args, const mp_obj_t *args, ip_
13081317 #if MICROPY_PY_LWIP_SOCK_RAW
13091318 case MOD_NETWORK_SOCK_RAW :
13101319 #endif
1320+ lwip_socket_check_connected (socket );
13111321 ret = lwip_raw_udp_receive (socket , (byte * )vstr .buf , len , flags , ip , port , & _errno );
13121322 break ;
13131323 }
@@ -1580,7 +1590,10 @@ static mp_uint_t lwip_socket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_
15801590 }
15811591 } else if (socket -> type == MOD_NETWORK_SOCK_STREAM ) {
15821592 // For TCP sockets there is just one slot for incoming data
1583- if (socket -> incoming .tcp .pbuf != NULL ) {
1593+ // The socket is also readable when in RST state
1594+ if (socket -> incoming .tcp .pbuf != NULL
1595+ || socket -> state == ERR_RST
1596+ || socket -> state == STATE_PEER_RST_HANDLED ) {
15841597 ret |= MP_STREAM_POLL_RD ;
15851598 }
15861599 } else {
@@ -1619,6 +1632,8 @@ static mp_uint_t lwip_socket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_
16191632 } else if (socket -> state == ERR_RST ) {
16201633 // Socket was reset by peer, a write will return an error
16211634 ret |= flags & MP_STREAM_POLL_WR ;
1635+ ret |= MP_STREAM_POLL_ERR | MP_STREAM_POLL_HUP ;
1636+ } else if (socket -> state == STATE_PEER_RST_HANDLED ) {
16221637 ret |= MP_STREAM_POLL_HUP ;
16231638 } else if (socket -> state == _ERR_BADF ) {
16241639 ret |= MP_STREAM_POLL_NVAL ;
@@ -1629,14 +1644,15 @@ static mp_uint_t lwip_socket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_
16291644 }
16301645
16311646 } else if (request == MP_STREAM_CLOSE ) {
1647+ // Free any incoming buffers or connections that are stored
1648+ lwip_socket_free_incoming (socket , true);
1649+
16321650 if (socket -> pcb .tcp == NULL ) {
1651+ socket -> state = _ERR_BADF ;
16331652 MICROPY_PY_LWIP_EXIT
16341653 return 0 ;
16351654 }
16361655
1637- // Free any incoming buffers or connections that are stored
1638- lwip_socket_free_incoming (socket );
1639-
16401656 switch (socket -> type ) {
16411657 case MOD_NETWORK_SOCK_STREAM : {
16421658 // Deregister callback (pcb.tcp is set to NULL below so must deregister now)
0 commit comments