1
0
mirror of https://github.com/tomahawk-player/tomahawk.git synced 2025-08-09 07:36:48 +02:00

Introduce the Dpointer concept to ConnectionManager

This commit is contained in:
Uwe L. Korn
2013-06-07 16:35:29 +02:00
parent 26dbc9d1cc
commit 494e75bff1
3 changed files with 105 additions and 54 deletions

View File

@@ -16,7 +16,8 @@
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>. * along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "ConnectionManager.h" #include "ConnectionManager_p.h"
#include "ControlConnection.h" #include "ControlConnection.h"
#include "QTcpSocketExtra.h" #include "QTcpSocketExtra.h"
#include "Servent.h" #include "Servent.h"
@@ -30,11 +31,16 @@
#include <qtconcurrentrun.h> #include <qtconcurrentrun.h>
ConnectionManager::ConnectionManager( const QString &nodeid ) ConnectionManager::ConnectionManager( const QString &nodeid )
: m_nodeid( nodeid ) : d_ptr( new ConnectionManagerPrivate( this, nodeid ) )
{ {
// TODO sth? // TODO sth?
} }
ConnectionManager::~ConnectionManager()
{
delete d_ptr;
}
void void
ConnectionManager::handleSipInfo( const Tomahawk::peerinfo_ptr &peerInfo ) ConnectionManager::handleSipInfo( const Tomahawk::peerinfo_ptr &peerInfo )
{ {
@@ -45,7 +51,7 @@ ConnectionManager::handleSipInfo( const Tomahawk::peerinfo_ptr &peerInfo )
void void
ConnectionManager::handleSipInfoPrivate( const Tomahawk::peerinfo_ptr &peerInfo ) ConnectionManager::handleSipInfoPrivate( const Tomahawk::peerinfo_ptr &peerInfo )
{ {
m_mutex.lock(); d_func()->mutex.lock();
// Respect different behaviour before 0.7.100 // Respect different behaviour before 0.7.100
peerInfoDebug( peerInfo ) << Q_FUNC_INFO << "Trying to connect to client with version " << peerInfo->versionString().split(' ').last() << TomahawkUtils::compareVersionStrings( peerInfo->versionString().split(' ').last(), "0.7.99" ); peerInfoDebug( peerInfo ) << Q_FUNC_INFO << "Trying to connect to client with version " << peerInfo->versionString().split(' ').last() << TomahawkUtils::compareVersionStrings( peerInfo->versionString().split(' ').last(), "0.7.99" );
if ( !peerInfo->versionString().isEmpty() && TomahawkUtils::compareVersionStrings( peerInfo->versionString().split(' ').last(), "0.7.100" ) < 0) if ( !peerInfo->versionString().isEmpty() && TomahawkUtils::compareVersionStrings( peerInfo->versionString().split(' ').last(), "0.7.100" ) < 0)
@@ -63,7 +69,7 @@ ConnectionManager::handleSipInfoPrivate( const Tomahawk::peerinfo_ptr &peerInfo
// We connected to the peer, so we are done here. // We connected to the peer, so we are done here.
} }
} }
m_mutex.unlock(); d_func()->mutex.unlock();
return; return;
} }
foreach ( SipInfo info, peerInfo->sipInfos() ) foreach ( SipInfo info, peerInfo->sipInfos() )
@@ -78,7 +84,7 @@ ConnectionManager::handleSipInfoPrivate( const Tomahawk::peerinfo_ptr &peerInfo
return; return;
} }
} }
m_mutex.unlock(); d_func()->mutex.unlock();
} }
void void
@@ -87,78 +93,78 @@ ConnectionManager::connectToPeer( const Tomahawk::peerinfo_ptr &peerInfo, bool l
// Lock, so that we will not attempt to do two parallell connects. // Lock, so that we will not attempt to do two parallell connects.
if (lock) if (lock)
{ {
m_mutex.lock(); d_func()->mutex.lock();
} }
// Check that we are not already connected to this peer // Check that we are not already connected to this peer
ControlConnection* cconn = Servent::instance()->lookupControlConnection( peerInfo->nodeId() ); ControlConnection* cconn = Servent::instance()->lookupControlConnection( peerInfo->nodeId() );
if ( cconn != NULL || !m_controlConnection.isNull() ) if ( cconn != NULL || !d_func()->controlConnection.isNull() )
{ {
// We are already connected to this peer, so just add some more details. // We are already connected to this peer, so just add some more details.
peerInfoDebug( peerInfo ) << "Existing connection found, not connecting."; peerInfoDebug( peerInfo ) << "Existing connection found, not connecting.";
cconn->addPeerInfo( peerInfo ); cconn->addPeerInfo( peerInfo );
if ( cconn != NULL ) if ( cconn != NULL )
{ {
m_controlConnection = QPointer<ControlConnection>(cconn); d_func()->controlConnection = QPointer<ControlConnection>(cconn);
} }
m_mutex.unlock(); d_func()->mutex.unlock();
return; return;
// TODO: Keep the peerInfo in mind for reconnecting // TODO: Keep the peerInfo in mind for reconnecting
// FIXME: Do we need this for reconnecting if the connection drops? // FIXME: Do we need this for reconnecting if the connection drops?
} }
// If we are not connected, try to connect // If we are not connected, try to connect
m_currentPeerInfo = peerInfo; d_func()->currentPeerInfo = peerInfo;
peerInfoDebug( peerInfo ) << "No existing connection found, trying to connect."; peerInfoDebug( peerInfo ) << "No existing connection found, trying to connect.";
m_sipCandidates.append( peerInfo->sipInfos() ); d_func()->sipCandidates.append( peerInfo->sipInfos() );
QVariantMap m; QVariantMap m;
m["conntype"] = "accept-offer"; m["conntype"] = "accept-offer";
m["key"] = peerInfo->key(); m["key"] = peerInfo->key();
m["nodeid"] = Database::instance()->impl()->dbid(); m["nodeid"] = Database::instance()->impl()->dbid();
m_controlConnection = QPointer<ControlConnection>( new ControlConnection( Servent::instance() ) ); d_func()->controlConnection = QPointer<ControlConnection>( new ControlConnection( Servent::instance() ) );
m_controlConnection->setShutdownOnEmptyPeerInfos( false ); d_func()->controlConnection->setShutdownOnEmptyPeerInfos( false );
m_controlConnection->addPeerInfo( peerInfo ); d_func()->controlConnection->addPeerInfo( peerInfo );
m_controlConnection->setFirstMessage( m ); d_func()->controlConnection->setFirstMessage( m );
if ( peerInfo->id().length() ) if ( peerInfo->id().length() )
m_controlConnection->setName( peerInfo->contactId() ); d_func()->controlConnection->setName( peerInfo->contactId() );
if ( peerInfo->nodeId().length() ) if ( peerInfo->nodeId().length() )
m_controlConnection->setId( peerInfo->nodeId() ); d_func()->controlConnection->setId( peerInfo->nodeId() );
m_controlConnection->setProperty( "nodeid", peerInfo->nodeId() ); d_func()->controlConnection->setProperty( "nodeid", peerInfo->nodeId() );
Servent::instance()->registerControlConnection( m_controlConnection.data() ); Servent::instance()->registerControlConnection( d_func()->controlConnection.data() );
tryConnect(); tryConnect();
} }
void ConnectionManager::tryConnect() void ConnectionManager::tryConnect()
{ {
// ATTENTION: mutex should be already locked by the calling function. // ATTENTION: mutex should be already locked by the calling function.
Q_ASSERT( !m_controlConnection.isNull() ); Q_ASSERT( !d_func()->controlConnection.isNull() );
if ( m_sipCandidates.isEmpty() ) if ( d_func()->sipCandidates.isEmpty() )
{ {
// No more possibilities to connect. // No more possibilities to connect.
peerInfoDebug( m_currentPeerInfo ) << Q_FUNC_INFO << "No more possible SIP endpoints for " << m_controlConnection->name() << " skipping."; peerInfoDebug( d_func()->currentPeerInfo ) << Q_FUNC_INFO << "No more possible SIP endpoints for " << d_func()->controlConnection->name() << " skipping.";
// Clean up. // Clean up.
m_currentPeerInfo.clear(); d_func()->currentPeerInfo.clear();
delete m_controlConnection.data(); delete d_func()->controlConnection.data();
m_mutex.unlock(); d_func()->mutex.unlock();
return; return;
} }
// Use first available SIP endpoint and remove it from the list // Use first available SIP endpoint and remove it from the list
SipInfo info = m_sipCandidates.takeFirst(); SipInfo info = d_func()->sipCandidates.takeFirst();
if ( !info.isVisible() ) if ( !info.isVisible() )
{ {
peerInfoDebug( m_currentPeerInfo ) << Q_FUNC_INFO << "Try next SipInfo, we can't connect to this one"; peerInfoDebug( d_func()->currentPeerInfo ) << Q_FUNC_INFO << "Try next SipInfo, we can't connect to this one";
tryConnect(); tryConnect();
return; return;
} }
peerInfoDebug( m_currentPeerInfo ) << Q_FUNC_INFO << "Connecting to " << info.host() << ":" << info.port(); peerInfoDebug( d_func()->currentPeerInfo ) << Q_FUNC_INFO << "Connecting to " << info.host() << ":" << info.port();
Q_ASSERT( info.port() > 0 ); Q_ASSERT( info.port() > 0 );
// Check that we are not connecting to ourselves // Check that we are not connecting to ourselves
@@ -166,31 +172,31 @@ void ConnectionManager::tryConnect()
{ {
if ( info.host() == ha.toString() && info.port() == Servent::instance()->port() ) if ( info.host() == ha.toString() && info.port() == Servent::instance()->port() )
{ {
peerInfoDebug( m_currentPeerInfo ) << Q_FUNC_INFO << "Tomahawk won't try to connect to" << info.host() << ":" << info.port() << ": same ip:port as ourselves."; peerInfoDebug( d_func()->currentPeerInfo ) << Q_FUNC_INFO << "Tomahawk won't try to connect to" << info.host() << ":" << info.port() << ": same ip:port as ourselves.";
tryConnect(); tryConnect();
return; return;
} }
} }
if ( info.host() == Servent::instance()->additionalAddress() && info.port() == Servent::instance()->additionalPort() ) if ( info.host() == Servent::instance()->additionalAddress() && info.port() == Servent::instance()->additionalPort() )
{ {
peerInfoDebug( m_currentPeerInfo ) << Q_FUNC_INFO << "Tomahawk won't try to connect to" << info.host() << ":" << info.port() << ": same ip:port as ourselves."; peerInfoDebug( d_func()->currentPeerInfo ) << Q_FUNC_INFO << "Tomahawk won't try to connect to" << info.host() << ":" << info.port() << ": same ip:port as ourselves.";
tryConnect(); tryConnect();
return; return;
} }
// We should have already setup a first message in connectToPeer // We should have already setup a first message in connectToPeer
Q_ASSERT( !m_controlConnection->firstMessage().isNull() ); Q_ASSERT( !d_func()->controlConnection->firstMessage().isNull() );
QTcpSocketExtra* sock = new QTcpSocketExtra(); QTcpSocketExtra* sock = new QTcpSocketExtra();
sock->setConnectTimeout( CONNECT_TIMEOUT ); sock->setConnectTimeout( CONNECT_TIMEOUT );
sock->_disowned = false; sock->_disowned = false;
sock->_conn = m_controlConnection.data(); sock->_conn = d_func()->controlConnection.data();
sock->_outbound = true; sock->_outbound = true;
connect( sock, SIGNAL( connected() ), this, SLOT( socketConnected() ) ); connect( sock, SIGNAL( connected() ), this, SLOT( socketConnected() ) );
connect( sock, SIGNAL( error( QAbstractSocket::SocketError ) ), this, SLOT( socketError( QAbstractSocket::SocketError ) ) ); connect( sock, SIGNAL( error( QAbstractSocket::SocketError ) ), this, SLOT( socketError( QAbstractSocket::SocketError ) ) );
peerInfoDebug( m_currentPeerInfo ) << Q_FUNC_INFO << "Connecting socket to " << info.host() << ":" << info.port(); peerInfoDebug( d_func()->currentPeerInfo ) << Q_FUNC_INFO << "Connecting socket to " << info.host() << ":" << info.port();
sock->connectToHost( info.host(), info.port(), QTcpSocket::ReadWrite ); sock->connectToHost( info.host(), info.port(), QTcpSocket::ReadWrite );
sock->moveToThread( thread() ); sock->moveToThread( thread() );
} }
@@ -199,10 +205,10 @@ void
ConnectionManager::socketError( QAbstractSocket::SocketError error ) ConnectionManager::socketError( QAbstractSocket::SocketError error )
{ {
Q_UNUSED( error ); Q_UNUSED( error );
Q_ASSERT( !m_controlConnection.isNull() ); Q_ASSERT( !d_func()->controlConnection.isNull() );
QTcpSocketExtra* sock = (QTcpSocketExtra*)sender(); QTcpSocketExtra* sock = (QTcpSocketExtra*)sender();
peerInfoDebug( m_currentPeerInfo ) << Q_FUNC_INFO << "Connecting to " << sock->peerAddress().toString() << " failed: " << sock->errorString(); peerInfoDebug( d_func()->currentPeerInfo ) << Q_FUNC_INFO << "Connecting to " << sock->peerAddress().toString() << " failed: " << sock->errorString();
sock->deleteLater(); sock->deleteLater();
// Try to connect with the next available SipInfo. // Try to connect with the next available SipInfo.
@@ -215,35 +221,35 @@ ConnectionManager::socketConnected()
{ {
QTcpSocketExtra* sock = (QTcpSocketExtra*)sender(); QTcpSocketExtra* sock = (QTcpSocketExtra*)sender();
peerInfoDebug( m_currentPeerInfo ) << Q_FUNC_INFO << "Connected to hostaddr: " << sock->peerAddress() << ", hostname:" << sock->peerName(); peerInfoDebug( d_func()->currentPeerInfo ) << Q_FUNC_INFO << "Connected to hostaddr: " << sock->peerAddress() << ", hostname:" << sock->peerName();
Q_ASSERT( !sock->_conn.isNull() ); Q_ASSERT( !sock->_conn.isNull() );
handoverSocket( sock ); handoverSocket( sock );
m_currentPeerInfo.clear(); d_func()->currentPeerInfo.clear();
m_mutex.unlock(); d_func()->mutex.unlock();
} }
void void
ConnectionManager::handoverSocket( QTcpSocketExtra* sock ) ConnectionManager::handoverSocket( QTcpSocketExtra* sock )
{ {
Q_ASSERT( !m_controlConnection.isNull() ); Q_ASSERT( !d_func()->controlConnection.isNull() );
Q_ASSERT( sock ); Q_ASSERT( sock );
Q_ASSERT( m_controlConnection->socket().isNull() ); Q_ASSERT( d_func()->controlConnection->socket().isNull() );
Q_ASSERT( sock->isValid() ); Q_ASSERT( sock->isValid() );
disconnect( sock, SIGNAL( disconnected() ), sock, SLOT( deleteLater() ) ); disconnect( sock, SIGNAL( disconnected() ), sock, SLOT( deleteLater() ) );
disconnect( sock, SIGNAL( error( QAbstractSocket::SocketError ) ), this, SLOT( socketError( QAbstractSocket::SocketError ) ) ); disconnect( sock, SIGNAL( error( QAbstractSocket::SocketError ) ), this, SLOT( socketError( QAbstractSocket::SocketError ) ) );
sock->_disowned = true; sock->_disowned = true;
m_controlConnection->setOutbound( sock->_outbound ); d_func()->controlConnection->setOutbound( sock->_outbound );
m_controlConnection->setPeerPort( sock->peerPort() ); d_func()->controlConnection->setPeerPort( sock->peerPort() );
m_controlConnection->start( sock ); d_func()->controlConnection->start( sock );
// ControlConntection is now connected, now it can be destroyed if the PeerInfos disappear // ControlConntection is now connected, now it can be destroyed if the PeerInfos disappear
m_controlConnection->setShutdownOnEmptyPeerInfos( true ); d_func()->controlConnection->setShutdownOnEmptyPeerInfos( true );
m_currentPeerInfo.clear(); d_func()->currentPeerInfo.clear();
m_mutex.unlock(); d_func()->mutex.unlock();
} }

View File

@@ -25,8 +25,8 @@
#include <QAbstractSocket> #include <QAbstractSocket>
#include <QObject> #include <QObject>
#include <QMutex>
class ConnectionManagerPrivate;
class QTcpSocketExtra; class QTcpSocketExtra;
class DLLEXPORT ConnectionManager : public QObject class DLLEXPORT ConnectionManager : public QObject
@@ -36,6 +36,7 @@ class DLLEXPORT ConnectionManager : public QObject
public: public:
static QSharedPointer<ConnectionManager> getManagerForNodeId( const QString& nodeid ); static QSharedPointer<ConnectionManager> getManagerForNodeId( const QString& nodeid );
ConnectionManager( const QString& nodeid ); ConnectionManager( const QString& nodeid );
~ConnectionManager();
void handleSipInfo( const Tomahawk::peerinfo_ptr& peerInfo ); void handleSipInfo( const Tomahawk::peerinfo_ptr& peerInfo );
@@ -44,6 +45,9 @@ private slots:
void socketError( QAbstractSocket::SocketError error ); void socketError( QAbstractSocket::SocketError error );
private: private:
Q_DECLARE_PRIVATE( ConnectionManager )
ConnectionManagerPrivate* d_ptr;
void connectToPeer(const Tomahawk::peerinfo_ptr& peerInfo , bool lock); void connectToPeer(const Tomahawk::peerinfo_ptr& peerInfo , bool lock);
void handleSipInfoPrivate( const Tomahawk::peerinfo_ptr& peerInfo ); void handleSipInfoPrivate( const Tomahawk::peerinfo_ptr& peerInfo );
@@ -56,13 +60,6 @@ private:
* Attempt to connect to the peer using the current stored information. * Attempt to connect to the peer using the current stored information.
*/ */
void tryConnect(); void tryConnect();
// We just keep this for debug purposes and only during connection attempts.
Tomahawk::peerinfo_ptr m_currentPeerInfo;
QString m_nodeid;
QPointer<ControlConnection> m_controlConnection;
QList<SipInfo> m_sipCandidates;
QMutex m_mutex;
}; };
#endif // CONNECTIONMANAGER_H #endif // CONNECTIONMANAGER_H

View File

@@ -0,0 +1,48 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2013, Uwe L. Korn <uwelk@xhochy.com>
*
* Tomahawk is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Tomahawk is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CONNECTIONMANAGER_P_H
#define CONNECTIONMANAGER_P_H
#include "ConnectionManager.h"
#include <QMutex>
class ConnectionManagerPrivate : public QObject
{
Q_OBJECT
public:
ConnectionManagerPrivate( ConnectionManager* q, const QString& _nodeid )
: q_ptr ( q )
, nodeid( _nodeid )
{
}
ConnectionManager* q_ptr;
Q_DECLARE_PUBLIC ( ConnectionManager )
private:
// We just keep this for debug purposes and only during connection attempts.
Tomahawk::peerinfo_ptr currentPeerInfo;
QString nodeid;
QPointer<ControlConnection> controlConnection;
QList<SipInfo> sipCandidates;
QMutex mutex;
};
#endif // CONNECTIONMANAGER_P_H