Ethernet problem, application crash, problem in NutTcpReceive

classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

Ethernet problem, application crash, problem in NutTcpReceive

Michael Fischer
Hello List,

for the test I use the trunk version 6699 and a STM3240G-EVAL board.
The application was compiled in debug mode with the GNU Arm Embedded Toolchain
in version 7-2017-q4.

The application is the iperf application for testing the Ethernet performance.
Some more infos about JPerf can be find here on my page, which was done with lwIP:
https://www.emb4fun.de/projects/tctsallwipuhttp/index.html

JPerf, version 2.0.2, can be find here:
https://code.google.com/archive/p/xjperf/

The application I used for NutOS was attached at the end of this description too.

The application does not use DHCP, it use a static IP-Adress, 192.168.1.200.
With the JPerf GUI it is possible to use one or more stream to connect with the
target. If the JPerf GUI is started with the "Run IPerf!" button it runs 10 seconds
and stop automatically.

This makes no problem if one or more streams are used. The application can handle up
to 4 streams in parallel.

How to produce the error?

Start the JPerf with the "Run IPerf!" button, do not wait the 10 seconds, it should
not stop automatically. Stop manually with the "Stop IPerf" button.

Now the application crash, and stops in IntBusfaultHandler.

The problem is a NULL pointer access in the while loop in NutTcpReceive:

         ab_cnt = 0;
         while (ab_cnt < size) {
             nb = sock->so_rx_buf;
             nb_cnt = nb->nb_ap.sz - rd_cnt;
             mv_cnt = size - ab_cnt;
   
nb is NULL here.

The problem can be fixed with the following code after the first while loop:

     /*
      * Wait until any data arrived, a timeout occurs
      * or the connection terminates.
      */
     while (sock->so_rx_cnt - sock->so_rd_cnt == 0) {
         if (sock->so_state != TCPS_ESTABLISHED) {
             sock->so_last_error = ENOTCONN;
             return -1;
         }
         if (NutEventWait(&sock->so_rx_tq, sock->so_read_to))
             return 0;
     }

     /* @@MF start: Check for terminated connection with empty buffer */
     if ((sock->so_state != TCPS_ESTABLISHED) && (NULL == sock->so_rx_buf)) {
         sock->so_last_error = ENOTCONN;
         printf(".");
         return -1;
     }
     /*  @@MF end */

Attached I have the code from my NutOS application for testing.

Best regards,
Michael

=======================================================================================

/**************************************************************************
*  Copyright (c) 2014 by Michael Fischer. All rights reserved.
*
*  Redistribution and use in source and binary forms, with or without
*  modification, are permitted provided that the following conditions
*  are met:
*
*  1. Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*  2. Redistributions in binary form must reproduce the above copyright
*     notice, this list of conditions and the following disclaimer in the
*     documentation and/or other materials provided with the distribution.
*  3. Neither the name of the author nor the names of its contributors may
*     be used to endorse or promote products derived from this software
*     without specific prior written permission.
*
*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
*  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
*  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
*  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
*  THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
*  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
*  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
*  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
*  AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
*  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
*  THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
*  SUCH DAMAGE.
*
***************************************************************************
*  History:
*
*  05.01.2014  mifi  First Version
**************************************************************************/
#define __IPERF_C__

/*=======================================================================*/
/*  Includes                                                             */
/*=======================================================================*/
#include <stdio.h>
#include <io.h>

#include <dev/board.h>
#include <sys/version.h>
#include <sys/thread.h>
#include <sys/timer.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <net/route.h>

/*=======================================================================*/
/*  All Structures and Common Constants                                  */
/*=======================================================================*/

#define MY_MAC    "\x00\x06\x98\x30\x00\x35"
#define MY_IPADDR "192.168.1.200"
#define MY_IPMASK "255.255.255.0"
#define MY_IPGATE "0.0.0.0"

/* Iperf thread stack size. */
#ifndef IPERF_SERVICE_STACK

#if defined(__CORTEX__)
#define IPERF_SERVICE_STACK   ((1024 * NUT_THREAD_STACK_MULT) + NUT_THREAD_STACK_ADD)
#else
#define IPERF_SERVICE_STACK   ((2048 * NUT_THREAD_STACK_MULT) + NUT_THREAD_STACK_ADD)
#endif

#endif /* IPERF_SERVICE_STACK */

/* Iperf port */
#define IPERF_TCP_PORT        5001

/*=======================================================================*/
/*  Definition of all local Data                                         */
/*=======================================================================*/

/* Dummy read buffer */
static uint8_t DummyRxBuffer[4096];

/*=======================================================================*/
/*  Definition of all local Procedures                                   */
/*=======================================================================*/

/*************************************************************************/
/*  IperfTask                                                            */
/*                                                                       */
/*  In    : task parameter                                               */
/*  Out   : none                                                         */
/*  Return: never                                                        */
/*************************************************************************/
THREAD(IperfTask, arg)
{
    TCPSOCKET *sock;
    FILE      *stream;
    size_t     Result;
   
    (void)arg;
   
    /*
     * Now loop endless for connections.
     */
    for (;;)
    {
       /*
        * Create a socket.
        */
       if ((sock = NutTcpCreateSocket()) == 0)
       {
          printf("Creating socket failed\n");
          NutSleep(5000);
          continue;
       }
       
       /*
        * Listen on port IPERF_TCP_PORT. This call will block
        * until we get a connection from a client.
        */
       NutTcpAccept(sock, IPERF_TCP_PORT);
       
       /*
        * Associate a stream with the socket so we can use standard I/O calls.
        */
       if ((stream = _fdopen((int) ((uintptr_t) sock), "r+b")) == 0)
       {
          printf("Creating stream device failed\n");
       }
       else
       {
          /*
           * Receive IPerf data
           */
          do
          {
             Result = fread(DummyRxBuffer, 1, sizeof(DummyRxBuffer), stream);
             if (Result <= 0)
             {
                break;
             }
          } while (1);

          /*
           * Destroy the virtual stream device.
           */
          fclose(stream);
       } /* end create stream */

       /*
        * Close our socket.
        */
       NutTcpCloseSocket(sock);
    } /* end for (;;) */

} /* IperfTask */

/*=======================================================================*/
/*  All code exported                                                    */
/*=======================================================================*/

/*************************************************************************/
/*  main                                                                 */
/*                                                                       */
/*  Nut/OS automatically calls this entry after initialization.          */
/*                                                                       */
/*  In    : none                                                         */
/*  Out   : none                                                         */
/*  Return: never                                                        */
/*************************************************************************/
int main (void)
{
    uint8_t  mac[] = MY_MAC;
    uint32_t ip_addr = inet_addr(MY_IPADDR);
    uint32_t ip_mask = inet_addr(MY_IPMASK);
    uint32_t ip_gate = inet_addr(MY_IPGATE);
    uint32_t baud = 115200;
    uint8_t  i;

    /*
     * Initialize the uart device.
     */
    NutRegisterDevice(&DEV_CONSOLE, 0, 0);
    freopen(DEV_CONSOLE.dev_name, "w", stdout);
    _ioctl(_fileno(stdout), UART_SETSPEED, &baud);
    NutSleep(200);
    printf("\n\nNut/OS %s Iperf test\n", NutVersionString());

    /*
     * Register Ethernet controller.
     */
    if (NutRegisterDevice(&DEV_ETHER, 0, 0))
    {
       puts("Registering device failed");
    }

    printf("Configure %s...", DEV_ETHER_NAME);
    if (NutNetIfConfig(DEV_ETHER_NAME, mac, ip_addr, ip_mask) == 0)
    {
       /* Without DHCP we had to set the default gateway manually.*/
       if(ip_gate)
       {
          printf("hard coded gate...");
          NutIpRouteAdd(0, 0, ip_gate, &DEV_ETHER);
       }
       puts("OK");
    }
    else
    {
       puts("failed");
    }
    printf("%s ready\n", inet_ntoa(ip_addr));


    /*
     * Start four Iperf threads.
     */
    for (i = 1; i <= 4; i++)
    {
       char thname[] = "iperf0";

       thname[5] = '0' + i;
       NutThreadCreate(thname, IperfTask, NULL, IPERF_SERVICE_STACK);
    }

    /*
     * We could do something useful here, like serving a watchdog.
     */
    NutThreadSetPriority(254);
    for (;;)
    {
       NutSleep(60000);
    }
    return(0);
} /* main */

/*** EOF ***/






-------------- next part --------------
/**************************************************************************
*  Copyright (c) 2014 by Michael Fischer. All rights reserved.
*
*  Redistribution and use in source and binary forms, with or without
*  modification, are permitted provided that the following conditions
*  are met:
*  
*  1. Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*  2. Redistributions in binary form must reproduce the above copyright
*     notice, this list of conditions and the following disclaimer in the
*     documentation and/or other materials provided with the distribution.
*  3. Neither the name of the author nor the names of its contributors may
*     be used to endorse or promote products derived from this software
*     without specific prior written permission.
*
*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
*  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
*  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
*  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
*  THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
*  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
*  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
*  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
*  AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
*  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
*  THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
*  SUCH DAMAGE.
*
***************************************************************************
*  History:
*
*  05.01.2014  mifi  First Version
**************************************************************************/
#define __IPERF_C__

/*=======================================================================*/
/*  Includes                                                             */
/*=======================================================================*/
#include <stdio.h>
#include <io.h>

#include <dev/board.h>
#include <sys/version.h>
#include <sys/thread.h>
#include <sys/timer.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <net/route.h>

/*=======================================================================*/
/*  All Structures and Common Constants                                  */
/*=======================================================================*/

#define MY_MAC    "\x00\x06\x98\x30\x00\x35"
#define MY_IPADDR "192.168.1.200"
#define MY_IPMASK "255.255.255.0"
#define MY_IPGATE "0.0.0.0"

/* Iperf thread stack size. */
#ifndef IPERF_SERVICE_STACK

#if defined(__CORTEX__)
#define IPERF_SERVICE_STACK   ((1024 * NUT_THREAD_STACK_MULT) + NUT_THREAD_STACK_ADD)
#else
#define IPERF_SERVICE_STACK   ((2048 * NUT_THREAD_STACK_MULT) + NUT_THREAD_STACK_ADD)
#endif

#endif /* IPERF_SERVICE_STACK */

/* Iperf port */
#define IPERF_TCP_PORT        5001

/*=======================================================================*/
/*  Definition of all local Data                                         */
/*=======================================================================*/

/* Dummy read buffer */
static uint8_t DummyRxBuffer[4096];

/*=======================================================================*/
/*  Definition of all local Procedures                                   */
/*=======================================================================*/

/*************************************************************************/
/*  IperfTask                                                            */
/*                                                                       */
/*  In    : task parameter                                               */
/*  Out   : none                                                         */
/*  Return: never                                                        */
/*************************************************************************/
THREAD(IperfTask, arg)
{
   TCPSOCKET *sock;
   FILE      *stream;
   size_t     Result;
   
   (void)arg;
   
   /*
    * Now loop endless for connections.
    */
   for (;;)
   {
      /*
       * Create a socket.
       */
      if ((sock = NutTcpCreateSocket()) == 0)
      {
         printf("Creating socket failed\n");
         NutSleep(5000);
         continue;
      }
     
      /*
       * Listen on port IPERF_TCP_PORT. This call will block
       * until we get a connection from a client.
       */
      NutTcpAccept(sock, IPERF_TCP_PORT);
     
      /*
       * Associate a stream with the socket so we can use standard I/O calls.
       */
      if ((stream = _fdopen((int) ((uintptr_t) sock), "r+b")) == 0)
      {
         printf("Creating stream device failed\n");
      }
      else
      {
         /*
          * Receive IPerf data
          */
         do
         {
            Result = fread(DummyRxBuffer, 1, sizeof(DummyRxBuffer), stream);
            if (Result <= 0)
            {
               break;
            }
         } while (1);

         /*
          * Destroy the virtual stream device.
          */
         fclose(stream);
      } /* end create stream */

      /*
       * Close our socket.
       */
      NutTcpCloseSocket(sock);
   } /* end for (;;) */

} /* IperfTask */

/*=======================================================================*/
/*  All code exported                                                    */
/*=======================================================================*/

/*************************************************************************/
/*  main                                                                 */
/*                                                                       */
/*  Nut/OS automatically calls this entry after initialization.          */
/*                                                                       */
/*  In    : none                                                         */
/*  Out   : none                                                         */
/*  Return: never                                                        */
/*************************************************************************/
int main (void)
{
   uint8_t  mac[] = MY_MAC;
   uint32_t ip_addr = inet_addr(MY_IPADDR);
   uint32_t ip_mask = inet_addr(MY_IPMASK);
   uint32_t ip_gate = inet_addr(MY_IPGATE);
   uint32_t baud = 115200;
   uint8_t  i;

   /*
    * Initialize the uart device.
    */
   NutRegisterDevice(&DEV_CONSOLE, 0, 0);
   freopen(DEV_CONSOLE.dev_name, "w", stdout);
   _ioctl(_fileno(stdout), UART_SETSPEED, &baud);
   NutSleep(200);
   printf("\n\nNut/OS %s Iperf test\n", NutVersionString());

   /*
    * Register Ethernet controller.
    */
   if (NutRegisterDevice(&DEV_ETHER, 0, 0))
   {
      puts("Registering device failed");
   }

   printf("Configure %s...", DEV_ETHER_NAME);
   if (NutNetIfConfig(DEV_ETHER_NAME, mac, ip_addr, ip_mask) == 0)
   {
      /* Without DHCP we had to set the default gateway manually.*/
      if(ip_gate)
      {
         printf("hard coded gate...");
         NutIpRouteAdd(0, 0, ip_gate, &DEV_ETHER);
      }
      puts("OK");
   }
   else
   {
      puts("failed");
   }
   printf("%s ready\n", inet_ntoa(ip_addr));


   /*
    * Start four Iperf threads.
    */
   for (i = 1; i <= 4; i++)
   {
      char thname[] = "iperf0";

      thname[5] = '0' + i;
      NutThreadCreate(thname, IperfTask, NULL, IPERF_SERVICE_STACK);
   }

   /*
    * We could do something useful here, like serving a watchdog.
    */
   NutThreadSetPriority(254);
   for (;;)
   {
      NutSleep(60000);
   }
   return(0);
} /* main */

/*** EOF ***/

_______________________________________________
http://lists.egnite.de/mailman/listinfo/en-nut-discussion
Reply | Threaded
Open this post in threaded view
|

Re: Ethernet problem, application crash, problem in NutTcpReceive

Uwe Bonnes
Michael Fischer writes:
> Hello List,
>
> for the test I use the trunk version 6699 and a STM3240G-EVAL board.
> The application was compiled in debug mode with the GNU Arm Embedded Toolchain
> in version 7-2017-q4.

Strange, version 6699 is on Philips branch for lm3s.

>
> The application is the iperf application for testing the Ethernet performance.
> Some more infos about JPerf can be find here on my page, which was done with lwIP:
> https://www.emb4fun.de/projects/tctsallwipuhttp/index.html
>
> JPerf, version 2.0.2, can be find here:
> https://code.google.com/archive/p/xjperf/
>
The link gives 404.

I tried iperf3 first, but could not get it to talk to the test
program. With much fiddling, I was able to find and setup iperf and
jperf in  version 2

> The application I used for NutOS was attached at the end of this description too.
>
> The application does not use DHCP, it use a static IP-Adress, 192.168.1.200.
> With the JPerf GUI it is possible to use one or more stream to connect with the
> target. If the JPerf GUI is started with the "Run IPerf!" button it runs 10 seconds
> and stop automatically.
>
> This makes no problem if one or more streams are used. The application can handle up
> to 4 streams in parallel.
>
> How to produce the error?
>
> Start the JPerf with the "Run IPerf!" button, do not wait the 10 seconds, it should
> not stop automatically. Stop manually with the "Stop IPerf" button.
>
> Now the application crash, and stops in IntBusfaultHandler.
>

I tested on a Nucleo F767 with svn head and version 6700 and in no
situation could reproduce the error.

> The problem is a NULL pointer access in the while loop in NutTcpReceive:
>
>          ab_cnt = 0;
>          while (ab_cnt < size) {
>              nb = sock->so_rx_buf;
>              nb_cnt = nb->nb_ap.sz - rd_cnt;
>              mv_cnt = size - ab_cnt;
>    
> nb is NULL here.
>
> The problem can be fixed with the following code after the first while loop:
>
>      /*
>       * Wait until any data arrived, a timeout occurs
>       * or the connection terminates.
>       */
>      while (sock->so_rx_cnt - sock->so_rd_cnt == 0) {
>          if (sock->so_state != TCPS_ESTABLISHED) {
>              sock->so_last_error = ENOTCONN;
>              return -1;
>          }
>          if (NutEventWait(&sock->so_rx_tq, sock->so_read_to))
>              return 0;
>      }
>
>      /* @@MF start: Check for terminated connection with empty buffer */
>      if ((sock->so_state != TCPS_ESTABLISHED) && (NULL == sock->so_rx_buf)) {
>          sock->so_last_error = ENOTCONN;
>          printf(".");
>          return -1;
>      }
>      /*  @@MF end */
>
Please, provide a diff. Textual descripton of what to change in some
code is error prone.

Even if I can not reproduces, I will consider applying.

I also consider to put your programm into the app directory as
iperf2_server. Does that naming sound right for you. I think, the
program implements an iperf server, and at the moment only for iperf2.


Bye
--
Uwe Bonnes                [hidden email]

Institut fuer Kernphysik  Schlossgartenstrasse 9  64289 Darmstadt
--------- Tel. 06151 1623569 ------- Fax. 06151 1623305 ---------
_______________________________________________
http://lists.egnite.de/mailman/listinfo/en-nut-discussion