pxmlw6n2f/Gazebo_Distributed/gazebo/transport/Connection.cc

984 lines
26 KiB
C++

/*
* Copyright (C) 2012 Open Source Robotics Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#ifdef _WIN32
// For socket(), connect(), send(), and recv().
#include <Winsock2.h>
#include <Ws2def.h>
#include <Ws2ipdef.h>
#include <Ws2tcpip.h>
#include <iphlpapi.h>
// Type used for raw data on this platform.
typedef char raw_type;
#define snprintf _snprintf
#else
// For data types
#include <sys/types.h>
// For socket(), connect(), send(), and recv()
#include <sys/socket.h>
// For gethostbyname()
#include <netdb.h>
// For inet_addr()
#include <arpa/inet.h>
// For close()
#include <unistd.h>
// For sockaddr_in
#include <netinet/in.h>
// Type used for raw data on this platform
typedef void raw_type;
#include <ifaddrs.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <boost/lexical_cast.hpp>
#include "gazebo/common/Console.hh"
#include "gazebo/msgs/msgs.hh"
#include "gazebo/transport/IOManager.hh"
#include "gazebo/transport/ConnectionManager.hh"
#include "gazebo/transport/Connection.hh"
using namespace gazebo;
using namespace transport;
extern void dummy_callback_fn(uint32_t);
unsigned int Connection::idCounter = 0;
IOManager *Connection::iomanager = NULL;
// Version 1.52 of boost has an address::is_unspecfied function, but
// Version 1.46.1 (installed on ubuntu) does not. So this helper function
// is stolen from adress::is_unspecified function in boost v1.52.
static bool addressIsUnspecified(const boost::asio::ip::address_v4 &_addr)
{
return _addr.to_ulong() == 0;
}
// Version 1.52 of boost has an address::is_loopback function, but
// Version 1.46.1 (installed on ubuntu) does not. So this helper function
// is stolen from adress::is_loopback function in boost v1.52.
static bool addressIsLoopback(const boost::asio::ip::address_v4 &_addr)
{
return (_addr.to_ulong() & 0xFF000000) == 0x7F000000;
}
//////////////////////////////////////////////////
Connection::Connection()
{
this->isOpen = false;
this->dropMsgLogged = false;
this->headerBuffer = new char[HEADER_LENGTH+1];
if (iomanager == NULL)
iomanager = new IOManager();
this->socket = new boost::asio::ip::tcp::socket(iomanager->GetIO());
iomanager->IncCount();
this->id = idCounter++;
this->acceptor = NULL;
this->readQuit = false;
this->connectError = false;
this->writeQueue.clear();
this->writeCount = 0;
this->localURI = std::string("http://") + this->GetLocalHostname() + ":" +
boost::lexical_cast<std::string>(this->GetLocalPort());
this->localAddress = this->GetLocalEndpoint().address().to_string();
// Get and set the IP white list from the GAZEBO_IP_WHITE_LIST environment
// variable.
char *whiteListEnv = getenv("GAZEBO_IP_WHITE_LIST");
if (whiteListEnv && !std::string(whiteListEnv).empty())
{
// Automatically add in the local addresses. This guarantees that
// Gazebo will run properly on the local machine.
this->ipWhiteList = "," + this->localAddress + ",127.0.0.1,"
+ whiteListEnv + ",";
}
}
//////////////////////////////////////////////////
Connection::~Connection()
{
delete [] this->headerBuffer;
this->headerBuffer = NULL;
this->Shutdown();
if (iomanager)
{
iomanager->DecCount();
if (iomanager->GetCount() == 0)
{
this->idCounter = 0;
delete iomanager;
iomanager = NULL;
}
}
}
//////////////////////////////////////////////////
bool Connection::Connect(const std::string &_host, unsigned int _port)
{
boost::mutex::scoped_lock lock(this->connectMutex);
std::string service = boost::lexical_cast<std::string>(_port);
int httpIndex = _host.find("http://");
std::string host = _host;
if (httpIndex != static_cast<int>(std::string::npos))
host = _host.substr(7, _host.size() - 7);
// Resolve the host name into an IP address
boost::asio::ip::tcp::resolver::iterator end;
boost::asio::ip::tcp::resolver resolver(iomanager->GetIO());
boost::asio::ip::tcp::resolver::query query(host, service,
boost::asio::ip::resolver_query_base::numeric_service);
boost::asio::ip::tcp::resolver::iterator endpointIter;
try
{
endpointIter = resolver.resolve(query);
// Find the first valid IPv4 address
for (; endpointIter != end &&
!(*endpointIter).endpoint().address().is_v4(); ++endpointIter)
{
}
// Make sure we didn't run off the end of the list.
if (endpointIter == end)
{
gzerr << "Unable to resolve uri[" << _host << ":" << _port << "]\n";
return false;
}
}
catch(...)
{
gzerr << "Unable to resolve uri[" << host << ":" << _port << "]\n";
return false;
}
this->connectError = false;
this->remoteURI.clear();
// Use async connect so that we can use a custom timeout. This is useful
// when trying to detect network errors.
this->socket->async_connect(*endpointIter++,
boost::bind(&Connection::OnConnect, this,
boost::asio::placeholders::error, endpointIter));
// Wait for at most 60 seconds for a connection to be established.
// The connectionCondition notification occurs in ::OnConnect.
if (!this->connectCondition.timed_wait(lock,
boost::posix_time::milliseconds(60000)) || this->connectError)
{
gzlog << "Failed to create connection to remote host["
<< host << ":" << _port << "]\n";
this->socket->close();
return false;
}
if (this->remoteURI.empty())
{
gzerr << "Unable to connect to host[" << host << ":" << _port << "]\n";
return false;
}
this->isOpen = true;
return true;
}
//////////////////////////////////////////////////
void Connection::Listen(unsigned int port, const AcceptCallback &_acceptCB)
{
this->acceptCB = _acceptCB;
this->acceptor = new boost::asio::ip::tcp::acceptor(iomanager->GetIO());
boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::tcp::v4(), port);
this->acceptor->open(endpoint.protocol());
this->acceptor->set_option(
boost::asio::ip::tcp::acceptor::reuse_address(true));
this->acceptor->set_option(
boost::asio::ip::tcp::acceptor::keep_alive(true));
// Enable TCP_NO_DELAY
this->acceptor->set_option(boost::asio::ip::tcp::no_delay(true));
this->acceptor->bind(endpoint);
this->acceptor->listen();
this->acceptConn = ConnectionPtr(new Connection());
this->acceptor->async_accept(*this->acceptConn->socket,
boost::bind(&Connection::OnAccept, this,
boost::asio::placeholders::error));
}
//////////////////////////////////////////////////
void Connection::OnAccept(const boost::system::error_code &e)
{
// Call the accept callback if there isn't an error
if (!e)
{
this->acceptConn->isOpen = true;
if (!this->ipWhiteList.empty() &&
this->ipWhiteList.find("," +
this->acceptConn->GetRemoteHostname() + ",") == std::string::npos)
{
gzlog << "Rejected connection from["
<< this->acceptConn->GetRemoteHostname() << "], not in white list["
<< this->ipWhiteList << "]\n";
}
else
{
this->acceptCB(this->acceptConn);
}
// First start a new acceptor
this->acceptConn = ConnectionPtr(new Connection());
this->acceptor->async_accept(*this->acceptConn->socket,
boost::bind(&Connection::OnAccept, this,
boost::asio::placeholders::error));
}
else
{
// Probably the connection was closed. No need to report an error since
// this can happen duing a shutdown.
if (e.value() != ECANCELED)
gzerr << e.message() << "Value[" << e.value() << "]" << std::endl;
}
}
//////////////////////////////////////////////////
void Connection::StartRead(const ReadCallback & /*_cb*/)
{
gzerr << "\n\n\n\n DONT USE \n\n\n\n";
}
//////////////////////////////////////////////////
void Connection::StopRead()
{
this->readQuit = true;
}
//////////////////////////////////////////////////
void Connection::EnqueueMsg(const std::string &_buffer, bool _force)
{
this->EnqueueMsg(_buffer, boost::bind(&dummy_callback_fn, _1), 0, _force);
}
//////////////////////////////////////////////////
void Connection::EnqueueMsg(const std::string &_buffer,
boost::function<void(uint32_t)> _cb, uint32_t _id, bool _force)
{
// Don't enqueue empty messages
if (_buffer.empty() || !this->IsOpen())
{
return;
}
char headerBufferLocal[HEADER_LENGTH + 1];
snprintf(headerBufferLocal, HEADER_LENGTH + 1, "%08x",
static_cast<unsigned int>(_buffer.size()));
{
boost::recursive_mutex::scoped_lock lock(this->writeMutex);
if (this->writeQueue.empty() ||
(this->writeCount > 0 && this->writeQueue.size() == 1) ||
(this->writeQueue.back().size()+_buffer.size() > 4096))
this->writeQueue.push_back(std::string(headerBufferLocal) + _buffer);
else
this->writeQueue.back() += std::string(headerBufferLocal) + _buffer;
this->callbacks.push_back(std::make_pair(_cb, _id));
}
if (_force)
{
this->ProcessWriteQueue();
}
else
{
// Tell the connection manager that it needs to update
ConnectionManager::Instance()->TriggerUpdate();
}
}
/////////////////////////////////////////////////
void Connection::ProcessWriteQueue(bool _blocking)
{
boost::recursive_mutex::scoped_lock lock(this->writeMutex);
if (!this->IsOpen())
{
return;
}
// async_write should only be called when the last async_write has
// completed. therefore we have to check the writeCount attribute
if (this->writeQueue.empty() || this->writeCount > 0)
{
return;
}
this->writeCount++;
// Write the serialized data to the socket. We use
// "gather-write" to send both the head and the data in
// a single write operation
if (!_blocking)
{
this->callbackIndex = this->callbacks.size();
boost::asio::async_write(*this->socket,
boost::asio::buffer(this->writeQueue.front().c_str(),
this->writeQueue.front().size()),
boost::bind(&Connection::OnWrite, shared_from_this(),
boost::asio::placeholders::error));
}
else
{
try
{
boost::asio::write(*this->socket,
boost::asio::buffer(this->writeQueue.front().c_str(),
this->writeQueue.front().size()));
}
catch(...)
{
this->Shutdown();
}
// Call the callback, in not NULL
if (!this->callbacks.front().first.empty())
this->callbacks.front().first(this->callbacks.front().second);
this->writeQueue.pop_front();
this->writeCount--;
}
}
//////////////////////////////////////////////////
std::string Connection::GetLocalURI() const
{
return this->localURI;
}
//////////////////////////////////////////////////
std::string Connection::GetRemoteURI() const
{
return this->remoteURI;
}
//////////////////////////////////////////////////
void Connection::OnWrite(const boost::system::error_code &_e)
{
{
boost::recursive_mutex::scoped_lock lock(this->writeMutex);
for (unsigned int i = 0; i < this->callbackIndex; ++i)
{
if (!this->callbacks.empty())
{
if (!this->callbacks.front().first.empty())
this->callbacks.front().first(this->callbacks.front().second);
this->callbacks.pop_front();
}
}
if (!this->writeQueue.empty())
this->writeQueue.pop_front();
this->writeCount--;
}
if (_e)
{
// It will reach this point if the remote connection disconnects.
this->Shutdown();
}
}
//////////////////////////////////////////////////
void Connection::Shutdown()
{
if (!this->socket)
return;
this->Cancel();
// Shutdown the TBB task
this->shutdown();
this->Close();
}
//////////////////////////////////////////////////
bool Connection::IsOpen() const
{
bool result = this->socket && this->socket->is_open();
return this->isOpen && result;
}
//////////////////////////////////////////////////
void Connection::Close()
{
boost::mutex::scoped_lock lock(this->socketMutex);
if (this->socket && this->socket->is_open())
{
try
{
this->socket->close();
boost::system::error_code ec;
this->socket->shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec);
}
catch(boost::system::system_error &e)
{
// This warning message is unnecessary...
// gzwarn << "Error closing socket[" << this->id << "] ["
// << e.what() << "]\n";
}
delete this->socket;
this->socket = NULL;
}
if (this->acceptor && this->acceptor->is_open())
{
try
{
this->acceptor->close();
}
catch(boost::system::system_error &e)
{
gzwarn <<"Error closing acceptor[" << this->id << "]\n";
}
delete this->acceptor;
this->acceptor = NULL;
}
boost::recursive_mutex::scoped_lock lock2(this->writeMutex);
this->writeQueue.clear();
this->callbacks.clear();
}
//////////////////////////////////////////////////
void Connection::Cancel()
{
if (this->acceptor)
{
try
{
this->acceptor->cancel();
}
catch(boost::system::system_error &e)
{
gzwarn << "Connection::Cancel Error[" << e.what() << "]\n";
// Left empty on purpose
}
delete this->acceptor;
this->acceptor = NULL;
}
{
boost::mutex::scoped_lock lock(this->socketMutex);
if (this->socket && this->socket->is_open())
{
try
{
this->socket->cancel();
}
catch(...)
{
this->socket->close();
}
}
}
}
//////////////////////////////////////////////////
bool Connection::Read(std::string &data)
{
bool result = false;
char header[HEADER_LENGTH];
std::vector<char> incoming;
std::size_t incoming_size;
boost::system::error_code error;
boost::recursive_mutex::scoped_lock lock(this->readMutex);
// First read the header
this->socket->read_some(boost::asio::buffer(header), error);
if (error)
{
gzerr << "Connection[" << this->id << "] Closed during Read\n";
throw boost::system::system_error(error);
}
// Parse the header to get the size of the incoming data packet
incoming_size = this->ParseHeader(std::string(header, HEADER_LENGTH));
if (incoming_size > 0)
{
incoming.resize(incoming_size);
std::size_t len = 0;
do
{
// Read in the actual data
len += this->socket->read_some(boost::asio::buffer(&incoming[len],
incoming_size - len), error);
} while (len < incoming_size && !error && !this->readQuit);
if (len != incoming_size)
{
gzerr << "Did not read everying. Read[" << len
<< "] Needed[" << incoming_size << "]\n";
}
if (error)
throw boost::system::system_error(error);
data = std::string(&incoming[0], incoming.size());
result = true;
}
return result;
}
//////////////////////////////////////////////////
std::string Connection::GetLocalAddress() const
{
return this->localAddress;
}
//////////////////////////////////////////////////
unsigned int Connection::GetLocalPort() const
{
try
{
if (this->socket && this->socket->is_open())
return this->socket->local_endpoint().port();
else if (this->acceptor)
return this->acceptor->local_endpoint().port();
}
catch(...)
{
}
return 0;
}
//////////////////////////////////////////////////
std::string Connection::GetRemoteAddress() const
{
return this->remoteAddress;
}
//////////////////////////////////////////////////
unsigned int Connection::GetRemotePort() const
{
if (this->socket && this->socket->is_open())
{
try
{
return this->socket->remote_endpoint().port();
}
catch(...)
{
return 0;
}
}
else
return 0;
}
//////////////////////////////////////////////////
std::size_t Connection::ParseHeader(const std::string &header)
{
std::size_t data_size = 0;
std::istringstream is(header);
if (!(is >> std::hex >> data_size))
{
// Header doesn't seem to be valid. Inform the caller
boost::system::error_code error(boost::asio::error::invalid_argument);
}
return data_size;
}
//////////////////////////////////////////////////
void Connection::ReadLoop(const ReadCallback &cb)
{
std::string data;
this->readQuit = false;
while (!this->readQuit)
{
try
{
if (this->socket->available() >= HEADER_LENGTH)
{
if (this->Read(data))
{
(cb)(data);
}
}
else
{
common::Time::MSleep(10);
continue;
}
}
catch(std::exception &e)
{
// The connection closed
break;
}
}
}
//////////////////////////////////////////////////
boost::asio::ip::tcp::endpoint Connection::GetLocalEndpoint()
{
boost::asio::ip::address_v4 address;
// Get the GAZEBO_HOSTNAME environment variable. This will be NULL if it's not
// set.
char *hostname = getenv("GAZEBO_HOSTNAME");
// Get the GAZEBO_IP environment variable. This will be NULL if it's not
// set.
char *ip = getenv("GAZEBO_IP");
// First try GAZEBO_HOSTNAME if it is set.
if (hostname && !std::string(hostname).empty())
{
boost::asio::ip::tcp::resolver resolver(iomanager->GetIO());
boost::asio::ip::tcp::resolver::query query(hostname, "");
boost::asio::ip::tcp::resolver::iterator iter = resolver.resolve(query);
boost::asio::ip::tcp::resolver::iterator end;
// Loop through the results, and stop at the first valid address.
while (iter != end)
{
boost::asio::ip::tcp::endpoint testEndPoint = *iter++;
// Check the end point for validity.
if (!addressIsUnspecified(testEndPoint.address().to_v4()))
{
address = testEndPoint.address().to_v4();
break;
}
}
// Complain if GAZEBO_HOSTNAME was set, but we were not able to get
// a valid address.
if (addressIsUnspecified(address))
gzerr << "GAZEBO_HOSTNAME[" << hostname << "] is invalid. "
<< "We will fallback onto GAZEBO_IP.";
}
// Try GAZEBO_IP if GAZEBO_HOSTNAME is not set or we were not able to
// find a valid address.
if (ip && !std::string(ip).empty() && addressIsUnspecified(address))
{
if (!ValidateIP(ip))
{
gzerr << "GAZEBO_IP environment variable with value[" << ip
<< "] is invalid. We will still try to use it, be warned.\n";
}
address = boost::asio::ip::address_v4::from_string(ip);
}
// Try to automatically find a valid address if GAZEBO_IP and
// GAZEBO_HOSTNAME have failed.
if (addressIsUnspecified(address))
{
#ifndef _WIN32
// the following is *nix implementation to get the external IP of the
// current machine.
struct ifaddrs *ifaddr, *ifa;
// Get interface addresses
if (getifaddrs(&ifaddr) == -1)
{
perror("getifaddres");
gzthrow("Unable to get local interface addresses");
}
char host[NI_MAXHOST];
// Iterate over all the interface addresses
for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)
{
if (ifa->ifa_addr == NULL)
continue;
int family = ifa->ifa_addr->sa_family;
// \todo We currently don't handle AF_INET6 addresses. So I commented
// out the below line, and removed AF_INET6 for the if clause.
// if (family == AF_INET || family == AF_INET6)
if (family == AF_INET)
{
int s = getnameinfo(ifa->ifa_addr,
(family == AF_INET) ? sizeof(struct sockaddr_in) :
sizeof(struct sockaddr_in6),
host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
if (s != 0)
gzthrow(std::string("getnameinfo() failed[") +
gai_strerror(s) + "]\n");
// Validate the IP address to make sure it's a valid dotted quad.
if (!ValidateIP(host))
continue;
address = boost::asio::ip::address_v4::from_string(host);
// Also make sure that the IP address is not a loopback interface.
if (!addressIsLoopback(address))
break;
}
}
// Use a loopback interface as a fallback.
if (addressIsUnspecified(address))
{
gzwarn << "Unable to find a non-loopback interface. You will "
<< "not be able to connect to remote server.\n";
address = address.loopback();
}
freeifaddrs(ifaddr);
// _WIN32
#else
// Establish our default return value, in case everything below fails.
std::string retAddr("127.0.0.1");
// Look up our address.
ULONG outBufLen = 0;
PIP_ADAPTER_ADDRESSES addrs = NULL;
// Not sure whether these are the right flags, but they work
// on Windows 7
ULONG flags = (GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST |
GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME);
// The first time, it'll fail; we're asking how much space is needed to
// store the result.
GetAdaptersAddresses(AF_INET, flags, NULL, addrs, &outBufLen);
// Allocate the required space.
addrs = new IP_ADAPTER_ADDRESSES[outBufLen];
ULONG ret;
// Now the call should succeed.
if ((ret = GetAdaptersAddresses(AF_INET, flags, NULL, addrs, &outBufLen)) ==
NO_ERROR)
{
// Iterate over all returned adapters, arbitrarily sticking with the
// last non-loopback one that we find.
for (PIP_ADAPTER_ADDRESSES curr = addrs; curr; curr = curr->Next)
{
// Iterate over all unicast addresses for this adapter
for (PIP_ADAPTER_UNICAST_ADDRESS unicast = curr->FirstUnicastAddress;
unicast; unicast = unicast->Next)
{
// Cast to get an IPv4 numeric address (the AF_INET flag used above
// ensures that we're only going to get IPv4 address here).
sockaddr_in* sockaddress =
reinterpret_cast<sockaddr_in*>(unicast->Address.lpSockaddr);
// Make it a dotted quad
char ipv4Str[3*4+3+1];
snprintf(ipv4Str, sizeof(ipv4Str), "%d.%d.%d.%d",
sockaddress->sin_addr.S_un.S_un_b.s_b1,
sockaddress->sin_addr.S_un.S_un_b.s_b2,
sockaddress->sin_addr.S_un.S_un_b.s_b3,
sockaddress->sin_addr.S_un.S_un_b.s_b4);
// Ignore loopback address (that's our default anyway)
if (!strcmp(ipv4Str, "127.0.0.1"))
continue;
retAddr = ipv4Str;
}
}
}
else
{
gzerr << "GetAdaptersAddresses() failed: " << ret << std::endl;
}
delete [] addrs;
if (retAddr == "127.0.0.1")
{
gzwarn <<
"Couldn't find a preferred IP via the GetAdaptersAddresses() call; "
"I'm assuming that your IP "
"address is 127.0.0.1. This should work for local processes, "
"but will almost certainly not work if you have remote processes."
"Report to the disc-zmq development team to seek a fix." << std::endl;
}
address = boost::asio::ip::address_v4::from_string(retAddr);
#endif
}
// Complain if we were unable to find a valid address
if (addressIsUnspecified(address))
gzthrow("Unable to get IP address for the local machine."
"Please check your network configuration.");
return boost::asio::ip::tcp::endpoint(address, 0);
}
/////////////////////////////////////////////////
bool Connection::ValidateIP(const std::string &_ip)
{
struct sockaddr_in sa;
#ifdef _WIN32
int result = InetPton(AF_INET, _ip.c_str(), &(sa.sin_addr));
#else
int result = inet_pton(AF_INET, _ip.c_str(), &(sa.sin_addr));
#endif
return result != 0;
}
//////////////////////////////////////////////////
boost::asio::ip::tcp::endpoint Connection::GetRemoteEndpoint() const
{
boost::asio::ip::tcp::endpoint ep;
if (this->socket)
{
boost::system::error_code ec;
ep = this->socket->remote_endpoint(ec);
if (ec)
gzerr << "Getting remote endpoint failed" << std::endl;
}
return ep;
}
//////////////////////////////////////////////////
std::string Connection::GetHostname(boost::asio::ip::tcp::endpoint _ep)
{
std::string result;
// Use the IP address if it's valid. This saves time, and is better than
// trying to find a hostname (particularly in cases where /etc/hosts has
// bad information).
if (!addressIsUnspecified(_ep.address().to_v4()))
{
result = _ep.address().to_string();
}
// Otherwise perform a lookup
else
{
boost::asio::ip::tcp::resolver resolver(iomanager->GetIO());
boost::asio::ip::tcp::resolver::iterator iter = resolver.resolve(_ep);
boost::asio::ip::tcp::resolver::iterator end;
while (iter != end)
{
result = (*iter).host_name();
++iter;
}
}
return result;
}
//////////////////////////////////////////////////
std::string Connection::GetRemoteHostname() const
{
return this->GetHostname(this->GetRemoteEndpoint());
}
//////////////////////////////////////////////////
std::string Connection::GetLocalHostname()
{
return GetHostname(GetLocalEndpoint());
}
//////////////////////////////////////////////////
void Connection::OnConnect(const boost::system::error_code &_error,
boost::asio::ip::tcp::resolver::iterator /*_endPointIter*/)
{
// This function is called when a connection is successfully (or
// unsuccessfully) established.
boost::mutex::scoped_lock lock(this->connectMutex);
if (_error == boost::system::errc::success)
{
this->remoteURI = std::string("http://") + this->GetRemoteHostname()
+ ":" + boost::lexical_cast<std::string>(this->GetRemotePort());
if (this->socket && this->socket->is_open())
{
this->remoteAddress =
this->socket->remote_endpoint().address().to_string();
}
else
{
this->connectError = true;
gzerr << "Invalid socket connection\n";
}
// Notify the condition that it may proceed.
this->connectCondition.notify_one();
}
else
{
this->connectError = true;
this->connectCondition.notify_one();
}
}
//////////////////////////////////////////////////
unsigned int Connection::GetId() const
{
return this->id;
}
//////////////////////////////////////////////////
std::string Connection::GetIPWhiteList() const
{
return this->ipWhiteList;
}