172 lines
4.6 KiB
C++
172 lines
4.6 KiB
C++
// 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 <memory>
|
|
|
|
#include "../sockstreambuf.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(
|
|
std::shared_ptr<connection> thecon
|
|
)
|
|
{
|
|
thecon->shutdown();
|
|
}
|
|
|
|
std::unique_ptr<timeout> con_timeout;
|
|
rmutex class_mutex;
|
|
std::shared_ptr<connection> con;
|
|
std::unique_ptr<sockstreambuf> buf;
|
|
|
|
};
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
}
|
|
|
|
|
|
#endif // DLIB_IOSOCKSTrEAM_Hh_
|
|
|
|
|