void Connection::closeConnectionTask() { //dispatcher thread #ifdef __DEBUG_NET_DETAIL__ std::clog << "Connection::closeConnectionTask" << std::endl; #endif m_connectionLock.lock(); if(m_closeState != CLOSE_STATE_REQUESTED) { std::clog << "Error: [Connection::closeConnectionTask] m_closeState = " << m_closeState << std::endl; m_connectionLock.unlock(); return; } m_closeState = CLOSE_STATE_CLOSING; if(m_protocol) { Dispatcher::getInstance().addTask( createTask(boost::bind(&Protocol::releaseProtocol, m_protocol))); m_protocol->setConnection(NULL); m_protocol = NULL; } if(!closingConnection()) m_connectionLock.unlock(); }
void Connection::parseHeader(const boost::system::error_code& error) { m_connectionLock.lock(); m_pendingRead--; if(m_closeState == CLOSE_STATE_CLOSING) { if(!closingConnection()) m_connectionLock.unlock(); return; } int32_t size = m_msg.decodeHeader(); if(!error && size > 0 && size < NETWORKMESSAGE_MAXSIZE - 16) { // Read packet content m_pendingRead++; m_msg.setMessageLength(size + NetworkMessage::headerLength); boost::asio::async_read(m_socket, boost::asio::buffer(m_msg.getBodyBuffer(), size), boost::bind(&Connection::parsePacket, this, boost::asio::placeholders::error)); } else handleReadError(error); m_connectionLock.unlock(); }
void Connection::parsePacket(const boost::system::error_code& error) { m_connectionLock.lock(); m_pendingRead--; if(m_closeState == CLOSE_STATE_CLOSING) { if(!closingConnection()) m_connectionLock.unlock(); return; } if(!error) { // Protocol selection if(!m_protocol) { // Protocol depends on the first byte of the packet uint8_t protocolId = m_msg.GetByte(); switch(protocolId) { case 0x01: // Login server protocol m_protocol = new ProtocolLogin(this); break; case 0x0A: // World server protocol m_protocol = new ProtocolGame(this); break; case 0xFF: // Status protocol m_protocol = new ProtocolStatus(this); break; default: // No valid protocol close(); m_connectionLock.unlock(); return; break; } m_protocol->onRecvFirstMessage(m_msg); } else { // Send the packet to the current protocol m_protocol->onRecvMessage(m_msg); } // Wait to the next packet m_pendingRead++; boost::asio::async_read(m_socket, boost::asio::buffer(m_msg.getBuffer(), NetworkMessage::headerLength), boost::bind(&Connection::parseHeader, this, boost::asio::placeholders::error)); } else handleReadError(error); m_connectionLock.unlock(); }
void Connection::onWriteOperation(OutputMessage_ptr msg, const boost::system::error_code& error) { #ifdef __DEBUG_NET_DETAIL__ std::clog << "onWriteOperation" << std::endl; #endif msg.reset(); m_connectionLock.lock(); if(!error) { if(m_pendingWrite > 0) { if(!m_outputQueue.empty()) { OutputMessage_ptr msg = m_outputQueue.front(); m_outputQueue.pop_front(); internalSend(msg); #ifdef __DEBUG_NET_DETAIL__ std::clog << "Connection::onWriteOperation send " << msg->getMessageLength() << std::endl; #endif } m_pendingWrite--; } else { std::clog << "Error: [Connection::onWriteOperation] Getting unexpected notification!" << std::endl; // Error. Pending operations counter is 0, but we are getting a // notification!! } } else { m_pendingWrite--; handleWriteError(error); } if(m_closeState == CLOSE_STATE_CLOSING) { if(!closingConnection()) m_connectionLock.lock(); return; } m_connectionLock.unlock(); }
void IDBDatabaseBackend::close(PassRefPtr<IDBDatabaseCallbacks> prpCallbacks) { RefPtr<IDBDatabaseCallbacks> callbacks = prpCallbacks; ASSERT(m_databaseCallbacksSet.contains(callbacks)); m_databaseCallbacksSet.remove(callbacks); if (m_pendingSecondHalfOpen && m_pendingSecondHalfOpen->databaseCallbacks() == callbacks) { m_pendingSecondHalfOpen->callbacks()->onError(IDBDatabaseError::create(IDBDatabaseException::AbortError, "The connection was closed.")); m_pendingSecondHalfOpen.release(); } if (connectionCount() > 1) return; // processPendingCalls allows the inspector to process a pending open call // and call close, reentering IDBDatabaseBackend::close. Then the // backend would be removed both by the inspector closing its connection, and // by the connection that first called close. // To avoid that situation, don't proceed in case of reentrancy. if (m_closingConnection) return; TemporaryChange<bool> closingConnection(m_closingConnection, true); processPendingCalls(); // FIXME: Add a test for the m_pendingOpenCalls cases below. if (!connectionCount() && !m_pendingOpenCalls.size() && !m_pendingDeleteCalls.size()) { TransactionMap transactions(m_transactions); RefPtr<IDBDatabaseError> error = IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Connection is closing."); for (TransactionMap::const_iterator::Values it = transactions.values().begin(), end = transactions.values().end(); it != end; ++it) (*it)->abort(error); ASSERT(m_transactions.isEmpty()); m_serverConnection->close(); // This check should only be false in unit tests. ASSERT(m_factory); if (m_factory) m_factory->removeIDBDatabaseBackend(m_identifier); } }