/src/libtomahawk/network/Servent.cpp

http://github.com/tomahawk-player/tomahawk · C++ · 1455 lines · 1113 code · 239 blank · 103 comment · 186 complexity · e56e39e8adde5497fbb9877e950fdd36 MD5 · raw file

  1. /* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
  2. *
  3. * Copyright 2010-2015, Christian Muehlhaeuser <muesli@tomahawk-player.org>
  4. * Copyright 2010-2012, Jeff Mitchell <jeff@tomahawk-player.org>
  5. * Copyright 2013, Teo Mrnjavac <teo@kde.org>
  6. * Copyright 2013-2014, Uwe L. Korn <uwelk@xhochy.com>
  7. *
  8. * Tomahawk is free software: you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation, either version 3 of the License, or
  11. * (at your option) any later version.
  12. *
  13. * Tomahawk is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
  20. */
  21. #include "Servent_p.h"
  22. #include "accounts/AccountManager.h"
  23. #include "database/Database.h"
  24. #include "database/DatabaseImpl.h"
  25. #include "network/acl/AclRegistry.h"
  26. #include "network/Msg.h"
  27. #include "network/ConnectionManager.h"
  28. #include "network/DbSyncConnection.h"
  29. #include "sip/SipInfo.h"
  30. #include "sip/PeerInfo.h"
  31. #include "sip/SipPlugin.h"
  32. #include "utils/Closure.h"
  33. #include "utils/Json.h"
  34. #include "utils/TomahawkUtils.h"
  35. #include "utils/Logger.h"
  36. #include "utils/NetworkAccessManager.h"
  37. #include "utils/NetworkReply.h"
  38. #include "Connection.h"
  39. #include "ControlConnection.h"
  40. #include "PortFwdThread.h"
  41. #include "QTcpSocketExtra.h"
  42. #include "Source.h"
  43. #include "SourceList.h"
  44. #include "StreamConnection.h"
  45. #include "UrlHandler.h"
  46. #include <QCoreApplication>
  47. #include <QMutexLocker>
  48. #include <QNetworkInterface>
  49. #include <QFile>
  50. #include <QThread>
  51. #include <QNetworkProxy>
  52. #include <QNetworkRequest>
  53. #include <QNetworkReply>
  54. typedef QPair< QList< SipInfo >, Connection* > sipConnectionPair;
  55. Q_DECLARE_METATYPE( sipConnectionPair )
  56. Q_DECLARE_METATYPE( QList< SipInfo > )
  57. Q_DECLARE_METATYPE( Connection* )
  58. Q_DECLARE_METATYPE( QTcpSocketExtra* )
  59. Q_DECLARE_METATYPE( Tomahawk::peerinfo_ptr )
  60. using namespace Tomahawk;
  61. Servent* Servent::s_instance = 0;
  62. Servent*
  63. Servent::instance()
  64. {
  65. return s_instance;
  66. }
  67. Servent::Servent( QObject* parent )
  68. : QTcpServer( parent ),
  69. d_ptr( new ServentPrivate( this ) )
  70. {
  71. s_instance = this;
  72. d_func()->noAuth = qApp->arguments().contains( "--noauth" );
  73. setProxy( QNetworkProxy::NoProxy );
  74. IODeviceFactoryFunc fac = std::bind( &Servent::remoteIODeviceFactory, this,
  75. std::placeholders::_1,
  76. std::placeholders::_2,
  77. std::placeholders::_3 );
  78. Tomahawk::UrlHandler::registerIODeviceFactory( "servent", fac );
  79. }
  80. Servent::~Servent()
  81. {
  82. tDebug() << Q_FUNC_INFO;
  83. foreach ( ControlConnection* cc, d_func()->controlconnections )
  84. delete cc;
  85. if ( d_func()->portfwd )
  86. {
  87. d_func()->portfwd.data()->quit();
  88. d_func()->portfwd.data()->wait( 60000 );
  89. delete d_func()->portfwd.data();
  90. }
  91. delete d_ptr;
  92. }
  93. bool
  94. Servent::startListening( QHostAddress ha, bool upnp, int port, Tomahawk::Network::ExternalAddress::Mode mode, int defaultPort, bool autoDetectExternalIp, const QString& externalHost, int externalPort )
  95. {
  96. Q_D( Servent );
  97. d->externalAddresses = QList<QHostAddress>();
  98. d->port = port;
  99. // Listen on both the selected port and, if not the same, the default port -- the latter sometimes necessary for zeroconf
  100. // TODO: only listen on both when zeroconf sip is enabled
  101. // TODO: use a real zeroconf system instead of a simple UDP broadcast?
  102. if ( !listen( ha, d->port ) )
  103. {
  104. if ( d->port != defaultPort )
  105. {
  106. if ( !listen( ha, defaultPort ) )
  107. {
  108. tLog() << Q_FUNC_INFO << "Failed to listen on both port" << d->port << "and port" << defaultPort;
  109. tLog() << Q_FUNC_INFO << "Error string is:" << errorString();
  110. return false;
  111. }
  112. else
  113. d->port = defaultPort;
  114. }
  115. }
  116. d->externalListenAll = false;
  117. if ( ha == QHostAddress::Any || ha == QHostAddress::AnyIPv6 )
  118. {
  119. // We are listening on all available addresses, so we should send a SipInfo for all of them.
  120. d->externalAddresses = QNetworkInterface::allAddresses();
  121. cleanAddresses( d->externalAddresses );
  122. tLog( LOGVERBOSE ) << Q_FUNC_INFO << "Listening to" << d->externalAddresses;
  123. d->externalListenAll = true;
  124. }
  125. else if ( ( ha.toString() != "127.0.0.1" ) && ( ha.toString() != "::1" ) && ( ha.toString() != "::7F00:1" ) )
  126. {
  127. // We listen only to one specific Address, only announce this.
  128. d->externalAddresses.append( ha );
  129. }
  130. // If we only accept connections via localhost, we'll announce nothing.
  131. tLog( LOGVERBOSE ) << Q_FUNC_INFO << "Servent listening on port" << d->port
  132. << "using address" << ha.toString()
  133. << "- servent thread:" << thread()
  134. << "- address mode:" << (int)( mode );
  135. switch ( mode )
  136. {
  137. case Tomahawk::Network::ExternalAddress::Static:
  138. d->externalPort = externalPort;
  139. if ( autoDetectExternalIp )
  140. {
  141. QNetworkReply* reply = Tomahawk::Utils::nam()->get( QNetworkRequest( QUrl( "http://toma.hk/?stat=1" ) ) );
  142. connect( reply, SIGNAL( finished() ), SLOT( ipDetected() ) );
  143. // Not emitting ready here as we are not done.
  144. }
  145. else
  146. {
  147. d->externalHostname = externalHost;
  148. d->ready = true;
  149. // All setup is made, were done.
  150. emit ready();
  151. }
  152. break;
  153. case Tomahawk::Network::ExternalAddress::Lan:
  154. // Nothing has to be done here.
  155. d->ready = true;
  156. emit ready();
  157. break;
  158. case Tomahawk::Network::ExternalAddress::Upnp:
  159. if ( upnp )
  160. {
  161. // upnp could be turned off on the cli with --noupnp
  162. tLog( LOGVERBOSE ) << Q_FUNC_INFO << "External address mode set to upnp...";
  163. d->portfwd = QPointer< PortFwdThread >( new PortFwdThread( d->port ) );
  164. Q_ASSERT( d->portfwd );
  165. connect( d->portfwd.data(), SIGNAL( externalAddressDetected( QHostAddress, unsigned int ) ),
  166. SLOT( setExternalAddress( QHostAddress, unsigned int ) ) );
  167. d->portfwd.data()->start();
  168. }
  169. else
  170. {
  171. d->ready = true;
  172. emit ready();
  173. }
  174. break;
  175. }
  176. connect( ACLRegistry::instance(), SIGNAL( aclResult( QString, QString, Tomahawk::ACLStatus::Type ) ),
  177. this, SLOT( checkACLResult( QString, QString, Tomahawk::ACLStatus::Type ) ),
  178. Qt::QueuedConnection );
  179. return true;
  180. }
  181. void
  182. Servent::setExternalAddress( QHostAddress ha, unsigned int port )
  183. {
  184. if ( isValidExternalIP( ha ) )
  185. {
  186. d_func()->externalHostname = ha.toString();
  187. d_func()->externalPort = port;
  188. }
  189. if ( d_func()->externalPort == 0 || !isValidExternalIP( ha ) )
  190. tLog() << Q_FUNC_INFO << "UPnP failed, no further external address could be acquired!";
  191. else
  192. tLog( LOGVERBOSE ) << Q_FUNC_INFO << "UPnP setup successful";
  193. d_func()->ready = true;
  194. emit ready();
  195. }
  196. QString
  197. Servent::createConnectionKey( const QString& name, const QString &nodeid, const QString &key, bool onceOnly )
  198. {
  199. Q_ASSERT( this->thread() == QThread::currentThread() );
  200. QString _key = ( key.isEmpty() ? uuid() : key );
  201. ControlConnection* cc = new ControlConnection( this );
  202. cc->setName( name.isEmpty() ? QString( "KEY(%1)" ).arg( key ) : name );
  203. if ( !nodeid.isEmpty() )
  204. cc->setId( nodeid );
  205. cc->setOnceOnly( onceOnly );
  206. tDebug( LOGVERBOSE ) << "Creating connection key with name of" << cc->name() << "and id of" << cc->id() << "and key of" << _key << "; key is once only? :" << (onceOnly ? "true" : "false");
  207. registerOffer( _key, cc );
  208. return _key;
  209. }
  210. bool
  211. Servent::isValidExternalIP( const QHostAddress& addr )
  212. {
  213. QString ip = addr.toString();
  214. if (addr.protocol() == QAbstractSocket::IPv4Protocol)
  215. {
  216. // private network
  217. if ( addr.isInSubnet(QHostAddress::parseSubnet( "10.0.0.0/8" ) ) )
  218. return false;
  219. // localhost
  220. if ( addr.isInSubnet(QHostAddress::parseSubnet( "127.0.0.0/8" ) ) )
  221. return false;
  222. // private network
  223. if ( addr.isInSubnet(QHostAddress::parseSubnet( "169.254.0.0/16" ) ) )
  224. return false;
  225. // private network
  226. if ( addr.isInSubnet(QHostAddress::parseSubnet( "172.16.0.0/12" ) ) )
  227. return false;
  228. // private network
  229. if ( addr.isInSubnet(QHostAddress::parseSubnet( "192.168.0.0/16" ) ) )
  230. return false;
  231. // multicast
  232. if ( addr.isInSubnet(QHostAddress::parseSubnet( "224.0.0.0/4" ) ) )
  233. return false;
  234. }
  235. else if (addr.protocol() == QAbstractSocket::IPv6Protocol)
  236. {
  237. // "unspecified address"
  238. if ( addr.isInSubnet(QHostAddress::parseSubnet( "::/128" ) ) )
  239. return false;
  240. // link-local
  241. if ( addr.isInSubnet(QHostAddress::parseSubnet( "fe80::/10" ) ) )
  242. return false;
  243. // unique local addresses
  244. if ( addr.isInSubnet(QHostAddress::parseSubnet( "fc00::/7" ) ) )
  245. return false;
  246. // benchmarking only
  247. if ( addr.isInSubnet(QHostAddress::parseSubnet( "2001:2::/48" ) ) )
  248. return false;
  249. // non-routed IPv6 addresses used for Cryptographic Hash Identifiers
  250. if ( addr.isInSubnet(QHostAddress::parseSubnet( "2001:10::/28" ) ) )
  251. return false;
  252. // documentation prefix
  253. if ( addr.isInSubnet(QHostAddress::parseSubnet( "2001:db8::/32" ) ) )
  254. return false;
  255. // multicast
  256. if ( addr.isInSubnet(QHostAddress::parseSubnet( "ff00::0/8" ) ) )
  257. return false;
  258. }
  259. else
  260. {
  261. return false;
  262. }
  263. return !addr.isNull();
  264. }
  265. void
  266. Servent::registerOffer( const QString& key, Connection* conn )
  267. {
  268. d_func()->offers[key] = QPointer<Connection>(conn);
  269. }
  270. void
  271. Servent::registerLazyOffer(const QString &key, const peerinfo_ptr &peerInfo, const QString &nodeid, const int timeout )
  272. {
  273. d_func()->lazyoffers[key] = QPair< peerinfo_ptr, QString >( peerInfo, nodeid );
  274. QTimer* timer = new QTimer( this );
  275. timer->setInterval( timeout );
  276. timer->setSingleShot( true );
  277. NewClosure( timer, SIGNAL( timeout() ), this, SLOT( deleteLazyOffer( const QString& ) ), key );
  278. timer->start();
  279. }
  280. void
  281. Servent::deleteLazyOffer( const QString& key )
  282. {
  283. d_func()->lazyoffers.remove( key );
  284. // Cleanup.
  285. QTimer* timer = (QTimer*)sender();
  286. if ( timer )
  287. {
  288. timer->deleteLater();
  289. }
  290. }
  291. void
  292. Servent::registerControlConnection( ControlConnection* conn )
  293. {
  294. Q_D( Servent );
  295. Q_ASSERT( conn );
  296. QMutexLocker locker( &d->controlconnectionsMutex );
  297. tLog( LOGVERBOSE ) << Q_FUNC_INFO << conn->name();
  298. d->controlconnections << conn;
  299. d->connectedNodes << conn->id();
  300. }
  301. void
  302. Servent::unregisterControlConnection( ControlConnection* conn )
  303. {
  304. Q_D( Servent );
  305. Q_ASSERT( conn );
  306. QMutexLocker locker( &d->controlconnectionsMutex );
  307. tLog( LOGVERBOSE ) << Q_FUNC_INFO << conn->name();
  308. d->connectedNodes.removeAll( conn->id() );
  309. d->controlconnections.removeAll( conn );
  310. }
  311. ControlConnection*
  312. Servent::lookupControlConnection( const SipInfo& sipInfo )
  313. {
  314. Q_D( Servent );
  315. QMutexLocker locker( &d->controlconnectionsMutex );
  316. foreach ( ControlConnection* c, d_func()->controlconnections )
  317. {
  318. tLog() << sipInfo.port() << c->peerPort() << sipInfo.host() << c->peerIpAddress().toString();
  319. if ( sipInfo.port() == c->peerPort() && sipInfo.host() == c->peerIpAddress().toString() )
  320. return c;
  321. }
  322. return NULL;
  323. }
  324. ControlConnection*
  325. Servent::lookupControlConnection( const QString& nodeid )
  326. {
  327. Q_D( Servent );
  328. QMutexLocker locker( &d->controlconnectionsMutex );
  329. foreach ( ControlConnection* c, d_func()->controlconnections )
  330. {
  331. if ( c->id() == nodeid )
  332. return c;
  333. }
  334. return NULL;
  335. }
  336. QList<SipInfo>
  337. Servent::getLocalSipInfos( const QString& nodeid, const QString& key )
  338. {
  339. Q_D( Servent );
  340. QList<SipInfo> sipInfos = QList<SipInfo>();
  341. QList<QHostAddress> addresses = d->externalAddresses;
  342. if ( d->externalListenAll )
  343. {
  344. addresses = QNetworkInterface::allAddresses();
  345. cleanAddresses( addresses );
  346. }
  347. foreach ( QHostAddress ha, addresses )
  348. {
  349. SipInfo info = SipInfo();
  350. info.setHost( ha.toString() );
  351. info.setPort( d_func()->port );
  352. info.setKey( key );
  353. info.setVisible( true );
  354. info.setNodeId( nodeid );
  355. sipInfos.append( info );
  356. }
  357. if ( !d_func()->externalHostname.isEmpty() )
  358. {
  359. SipInfo info = SipInfo();
  360. info.setHost( d_func()->externalHostname );
  361. info.setPort( d_func()->externalPort );
  362. info.setKey( key );
  363. info.setVisible( true );
  364. info.setNodeId( nodeid );
  365. sipInfos.append( info );
  366. }
  367. if ( sipInfos.isEmpty() )
  368. {
  369. // We are not visible via any IP, send a dummy SipInfo
  370. SipInfo info = SipInfo();
  371. info.setVisible( false );
  372. info.setKey( key );
  373. info.setNodeId( nodeid );
  374. tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "Only accepting connections, no usable IP to listen to found.";
  375. }
  376. return sipInfos;
  377. }
  378. void
  379. Servent::queueForAclResult( const QString& username, const QSet<peerinfo_ptr>& peerInfos )
  380. {
  381. if ( peerInfos.isEmpty() || (*peerInfos.begin())->sipInfos().isEmpty() )
  382. {
  383. // If all peerInfos disappeared, do not queue.
  384. // If the peerInfo has not got a sipInfo anymore, do not queue either.
  385. return;
  386. }
  387. if ( !d_func()->queuedForACLResult.contains( username ) )
  388. {
  389. d_func()->queuedForACLResult[username] = QMap<QString, QSet<Tomahawk::peerinfo_ptr> >();
  390. }
  391. d_func()->queuedForACLResult[username][ (*peerInfos.begin())->nodeId() ] = QSet<Tomahawk::peerinfo_ptr>( peerInfos );
  392. }
  393. SipInfo
  394. Servent::getSipInfoForOldVersions( const QList<SipInfo>& sipInfos )
  395. {
  396. SipInfo info = SipInfo();
  397. info.setVisible( false );
  398. foreach ( SipInfo _info, sipInfos )
  399. {
  400. QHostAddress ha = QHostAddress( _info.host() );
  401. if ( ( Servent::isValidExternalIP( ha ) && ha.protocol() == QAbstractSocket::IPv4Protocol ) || ( ha.protocol() == QAbstractSocket::UnknownNetworkLayerProtocol ) || ( ha.isNull() && !_info.host().isEmpty() ))
  402. {
  403. info = _info;
  404. break;
  405. }
  406. }
  407. return info;
  408. }
  409. void
  410. Servent::registerPeer( const Tomahawk::peerinfo_ptr& peerInfo )
  411. {
  412. if ( peerInfo->hasControlConnection() )
  413. {
  414. peerInfoDebug( peerInfo ) << "already had control connection, doing nothing: " << peerInfo->controlConnection()->name();
  415. tLog() << "existing control connection has following peers:";
  416. foreach ( const peerinfo_ptr& otherPeerInfo, peerInfo->controlConnection()->peerInfos() )
  417. {
  418. peerInfoDebug( otherPeerInfo );
  419. }
  420. tLog() << "end peers";
  421. return;
  422. }
  423. if ( peerInfo->type() == Tomahawk::PeerInfo::Local )
  424. {
  425. peerInfoDebug(peerInfo) << "we need to establish the connection now... thinking";
  426. if ( !connectedToSession( peerInfo->nodeId() ) )
  427. {
  428. handleSipInfo( peerInfo );
  429. }
  430. else
  431. {
  432. // FIXME: do we need to port this?!
  433. // qDebug() << "Already connected to" << host; // so peerInfo was 0 before
  434. // qDebug() << "They connected to us and we don't have a PeerInfo object, created one...";
  435. // m_peersOnline.append( peerInfo );
  436. // // attach to control connection
  437. // ControlConnection* conn = Servent::instance()->lookupControlConnection( sipInfo );
  438. // // we're connected to this nodeid, so we should find a control connection for this sipinfo, no?
  439. // Q_ASSERT( conn );
  440. // conn->addPeerInfo( peerInfo );
  441. }
  442. }
  443. else
  444. {
  445. QString key = uuid();
  446. const QString& nodeid = Database::instance()->impl()->dbid();
  447. QList<SipInfo> sipInfos = getLocalSipInfos( nodeid, key );
  448. // The offer should be removed after some time or we will build up a heap of unused PeerInfos
  449. registerLazyOffer( key, peerInfo, nodeid, sipInfos.length() * 1.5 * CONNECT_TIMEOUT );
  450. // SipInfos were single-value before 0.7.100
  451. if ( !peerInfo->versionString().isEmpty() && TomahawkUtils::compareVersionStrings( peerInfo->versionString().split(' ').last(), "0.7.100" ) < 0)
  452. {
  453. SipInfo info = getSipInfoForOldVersions( sipInfos );
  454. peerInfo->sendLocalSipInfos( QList<SipInfo>() << info );
  455. }
  456. else
  457. {
  458. peerInfo->sendLocalSipInfos( sipInfos );
  459. }
  460. handleSipInfo( peerInfo );
  461. connect( peerInfo.data(), SIGNAL( sipInfoChanged() ), SLOT( onSipInfoChanged() ) );
  462. }
  463. }
  464. void
  465. Servent::onSipInfoChanged()
  466. {
  467. Tomahawk::PeerInfo* peerInfo = qobject_cast< Tomahawk::PeerInfo* >( sender() );
  468. if ( !peerInfo )
  469. return;
  470. handleSipInfo( peerInfo->weakRef().toStrongRef() );
  471. }
  472. void
  473. Servent::handleSipInfo( const Tomahawk::peerinfo_ptr& peerInfo )
  474. {
  475. // We do not have received the initial SipInfo for this client yet, so wait for it.
  476. // Each client will have at least one non-visible SipInfo
  477. if ( peerInfo->sipInfos().isEmpty() )
  478. return;
  479. QSharedPointer<ConnectionManager> manager = ConnectionManager::getManagerForNodeId( peerInfo->nodeId() );
  480. manager->handleSipInfo( peerInfo );
  481. }
  482. void
  483. Servent::incomingConnection( qintptr sd )
  484. {
  485. Q_ASSERT( this->thread() == QThread::currentThread() );
  486. QTcpSocketExtra* sock = new QTcpSocketExtra;
  487. tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "Accepting connection, sock" << sock;
  488. sock->moveToThread( thread() );
  489. sock->_disowned = false;
  490. sock->_outbound = false;
  491. if ( !sock->setSocketDescriptor( sd ) )
  492. {
  493. Q_ASSERT( false );
  494. return;
  495. }
  496. connect( sock, SIGNAL( readyRead() ), SLOT( readyRead() ) );
  497. connect( sock, SIGNAL( disconnected() ), sock, SLOT( deleteLater() ) );
  498. }
  499. void
  500. Servent::readyRead()
  501. {
  502. Q_D( Servent );
  503. Q_ASSERT( this->thread() == QThread::currentThread() );
  504. QPointer< QTcpSocketExtra > sock = (QTcpSocketExtra*)sender();
  505. tLog( LOGVERBOSE ) << Q_FUNC_INFO << "Starting to read from new incoming connection from: " << sock->peerAddress().toString();
  506. if ( sock.isNull() || sock.data()->_disowned )
  507. {
  508. return;
  509. }
  510. if ( sock.data()->_msg.isNull() )
  511. {
  512. char msgheader[ Msg::headerSize() ];
  513. if ( sock.data()->bytesAvailable() < Msg::headerSize() )
  514. return;
  515. sock.data()->read( (char*) &msgheader, Msg::headerSize() );
  516. sock.data()->_msg = Msg::begin( (char*) &msgheader );
  517. }
  518. if ( sock.data()->bytesAvailable() < sock.data()->_msg->length() )
  519. return;
  520. QByteArray ba = sock.data()->read( sock.data()->_msg->length() );
  521. sock.data()->_msg->fill( ba );
  522. if ( !sock.data()->_msg->is( Msg::JSON ) )
  523. {
  524. tDebug() << ba;
  525. tDebug() << sock.data()->_msg->payload();
  526. Q_ASSERT( sock.data()->_msg->is( Msg::JSON ) );
  527. }
  528. ControlConnection* cc = 0;
  529. bool ok;
  530. QString key, conntype, nodeid, controlid;
  531. QVariantMap m = TomahawkUtils::parseJson( sock.data()->_msg->payload(), &ok ).toMap();
  532. if ( !ok )
  533. {
  534. tDebug() << "Invalid JSON on new connection, aborting";
  535. goto closeconnection;
  536. }
  537. conntype = m.value( "conntype" ).toString();
  538. key = m.value( "key" ).toString();
  539. nodeid = m.value( "nodeid" ).toString();
  540. controlid = m.value( "controlid" ).toString();
  541. tDebug( LOGVERBOSE ) << "Incoming connection details:" << m;
  542. if ( !nodeid.isEmpty() ) // only control connections send nodeid
  543. {
  544. QMutexLocker locker( &d->controlconnectionsMutex );
  545. bool dupe = false;
  546. if ( d_func()->connectedNodes.contains( nodeid ) )
  547. {
  548. tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "Connected nodes contains it.";
  549. dupe = true;
  550. }
  551. foreach ( ControlConnection* con, d_func()->controlconnections )
  552. {
  553. Q_ASSERT( con );
  554. tLog( LOGVERBOSE ) << Q_FUNC_INFO << "Known connection:" << con->id();
  555. // Only check for known inboud ControlConnections
  556. if ( con->id() == nodeid && !con->outbound() )
  557. {
  558. dupe = true;
  559. break;
  560. }
  561. }
  562. // for zeroconf there might be no offer, that case is handled later
  563. ControlConnection* ccMatch = qobject_cast< ControlConnection* >( d_func()->offers.value( key ).data() );
  564. if ( dupe && ccMatch )
  565. {
  566. tLog() << "Duplicate control connection detected, dropping:" << nodeid << conntype;
  567. tDebug() << "PEERINFO: to be dropped connection has following peers";
  568. foreach ( const peerinfo_ptr& currentPeerInfo, ccMatch->peerInfos() )
  569. {
  570. peerInfoDebug( currentPeerInfo );
  571. }
  572. foreach ( ControlConnection* keepConnection, d_func()->controlconnections )
  573. {
  574. Q_ASSERT( keepConnection );
  575. // Only check for known inboud ControlConnections
  576. if ( keepConnection->id() == nodeid && !keepConnection->outbound() )
  577. {
  578. tDebug() << "Keep connection" << keepConnection->name() << "with following peers";
  579. foreach ( const peerinfo_ptr& currentPeerInfo, keepConnection->peerInfos() )
  580. peerInfoDebug( currentPeerInfo );
  581. tDebug() << "Add these peers now";
  582. foreach ( const peerinfo_ptr& currentPeerInfo, ccMatch->peerInfos() )
  583. {
  584. tDebug() << "Adding" << currentPeerInfo->id();
  585. keepConnection->addPeerInfo( currentPeerInfo );
  586. }
  587. tDebug() << "Done adding.";
  588. }
  589. }
  590. goto closeconnection;
  591. }
  592. }
  593. {
  594. QMutexLocker locker( &d->controlconnectionsMutex );
  595. foreach ( ControlConnection* con, d_func()->controlconnections )
  596. {
  597. Q_ASSERT( con );
  598. // Only check for known inboud ControlConnections
  599. if ( con->id() == controlid && !con->outbound() )
  600. {
  601. cc = con;
  602. break;
  603. }
  604. }
  605. }
  606. // they connected to us and want something we are offering
  607. if ( conntype == "accept-offer" || conntype == "push-offer" )
  608. {
  609. sock.data()->_msg.clear();
  610. tDebug( LOGVERBOSE ) << Q_FUNC_INFO << key << nodeid << "socket peer address =" << sock.data()->peerAddress() << "socket peer name =" << sock.data()->peerName();
  611. Connection* conn = claimOffer( cc, nodeid, key, sock.data()->peerAddress() );
  612. if ( !conn )
  613. {
  614. tLog() << "claimOffer FAILED, key:" << key << nodeid;
  615. goto closeconnection;
  616. }
  617. if ( sock.isNull() )
  618. {
  619. tLog() << "Socket has become null, possibly took too long to make an ACL decision, key:" << key << nodeid;
  620. return;
  621. }
  622. else if ( !sock.data()->isValid() )
  623. {
  624. tLog() << "Socket has become invalid, possibly took too long to make an ACL decision, key:" << key << nodeid;
  625. goto closeconnection;
  626. }
  627. tDebug( LOGVERBOSE ) << "claimOffer OK:" << key << nodeid;
  628. if ( !nodeid.isEmpty() )
  629. {
  630. conn->setId( nodeid );
  631. registerControlConnection( qobject_cast<ControlConnection*>(conn) );
  632. }
  633. handoverSocket( conn, sock.data() );
  634. return;
  635. }
  636. else
  637. {
  638. tLog() << "Invalid or unhandled conntype";
  639. }
  640. // fallthru to cleanup:
  641. closeconnection:
  642. tLog() << "Closing incoming connection, something was wrong.";
  643. sock.data()->_msg.clear();
  644. sock.data()->disconnectFromHost();
  645. }
  646. // creates a new tcp connection to peer from conn, handled by given connector
  647. // new_conn is responsible for sending the first msg, if needed
  648. void
  649. Servent::createParallelConnection( Connection* orig_conn, Connection* new_conn, const QString& key )
  650. {
  651. tDebug( LOGVERBOSE ) << Q_FUNC_INFO << ", key:" << key << thread() << orig_conn;
  652. // if we can connect to them directly:
  653. if ( orig_conn && orig_conn->outbound() )
  654. {
  655. SipInfo info = SipInfo();
  656. info.setVisible( true );
  657. info.setKey( key );
  658. info.setNodeId( orig_conn->id() );
  659. info.setHost( orig_conn->socket()->peerName() );
  660. info.setPort( orig_conn->peerPort() );
  661. Q_ASSERT( info.isValid() );
  662. initiateConnection( info, new_conn );
  663. }
  664. else // ask them to connect to us:
  665. {
  666. QString tmpkey = uuid();
  667. tLog() << "Asking them to connect to us using" << tmpkey ;
  668. registerOffer( tmpkey, new_conn );
  669. QVariantMap m;
  670. m.insert( "conntype", "request-offer" );
  671. m.insert( "key", tmpkey );
  672. m.insert( "offer", key );
  673. m.insert( "controlid", Database::instance()->impl()->dbid() );
  674. if (orig_conn) {
  675. orig_conn->sendMsg( Msg::factory( TomahawkUtils::toJson( m ), Msg::JSON ) );
  676. }
  677. }
  678. }
  679. void
  680. Servent::socketConnected()
  681. {
  682. QTcpSocketExtra* sock = (QTcpSocketExtra*)sender();
  683. tLog( LOGVERBOSE ) << Q_FUNC_INFO << thread() << "socket:" << sock << ", hostaddr:" << sock->peerAddress() << ", hostname:" << sock->peerName();
  684. if ( sock->_conn.isNull() )
  685. {
  686. sock->close();
  687. sock->deleteLater();
  688. tLog( LOGVERBOSE ) << Q_FUNC_INFO << "Socket's connection was null, could have timed out or been given an invalid address";
  689. return;
  690. }
  691. Connection* conn = sock->_conn.data();
  692. handoverSocket( conn, sock );
  693. }
  694. // transfers ownership of socket to the connection and inits the connection
  695. void
  696. Servent::handoverSocket( Connection* conn, QTcpSocketExtra* sock )
  697. {
  698. Q_ASSERT( conn );
  699. Q_ASSERT( sock );
  700. Q_ASSERT( conn->socket().isNull() );
  701. Q_ASSERT( sock->isValid() );
  702. disconnect( sock, SIGNAL( readyRead() ), this, SLOT( readyRead() ) );
  703. disconnect( sock, SIGNAL( disconnected() ), sock, SLOT( deleteLater() ) );
  704. disconnect( sock, SIGNAL( error( QAbstractSocket::SocketError ) ), this, SLOT( socketError( QAbstractSocket::SocketError ) ) );
  705. sock->_disowned = true;
  706. conn->setOutbound( sock->_outbound );
  707. conn->setPeerPort( sock->peerPort() );
  708. conn->start( sock );
  709. }
  710. void
  711. Servent::cleanupSocket( QTcpSocketExtra* sock )
  712. {
  713. if ( !sock )
  714. {
  715. tLog() << "SocketError, sock is null";
  716. return;
  717. }
  718. if ( sock->_conn.isNull() )
  719. {
  720. tLog() << "SocketError, connection is null";
  721. }
  722. sock->deleteLater();
  723. }
  724. void
  725. Servent::initiateConnection( const SipInfo& sipInfo, Connection* conn )
  726. {
  727. Q_D( Servent );
  728. Q_ASSERT( sipInfo.isValid() );
  729. Q_ASSERT( sipInfo.isVisible() );
  730. Q_ASSERT( sipInfo.port() > 0 );
  731. Q_ASSERT( conn );
  732. // Check that we are not connecting to ourselves
  733. QList<QHostAddress> addresses = d->externalAddresses;
  734. if ( d->externalListenAll )
  735. {
  736. addresses = QNetworkInterface::allAddresses();
  737. }
  738. foreach ( QHostAddress ha, addresses )
  739. {
  740. if ( sipInfo.host() == ha.toString() && sipInfo.port() == d_func()->port )
  741. {
  742. tLog( LOGVERBOSE ) << Q_FUNC_INFO << "Tomahawk won't try to connect to" << sipInfo.host() << ":" << sipInfo.port() << ": same IP as ourselves.";
  743. return;
  744. }
  745. }
  746. if ( sipInfo.host() == d_func()->externalHostname && sipInfo.port() == d_func()->port )
  747. {
  748. tLog( LOGVERBOSE ) << Q_FUNC_INFO << "Tomahawk won't try to connect to" << sipInfo.host() << ":" << sipInfo.port() << ": same IP as ourselves.";
  749. return;
  750. }
  751. if ( conn->firstMessage().isNull() )
  752. {
  753. QVariantMap m;
  754. m["conntype"] = "accept-offer";
  755. m["key"] = sipInfo.key();
  756. m["controlid"] = Database::instance()->impl()->dbid();
  757. conn->setFirstMessage( m );
  758. }
  759. QTcpSocketExtra* sock = new QTcpSocketExtra();
  760. sock->setConnectTimeout( CONNECT_TIMEOUT );
  761. sock->_disowned = false;
  762. sock->_conn = conn;
  763. sock->_outbound = true;
  764. connect( sock, SIGNAL( connected() ), SLOT( socketConnected() ) );
  765. connect( sock, SIGNAL( error( QAbstractSocket::SocketError ) ), this, SLOT( socketError( QAbstractSocket::SocketError ) ) );
  766. if ( !conn->peerIpAddress().isNull() )
  767. sock->connectToHost( conn->peerIpAddress(), sipInfo.port(), QTcpSocket::ReadWrite );
  768. else
  769. sock->connectToHost( sipInfo.host(), sipInfo.port(), QTcpSocket::ReadWrite );
  770. sock->moveToThread( thread() );
  771. }
  772. void
  773. Servent::socketError( QAbstractSocket::SocketError e )
  774. {
  775. QTcpSocketExtra* sock = (QTcpSocketExtra*)sender();
  776. if ( !sock )
  777. {
  778. tLog() << "SocketError, sock is null";
  779. return;
  780. }
  781. if ( !sock->_conn.isNull() )
  782. {
  783. Connection* conn = sock->_conn.data();
  784. tLog() << "Servent::SocketError:" << e << conn->id() << conn->name();
  785. if ( !sock->_disowned )
  786. {
  787. // connection will delete if we already transferred ownership, otherwise:
  788. sock->deleteLater();
  789. }
  790. conn->markAsFailed(); // will emit failed, then finished
  791. }
  792. else
  793. {
  794. tLog() << "SocketError, connection is null";
  795. sock->deleteLater();
  796. }
  797. }
  798. void
  799. Servent::checkACLResult( const QString& nodeid, const QString& username, Tomahawk::ACLStatus::Type peerStatus )
  800. {
  801. Q_D( Servent );
  802. if ( !d->queuedForACLResult.contains( username ) )
  803. {
  804. return;
  805. }
  806. if ( !d->queuedForACLResult.value( username ).contains( nodeid ) )
  807. {
  808. return;
  809. }
  810. tDebug( LOGVERBOSE ) << Q_FUNC_INFO << QString( "ACL status for user %1 is" ).arg( username ) << peerStatus;
  811. QSet<Tomahawk::peerinfo_ptr> peerInfos = d->queuedForACLResult.value( username ).value( nodeid );
  812. if ( peerStatus == Tomahawk::ACLStatus::Stream )
  813. {
  814. foreach ( const Tomahawk::peerinfo_ptr& peerInfo, peerInfos )
  815. {
  816. registerPeer( peerInfo );
  817. }
  818. }
  819. // We have a result, so remove from queue
  820. d->queuedForACLResult[username].remove( nodeid );
  821. }
  822. void
  823. Servent::ipDetected()
  824. {
  825. Q_D( Servent );
  826. QNetworkReply* reply = qobject_cast<QNetworkReply*>( sender() );
  827. if ( reply->error() == QNetworkReply::NoError )
  828. {
  829. bool ok;
  830. // We are called when the NetworkReply has finished so we should have all data available.
  831. const QVariantMap res = TomahawkUtils::parseJson( reply->readAll(), &ok ).toMap();
  832. if ( !ok )
  833. {
  834. tLog() << Q_FUNC_INFO << "Failed parsing ip-autodetection response";
  835. d->externalPort = -1;
  836. emit ipDetectionFailed( QNetworkReply::NoError, tr( "Automatically detecting external IP failed: Could not parse JSON response." ) );
  837. }
  838. else
  839. {
  840. QString externalIP = res.value( "ip" ).toString();
  841. tLog( LOGVERBOSE ) << Q_FUNC_INFO << "Found external IP:" << externalIP;
  842. d->externalHostname = externalIP;
  843. }
  844. }
  845. else
  846. {
  847. d->externalPort = -1;
  848. tLog() << Q_FUNC_INFO << "ip-autodetection returned an error:" << reply->errorString();
  849. emit ipDetectionFailed( reply->error(), tr( "Automatically detecting external IP failed: %1" ).arg( reply->errorString() ) );
  850. }
  851. d->ready = true;
  852. emit ready();
  853. }
  854. void
  855. Servent::reverseOfferRequest( ControlConnection* orig_conn, const QString& theirdbid, const QString& key, const QString& theirkey )
  856. {
  857. Q_ASSERT( this->thread() == QThread::currentThread() );
  858. tDebug( LOGVERBOSE ) << "Servent::reverseOfferRequest received for" << key;
  859. Connection* new_conn = claimOffer( orig_conn, theirdbid, key );
  860. if ( !new_conn )
  861. {
  862. tDebug() << "claimOffer failed, killing requesting connection out of spite";
  863. orig_conn->shutdown();
  864. return;
  865. }
  866. QVariantMap m;
  867. m["conntype"] = "push-offer";
  868. m["key"] = theirkey;
  869. m["controlid"] = Database::instance()->impl()->dbid();
  870. new_conn->setFirstMessage( m );
  871. createParallelConnection( orig_conn, new_conn, theirkey );
  872. }
  873. bool
  874. Servent::visibleExternally() const
  875. {
  876. return !d_func()->externalHostname.isNull() || !d_func()->externalAddresses.isEmpty();
  877. }
  878. bool
  879. Servent::ipv6ConnectivityLikely() const
  880. {
  881. foreach ( QHostAddress ha, d_func()->externalAddresses )
  882. {
  883. if ( ha.protocol() == QAbstractSocket::IPv6Protocol && Servent::isValidExternalIP( ha ) )
  884. {
  885. return true;
  886. }
  887. }
  888. return false;
  889. }
  890. int
  891. Servent::port() const
  892. {
  893. return d_func()->port;
  894. }
  895. QList<QHostAddress>
  896. Servent::addresses() const
  897. {
  898. Q_D( const Servent );
  899. if ( d->externalListenAll )
  900. {
  901. QList<QHostAddress> addresses( QNetworkInterface::allAddresses() );
  902. cleanAddresses( addresses );
  903. return addresses;
  904. }
  905. return d->externalAddresses;
  906. }
  907. QString
  908. Servent::additionalAddress() const
  909. {
  910. return d_func()->externalHostname;
  911. }
  912. int
  913. Servent::additionalPort() const
  914. {
  915. return d_func()->externalPort;
  916. }
  917. bool
  918. equalByIPv6Address( QHostAddress a1, QHostAddress a2 )
  919. {
  920. Q_IPV6ADDR addr1 = a1.toIPv6Address();
  921. Q_IPV6ADDR addr2 = a2.toIPv6Address();
  922. for (int i = 0; i < 16; ++i)
  923. {
  924. if ( addr1[i] != addr2[i] )
  925. return false;
  926. }
  927. return true;
  928. }
  929. // return the appropriate connection for a given offer key, or NULL if invalid
  930. Connection*
  931. Servent::claimOffer( ControlConnection* cc, const QString &nodeid, const QString &key, const QHostAddress peer )
  932. {
  933. Q_D( Servent );
  934. // magic key for stream connections:
  935. if ( key.startsWith( "FILE_REQUEST_KEY:" ) )
  936. {
  937. // check if the source IP matches an existing, authenticated connection
  938. if ( !d->noAuth && peer != QHostAddress::Any && !isIPWhitelisted( peer ) )
  939. {
  940. bool authed = false;
  941. tLog( LOGVERBOSE ) << Q_FUNC_INFO << "Checking for ControlConnection with IP" << peer;
  942. QMutexLocker locker( &d->controlconnectionsMutex );
  943. foreach ( ControlConnection* cc, d->controlconnections )
  944. {
  945. if ( cc->socket() )
  946. tLog( LOGVERBOSE ) << Q_FUNC_INFO << "Probing:" << cc->name() << cc->socket()->peerAddress();
  947. else
  948. tLog( LOGVERBOSE ) << Q_FUNC_INFO << "Probing error:" << cc->name() << "has invalid socket";
  949. // Always compare IPv6 addresses as IPv4 address are sometime simply IPv4 addresses, sometimes mapped IPv6 addresses
  950. if ( cc->socket() && equalByIPv6Address( cc->socket()->peerAddress(), peer ) )
  951. {
  952. authed = true;
  953. break;
  954. }
  955. }
  956. if ( !authed )
  957. {
  958. tLog() << "File transfer request rejected as the request came from an IP which we could not match to existing peer connections.";
  959. return NULL;
  960. }
  961. }
  962. QString fid = key.right( key.length() - 17 );
  963. StreamConnection* sc = new StreamConnection( this, cc, fid );
  964. return sc;
  965. }
  966. if ( key == "whitelist" ) // LAN IP address, check source IP
  967. {
  968. if ( isIPWhitelisted( peer ) )
  969. {
  970. tDebug() << "Connection is from whitelisted IP range (LAN)";
  971. ControlConnection* conn = new ControlConnection( this );
  972. conn->setName( peer.toString() );
  973. Tomahawk::Accounts::Account* account = Tomahawk::Accounts::AccountManager::instance()->zeroconfAccount();
  974. // if we get this connection the account should exist and be enabled
  975. Q_ASSERT( account );
  976. Q_ASSERT( account->enabled() );
  977. // this is terrible, actually there should be a way to let this be created by the zeroconf plugin
  978. // because this way we rely on the ip being used as id in two totally different parts of the code
  979. Tomahawk::peerinfo_ptr peerInfo = Tomahawk::PeerInfo::get( account->sipPlugin(), peer.toString(), Tomahawk::PeerInfo::AutoCreate );
  980. peerInfo->setContactId( peer.toString() );
  981. peerInfoDebug( peerInfo );
  982. conn->addPeerInfo( peerInfo );
  983. return conn;
  984. }
  985. else
  986. {
  987. tDebug() << "Connection claimed to be whitelisted, but wasn't.";
  988. return NULL;
  989. }
  990. }
  991. if ( d->lazyoffers.contains( key ) )
  992. {
  993. ControlConnection* conn = new ControlConnection( this );
  994. conn->setName( d->lazyoffers.value( key ).first->contactId() );
  995. conn->addPeerInfo( d->lazyoffers.value( key ).first );
  996. conn->setId( d->lazyoffers.value( key ).second );
  997. if ( !nodeid.isEmpty() )
  998. {
  999. // Used by the connection for the ACL check
  1000. // If there isn't a nodeid it's not the first connection and will already have been stopped
  1001. conn->setNodeId( nodeid );
  1002. }
  1003. return conn;
  1004. }
  1005. else if ( d->offers.contains( key ) )
  1006. {
  1007. QPointer<Connection> conn = d->offers.value( key );
  1008. if ( conn.isNull() )
  1009. {
  1010. // This can happen if it's a streamconnection, but the audioengine has
  1011. // already closed the iodevice, causing the connection to be deleted before
  1012. // the peer connects and provides the first byte
  1013. tLog() << Q_FUNC_INFO << "invalid/expired offer:" << key;
  1014. return NULL;
  1015. }
  1016. tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "nodeid is: " << nodeid;
  1017. if ( !nodeid.isEmpty() )
  1018. {
  1019. // Used by the connection for the ACL check
  1020. // If there isn't a nodeid it's not the first connection and will already have been stopped
  1021. conn->setNodeId( nodeid );
  1022. }
  1023. if ( conn.data()->onceOnly() )
  1024. {
  1025. d->offers.remove( key );
  1026. return conn.data();
  1027. }
  1028. else
  1029. {
  1030. return conn.data()->clone();
  1031. }
  1032. }
  1033. else if ( d->noAuth )
  1034. {
  1035. Connection* conn;
  1036. conn = new ControlConnection( this );
  1037. conn->setName( key );
  1038. return conn;
  1039. }
  1040. else
  1041. {
  1042. tLog() << "Invalid offer key:" << key;
  1043. return NULL;
  1044. }
  1045. }
  1046. void
  1047. Servent::remoteIODeviceFactory( const Tomahawk::result_ptr& result, const QString& url,
  1048. std::function< void ( const QString&, QSharedPointer< QIODevice >& ) > callback )
  1049. {
  1050. QSharedPointer<QIODevice> sp;
  1051. QStringList parts = url.mid( QString( "servent://" ).length() ).split( "\t" );
  1052. const QString sourceName = parts.at( 0 );
  1053. const QString fileId = parts.at( 1 );
  1054. source_ptr s = SourceList::instance()->get( sourceName );
  1055. if ( s.isNull() || !s->controlConnection() )
  1056. {
  1057. callback( result->url(), sp );
  1058. return;
  1059. }
  1060. ControlConnection* cc = s->controlConnection();
  1061. StreamConnection* sc = new StreamConnection( this, cc, fileId, result );
  1062. createParallelConnection( cc, sc, QString( "FILE_REQUEST_KEY:%1" ).arg( fileId ) );
  1063. // std::functions cannot accept temporaries as parameters
  1064. sp = sc->iodevice();
  1065. callback( result->url(), sp );
  1066. }
  1067. void
  1068. Servent::registerStreamConnection( StreamConnection* sc )
  1069. {
  1070. Q_ASSERT( !d_func()->scsessions.contains( sc ) );
  1071. tDebug( LOGVERBOSE ) << "Registering Stream" << d_func()->scsessions.length() + 1;
  1072. QMutexLocker lock( &d_func()->ftsession_mut );
  1073. d_func()->scsessions.append( sc );
  1074. printCurrentTransfers();
  1075. emit streamStarted( sc );
  1076. }
  1077. void
  1078. Servent::onStreamFinished( StreamConnection* sc )
  1079. {
  1080. Q_ASSERT( sc );
  1081. tDebug( LOGVERBOSE ) << "Stream Finished, unregistering" << sc->id();
  1082. QMutexLocker lock( &d_func()->ftsession_mut );
  1083. d_func()->scsessions.removeAll( sc );
  1084. printCurrentTransfers();
  1085. emit streamFinished( sc );
  1086. }
  1087. // used for debug output:
  1088. void
  1089. Servent::printCurrentTransfers()
  1090. {
  1091. int k = 1;
  1092. // qDebug() << "~~~ Active file transfer connections:" << m_scsessions.length();
  1093. foreach ( StreamConnection* i, d_func()->scsessions )
  1094. {
  1095. qDebug() << k << ") " << i->id();
  1096. }
  1097. qDebug() << endl;
  1098. }
  1099. void
  1100. Servent::cleanAddresses( QList<QHostAddress>& addresses ) const
  1101. {
  1102. QList<QHostAddress>::iterator iter = addresses.begin();
  1103. while ( iter != addresses.end() )
  1104. {
  1105. QString hostString = iter->toString();
  1106. if ( hostString.startsWith( QLatin1String( "127.0.0." ) ) //< IPv4 localhost
  1107. // IPv6 localhost
  1108. || hostString == "::1"
  1109. // IPv4 localhost as IPv6 address
  1110. || hostString == "::7F00:1" )
  1111. {
  1112. iter = addresses.erase( iter );
  1113. // Always continue if we changed iter as we might have reached the end
  1114. continue;
  1115. }
  1116. // Remove IPv6 link local addresses
  1117. if ( iter->isInSubnet( QHostAddress::parseSubnet( "fe80::/10" ) ) )
  1118. {
  1119. iter = addresses.erase( iter );
  1120. continue;
  1121. }
  1122. // Advance to next element
  1123. ++iter;
  1124. }
  1125. }
  1126. bool
  1127. Servent::isIPWhitelisted( QHostAddress ip )
  1128. {
  1129. tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "Performing checks against ip" << ip.toString();
  1130. typedef QPair< QHostAddress, int > range;
  1131. QList< range > subnetEntries;
  1132. QList< QNetworkInterface > networkInterfaces = QNetworkInterface::allInterfaces();
  1133. foreach ( QNetworkInterface interface, networkInterfaces )
  1134. {
  1135. tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "Checking interface" << interface.humanReadableName();
  1136. QList< QNetworkAddressEntry > addressEntries = interface.addressEntries();
  1137. foreach ( QNetworkAddressEntry addressEntry, addressEntries )
  1138. {
  1139. tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "Checking address entry with ip" << addressEntry.ip().toString() << "and prefix length" << addressEntry.prefixLength();
  1140. if ( ip.isInSubnet( addressEntry.ip(), addressEntry.prefixLength() ) )
  1141. {
  1142. tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "success";
  1143. return true;
  1144. }
  1145. }
  1146. }
  1147. // Qt cannot cope correctly with IPv4 addresses mapped into the IPv6
  1148. // address space
  1149. if ( ip.protocol() == QAbstractSocket::IPv6Protocol )
  1150. {
  1151. Q_IPV6ADDR ipv6 = ip.toIPv6Address();
  1152. // Check if it is actually an IPv4 address
  1153. // First 80 bits are zero, then 16 bits 1s
  1154. bool isIPv4 = true;
  1155. for ( int i = 0; i < 9; i++) {
  1156. isIPv4 &= ( ipv6[i] == 0 );
  1157. }
  1158. isIPv4 &= ( ipv6[10] == 0xff );
  1159. isIPv4 &= ( ipv6[11] == 0xff );
  1160. if ( isIPv4 )
  1161. {
  1162. // Convert to a real IPv4 address and rerun checks
  1163. quint32 ipv4 = (static_cast<quint32>(ipv6[12]) << 24)
  1164. | (static_cast<quint32>(ipv6[13]) << 16)
  1165. | (static_cast<quint32>(ipv6[14]) << 8)
  1166. | static_cast<quint32>(ipv6[15]);
  1167. QHostAddress addr( ipv4 );
  1168. return isIPWhitelisted( addr );
  1169. }
  1170. }
  1171. tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "failure";
  1172. return false;
  1173. }
  1174. bool
  1175. Servent::connectedToSession( const QString& session )
  1176. {
  1177. Q_D( Servent );
  1178. QMutexLocker locker( &d->controlconnectionsMutex );
  1179. foreach ( ControlConnection* cc, d_func()->controlconnections )
  1180. {
  1181. Q_ASSERT( cc );
  1182. if ( cc->id() == session )
  1183. return true;
  1184. }
  1185. return false;
  1186. }
  1187. unsigned int
  1188. Servent::numConnectedPeers() const
  1189. {
  1190. return d_func()->controlconnections.length();
  1191. }
  1192. QList<StreamConnection*>
  1193. Servent::streams() const
  1194. {
  1195. return d_func()->scsessions;
  1196. }
  1197. void
  1198. Servent::triggerDBSync()
  1199. {
  1200. // tell peers we have new stuff they should sync
  1201. QList< source_ptr > sources = SourceList::instance()->sources();
  1202. foreach ( const source_ptr& src, sources )
  1203. {
  1204. // skip local source
  1205. if ( src.isNull() || src->isLocal() )
  1206. continue;
  1207. if ( src->controlConnection() && src->controlConnection()->dbSyncConnection() ) // source online?
  1208. src->controlConnection()->dbSyncConnection()->trigger();
  1209. }
  1210. emit dbSyncTriggered();
  1211. }
  1212. bool
  1213. Servent::isReady() const
  1214. {
  1215. return d_func()->ready;
  1216. }