Re: Porting old streambuf code to current C++ library



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;
}
.



Relevant Pages

  • [PATCH] cpm_uart: Fix dpram allocation and non-console uarts
    ... Makes non-console UART work on both 8xx and 82xx ... static unsigned int cpm_uart_tx_empty(struct uart_port *port) ... /* Write back buffer pointer */ ... * Allocate DP-Ram and memory buffers. ...
    (Linux-Kernel)
  • Re: Access violation with heap memory
    ... I'm getting a runtime access violation using heap memory that was ... Now, when I try to access the buffer in the main function, I ... Why are you using 'char'? ... Note that there is no need to allocate storage until you are in the FillBuf, ...
    (microsoft.public.vc.mfc)
  • Re: [PATCH 0/3]HTLB mapping for drivers (take 2)
    ... It sounds like this patch set working towards the same goal as my ... so the buffer is in normal memory. ... is responsible for populating a buffer for sending to a device. ... Allocate memory. ...
    (Linux-Kernel)
  • Re: perfmon2 vector argument question
    ... into a kernel buffer. ... the vector must be copied into a kernel-level buffer. ... because kmalloc/kfree are expensive. ... Another approach that was suggested to me is to allocate on demand but not kfree ...
    (Linux-Kernel)
  • Re: [RFC v2][PATCH 2/9] General infrastructure for checkpoint restart
    ... kmalloc a temporary buffer and flush immediately. ... Only after the container resumes ... (This is also useful in case you want to keep the checkpoint image entirely ... provides a shortcut to allocate space directly on the buffer, ...
    (Linux-Kernel)