eclipse-threadx / netxduo

Eclipse ThreadX - NetXDuo is an advanced, industrial-grade TCP/IP network stack designed specifically for deeply embedded real-time and IoT applications
https://github.com/eclipse-threadx/rtos-docs/blob/main/rtos-docs/netx-duo/index.md
MIT License
230 stars 131 forks source link

FIONREAD ioctl on BSD TCP socket returns incorrect value #151

Closed marcin-de closed 1 year ago

marcin-de commented 1 year ago

When using BSD TCP socket, if data packet arrives and recv() is called with bufferLength smaller than received packet length, calls to FIONREAD ioctl (after recv()!) on this socket returns 0 even if there is "partially received" data still available.

This results from use of _nx_tcp_socket_bytes_available, returning only amount of data present in receive queue in packets which are not-yet-received - but if packet has already been removed from Rx queue and passed to BSD wrapper, it is not taken into account even if it was not fully read by user app.

To reproduce:

This behavior is a showstopper for implementations where user wants to read part of data to determine if rest of data is of interest (e.g. to check whether header of data is OK and if it is, receive rest of data).

Workaround is to check in ioctl code if there is already received packet and add its (remaining) length to count of data in packet queue.

marcin-de commented 1 year ago

Modified FIONREAD can look similar to this:

        case FIONREAD:
        {

            /* Check NULL pointer. */
            if(result == NX_NULL)
            {
                tx_mutex_put(nx_bsd_protection_ptr);

                set_errno(EFAULT);

                /* Error, invalid address. */
                NX_BSD_ERROR(NX_SOC_ERROR, __LINE__);

                return(NX_SOC_ERROR);
            }

            /* Determine which socket pointer to use.  */
            if (tcp_socket_ptr)
            {

// check if packet is already received (partially?)

                NX_PACKET   *packet_ptr = NULL;
                ULONG       rx_count = 0;

                packet_ptr = bsd_socket_ptr -> nx_bsd_socket_received_packet;
                if (packet_ptr) {
                    rx_count = packet_ptr ->nx_packet_length - bsd_socket_ptr ->nx_bsd_socket_received_packet_offset;
                }

// next, check if any packets are queued to be received

              /* Extract the number of bytes on the TCP receive queue. */
                status = nx_tcp_socket_bytes_available(tcp_socket_ptr, (ULONG *)result);

                if (status != NX_SUCCESS)
                {

                    tx_mutex_put(nx_bsd_protection_ptr);

                    /* Error in the native NetX call.  */
                    NX_BSD_ERROR(NX_BSD_MUTEX_ERROR, __LINE__);
                    return(NX_SOC_ERROR);
                }

// add packets in queue and partial data

                *result += rx_count;
            }
            else if (udp_socket_ptr)
            {

                /* Extract the number of bytes on the UDP receive queue. */
                *result = (INT)(bsd_socket_ptr ->  nx_bsd_socket_received_byte_count);
            }

            break;
        }
wenhui-xie commented 1 year ago

@marcin-de Thanks for your report, we will look into this issue.

wenhui-xie commented 1 year ago

@marcin-de I have checked that this is a bug of BSD. And your fix of FIONREAD is correct. We will fix this bug in our repo. Thanks again.

bo-ms commented 1 year ago

Closing. Fixed in 6.2.1 release.