Connection::~Connection() { // ensure we emit this before our vtable goes down, since we are the // Bridge on the underlying Atlas codec, and otherwise we might get // a pure virtual method call hardDisconnect(true); }
int BaseConnection::connect(const std::string & host, short port) { if (_socket) { _socket->detach(); _socket.reset(); } try { StreamSocket::Callbacks callbacks; callbacks.dispatch = [&] {this->dispatch();}; callbacks.stateChanged = [&](StreamSocket::Status state) { if (state == StreamSocket::NEGOTIATE) { //Turn off Nagle's algorithm to increase responsiveness. ((ResolvableAsioStreamSocket<ip::tcp>*)_socket.get())->getAsioSocket().set_option(ip::tcp::no_delay(true)); } this->stateChanged(state);}; auto socket = new ResolvableAsioStreamSocket<ip::tcp>(_io_service, _clientName, _bridge, callbacks); _socket.reset(socket); std::stringstream ss; ss << port; ip::tcp::resolver::query query(host, ss.str()); setStatus(CONNECTING); socket->connectWithQuery(query); } catch (const std::exception& e) { error() << "Error when trying to connect to " << host << " on port " << port << ": " << e.what(); hardDisconnect(true); return -1; } return 0; }
void Connection::send(const Atlas::Objects::Root &obj) { if ((_status != CONNECTED) && (_status != DISCONNECTING)) { error() << "called send on closed connection"; return; } if (!_socket) { handleFailure("Connection::send: stream failed"); hardDisconnect(true); return; } #ifdef ATLAS_LOG std::stringstream debugStream; Atlas::Codecs::Bach debugCodec(debugStream, *this /*dummy*/); Atlas::Objects::ObjectsEncoder debugEncoder(debugCodec); debugEncoder.streamObjectsMessage(obj); debugStream << std::flush; std::cout << "sending:" << debugStream.str() << std::endl; #endif _socket->getEncoder().streamObjectsMessage(obj); _socket->write(); }
void BaseConnection::onConnectTimeout() { std::ostringstream os; os << "Connect to " << _host << ':' << _port << " timed out"; handleTimeout(os.str()); hardDisconnect(true); }
BaseConnection::~BaseConnection() { if (_status != DISCONNECTED) { hardDisconnect(true); } if (_socket) { _socket->detach(); _socket.reset(); } }
void BaseConnection::stateChanged(StreamSocket::Status status) { switch (status) { case StreamSocket::CONNECTING: setStatus(CONNECTING); break; case StreamSocket::CONNECTING_TIMEOUT: onConnectTimeout(); break; case StreamSocket::CONNECTING_FAILED: handleFailure("Failed to connect to " + _host); hardDisconnect(true); break; case StreamSocket::NEGOTIATE: setStatus(NEGOTIATE); break; case StreamSocket::NEGOTIATE_FAILED: hardDisconnect(true); break; case StreamSocket::NEGOTIATE_TIMEOUT: onNegotiateTimeout(); break; case StreamSocket::CONNECTED: setStatus(CONNECTED); onConnect(); break; case StreamSocket::CONNECTION_FAILED: hardDisconnect(true); break; case StreamSocket::DISCONNECTING: setStatus(DISCONNECTING); break; default: break; } }
void Connection::unlock() { if (m_lock < 1) throw InvalidOperation("Imbalanced lock/unlock calls on Connection"); if (--m_lock == 0) { switch (_status) { case DISCONNECTING: debug() << "Connection unlocked in DISCONNECTING, closing socket"; debug() << "have " << m_opDeque.size() << " ops waiting"; m_opDeque.clear(); hardDisconnect(true); break; default: warning() << "Connection unlocked in spurious state : this may cause a failure later"; break; } } }
int BaseConnection::connectLocal(const std::string & filename) { if (_socket) { _socket->detach(); _socket.reset(); } try { StreamSocket::Callbacks callbacks; callbacks.dispatch = [&] {this->dispatch();}; callbacks.stateChanged = [&](StreamSocket::Status state) {this->stateChanged(state);}; auto socket = new AsioStreamSocket<local::stream_protocol>( _io_service, _clientName, _bridge, callbacks); _socket.reset(socket); setStatus(CONNECTING); socket->connect(local::stream_protocol::endpoint(filename)); } catch (const std::exception& e) { hardDisconnect(true); return -1; } return 0; }
int Connection::disconnect() { if (_status == DISCONNECTING) { warning() << "duplicate disconnect on Connection that's already disconnecting"; return -1; } if (_status == DISCONNECTED) { warning() << "called disconnect on already disconnected Connection"; return -1; } // This assert means that this function will always return early below // where m_lock is checked. m_lock seems to be used by Account to prevent // disconnecting when something is pending. // FIXME Look into this. assert(m_lock == 0); // this is a soft disconnect; it will give people a chance to do tear down and so on // in response, people who need to hold the disconnect will lock() the // connection, and unlock when their work is done. A timeout stops // locks from preventing disconnection setStatus(DISCONNECTING); Disconnecting.emit(); if (m_lock == 0) { hardDisconnect(true); return 0; } // fell through, so someone has locked => // start a disconnect timeout // _timeout = new Timeout(5000); // _timeout->Expired.connect(sigc::mem_fun(this, &Connection::onDisconnectTimeout)); return 0; }
void test_hardDisconnect(bool flag) { hardDisconnect(flag); }
void Connection::onDisconnectTimeout() { handleTimeout("timed out waiting for disconnection"); hardDisconnect(true); }
void BaseConnection::onNegotiateTimeout() { handleTimeout("Atlas negotiation timed out"); hardDisconnect(true); }