You are not logged in.

#1 2008-05-12 07:40:47

android
Member
From: San Diego
Registered: 2003-04-18
Posts: 160

fflush(stdout) not flushing all output - SOLVED

Hi Out There,

I know this problem is as old as ditch water, but I'm still having it and this time nothing seems to be fixing it.

I have this C program that I want to use as a command line filter to turn data packets from a machine into readable format.

The packets come in from a cat /dev/tts/1 and are piped through the filter: cat /dev/tts/1 | ./pretty-packet

The output shows on stdout.

Most of the time the filtering is just converting the 0x02 into "<STX>" and the 0x03 into "<ETX>\n", the rest of the data is ascii and just dumps to stdout.

But there is one packet type, command 'u' that wants more detailed stateful filtering and formating. Part of the output for this packet just never shows up on stdout. It's just lost.

In the code the <STX> and command character are already putchar()'ed before testing for 'u', but on non 'u' packets everything shows up, and on 'u' packets a bunch of stuff never comes out. The next different packet just shows up and things keep going.

The source isn't too long:

//
// pretty-packet.c -jea 2008-05-11
//
// stateful packet filter to make machine packets ascii human readable
//  intended to be used as a pipe from the command line:
//
//  $ cat /dev/tts/1 | ./pretty-packet
//
//  or to save the output to a file:
//
//  $ cat /dev/tts/1 | ./pretty-packet > pretty-packet.log
//
//  build with:
//
//  $ cc pretty-packet.c -o pretty-packet
//
// also can read input directly from a named source
//  in this case the filter aspect is no longer used
//  and the command is run as:
//
//  $ ./pretty-packet
//
// uncomment the following line to build for direct reading
#define DIRECT_PORT

#include <stdio.h>

main ()
{
    unsigned int inchar;

    FILE * port;

#ifdef DIRECT_PORT
    port = fopen("/dev/tts/1", "r");
#else
    port = stdin;
#endif
    // set no buffering
    setvbuf(port, 0, _IONBF, 0);
    setvbuf(stdout, 0, _IONBF, 0);

    // state == 0 - print w/ STX and ETX
    // state == 1 - last inchar was STX
    // state == 2 - in 'u' start addr and count fields
    // state == 3 - in 'u' data fields
    unsigned int state=0;
    unsigned int count=0;

    while (1)
    {
        inchar = getc(port);

        if (state == 0)
        {
            switch (inchar)
            {
                case 0x02:
                    printf("<STX>");
                    state = 1;
                    break;

                case 0x03:
                    printf("<ETX>\n");
                    break;

                default:
                    putchar(inchar);
            }
        }
        else if (state == 1)
        {
            putchar(inchar);
            if (inchar == 'u' )
            {
                count = 0;
                state = 2;
            }
            else
            {
                state = 0;
            }
        }
        else if (state == 2)
        {
            putchar(inchar);
            if (count == 5)
            {
                putchar('\n');
                count++;
            }
            else if (count == 8)
            {
                putchar('\n');
                count = 0;
                state = 3;
            }
            else
            {
                count++;
            }
        }
        else if (state == 3)
        {
            if (inchar == 0x03)
            {
                printf("<ETX>\n");
                count = 0;
                state = 0;
            }
            else
            {
                if (count == 3)
                {
                    putchar(inchar);
                    putchar(' ');
                    count++;
                }
                else if (count == 8)
                {
                    putchar(inchar);
                    putchar('\n');
                    count = 0;
                }
                else
                {
                    putchar(inchar);
                    count++;
                }
            }
        }
        else
        {
            count = 0;
            state = 0;
        }
//        putchar(' ');
//        putchar(0x08);
        fflush(stdout);
//        sleep(0);
    }
}

The output looks like this:

<STX>p010001102000220003<ETX>
<STX>r0000C1<ETX>
<STX>oFFFFFF<ETX>
<STX>t12345678<ETX>
975F976C9762976C9764976D9764976C<STX>vFFFFFF<ETX>
<STX>oFFFFFF<ETX>
<STX>t12345678<ETX>
<STX>vFFFFFF<ETX>
<STX>oFFFFFF<ETX>
<STX>t12345678<ETX>

You can see the one line of output that doesn't start with <STX>, that's the 'u'. It's raw data is:

<STX>u000000000008975E976E9762976C9763976B9764976C<ETX>

where the <STX> = 0x02 and the <ETX> = 0x03

The 'o', 'p', 't' packets etc all work fine, but the 'u' looses it's <STX>u, the state == 2 data and the <ETX>\n, the state == 3 data is what shows up, but without the spaces and newlines that are supposed to be inserted.

What the heck, I've tried doing a bunch of the flushing tips I found, but no joy 8-(

Any help would be wildly appreciated!

android

Last edited by android (2008-05-12 08:23:37)

Offline

#2 2008-05-12 08:22:58

android
Member
From: San Diego
Registered: 2003-04-18
Posts: 160

Re: fflush(stdout) not flushing all output - SOLVED

Dang,

Isn't this always how it goes, after working on this for hours, I finally posted it here in desperation.

Then within the next hour the whole thing was solved.

It was actually problems in the formating of the data from the other end, as well as a few bugs in the code above that were made clear after the data started to flow.

Sorry for the random midnight delirium.

hasta pronto archers...

android

Offline

Board footer

Powered by FluxBB