|
From: John Kerich on 24 Jun 2008 11:50 I am trying to port exist code to a Linux box. The problem is the code is using the old C++ library classes and some of the calls are now illegal. The class that I am having problems with is declared as "class FoIpSocketStreambuf : public streambuf {" in its include file and it wants to modify the streambuf address. Here is the problem area: // 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( ebuf()!=0 && base()!=0 && ebuf()-base()>6 ); <== rogue wave call for under/over flow // The put area starts a bit more than half way along the buffer char *putStart = base() + (ebuf()-base()-4)/2 + 4; // Set the get pointer to the beginning of the buffer. setg(base(),base()+4,base()+4); // Set the put pointer from the start of put area to the end of buffer setp(putStart,ebuf()); } FoIpSocketStreambuf::FoIpSocketStreambuf() { 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. setb(p, p+RWNET_BUFSIZE, 1); // dtor will delete buffer resetbuf(); } } As you can see it is using setb be to create a buffer area. Then in reset() it gets the start and end address of the stream and after some math is calling setp and setg with new start and end addresses. In the new C++ library setb(), ebuf(), and base() can no longer be directly called anymore. I can see in the new library that setb was replaced with setbuff or pubsetbuff, but I can't find anything that tells me what the member is doing when called. For example is it calling/setting setp or setg. The next problem is what to replace the base() and ebuf() calls with. I can't find anything that does the same thing in the new library. From the documents I have read, I think setbuf() is calling setp() and setg() but that's just a guess. Does anyone know how to port this code?
From: James Kanze on 25 Jun 2008 05:12 On Jun 24, 5:50 pm, John Kerich <jker...(a)sgt-inc.com> wrote: > I am trying to port exist code to a Linux box. The problem is > the code is using the old C++ library classes and some of the > calls are now illegal. Or maybe never were legal, or maybe were only legal with one specific implementation:-). > The class that I am having problems with is declared as "class > FoIpSocketStreambuf : public streambuf {" in its include file > and it wants to modify the streambuf address. Here is the > problem area: > // 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( ebuf()!=0 && base()!=0 && ebuf()-base()>6 ); <== > rogue wave call for under/over flow > // The put area starts a bit more than half way along the buffer > char *putStart = base() + (ebuf()-base()-4)/2 + 4; > // Set the get pointer to the beginning of the buffer. > setg(base(),base()+4,base()+4); > // Set the put pointer from the start of put area to the end of > buffer > setp(putStart,ebuf()); > } > FoIpSocketStreambuf::FoIpSocketStreambuf() > { > 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. More to the point, why isn't char[ RWNET_BUFSIZE ] declared directly as a member, skipping the dynamic allocation completely? Otherwise, if RWNET_BUFSIZE isn't a compile time constant, I'd use an std::vector<char> member to manage it. > setb(p, p+RWNET_BUFSIZE, 1); // dtor will delete buffer > resetbuf(); > } > } > As you can see it is using setb be to create a buffer area. > Then in reset() it gets the start and end address of the > stream and after some math is calling setp and setg with new > start and end addresses. I'm not too sure (it's been a long time since I used the classical iostreams), but some of these functions look like extensions even in classical iostream. In general, the streambuf manages two sets of buffer pointers, which may or may not point to the same buffers. (In the case of a socket streambuf, they should probably NOT point to the same areas.) The functions you refer to seem to be concerned with managing a global buffer, from which the get and put area buffers are defined. The standard streambuf does not have any support for this; you can very easily use two separate allocations for the get and put areas, if that's what you want. In this particular case, what I'd probably do is add an std::vector< char > member to the class, then rewrite the constructor to be FoIpSocketStreambuf::FoIpSocketStreambuf() : myBuffer( RWNET_BUFSIZE ) { resetbuf() ; } and in resetbuf(), replace base() with &myBuffer[0], and ebuf() with "&myBuffer[0] + myBuffer.size()". > In the new C++ library setb(), ebuf(), and base() can no longer be > directly called anymore. I can see in the new library that setb was > replaced with setbuff or pubsetbuff, but I can't find anything that > tells me what the member is doing when called. pubsetbuf just calls setbuf, which is a virtual function. By default, unless you've overridden it, it does nothing. The pubsetbuf/setbuf interface is designed so that client code can specify a buffer, in derived streambuf's where that might make sense. Since your class provides a buffer itself, it doesn't make sense, so you should just ignore them. > For example is it calling/setting setp or setg. The next > problem is what to replace the base() and ebuf() calls with. > I can't find anything that does the same thing in the new > library. That's because there isn't any global buffer handling in the standard library. (I don't remember any in the classical iostream library either; it's possible that this is just a Rogue Wave extension.) From the code you've posted, however, and some familiarity with the streambuf naming conventions, it would seem that all they do is set or return pointers to the beginning and the end of some common buffer, shared between reading and writing; given the code, it would also seem that they don't do anything else; that you still have to position the pointers for the get and the put areas. If you use an std::vector<char> as your buffer, then basically, the two pointers correspond to &buf[0] and &buf[0]+buf.size(). (If you don't use std::vector, then just declare two pointers, and set and access them manually.) -- James Kanze (GABI Software) email:james.kanze(a)gmail.com Conseils en informatique orientée objet/ Beratung in objektorientierter Datenverarbeitung 9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
From: John Kerich on 25 Jun 2008 08:36 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; }
|
Pages: 1 Prev: HP-UX Vs Solaris Shared memory Next: Searching a small file database |