From 1d3dd67bf313469faf35db17e86e97c85ce31a69 Mon Sep 17 00:00:00 2001
From: "Uwe L. Korn" <uwelk@xhochy.com>
Date: Sun, 9 Jun 2013 11:47:00 +0200
Subject: [PATCH] Reconnect if ACL decision took too long

---
 src/libtomahawk/network/Connection.cpp        | 12 +++--
 src/libtomahawk/network/Connection.h          |  3 +-
 src/libtomahawk/network/ControlConnection.cpp | 12 +++++
 src/libtomahawk/network/ControlConnection.h   |  1 +
 src/libtomahawk/network/Servent.cpp           | 45 +++++++++++++++++++
 src/libtomahawk/network/Servent.h             |  4 ++
 src/libtomahawk/network/Servent_p.h           |  2 +
 7 files changed, 74 insertions(+), 5 deletions(-)

diff --git a/src/libtomahawk/network/Connection.cpp b/src/libtomahawk/network/Connection.cpp
index 47986cb93..21cf176fb 100644
--- a/src/libtomahawk/network/Connection.cpp
+++ b/src/libtomahawk/network/Connection.cpp
@@ -207,23 +207,27 @@ Connection::checkACL()
     }
 
     QString nodeid = property( "nodeid" ).toString();
-    QString bareName = name().contains( '/' ) ? name().left( name().indexOf( "/" ) ) : name();
     tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "Checking ACL for" << name();
     connect( ACLRegistry::instance(), SIGNAL( aclResult( QString, QString, ACLRegistry::ACL ) ), this, SLOT( checkACLResult( QString, QString, ACLRegistry::ACL ) ), Qt::QueuedConnection );
-    QMetaObject::invokeMethod( ACLRegistry::instance(), "isAuthorizedUser", Qt::QueuedConnection, Q_ARG( QString, nodeid ), Q_ARG( QString, bareName ), Q_ARG( ACLRegistry::ACL, ACLRegistry::NotFound ) );
+    QMetaObject::invokeMethod( ACLRegistry::instance(), "isAuthorizedUser", Qt::QueuedConnection, Q_ARG( QString, nodeid ), Q_ARG( QString, bareName() ), Q_ARG( ACLRegistry::ACL, ACLRegistry::NotFound ) );
 }
 
 
+QString
+Connection::bareName() const
+{
+    return name().contains( '/' ) ? name().left( name().indexOf( "/" ) ) : name();
+}
+
 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() )
     {
         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 )
+    if ( username != bareName() )
     {
         tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "username not our barename";
         return;
diff --git a/src/libtomahawk/network/Connection.h b/src/libtomahawk/network/Connection.h
index 769e05a58..075ddefed 100644
--- a/src/libtomahawk/network/Connection.h
+++ b/src/libtomahawk/network/Connection.h
@@ -92,6 +92,7 @@ public:
 
     const QHostAddress peerIpAddress() const { return m_peerIpAddress; }
 
+    QString bareName() const;
 signals:
     void ready();
     void failed();
@@ -105,6 +106,7 @@ protected:
 
 protected slots:
     virtual void handleMsg( msg_ptr msg ) = 0;
+    virtual void authCheckTimeout();
 
 public slots:
     virtual void start( QTcpSocket* sock );
@@ -122,7 +124,6 @@ private slots:
     void doSetup();
     void checkACL();
     void checkACLResult( const QString &nodeid, const QString &username, ACLRegistry::ACL peerStatus );
-    void authCheckTimeout();
     void bytesWritten( qint64 );
     void calcStats();
 
diff --git a/src/libtomahawk/network/ControlConnection.cpp b/src/libtomahawk/network/ControlConnection.cpp
index 120c4b715..2a870aad7 100644
--- a/src/libtomahawk/network/ControlConnection.cpp
+++ b/src/libtomahawk/network/ControlConnection.cpp
@@ -273,6 +273,18 @@ ControlConnection::handleMsg( msg_ptr msg )
     tDebug() << id() << "Invalid msg:" << QString::fromLatin1( msg->payload() );
 }
 
+void
+ControlConnection::authCheckTimeout()
+{
+    if ( m_ready )
+        return;
+
+    Servent::instance()->queueForAclResult( bareName(), m_peerInfos );
+
+    tDebug( LOGVERBOSE ) << "Closing connection, not authed in time.";
+    shutdown();
+}
+
 
 void
 ControlConnection::onPingTimer()
diff --git a/src/libtomahawk/network/ControlConnection.h b/src/libtomahawk/network/ControlConnection.h
index a8bde2d15..f4bfb3c4f 100644
--- a/src/libtomahawk/network/ControlConnection.h
+++ b/src/libtomahawk/network/ControlConnection.h
@@ -58,6 +58,7 @@ protected:
 
 protected slots:
     virtual void handleMsg( msg_ptr msg );
+    virtual void authCheckTimeout();
 
 private slots:
     void dbSyncConnFinished( QObject* c );
diff --git a/src/libtomahawk/network/Servent.cpp b/src/libtomahawk/network/Servent.cpp
index d4b106ce6..bdb77ee92 100644
--- a/src/libtomahawk/network/Servent.cpp
+++ b/src/libtomahawk/network/Servent.cpp
@@ -210,6 +210,8 @@ Servent::startListening( QHostAddress ha, bool upnp, int port )
             break;
     }
 
+    connect( ACLRegistry::instance(), SIGNAL( aclResult( QString, QString, ACLRegistry::ACL ) ), this, SLOT( checkACLResult( QString, QString, ACLRegistry::ACL ) ), Qt::QueuedConnection );
+
     return true;
 }
 
@@ -421,6 +423,22 @@ Servent::getLocalSipInfos( const QString& nodeid, const QString& key )
     return sipInfos;
 }
 
+void
+Servent::queueForAclResult( const QString& username, const QSet<peerinfo_ptr>& peerInfos )
+{
+    if ( peerInfos.isEmpty() )
+    {
+        // If all peerInfos disappeared, do not queue.
+        return;
+    }
+
+    if ( !d_func()->queuedForACLResult.contains( username ) )
+    {
+        d_func()->queuedForACLResult[username] = QMap<QString, QSet<Tomahawk::peerinfo_ptr> >();
+    }
+    d_func()->queuedForACLResult[username][ (*peerInfos.begin())->nodeId() ] = QSet<Tomahawk::peerinfo_ptr>( peerInfos );
+}
+
 SipInfo
 Servent::getSipInfoForOldVersions( const QList<SipInfo>& sipInfos )
 {
@@ -880,6 +898,33 @@ Servent::socketError( QAbstractSocket::SocketError e )
     }
 }
 
+void
+Servent::checkACLResult( const QString& nodeid, const QString& username, ACLRegistry::ACL peerStatus )
+{
+
+    if ( !d_func()->queuedForACLResult.contains( username ) )
+    {
+        return;
+    }
+    if ( !d_func()->queuedForACLResult.value( username ).contains( nodeid ) )
+    {
+        return;
+    }
+
+    tDebug( LOGVERBOSE ) << Q_FUNC_INFO << QString( "ACL status for user %1 is" ).arg( username ) << peerStatus;
+    QSet<Tomahawk::peerinfo_ptr> peerInfos = d_func()->queuedForACLResult.value( username ).value( nodeid );
+    if ( peerStatus == ACLRegistry::Stream )
+    {
+        foreach ( Tomahawk::peerinfo_ptr peerInfo, peerInfos )
+        {
+            registerPeer( peerInfo );
+        }
+
+    }
+    // We have a result, so remove from queue
+    d_func()->queuedForACLResult[username].remove( nodeid );
+}
+
 void
 Servent::reverseOfferRequest( ControlConnection* orig_conn, const QString& theirdbid, const QString& key, const QString& theirkey )
 {
diff --git a/src/libtomahawk/network/Servent.h b/src/libtomahawk/network/Servent.h
index 5a455cc48..63f259ce3 100644
--- a/src/libtomahawk/network/Servent.h
+++ b/src/libtomahawk/network/Servent.h
@@ -36,6 +36,7 @@
 
 #include "Typedefs.h"
 #include "Msg.h"
+#include "AclRegistry.h"
 
 #include "DllMacro.h"
 
@@ -134,6 +135,8 @@ public:
     bool isReady() const;
 
     QList<SipInfo> getLocalSipInfos(const QString& nodeid, const QString &key);
+
+    void queueForAclResult( const QString& username, const QSet<Tomahawk::peerinfo_ptr>& peerInfos );
 signals:
     void dbSyncTriggered();
     void streamStarted( StreamConnection* );
@@ -158,6 +161,7 @@ private slots:
     void deleteLazyOffer( const QString& key );
     void readyRead();
     void socketError( QAbstractSocket::SocketError e );
+    void checkACLResult( const QString &nodeid, const QString &username, ACLRegistry::ACL peerStatus );
 
     Connection* claimOffer( ControlConnection* cc, const QString &nodeid, const QString &key, const QHostAddress peer = QHostAddress::Any );
 
diff --git a/src/libtomahawk/network/Servent_p.h b/src/libtomahawk/network/Servent_p.h
index f0f06bd7f..60ecc1231 100644
--- a/src/libtomahawk/network/Servent_p.h
+++ b/src/libtomahawk/network/Servent_p.h
@@ -83,6 +83,8 @@ private:
     // currently active file transfers:
     QList< StreamConnection* > scsessions;
     QMutex ftsession_mut;
+    // username -> nodeid -> PeerInfos
+    QMap<QString, QMap<QString, QSet<Tomahawk::peerinfo_ptr> > > queuedForACLResult;
 
     QPointer< PortFwdThread > portfwd;
 };