diff options
author | levine <levine@ae88bc3d-4319-0410-8dbf-d08b4c9d3795> | 1997-04-30 14:39:07 +0000 |
---|---|---|
committer | levine <levine@ae88bc3d-4319-0410-8dbf-d08b4c9d3795> | 1997-04-30 14:39:07 +0000 |
commit | 9770747c8ab4e7dac82aac61854b48d819460275 (patch) | |
tree | f70ed075e5b42275e2028fc64d0fea414bb24d88 /ace | |
parent | d150d631a443ca003c604190f4b0550489b816a2 (diff) | |
download | ATCD-9770747c8ab4e7dac82aac61854b48d819460275.tar.gz |
James' updates to IOStream
Diffstat (limited to 'ace')
-rw-r--r-- | ace/IOStream.cpp | 406 | ||||
-rw-r--r-- | ace/IOStream.h | 529 |
2 files changed, 713 insertions, 222 deletions
diff --git a/ace/IOStream.cpp b/ace/IOStream.cpp index e9e8384b917..79e28154d74 100644 --- a/ace/IOStream.cpp +++ b/ace/IOStream.cpp @@ -1,10 +1,15 @@ // IOStream.cpp // $Id$ -#if !defined (ACE_IOSTREAM_C) + +#ifndef ACE_IOSTREAM_C #define ACE_IOSTREAM_C #define ACE_BUILD_DLL #include "ace/IOStream.h" +#include "ace/Thread.h" +#include "ace/Handle_Set.h" + +/////////////////////////////////////////////////////////////////////////// /* Here's a simple example of how iostream's non-virtual operators can get you in a mess: @@ -79,8 +84,28 @@ // function will be invoked by the first >>. Since it returns // a myiostream&, the second >> will be invoked as desired. */ -template <class STREAM> int -ACE_Streambuf<STREAM>::underflow (void) + +/////////////////////////////////////////////////////////////////////////// + +#if ! defined( ACE_IOSTREAM_BUILDING_TEMPLATE ) + +ACE_Time_Value * +ACE_Streambuf_T::recv_timeout( ACE_Time_Value * tv ) +{ + ACE_Time_Value * rval = recv_timeout_; + if( tv ) + { + recv_timeout_value_ = *tv; + recv_timeout_ = &recv_timeout_value_; + } + else + recv_timeout_ = NULL; + + return rval; +} + +int +ACE_Streambuf_T::underflow (void) { // If input mode is not set, any attempt to read from the stream is // a failure. @@ -102,7 +127,7 @@ ACE_Streambuf<STREAM>::underflow (void) // explicitly handle deletion of the TWO buffers at destruction. // setb (this->eback_saved_, - this->eback_saved_ + ACE_STREAMBUF_SIZE, 0); + this->eback_saved_ + streambuf_size_, 0); // Using the new values for base (), initialize the get area. // This simply sets eback (), gptr () and egptr () described @@ -151,7 +176,7 @@ ACE_Streambuf<STREAM>::underflow (void) // to use our private get buffer. setb (this->eback_saved_, - this->eback_saved_ + ACE_STREAMBUF_SIZE, 0); + this->eback_saved_ + streambuf_size_, 0); // And restore the previous state of the get pointers. @@ -198,8 +223,8 @@ ACE_Streambuf<STREAM>::underflow (void) // Much of this is similar to underflow. I'll just hit the highlights // rather than repeating a lot of what you've already seen. -template <class STREAM> int -ACE_Streambuf<STREAM>::overflow (int c) +int +ACE_Streambuf_T::overflow (int c) { // Check to see if output is allowed at all. if (!(mode_ & ios::out)) @@ -211,7 +236,7 @@ ACE_Streambuf<STREAM>::overflow (int c) // Set base () to use put's private buffer. // setb (this->pbase_saved_, - this->pbase_saved_ + ACE_STREAMBUF_SIZE, 0); + this->pbase_saved_ + streambuf_size_, 0); // Set the put area using the new base () values. setp (base (), ebuf ()); @@ -236,7 +261,7 @@ ACE_Streambuf<STREAM>::overflow (int c) setg (0, 0, 0); // Reconfigure base () and restore the put pointers. - setb (pbase_saved_, pbase_saved_ + ACE_STREAMBUF_SIZE, 0); + setb (pbase_saved_, pbase_saved_ + streambuf_size_, 0); setp (base (), ebuf ()); // Save the new mode. @@ -246,8 +271,7 @@ ACE_Streambuf<STREAM>::overflow (int c) // If there is output to be flushed, do so now. We shouldn't // get here unless this is the case... - if (out_waiting () - && EOF == syncout ()) + if (out_waiting () && EOF == syncout ()) return EOF; } @@ -269,8 +293,8 @@ ACE_Streambuf<STREAM>::overflow (int c) // syncin -template <class STREAM> int -ACE_Streambuf<STREAM>::syncin (void) +int +ACE_Streambuf_T::syncin (void) { // As discussed, there really isn't any way to sync input from a socket-like // device. We specifially override this base-class function so that it won't @@ -278,12 +302,10 @@ ACE_Streambuf<STREAM>::syncin (void) return 0; } -///// ///// ///// ///// ///// ///// ///// ///// ///// ///// ///// ///// ///// ///// ///// - // syncout -template <class STREAM> int -ACE_Streambuf<STREAM>::syncout (void) +int +ACE_Streambuf_T::syncout (void) { // Unlike syncin, syncout is a doable thing. All we have to do is // write whatever is in the output buffer to the peer. flushbuf () @@ -295,8 +317,8 @@ ACE_Streambuf<STREAM>::syncout (void) return 0; } -template <class STREAM> int -ACE_Streambuf<STREAM>::sync (void) +int +ACE_Streambuf_T::sync (void) { // sync () is fairly traditional in that it syncs both input and output. // We could have omitted the call to syncin () but someday, we may want it @@ -314,23 +336,59 @@ ACE_Streambuf<STREAM>::sync (void) // flushbuf -template <class STREAM> int -ACE_Streambuf<STREAM>::flushbuf (void) +int +ACE_Streambuf_T::flushbuf (void) { // pptr() is one character beyond the last character put // into the buffer. pbase() points to the beginning of // the put buffer. Unless pptr() is greater than pbase() - // there is nothing to be sent to the peer_. + // there is nothing to be sent to the peer. // if( pptr() <= pbase() ) return 0; + // 4/12/97 -- JCEJ + // Kludge!!! + // If the remote side shuts down the connection, an attempt to + // send() to the remote will result in the message 'Broken Pipe' + // I think this is an OS message, I've tracked it down to the + // ACE_OS::write () function. That's the last one to be called + // before the message. I can only test this on Linux though, so + // I don't know how other systems will react. + // + // To get around this gracefully, I do a PEEK recv() with an + // immediate (nearly) timeout. recv() is much more graceful + // on it's failure. If we get -1 from recv() not due to timeout + // then we know we're SOL. + // + // Q: Is 'errno' threadsafe? Should the section below be a + // critical section? + // + // + // char tbuf[1]; + // ACE_Time_Value to(0,1); + // if( this->recv( tbuf, 1, MSG_PEEK, &to ) == -1 ) + // { + // if( errno != ETIME ) + // { + // perror("OOPS preparing to send to peer"); + // return EOF; + // } + // } + // + // The correct way to handle this is for the application to + // trap (and ignore?) SIGPIPE. Thanks to Amos Shapira + // for reminding me of this. + // + // Starting at the beginning of the buffer, send as much - // data as there is waiting. send_n guarantees that all + // data as there is waiting. send guarantees that all // of the data will be sent or an error will be returned. // - if( peer_->send_n( pbase(), pptr() - pbase() ) == -1 ) + if( this->send( pbase(), pptr() - pbase() ) == -1 ) + { return EOF; + } // Now that we've sent everything in the output buffer, we reset the // buffer pointers to appear empty. @@ -340,86 +398,104 @@ ACE_Streambuf<STREAM>::flushbuf (void) return 0; } -template <class STREAM> int -ACE_Streambuf<STREAM>::get_one_byte (void) +int +ACE_Streambuf_T::get_one_byte ( void ) { - char * p = base (); - ssize_t i = peer_->recv_n (p, 1); - // The recv function will return immediately if there is no data // waiting. So, we use recv_n to wait for exactly one byte to come // from the peer. Later, we can use recv to see if there is // anything else in the buffer. (Ok, we could use flags to tell it // to block but I like this better.) - if (i != 1) + if( this->recv_n( base(), 1, MSG_PEEK, recv_timeout_ ) != 1 ) return EOF; - // Set the get pointers to indicate that we've got new data. - setg (base (), base (), base () + 1); - return 1; } -template <class STREAM> int -ACE_Streambuf<STREAM>::fillbuf (void) +int +ACE_Streambuf_T::fillbuf (void) + // This will be called when the read (get) buffer has been + // exhausted (ie -- gptr == egptr) { - char *p; - - // Invoke recv_n to get at least one byte from the remote. This + // Invoke recv_n to get exactly one byte from the remote. This // will block until something shows up. - - if (this->get_one_byte () == EOF) + // + if( get_one_byte() == EOF ) return EOF; // Now, get whatever else may be in the buffer. This will return if - // there is nothing in the buffer. Notice that we can only read - // blen ()-1 bytes since we've already read one via <get_one_byte> + // there is nothing in the buffer. - p = base () + 1; - ssize_t t = peer_->recv (p, blen () - 1); + int bc = this->recv ( base(), blen(), recv_timeout_ ); // recv will give us -1 if there was a problem. If there was // nothing waiting to be read, it will give us 0. That isn't an // error. - if (t++ < 0) + if (bc < 0) return EOF; // Move the get pointer to reflect the number of bytes we just read. - setg (base (), base (), base () + t); + setg (base (), base (), base () + bc ); // Return the byte-read-count including the one from <get_one_byte> - return t; + return bc; } -// We will be given a STREAM by the iostream object which creates us. -// See the ACE_IOStream template for how that works. Like other -// streambuf objects, we can be input-only, output-only or both. - -template <class STREAM> -ACE_Streambuf<STREAM>::ACE_Streambuf (STREAM *peer, int io_mode) - : peer_ (peer), - get_mode_ (1), +ACE_Streambuf_T::ACE_Streambuf_T (u_int streambuf_size, int io_mode) + : get_mode_ (1), put_mode_ (2), - mode_ (io_mode) + mode_ (io_mode), + streambuf_size_ (streambuf_size), + recv_timeout_(NULL) { - // A streambuf allows for unbuffered IO where every character is - // read as requested and written as provided. To me, this seems - // terribly inefficient for socket-type operations, so I've disabled - // it. All of the work would be done by the underflow/overflow - // functions anyway and I haven't implemented anything there to - // support unbuffered IO. + (void)reset_get_buffer(); + (void)reset_put_buffer(); +} - this->unbuffered (0); +u_int ACE_Streambuf_T::streambuf_size(void) +{ + return streambuf_size_; +} - // Linebuffered is similar to unbuffered. Again, I don't have any - // need for this and I don't see the advantage. I believe this - // would have to be supported by underflow/overflow to be effective. -#if !defined (ACE_LACKS_LINEBUFFERED_STREAMBUF) - this->linebuffered (0); -#endif /* ! ACE_LACKS_LINEBUFFERED_STREAMBUF */ +u_int ACE_Streambuf_T::get_waiting(void) + // Return the number of bytes not yet gotten. + // eback + get_waiting = gptr +{ + return this->gptr_saved_ - this->eback_saved_; +} + +u_int ACE_Streambuf_T::get_avail(void) + // Return the number of bytes in the get area (includes some already gotten); + // eback + get_avail = egptr +{ + return this->egptr_saved_ - this->eback_saved_; +} + +u_int ACE_Streambuf_T::put_avail(void) + // Return the number of bytes to be 'put' onto the stream media. + // pbase + put_avail = pptr +{ + return this->pptr_saved_ - this->pbase_saved_; +} + +char * +ACE_Streambuf_T::reset_get_buffer(char * newBuffer, u_int _streambuf_size, u_int _gptr, u_int _egptr ) +// +// Typical usage: +// +// u_int newGptr = otherStream->get_waiting(); +// u_int newEgptr = otherStream->get_avail(); +// char * newBuf = otherStream->reset_get_buffer(); +// char * oldgetbuf = myStream->reset_get_buffer( newBuf, otherStream->streambuf_size(), newGptr, newEgptr ); +// +// 'myStream' now has the get buffer of 'otherStream' and can use it in any way. +// 'otherStream' now has a new, empty get buffer. +// +{ + char * rval = this->eback_saved_; // The get area is where the iostrem will get data from. This is // our read buffer. There are three pointers which describe the @@ -437,9 +513,40 @@ ACE_Streambuf<STREAM>::ACE_Streambuf (STREAM *peer, int io_mode) // the variables below. Initially, they all point to the beginning // of our read-dedicated buffer. // - ACE_NEW (this->eback_saved_, char[ACE_STREAMBUF_SIZE]); - this->gptr_saved_ = this->eback_saved_; - this->egptr_saved_ = this->eback_saved_; + if( newBuffer ) + { + if( streambuf_size_ != _streambuf_size ) + return NULL; + this->eback_saved_ = newBuffer; + } + else + { + ACE_NEW_RETURN (this->eback_saved_, char[streambuf_size_], 0); + } + + this->gptr_saved_ = this->eback_saved_ + _gptr; + this->egptr_saved_ = this->eback_saved_ + _egptr; + + // Disable the get area initially. This will cause underflow to be + // invoked on the first get operation. + setg (0, 0, 0); + + reset_base(); + + return rval; +} + +char * +ACE_Streambuf_T::reset_put_buffer(char * newBuffer, u_int _streambuf_size, u_int _pptr ) +// +// Typical usage: +// +// u_int newPptr = otherStream->put_avail(); +// char * newBuf = otherStream->reset_put_buffer(); +// char * oldputbuf = otherStream->reset_put_buffer( newBuf, otherStream->streambuf_size(), newPptr ); +// +{ + char * rval = this->pbase_saved_; // The put area is where the iostream will put data that needs to be // sent to the peer. This becomes our write buffer. The three @@ -454,18 +561,32 @@ ACE_Streambuf<STREAM>::ACE_Streambuf (STREAM *peer, int io_mode) // Again to switch quickly between modes, we keep copies of // these three pointers. // - ACE_NEW (this->pbase_saved_, char[ACE_STREAMBUF_SIZE]); - this->pptr_saved_ = this->pbase_saved_; - this->epptr_saved_ = this->pbase_saved_ + ACE_STREAMBUF_SIZE; + if( newBuffer ) + { + if( streambuf_size_ != _streambuf_size ) + return NULL; + this->pbase_saved_ = newBuffer; + } + else + { + ACE_NEW_RETURN (this->pbase_saved_, char[streambuf_size_], 0); + } - // Disable the get area initially. This will cause underflow to be - // invoked on the first get operation. - setg (0, 0, 0); + this->pptr_saved_ = this->pbase_saved_ + _pptr; + this->epptr_saved_ = this->pbase_saved_ + streambuf_size_; // Disable the put area. Overflow will be called by the first call // to any put operator. setp (0, 0); + reset_base(); + + return rval; +} + +void +ACE_Streambuf_T::reset_base(void) +{ // Until we experience the first get or put operation, we do not // know what our current IO mode is. this->cur_mode_ = 0; @@ -482,20 +603,61 @@ ACE_Streambuf<STREAM>::ACE_Streambuf (STREAM *peer, int io_mode) // would be deleted when the object destructs. Since we are providing // separate read/write buffers, it is up to us to manage their memory. -template <class STREAM> -ACE_Streambuf<STREAM>::~ACE_Streambuf (void) +ACE_Streambuf_T::~ACE_Streambuf_T (void) { delete [] this->eback_saved_; delete [] this->pbase_saved_; } +#endif // ACE_IOSTREAM_BUILDING_TEMPLATE + +/////////////////////////////////////////////////////////////////////////// + + +// We will be given a STREAM by the iostream object which creates us. +// See the ACE_IOStream template for how that works. Like other +// streambuf objects, we can be input-only, output-only or both. + +template <class STREAM> +ACE_Streambuf<STREAM>::ACE_Streambuf (STREAM *peer, u_int streambuf_size, int io_mode ) + : ACE_Streambuf_T( streambuf_size, io_mode ), peer_ (peer) +{ + // A streambuf allows for unbuffered IO where every character is + // read as requested and written as provided. To me, this seems + // terribly inefficient for socket-type operations, so I've disabled + // it. All of the work would be done by the underflow/overflow + // functions anyway and I haven't implemented anything there to + // support unbuffered IO. + + this->unbuffered (0); + + // Linebuffered is similar to unbuffered. Again, I don't have any + // need for this and I don't see the advantage. I believe this + // would have to be supported by underflow/overflow to be effective. +#if !defined (ACE_LACKS_LINEBUFFERED_STREAMBUF) + this->linebuffered (0); +#endif /* ! ACE_LACKS_LINEBUFFERED_STREAMBUF */ + +} + + +/////////////////////////////////////////////////////////////////////////// + + // The typical constructor. This will initiailze your STREAM and then // setup the iostream baseclass to use a custom streambuf based on // STREAM. template <class STREAM> -ACE_IOStream<STREAM>::ACE_IOStream (void) - : iostream (streambuf_ = new ACE_Streambuf<STREAM> ((STREAM *) this)) +ACE_IOStream<STREAM>::ACE_IOStream ( STREAM & stream, u_int streambuf_size ) + : iostream(streambuf_ = new ACE_Streambuf<STREAM> ((STREAM *) this, streambuf_size)), + STREAM(stream) +{ +} + +template <class STREAM> +ACE_IOStream<STREAM>::ACE_IOStream ( u_int streambuf_size ) + : iostream(streambuf_ = new ACE_Streambuf<STREAM> ((STREAM *) this, streambuf_size)) { } @@ -517,19 +679,54 @@ ACE_IOStream<STREAM>::close (void) return STREAM::close (); } -#if defined (__GNUC__) && !defined (CHORUS) +template <class STREAM> ACE_IOStream<STREAM> & +ACE_IOStream<STREAM>::operator>>(ACE_Time_Value *& tv ) +{ + ACE_Time_Value * old_tv = this->streambuf_->recv_timeout(tv); + tv = old_tv; + return *this; +} + +#if (defined(__GNUC__) && !defined (CHORUS)) || defined(ACE_WIN32) + // A simple string operator. The base iostream has 'em for char* but // that isn't always the best thing for a String. If we don't provide // our own here, we may not get what we want. template <class STREAM> ACE_IOStream<STREAM> & -ACE_IOStream<STREAM>::operator>> (String & v) +ACE_IOStream<STREAM>::operator>> (ACE_IOStream_String & v) +{ + if( ipfx0() ) + { + char c; + iostream::operator>> (c); + + for (v = c ; this->get (c) && !isspace (c) ; v += c) + continue; + } + + isfx(); + + return *this; +} + + +template <class STREAM> ACE_IOStream<STREAM> & +ACE_IOStream<STREAM>::operator<< (ACE_IOStream_String & v) { - char c; - iostream::operator>> (c); + if( opfx() ) + { +#if defined (ACE_WIN32) + for( int i = 0 ; i < v.GetLength() ; ++i ) +#else + for( u_int i = 0 ; i < (u_int)v.length() ; ++i ) +#endif + { + this->put( v[i] ); + } + } - for (v = c ; this->get (c) && !isspace (c) ; v += c) - continue; + osfx(); return *this; } @@ -542,6 +739,8 @@ ACE_IOStream<STREAM>::operator>> (String & v) template <class STREAM> ACE_IOStream<STREAM> & ACE_IOStream<STREAM>::operator>> (QuotedString & str) { + if( ipfx0() ) + { char c; if( !(*this >> c) ) // eat space up to the first char @@ -569,18 +768,37 @@ ACE_IOStream<STREAM>::operator>> (QuotedString & str) } } } + } + + isfx(); - return *this; + return *this; } template <class STREAM> ACE_IOStream<STREAM> & ACE_IOStream<STREAM>::operator<< (QuotedString & str) { - *this << '"'; - *this << (String&)str; - *this << '"'; - return *this; + if( opfx() ) + { + this->put('"'); + for( u_int i = 0 ; i < str.length() ; ++i ) + { + if( str[i] == '"' ) + this->put('\\'); + this->put( str[i] ); + } + this->put('"'); + } + + osfx(); + + return *this; } -#endif /* __GNUG__ */ + +/////////////////////////////////////////////////////////////////////////// + + +#endif /* (__GNUC__ && ! CHORUS) || ACE_WIN32 */ #endif /* ACE_IOSTREAM_C */ + diff --git a/ace/IOStream.h b/ace/IOStream.h index 45d08db7830..86865241ef6 100644 --- a/ace/IOStream.h +++ b/ace/IOStream.h @@ -17,30 +17,123 @@ // // ============================================================================ +/* + Changes 4/5/97 + + ACE_Streambuf_T + + New public functions added + + char * reset_get_buffer( char * newbuf, u_int bufsiz, u_int inuse ) + char * reset_put_buffer( char * newbuf, u_int bufsiz, u_int inuse ) + + Resets the get/put buffer and returns a pointer to the + previous buffer. + + If newbuf is not NULL and bufsiz matches the current + streambuf_size_ value, then the current buffer will + be replaced by newbuf. If the stream sizes do not match, + a NULL pointer is returned and the buffer left unchanged. + + If newbuf is NULL, a new buffer will be allocated from + the heap. + + This kind of thing is handy if you're chaining streams. + For instance, I have a stream built on a message queue + which marshals and sends data from one thread to another. + The receiving thread then sends that data to a peer() + via a stream built on a socket. It is more efficient + to simply replace the socket stream's put buffer with that + of the message queue rather than copying the data from + one to another. + + u_int streambuf_size( void ) + + Get the size of the stream buffers. Note that the get + and put buffers are the same size. + + New protected functions added + + void reset_base( void ) + + Resets the base() pointers which toggle between get + and put mode as well as the cur_mode_ value. + + Constructor changed + + Initialization of the get/put buffers was moved here from + the derived class/template ACE_Streambuf<...> + + At the same time, the new functions reset_get/put_buffer + are now used instead of the previous monolithic function. + + ACE_Streambuf<...> + + Constructor changed: + + Initialization of the get/put buffers has been moved to the + baseclass ACE_Streambuf_T. This will reduce template bloat + as well as giving us more functionality as described above. + */ + #if !defined (ACE_IOSTREAM_H) #define ACE_IOSTREAM_H #include "ace/OS.h" +#include "ace/INET_Addr.h" #include <iomanip.h> #if defined (__GNUC__) && !defined (CHORUS) #include <String.h> +typedef String ACE_IOStream_String; +#endif /* __GNUC__ */ +// +#if defined (ACE_WIN32) +typedef CString ACE_IOStream_String; +#endif /* ACE_WIN32 */ -class QuotedString : public String +#if defined(__GNUC__) || defined(ACE_WIN32) + +class QuotedString : public ACE_IOStream_String { public: - inline QuotedString & operator =(char c) { return (QuotedString&) String::operator=(c); } - inline QuotedString & operator =(char* c) { return (QuotedString&) String::operator=(c); } + inline QuotedString() { + *this = ""; + } + inline QuotedString(const char * c) { + *this = ACE_IOStream_String(c); + } + inline QuotedString(const ACE_IOStream_String& s) { + *this = s; + } + inline QuotedString& operator=(const ACE_IOStream_String& s) { + return (QuotedString&) ACE_IOStream_String::operator=(s); + } + inline QuotedString & operator =(const char c) { + return (QuotedString&) ACE_IOStream_String::operator=(c); + } + inline QuotedString & operator =(const char* c) { + return (QuotedString&) ACE_IOStream_String::operator=(c); + } + inline bool operator < (const QuotedString& s) const { + return *(ACE_IOStream_String *)this < (ACE_IOStream_String)s; + } +#if defined (ACE_WIN32) + inline int length(void) { + return this->GetLength(); + } +#endif }; -#endif /* __GNUC__ */ -template <class STREAM> -class ACE_Streambuf : public streambuf +#endif /* __GNUC__ || ACE_WIN32 */ + +/////////////////////////////////////////////////////////////////////////// + +class ACE_Export ACE_Streambuf_T : public streambuf // = TITLE // Create your custom streambuf by providing and ACE_*_Stream // object to this template. I have tested it with // ACE_SOCK_Stream and it should work fine for others as well. - // I'm hoping to add functionality for ACE_SOCK_Dgram soon... // // = DESCRIPTION // For any iostream object, the real work is done by the @@ -99,19 +192,51 @@ class ACE_Streambuf : public streambuf // "syncing" the input. It simply remains buffered. { public: - ACE_Streambuf (STREAM * peer, int io_mode = ios::in | ios::out); - // We will be given a STREAM by the iostream object which creates - // us. See the ACE_IOStream template for how that works. Like - // other streambuf objects, we can be input-only, output-only or - // both. - virtual ~ACE_Streambuf (void); + virtual ~ACE_Streambuf_T (void); // If the default allocation strategey were used the common buffer // would be deleted when the object destructs. Since we are // providing separate read/write buffers, it is up to us to manage // their memory. + ACE_Time_Value * recv_timeout( ACE_Time_Value * tv = NULL ); + // Get the current Time_Value pointer and provide a new one. + + char * reset_put_buffer(char * newBuffer = NULL, u_int _streambuf_size = 0, u_int _pptr = 0 ); + // Use this to allocate a new/different buffer for put operations. If you + // do not provide a buffer pointer, one will be allocated. That is the + // preferred method. If you do provide a buffer, the size must match that + // being used by the get buffer. + // If successful, you will receive a pointer to the current put buffer. + // It is your responsibility to delete this memory when you are done with it. + + u_int put_avail(void); + // Return the number of bytes to be 'put' onto the stream media. + // pbase + put_avail = pptr + + char * reset_get_buffer(char * newBuffer = NULL, u_int _streambuf_size = 0, u_int _gptr = 0, u_int _egptr = 0 ); + // Use this to allocate a new/different buffer for get operations. If you + // do not provide a buffer pointer, one will be allocated. That is the + // preferred method. If you do provide a buffer, the size must match that + // being used by the put buffer. + // If successful, you will receive a pointer to the current get buffer. + // It is your responsibility to delete this memory when you are done with it. + + u_int get_waiting(void); + // Return the number of bytes not yet gotten. + // eback + get_waiting = gptr + // + u_int get_avail(void); + // Return the number of bytes in the get area (includes some already gotten); + // eback + get_avail = egptr + // + + u_int streambuf_size(void); + // Query the streambuf for the size of it's buffers. + protected: + ACE_Streambuf_T (u_int streambuf_size, int io_mode); + virtual int sync (void); // Sync both input and output. See syncin/syncout below for // descriptions. @@ -123,10 +248,11 @@ protected: // The overflow function receives the character which caused the // overflow. -private: - STREAM *peer_; - // This will be our ACE_SOCK_Stream or similar object. + void reset_base(void); + // Resets the base() pointer and streambuf mode. This is + // used internally when get/put buffers are allocatd. +protected: // = Two pointer sets for manipulating the read/write areas. char *eback_saved_; char *gptr_saved_; @@ -146,6 +272,15 @@ private: // mode tells us if we're working for an istream, ostream, or // iostream. + const u_int streambuf_size_; + // This defines the size of the input and output buffers. It can + // be set by the object constructor. + + ACE_Time_Value recv_timeout_value_; + ACE_Time_Value * recv_timeout_; + // We want to allow the user to provide Time_Value pointers to + // prevent infinite blocking while waiting to receive data. + int syncin (void); // syncin is called when the input needs to be synced with the // source file. In a filebuf, this results in the seek() system @@ -168,28 +303,68 @@ private: // underflow. It will attempt to fill the read buffer from the // peer. - int get_one_byte (void); + virtual int get_one_byte ( ); // Used by fillbuf and others to get exactly one byte from the peer. // recv_n is used to be sure we block until something is available. + // It is virtual because we really need to override it for + // datagram-derived objects. + + virtual ssize_t send ( char * buf, ssize_t len ) = 0; + virtual ssize_t recv ( char * buf, ssize_t len, ACE_Time_Value * tv = NULL ) = 0; + virtual ssize_t recv ( char * buf, ssize_t len, int flags, ACE_Time_Value * tv = NULL ) = 0; + virtual ssize_t recv_n( char * buf, ssize_t len, int flags = 0, ACE_Time_Value * tv = NULL ) = 0; + // Stream connections and "unconnected connections" (ie -- datagrams) + // need to work just a little differently. We derive custom + // Streambuf objects for them and provide these functions at that time. + + virtual ACE_HANDLE get_handle(void) + { + return 0; + } }; -// This macro defines the get operator for class MT into datatype DT. -// We will use it below to quickly override most (all?) iostream get -// operators. Notice how the ipfx() and isfx() functions are used. +/////////////////////////////////////////////////////////////////////////// -#define ACE_OPERATORG(MT,DT) \ - inline virtual MT& operator>> (DT v) { \ - if (ipfx ()) iostream::operator>> (v); isfx (); return *this; \ - } +template <class STREAM> +class ACE_Streambuf : public ACE_Streambuf_T +{ +public: + ACE_Streambuf (STREAM * peer, u_int streambuf_size = ACE_STREAMBUF_SIZE, int io_mode = ios::in | ios::out); + // We will be given a STREAM by the iostream object which creates + // us. See the ACE_IOStream template for how that works. Like + // other streambuf objects, we can be input-only, output-only or + // both. -// This macro defines the put operator for class MT into datatype DT. -// We will use it below to quickly override most (all?) iostream put -// operators. Notice how the opfx() and osfx() functions are used. + virtual ssize_t send ( char * buf, ssize_t len ) + { + return peer_->send_n(buf,len); + } + virtual ssize_t recv ( char * buf, ssize_t len, ACE_Time_Value * tv = NULL ) + { + return this->recv( buf, len, 0, tv ); + } + virtual ssize_t recv ( char * buf, ssize_t len, int flags, ACE_Time_Value * tv = NULL ) + { + ssize_t rval = peer_->recv(buf,len,flags,tv); + return rval; + } + virtual ssize_t recv_n( char * buf, ssize_t len, int flags = 0, ACE_Time_Value * tv = NULL ) + { + ssize_t rval = peer_->recv_n(buf,len,flags,tv); + return rval; + } + +protected: + STREAM * peer_; + // This will be our ACE_SOCK_Stream or similar object. + + virtual ACE_HANDLE get_handle(void) + { + return peer_ ? peer_->get_handle() : 0 ; + } +}; -#define ACE_OPERATORP(MT,DT) \ - inline virtual MT& operator<< (DT v) { \ - if (opfx ()) iostream::operator<< (v); osfx (); return *this; \ - } +/////////////////////////////////////////////////////////////////////////// // These typedefs are provided by G++ (on some systems?) without the // trailing '_'. Since we can't count on 'em, I've defined them to @@ -204,83 +379,95 @@ typedef ostream& (*__omanip_)(ostream&); // // virtual MT& operator<<(ios& (*func)(ios&)) { (*func)(*this); return *this; } + + +// This macro defines the get operator for class MT into datatype DT. +// We will use it below to quickly override most (all?) iostream get +// operators. Notice how the ipfx() and isfx() functions are used. + +#define GET_SIG(MT,DT) inline virtual MT& operator>> (DT v) +#define GET_CODE { if (ipfx ()) iostream::operator>> (v); isfx (); return *this; } +#define GET_PROT(MT,DT,CODE) GET_SIG(MT,DT) CODE +#define GET_FUNC(MT,DT) GET_PROT(MT,DT,GET_CODE) + +// This macro defines the put operator for class MT into datatype DT. +// We will use it below to quickly override most (all?) iostream put +// operators. Notice how the opfx() and osfx() functions are used. + +#define PUT_SIG(MT,DT) inline virtual MT& operator<< (DT v) +#define PUT_CODE { if (opfx ()) iostream::operator<< (v); osfx (); return *this; } +#define PUT_PROT(MT,DT,CODE) PUT_SIG(MT,DT) CODE +#define PUT_FUNC(MT,DT) PUT_PROT(MT,DT,PUT_CODE) + + // These are necessary in case somebody wants to derive from us and // override one of these with a custom approach. +#define GET_FUNC_SET0(MT,CODE,CODE2) \ + GET_PROT(MT,short &,CODE) \ + GET_PROT(MT,u_short &,CODE) \ + GET_PROT(MT,int &,CODE) \ + GET_PROT(MT,u_int &,CODE) \ + GET_PROT(MT,long &,CODE) \ + GET_PROT(MT,u_long &,CODE) \ + GET_PROT(MT,float &,CODE) \ + GET_PROT(MT,double &,CODE) \ + GET_PROT(MT,long double &,CODE) \ + GET_PROT(MT,char &,CODE) \ + GET_PROT(MT,u_char &,CODE) \ + GET_PROT(MT,char *,CODE) \ + GET_PROT(MT,u_char *,CODE) \ + inline virtual MT& operator>>(__omanip_ func) CODE2 \ + inline virtual MT& operator>>(__manip_ func) CODE2 + +#define PUT_FUNC_SET0(MT,CODE,CODE2) \ + PUT_PROT(MT,short,CODE) \ + PUT_PROT(MT,u_short,CODE) \ + PUT_PROT(MT,int,CODE) \ + PUT_PROT(MT,u_int,CODE) \ + PUT_PROT(MT,long,CODE) \ + PUT_PROT(MT,u_long,CODE) \ + PUT_PROT(MT,float,CODE) \ + PUT_PROT(MT,double,CODE) \ + PUT_PROT(MT,char,CODE) \ + PUT_PROT(MT,u_char,CODE) \ + PUT_PROT(MT,const char *,CODE) \ + PUT_PROT(MT,const u_char *,CODE) \ + PUT_PROT(MT,const void *,CODE) \ + inline virtual MT& operator<<(__omanip_ func) CODE2 \ + inline virtual MT& operator<<(__manip_ func) CODE2 + + #if defined (ACE_LACKS_SIGNED_CHAR) -#define ACE_OPERATORG_SET(MT) \ - ACE_OPERATORG(MT,short &); \ - ACE_OPERATORG(MT,u_short &); \ - ACE_OPERATORG(MT,int &); \ - ACE_OPERATORG(MT,u_int &); \ - ACE_OPERATORG(MT,long &); \ - ACE_OPERATORG(MT,u_long &); \ - ACE_OPERATORG(MT,float &); \ - ACE_OPERATORG(MT,double &); \ - ACE_OPERATORG(MT,long double &); \ - ACE_OPERATORG(MT,char &) \ - ACE_OPERATORG(MT,u_char &); \ - ACE_OPERATORG(MT,char *) \ - ACE_OPERATORG(MT,u_char *); \ - virtual MT& operator>>(__omanip_ func) { (*func)(*this); return *this; } \ - virtual MT& operator>>(__manip_ func) { (*func)(*this); return *this; } - -#define ACE_OPERATORP_SET(MT) \ - ACE_OPERATORP(MT,short); \ - ACE_OPERATORP(MT,u_short); \ - ACE_OPERATORP(MT,int); \ - ACE_OPERATORP(MT,u_int); \ - ACE_OPERATORP(MT,long); \ - ACE_OPERATORP(MT,u_long); \ - ACE_OPERATORP(MT,float); \ - ACE_OPERATORP(MT,double); \ - ACE_OPERATORP(MT,char); \ - ACE_OPERATORP(MT,u_char); \ - ACE_OPERATORP(MT,const char *); \ - ACE_OPERATORP(MT,const u_char *); \ - ACE_OPERATORP(MT,const void *); \ - virtual MT& operator<<(__omanip_ func) { (*func)(*this); return *this; } \ - virtual MT& operator<<(__manip_ func) { (*func)(*this); return *this; } + #define GET_FUNC_SET1(MT,CODE,CODE2) GET_FUNC_SET0(MT,CODE,CODE2) + #define PUT_FUNC_SET1(MT,CODE,CODE2) PUT_FUNC_SET0(MT,CODE,CODE2) #else -#define ACE_OPERATORG_SET(MT) \ - ACE_OPERATORG(MT,short &); \ - ACE_OPERATORG(MT,u_short &); \ - ACE_OPERATORG(MT,int &); \ - ACE_OPERATORG(MT,u_int &); \ - ACE_OPERATORG(MT,long &); \ - ACE_OPERATORG(MT,u_long &); \ - ACE_OPERATORG(MT,float &); \ - ACE_OPERATORG(MT,double &); \ - ACE_OPERATORG(MT,long double &); \ - ACE_OPERATORG(MT,char &) \ - ACE_OPERATORG(MT,u_char &); \ - ACE_OPERATORG(MT,signed char &); \ - ACE_OPERATORG(MT,char *) \ - ACE_OPERATORG(MT,u_char *); \ - ACE_OPERATORG(MT,signed char *); \ - virtual MT& operator>>(__omanip_ func) { (*func)(*this); return *this; } \ - virtual MT& operator>>(__manip_ func) { (*func)(*this); return *this; } - -#define ACE_OPERATORP_SET(MT) \ - ACE_OPERATORP(MT,short); \ - ACE_OPERATORP(MT,u_short); \ - ACE_OPERATORP(MT,int); \ - ACE_OPERATORP(MT,u_int); \ - ACE_OPERATORP(MT,long); \ - ACE_OPERATORP(MT,u_long); \ - ACE_OPERATORP(MT,float); \ - ACE_OPERATORP(MT,double); \ - ACE_OPERATORP(MT,char); \ - ACE_OPERATORP(MT,u_char); \ - ACE_OPERATORP(MT,signed char); \ - ACE_OPERATORP(MT,const char *); \ - ACE_OPERATORP(MT,const u_char *); \ - ACE_OPERATORP(MT,const signed char *); \ - ACE_OPERATORP(MT,const void *); \ - virtual MT& operator<<(__omanip_ func) { (*func)(*this); return *this; } \ - virtual MT& operator<<(__manip_ func) { (*func)(*this); return *this; } + #define GET_FUNC_SET1(MT,CODE,CODE2) \ + GET_PROT(MT,signed char &,CODE) \ + GET_PROT(MT,signed char *,CODE) \ + GET_FUNC_SET0(MT,CODE,CODE2) + + #define PUT_FUNC_SET1(MT,CODE,CODE2) \ + PUT_FUNC(MT,signed char) \ + PUT_FUNC(MT,const signed char *) \ + PUT_FUNC_SET0(MT,CODE,CODE2) #endif /* ACE_LACKS_SIGNED_CHAR */ +#define GET_MANIP_CODE { if( ipfx() ) { (*func)(*this); } isfx(); return *this; } +#define PUT_MANIP_CODE { if( opfx() ) { (*func)(*this); } osfx(); return *this; } + +#define GET_FUNC_SET(MT) GET_FUNC_SET1(MT,GET_CODE,GET_MANIP_CODE) +#define PUT_FUNC_SET(MT) PUT_FUNC_SET1(MT,PUT_CODE,PUT_MANIP_CODE) +#define GETPUT_FUNC_SET(MT) GET_FUNC_SET(MT) PUT_FUNC_SET(MT) + + +#define GET_SIG_SET(MT) GET_FUNC_SET1(MT,= 0;,= 0;) +#define PUT_SIG_SET(MT) PUT_FUNC_SET1(MT,= 0;,= 0;) +#define GETPUT_SIG_SET(MT) GET_SIG_SET(MT) PUT_SIG_SET(MT) + + +/////////////////////////////////////////////////////////////////////////// + template <class STREAM> class ACE_IOStream : public iostream, public STREAM // = TITLE @@ -316,12 +503,12 @@ class ACE_IOStream : public iostream, public STREAM // customize only one or two. { public: - ACE_IOStream (void); + ACE_IOStream ( STREAM & stream, u_int streambuf_size = ACE_STREAMBUF_SIZE); + ACE_IOStream ( u_int streambuf_size = ACE_STREAMBUF_SIZE); // The default constructor. This will initiailze your STREAM and // then setup the iostream baseclass to use a custom streambuf based // on STREAM. - virtual ~ACE_IOStream (void); // We have to get rid of the streambuf_ ourselves since we gave it // to iostream(); @@ -330,43 +517,35 @@ public: // The only ambituity in the multiple inheritance is the close() // function. -#if defined (__GNUC__) - virtual ACE_IOStream& operator>>(String & v); +#if defined(__GNUC__) || defined(ACE_WIN32) + virtual ACE_IOStream & operator>>(ACE_IOStream_String & v); // A simple string operator. The base iostream has 'em for char* // but that isn't always the best thing for a String. If we don't // provide our own here, we may not get what we want. - virtual ACE_IOStream& operator>>(QuotedString &v); + virtual ACE_IOStream & operator<<(ACE_IOStream_String & v); + // The converse of the String put operator. + + virtual ACE_IOStream & operator>>(QuotedString &v); // A more clever operator that handles quoted strings so that we // can get strings containing whitespace! - virtual ACE_IOStream& operator<<(QuotedString &v); + virtual ACE_IOStream & operator<<(QuotedString &v); // The converse of the QuotedString put operator. -#endif /* __GNUG__ */ +#endif /* __GNUC__ || ACE_WIN32 */ -#if !defined (ACE_LACKS_IOSTREAM_SETGET) // = Using the macros to provide get/set operators. - ACE_OPERATORG_SET (ACE_IOStream<STREAM>); - ACE_OPERATORP_SET (ACE_IOStream<STREAM>); +#if !defined (ACE_LACKS_IOSTREAM_SETGET) + GETPUT_FUNC_SET (ACE_IOStream<STREAM>) #endif /* ACE_LACKS_IOSTREAM_SETSET */ - // = These are handy to have around for overriding. - - // The *pfx functions are called at the beginning of each get/put - // operator. The *sfx are called at the end. In a derivative - // class, I've overridden the osfx() operator such that a space will - // be inserted after every put operation so that my transmitted - // "fields" are always separated. - #if defined (ACE_LACKS_IOSTREAM_FX) - // These should be faked out to do the right thing, if we knew - // what that was. Instead, they're just faked out. - virtual int ipfx (int need = 0) { ACE_UNUSED_ARG (need); return 1; } - virtual int ipfx0(void) { return 1; } // Optimized ipfx(0) - virtual int ipfx1(void) { return 1; } // Optimized ipfx(1) - virtual void isfx (void) { /* null */ } - virtual int opfx (void) { return 1; } - virtual void osfx (void) { /* null */ } + virtual int ipfx (int need = 0) { ACE_UNUSED_ARG (need); return good(); } + virtual int ipfx0(void) { return good(); } // Optimized ipfx(0) + virtual int ipfx1(void) { return good(); } // Optimized ipfx(1) + virtual void isfx (void) { } + virtual int opfx (void) { return good(); } + virtual void osfx (void) { put(' '); } #else #if defined (__GNUC__) virtual int ipfx0(void) { return(iostream::ipfx0()); } // Optimized ipfx(0) @@ -381,11 +560,17 @@ public: virtual void osfx (void) { iostream::osfx(); } #endif /* ACE_LACKS_IOSTREAM_FX */ + ACE_IOStream & operator>>( ACE_Time_Value *& tv ); + // Allow the programmer to provide a timeout for read operations. + // Give it a pointer to NULL to block forever. + protected: + ACE_Streambuf<STREAM> *streambuf_; // This is where all of the action takes place. The // streambuf_ is the interface to the underlying STREAM. +private: // We move these into the private section so that they cannot // be used by the application programmer. This is necessary // because streambuf_ will be buffering IO on the STREAM @@ -397,8 +582,96 @@ protected: ssize_t recv_n (...); }; +/////////////////////////////////////////////////////////////////////////// + +template <class STREAM> +class ACE_SOCK_Dgram_SC : public STREAM +// Datagrams don't have the notion of a "peer". Each send and receive +// on a datagram can go to a different peer if you want. If you're +// using datagrams for stream activity, you probably want 'em all to +// go to (and come from) the same place. That's what this class is +// for. BTW: 'Dgram_SC' is short for 'Datagram-Self-Contained'. +// Here, we keep an address object so that we can remember who last +// sent us data. When we write back, we're then able to write back +// to that same address. +{ +protected: + ACE_INET_Addr peer_; + +public: + ACE_SOCK_Dgram_SC() : STREAM() + { + } + + ACE_SOCK_Dgram_SC ( STREAM & source, ACE_INET_Addr & dest ) + : STREAM( source ), peer_ ( dest ) + { + } + + inline ssize_t send_n( char * buf,ssize_t len ) + { + return STREAM::send(buf,len,peer_); + } + inline ssize_t recv ( char * buf,ssize_t len, ACE_Time_Value * tv = NULL) + { + return recv( buf, len, 0, tv ); + } + inline ssize_t recv ( char * buf,ssize_t len, int flags, ACE_Time_Value * tv = NULL) + { + if( tv != 0 ) + { + ACE_HANDLE handle = this->get_handle(); + ACE_Handle_Set handle_set; + + handle_set.set_bit (handle); + + switch (ACE_OS::select (int (handle) + 1, + (fd_set *) handle_set, // read_fds. + (fd_set *) 0, // write_fds. + (fd_set *) 0, // exception_fds. + tv)) + { + case 0: + errno = ETIME; + case -1: + return -1; + default: + ; // Do the 'recv' below + } + } + + int rval = STREAM::recv (buf,len,peer_,flags); +#ifdef WIN32 + if( rval == SOCKET_ERROR ) + if( WSAGetLastError() == WSAEMSGSIZE ) + if( flags & MSG_PEEK ) + rval = len; +#endif + + return (rval<len)?rval:len; + } + inline ssize_t recv_n( char * buf,ssize_t len, int flags = 0, ACE_Time_Value * tv = NULL ) + { + int rval = this->recv( buf, len, flags, tv ); + return rval; + } + inline int get_remote_addr (ACE_INET_Addr & addr) const + { + addr = peer_; + return 0; + } + +}; + +/////////////////////////////////////////////////////////////////////////// + + #if defined (ACE_TEMPLATES_REQUIRE_SOURCE) -#include "IOStream.cpp" +# if ! defined( ACE_IOSTREAM_C ) +# define ACE_IOSTREAM_BUILDING_TEMPLATE +# endif +# include "IOStream.cpp" #endif /* ACE_TEMPLATES_REQUIRE_SOURCE */ #endif /* ACE_IOSTREAM_H */ + |