Re: Porting old streambuf code to current C++ library
- From: John Kerich <jkerich@xxxxxxxxxxx>
- Date: Wed, 25 Jun 2008 05:36:58 -0700 (PDT)
After debugging the old code to see what it was doing I found that the
that base() and ebuf() where returning the start and start
+RWNET_BUFSIZE addresses. The pioner calls to setg and setp where
null until it initialized them. For example:
p= 0x7e3228
setb(0x7E3228, 0x7e522C, 1)
base() -> 0x7E3228
ebuf() -> 0x7E522C
putStart -> 0x7e322C
setg(0x7e3228, 0x7e322C, 0x7e322C)
setp(0x7e422C, 0x7e522C)
The base() and ebuf() values seem to stay the same all the time, which
makes sense since the p array does change.
I decided not to do the &myBuffer[0] + myBuffer.size() to keep the
code as close to the orignal as possible so I added a mybase() and
myebuf() member to my class, as seen below, to do what the old base()
and ebuf() did, return the start and end +1 of the p array.
FoIpSocketStreambuf.h
#ifndef __FoIpSocketStreambuf_h
#define __FoIpSocketStreambuf_h
/
***************************************************************************
*
* FoIpSocketStreambuf.h
*
**************************************************************************/
/*
* SocketStreams: classes for iostream I/O using Sockets
*
*/
#include <streambuf>
#include <rw/network/RWSocket.h>
#include <rw/network/RWInetAddr.h>
#include <rw/network/RWInetHost.h>
#include <rw/network/RWInetPort.h>
#include <rw/network/RWSockAddr.h>
#include <rw/network/RWSockType.h>
#include <rw/network/RWSockAddrBase.h>
/*
* FoIpSocketStreambuf: A streambuf which is also a socket
* This code was cloned from RogueWaves RWPortalStreambuf
* changing their use of a RWPortal to our use of an RWSocket.
* This was done to implement Mcast/DataGram using net.h++. This
code
* is not using EcTypes and will not to ensure that the RW code
* does not break
*/
class FoIpSocketStreambuf : public std::streambuf {
public:
// Initialize and destroy the streambuf.
FoIpSocketStreambuf();
FoIpSocketStreambuf( RWSocket* p,
RWInetAddr inSendAddr,
RWSockAddr inRecvAddr);
~FoIpSocketStreambuf();
// Read/write using the socket
// once the buffer overflows. Here is
// where the action happens.
virtual int overflow(int = EOF);
virtual int underflow();
// Flush the buffer.
virtual int sync();
// Set the communications channel that we are writing into.
virtual void setSocket(RWSocket* p);
// Allow user to get at receive address.
// For UPD (DataGrams) this changes everytime
// data is receive on the socket.
RWSockAddr* getRecvAddr();
// Allow user to set send address.
// For UPD (DataGrams).
void setSendAddr(RWInetAddr inSendAddr);
// Return the start address of the buffer you allocated for setbuf
char * mybase();
//Save the start address of the buffer you allocated for setbuf
void mybase(char * new_base);
// Return end address + 1 of the buffer you allocated for setbuf
char * myebuf();
// Save the end address + 1 of the buffer you allocated for setbuf
void myebuf(char * new_ebuf);
// Are there bytes waiting to be proccess on the output stream?
int out_waiting();
protected:
// Here is where all the overflows and underflows go!
RWSocket* mySock;
// Mcast/DataGram stuff
RWInetAddr mySendAddr;
// Mcast/DataGram stuff
RWSockAddr myRecvAddr;
// Reset the get and put buffers
void resetbuf();
char * my_base;
char * my_ebuf;
};
#endif
In the class I added new member for the mybase and myebuf calls and
recreated the out_waiting() inline that was dropped in the new
streambuf library. The unbuffered() inline was replaced by
_C_is_unbuffered().
Hopefully it will work when I finally get to test it out in 6 or 8
months from now.
FoIpSocketStreambuf.C
include "FoIpSocketStreambuf.h"
#include <rw/rwerr.h>
static const int RWNET_BUFSIZE = 2*4096+4; // 1024 byte packets seems
ok
// resetbuf(): reset the buffers
// The streambuf's buffer consists of 4 bytes of putback area, then
// the get buffer, then the put buffer.
// This needs to be kept in synch with the buffer setting in
underflow.
//
void FoIpSocketStreambuf::resetbuf()
{
// The precondition implies that we don't allow unbuffered I/O (yet)
RWPRECONDITION( !myebuf() && !mybase() && myebuf()-mybase()>6 );
// The put area starts a bit more than half way along the buffer
char *putStart = mybase() + (myebuf()-mybase()-4)/2 + 4;
// Set the get pointer to the beginning of the buffer.
setg(mybase(), mybase()+4, mybase()+4);
// Set the put pointer from the start of put area to the end of
buffer
setp(putStart, myebuf());
}
FoIpSocketStreambuf::FoIpSocketStreambuf() :
my_base(NULL),
my_ebuf(NULL)
{
char *p = new char[RWNET_BUFSIZE];
if (p) { // hmmmm this seems broken with advent of exceptions
// Set the buffer area, from p to p + buffer size.
mybase(p);
myebuf(p+RWNET_BUFSIZE);
setbuf(p, RWNET_BUFSIZE); // dtor will delete buffer
resetbuf();
}
}
FoIpSocketStreambuf::FoIpSocketStreambuf(
RWSocket* s,
RWInetAddr inSendAddr,
RWSockAddr inRecvAddr) :
mySock(s),
mySendAddr(inSendAddr),
myRecvAddr(inRecvAddr),
my_base(NULL),
my_ebuf(NULL)
{
// allocate a buffer
char *p = new char[RWNET_BUFSIZE];
if (p) { // hmmmm this seems broken with advent of exceptions
// Set the buffer area, from p to p + buffer size.
mybase(p);
myebuf(p+RWNET_BUFSIZE);
setbuf(p, RWNET_BUFSIZE); // dtor will delete buffer
resetbuf();
}
}
FoIpSocketStreambuf::~FoIpSocketStreambuf()
{
// If there's any data to be written,
// force write on socket.
sync();
}
int FoIpSocketStreambuf::overflow(int c)
{
// Check that we're not buffered or not at start of buffer
if ( _C_is_unbuffered() || !mybase() )
{
if (c!=EOF)
{
char theChar = c;
mySock->sendto(&theChar,1,mySendAddr);
}
}
else
{
// Send data to mySendAddr, from start of put area, the number of
// unflushed characters.
mySock->sendto(pbase(),out_waiting(),mySendAddr);
// Init put pointers, start of put area, end of put area
setp(pbase(),epptr());
if (c!=EOF)
{
// Put one character.
sputc(c);
}
}
return 1;
}
int FoIpSocketStreambuf::underflow()
{
if (in_avail())
{
return (unsigned char) *gptr();
} // no action needed
int c = EOF;// return value - default to EOF
if (!_C_is_unbuffered() && mybase())
{ // this is buffered
sync(); // flush output
// set up get area buffer pointers. compute buffer pointers as in
// resetbuf
char *getBegin = mybase()+4;
char *getEnd = pbase();
// Get a buffer full of data
int count = mySock->recvfrom(getBegin,getEnd-
getBegin,&myRecvAddr);
setg(mybase(), getBegin, getBegin+count);
if (count)
{
c = (unsigned char) *gptr();
}
}
else
{ // not buffered
// Note that the throw below will not be thrown unless this class
// is changed because all destructors allocate a buffer.
RWTHROW( RWInternalErr("FoIpSocketStreambuf: Sorry - unbuffered
input not yet implemented") );
}
return c;
}
int FoIpSocketStreambuf::sync()
{
// If the number of characters waiting to be sent
// is greater than zero...
if (out_waiting())
{
// Force data to be written on socket
if (overflow(EOF) == EOF)
{
return EOF;
}
}
// Commented out the flushing of the input buffer.
// It seems weird to flush the input buffer for a portal, because
// you can never get that input back again. The ANSI std is
// not clear on what the correct approach is.
#if 0
else if (in_avail())
{
setg(eback(), gptr(), gptr());
setp(gptr(), gptr());
}
#endif
return 0;
}
void FoIpSocketStreambuf::setSocket(RWSocket* p)
{
sync();
mySock = p;
}
RWSockAddr*
FoIpSocketStreambuf::getRecvAddr()
{
return (&myRecvAddr);
}
void
FoIpSocketStreambuf::setSendAddr(
RWInetAddr inSendAddr)
{
mySendAddr = inSendAddr;
}
/*
FoIpSocketStreambuf::mybase
Description: Save the start address of the buffer you allocated for
setbuf
return - The start address of teh buffer you allocated for setbuf
*/
char *
FoIpSocketStreambuf::mybase ()
{
return my_base;
}
/*
FoIpSocketStreambuf::mybase
Description: Return the start address of the buffer you allocated
for setbuf
return - The start address of the buffer you allocated for setbuf
*/
void
FoIpSocketStreambuf::mybase (char * new_base)
{
my_base = new_base;
}
/*
FoIpSocketStreambuf::myebuf
Description: Return end address + 1 of the buffer you allocated for
setbuf
return - The end address + 1 of the buffer you allocated for setbuf
*/
char *
FoIpSocketStreambuf::myebuf()
{
return my_ebuf;
}
/*
FoIpSocketStreambuf::myebuf
Description: Save the end address + 1 of the buffer you allocated
for setbuf
return - The end address of the buffer you allocated for setbuf
*/
void
FoIpSocketStreambuf::myebuf (char * new_ebuf)
{
my_ebuf = new_ebuf;
}
/*
FoIpSocketStreambuf::out_waiting
Description: Are there bytes waiting to be proccess on the output
stream?
return - 0 = not waiting, >0 bytes waiting
*/
int
FoIpSocketStreambuf::out_waiting()
{
return pptr() ? pptr() - pbase() : 0;
}
.
- References:
- Porting old streambuf code to current C++ library
- From: John Kerich
- Re: Porting old streambuf code to current C++ library
- From: James Kanze
- Porting old streambuf code to current C++ library
- Prev by Date: Re: How long does read(2) wait before an EAGAIN is thrown?
- Next by Date: Re: web server with pool of thread
- Previous by thread: Re: Porting old streambuf code to current C++ library
- Next by thread: Searching a small file database
- Index(es):
Relevant Pages
|