1
0
mirror of https://github.com/tomahawk-player/tomahawk.git synced 2025-03-21 16:29:43 +01:00

Introduce ConnectionManager for outgoing connections

This commit is contained in:
Uwe L. Korn 2013-05-23 11:44:52 +02:00
parent e16028f164
commit 35c32575c1
6 changed files with 392 additions and 202 deletions

@ -307,6 +307,7 @@ list(APPEND libSources
network/Connection.cpp
network/ControlConnection.cpp
network/QTcpSocketExtra.cpp
network/ConnectionManager.cpp
playlist/PlaylistUpdaterInterface.cpp
playlist/dynamic/DynamicPlaylist.cpp

@ -0,0 +1,261 @@
/* === 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/>.
*/
#include "ConnectionManager.h"
#include "ControlConnection.h"
#include "Servent.h"
#include "database/Database.h"
#include "database/DatabaseImpl.h"
#include "sip/SipPlugin.h"
#include "utils/Logger.h"
#include <boost/bind.hpp>
#include <qtconcurrentrun.h>
ConnectionManager::ConnectionManager( const QString &nodeid )
: m_nodeid( nodeid )
{
// TODO sth?
}
void
ConnectionManager::handleSipInfo( const Tomahawk::peerinfo_ptr &peerInfo )
{
// Start handling in a separate thread so that we do not block the event loop.
QtConcurrent::run( this, &ConnectionManager::handleSipInfoPrivate, peerInfo );
}
void
ConnectionManager::handleSipInfoPrivate( const Tomahawk::peerinfo_ptr &peerInfo )
{
m_mutex.lock();
// Respect different behaviour before 0.7.99
if ( !peerInfo->versionString().isEmpty() && TomahawkUtils::compareVersionStrings( peerInfo->versionString(), "Tomahawk Player EmptyOS 0.7.99" ) < 0)
{
peerInfoDebug( peerInfo ) << Q_FUNC_INFO << "Using old-style (<0.7.99) connection order.";
SipInfo we = Servent::getSipInfoForOldVersions( Servent::instance()->getLocalSipInfos( QString(), QString() ) );
SipInfo they = peerInfo->sipInfos().first();
if ( they.isVisible() )
{
if ( !we.isVisible() || we.host() < they.host() || (we.host() == they.host() && we.port() < they.port()))
{
tLog( LOGVERBOSE ) << Q_FUNC_INFO << "Initiate connection to" << peerInfo->id() << "at" << they.host() << "peer of:" << peerInfo->sipPlugin()->account()->accountFriendlyName();
connectToPeer( peerInfo, false );
return;
// We connected to the peer, so we are done here.
}
}
m_mutex.unlock();
return;
}
foreach ( SipInfo info, peerInfo->sipInfos() )
{
if (info.isVisible())
{
// There is at least one SipInfo that may be visible. Try connecting.
// Duplicate Connections are checked by connectToPeer, so we do not need to take care of this
tLog( LOGVERBOSE ) << Q_FUNC_INFO << "Initiate connection to" << peerInfo->id() << "at" << info.host() << "peer of:" << peerInfo->sipPlugin()->account()->accountFriendlyName();
connectToPeer( peerInfo, false );
// We connected to the peer, so we are done here.
return;
}
}
m_mutex.unlock();
}
void
ConnectionManager::connectToPeer( const Tomahawk::peerinfo_ptr &peerInfo, bool lock )
{
// Lock, so that we will not attempt to do two parallell connects.
if (lock)
{
m_mutex.lock();
}
// Check that we are not already connected to this peer
ControlConnection* cconn = Servent::instance()->lookupControlConnection( peerInfo->nodeId() );
if ( cconn != NULL || !m_controlConnection.isNull() )
{
// We are already connected to this peer, so just add some more details.
peerInfoDebug( peerInfo ) << "Existing connection found, not connecting.";
cconn->addPeerInfo( peerInfo );
if ( cconn != NULL )
{
m_controlConnection = QPointer<ControlConnection>(cconn);
}
m_mutex.unlock();
return;
// TODO: Keep the peerInfo in mind for reconnecting
// FIXME: Do we need this for reconnecting if the connection drops?
}
// If we are not connected, try to connect
m_currentPeerInfo = peerInfo;
peerInfoDebug( peerInfo ) << "No existing connection found, trying to connect.";
m_sipCandidates.append( peerInfo->sipInfos() );
QVariantMap m;
m["conntype"] = "accept-offer";
m["key"] = peerInfo->key();
m["nodeid"] = Database::instance()->impl()->dbid();
m_controlConnection = QPointer<ControlConnection>( new ControlConnection( Servent::instance() ) );
m_controlConnection->addPeerInfo( peerInfo );
m_controlConnection->setFirstMessage( m );
if ( peerInfo->id().length() )
m_controlConnection->setName( peerInfo->contactId() );
if ( peerInfo->nodeId().length() )
m_controlConnection->setId( peerInfo->nodeId() );
m_controlConnection->setProperty( "nodeid", peerInfo->nodeId() );
Servent::instance()->registerControlConnection( m_controlConnection.data() );
tryConnect();
}
void ConnectionManager::tryConnect()
{
// ATTENTION: mutex should be already locked by the calling function.
Q_ASSERT( !m_controlConnection.isNull() );
if ( m_sipCandidates.isEmpty() )
{
// No more possibilities to connect.
peerInfoDebug( m_currentPeerInfo ) << Q_FUNC_INFO << "No more possible SIP endpoints for " << m_controlConnection->name() << " skipping.";
// Clean up.
m_currentPeerInfo.clear();
delete m_controlConnection.data();
m_mutex.unlock();
return;
}
// Use first available SIP endpoint and remove it from the list
SipInfo info = m_sipCandidates.takeFirst();
if ( !info.isVisible() )
{
peerInfoDebug( m_currentPeerInfo ) << Q_FUNC_INFO << "Try next SipInfo, we can't connect to this one";
tryConnect();
return;
}
peerInfoDebug( m_currentPeerInfo ) << Q_FUNC_INFO << "Connecting to " << info.host() << ":" << info.port();
Q_ASSERT( info.port() > 0 );
// Check that we are not connecting to ourselves
foreach( QHostAddress ha, Servent::instance()->addresses() )
{
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.";
tryConnect();
return;
}
}
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.";
tryConnect();
return;
}
// We should have already setup a first message in connectToPeer
Q_ASSERT( !m_controlConnection->firstMessage().isNull() );
QTcpSocketExtra* sock = new QTcpSocketExtra();
sock->setConnectTimeout( CONNECT_TIMEOUT );
sock->_disowned = false;
sock->_conn = m_controlConnection.data();
sock->_outbound = true;
connect( sock, SIGNAL( connected() ), this, SLOT( socketConnected() ) );
connect( sock, SIGNAL( error( QAbstractSocket::SocketError ) ), this, SLOT( socketError( QAbstractSocket::SocketError ) ) );
peerInfoDebug( m_currentPeerInfo ) << Q_FUNC_INFO << "Connecting socket to " << info.host() << ":" << info.port();
sock->connectToHost( info.host(), info.port(), QTcpSocket::ReadWrite );
sock->moveToThread( thread() );
}
void
ConnectionManager::socketError( QAbstractSocket::SocketError error )
{
Q_UNUSED( error );
Q_ASSERT( !m_controlConnection.isNull() );
QTcpSocketExtra* sock = (QTcpSocketExtra*)sender();
peerInfoDebug( m_currentPeerInfo ) << Q_FUNC_INFO << "Connecting to " << sock->peerAddress().toString() << " failed: " << sock->errorString();
sock->deleteLater();
// Try to connect with the next available SipInfo.
tryConnect();
}
void
ConnectionManager::socketConnected()
{
QTcpSocketExtra* sock = (QTcpSocketExtra*)sender();
peerInfoDebug( m_currentPeerInfo ) << Q_FUNC_INFO << "Connected to hostaddr: " << sock->peerAddress() << ", hostname:" << sock->peerName();
Q_ASSERT( !sock->_conn.isNull() );
handoverSocket( sock );
m_currentPeerInfo.clear();
m_mutex.unlock();
}
void
ConnectionManager::handoverSocket( QTcpSocketExtra* sock )
{
Q_ASSERT( !m_controlConnection.isNull() );
Q_ASSERT( sock );
Q_ASSERT( m_controlConnection->socket().isNull() );
Q_ASSERT( sock->isValid() );
disconnect( sock, SIGNAL( readyRead() ), this, SLOT( readyRead() ) );
disconnect( sock, SIGNAL( disconnected() ), sock, SLOT( deleteLater() ) );
disconnect( sock, SIGNAL( error( QAbstractSocket::SocketError ) ), this, SLOT( socketError( QAbstractSocket::SocketError ) ) );
sock->_disowned = true;
m_controlConnection->setOutbound( sock->_outbound );
m_controlConnection->setPeerPort( sock->peerPort() );
m_controlConnection->start( sock );
m_currentPeerInfo.clear();
m_mutex.unlock();
}
static QMutex* nodeMapMutex = new QMutex();
static QMap< QString, QSharedPointer< ConnectionManager > > connectionManagers;
QSharedPointer<ConnectionManager>
ConnectionManager::getManagerForNodeId( const QString &nodeid )
{
QMutexLocker locker( nodeMapMutex );
if ( connectionManagers.contains( nodeid ) && !connectionManagers.value( nodeid ).isNull() ) {
return connectionManagers.value( nodeid );
}
// There exists no connection for this nodeid
QSharedPointer< ConnectionManager > manager( new ConnectionManager( nodeid ) );
connectionManagers[nodeid] = manager;
return manager;
}

@ -0,0 +1,68 @@
/* === 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_H
#define CONNECTIONMANAGER_H
#include "DllMacro.h"
#include "sip/PeerInfo.h"
#include <QAbstractSocket>
#include <QObject>
#include <QMutex>
class QTcpSocketExtra;
class DLLEXPORT ConnectionManager : public QObject
{
Q_OBJECT
public:
static QSharedPointer<ConnectionManager> getManagerForNodeId( const QString& nodeid );
ConnectionManager( const QString& nodeid );
void handleSipInfo( const Tomahawk::peerinfo_ptr& peerInfo );
private slots:
void socketConnected();
void socketError( QAbstractSocket::SocketError error );
private:
void connectToPeer(const Tomahawk::peerinfo_ptr& peerInfo , bool lock);
void handleSipInfoPrivate( const Tomahawk::peerinfo_ptr& peerInfo );
/**
* Transfers ownership of socket to the ControlConnection and inits the ControlConnection
*/
void handoverSocket( QTcpSocketExtra* sock );
/**
* Attempt to connect to the peer using the current stored information.
*/
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

@ -276,7 +276,11 @@ void
ControlConnection::addPeerInfo( const peerinfo_ptr& peerInfo )
{
peerInfo->setControlConnection( this );
m_peerInfos.insert( peerInfo );
// Check if we already have added this peerInfo
if ( !m_peerInfos.contains( peerInfo ) )
{
m_peerInfos.insert( peerInfo );
}
}

@ -27,6 +27,7 @@
#include "ControlConnection.h"
#include "database/Database.h"
#include "database/DatabaseImpl.h"
#include "network/ConnectionManager.h"
#include "StreamConnection.h"
#include "SourceList.h"
#include "sip/SipInfo.h"
@ -247,7 +248,6 @@ Servent::createConnectionKey( const QString& name, const QString &nodeid, const
return _key;
}
bool
Servent::isValidExternalIP( const QHostAddress& addr )
{
@ -351,6 +351,17 @@ Servent::lookupControlConnection( const SipInfo& sipInfo )
return NULL;
}
ControlConnection*
Servent::lookupControlConnection( const QString& nodeid )
{
foreach ( ControlConnection* c, m_controlconnections )
{
if ( c->id() == nodeid )
return c;
}
return NULL;
}
QList<SipInfo>
Servent::getLocalSipInfos( const QString& nodeid, const QString& key )
@ -391,7 +402,7 @@ Servent::getLocalSipInfos( const QString& nodeid, const QString& key )
}
SipInfo
Servent::getSipInfoForOldVersions( const QList<SipInfo>& sipInfos ) const
Servent::getSipInfoForOldVersions( const QList<SipInfo>& sipInfos )
{
SipInfo info = SipInfo();
info.setVisible( false );
@ -429,7 +440,7 @@ Servent::registerPeer( const Tomahawk::peerinfo_ptr& peerInfo )
peerInfoDebug(peerInfo) << "we need to establish the connection now... thinking";
if ( !connectedToSession( peerInfo->nodeId() ) )
{
connectToPeer( peerInfo );
ConnectionManager::getManagerForNodeId( peerInfo->nodeId() )->handleSipInfo( peerInfo );
}
else
{
@ -491,40 +502,7 @@ void Servent::handleSipInfo( const Tomahawk::peerinfo_ptr& peerInfo )
if ( peerInfo->sipInfos().isEmpty() )
return;
// Respect different behaviour before 0.7.99
if ( !peerInfo->versionString().isEmpty() && TomahawkUtils::compareVersionStrings( peerInfo->versionString(), "Tomahawk Player EmptyOS 0.7.99" ) < 0)
{
SipInfo we = getSipInfoForOldVersions( getLocalSipInfos( QString(), QString() ) );
SipInfo they = peerInfo->sipInfos().first();
if ( they.isVisible() )
{
if ( !we.isVisible() || we.host() < they.host() || (we.host() == they.host() && we.port() < they.port()))
{
tLog( LOGVERBOSE ) << Q_FUNC_INFO << "Initiate connection to" << peerInfo->id() << "at" << they.host() << "peer of:" << peerInfo->sipPlugin()->account()->accountFriendlyName();
connectToPeer( peerInfo );
// We connected to the peer, so we are done here.
return;
}
}
}
foreach ( SipInfo info, peerInfo->sipInfos() )
{
if (info.isVisible())
{
// There is at least one SipInfo that may be visible. Try connecting.
// Duplicate Connections are checked by connectToPeer, so we do not need to take care of this
tLog( LOGVERBOSE ) << Q_FUNC_INFO << "Initiate connection to" << peerInfo->id() << "at" << info.host() << "peer of:" << peerInfo->sipPlugin()->account()->accountFriendlyName();
connectToPeer( peerInfo );
// We connected to the peer, so we are done here.
return;
}
}
// If we reach this point none of the previous SipInfos was visible.
if ( peerInfo->controlConnection() )
delete peerInfo->controlConnection();
tDebug() << Q_FUNC_INFO << peerInfo->id() << "They are not visible, doing nothing atm";
ConnectionManager::getManagerForNodeId( peerInfo->nodeId() )->handleSipInfo( peerInfo );
}
void
@ -721,7 +699,6 @@ Servent::createParallelConnection( Connection* orig_conn, Connection* new_conn,
// if we can connect to them directly:
if ( orig_conn && orig_conn->outbound() )
{
QList<SipInfo> sipInfo = QList<SipInfo>();
SipInfo info = SipInfo();
info.setVisible( true );
info.setKey( key );
@ -729,8 +706,7 @@ Servent::createParallelConnection( Connection* orig_conn, Connection* new_conn,
info.setHost( orig_conn->socket()->peerAddress().toString() );
info.setPort( orig_conn->peerPort() );
Q_ASSERT( info.isValid() );
sipInfo.append( info );
connectToPeer( peerinfo_ptr(), sipInfo, new_conn );
initiateConnection( info, new_conn );
}
else // ask them to connect to us:
{
@ -755,13 +731,13 @@ Servent::socketConnected()
{
QTcpSocketExtra* sock = (QTcpSocketExtra*)sender();
tDebug( LOGVERBOSE ) << Q_FUNC_INFO << thread() << "socket:" << sock << ", hostaddr:" << sock->peerAddress() << ", hostname:" << sock->peerName();
tLog( LOGVERBOSE ) << Q_FUNC_INFO << thread() << "socket:" << sock << ", hostaddr:" << sock->peerAddress() << ", hostname:" << sock->peerName();
if ( sock->_conn.isNull() )
{
sock->close();
sock->deleteLater();
tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "Socket's connection was null, could have timed out or been given an invalid address";
tLog( LOGVERBOSE ) << Q_FUNC_INFO << "Socket's connection was null, could have timed out or been given an invalid address";
return;
}
@ -769,9 +745,9 @@ Servent::socketConnected()
handoverSocket( conn, sock );
}
// transfers ownership of socket to the connection and inits the connection
void Servent::handoverSocket( Connection* conn, QTcpSocketExtra* sock )
void
Servent::handoverSocket( Connection* conn, QTcpSocketExtra* sock )
{
Q_ASSERT( conn );
Q_ASSERT( sock );
@ -780,8 +756,7 @@ void Servent::handoverSocket( Connection* conn, QTcpSocketExtra* sock )
disconnect( sock, SIGNAL( readyRead() ), this, SLOT( readyRead() ) );
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;
conn->setOutbound( sock->_outbound );
@ -807,149 +782,33 @@ Servent::cleanupSocket( QTcpSocketExtra *sock )
}
void
Servent::connectToPeer( const peerinfo_ptr& peerInfo )
Servent::initiateConnection( const SipInfo& sipInfo, Connection* conn )
{
Q_ASSERT( this->thread() == QThread::currentThread() );
peerInfoDebug( peerInfo ) << "connectToPeer: search for already established connections to the same nodeid:" << m_controlconnections.count() << "connections";
if ( peerInfo->controlConnection() )
{
if ( peerInfo->controlConnection()->isReady() && peerInfo->controlConnection()->isRunning() ) {
peerInfoDebug( peerInfo ) << Q_FUNC_INFO << "We have a running ControlConnection, so no use to connect.";
return;
}
else
{
peerInfoDebug( peerInfo ) << Q_FUNC_INFO << "deleting the existing ControlConnection";
delete peerInfo->controlConnection();
}
}
bool isDupe = false;
ControlConnection* conn = 0;
// try to find a ControlConnection with the same SipInfo, then we dont need to try to connect again
foreach ( ControlConnection* c, m_controlconnections )
{
Q_ASSERT( c );
if ( c->id() == peerInfo->nodeId() )
{
conn = c;
foreach ( const peerinfo_ptr& currentPeerInfo, c->peerInfos() )
{
peerInfoDebug( currentPeerInfo ) << "Same object:" << ( peerInfo == currentPeerInfo ) << ( peerInfo.data() == currentPeerInfo.data() ) << ( peerInfo->debugName() == currentPeerInfo->debugName() );
if ( peerInfo == currentPeerInfo )
{
isDupe = true;
peerInfoDebug( currentPeerInfo ) << "Not adding, because it's a dupe: peerInfoCount remains the same" << conn->peerInfos().count();
break;
}
}
if ( !c->peerInfos().contains( peerInfo ) )
{
c->addPeerInfo( peerInfo );
// peerInfoDebug(peerInfo) << "Adding " << peerInfo->debugName() << ", not a dupe... new peerInfoCount:" << c->peerInfos().count();
// foreach ( const peerinfo_ptr& kuh, c->peerInfos() )
// {
// peerInfoDebug(peerInfo) << " ** " << kuh->debugName();
// }
}
break;
}
}
peerInfoDebug( peerInfo ) << "connectToPeer: found a match:" << ( conn ? conn->name() : "false" ) << "dupe:" << isDupe;
if ( isDupe )
{
peerInfoDebug( peerInfo ) << "it's a dupe, nothing to do here, returning and stopping processing: peerInfoCount:" << conn->peerInfos().count();
}
if ( conn )
return;
QVariantMap m;
m["conntype"] = "accept-offer";
m["key"] = peerInfo->key();
m["nodeid"] = Database::instance()->impl()->dbid();
peerInfoDebug(peerInfo) << "No match found, creating a new ControlConnection...";
conn = new ControlConnection( this );
conn->addPeerInfo( peerInfo );
conn->setFirstMessage( m );
if ( peerInfo->id().length() )
conn->setName( peerInfo->contactId() );
if ( peerInfo->nodeId().length() )
conn->setId( peerInfo->nodeId() );
conn->setProperty( "nodeid", peerInfo->nodeId() );
registerControlConnection( conn );
connectToPeer( peerInfo, peerInfo->sipInfos(), conn );
}
void
Servent::connectToPeer(const peerinfo_ptr& peerInfo, const QList<SipInfo>& sipInfos, Connection* conn )
{
if ( sipInfos.isEmpty() )
{
if ( conn != NULL ) {
peerInfoDebug(peerInfo) << Q_FUNC_INFO << "No more possible SIP endpoints for " << conn->name() << " skipping.";
} else {
peerInfoDebug(peerInfo) << Q_FUNC_INFO << "No more possible SIP endpoints for <null connection> skipping.";
}
// If a peerinfo was supplied and has a ControlConnection which should be destroyed, than use this
if ( !peerInfo.isNull() && peerInfo->controlConnection() )
delete peerInfo->controlConnection();
else
// Connecting failed, so destroy this connection.
delete conn;
return;
}
QList<SipInfo> sipInfo = QList<SipInfo>( sipInfos );
// Use first available SIP endpoint and remove it from the list
SipInfo info = sipInfo.takeFirst();
if ( !info.isVisible() )
{
peerInfoDebug(peerInfo) << Q_FUNC_INFO << "Try next SipInfo, we can't connect to this one";
connectToPeer( peerInfo, sipInfo, conn );
return;
}
peerInfoDebug(peerInfo) << Q_FUNC_INFO << info.host() << ":" << info.port() << thread() << QThread::currentThread();
Q_ASSERT( info.port() > 0 );
Q_ASSERT( sipInfo.isValid() );
Q_ASSERT( sipInfo.isVisible() );
Q_ASSERT( sipInfo.port() > 0 );
Q_ASSERT( conn );
// Check that we are not connecting to ourselves
foreach( QHostAddress ha, m_externalAddresses )
{
if ( info.host() == ha.toString() )
if ( sipInfo.host() == ha.toString() )
{
peerInfoDebug(peerInfo) << Q_FUNC_INFO << "Tomahawk won't try to connect to" << info.host() << ":" << info.port() << ": same IP as ourselves.";
connectToPeer( peerInfo, sipInfo, conn );
tLog( LOGVERBOSE ) << Q_FUNC_INFO << "Tomahawk won't try to connect to" << sipInfo.host() << ":" << sipInfo.port() << ": same IP as ourselves.";
return;
}
}
if ( info.host() == m_externalHostname )
if ( sipInfo.host() == m_externalHostname )
{
peerInfoDebug(peerInfo) << Q_FUNC_INFO << "Tomahawk won't try to connect to" << info.host() << ":" << info.port() << ": same IP as ourselves.";
connectToPeer( peerInfo, sipInfo, conn );
tLog( LOGVERBOSE ) << Q_FUNC_INFO << "Tomahawk won't try to connect to" << sipInfo.host() << ":" << sipInfo.port() << ": same IP as ourselves.";
return;
}
if ( info.key().length() && conn->firstMessage().isNull() )
if ( !sipInfo.key().isEmpty() && conn->firstMessage().isNull() )
{
QVariantMap m;
m["conntype"] = "accept-offer";
m["key"] = info.key();
m["key"] = sipInfo.key();
m["controlid"] = Database::instance()->impl()->dbid();
conn->setFirstMessage( m );
}
@ -961,45 +820,43 @@ Servent::connectToPeer(const peerinfo_ptr& peerInfo, const QList<SipInfo>& sipIn
sock->_outbound = true;
connect( sock, SIGNAL( connected() ), SLOT( socketConnected() ) );
NewClosure( sock, SIGNAL( error( QAbstractSocket::SocketError ) ),
this, SLOT( connectToPeerFailed( Tomahawk::peerinfo_ptr, QList<SipInfo>, Connection*, QTcpSocketExtra* ) ),
peerInfo, sipInfo, conn, sock );
connect( sock, SIGNAL( error( QAbstractSocket::SocketError ) ), this, SLOT( socketError( QAbstractSocket::SocketError ) ) );
if ( !conn->peerIpAddress().isNull() )
sock->connectToHost( conn->peerIpAddress(), info.port(), QTcpSocket::ReadWrite );
sock->connectToHost( conn->peerIpAddress(), sipInfo.port(), QTcpSocket::ReadWrite );
else
sock->connectToHost( info.host(), info.port(), QTcpSocket::ReadWrite );
sock->connectToHost( sipInfo.host(), sipInfo.port(), QTcpSocket::ReadWrite );
sock->moveToThread( thread() );
}
void
Servent::connectToPeerFailed( const peerinfo_ptr& peerInfo, QList<SipInfo> sipInfo, Connection* conn, QTcpSocketExtra* socket )
{
peerInfoDebug(peerInfo) << Q_FUNC_INFO << "Connecting to " << socket->peerAddress().toString() << " failed: " << socket->errorString();
bool connIsNull = socket->_conn.isNull();
cleanupSocket( socket );
if ( !connIsNull ) {
// Try next SipInfo (don't do this if the connection was destroyed in between)
connectToPeer( peerInfo, sipInfo, conn );
}
else
{
peerInfoDebug( peerInfo ) << Q_FUNC_INFO << "Connecting stopped because Connection is null.";
}
}
void
Servent::socketError( QAbstractSocket::SocketError e )
{
QTcpSocketExtra* sock = (QTcpSocketExtra*)sender();
if ( !sock )
{
tLog() << "SocketError, sock is null";
return;
}
if ( !sock->_conn.isNull() )
{
Connection* conn = sock->_conn.data();
tLog() << Q_FUNC_INFO << e << conn->id() << conn->name();
}
tLog() << "Servent::SocketError:" << e << conn->id() << conn->name();
cleanupSocket( sock );
if ( !sock->_disowned )
{
// connection will delete if we already transferred ownership, otherwise:
sock->deleteLater();
}
conn->markAsFailed(); // will emit failed, then finished
}
else
{
tLog() << "SocketError, connection is null";
sock->deleteLater();
}
}
void

@ -66,6 +66,7 @@ Q_OBJECT
public:
static Servent* instance();
static bool isValidExternalIP( const QHostAddress& addr );
static SipInfo getSipInfoForOldVersions( const QList<SipInfo> &sipInfos );
explicit Servent( QObject* parent = 0 );
virtual ~Servent();
@ -81,6 +82,7 @@ public:
void registerControlConnection( ControlConnection* conn );
void unregisterControlConnection( ControlConnection* conn );
ControlConnection* lookupControlConnection( const SipInfo& sipInfo );
ControlConnection* lookupControlConnection( const QString& nodeid );
// you may call this method as often as you like for the same peerInfo, dupe checking is done inside
void registerPeer( const Tomahawk::peerinfo_ptr& peerInfo );
@ -90,8 +92,7 @@ public slots:
void onSipInfoChanged();
public:
void connectToPeer( const Tomahawk::peerinfo_ptr& ha );
void connectToPeer(const Tomahawk::peerinfo_ptr &peerInfo, const QList<SipInfo>& sipInfos, Connection* conn );
void initiateConnection( const SipInfo& sipInfo, Connection* conn );
void reverseOfferRequest( ControlConnection* orig_conn, const QString &theirdbid, const QString& key, const QString& theirkey );
bool visibleExternally() const { return (!m_externalHostname.isNull()) || (m_externalAddresses.length() > 0); }
@ -132,7 +133,6 @@ public:
bool isReady() const { return m_ready; }
QList<SipInfo> getLocalSipInfos(const QString& nodeid, const QString &key);
SipInfo getSipInfoForOldVersions( const QList<SipInfo> &sipInfos ) const;
signals:
void dbSyncTriggered();
void streamStarted( StreamConnection* );
@ -145,7 +145,6 @@ protected:
public slots:
void setExternalAddress( QHostAddress ha, unsigned int port );
void connectToPeerFailed( const Tomahawk::peerinfo_ptr& peerInfo, QList<SipInfo> sipInfo, Connection* conn , QTcpSocketExtra *socket );
void socketError( QAbstractSocket::SocketError e );
void createParallelConnection( Connection* orig_conn, Connection* new_conn, const QString& key );