[En-Nut-Discussion] _fdopen failed to create the stream on the socket

Ma-Prokop, Yuhong yuhong.ma.prokop at ims.fraunhofer.de
Thu Nov 12 14:03:53 CET 2009


Hello Harald,

thanks for your answer!

What I have is as following:

Nut/Os Version: 4.4.0
Target CPU: Ethernut 3.0E
File System: UROM

I have 7 server threads running at a time.

I firstly thought it is because the "_iob[]" which is used in "_fdopen" is not protected by multiple thread accesses, then i added a MUX for the "_iob[]", but the result is same. 

Then I found out that the function "_close(int)" which is called in "fclose()" failed, this leads to the failing in "fclose()"

One more question related to my problem: if the browser closes the website DURING the webserver processing of "NutHttpProcessRequest(http_stream)", shall the stream be closed or the stream shall stay there? I have the feeling that the streams stay there and lead to memory leak.

Best Regards,
Hong  


-----Ursprüngliche Nachricht-----
Von: en-nut-discussion-bounces at egnite.de [mailto:en-nut-discussion-bounces at egnite.de] Im Auftrag von en-nut-discussion-request at egnite.de
Gesendet: Donnerstag, 12. November 2009 12:00
An: en-nut-discussion at egnite.de
Betreff: En-Nut-Discussion Digest, Vol 73, Issue 11

Send En-Nut-Discussion mailing list submissions to
	en-nut-discussion at egnite.de

To subscribe or unsubscribe via the World Wide Web, visit
	http://lists.egnite.de/mailman/listinfo/en-nut-discussion
or, via email, send a message with subject or body 'help' to
	en-nut-discussion-request at egnite.de

You can reach the person managing the list at
	en-nut-discussion-owner at egnite.de

When replying, please edit your Subject line so it is more specific
than "Re: Contents of En-Nut-Discussion digest..."


Today's Topics:

   1. _fdopen failed to create the stream on the	socket
      (Ma-Prokop, Yuhong)
   2. Re: _fdopen failed to create the stream on the socket
      (Harald Kipp)
   3. Re: Timing issues on Ethernut 1.3 (AVR) (Harald Kipp)
   4. Re: Timing issues on Ethernut 1.3 (AVR) (Harald Kipp)
   5. Suggested modification to nut\net\tcpsm.c again (Harald Kipp)
   6. FTP server fails with very small files (Malte Marwedel)


----------------------------------------------------------------------

Message: 1
Date: Wed, 11 Nov 2009 09:17:36 +0100
From: "Ma-Prokop, Yuhong" <yuhong.ma.prokop at ims.fraunhofer.de>
Subject: [En-Nut-Discussion] _fdopen failed to create the stream on
	the	socket
To: <en-nut-discussion at egnite.de>
Message-ID:
	<02CDDA1E92DA1C4BB91B40FB0555A9B30145E716 at HERMES-1.ims.local>
Content-Type: text/plain;	charset="us-ascii"

 

Hello Everyone,

 

I have one problem with my nut/os Webserver: after some calling from the
clients (browers) the webserver does not response any more!

 

I tried to track along the problem: it is because the _fdopen function
failed to create stream on the socket and returns "-1". According to my
debugging output the opened stream number is over the FOPEN_MAX which is
defined in nut/os.

But fclose function was called everytime after the successful _fdopen.
Then i found out that the fclose (as following) returns sometimes "255"
instead of "0" as it should be, so the existing stream cannot be closed,
then until the maximal streams are opened, no further clients-request
shall be processed!

 

Does somebody have the same problem with nut/os webserver?

Any help is appreciated!

 

Hong

 

my webserver thread is as following:

 

THREAD(Service, arg) {

      FILE *http_stream;

      TCPSOCKET *sock;

    u_char id = (u_char) ((uptr_t) arg);

 

      // give each thread a (unique) priority

      NutThreadSetPriority( EHZ_HTTP_PRIO );         //+ id

 

    /*

     * Now loop endless for connections.

     */

    for(;;)

    {

        /*

         * Create a socket.

         *

         * May fail because of lacking ressources

         */

        if ((sock = NutTcpCreateSocket()) == 0)

        {

            LOG_ERROR("%d: tcp socket create failed", id);

            NutSleep(5000);

            continue;

        }

            else

        /*

         * Set socket options.

         */

        {

            u_short mss = 1460;

            u_short tcpbufsiz = 8760;

            u_long tmo = 5000;

 

            if (NutTcpSetSockOpt(sock, TCP_MAXSEG, &mss, sizeof(mss)))

                LOG_ERROR("Sockopt MSS failed");

            if (NutTcpSetSockOpt(sock, SO_RCVBUF, &tcpbufsiz,
sizeof(tcpbufsiz)))

                  LOG_ERROR("Sockopt rxbuf failed");

            if (NutTcpSetSockOpt(sock, SO_RCVTIMEO, &tmo, sizeof(tmo)))

                  LOG_ERROR("Sockopt rx timeout failed");

        }

 

        /*

         * Listen on port 80. This call will block until we get a
connection

         * from a client.

         */

        NutTcpAccept(sock, 80);

              

     //   printf("remote-ip: %s\r\n", inet_ntoa(sock->so_remote_addr));

        

        /*

         * Wait until at least 4 kByte of free RAM is available. This
will

         * keep the client connected in low memory situations.

         */

        while( NutHeapAvailable() < 4096 )

        {

            LOG_ERROR("%d: not enough memory!", id );

                  // reboot the device if the amount of memory is too
small

                  //****

                  RESET;

                  //****

            NutSleep(1000);

        }

 

        /*

         * Associate a stream with the socket so we can use standard I/O
calls.

         *

         * should not fail

         */

        // inserting a timeout here was a tip of Piotr Szlachta in the
ethernut mailing list: 

        //
http://lists.egnite.de/pipermail/en-nut-discussion/2007-November/008655.
html

        int timeout=0;

        while ( !(http_stream = _fdopen((int) ((uptr_t) sock), "r+b"))
&& ++timeout<0xFF )

            NutSleep (10);

 

        if ((int)http_stream != 0 && (int) http_stream != -1 &&
(int)http_stream != -2) {

            /*

             * This API call saves us a lot of work. It will parse the

             * client's HTTP request, send any requested file from the

             * registered file system or handle CGI requests by calling

             * our registered CGI routine.

             */

#ifndef USE_UROM_FOR_HTTP

            if(!isMmcAccessGranted()) {

                  LOG_ERROR("Please check SD-Card.");

            }

            else {

                  NutHttpProcessRequest(http_stream);

            }

#else

            NutHttpProcessRequest(http_stream);

#endif     

 

            /*

             * Destroy the virtual stream device.

             */

            fclose_result = fclose(http_stream);

            LOG_ERROR("INFO: fclose with stream: %d result: %d: \n",
http_stream, fclose_result);

      

        }

        else {

            LOG_ERROR("DEFEKT with Thread %d: fdopen result: %d: \n",id,
(int)http_stream);

            NutSleep(100);

        }        

 

        /*

         * Close our socket.

         */

       if( (NutTcpCloseSocket(sock)) == -1)

                   LOG_ERROR("ACHTUNG: Socket not closed");

            

    }

}

 

The _fdopen function in my nut/os:

 (I modified the function just lightly to get know the failed reason) 

FILE *_fdopen(int fd, CONST char *mode)

{

    int mflags = _O_TEXT;

    u_char i;

 

    /*

     * Translate file mode.

     */

    if ((mflags = _fmode(mode)) == EOF)

        return (FILE*)0;

 

    /*

     * Find an empty slot.

        */

 

 

    for (i = 3; __iob[i]; i++)

        if (i >= FOPEN_MAX - 1) {

            errno = ENFILE;

           // return 0;

            return (FILE*)(-1);

        }

 

    if ((__iob[i] = malloc(sizeof(FILE))) != 0) {

        __iob[i]->iob_fd = fd;

        __iob[i]->iob_mode = mflags;

        __iob[i]->iob_flags = 0;

        __iob[i]->iob_unget = 0;

 

               return __iob[i]; 

    } else

       {

       

        errno = ENOMEM;

              return (FILE*)(-2);

       }

            

 

//   return __iob[i];

       

}

 

 

The _fdopen function in my nut/os:

 

int fclose(FILE * stream)

{

    int rc = EOF;

    u_char i;

 

    /*

     * Search the list first to detect bad stream pointer.

     */

    if (stream == 0) {

        errno = EBADF;

        return EOF;

    }

    for (i = 0; __iob[i] != stream;) {

        if (++i >= FOPEN_MAX) {

            errno = EBADF;

            return EOF;

        }

    }

 

    /*

     * Ignore unopened standard streams.

     */

    //if ((void *) stream < RAMSTART)

    //    return 0;

 

    /*

     * Close the file or device.

     */

    if (_close(stream->iob_fd) == 0)

        rc = 0;

    free(stream);

    __iob[i] = 0;

 

    return rc;

}

 

 

 

 

 



------------------------------

Message: 2
Date: Thu, 12 Nov 2009 09:17:32 +0100
From: Harald Kipp <harald.kipp at egnite.de>
Subject: Re: [En-Nut-Discussion] _fdopen failed to create the stream
	on the socket
To: "Ethernut User Chat (English)" <en-nut-discussion at egnite.de>
Message-ID: <4AFBC49C.8010606 at egnite.de>
Content-Type: text/plain; charset=ISO-8859-1

Ma-Prokop, Yuhong wrote:

> But fclose function was called everytime after the successful _fdopen.
> Then i found out that the fclose (as following) returns sometimes "255"
> instead of "0" as it should be, so the existing stream cannot be closed,
> then until the maximal streams are opened, no further clients-request
> shall be processed!

Hong,

can you please provide some more information.

1. Nut/OS version
2. Target CPU
3. File system

> Does somebody have the same problem with nut/os webserver?

Our online reference demo at

http://ethernut.microweb.org/

currently has an uptime of > 1 month. It needs to be restarted only to
clear the spam from the guest book. In general it looks quite reliable.

Harald

PS: I recently discovered 2 serious bugs in Nut/OS for 32-bit CPUs. But
the problems are different. More on this later.


------------------------------

Message: 3
Date: Thu, 12 Nov 2009 10:10:44 +0100
From: Harald Kipp <harald.kipp at egnite.de>
Subject: Re: [En-Nut-Discussion] Timing issues on Ethernut 1.3 (AVR)
To: "Ethernut User Chat (English)" <en-nut-discussion at egnite.de>
Message-ID: <4AFBD114.3070905 at egnite.de>
Content-Type: text/plain; charset=ISO-8859-1

Hi Daniel,

Daniel wrote:

> Issue 1, NutGetMillis()
> =======================

I tried this  one:

#include <dev/board.h>
#include <sys/thread.h>
#include <sys/timer.h>

#include <stdio.h>
#include <io.h>

THREAD(Thread, arg)
{
    for (;;) {
        uint32_t start = NutGetMillis();
        uint32_t end = start + 500;
        uint16_t i = 0;

        printf("Start Millis %p: %lu ms\n", arg, NutGetMillis());
        do {
            NutThreadYield();
            i++;
            if (i > 500) {
                printf("Current Millis %p: %lu ms\n", arg, NutGetMillis());
                i = 0;
            }
        } while(NutGetMillis() < end);
        printf("  End Millis %p: %lu ms\n", arg, NutGetMillis());
    }
}

int main(void)
{
    uint32_t baud = 115200;
    int i;

    NutRegisterDevice(&DEV_DEBUG, 0, 0);
    freopen(DEV_DEBUG_NAME, "w", stdout);
    _ioctl(_fileno(stdout), UART_SETSPEED, &baud);

    puts("\nTest Millis");

    for (i = 1; i <= 10; i++) {
        NutThreadCreate("th", Thread, (void *)i, 512);
    }

    for (;;) {
        NutSleep(1000);
    }
    return 0;
}

It works as expected:

Test Millis
Start Millis 0x1: 5 ms
Start Millis 0x2: 7 ms
Start Millis 0x3: 9 ms
Start Millis 0x4: 11 ms
Start Millis 0x5: 13 ms
Start Millis 0x6: 15 ms
Start Millis 0x7: 17 ms
Start Millis 0x8: 20 ms
Start Millis 0x9: 22 ms
Start Millis 0xa: 24 ms
Current Millis 0x1: 109 ms
Current Millis 0x2: 111 ms
Current Millis 0x3: 114 ms
Current Millis 0x4: 116 ms
Current Millis 0x5: 119 ms
Current Millis 0x6: 121 ms
Current Millis 0x7: 124 ms
Current Millis 0x8: 126 ms
Current Millis 0x9: 129 ms
Current Millis 0xa: 131 ms
Current Millis 0x1: 218 ms
Current Millis 0x2: 220 ms
...
  End Millis 0x1: 505 ms
Start Millis 0x1: 507 ms
  End Millis 0x2: 509 ms
Start Millis 0x2: 511 ms
  End Millis 0x3: 514 ms
Start Millis 0x3: 516 ms
  End Millis 0x4: 518 ms
Start Millis 0x4: 520 ms
  End Millis 0x5: 523 ms
Start Millis 0x5: 525 ms
  End Millis 0x6: 527 ms
Start Millis 0x6: 529 ms
  End Millis 0x7: 532 ms
Start Millis 0x7: 534 ms
  End Millis 0x8: 536 ms
Start Millis 0x8: 539 ms
  End Millis 0x9: 541 ms
Start Millis 0x9: 543 ms
  End Millis 0xa: 545 ms
Start Millis 0xa: 548 ms
...

May be in your application you should check entry and return time of
NutThreadYield(). Possibly another thread occupies the CPU for too long
time.

Harald

PS: I tested on Ethernut 3 (ARM), but AVR should work similar.



------------------------------

Message: 4
Date: Thu, 12 Nov 2009 10:28:31 +0100
From: Harald Kipp <harald.kipp at egnite.de>
Subject: Re: [En-Nut-Discussion] Timing issues on Ethernut 1.3 (AVR)
To: "Ethernut User Chat (English)" <en-nut-discussion at egnite.de>
Message-ID: <4AFBD53F.6060904 at egnite.de>
Content-Type: text/plain; charset=ISO-8859-1

Daniel wrote:

> Issue 2, NutGetTickCount()
> ======================

> The only hint i have is that I'm using the _delay_us(x) function, which is
> not from Ethernut. Maybe there`s the problem?

Could be. In my previous example I used DEV_DEBUG, a polling driver,
which will never release the CPU. Thus, each thread is blocked until the
running thread calls NutThreadYield(). The same is true for _delay_us(x).

As long as you are working with resolutions of milliseconds, you should
use Nut/OS events and timers, because they will release the CPU.

If you need higher resolutions, you may use a native timer interrupts
for polling, if possible. If the interrupt routine detects a change, it
calls NutEventPostFromIrq() to wake up a thread. In your example the
status change will be detected by the timer interrupt routine and the
thread will wait for a change in NutEventWait(). The optimal solution
is, of course, if the status change can be detected by a dedicated
interrupt, avoiding timer interrupt polling.

Keep in mind: As long as nothing happens, good application will run the
idle thread. Polling is bad for cooperative systems like Nut/OS.

Harald


------------------------------

Message: 5
Date: Thu, 12 Nov 2009 10:54:00 +0100
From: Harald Kipp <harald.kipp at egnite.de>
Subject: [En-Nut-Discussion] Suggested modification to nut\net\tcpsm.c
	again
To: "Ethernut User Chat (English)" <en-nut-discussion at egnite.de>
Message-ID: <4AFBDB38.3030300 at egnite.de>
Content-Type: text/plain; charset=ISO-8859-15

Some time ago Zack suggested a modification of the TCP state machine:

http://lists.egnite.de/pipermail/en-nut-discussion/2007-May/008089.html

I assume, that this one fixed the problem at that time. However, recent
tests showed, that the problem is back again.

I do not have a proof, just a strong feeling that somehow the way
changed, the GNU compiler does calculations. Wasn't there similar fix
required during the last months? I'm currently using GCC 4.4.2.

Unfortunately the problem now appears more often after

http://ethernut.svn.sourceforge.net/viewvc/ethernut/trunk/nut/net/tcpout.c?r1=1751&r2=2082

because so_retran_time may be 1 ms ahead.

As a result, Ethernut sends duplicate segments quite often.

Anyone else observed something similar with GCC calculation routines?

The following change seems to fix it.

/*
 * Process retransmit timer.
 */
if (sock->so_tx_nbq && sock->so_retran_time) {
  uint16_t millis = (uint16_t)NutGetMillis();
  uint16_t diff = millis > sock->so_retran_time ? millis -
sock->so_retran_time : sock->so_retran_time - millis;
  if (diff >= sock->so_rtto) {
    NutTcpStateRetranTimeout(sock);
  }
}

I'm afraid, that there are other parts of the OS/Net code failing with
the latest GCC.

Harald




------------------------------

Message: 6
Date: Thu, 12 Nov 2009 11:54:38 +0100
From: Malte Marwedel <m.marwedel at onlinehome.de>
Subject: [En-Nut-Discussion] FTP server fails with very small files
To: "Ethernut User Chat (English)" <en-nut-discussion at egnite.de>
Message-ID: <4AFBE96E.3000006 at onlinehome.de>
Content-Type: text/plain; charset=UTF-8; format=flowed

Hello,
I observed, that putting very small files (less than 54 bytes in size) 
to a board with Nut/OS results in a "550 Failed" with the ftp server.

I tried to find the cause of the problem and discovered that 
NutFtpDataConnect retuns 0 because the NutTcpConnect call returns -1.
I further observed that the error goes away as soon as I placed some 
debug outputs before the NutFtpDataConnect call. So, for me it looks 
like a timing issue. Can someone verify this problem?
My system is: Arthernet board with Nut/OS 4.8.0 using gcc 4.3.2

Malte


------------------------------

_______________________________________________
http://lists.egnite.de/mailman/listinfo/en-nut-discussion


End of En-Nut-Discussion Digest, Vol 73, Issue 11
*************************************************


More information about the En-Nut-Discussion mailing list