summaryrefslogtreecommitdiff
path: root/ace
diff options
context:
space:
mode:
authorlevine <levine@ae88bc3d-4319-0410-8dbf-d08b4c9d3795>1997-04-30 14:39:07 +0000
committerlevine <levine@ae88bc3d-4319-0410-8dbf-d08b4c9d3795>1997-04-30 14:39:07 +0000
commit9770747c8ab4e7dac82aac61854b48d819460275 (patch)
treef70ed075e5b42275e2028fc64d0fea414bb24d88 /ace
parentd150d631a443ca003c604190f4b0550489b816a2 (diff)
downloadATCD-9770747c8ab4e7dac82aac61854b48d819460275.tar.gz
James' updates to IOStream
Diffstat (limited to 'ace')
-rw-r--r--ace/IOStream.cpp406
-rw-r--r--ace/IOStream.h529
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 */
+