Boost logo

Boost :

From: mfdylan (dylan_at_[hidden])
Date: 2001-12-19 01:22:57


--- In boost_at_y..., "rtougher" <rtougher_at_y...> wrote:
> I've put "boost_sockets.hpp" in the sockets3 directory of the files
> section.
>
> All suggestions are welcome!
>

Here's a quick&dirty socketbuf template, better would be one that
derived from a streambuf that used an ABC interface to do the actual
read/write/availability checking (why the std library doesn't have
this I really don't understand). Your low-level socket class could
then derive from this.

struct socket_exception { };

template<class E, class T = std::char_traits<E> >
class basic_socketbuf : public std::basic_streambuf<E, T>
{
public:
        basic_socketbuf(int sock = 0, int bufsize = 4096)
                : m_socket(sock)
        {
                E* buf;
                buf = new E[bufsize];
                setg(buf, buf, buf);
                m_egbuf = buf + bufsize;
                buf = new E[bufsize]; // exception safety? huh?
                setp(buf, buf + bufsize);
        }
        virtual ~basic_socketbuf()
        {
                delete [] eback();
                delete [] pbase();
                closesocket(m_socket);
        }
        unsigned long avail() const
        {
                if (gptr() < egptr())
                        return egptr() - gptr();
                u_long ret = 0;
                ioctlsocket(m_socket, FIONREAD, &ret);
                return ret;
        }
protected:
        virtual int_type overflow(int_type c = T::eof())
        {
                if (T::eq_int_type(T::eof(), c))
                        return T::not_eof(c);
                if (pptr() < epptr())
                {
                        *pptr() = T::to_char_type(c);
                        if (c == '\n')
                                sync();
                }
                else
                        sync();
                return c;
        }
        virtual int_type pbackfail(int_type c = T::eof())
        {
                if (eback() < gptr())
                {
                        gbump(-1);
                        if (!T::eq_int_type(T::eof(), c))
                                *gptr() = c;
                        return T::not_eof(c);
                }
                return T::eof();
        }
        virtual int_type underflow()
        {
                if (gptr() < egptr())
                        return T::to_int_type(*gptr());
                if (egbuf() - gptr() < gptr() - eback())
                        setg(eback(), eback(), eback());
                int r = recv(m_socket, gptr(), egbuf() - gptr(), 0);
                if (r == 0)
                        return T::eof();
                else if (r == -1)
                        throw socket_exception();
                setg(eback(), gptr(), gptr() + r);
                return *gptr();
        }
        virtual int sync()
        {
                int len = pptr() - pbase();
                if (send(m_socket, pbase(), len, 0) != len)
                        throw socket_exception();
                setp(pbase(), pbase(), epptr());
                return 0;
        }
private:
        inline E* egbuf() { return m_egbuf; }
        E* m_egbuf;
        int m_socket;
};

template<class E, class T = std::char_traits<E> >
class basic_socketstream : public std::basic_iostream<E, T>
{
public:
        explicit basic_socketstream(int sock) :
                std::basic_iostream<E, T>(&m_buf), m_buf(sock) { }
        basic_socketbuf<E, T>* rdbuf() const { return &m_buf; }
        unsigned long avail() const { return m_buf.avail(); }
private:
        basic_socketbuf<E, T> m_buf;
};

typedef basic_socketbuf<char> socketbuf;
typedef basic_socketbuf<wchar_t> wsocketbuf;
typedef basic_socketstream<char> socketstream;
typedef basic_socketstream<wchar_t> wsocketstream;


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk