mirror of
https://github.com/tomahawk-player/tomahawk.git
synced 2025-03-20 07:49:42 +01:00
Merge pull request #184 from tomahawk-player/feature/sip-multiple-ip-addresses
Let SIP handle multiple IP Addresses per client
This commit is contained in:
commit
90ba7eae5b
@ -23,7 +23,7 @@ ENDIF()
|
||||
|
||||
SET( TOMAHAWK_VERSION_MAJOR 0 )
|
||||
SET( TOMAHAWK_VERSION_MINOR 7 )
|
||||
SET( TOMAHAWK_VERSION_PATCH 99 )
|
||||
SET( TOMAHAWK_VERSION_PATCH 999 )
|
||||
#SET( TOMAHAWK_VERSION_RC 0 )
|
||||
|
||||
SET( TOMAHAWK_TRANSLATION_LANGUAGES ar bg bn_IN ca cs de en el es fi fr hi_IN hu gl it ja lt pl pt_BR ru sv tr zh_CN zh_TW )
|
||||
|
@ -2,6 +2,7 @@
|
||||
*
|
||||
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
* Copyright 2010-2011, Jeff Mitchell <jeff@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
|
||||
@ -21,60 +22,41 @@
|
||||
|
||||
#include "utils/Logger.h"
|
||||
|
||||
|
||||
class TomahawkXmppMessagePrivate
|
||||
TomahawkXmppMessage::TomahawkXmppMessage()
|
||||
: m_sipInfos()
|
||||
{
|
||||
public:
|
||||
QString ip;
|
||||
int port;
|
||||
QString uniqname;
|
||||
QString key;
|
||||
bool visible;
|
||||
};
|
||||
|
||||
TomahawkXmppMessage::TomahawkXmppMessage(const QString &ip, unsigned int port, const QString &uniqname, const QString &key) : d_ptr(new TomahawkXmppMessagePrivate)
|
||||
{
|
||||
Q_D(TomahawkXmppMessage);
|
||||
d->ip = ip;
|
||||
d->port = port;
|
||||
d->uniqname = uniqname;
|
||||
d->key = key;
|
||||
d->visible = true;
|
||||
}
|
||||
|
||||
TomahawkXmppMessage::TomahawkXmppMessage() : d_ptr(new TomahawkXmppMessagePrivate)
|
||||
TomahawkXmppMessage::TomahawkXmppMessage( const QList<SipInfo> &sipInfos )
|
||||
: m_sipInfos( sipInfos )
|
||||
{
|
||||
Q_D(TomahawkXmppMessage);
|
||||
d->visible = false;
|
||||
d->port = -1;
|
||||
}
|
||||
|
||||
|
||||
TomahawkXmppMessage::~TomahawkXmppMessage()
|
||||
{
|
||||
}
|
||||
|
||||
const QString TomahawkXmppMessage::ip() const
|
||||
const QList<SipInfo>
|
||||
TomahawkXmppMessage::sipInfos() const
|
||||
{
|
||||
return d_func()->ip;
|
||||
return m_sipInfos;
|
||||
}
|
||||
|
||||
unsigned int TomahawkXmppMessage::port() const
|
||||
|
||||
const QString
|
||||
TomahawkXmppMessage::key() const
|
||||
{
|
||||
return d_func()->port;
|
||||
if ( m_sipInfos.isEmpty() )
|
||||
return QString();
|
||||
else
|
||||
return m_sipInfos.first().key();
|
||||
}
|
||||
|
||||
const QString TomahawkXmppMessage::uniqname() const
|
||||
const QString
|
||||
TomahawkXmppMessage::uniqname() const
|
||||
{
|
||||
return d_func()->uniqname;
|
||||
}
|
||||
|
||||
const QString TomahawkXmppMessage::key() const
|
||||
{
|
||||
return d_func()->key;
|
||||
}
|
||||
|
||||
bool TomahawkXmppMessage::visible() const
|
||||
{
|
||||
return d_func()->visible;
|
||||
if ( m_sipInfos.isEmpty() )
|
||||
return QString();
|
||||
else
|
||||
return m_sipInfos.first().nodeId();
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
*
|
||||
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
* Copyright 2010-2011, Jeff Mitchell <jeff@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
|
||||
@ -22,30 +23,37 @@
|
||||
|
||||
#include <jreen/stanzaextension.h>
|
||||
|
||||
#include "sip/SipInfo.h"
|
||||
|
||||
#define TOMAHAWK_SIP_MESSAGE_NS QLatin1String("http://www.tomhawk-player.org/sip/transports")
|
||||
|
||||
#include "accounts/AccountDllMacro.h"
|
||||
|
||||
class TomahawkXmppMessagePrivate;
|
||||
class ACCOUNTDLLEXPORT TomahawkXmppMessage : public Jreen::Payload
|
||||
{
|
||||
J_PAYLOAD(TomahawkXmppMessage)
|
||||
Q_DECLARE_PRIVATE(TomahawkXmppMessage)
|
||||
public:
|
||||
// sets visible to true
|
||||
TomahawkXmppMessage(const QString &ip, unsigned int port, const QString &uniqname, const QString &key);
|
||||
|
||||
// sets visible to false as we dont have any extra information
|
||||
TomahawkXmppMessage();
|
||||
TomahawkXmppMessage(const QList<SipInfo>& sipInfos);
|
||||
~TomahawkXmppMessage();
|
||||
|
||||
const QString ip() const;
|
||||
unsigned int port() const;
|
||||
const QString uniqname() const;
|
||||
/**
|
||||
* The SipInfo objects that are wrapped in this XmppMessage
|
||||
*/
|
||||
const QList<SipInfo> sipInfos() const;
|
||||
|
||||
/**
|
||||
* The name of the peer contained in this message
|
||||
*/
|
||||
const QString key() const;
|
||||
bool visible() const;
|
||||
|
||||
/**
|
||||
* The name of the peer contained in this message
|
||||
*/
|
||||
const QString uniqname() const;
|
||||
|
||||
private:
|
||||
QScopedPointer<TomahawkXmppMessagePrivate> d_ptr;
|
||||
QList<SipInfo> m_sipInfos;
|
||||
};
|
||||
|
||||
#endif // ENTITYTIME_H
|
||||
|
@ -2,6 +2,7 @@
|
||||
*
|
||||
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
* Copyright 2010-2011, Jeff Mitchell <jeff@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
|
||||
@ -19,6 +20,7 @@
|
||||
|
||||
#include "TomahawkXmppMessageFactory.h"
|
||||
|
||||
#include "network/Servent.h"
|
||||
#include "utils/Logger.h"
|
||||
|
||||
#include <QStringList>
|
||||
@ -29,6 +31,7 @@
|
||||
using namespace Jreen;
|
||||
|
||||
TomahawkXmppMessageFactory::TomahawkXmppMessageFactory()
|
||||
: m_sipInfos()
|
||||
{
|
||||
m_depth = 0;
|
||||
m_state = AtNowhere;
|
||||
@ -54,31 +57,35 @@ void TomahawkXmppMessageFactory::handleStartElement(const QStringRef &name, cons
|
||||
const QXmlStreamAttributes &attributes)
|
||||
{
|
||||
m_depth++;
|
||||
if (m_depth == 1) {
|
||||
if ( m_depth == 1 )
|
||||
{
|
||||
m_state = AtNowhere;
|
||||
m_ip = QString();
|
||||
m_port = -1;
|
||||
m_uniqname = QString();
|
||||
m_key = QString();
|
||||
m_visible = false;
|
||||
} else if (m_depth == 2) {
|
||||
if (name == QLatin1String("transport"))
|
||||
m_sipInfos = QList<SipInfo>();
|
||||
}
|
||||
else if ( m_depth == 2 )
|
||||
{
|
||||
if ( name == QLatin1String( "transport" ) )
|
||||
{
|
||||
// qDebug() << "Found Transport";
|
||||
m_state = AtTransport;
|
||||
|
||||
m_uniqname = attributes.value(QLatin1String("uniqname")).toString();
|
||||
m_key = attributes.value(QLatin1String("pwd")).toString();
|
||||
m_uniqname = attributes.value( QLatin1String( "uniqname" ) ).toString();
|
||||
m_key = attributes.value( QLatin1String( "pwd" ) ).toString();
|
||||
}
|
||||
} else if(m_depth == 3) {
|
||||
if (name == QLatin1String("candidate"))
|
||||
}
|
||||
else if(m_depth == 3)
|
||||
{
|
||||
if ( name == QLatin1String( "candidate" ) )
|
||||
{
|
||||
m_state = AtCandidate;
|
||||
// qDebug() << "Found candidate";
|
||||
m_ip = attributes.value(QLatin1String("ip")).toString();
|
||||
m_port = attributes.value(QLatin1String("port")).toString().toInt();
|
||||
|
||||
m_visible = true;
|
||||
SipInfo info = SipInfo();
|
||||
info.setVisible( true );
|
||||
info.setHost( attributes.value( QLatin1String( "ip" ) ).toString() );
|
||||
info.setPort( attributes.value( QLatin1String( "port" ) ).toString().toInt() );
|
||||
info.setKey( m_key );
|
||||
info.setNodeId( m_uniqname );
|
||||
Q_ASSERT( info.isValid() );
|
||||
m_sipInfos.append( info );
|
||||
}
|
||||
}
|
||||
Q_UNUSED(uri);
|
||||
@ -87,8 +94,22 @@ void TomahawkXmppMessageFactory::handleStartElement(const QStringRef &name, cons
|
||||
|
||||
void TomahawkXmppMessageFactory::handleEndElement(const QStringRef &name, const QStringRef &uri)
|
||||
{
|
||||
if (m_depth == 3)
|
||||
if ( m_depth == 3 )
|
||||
m_state = AtTransport;
|
||||
else if ( m_depth == 2 )
|
||||
{
|
||||
m_state = AtNowhere;
|
||||
// Check that we have at least one SipInfo so that we provide some information about invisible peers.
|
||||
if ( m_sipInfos.isEmpty() )
|
||||
{
|
||||
SipInfo info = SipInfo();
|
||||
info.setVisible( false );
|
||||
info.setKey( m_key );
|
||||
info.setNodeId( m_uniqname );
|
||||
Q_ASSERT( info.isValid() );
|
||||
m_sipInfos.append( info );
|
||||
}
|
||||
}
|
||||
Q_UNUSED(name);
|
||||
Q_UNUSED(uri);
|
||||
m_depth--;
|
||||
@ -111,38 +132,69 @@ void TomahawkXmppMessageFactory::serialize(Payload *extension, QXmlStreamWriter
|
||||
{
|
||||
TomahawkXmppMessage *sipMessage = se_cast<TomahawkXmppMessage*>(extension);
|
||||
|
||||
writer->writeStartElement(QLatin1String("tomahawk"));
|
||||
writer->writeDefaultNamespace(TOMAHAWK_SIP_MESSAGE_NS);
|
||||
writer->writeStartElement( QLatin1String( "tomahawk" ) );
|
||||
writer->writeDefaultNamespace( TOMAHAWK_SIP_MESSAGE_NS );
|
||||
|
||||
if(sipMessage->visible())
|
||||
// Get a copy of the list, so that we can modify it here.
|
||||
QList<SipInfo> sipInfos = QList<SipInfo>( sipMessage->sipInfos() );
|
||||
SipInfo lastInfo;
|
||||
foreach ( SipInfo info, sipInfos )
|
||||
{
|
||||
if ( info.isVisible() )
|
||||
{
|
||||
// add transport tag
|
||||
writer->writeStartElement(QLatin1String("transport"));
|
||||
writer->writeAttribute(QLatin1String("pwd"), sipMessage->key());
|
||||
writer->writeAttribute(QLatin1String("uniqname"), sipMessage->uniqname());
|
||||
QHostAddress ha = QHostAddress( info.host() );
|
||||
if ( ( Servent::isValidExternalIP( ha ) && ha.protocol() == QAbstractSocket::IPv4Protocol ) || ( ha.protocol() == QAbstractSocket::UnknownNetworkLayerProtocol ) || ( ha.isNull() && !info.host().isEmpty() ) )
|
||||
{
|
||||
// For comapability reasons, this shall be put as the last candidate (this is the IP/host that would have been sent in previous versions)
|
||||
lastInfo = info;
|
||||
sipInfos.removeOne( info );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
writer->writeEmptyElement(QLatin1String("candidate"));
|
||||
writer->writeAttribute(QLatin1String("component"), "1");
|
||||
writer->writeAttribute(QLatin1String("id"), "el0747fg11"); // FIXME
|
||||
writer->writeAttribute(QLatin1String("ip"), sipMessage->ip());
|
||||
writer->writeAttribute(QLatin1String("network"), "1");
|
||||
writer->writeAttribute(QLatin1String("port"), QVariant(sipMessage->port()).toString());
|
||||
writer->writeAttribute(QLatin1String("priority"), "1"); //TODO
|
||||
writer->writeAttribute(QLatin1String("protocol"), "tcp");
|
||||
writer->writeAttribute(QLatin1String("type"), "host"); //FIXME: correct?!
|
||||
writer->writeEndElement();
|
||||
}
|
||||
else
|
||||
{
|
||||
writer->writeEmptyElement(QLatin1String("transport"));
|
||||
}
|
||||
writer->writeEndElement();
|
||||
writer->writeStartElement( QLatin1String( "transport" ) );
|
||||
writer->writeAttribute( QLatin1String( "pwd" ), sipMessage->key() );
|
||||
writer->writeAttribute( QLatin1String( "uniqname" ), sipMessage->uniqname() );
|
||||
|
||||
foreach ( SipInfo info, sipInfos )
|
||||
{
|
||||
if ( info.isVisible() )
|
||||
serializeSipInfo( info, writer );
|
||||
}
|
||||
|
||||
if ( lastInfo.isValid() )
|
||||
{
|
||||
Q_ASSERT( lastInfo.isVisible() );
|
||||
tLog( LOGVERBOSE ) << Q_FUNC_INFO << "Using " << lastInfo.host() << ":" << lastInfo.port() << " as the host which all older clients will only detect";
|
||||
serializeSipInfo( lastInfo, writer );
|
||||
}
|
||||
|
||||
// </transport>
|
||||
writer->writeEndElement();
|
||||
// </tomahawk>
|
||||
writer->writeEndElement();
|
||||
}
|
||||
|
||||
Payload::Ptr TomahawkXmppMessageFactory::createPayload()
|
||||
Payload::Ptr
|
||||
TomahawkXmppMessageFactory::createPayload()
|
||||
{
|
||||
if(m_visible)
|
||||
return Payload::Ptr(new TomahawkXmppMessage(m_ip, m_port, m_uniqname, m_key));
|
||||
else
|
||||
return Payload::Ptr(new TomahawkXmppMessage());
|
||||
return Payload::Ptr( new TomahawkXmppMessage( m_sipInfos ) );
|
||||
}
|
||||
|
||||
void
|
||||
TomahawkXmppMessageFactory::serializeSipInfo(SipInfo &info, QXmlStreamWriter *writer)
|
||||
{
|
||||
if ( info.isVisible() )
|
||||
{
|
||||
writer->writeEmptyElement( QLatin1String( "candidate" ) );
|
||||
writer->writeAttribute( QLatin1String( "component" ), "1" );
|
||||
writer->writeAttribute( QLatin1String( "id" ), "el0747fg11" ); // FIXME
|
||||
writer->writeAttribute( QLatin1String( "ip" ), info.host() );
|
||||
writer->writeAttribute( QLatin1String( "network" ), "1" );
|
||||
writer->writeAttribute( QLatin1String( "port" ), QVariant( info.port() ).toString() );
|
||||
writer->writeAttribute( QLatin1String( "priority" ), "1" ); //TODO
|
||||
writer->writeAttribute( QLatin1String( "protocol" ), "tcp" );
|
||||
writer->writeAttribute( QLatin1String( "type" ), "host" ); //FIXME: correct?!
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
*
|
||||
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
* Copyright 2010-2011, Jeff Mitchell <jeff@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
|
||||
@ -39,13 +40,29 @@ public:
|
||||
void serialize(Jreen::Payload *extension, QXmlStreamWriter *writer);
|
||||
Jreen::Payload::Ptr createPayload();
|
||||
private:
|
||||
void serializeSipInfo(SipInfo& info, QXmlStreamWriter *writer);
|
||||
|
||||
enum State { AtNowhere, AtTransport, AtCandidate } m_state;
|
||||
|
||||
/**
|
||||
* All the provided Sip informations
|
||||
*/
|
||||
QList<SipInfo> m_sipInfos;
|
||||
|
||||
/**
|
||||
* The current parsing depth
|
||||
*/
|
||||
int m_depth;
|
||||
QString m_ip;
|
||||
int m_port;
|
||||
|
||||
/**
|
||||
* The unique name of the peer
|
||||
*/
|
||||
QString m_uniqname;
|
||||
|
||||
/**
|
||||
* The authentication key of the peer
|
||||
*/
|
||||
QString m_key;
|
||||
bool m_visible;
|
||||
};
|
||||
|
||||
#endif // ENTITYTIMEFACTORY_P_H
|
||||
|
@ -4,6 +4,7 @@
|
||||
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
* Copyright 2011, Leo Franchi <lfranchi@kde.org>
|
||||
* Copyright 2010-2012, Jeff Mitchell <jeff@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
|
||||
@ -435,22 +436,15 @@ XmppSipPlugin::errorMessage( Jreen::Client::DisconnectReason reason )
|
||||
|
||||
|
||||
void
|
||||
XmppSipPlugin::sendSipInfo( const Tomahawk::peerinfo_ptr& receiver, const SipInfo& info )
|
||||
XmppSipPlugin::sendSipInfos( const Tomahawk::peerinfo_ptr& receiver, const QList<SipInfo>& info )
|
||||
{
|
||||
tDebug( LOGVERBOSE ) << Q_FUNC_INFO << receiver << info;
|
||||
|
||||
if ( !m_client )
|
||||
return;
|
||||
|
||||
TomahawkXmppMessage *sipMessage;
|
||||
if ( info.isVisible() )
|
||||
{
|
||||
sipMessage = new TomahawkXmppMessage( info.host(), info.port(), info.nodeId(), info.key() );
|
||||
}
|
||||
else
|
||||
sipMessage = new TomahawkXmppMessage();
|
||||
|
||||
qDebug() << "Send sip messsage to" << receiver;
|
||||
TomahawkXmppMessage* sipMessage = new TomahawkXmppMessage( info );
|
||||
tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "Send sip messsage to" << receiver;
|
||||
Jreen::IQ iq( Jreen::IQ::Set, receiver->id() );
|
||||
iq.addExtension( sipMessage );
|
||||
Jreen::IQReply *reply = m_client->send( iq );
|
||||
@ -687,6 +681,7 @@ XmppSipPlugin::onNewMessage( const Jreen::Message& message )
|
||||
return;
|
||||
}
|
||||
|
||||
// FIXME: We do not sent SipInfo in JSON via XMPP, why do we receive it here?
|
||||
SipInfo info = SipInfo::fromJson( msg );
|
||||
if ( !info.isValid() )
|
||||
{
|
||||
@ -885,12 +880,22 @@ XmppSipPlugin::onNewIq( const Jreen::IQ& iq )
|
||||
Jreen::SoftwareVersion::Ptr softwareVersion = iq.payload<Jreen::SoftwareVersion>();
|
||||
if ( softwareVersion )
|
||||
{
|
||||
QMutexLocker locker( &peerQueueMutex );
|
||||
QString versionString = QString( "%1 %2 %3" ).arg( softwareVersion->name(), softwareVersion->os(), softwareVersion->version() );
|
||||
qDebug() << Q_FUNC_INFO << "Received software version for" << iq.from().full() << ":" << versionString;
|
||||
Tomahawk::peerinfo_ptr peerInfo = PeerInfo::get( this, iq.from().full() );
|
||||
if ( !peerInfo.isNull() )
|
||||
{
|
||||
peerInfo->setVersionString( versionString );
|
||||
if ( sipinfosQueue.contains( iq.from().full() ) )
|
||||
{
|
||||
peerInfo->setSipInfos( sipinfosQueue.value( iq.from().full() ) );
|
||||
sipinfosQueue.remove( iq.from().full() );
|
||||
}
|
||||
if ( peersWaitingForVersionString.contains( iq.from().full() ) )
|
||||
{
|
||||
peersWaitingForVersionString.remove( iq.from().full() );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -911,31 +916,37 @@ XmppSipPlugin::onNewIq( const Jreen::IQ& iq )
|
||||
TomahawkXmppMessage::Ptr sipMessage = iq.payload< TomahawkXmppMessage >();
|
||||
if ( sipMessage )
|
||||
{
|
||||
QMutexLocker locker( &peerQueueMutex );
|
||||
iq.accept();
|
||||
tLog( LOGVERBOSE ) << Q_FUNC_INFO << "Received Sip Information from:" << iq.from().full();
|
||||
|
||||
qDebug() << Q_FUNC_INFO << "Got SipMessage ..."
|
||||
<< "ip" << sipMessage->ip() << "port" << sipMessage->port() << "nodeId" << sipMessage->uniqname() << "key" << sipMessage->key() << "visible" << sipMessage->visible();
|
||||
|
||||
SipInfo info;
|
||||
info.setVisible( sipMessage->visible() );
|
||||
if ( sipMessage->visible() )
|
||||
// Check that all received SipInfos are valid.
|
||||
foreach ( SipInfo info, sipMessage->sipInfos() )
|
||||
{
|
||||
info.setHost( sipMessage->ip() );
|
||||
info.setPort( sipMessage->port() );
|
||||
info.setNodeId( sipMessage->uniqname() );
|
||||
info.setKey( sipMessage->key() );
|
||||
Q_ASSERT( info.isValid() );
|
||||
}
|
||||
|
||||
Q_ASSERT( info.isValid() );
|
||||
|
||||
qDebug() << Q_FUNC_INFO << "From:" << iq.from().full() << ":" << info;
|
||||
// Get the peer information for the sender.
|
||||
Tomahawk::peerinfo_ptr peerInfo = PeerInfo::get( this, iq.from().full() );
|
||||
if ( peerInfo.isNull() )
|
||||
{
|
||||
tDebug() << Q_FUNC_INFO << "no valid peerInfo for" << iq.from().full();
|
||||
return;
|
||||
}
|
||||
peerInfo->setSipInfo( info );
|
||||
if ( peerInfo->versionString().isEmpty() )
|
||||
{
|
||||
// If we do not have a version string, this peerInfo is still queued. So we queue its SipInfo until we have a valid version string.
|
||||
sipinfosQueue[iq.from().full()] = sipMessage->sipInfos();
|
||||
}
|
||||
else
|
||||
{
|
||||
peerInfo->setSipInfos( sipMessage->sipInfos() );
|
||||
}
|
||||
// If we stored a reference for this peer in our sip-waiting-queue, remove it.
|
||||
if ( peersWaitingForSip.contains( iq.from().full() ) )
|
||||
{
|
||||
peersWaitingForSip.remove( iq.from().full() );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -977,7 +988,21 @@ XmppSipPlugin::handlePeerStatus( const Jreen::JID& jid, Jreen::Presence::Type pr
|
||||
Tomahawk::peerinfo_ptr peerInfo = PeerInfo::get( this, fulljid );
|
||||
if ( !peerInfo.isNull() )
|
||||
{
|
||||
QMutexLocker locker( &peerQueueMutex );
|
||||
peerInfo->setStatus( PeerInfo::Offline );
|
||||
// If we stored a reference for this peer in our sip-waiting-queue, remove it.
|
||||
if ( peersWaitingForSip.contains( fulljid ) )
|
||||
{
|
||||
peersWaitingForSip.remove( fulljid );
|
||||
}
|
||||
if ( peersWaitingForVersionString.contains( fulljid ) )
|
||||
{
|
||||
peersWaitingForVersionString.remove( fulljid );
|
||||
}
|
||||
if ( sipinfosQueue.contains( fulljid ) )
|
||||
{
|
||||
sipinfosQueue.remove( fulljid );
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
@ -989,12 +1014,15 @@ XmppSipPlugin::handlePeerStatus( const Jreen::JID& jid, Jreen::Presence::Type pr
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO << "* Peer goes online:" << fulljid;
|
||||
|
||||
QMutexLocker locker( &peerQueueMutex );
|
||||
m_peers[ jid ] = presenceType;
|
||||
|
||||
Tomahawk::peerinfo_ptr peerInfo = PeerInfo::get( this, fulljid, PeerInfo::AutoCreate );
|
||||
peerInfo->setContactId( jid.bare() );
|
||||
peerInfo->setStatus( PeerInfo::Online );
|
||||
peerInfo->setFriendlyName( m_jidsNames.value( jid.bare() ) );
|
||||
peersWaitingForSip[fulljid] = peerInfo;
|
||||
peersWaitingForVersionString[fulljid] = peerInfo;
|
||||
|
||||
#ifndef ENABLE_HEADLESS
|
||||
if ( !m_avatarManager->avatar( jid.bare() ).isNull() )
|
||||
|
@ -4,6 +4,7 @@
|
||||
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
* Copyright 2011, Leo Franchi <lfranchi@kde.org>
|
||||
* Copyright 2010-2011, Jeff Mitchell <jeff@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
|
||||
@ -90,7 +91,7 @@ public slots:
|
||||
virtual void configurationChanged();
|
||||
virtual void addContact( const QString& peerId, const QString& msg = QString() );
|
||||
|
||||
virtual void sendSipInfo( const Tomahawk::peerinfo_ptr& receiver, const SipInfo& info );
|
||||
virtual void sendSipInfos( const Tomahawk::peerinfo_ptr& receiver, const QList<SipInfo>& info );
|
||||
|
||||
void showAddFriendDialog();
|
||||
void publishTune( const QUrl& url, const Tomahawk::InfoSystem::InfoStringHash& trackInfo );
|
||||
@ -153,6 +154,10 @@ private:
|
||||
enum IqContext { NoContext, RequestDisco, RequestedDisco, SipMessageSent, RequestedVCard, RequestVersion, RequestedVersion };
|
||||
AvatarManager* m_avatarManager;
|
||||
Jreen::PubSub::Manager* m_pubSubManager;
|
||||
QMap< QString, Tomahawk::peerinfo_ptr > peersWaitingForSip;
|
||||
QMap< QString, Tomahawk::peerinfo_ptr > peersWaitingForVersionString;
|
||||
QMap< QString, QList< SipInfo > > sipinfosQueue;
|
||||
QMutex peerQueueMutex;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -1,6 +1,7 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@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
|
||||
@ -29,6 +30,7 @@
|
||||
#include <QList>
|
||||
#include <QHostAddress>
|
||||
#include <QHostInfo>
|
||||
#include <QNetworkInterface>
|
||||
#include <QNetworkProxy>
|
||||
#include <QUdpSocket>
|
||||
#include <QTimer>
|
||||
@ -131,6 +133,10 @@ private slots:
|
||||
m_sock.readDatagram( datagram.data(), datagram.size(), &sender, &senderPort );
|
||||
qDebug() << "DATAGRAM RCVD" << QString::fromLatin1( datagram ) << sender;
|
||||
|
||||
// Ignore our own requests
|
||||
if ( QNetworkInterface::allAddresses().contains( sender ) )
|
||||
return;
|
||||
|
||||
// only process msgs originating on the LAN:
|
||||
if ( datagram.startsWith( "TOMAHAWKADVERT:" ) &&
|
||||
Servent::isIPWhitelisted( sender ) )
|
||||
|
@ -161,7 +161,9 @@ ZeroconfPlugin::lanHostFound( const QString& host, int port, const QString& name
|
||||
sipInfo.setVisible( true );
|
||||
|
||||
Tomahawk::peerinfo_ptr peerInfo = Tomahawk::PeerInfo::get( this, host, Tomahawk::PeerInfo::AutoCreate );
|
||||
peerInfo->setSipInfo( sipInfo );
|
||||
QList<SipInfo> sipInfos = QList<SipInfo>();
|
||||
sipInfos.append( sipInfo );
|
||||
peerInfo->setSipInfos( sipInfos );
|
||||
peerInfo->setContactId( host );
|
||||
peerInfo->setFriendlyName( name );
|
||||
peerInfo->setType( PeerInfo::Local );
|
||||
|
@ -65,7 +65,7 @@ public slots:
|
||||
|
||||
void advertise();
|
||||
|
||||
void sendSipInfo( const Tomahawk::peerinfo_ptr&, const SipInfo& ) {}
|
||||
virtual void sendSipInfos( const Tomahawk::peerinfo_ptr& receiver, const QList<SipInfo>& info ) {}
|
||||
void broadcastMsg( const QString & ) {}
|
||||
void addContact( const QString &, const QString& ) {}
|
||||
|
||||
|
@ -306,6 +306,8 @@ list(APPEND libSources
|
||||
network/Servent.cpp
|
||||
network/Connection.cpp
|
||||
network/ControlConnection.cpp
|
||||
network/QTcpSocketExtra.cpp
|
||||
network/ConnectionManager.cpp
|
||||
|
||||
playlist/PlaylistUpdaterInterface.cpp
|
||||
playlist/dynamic/DynamicPlaylist.cpp
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "database/DatabaseCommand_LoadAllSources.h"
|
||||
#include "database/DatabaseCommand_SourceOffline.h"
|
||||
#include "database/DatabaseCommand_UpdateSearchIndex.h"
|
||||
#include "database/DatabaseImpl.h"
|
||||
#include "database/Database.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
@ -81,10 +82,30 @@ Source::~Source()
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
bool
|
||||
Source::setControlConnection( ControlConnection* cc )
|
||||
{
|
||||
m_cc = cc;
|
||||
QMutexLocker locker( &m_setControlConnectionMutex );
|
||||
if ( !m_cc.isNull() && m_cc->isReady() && m_cc->isRunning() )
|
||||
{
|
||||
const QString& nodeid = Database::instance()->impl()->dbid();
|
||||
if ( cc->id() < nodeid && m_cc->outbound() )
|
||||
{
|
||||
m_cc = cc;
|
||||
// This ControlConnection is not needed anymore, get rid of it!
|
||||
m_cc->deleteLater();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_cc = cc;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -456,6 +477,12 @@ Source::playlistInterface()
|
||||
return m_playlistInterface;
|
||||
}
|
||||
|
||||
QSharedPointer<QMutexLocker>
|
||||
Source::acquireLock()
|
||||
{
|
||||
return QSharedPointer<QMutexLocker>( new QMutexLocker( &m_mutex ) );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Source::onPlaybackStarted( const Tomahawk::track_ptr& track, unsigned int duration )
|
||||
|
@ -2,6 +2,7 @@
|
||||
*
|
||||
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
* Copyright 2010-2012, Jeff Mitchell <jeff@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
|
||||
@ -25,6 +26,7 @@
|
||||
#include <QtCore/QVariantMap>
|
||||
|
||||
#include "Typedefs.h"
|
||||
#include "network/ControlConnection.h"
|
||||
#include "network/DbSyncConnection.h"
|
||||
#include "collection/Collection.h"
|
||||
#include "Query.h"
|
||||
@ -32,7 +34,6 @@
|
||||
|
||||
#include "DllMacro.h"
|
||||
|
||||
class ControlConnection;
|
||||
class DatabaseCommand_DeleteFiles;
|
||||
class DatabaseCommand_LoadAllSources;
|
||||
class DatabaseCommand_LogPlayback;
|
||||
@ -85,8 +86,8 @@ public:
|
||||
void removeCollection( const Tomahawk::collection_ptr& c );
|
||||
|
||||
int id() const { return m_id; }
|
||||
ControlConnection* controlConnection() const { return m_cc; }
|
||||
void setControlConnection( ControlConnection* cc );
|
||||
ControlConnection* controlConnection() const { return m_cc.data(); }
|
||||
bool setControlConnection( ControlConnection* cc );
|
||||
|
||||
const QSet< Tomahawk::peerinfo_ptr > peerInfos() const;
|
||||
|
||||
@ -101,6 +102,8 @@ public:
|
||||
|
||||
Tomahawk::playlistinterface_ptr playlistInterface();
|
||||
|
||||
QSharedPointer<QMutexLocker> acquireLock();
|
||||
|
||||
signals:
|
||||
void syncedWithDatabase();
|
||||
void synced();
|
||||
@ -168,11 +171,13 @@ private:
|
||||
DBSyncConnection::State m_state;
|
||||
QTimer m_currentTrackTimer;
|
||||
|
||||
ControlConnection* m_cc;
|
||||
QPointer<ControlConnection> m_cc;
|
||||
QList< QSharedPointer<DatabaseCommand> > m_cmds;
|
||||
int m_commandCount;
|
||||
QString m_lastCmdGuid;
|
||||
mutable QMutex m_cmdMutex;
|
||||
QMutex m_setControlConnectionMutex;
|
||||
QMutex m_mutex;
|
||||
|
||||
Tomahawk::playlistinterface_ptr m_playlistInterface;
|
||||
};
|
||||
|
@ -2,6 +2,7 @@
|
||||
*
|
||||
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
* Copyright 2010-2011, Jeff Mitchell <jeff@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
|
||||
@ -216,14 +217,19 @@ void
|
||||
Connection::checkACLResult( const QString &nodeid, const QString &username, ACLRegistry::ACL peerStatus )
|
||||
{
|
||||
QString bareName = name().contains( '/' ) ? name().left( name().indexOf( "/" ) ) : name();
|
||||
if ( nodeid != property( "nodeid" ).toString() || username != bareName )
|
||||
if ( nodeid != property( "nodeid" ).toString() )
|
||||
{
|
||||
tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "nodeid not ours, or username not our barename";
|
||||
tDebug( LOGVERBOSE ) << Q_FUNC_INFO << QString( "nodeid (%1) not ours (%2) for user %3" ).arg( nodeid ).arg( property( "nodeid" ).toString() ).arg( username );
|
||||
return;
|
||||
}
|
||||
if ( username != bareName )
|
||||
{
|
||||
tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "username not our barename";
|
||||
return;
|
||||
}
|
||||
|
||||
disconnect( ACLRegistry::instance(), SIGNAL( aclResult( QString, QString, ACLRegistry::ACL ) ) );
|
||||
tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "ACL status is" << peerStatus;
|
||||
tDebug( LOGVERBOSE ) << Q_FUNC_INFO << QString( "ACL status for user %1 is" ).arg( username ) << peerStatus;
|
||||
if ( peerStatus == ACLRegistry::Stream )
|
||||
{
|
||||
QTimer::singleShot( 0, this, SLOT( doSetup() ) );
|
||||
@ -306,15 +312,20 @@ Connection::doSetup()
|
||||
void
|
||||
Connection::socketDisconnected()
|
||||
{
|
||||
qint64 bytesAvailable = 0;
|
||||
if ( !m_sock.isNull() )
|
||||
{
|
||||
bytesAvailable = m_sock->bytesAvailable();
|
||||
}
|
||||
tDebug( LOGVERBOSE ) << "SOCKET DISCONNECTED" << this->name() << id()
|
||||
<< "shutdown will happen after incoming queue empties."
|
||||
<< "bytesavail:" << m_sock->bytesAvailable()
|
||||
<< "bytesavail:" << bytesAvailable
|
||||
<< "bytesRecvd" << bytesReceived();
|
||||
|
||||
m_peer_disconnected = true;
|
||||
emit socketClosed();
|
||||
|
||||
if ( m_msgprocessor_in.length() == 0 && m_sock->bytesAvailable() == 0 )
|
||||
if ( m_msgprocessor_in.length() == 0 && bytesAvailable == 0 )
|
||||
{
|
||||
handleIncomingQueueEmpty();
|
||||
actualShutdown();
|
||||
|
@ -60,28 +60,28 @@ public:
|
||||
|
||||
void setFirstMessage( const QVariant& m );
|
||||
void setFirstMessage( msg_ptr m );
|
||||
msg_ptr firstMessage() const { return m_firstmsg; };
|
||||
msg_ptr firstMessage() const { return m_firstmsg; }
|
||||
|
||||
const QPointer<QTcpSocket>& socket() { return m_sock; };
|
||||
const QPointer<QTcpSocket>& socket() { return m_sock; }
|
||||
|
||||
void setOutbound( bool o ) { m_outbound = o; };
|
||||
void setOutbound( bool o ) { m_outbound = o; }
|
||||
bool outbound() const { return m_outbound; }
|
||||
|
||||
Servent* servent() { return m_servent; };
|
||||
Servent* servent() { return m_servent; }
|
||||
|
||||
// get public port of remote peer:
|
||||
int peerPort() { return m_peerport; };
|
||||
void setPeerPort( int p ) { m_peerport = p; };
|
||||
int peerPort() { return m_peerport; }
|
||||
void setPeerPort( int p ) { m_peerport = p; }
|
||||
|
||||
void markAsFailed();
|
||||
|
||||
void setName( const QString& n ) { m_name = n; };
|
||||
QString name() const { return m_name; };
|
||||
void setName( const QString& n ) { m_name = n; }
|
||||
QString name() const { return m_name; }
|
||||
|
||||
void setOnceOnly( bool b ) { m_onceonly = b; };
|
||||
bool onceOnly() const { return m_onceonly; };
|
||||
void setOnceOnly( bool b ) { m_onceonly = b; }
|
||||
bool onceOnly() const { return m_onceonly; }
|
||||
|
||||
bool isReady() const { return m_ready; } ;
|
||||
bool isReady() const { return m_ready; }
|
||||
bool isRunning() const { return m_sock != 0; }
|
||||
|
||||
qint64 bytesSent() const { return m_tx_bytes; }
|
||||
|
261
src/libtomahawk/network/ConnectionManager.cpp
Normal file
261
src/libtomahawk/network/ConnectionManager.cpp
Normal file
@ -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.999
|
||||
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.999" ) < 0)
|
||||
{
|
||||
peerInfoDebug( peerInfo ) << Q_FUNC_INFO << "Using old-style (<0.7.999) connection order.";
|
||||
SipInfo we = Servent::getSipInfoForOldVersions( Servent::instance()->getLocalSipInfos( QString( "default" ), QString( "default" ) ) );
|
||||
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( 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;
|
||||
}
|
68
src/libtomahawk/network/ConnectionManager.h
Normal file
68
src/libtomahawk/network/ConnectionManager.h
Normal file
@ -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
|
@ -100,20 +100,29 @@ ControlConnection::setup()
|
||||
|
||||
// setup source and remote collection for this peer
|
||||
m_source = SourceList::instance()->get( id(), friendlyName, true );
|
||||
m_source->setControlConnection( this );
|
||||
QSharedPointer<QMutexLocker> locker = m_source->acquireLock();
|
||||
if ( m_source->setControlConnection( this ) )
|
||||
{
|
||||
// We are the new ControlConnection for this source
|
||||
|
||||
// delay setting up collection/etc until source is synced.
|
||||
// we need it DB synced so it has an ID + exists in DB.
|
||||
connect( m_source.data(), SIGNAL( syncedWithDatabase() ),
|
||||
SLOT( registerSource() ), Qt::QueuedConnection );
|
||||
// delay setting up collection/etc until source is synced.
|
||||
// we need it DB synced so it has an ID + exists in DB.
|
||||
connect( m_source.data(), SIGNAL( syncedWithDatabase() ),
|
||||
SLOT( registerSource() ), Qt::QueuedConnection );
|
||||
|
||||
m_source->setOnline();
|
||||
m_source->setOnline();
|
||||
|
||||
m_pingtimer = new QTimer;
|
||||
m_pingtimer->setInterval( 5000 );
|
||||
connect( m_pingtimer, SIGNAL( timeout() ), SLOT( onPingTimer() ) );
|
||||
m_pingtimer->start();
|
||||
m_pingtimer_mark.start();
|
||||
m_pingtimer = new QTimer;
|
||||
m_pingtimer->setInterval( 5000 );
|
||||
connect( m_pingtimer, SIGNAL( timeout() ), SLOT( onPingTimer() ) );
|
||||
m_pingtimer->start();
|
||||
m_pingtimer_mark.start();
|
||||
}
|
||||
else
|
||||
{
|
||||
// There is already another ControlConnection in use, we are useless.
|
||||
deleteLater();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -121,13 +130,18 @@ ControlConnection::setup()
|
||||
void
|
||||
ControlConnection::registerSource()
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO << m_source->id();
|
||||
Source* source = (Source*) sender();
|
||||
Q_UNUSED( source )
|
||||
Q_ASSERT( source == m_source.data() );
|
||||
QSharedPointer<QMutexLocker> locker = m_source->acquireLock();
|
||||
// Only continue if we are still the ControlConnection associated with this source.
|
||||
if ( m_source->controlConnection() == this )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO << m_source->id();
|
||||
Source* source = (Source*) sender();
|
||||
Q_UNUSED( source )
|
||||
Q_ASSERT( source == m_source.data() );
|
||||
|
||||
m_registered = true;
|
||||
setupDbSyncConnection();
|
||||
m_registered = true;
|
||||
setupDbSyncConnection();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -221,6 +235,7 @@ ControlConnection::handleMsg( msg_ptr msg )
|
||||
if ( !msg->is( Msg::JSON ) )
|
||||
{
|
||||
Q_ASSERT( msg->is( Msg::JSON ) );
|
||||
tLog( LOGVERBOSE ) << Q_FUNC_INFO << "Received message was not in JSON format";
|
||||
markAsFailed();
|
||||
return;
|
||||
}
|
||||
|
65
src/libtomahawk/network/QTcpSocketExtra.cpp
Normal file
65
src/libtomahawk/network/QTcpSocketExtra.cpp
Normal file
@ -0,0 +1,65 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
* Copyright 2010-2012, Jeff Mitchell <jeff@tomahawk-player.org>
|
||||
* Copyright 2013, Teo Mrnjavac <teo@kde.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 "QTcpSocketExtra.h"
|
||||
|
||||
#include "utils/Logger.h"
|
||||
|
||||
void
|
||||
QTcpSocketExtra::connectToHost( const QHostAddress& host, quint16 port, OpenMode openMode )
|
||||
{
|
||||
if ( m_connectTimer->isActive() == true )
|
||||
{
|
||||
tLog() << Q_FUNC_INFO << "Connection already establishing.";
|
||||
return;
|
||||
}
|
||||
|
||||
QTcpSocket::connectToHost( host, port, openMode);
|
||||
if ( m_connectTimeout > 0 )
|
||||
m_connectTimer->start( m_connectTimeout );
|
||||
}
|
||||
|
||||
void
|
||||
QTcpSocketExtra::connectToHost(const QString& host, quint16 port, OpenMode openMode)
|
||||
{
|
||||
if ( m_connectTimer->isActive() == true )
|
||||
{
|
||||
tLog() << Q_FUNC_INFO << "Connection already establishing.";
|
||||
return;
|
||||
}
|
||||
|
||||
QTcpSocket::connectToHost( host, port, openMode);
|
||||
if ( m_connectTimeout > 0 )
|
||||
m_connectTimer->start( m_connectTimeout );
|
||||
}
|
||||
|
||||
void
|
||||
QTcpSocketExtra::connectTimeout()
|
||||
{
|
||||
m_connectTimer->stop();
|
||||
if ( state() != ConnectedState )
|
||||
{
|
||||
// We did not manage to connect in the given timespan, so abort the attempt...
|
||||
abort();
|
||||
// .. and notify error handlers.
|
||||
emit error( SocketTimeoutError );
|
||||
}
|
||||
}
|
93
src/libtomahawk/network/QTcpSocketExtra.h
Normal file
93
src/libtomahawk/network/QTcpSocketExtra.h
Normal file
@ -0,0 +1,93 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
* Copyright 2010-2012, Jeff Mitchell <jeff@tomahawk-player.org>
|
||||
* Copyright 2013, Teo Mrnjavac <teo@kde.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 QTCPSOCKETEXTRA_H
|
||||
#define QTCPSOCKETEXTRA_H
|
||||
|
||||
// time before new connection terminates if no auth received
|
||||
#define AUTH_TIMEOUT 180000
|
||||
|
||||
#include <QPointer>
|
||||
#include <QString>
|
||||
#include <QTcpSocket>
|
||||
#include <QTimer>
|
||||
|
||||
#include "Msg.h"
|
||||
#include "DllMacro.h"
|
||||
|
||||
class Connection;
|
||||
|
||||
// this is used to hold a bit of state, so when a connected signal is emitted
|
||||
// from a socket, we can associate it with a Connection object etc.
|
||||
// In addition, functionality to limit the connection timeout is implemented.
|
||||
class DLLEXPORT QTcpSocketExtra : public QTcpSocket
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
QTcpSocketExtra() : QTcpSocket(), m_connectTimeout( -1 )
|
||||
{
|
||||
QTimer::singleShot( AUTH_TIMEOUT, this, SLOT( authTimeout() ) ) ;
|
||||
m_connectTimer = new QTimer( this );
|
||||
connect( m_connectTimer, SIGNAL( timeout() ), this, SLOT( connectTimeout() ) );
|
||||
}
|
||||
|
||||
void connectToHost(const QString& host, quint16 port, OpenMode openMode = ReadWrite );
|
||||
void connectToHost( const QHostAddress& host, quint16 port, OpenMode openMode = ReadWrite );
|
||||
|
||||
QPointer<Connection> _conn;
|
||||
bool _outbound;
|
||||
bool _disowned;
|
||||
msg_ptr _msg;
|
||||
|
||||
/**
|
||||
* Set a time limit for establishing a connection.
|
||||
*/
|
||||
void setConnectTimeout( qint32 timeout ) { m_connectTimeout = timeout; }
|
||||
|
||||
/**
|
||||
* Get the current timeout for establishing a connection.
|
||||
*/
|
||||
qint32 connectTimeout() const { return m_connectTimeout; }
|
||||
|
||||
private slots:
|
||||
void connectTimeout();
|
||||
void authTimeout()
|
||||
{
|
||||
if( _disowned )
|
||||
return;
|
||||
|
||||
qDebug() << "Connection timed out before providing a valid offer-key";
|
||||
this->disconnectFromHost();
|
||||
}
|
||||
private:
|
||||
/**
|
||||
* How long we will wait for a connection to establish
|
||||
*/
|
||||
qint32 m_connectTimeout;
|
||||
|
||||
/**
|
||||
* Timer to measure the connection initialisation
|
||||
*/
|
||||
QTimer* m_connectTimer;
|
||||
};
|
||||
|
||||
#endif // QTCPSOCKETEXTRA_H
|
@ -3,6 +3,7 @@
|
||||
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
* Copyright 2010-2012, Jeff Mitchell <jeff@tomahawk-player.org>
|
||||
* Copyright 2013, Teo Mrnjavac <teo@kde.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
|
||||
@ -27,6 +28,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"
|
||||
@ -34,6 +36,7 @@
|
||||
#include "sip/SipPlugin.h"
|
||||
#include "PortFwdThread.h"
|
||||
#include "TomahawkSettings.h"
|
||||
#include "utils/Closure.h"
|
||||
#include "utils/TomahawkUtils.h"
|
||||
#include "utils/Logger.h"
|
||||
#include "accounts/AccountManager.h"
|
||||
@ -50,6 +53,14 @@
|
||||
|
||||
#include <boost/bind.hpp>
|
||||
|
||||
|
||||
typedef QPair< QList< SipInfo >, Connection* > sipConnectionPair;
|
||||
Q_DECLARE_METATYPE( sipConnectionPair )
|
||||
Q_DECLARE_METATYPE( QList< SipInfo > )
|
||||
Q_DECLARE_METATYPE( Connection* )
|
||||
Q_DECLARE_METATYPE( QTcpSocketExtra* )
|
||||
Q_DECLARE_METATYPE( Tomahawk::peerinfo_ptr )
|
||||
|
||||
using namespace Tomahawk;
|
||||
|
||||
Servent* Servent::s_instance = 0;
|
||||
@ -70,7 +81,6 @@ Servent::Servent( QObject* parent )
|
||||
{
|
||||
s_instance = this;
|
||||
|
||||
m_lanHack = qApp->arguments().contains( "--lanhack" );
|
||||
m_noAuth = qApp->arguments().contains( "--noauth" );
|
||||
|
||||
setProxy( QNetworkProxy::NoProxy );
|
||||
@ -113,6 +123,7 @@ Servent::~Servent()
|
||||
bool
|
||||
Servent::startListening( QHostAddress ha, bool upnp, int port )
|
||||
{
|
||||
m_externalAddresses = QList<QHostAddress>();
|
||||
m_port = port;
|
||||
int defPort = TomahawkSettings::instance()->defaultPort();
|
||||
|
||||
@ -125,8 +136,8 @@ Servent::startListening( QHostAddress ha, bool upnp, int port )
|
||||
{
|
||||
if ( !listen( ha, defPort ) )
|
||||
{
|
||||
tLog() << "Failed to listen on both port" << m_port << "and port" << defPort;
|
||||
tLog() << "Error string is:" << errorString();
|
||||
tLog() << Q_FUNC_INFO << "Failed to listen on both port" << m_port << "and port" << defPort;
|
||||
tLog() << Q_FUNC_INFO << "Error string is:" << errorString();
|
||||
return false;
|
||||
}
|
||||
else
|
||||
@ -134,38 +145,67 @@ Servent::startListening( QHostAddress ha, bool upnp, int port )
|
||||
}
|
||||
}
|
||||
|
||||
TomahawkSettings::ExternalAddressMode mode = TomahawkSettings::instance()->externalAddressMode();
|
||||
if ( ha == QHostAddress::AnyIPv6 )
|
||||
{
|
||||
// We are listening on all available addresses, so we should send a SipInfo for all of them.
|
||||
foreach ( QHostAddress addr, QNetworkInterface::allAddresses() )
|
||||
{
|
||||
if ( addr.toString() == "127.0.0.1" )
|
||||
continue; // IPv4 localhost
|
||||
if ( addr.toString() == "::1" )
|
||||
continue; // IPv6 localhost
|
||||
if ( addr.toString() == "::7F00:1" )
|
||||
continue; // IPv4 localhost as IPv6 address
|
||||
if ( addr.isInSubnet( QHostAddress::parseSubnet( "fe80::/10" ) ) )
|
||||
continue; // Skip link local addresses
|
||||
tLog( LOGVERBOSE ) << Q_FUNC_INFO << "Listening to " << addr.toString();
|
||||
m_externalAddresses.append( addr );
|
||||
}
|
||||
|
||||
tLog() << "Servent listening on port" << m_port << "- servent thread:" << thread()
|
||||
}
|
||||
else if ( ( ha.toString() != "127.0.0.1" ) && ( ha.toString() != "::1" ) && ( ha.toString() != "::7F00:1" ) )
|
||||
{
|
||||
// We listen only to one specific Address, only announce this.
|
||||
m_externalAddresses.append( ha );
|
||||
}
|
||||
// If we only accept connections via localhost, we'll announce nothing.
|
||||
|
||||
TomahawkSettings::ExternalAddressMode mode = TomahawkSettings::instance()->externalAddressMode();
|
||||
tLog( LOGVERBOSE ) << Q_FUNC_INFO << "Servent listening on port" << m_port << "- servent thread:" << thread()
|
||||
<< "- address mode:" << (int)( mode );
|
||||
|
||||
// --lanhack means to advertise your LAN IP as if it were externally visible
|
||||
switch ( mode )
|
||||
{
|
||||
case TomahawkSettings::Static:
|
||||
m_externalHostname = TomahawkSettings::instance()->externalHostname();
|
||||
m_externalPort = TomahawkSettings::instance()->externalPort();
|
||||
m_ready = true;
|
||||
// All setup is made, were done.
|
||||
emit ready();
|
||||
break;
|
||||
|
||||
case TomahawkSettings::Lan:
|
||||
setInternalAddress();
|
||||
// Nothing has to be done here.
|
||||
m_ready = true;
|
||||
emit ready();
|
||||
break;
|
||||
|
||||
case TomahawkSettings::Upnp:
|
||||
if ( !upnp )
|
||||
if ( upnp )
|
||||
{
|
||||
setInternalAddress();
|
||||
break;
|
||||
// upnp could be turned of on the cli with --noupnp
|
||||
tLog( LOGVERBOSE ) << Q_FUNC_INFO << "External address mode set to upnp...";
|
||||
m_portfwd = QPointer< PortFwdThread >( new PortFwdThread( m_port ) );
|
||||
Q_ASSERT( m_portfwd );
|
||||
connect( m_portfwd.data(), SIGNAL( externalAddressDetected( QHostAddress, unsigned int ) ),
|
||||
SLOT( setExternalAddress( QHostAddress, unsigned int ) ) );
|
||||
m_portfwd.data()->start();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ready = true;
|
||||
emit ready();
|
||||
}
|
||||
// TODO check if we have a public/internet IP on this machine directly
|
||||
tLog() << "External address mode set to upnp...";
|
||||
m_portfwd = QPointer< PortFwdThread >( new PortFwdThread( m_port ) );
|
||||
Q_ASSERT( m_portfwd );
|
||||
connect( m_portfwd.data(), SIGNAL( externalAddressDetected( QHostAddress, unsigned int ) ),
|
||||
SLOT( setExternalAddress( QHostAddress, unsigned int ) ) );
|
||||
m_portfwd.data()->start();
|
||||
break;
|
||||
}
|
||||
|
||||
@ -173,6 +213,25 @@ Servent::startListening( QHostAddress ha, bool upnp, int port )
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Servent::setExternalAddress( QHostAddress ha, unsigned int port )
|
||||
{
|
||||
if ( isValidExternalIP( ha ) )
|
||||
{
|
||||
m_externalHostname = ha.toString();
|
||||
m_externalPort = port;
|
||||
}
|
||||
|
||||
if ( m_externalPort == 0 || !isValidExternalIP( ha ) )
|
||||
tLog() << Q_FUNC_INFO << "UPnP failed, no further external address could be acquired!";
|
||||
else
|
||||
tLog( LOGVERBOSE ) << Q_FUNC_INFO << "UPnP setup successful";
|
||||
|
||||
m_ready = true;
|
||||
emit ready();
|
||||
}
|
||||
|
||||
|
||||
QString
|
||||
Servent::createConnectionKey( const QString& name, const QString &nodeid, const QString &key, bool onceOnly )
|
||||
{
|
||||
@ -190,12 +249,56 @@ Servent::createConnectionKey( const QString& name, const QString &nodeid, const
|
||||
return _key;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Servent::isValidExternalIP( const QHostAddress& addr ) const
|
||||
Servent::isValidExternalIP( const QHostAddress& addr )
|
||||
{
|
||||
QString ip = addr.toString();
|
||||
if ( !m_lanHack && ( ip.startsWith( "10." ) || ip.startsWith( "172.16." ) || ip.startsWith( "192.168." ) ) )
|
||||
if (addr.protocol() == QAbstractSocket::IPv4Protocol)
|
||||
{
|
||||
// private network
|
||||
if ( addr.isInSubnet(QHostAddress::parseSubnet("10.0.0.0/8")) )
|
||||
return false;
|
||||
// localhost
|
||||
if ( addr.isInSubnet(QHostAddress::parseSubnet("127.0.0.0/8")) )
|
||||
return false;
|
||||
// private network
|
||||
if ( addr.isInSubnet(QHostAddress::parseSubnet("169.254.0.0/16")) )
|
||||
return false;
|
||||
// private network
|
||||
if ( addr.isInSubnet(QHostAddress::parseSubnet("172.16.0.0/12")) )
|
||||
return false;
|
||||
// private network
|
||||
if ( addr.isInSubnet(QHostAddress::parseSubnet("192.168.0.0/16")) )
|
||||
return false;
|
||||
// multicast
|
||||
if ( addr.isInSubnet(QHostAddress::parseSubnet("224.0.0.0/4")) )
|
||||
return false;
|
||||
}
|
||||
else if (addr.protocol() == QAbstractSocket::IPv4Protocol)
|
||||
{
|
||||
// "unspecified address"
|
||||
if ( addr.isInSubnet(QHostAddress::parseSubnet("::/128")) )
|
||||
return false;
|
||||
// link-local
|
||||
if ( addr.isInSubnet(QHostAddress::parseSubnet("fe80::/10")) )
|
||||
return false;
|
||||
// unique local addresses
|
||||
if ( addr.isInSubnet(QHostAddress::parseSubnet("fc00::/7")) )
|
||||
return false;
|
||||
// benchmarking only
|
||||
if ( addr.isInSubnet(QHostAddress::parseSubnet("2001:2::/48")) )
|
||||
return false;
|
||||
// non-routed IPv6 addresses used for Cryptographic Hash Identifiers
|
||||
if ( addr.isInSubnet(QHostAddress::parseSubnet("2001:10::/28")) )
|
||||
return false;
|
||||
// documentation prefix
|
||||
if ( addr.isInSubnet(QHostAddress::parseSubnet("2001:db8::/32")) )
|
||||
return false;
|
||||
// multicast
|
||||
if ( addr.isInSubnet(QHostAddress::parseSubnet("ff00::0/8 ")) )
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@ -203,60 +306,35 @@ Servent::isValidExternalIP( const QHostAddress& addr ) const
|
||||
return !addr.isNull();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Servent::setInternalAddress()
|
||||
{
|
||||
foreach ( QHostAddress ha, QNetworkInterface::allAddresses() )
|
||||
{
|
||||
if ( ha.toString() == "127.0.0.1" )
|
||||
continue;
|
||||
if ( ha.toString().contains( ":" ) )
|
||||
continue; //ipv6
|
||||
|
||||
if ( m_lanHack && isValidExternalIP( ha ) )
|
||||
{
|
||||
tLog() << "LANHACK: set external address to lan address" << ha.toString();
|
||||
setExternalAddress( ha, m_port );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ready = true;
|
||||
emit ready();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Servent::setExternalAddress( QHostAddress ha, unsigned int port )
|
||||
{
|
||||
if ( isValidExternalIP( ha ) )
|
||||
{
|
||||
m_externalAddress = ha;
|
||||
m_externalPort = port;
|
||||
}
|
||||
|
||||
if ( m_externalPort == 0 || !isValidExternalIP( ha ) )
|
||||
{
|
||||
tLog() << "UPnP failed, LAN and outbound connections only!";
|
||||
setInternalAddress();
|
||||
return;
|
||||
}
|
||||
|
||||
tLog() << "UPnP setup successful";
|
||||
m_ready = true;
|
||||
emit ready();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Servent::registerOffer( const QString& key, Connection* conn )
|
||||
{
|
||||
m_offers[key] = QPointer<Connection>(conn);
|
||||
}
|
||||
|
||||
void
|
||||
Servent::registerLazyOffer(const QString &key, const peerinfo_ptr &peerInfo, const QString &nodeid, const int timeout )
|
||||
{
|
||||
m_lazyoffers[key] = QPair< peerinfo_ptr, QString >( peerInfo, nodeid );
|
||||
QTimer* timer = new QTimer( this );
|
||||
timer->setInterval( timeout );
|
||||
timer->setSingleShot( true );
|
||||
NewClosure( timer, SIGNAL( timeout() ), this, SLOT( deleteLazyOffer( const QString& ) ), key );
|
||||
timer->start();
|
||||
}
|
||||
|
||||
void
|
||||
Servent::deleteLazyOffer( const QString& key )
|
||||
{
|
||||
m_lazyoffers.remove( key );
|
||||
|
||||
// Cleanup.
|
||||
QTimer* timer = (QTimer*)sender();
|
||||
if ( timer )
|
||||
{
|
||||
timer->deleteLater();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Servent::registerControlConnection( ControlConnection* conn )
|
||||
@ -292,6 +370,73 @@ 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 )
|
||||
{
|
||||
QList<SipInfo> sipInfos = QList<SipInfo>();
|
||||
foreach ( QHostAddress ha, m_externalAddresses )
|
||||
{
|
||||
SipInfo info = SipInfo();
|
||||
info.setHost( ha.toString() );
|
||||
info.setPort( m_port );
|
||||
info.setKey( key );
|
||||
info.setVisible( true );
|
||||
info.setNodeId( nodeid );
|
||||
sipInfos.append( info );
|
||||
}
|
||||
if ( m_externalHostname.length() > 0)
|
||||
{
|
||||
SipInfo info = SipInfo();
|
||||
info.setHost( m_externalHostname );
|
||||
info.setPort( m_externalPort );
|
||||
info.setKey( key );
|
||||
info.setVisible( true );
|
||||
info.setNodeId( nodeid );
|
||||
sipInfos.append( info );
|
||||
}
|
||||
|
||||
if ( sipInfos.isEmpty() )
|
||||
{
|
||||
// We are not visible via any IP, send a dummy SipInfo
|
||||
SipInfo info = SipInfo();
|
||||
info.setVisible( false );
|
||||
info.setKey( key );
|
||||
info.setNodeId( nodeid );
|
||||
tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "Only accepting connections, no usable IP to listen to found.";
|
||||
}
|
||||
|
||||
return sipInfos;
|
||||
}
|
||||
|
||||
SipInfo
|
||||
Servent::getSipInfoForOldVersions( const QList<SipInfo>& sipInfos )
|
||||
{
|
||||
SipInfo info = SipInfo();
|
||||
info.setVisible( false );
|
||||
foreach ( SipInfo _info, sipInfos )
|
||||
{
|
||||
QHostAddress ha = QHostAddress( _info.host() );
|
||||
if ( ( Servent::isValidExternalIP( ha ) && ha.protocol() == QAbstractSocket::IPv4Protocol ) || ( ha.protocol() == QAbstractSocket::UnknownNetworkLayerProtocol ) || ( ha.isNull() && !_info.host().isEmpty() ))
|
||||
{
|
||||
info = _info;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
void
|
||||
Servent::registerPeer( const Tomahawk::peerinfo_ptr& peerInfo )
|
||||
@ -312,9 +457,9 @@ Servent::registerPeer( const Tomahawk::peerinfo_ptr& peerInfo )
|
||||
if ( peerInfo->type() == Tomahawk::PeerInfo::Local )
|
||||
{
|
||||
peerInfoDebug(peerInfo) << "we need to establish the connection now... thinking";
|
||||
if ( !connectedToSession( peerInfo->sipInfo().nodeId() ) )
|
||||
if ( !connectedToSession( peerInfo->nodeId() ) )
|
||||
{
|
||||
connectToPeer( peerInfo );
|
||||
ConnectionManager::getManagerForNodeId( peerInfo->nodeId() )->handleSipInfo( peerInfo );
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -335,35 +480,23 @@ Servent::registerPeer( const Tomahawk::peerinfo_ptr& peerInfo )
|
||||
}
|
||||
else
|
||||
{
|
||||
SipInfo info;
|
||||
QString peerId = peerInfo->id();
|
||||
QString key = uuid();
|
||||
ControlConnection* conn = new ControlConnection( this );
|
||||
|
||||
const QString& nodeid = Database::instance()->impl()->dbid();
|
||||
conn->setName( peerInfo->contactId() );
|
||||
conn->setId( nodeid );
|
||||
conn->addPeerInfo( peerInfo );
|
||||
|
||||
if ( visibleExternally() )
|
||||
QList<SipInfo> sipInfos = getLocalSipInfos( nodeid, key );
|
||||
// The offer should be removed after some time or we will build up a heap of unused PeerInfos
|
||||
registerLazyOffer( key, peerInfo, nodeid, sipInfos.length() * 1.5 * CONNECT_TIMEOUT );
|
||||
// SipInfos were single-value before 0.7.999
|
||||
if ( !peerInfo->versionString().isEmpty() && TomahawkUtils::compareVersionStrings( peerInfo->versionString().split(' ').last(), "0.7.999" ) < 0)
|
||||
{
|
||||
registerOffer( key, conn );
|
||||
info.setVisible( true );
|
||||
info.setHost( externalAddress() );
|
||||
info.setPort( externalPort() );
|
||||
info.setKey( key );
|
||||
info.setNodeId( nodeid );
|
||||
|
||||
tDebug() << "Asking them (" << peerInfo->id() << ") to connect to us:" << info;
|
||||
SipInfo info = getSipInfoForOldVersions( sipInfos );
|
||||
peerInfo->sendLocalSipInfos( QList<SipInfo>() << info );
|
||||
}
|
||||
else
|
||||
{
|
||||
info.setVisible( false );
|
||||
tDebug() << "We are not visible externally:" << info;
|
||||
peerInfo->sendLocalSipInfos( sipInfos );
|
||||
}
|
||||
|
||||
peerInfo->sendLocalSipInfo( info );
|
||||
|
||||
handleSipInfo( peerInfo );
|
||||
connect( peerInfo.data(), SIGNAL( sipInfoChanged() ), SLOT( onSipInfoChanged() ) );
|
||||
}
|
||||
@ -384,43 +517,12 @@ Servent::onSipInfoChanged()
|
||||
|
||||
void Servent::handleSipInfo( const Tomahawk::peerinfo_ptr& peerInfo )
|
||||
{
|
||||
tLog() << Q_FUNC_INFO << peerInfo->id() << peerInfo->sipInfo();
|
||||
|
||||
SipInfo info = peerInfo->sipInfo();
|
||||
if ( !info.isValid() )
|
||||
// We do not have received the initial SipInfo for this client yet, so wait for it.
|
||||
// Each client will have at least one non-visible SipInfo
|
||||
if ( peerInfo->sipInfos().isEmpty() )
|
||||
return;
|
||||
|
||||
/*
|
||||
If only one party is externally visible, connection is obvious
|
||||
If both are, peer with lowest IP address initiates the connection.
|
||||
|
||||
This avoids dupe connections.
|
||||
*/
|
||||
if ( info.isVisible() )
|
||||
{
|
||||
if ( !visibleExternally() ||
|
||||
externalAddress() < info.host() ||
|
||||
( externalAddress() == info.host() && externalPort() < info.port() ) )
|
||||
{
|
||||
|
||||
tDebug() << "Initiate connection to" << peerInfo->id() << "at" << info.host() << "peer of:" << peerInfo->sipPlugin()->account()->accountFriendlyName();
|
||||
connectToPeer( peerInfo );
|
||||
}
|
||||
else
|
||||
{
|
||||
tDebug() << Q_FUNC_INFO << "They should be conecting to us...";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
tDebug() << Q_FUNC_INFO << "They are not visible, doing nothing atm";
|
||||
|
||||
if ( !visibleExternally() )
|
||||
{
|
||||
if ( peerInfo->controlConnection() )
|
||||
delete peerInfo->controlConnection();
|
||||
}
|
||||
}
|
||||
ConnectionManager::getManagerForNodeId( peerInfo->nodeId() )->handleSipInfo( peerInfo );
|
||||
}
|
||||
|
||||
void
|
||||
@ -450,6 +552,7 @@ Servent::readyRead()
|
||||
{
|
||||
Q_ASSERT( this->thread() == QThread::currentThread() );
|
||||
QPointer< QTcpSocketExtra > sock = (QTcpSocketExtra*)sender();
|
||||
tLog( LOGVERBOSE ) << Q_FUNC_INFO << "Starting to read from new incoming connection from: " << sock->peerAddress().toString();
|
||||
|
||||
if ( sock.isNull() || sock.data()->_disowned )
|
||||
{
|
||||
@ -616,10 +719,14 @@ Servent::createParallelConnection( Connection* orig_conn, Connection* new_conn,
|
||||
// if we can connect to them directly:
|
||||
if ( orig_conn && orig_conn->outbound() )
|
||||
{
|
||||
connectToPeer( orig_conn->socket()->peerAddress().toString(),
|
||||
orig_conn->peerPort(),
|
||||
key,
|
||||
new_conn );
|
||||
SipInfo info = SipInfo();
|
||||
info.setVisible( true );
|
||||
info.setKey( key );
|
||||
info.setNodeId( orig_conn->id() );
|
||||
info.setHost( orig_conn->socket()->peerAddress().toString() );
|
||||
info.setPort( orig_conn->peerPort() );
|
||||
Q_ASSERT( info.isValid() );
|
||||
initiateConnection( info, new_conn );
|
||||
}
|
||||
else // ask them to connect to us:
|
||||
{
|
||||
@ -631,7 +738,6 @@ Servent::createParallelConnection( Connection* orig_conn, Connection* new_conn,
|
||||
m.insert( "conntype", "request-offer" );
|
||||
m.insert( "key", tmpkey );
|
||||
m.insert( "offer", key );
|
||||
m.insert( "port", externalPort() );
|
||||
m.insert( "controlid", Database::instance()->impl()->dbid() );
|
||||
|
||||
QJson::Serializer ser;
|
||||
@ -645,13 +751,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;
|
||||
}
|
||||
|
||||
@ -659,9 +765,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 );
|
||||
@ -670,8 +776,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 );
|
||||
@ -680,6 +785,69 @@ void Servent::handoverSocket( Connection* conn, QTcpSocketExtra* sock )
|
||||
conn->start( sock );
|
||||
}
|
||||
|
||||
void
|
||||
Servent::cleanupSocket( QTcpSocketExtra *sock )
|
||||
{
|
||||
if ( !sock )
|
||||
{
|
||||
tLog() << "SocketError, sock is null";
|
||||
return;
|
||||
}
|
||||
|
||||
if ( sock->_conn.isNull() )
|
||||
{
|
||||
tLog() << "SocketError, connection is null";
|
||||
}
|
||||
sock->deleteLater();
|
||||
}
|
||||
|
||||
void
|
||||
Servent::initiateConnection( const SipInfo& sipInfo, Connection* conn )
|
||||
{
|
||||
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 ( sipInfo.host() == ha.toString() )
|
||||
{
|
||||
tLog( LOGVERBOSE ) << Q_FUNC_INFO << "Tomahawk won't try to connect to" << sipInfo.host() << ":" << sipInfo.port() << ": same IP as ourselves.";
|
||||
return;
|
||||
}
|
||||
}
|
||||
if ( sipInfo.host() == m_externalHostname )
|
||||
{
|
||||
tLog( LOGVERBOSE ) << Q_FUNC_INFO << "Tomahawk won't try to connect to" << sipInfo.host() << ":" << sipInfo.port() << ": same IP as ourselves.";
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !sipInfo.key().isEmpty() && conn->firstMessage().isNull() )
|
||||
{
|
||||
QVariantMap m;
|
||||
m["conntype"] = "accept-offer";
|
||||
m["key"] = sipInfo.key();
|
||||
m["controlid"] = Database::instance()->impl()->dbid();
|
||||
conn->setFirstMessage( m );
|
||||
}
|
||||
|
||||
QTcpSocketExtra* sock = new QTcpSocketExtra();
|
||||
sock->setConnectTimeout( CONNECT_TIMEOUT );
|
||||
sock->_disowned = false;
|
||||
sock->_conn = conn;
|
||||
sock->_outbound = true;
|
||||
|
||||
connect( sock, SIGNAL( connected() ), SLOT( socketConnected() ) );
|
||||
connect( sock, SIGNAL( error( QAbstractSocket::SocketError ) ), this, SLOT( socketError( QAbstractSocket::SocketError ) ) );
|
||||
|
||||
if ( !conn->peerIpAddress().isNull() )
|
||||
sock->connectToHost( conn->peerIpAddress(), sipInfo.port(), QTcpSocket::ReadWrite );
|
||||
else
|
||||
sock->connectToHost( sipInfo.host(), sipInfo.port(), QTcpSocket::ReadWrite );
|
||||
sock->moveToThread( thread() );
|
||||
}
|
||||
|
||||
void
|
||||
Servent::socketError( QAbstractSocket::SocketError e )
|
||||
@ -711,132 +879,6 @@ Servent::socketError( QAbstractSocket::SocketError e )
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Servent::connectToPeer( const peerinfo_ptr& peerInfo )
|
||||
{
|
||||
Q_ASSERT( this->thread() == QThread::currentThread() );
|
||||
|
||||
SipInfo sipInfo = peerInfo->sipInfo();
|
||||
|
||||
peerInfoDebug( peerInfo ) << "connectToPeer: search for already established connections to the same nodeid:" << m_controlconnections.count() << "connections";
|
||||
if ( peerInfo->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() == sipInfo.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"] = sipInfo.key();
|
||||
m["port"] = externalPort();
|
||||
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 ( sipInfo.nodeId().length() )
|
||||
conn->setId( sipInfo.nodeId() );
|
||||
|
||||
conn->setProperty( "nodeid", sipInfo.nodeId() );
|
||||
|
||||
registerControlConnection( conn );
|
||||
connectToPeer( sipInfo.host(), sipInfo.port(), sipInfo.key(), conn );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Servent::connectToPeer( const QString& ha, int port, const QString& key, Connection* conn )
|
||||
{
|
||||
tDebug( LOGVERBOSE ) << "Servent::connectToPeer:" << ha << ":" << port
|
||||
<< thread() << QThread::currentThread();
|
||||
|
||||
Q_ASSERT( port > 0 );
|
||||
Q_ASSERT( conn );
|
||||
|
||||
if ( ( ha == m_externalAddress.toString() || ha == m_externalHostname ) &&
|
||||
( port == m_externalPort ) )
|
||||
{
|
||||
tDebug() << "ERROR: Tomahawk won't try to connect to" << ha << ":" << port << ": identified as ourselves.";
|
||||
return;
|
||||
}
|
||||
|
||||
if ( key.length() && conn->firstMessage().isNull() )
|
||||
{
|
||||
QVariantMap m;
|
||||
m["conntype"] = "accept-offer";
|
||||
m["key"] = key;
|
||||
m["port"] = externalPort();
|
||||
m["controlid"] = Database::instance()->impl()->dbid();
|
||||
conn->setFirstMessage( m );
|
||||
}
|
||||
|
||||
QTcpSocketExtra* sock = new QTcpSocketExtra();
|
||||
sock->_disowned = false;
|
||||
sock->_conn = conn;
|
||||
sock->_outbound = true;
|
||||
|
||||
connect( sock, SIGNAL( connected() ), SLOT( socketConnected() ) );
|
||||
connect( sock, SIGNAL( error( QAbstractSocket::SocketError ) ),
|
||||
SLOT( socketError( QAbstractSocket::SocketError ) ) );
|
||||
|
||||
if ( !conn->peerIpAddress().isNull() )
|
||||
sock->connectToHost( conn->peerIpAddress(), port, QTcpSocket::ReadWrite );
|
||||
else
|
||||
sock->connectToHost( ha, port, QTcpSocket::ReadWrite );
|
||||
sock->moveToThread( thread() );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Servent::reverseOfferRequest( ControlConnection* orig_conn, const QString& theirdbid, const QString& key, const QString& theirkey )
|
||||
{
|
||||
@ -854,13 +896,11 @@ Servent::reverseOfferRequest( ControlConnection* orig_conn, const QString& their
|
||||
QVariantMap m;
|
||||
m["conntype"] = "push-offer";
|
||||
m["key"] = theirkey;
|
||||
m["port"] = externalPort();
|
||||
m["controlid"] = Database::instance()->impl()->dbid();
|
||||
new_conn->setFirstMessage( m );
|
||||
createParallelConnection( orig_conn, new_conn, QString() );
|
||||
}
|
||||
|
||||
|
||||
// return the appropriate connection for a given offer key, or NULL if invalid
|
||||
Connection*
|
||||
Servent::claimOffer( ControlConnection* cc, const QString &nodeid, const QString &key, const QHostAddress peer )
|
||||
@ -922,7 +962,20 @@ Servent::claimOffer( ControlConnection* cc, const QString &nodeid, const QString
|
||||
}
|
||||
}
|
||||
|
||||
if ( m_offers.contains( key ) )
|
||||
if ( m_lazyoffers.contains( key ) )
|
||||
{
|
||||
ControlConnection* conn = new ControlConnection( this );
|
||||
conn->setName( m_lazyoffers.value( key ).first->contactId() );
|
||||
conn->addPeerInfo( m_lazyoffers.value( key ).first );
|
||||
conn->setId( m_lazyoffers.value( key ).second );
|
||||
|
||||
// Register as non-lazy offer
|
||||
m_lazyoffers.remove( key );
|
||||
registerOffer( key, conn );
|
||||
|
||||
return conn;
|
||||
}
|
||||
else if ( m_offers.contains( key ) )
|
||||
{
|
||||
QPointer<Connection> conn = m_offers.value( key );
|
||||
if ( conn.isNull() )
|
||||
|
@ -3,6 +3,7 @@
|
||||
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
* Copyright 2010-2012, Jeff Mitchell <jeff@tomahawk-player.org>
|
||||
* Copyright 2013, Teo Mrnjavac <teo@kde.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
|
||||
@ -21,8 +22,8 @@
|
||||
#ifndef SERVENT_H
|
||||
#define SERVENT_H
|
||||
|
||||
// time before new connection terminates if no auth received
|
||||
#define AUTH_TIMEOUT 180000
|
||||
// time before new connection terminate if it could not be established
|
||||
#define CONNECT_TIMEOUT 10000
|
||||
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QMap>
|
||||
@ -40,6 +41,7 @@
|
||||
|
||||
#include "Typedefs.h"
|
||||
#include "Msg.h"
|
||||
#include "network/QTcpSocketExtra.h"
|
||||
|
||||
#include <boost/function.hpp>
|
||||
|
||||
@ -58,56 +60,30 @@ class SipInfo;
|
||||
typedef boost::function< void( const Tomahawk::result_ptr&,
|
||||
boost::function< void( QSharedPointer< QIODevice >& ) > )> IODeviceFactoryFunc;
|
||||
|
||||
// this is used to hold a bit of state, so when a connected signal is emitted
|
||||
// from a socket, we can associate it with a Connection object etc.
|
||||
class DLLEXPORT QTcpSocketExtra : public QTcpSocket
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
QTcpSocketExtra() : QTcpSocket()
|
||||
{
|
||||
QTimer::singleShot( AUTH_TIMEOUT, this, SLOT( authTimeout() ) ) ;
|
||||
}
|
||||
|
||||
QPointer<Connection> _conn;
|
||||
bool _outbound;
|
||||
bool _disowned;
|
||||
msg_ptr _msg;
|
||||
|
||||
private slots:
|
||||
void authTimeout()
|
||||
{
|
||||
if( _disowned )
|
||||
return;
|
||||
|
||||
qDebug() << "Connection timed out before providing a valid offer-key";
|
||||
this->disconnectFromHost();
|
||||
}
|
||||
};
|
||||
|
||||
class DLLEXPORT Servent : public QTcpServer
|
||||
{
|
||||
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();
|
||||
|
||||
bool startListening( QHostAddress ha, bool upnp, int port );
|
||||
|
||||
int port() const { return m_port; }
|
||||
|
||||
// creates new token that allows a controlconnection to be set up
|
||||
QString createConnectionKey( const QString& name = "", const QString &nodeid = "", const QString &key = "", bool onceOnly = true );
|
||||
|
||||
void registerOffer( const QString& key, Connection* conn );
|
||||
void registerLazyOffer( const QString& key, const Tomahawk::peerinfo_ptr& peerInfo, const QString &nodeid , const int timeout );
|
||||
|
||||
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 );
|
||||
@ -117,13 +93,30 @@ public slots:
|
||||
void onSipInfoChanged();
|
||||
|
||||
public:
|
||||
void connectToPeer( const Tomahawk::peerinfo_ptr& ha );
|
||||
void connectToPeer( const QString& ha, int port, const QString& key, Connection* conn );
|
||||
void reverseOfferRequest( ControlConnection* orig_conn, const QString& theirdbid, const QString& key, const QString& theirkey );
|
||||
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_externalPort > 0 && !m_externalAddress.isNull()); }
|
||||
QString externalAddress() const { return !m_externalHostname.isNull() ? m_externalHostname : m_externalAddress.toString(); }
|
||||
int externalPort() const { return m_externalPort; }
|
||||
bool visibleExternally() const { return (!m_externalHostname.isNull()) || (m_externalAddresses.length() > 0); }
|
||||
|
||||
/**
|
||||
* The port this Peer listens directly (per default)
|
||||
*/
|
||||
int port() const { return m_port; }
|
||||
|
||||
/**
|
||||
* The IP addresses this Peer listens directly (per default)
|
||||
*/
|
||||
QList< QHostAddress > addresses() const { return m_externalAddresses; }
|
||||
|
||||
/**
|
||||
* An additional address this peer listens to, e.g. via UPnP.
|
||||
*/
|
||||
QString additionalAddress() const { return m_externalHostname; }
|
||||
|
||||
/**
|
||||
* An additional port this peer listens to, e.g. via UPnP (only in combination with additionalAddress.
|
||||
*/
|
||||
int additionalPort() const { return m_externalPort; }
|
||||
|
||||
static bool isIPWhitelisted( QHostAddress ip );
|
||||
|
||||
@ -138,8 +131,9 @@ public:
|
||||
void localFileIODeviceFactory( const Tomahawk::result_ptr& result, boost::function< void ( QSharedPointer< QIODevice >& ) > callback );
|
||||
void httpIODeviceFactory( const Tomahawk::result_ptr& result, boost::function< void ( QSharedPointer< QIODevice >& ) > callback );
|
||||
|
||||
bool isReady() const { return m_ready; };
|
||||
bool isReady() const { return m_ready; }
|
||||
|
||||
QList<SipInfo> getLocalSipInfos(const QString& nodeid, const QString &key);
|
||||
signals:
|
||||
void dbSyncTriggered();
|
||||
void streamStarted( StreamConnection* );
|
||||
@ -150,10 +144,8 @@ protected:
|
||||
void incomingConnection( int sd );
|
||||
|
||||
public slots:
|
||||
void setInternalAddress();
|
||||
void setExternalAddress( QHostAddress ha, unsigned int port );
|
||||
|
||||
void socketError( QAbstractSocket::SocketError );
|
||||
void createParallelConnection( Connection* orig_conn, Connection* new_conn, const QString& key );
|
||||
|
||||
void registerStreamConnection( StreamConnection* );
|
||||
@ -163,25 +155,44 @@ public slots:
|
||||
void triggerDBSync();
|
||||
|
||||
private slots:
|
||||
void deleteLazyOffer( const QString& key );
|
||||
void readyRead();
|
||||
void socketError( QAbstractSocket::SocketError e );
|
||||
|
||||
Connection* claimOffer( ControlConnection* cc, const QString &nodeid, const QString &key, const QHostAddress peer = QHostAddress::Any );
|
||||
|
||||
private:
|
||||
bool isValidExternalIP( const QHostAddress& addr ) const;
|
||||
void handoverSocket( Connection* conn, QTcpSocketExtra* sock );
|
||||
void cleanupSocket( QTcpSocketExtra* sock );
|
||||
void printCurrentTransfers();
|
||||
|
||||
QJson::Parser parser;
|
||||
QList< ControlConnection* > m_controlconnections; // canonical list of authed peers
|
||||
QMap< QString, QPointer< Connection > > m_offers;
|
||||
QMap< QString, QPair< Tomahawk::peerinfo_ptr, QString > > m_lazyoffers;
|
||||
QStringList m_connectedNodes;
|
||||
|
||||
int m_port, m_externalPort;
|
||||
QHostAddress m_externalAddress;
|
||||
/**
|
||||
* The external port used by all address except those obtained via UPnP or the static configuration option
|
||||
*/
|
||||
int m_port;
|
||||
|
||||
/**
|
||||
* Either the static set or the UPnP set external port
|
||||
*/
|
||||
int m_externalPort;
|
||||
|
||||
/**
|
||||
* All available external IPs
|
||||
*/
|
||||
QList<QHostAddress> m_externalAddresses;
|
||||
|
||||
/**
|
||||
* Either the static set or the UPnP set external host
|
||||
*/
|
||||
QString m_externalHostname;
|
||||
|
||||
bool m_ready;
|
||||
bool m_lanHack;
|
||||
bool m_noAuth;
|
||||
|
||||
// currently active file transfers:
|
||||
|
@ -1,6 +1,7 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2012, Dominik Schmidt <dev@dominik-schmidt.de>
|
||||
* 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
|
||||
@ -202,9 +203,9 @@ PeerInfo::sipPlugin() const
|
||||
|
||||
|
||||
void
|
||||
PeerInfo::sendLocalSipInfo( const SipInfo& sipInfo )
|
||||
PeerInfo::sendLocalSipInfos( const QList<SipInfo>& sipInfos )
|
||||
{
|
||||
sipPlugin()->sendSipInfo( weakRef().toStrongRef(), sipInfo );
|
||||
sipPlugin()->sendSipInfos( weakRef().toStrongRef(), sipInfos );
|
||||
}
|
||||
|
||||
|
||||
@ -228,6 +229,23 @@ PeerInfo::contactId() const
|
||||
return m_contactId;
|
||||
}
|
||||
|
||||
const QString
|
||||
PeerInfo::nodeId() const
|
||||
{
|
||||
Q_ASSERT( !m_sipInfos.isEmpty() );
|
||||
// All sip infos share the same nodeId
|
||||
return m_sipInfos.first().nodeId();
|
||||
}
|
||||
|
||||
const QString
|
||||
PeerInfo::key() const
|
||||
{
|
||||
Q_ASSERT( !m_sipInfos.isEmpty() );
|
||||
// All sip infos share the same key
|
||||
return m_sipInfos.first().key();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
PeerInfo::setStatus( PeerInfo::Status status )
|
||||
@ -259,22 +277,19 @@ PeerInfo::status() const
|
||||
|
||||
|
||||
void
|
||||
PeerInfo::setSipInfo( const SipInfo& sipInfo )
|
||||
PeerInfo::setSipInfos( const QList<SipInfo>& sipInfos )
|
||||
{
|
||||
if ( sipInfo == m_sipInfo )
|
||||
return;
|
||||
m_sipInfos = sipInfos;
|
||||
|
||||
m_sipInfo = sipInfo;
|
||||
|
||||
tLog() << "id:" << id() << "info changed" << sipInfo;
|
||||
tLog() << "id:" << id() << "info changed" << sipInfos;
|
||||
emit sipInfoChanged();
|
||||
}
|
||||
|
||||
|
||||
const SipInfo
|
||||
PeerInfo::sipInfo() const
|
||||
const QList<SipInfo>
|
||||
PeerInfo::sipInfos() const
|
||||
{
|
||||
return m_sipInfo;
|
||||
return m_sipInfos;
|
||||
}
|
||||
|
||||
|
||||
@ -389,7 +404,6 @@ PeerInfo::setData( const QVariant& data )
|
||||
m_data = data;
|
||||
}
|
||||
|
||||
|
||||
const
|
||||
QVariant PeerInfo::data() const
|
||||
{
|
||||
|
@ -74,7 +74,7 @@ public:
|
||||
const QString id() const;
|
||||
SipPlugin* sipPlugin() const;
|
||||
const QString debugName() const;
|
||||
void sendLocalSipInfo( const SipInfo& sipInfo );
|
||||
void sendLocalSipInfos( const QList<SipInfo>& sipInfos );
|
||||
|
||||
QWeakPointer< Tomahawk::PeerInfo > weakRef();
|
||||
void setWeakRef( QWeakPointer< Tomahawk::PeerInfo > weakRef );
|
||||
@ -96,8 +96,8 @@ public:
|
||||
void setStatus( Status status );
|
||||
Status status() const;
|
||||
|
||||
void setSipInfo( const SipInfo& sipInfo );
|
||||
const SipInfo sipInfo() const;
|
||||
void setSipInfos( const QList<SipInfo>& sipInfos );
|
||||
const QList<SipInfo> sipInfos() const;
|
||||
|
||||
void setFriendlyName( const QString& friendlyName );
|
||||
const QString friendlyName() const;
|
||||
@ -112,6 +112,16 @@ public:
|
||||
void setData( const QVariant& data );
|
||||
const QVariant data() const;
|
||||
|
||||
/**
|
||||
* Get the node id of this peer
|
||||
*/
|
||||
const QString nodeId() const;
|
||||
|
||||
/**
|
||||
* Get the authentication key for this host
|
||||
*/
|
||||
const QString key() const;
|
||||
|
||||
signals:
|
||||
void sipInfoChanged();
|
||||
|
||||
@ -131,7 +141,7 @@ private:
|
||||
QString m_id;
|
||||
QString m_contactId;
|
||||
Status m_status;
|
||||
SipInfo m_sipInfo;
|
||||
QList<SipInfo> m_sipInfos;
|
||||
QString m_friendlyName;
|
||||
QString m_versionString;
|
||||
QVariant m_data;
|
||||
|
@ -121,7 +121,6 @@ bool
|
||||
SipInfo::isVisible() const
|
||||
{
|
||||
Q_ASSERT( isValid() );
|
||||
|
||||
return d->visible.toBool();
|
||||
}
|
||||
|
||||
@ -137,7 +136,6 @@ const QString
|
||||
SipInfo::host() const
|
||||
{
|
||||
Q_ASSERT( isValid() );
|
||||
|
||||
return d->host;
|
||||
}
|
||||
|
||||
@ -153,7 +151,6 @@ int
|
||||
SipInfo::port() const
|
||||
{
|
||||
Q_ASSERT( isValid() );
|
||||
|
||||
return d->port;
|
||||
}
|
||||
|
||||
@ -169,7 +166,6 @@ const QString
|
||||
SipInfo::nodeId() const
|
||||
{
|
||||
Q_ASSERT( isValid() );
|
||||
|
||||
return d->nodeId;
|
||||
}
|
||||
|
||||
@ -185,7 +181,6 @@ const QString
|
||||
SipInfo::key() const
|
||||
{
|
||||
Q_ASSERT( isValid() );
|
||||
|
||||
return d->key;
|
||||
}
|
||||
|
||||
|
@ -70,7 +70,11 @@ public slots:
|
||||
virtual void configurationChanged() = 0;
|
||||
|
||||
virtual void addContact( const QString& peerId, const QString& msg = QString() ) = 0;
|
||||
virtual void sendSipInfo( const Tomahawk::peerinfo_ptr& receiver, const SipInfo& info ) = 0;
|
||||
|
||||
/**
|
||||
* Send a list of SipInfos to all contacts.
|
||||
*/
|
||||
virtual void sendSipInfos( const Tomahawk::peerinfo_ptr& receiver, const QList<SipInfo>& infos ) = 0;
|
||||
|
||||
signals:
|
||||
void peerStatusChanged( const Tomahawk::peerinfo_ptr& );
|
||||
|
@ -2,6 +2,7 @@
|
||||
*
|
||||
* Copyright 2011, Dominik Schmidt <dev@dominik-schmidt.de>
|
||||
* Copyright 2011, Jeff Mitchell <jeff@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
|
||||
@ -64,24 +65,26 @@ DiagnosticsDialog::updateLogView()
|
||||
log.append( QString( "TOMAHAWK DIAGNOSTICS LOG -%1 \n\n" ).arg( QDateTime::currentDateTime().toString() ) );
|
||||
log.append( "TOMAHAWK-VERSION: " TOMAHAWK_VERSION "\n" );
|
||||
log.append( "PLATFORM: " TOMAHAWK_SYSTEM "\n\n");
|
||||
log.append( "NETWORK:\n General:\n" );
|
||||
log.append( "NETWORK:\n Listening to:\n" );
|
||||
|
||||
if ( Servent::instance()->visibleExternally() )
|
||||
{
|
||||
log.append(
|
||||
QString(
|
||||
" visible: true\n"
|
||||
" host: %1\n"
|
||||
" port: %2\n"
|
||||
"\n"
|
||||
).arg( Servent::instance()->externalAddress() )
|
||||
.arg( Servent::instance()->externalPort() )
|
||||
foreach ( QHostAddress ha, Servent::instance()->addresses() )
|
||||
{
|
||||
if ( ha.protocol() == QAbstractSocket::IPv6Protocol )
|
||||
log.append( QString( " [%1]:%2\n" ).arg( ha.toString() ).arg( Servent::instance()->port() ) );
|
||||
else
|
||||
log.append( QString( " %1:%2\n" ).arg( ha.toString() ).arg( Servent::instance()->port() ) );
|
||||
}
|
||||
if ( !Servent::instance()->additionalAddress().isNull() )
|
||||
{
|
||||
log.append( QString( " [%1]:%2\n" ).arg( Servent::instance()->additionalAddress() ).arg( Servent::instance()->additionalPort() ) );
|
||||
}
|
||||
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
log.append( " visible: false\n" );
|
||||
log.append( " not listening to any interface, outgoing connections only\n" );
|
||||
}
|
||||
|
||||
log.append( "\n\nINFOPLUGINS:\n" );
|
||||
@ -162,54 +165,17 @@ DiagnosticsDialog::accountLog( Tomahawk::Accounts::Account* account )
|
||||
|
||||
foreach( const Tomahawk::peerinfo_ptr& peerInfo, account->sipPlugin()->peersOnline() )
|
||||
{
|
||||
QString peerId = peerInfo->id();
|
||||
QString versionString = peerInfo->versionString();
|
||||
SipInfo sipInfo = peerInfo->sipInfo();
|
||||
if ( !sipInfo.isValid() )
|
||||
accountInfo.append( QString( " %1: " ).arg( peerInfo->id() ) );
|
||||
foreach ( SipInfo info, peerInfo->sipInfos() )
|
||||
{
|
||||
accountInfo.append(
|
||||
QString(" %1: %2 %3" /*"(%4)"*/)
|
||||
.arg( peerInfo->id() )
|
||||
.arg( "sipinfo invalid" )
|
||||
.arg( versionString )
|
||||
// .arg( connected ? "connected" : "not connected")
|
||||
);
|
||||
}
|
||||
else if ( sipInfo.isVisible() )
|
||||
{
|
||||
accountInfo.append(
|
||||
QString(" %1: %2:%3 %4" /*" (%5)"*/)
|
||||
.arg( peerId )
|
||||
.arg( sipInfo.host() )
|
||||
.arg( sipInfo.port() )
|
||||
.arg( versionString )
|
||||
// .arg( connected ? "connected" : "not connected")
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
accountInfo.append(
|
||||
QString(" %1: visible: false %2" /*" (%3)"*/)
|
||||
.arg( peerId )
|
||||
.arg( versionString )
|
||||
// .arg( connected ? "connected" : "not connected")
|
||||
);
|
||||
}
|
||||
|
||||
if( sipInfo.isValid() )
|
||||
{
|
||||
if( !Servent::instance()->visibleExternally() ||
|
||||
Servent::instance()->externalAddress() < sipInfo.host() ||
|
||||
( Servent::instance()->externalAddress() == sipInfo.host() && Servent::instance()->externalPort() < sipInfo.port() ) )
|
||||
{
|
||||
accountInfo.append(" (outbound)");
|
||||
}
|
||||
if ( info.isValid() )
|
||||
accountInfo.append( QString( "[%1]:%2; " ).arg( info.host() ).arg( info.port() ) );
|
||||
else
|
||||
{
|
||||
accountInfo.append(" (inbound)");
|
||||
}
|
||||
accountInfo.append( "SipInfo invalid; " );
|
||||
}
|
||||
accountInfo.append("\n");
|
||||
if ( ( ( peerInfo->sipInfos().length() == 1 ) && ( !peerInfo->sipInfos().first().isVisible() ) ) || ( peerInfo->sipInfos().isEmpty() ) )
|
||||
accountInfo.append( "(outbound connections only) ");
|
||||
accountInfo.append( QString( " (%1)\n" ).arg( peerInfo->versionString() ) );
|
||||
}
|
||||
accountInfo.append( "\n" );
|
||||
|
||||
|
@ -32,7 +32,7 @@
|
||||
<item>
|
||||
<widget class="QRadioButton" name="lanOnlyRadioButton">
|
||||
<property name="text">
|
||||
<string>None (outgoing connections only)</string>
|
||||
<string>Active (your host needs to be directly reachable)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
@ -610,7 +610,7 @@ TomahawkApp::initServent()
|
||||
|
||||
bool upnp = !arguments().contains( "--noupnp" );
|
||||
int port = TomahawkSettings::instance()->externalPort();
|
||||
if ( !Servent::instance()->startListening( QHostAddress( QHostAddress::Any ), upnp, port ) )
|
||||
if ( !Servent::instance()->startListening( QHostAddress( QHostAddress::AnyIPv6 ), upnp, port ) )
|
||||
{
|
||||
tLog() << "Failed to start listening with servent";
|
||||
exit( 1 );
|
||||
|
Loading…
x
Reference in New Issue
Block a user