Extending std::streambuf, how to reset the buffer once EOF has been reached?

Hello, I'm try to extend a std::streambuf, to forward the data over a socket.

The issue I am facing is that it does not reset the sync() state, once reached...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

class tcp_stream: public std::streambuf {
            char* buffer;
            const static std::size_t buffer_sz; //=4

...
            /**
             * Contract with streambuf
             * @Override
             */
            int overflow (int c);

            /**
             * Contract with streambuf
             * @Override
             */
            std::streamsize xsputn (const char* s, std::streamsize n);

            /**
             * Contract with streambuf
             * @Override
             */
            int sync();
...

}


And this is my implementation:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
    void tcp_stream::resetp(){ // invoked in the ctor
        setp(buffer, buffer + buffer_sz -1);
    }

    int tcp_stream::overflow(int ch){
        cout << "[overflow] " << ch << "; base pointer: " << uint64_t(pbase()) << " put pointer: " << uint64_t(pptr()) << endl;
        // edge case
        if( ch == traits_type::eof() || pptr() >= epptr() ) return traits_type::eof();
        cout << "added!" << endl;
        *pptr() = ch;
        pbump(1);
        return traits_type::to_int_type(ch);
    }

    int tcp_stream::sync(){
        cout << "[sync]" << endl;
        resetp();
        cout << "[sync end] base pointer: " << uint64_t(pbase()) << " put pointer: " << uint64_t(pptr()) << endl;
        return 0;
    }

    std::streamsize tcp_stream::xsputn (const char* s, std::streamsize n){
        cout << "[xsputn] (" << s << ", " << n << ")" << endl;
        ptrdiff_t diff = epptr() - pptr();
        memcpy(buffer, s, diff);
        pbump(diff);
        return diff;
    }


When it reaches the EOF, all the subsequent writings always invoke sync(). For instance:

1
2
3
4
5
6
7
8
    craic::tcp_stream tcps;
    clog.rdbuf(&tcps);

    std::string str;
    while( cin >> skipws >> str ){
        cout << "Input string: " << str << endl;
        clog << str.c_str() << endl;
    }

Assuming an internal buffer of 4 for my custom stringbuf, it produces:
1
2
3
4
5
6
7
8
9
10
11
12
alpha
Input string: alpha
[xsputn] (alpha, 5) // OK
[sync]
[sync end] base pointer: 8007936 put pointer: 8007936
beta
Input string: beta 
[sync] // It misses the write
[sync end] base pointer: 8007936 put pointer: 8007936
Input string: gamma
[sync] // And again...
[sync end] base pointer: 8007936 put pointer: 8007936


So.. how do I properly reset the buffer to the correct state?

Thanks,
Dean
Last edited on
Looks like for your buffer of 4, xsputn("alpha",5) returns 3, indicating that the output didn't complete. The stream gets its badbit set and doesn't do anything else (well, clang doesn't, gcc is calling sync)

xsputn is supposed to write everything, calling overflow as needed.

There's already a tcpstream in boost.asio, by the way.
Topic archived. No new replies allowed.