358 lines
8.9 KiB
C++
358 lines
8.9 KiB
C++
// Copyright (C) 2003 Davis E. King (davis@dlib.net)
|
|
// License: Boost Software License See LICENSE.txt for the full license.
|
|
#ifndef DLIB_LINKER_KERNEL_1_CPp_
|
|
#define DLIB_LINKER_KERNEL_1_CPp_
|
|
#include "linker_kernel_1.h"
|
|
|
|
namespace dlib
|
|
{
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
// ----------------------------------------------------------------------------------------
|
|
// member function definitions
|
|
// ----------------------------------------------------------------------------------------
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
linker::
|
|
linker (
|
|
) :
|
|
running(false),
|
|
running_signaler(running_mutex),
|
|
A(0),
|
|
B(0),
|
|
service_connection_running_signaler(service_connection_running_mutex)
|
|
{
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
linker::
|
|
linker (
|
|
connection& a,
|
|
connection& b
|
|
) :
|
|
running(false),
|
|
running_signaler(running_mutex),
|
|
A(0),
|
|
B(0),
|
|
service_connection_running_signaler(service_connection_running_mutex)
|
|
{
|
|
link(a,b);
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
linker::
|
|
~linker (
|
|
)
|
|
{
|
|
clear();
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
void linker::
|
|
clear (
|
|
)
|
|
{
|
|
|
|
// shutdown the connections
|
|
cons_mutex.lock();
|
|
if (A != 0 )
|
|
{
|
|
A->shutdown();
|
|
A = 0;
|
|
}
|
|
if (B != 0)
|
|
{
|
|
B->shutdown();
|
|
B = 0;
|
|
}
|
|
cons_mutex.unlock();
|
|
|
|
|
|
// wait for the other threads to signal that they have ended
|
|
running_mutex.lock();
|
|
while (running == true)
|
|
{
|
|
running_signaler.wait();
|
|
}
|
|
running_mutex.unlock();
|
|
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
bool linker::
|
|
is_running (
|
|
) const
|
|
{
|
|
running_mutex.lock();
|
|
bool temp = running;
|
|
running_mutex.unlock();
|
|
return temp;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
void linker::
|
|
link (
|
|
connection& a,
|
|
connection& b
|
|
)
|
|
{
|
|
// make sure requires clause is not broken
|
|
DLIB_CASSERT(
|
|
this->is_running() == false ,
|
|
"\tvoid linker::link"
|
|
<< "\n\tis_running() == " << this->is_running()
|
|
<< "\n\tthis: " << this
|
|
);
|
|
|
|
running_mutex.lock();
|
|
running = true;
|
|
running_mutex.unlock();
|
|
|
|
cons_mutex.lock();
|
|
A = &a;
|
|
B = &b;
|
|
cons_mutex.unlock();
|
|
|
|
|
|
|
|
service_connection_running_mutex.lock();
|
|
service_connection_running = true;
|
|
service_connection_running_mutex.unlock();
|
|
|
|
service_connection_error_mutex.lock();
|
|
service_connection_error = false;
|
|
service_connection_error_mutex.unlock();
|
|
|
|
// if we fail to make the thread
|
|
if (!create_new_thread(service_connection,this))
|
|
{
|
|
a.shutdown();
|
|
b.shutdown();
|
|
|
|
service_connection_running_mutex.lock();
|
|
service_connection_running = false;
|
|
service_connection_running_mutex.unlock();
|
|
|
|
cons_mutex.lock();
|
|
A = 0;
|
|
B = 0;
|
|
cons_mutex.unlock();
|
|
|
|
running_mutex.lock();
|
|
running = false;
|
|
running_mutex.unlock();
|
|
|
|
|
|
|
|
throw dlib::thread_error (
|
|
ECREATE_THREAD,
|
|
"failed to make new thread in linker::link()"
|
|
);
|
|
}
|
|
|
|
|
|
|
|
// forward data from a to b
|
|
char buf[200];
|
|
long status;
|
|
bool error = false; // becomes true if one of the connections returns an error
|
|
while (true)
|
|
{
|
|
status = a.read(buf,sizeof(buf));
|
|
// if there was an error reading from the socket
|
|
if (status == OTHER_ERROR)
|
|
{
|
|
error = true;
|
|
break;
|
|
}
|
|
else if (status == SHUTDOWN)
|
|
{
|
|
b.shutdown();
|
|
}
|
|
|
|
if (status <= 0)
|
|
{
|
|
// if a has closed normally
|
|
if (status == 0)
|
|
b.shutdown_outgoing();
|
|
break;
|
|
}
|
|
|
|
status = b.write(buf,status);
|
|
// if there was an error writing to the socket then break
|
|
if (status == OTHER_ERROR)
|
|
{
|
|
error = true;
|
|
break;
|
|
}
|
|
|
|
if (status <= 0)
|
|
break;
|
|
}
|
|
|
|
|
|
// if there was an error then shutdown both connections
|
|
if (error)
|
|
{
|
|
a.shutdown();
|
|
b.shutdown();
|
|
}
|
|
|
|
|
|
|
|
|
|
// wait for the other thread to end
|
|
service_connection_running_mutex.lock();
|
|
while(service_connection_running)
|
|
{
|
|
service_connection_running_signaler.wait();
|
|
}
|
|
service_connection_running_mutex.unlock();
|
|
|
|
|
|
// make sure connections are shutdown
|
|
a.shutdown();
|
|
b.shutdown();
|
|
|
|
|
|
// both threads have ended so the connections are no longer needed
|
|
cons_mutex.lock();
|
|
A = 0;
|
|
B = 0;
|
|
cons_mutex.unlock();
|
|
|
|
|
|
// if service_connection terminated due to an error then set error to true
|
|
service_connection_error_mutex.lock();
|
|
if (service_connection_error)
|
|
error = true;
|
|
service_connection_error_mutex.unlock();
|
|
|
|
|
|
// if we are ending because of an error
|
|
if (error)
|
|
{
|
|
|
|
// signal that the link() function is ending
|
|
running_mutex.lock();
|
|
running = false;
|
|
running_signaler.broadcast();
|
|
running_mutex.unlock();
|
|
|
|
// throw the exception for this error
|
|
throw dlib::socket_error (
|
|
ECONNECTION,
|
|
"a connection returned an error in linker::link()"
|
|
);
|
|
|
|
}
|
|
|
|
// signal that the link() function is ending
|
|
running_mutex.lock();
|
|
running = false;
|
|
running_signaler.broadcast();
|
|
running_mutex.unlock();
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
void linker::
|
|
service_connection (
|
|
void* param
|
|
)
|
|
{
|
|
linker& p = *static_cast<linker*>(param);
|
|
|
|
p.cons_mutex.lock();
|
|
// if the connections are gone for whatever reason then return
|
|
if (p.A == 0 || p.B == 0)
|
|
{
|
|
// signal that this function is ending
|
|
p.service_connection_running_mutex.lock();
|
|
p.service_connection_running = false;
|
|
p.service_connection_running_signaler.broadcast();
|
|
p.service_connection_running_mutex.unlock();
|
|
return;
|
|
}
|
|
connection& a = *p.A;
|
|
connection& b = *p.B;
|
|
p.cons_mutex.unlock();
|
|
|
|
|
|
|
|
// forward data from b to a
|
|
char buf[200];
|
|
long status;
|
|
bool error = false;
|
|
while (true)
|
|
{
|
|
status = b.read(buf,sizeof(buf));
|
|
// if there was an error reading from the socket
|
|
if (status == OTHER_ERROR)
|
|
{
|
|
error = true;
|
|
break;
|
|
}
|
|
else if (status == SHUTDOWN)
|
|
{
|
|
a.shutdown();
|
|
}
|
|
|
|
|
|
if (status <= 0)
|
|
{
|
|
// if b has closed normally
|
|
if (status == 0)
|
|
a.shutdown_outgoing();
|
|
break;
|
|
}
|
|
|
|
|
|
status = a.write(buf,status);
|
|
// if there was an error writing to the socket then break
|
|
if (status == OTHER_ERROR)
|
|
{
|
|
error = true;
|
|
break;
|
|
}
|
|
|
|
if (status <= 0)
|
|
break;
|
|
}
|
|
|
|
|
|
// if there was an error then shutdown both connections
|
|
if (error)
|
|
{
|
|
a.shutdown();
|
|
b.shutdown();
|
|
}
|
|
|
|
|
|
// if there was an error then signal that
|
|
if (error)
|
|
{
|
|
p.service_connection_error_mutex.lock();
|
|
p.service_connection_error = true;
|
|
p.service_connection_error_mutex.unlock();
|
|
}
|
|
|
|
// signal that this function is ending
|
|
p.service_connection_running_mutex.lock();
|
|
p.service_connection_running = false;
|
|
p.service_connection_running_signaler.broadcast();
|
|
p.service_connection_running_mutex.unlock();
|
|
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
}
|
|
#endif // DLIB_LINKER_KERNEL_1_CPp_
|
|
|