// Copyright (C) 2012 Davis E. King (davis@dlib.net) // License: Boost Software License See LICENSE.txt for the full license. #ifndef DLIB_IOSOCKSTrEAM_Hh_ #define DLIB_IOSOCKSTrEAM_Hh_ #include "iosockstream_abstract.h" #include <iostream> #include "../sockstreambuf.h" #include "../smart_pointers_thread_safe.h" #include "../timeout.h" #ifdef _MSC_VER // Disable the warning about inheriting from std::iostream 'via dominance' since this warning is a warning about // visual studio conforming to the standard and is ignorable. // See http://connect.microsoft.com/VisualStudio/feedback/details/733720/inheriting-from-std-fstream-produces-c4250-warning // for further details if interested. #pragma warning(disable : 4250) #endif // _MSC_VER namespace dlib { // ---------------------------------------------------------------------------------------- class iosockstream : public std::iostream { public: iosockstream( ) : std::iostream(0) { } iosockstream( const network_address& addr ) : std::iostream(0) { open(addr); } iosockstream( const network_address& addr, unsigned long timeout ) : std::iostream(0) { open(addr, timeout); } ~iosockstream() { close(); } void open ( const network_address& addr ) { auto_mutex lock(class_mutex); close(); con.reset(connect(addr)); buf.reset(new sockstreambuf(con.get())); // Note that we use the sockstreambuf's ability to autoflush instead of // telling the iostream::tie() function to tie the stream to itself even though // that should work fine. The reason we do it this way is because there is a // bug in visual studio 2012 that causes a program to crash when a stream is // tied to itself and then used. See // http://connect.microsoft.com/VisualStudio/feedback/details/772293/tying-a-c-iostream-object-to-itself-causes-a-stack-overflow-in-visual-studio-2012 // for further details. buf->flush_output_on_read(); rdbuf(buf.get()); clear(); } void open ( const network_address& addr, unsigned long timeout ) { auto_mutex lock(class_mutex); close(timeout); con.reset(connect(addr.host_address, addr.port, timeout)); buf.reset(new sockstreambuf(con.get())); buf->flush_output_on_read(); rdbuf(buf.get()); clear(); } void close( unsigned long timeout = 10000 ) { auto_mutex lock(class_mutex); rdbuf(0); try { if (buf) { dlib::timeout t(*con,&connection::shutdown,timeout); // This will flush the sockstreambuf and also destroy it. buf.reset(); if(con->shutdown_outgoing()) { // there was an error so just close it now and return con->shutdown(); } else { char junk[100]; // wait for the other end to close their side while (con->read(junk,sizeof(junk)) > 0); } } } catch (...) { con.reset(); throw; } con.reset(); } void terminate_connection_after_timeout ( unsigned long timeout ) { auto_mutex lock(class_mutex); if (con) { con_timeout.reset(new dlib::timeout(*this,&iosockstream::terminate_connection,timeout,con)); } } void shutdown ( ) { auto_mutex lock(class_mutex); if (con) con->shutdown(); } private: void terminate_connection( shared_ptr_thread_safe<connection> thecon ) { thecon->shutdown(); } scoped_ptr<timeout> con_timeout; rmutex class_mutex; shared_ptr_thread_safe<connection> con; scoped_ptr<sockstreambuf> buf; }; // ---------------------------------------------------------------------------------------- } #endif // DLIB_IOSOCKSTrEAM_Hh_