/src/libtomahawk/network/Connection.cpp

http://github.com/tomahawk-player/tomahawk · C++ · 701 lines · 505 code · 145 blank · 51 comment · 53 complexity · 92ec521b9ae8e6e60131a4d552a6e896 MD5 · raw file

  1. /* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
  2. *
  3. * Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
  4. * Copyright 2010-2011, Jeff Mitchell <jeff@tomahawk-player.org>
  5. * Copyright 2013, Uwe L. Korn <uwelk@xhochy.com>
  6. *
  7. * Tomahawk is free software: you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation, either version 3 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * Tomahawk is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
  19. */
  20. #include "Connection_p.h"
  21. #include "network/acl/AclRegistry.h"
  22. #include "network/acl/AclRequest.h"
  23. #include "network/Servent.h"
  24. #include "network/Msg.h"
  25. #include "utils/Logger.h"
  26. #include "utils/Json.h"
  27. #include "utils/TomahawkUtils.h"
  28. #include "QTcpSocketExtra.h"
  29. #include "Source.h"
  30. #include <QTime>
  31. #include <QThread>
  32. #define PROTOVER "4" // must match remote peer, or we can't talk.
  33. Connection::Connection( Servent* parent )
  34. : QObject()
  35. , d_ptr( new ConnectionPrivate( this, parent ) )
  36. {
  37. moveToThread( parent->thread() );
  38. tDebug( LOGVERBOSE ) << "CTOR Connection (super)" << thread();
  39. connect( &d_func()->msgprocessor_out, SIGNAL( ready( msg_ptr ) ),
  40. SLOT( sendMsg_now( msg_ptr ) ), Qt::QueuedConnection );
  41. connect( &d_func()->msgprocessor_in, SIGNAL( ready( msg_ptr ) ),
  42. SLOT( handleMsg( msg_ptr ) ), Qt::QueuedConnection );
  43. connect( &d_func()->msgprocessor_in, SIGNAL( empty() ),
  44. SLOT( handleIncomingQueueEmpty() ), Qt::QueuedConnection );
  45. }
  46. Connection::~Connection()
  47. {
  48. Q_D( Connection );
  49. tDebug( LOGVERBOSE ) << "DTOR connection (super)" << id() << thread() << d->sock.isNull();
  50. if ( !d->sock.isNull() )
  51. {
  52. d->sock->deleteLater();
  53. }
  54. delete d->statstimer;
  55. delete d_ptr;
  56. }
  57. void
  58. Connection::handleIncomingQueueEmpty()
  59. {
  60. Q_D( Connection );
  61. //qDebug() << Q_FUNC_INFO << "bavail" << m_sock->bytesAvailable()
  62. // << "isopen" << m_sock->isOpen()
  63. // << "m_peer_disconnected" << m_peer_disconnected
  64. // << "bytes rx" << bytesReceived();
  65. if ( !d->sock.isNull() && d->sock->bytesAvailable() == 0 && d->peer_disconnected )
  66. {
  67. tDebug( LOGVERBOSE ) << "No more data to read, peer disconnected. shutting down connection."
  68. << "bytesavail" << d->sock->bytesAvailable()
  69. << "bytesrx" << d->rx_bytes;
  70. shutdown();
  71. }
  72. }
  73. // convenience:
  74. void
  75. Connection::setFirstMessage( const QVariant& m )
  76. {
  77. const QByteArray ba = TomahawkUtils::toJson( m );
  78. //qDebug() << "first msg json len:" << ba.length();
  79. setFirstMessage( Msg::factory( ba, Msg::JSON ) );
  80. }
  81. void
  82. Connection::setFirstMessage( msg_ptr m )
  83. {
  84. Q_D( Connection );
  85. d->firstmsg = m;
  86. //qDebug() << id() << " first msg set to " << QString::fromAscii(m_firstmsg->payload())
  87. // << "msg len:" << m_firstmsg->length() ;
  88. }
  89. msg_ptr
  90. Connection::firstMessage() const
  91. {
  92. Q_D( const Connection );
  93. return d->firstmsg;
  94. }
  95. const QPointer<QTcpSocket>&
  96. Connection::socket() const
  97. {
  98. Q_D( const Connection );
  99. return d->sock;
  100. }
  101. void
  102. Connection::setOutbound( bool o )
  103. {
  104. Q_D( Connection );
  105. d->outbound = o;
  106. }
  107. bool
  108. Connection::outbound() const
  109. {
  110. Q_D( const Connection );
  111. return d->outbound;
  112. }
  113. Servent*
  114. Connection::servent() const
  115. {
  116. Q_D( const Connection );
  117. return d->servent;
  118. }
  119. int
  120. Connection::peerPort() const
  121. {
  122. Q_D( const Connection );
  123. return d->peerport;
  124. }
  125. void
  126. Connection::setPeerPort(int p)
  127. {
  128. Q_D( Connection );
  129. d->peerport = p;
  130. }
  131. void
  132. Connection::shutdown( bool waitUntilSentAll )
  133. {
  134. tDebug( LOGVERBOSE ) << Q_FUNC_INFO << waitUntilSentAll << id();
  135. if ( d_func()->do_shutdown )
  136. {
  137. //qDebug() << id() << " already shutting down";
  138. return;
  139. }
  140. d_func()->do_shutdown = true;
  141. if ( !waitUntilSentAll )
  142. {
  143. // qDebug() << "Shutting down immediately " << id();
  144. actualShutdown();
  145. }
  146. else
  147. {
  148. tDebug( LOGVERBOSE ) << "Shutting down after transfer complete " << id()
  149. << "Actual/Desired" << d_func()->tx_bytes << d_func()->tx_bytes_requested;
  150. bytesWritten( 0 ); // trigger shutdown if we've already sent everything
  151. // otherwise the bytesWritten slot will call actualShutdown()
  152. // once all enqueued data has been properly written to the socket
  153. }
  154. }
  155. void
  156. Connection::actualShutdown()
  157. {
  158. Q_D( Connection );
  159. tDebug( LOGVERBOSE ) << Q_FUNC_INFO << d->actually_shutting_down << id();
  160. if ( d->actually_shutting_down )
  161. {
  162. return;
  163. }
  164. d->actually_shutting_down = true;
  165. if ( !d->sock.isNull() && d->sock->isOpen() )
  166. {
  167. d->sock->disconnectFromHost();
  168. }
  169. // qDebug() << "EMITTING finished()";
  170. emit finished();
  171. }
  172. void
  173. Connection::markAsFailed()
  174. {
  175. tDebug( LOGVERBOSE ) << "Connection" << id() << "FAILED ***************" << thread();
  176. emit failed();
  177. shutdown();
  178. }
  179. void
  180. Connection::setName( const QString& n )
  181. {
  182. Q_D( Connection );
  183. d->name = n;
  184. }
  185. QString
  186. Connection::name() const
  187. {
  188. Q_D( const Connection );
  189. return d->name;
  190. }
  191. void
  192. Connection::setOnceOnly( bool b )
  193. {
  194. Q_D( Connection );
  195. d->onceonly = b;
  196. }
  197. bool
  198. Connection::onceOnly() const
  199. {
  200. Q_D( const Connection );
  201. return d->onceonly;
  202. }
  203. bool
  204. Connection::isReady() const
  205. {
  206. Q_D( const Connection );
  207. return d->ready;
  208. }
  209. bool
  210. Connection::isRunning() const
  211. {
  212. Q_D( const Connection );
  213. return d->sock != 0;
  214. }
  215. qint64
  216. Connection::bytesSent() const
  217. {
  218. return d_func()->tx_bytes;
  219. }
  220. qint64
  221. Connection::bytesReceived() const
  222. {
  223. return d_func()->rx_bytes;
  224. }
  225. void
  226. Connection::setMsgProcessorModeOut(quint32 m)
  227. {
  228. d_func()->msgprocessor_out.setMode( m );
  229. }
  230. void
  231. Connection::setMsgProcessorModeIn(quint32 m)
  232. {
  233. d_func()->msgprocessor_in.setMode( m );
  234. }
  235. const QHostAddress
  236. Connection::peerIpAddress() const
  237. {
  238. return d_func()->peerIpAddress;
  239. }
  240. void
  241. Connection::start( QTcpSocket* sock )
  242. {
  243. Q_D( Connection );
  244. Q_ASSERT( d->sock.isNull() );
  245. Q_ASSERT( sock );
  246. Q_ASSERT( sock->isValid() );
  247. d->sock = sock;
  248. if ( d->name.isEmpty() )
  249. {
  250. d->name = QString( "peer[%1]" ).arg( d->sock->peerAddress().toString() );
  251. }
  252. QTimer::singleShot( 0, this, SLOT( checkACL() ) );
  253. }
  254. void
  255. Connection::checkACL()
  256. {
  257. Q_D( Connection );
  258. QReadLocker nodeidLocker( &d->nodeidLock );
  259. if ( d->nodeid.isEmpty() )
  260. {
  261. tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "Not checking ACL, nodeid is empty";
  262. QTimer::singleShot( 0, this, SLOT( doSetup() ) );
  263. emit authSuccessful();
  264. return;
  265. }
  266. if ( Servent::isIPWhitelisted( d_func()->peerIpAddress ) )
  267. {
  268. QTimer::singleShot( 0, this, SLOT( doSetup() ) );
  269. emit authSuccessful();
  270. return;
  271. }
  272. tLog( LOGVERBOSE ) << Q_FUNC_INFO << "Checking ACL for" << name();
  273. d->aclRequest = Tomahawk::Network::ACL::aclrequest_ptr(
  274. new Tomahawk::Network::ACL::AclRequest( d->nodeid, bareName(), Tomahawk::ACLStatus::NotFound ),
  275. &QObject::deleteLater );
  276. connect( d->aclRequest.data(), SIGNAL( decision( Tomahawk::ACLStatus::Type ) ), SLOT( aclDecision( Tomahawk::ACLStatus::Type ) ), Qt::QueuedConnection );
  277. ACLRegistry::instance()->isAuthorizedRequest( d->aclRequest );
  278. }
  279. QString
  280. Connection::bareName() const
  281. {
  282. return name().contains( '/' ) ? name().left( name().indexOf( "/" ) ) : name();
  283. }
  284. void
  285. Connection::aclDecision( Tomahawk::ACLStatus::Type status )
  286. {
  287. Q_D( Connection );
  288. tLog( LOGVERBOSE ) << Q_FUNC_INFO << "ACL decision for" << name() << ":" << status;
  289. // We have a decision, free memory.
  290. d->aclRequest.clear();
  291. if ( status == Tomahawk::ACLStatus::Stream )
  292. {
  293. QTimer::singleShot( 0, this, SLOT( doSetup() ) );
  294. emit authSuccessful();
  295. return;
  296. }
  297. emit authFailed();
  298. shutdown();
  299. }
  300. void
  301. Connection::authCheckTimeout()
  302. {
  303. Q_D( Connection );
  304. if ( d->ready )
  305. return;
  306. emit authTimeout();
  307. tDebug( LOGVERBOSE ) << "Closing connection, not authed in time.";
  308. shutdown();
  309. }
  310. void
  311. Connection::doSetup()
  312. {
  313. Q_D( Connection );
  314. tDebug( LOGVERBOSE ) << Q_FUNC_INFO << thread() << d->id;
  315. /*
  316. New connections can be created from other thread contexts, such as
  317. when AudioEngine calls getIODevice.. - we need to ensure that connections
  318. and their associated sockets are running in the same thread as the servent.
  319. HINT: export QT_FATAL_WARNINGS=1 helps to catch these kind of errors.
  320. */
  321. if ( QThread::currentThread() != d->servent->thread() )
  322. {
  323. // Connections should always be in the same thread as the servent.
  324. moveToThread( d->servent->thread() );
  325. }
  326. if ( !d->setup )
  327. {
  328. // We only want to setup this connection once
  329. d->setup = true;
  330. //stats timer calculates BW used by this connection
  331. d->statstimer = new QTimer;
  332. d->statstimer->moveToThread( this->thread() );
  333. d->statstimer->setInterval( 1000 );
  334. connect( d->statstimer, SIGNAL( timeout() ), SLOT( calcStats() ) );
  335. d->statstimer->start();
  336. d->statstimer_mark.start();
  337. d->sock->moveToThread( thread() );
  338. connect( d->sock.data(), SIGNAL( bytesWritten( qint64 ) ),
  339. SLOT( bytesWritten( qint64 ) ), Qt::QueuedConnection );
  340. connect( d->sock.data(), SIGNAL( disconnected() ),
  341. SLOT( socketDisconnected() ), Qt::QueuedConnection );
  342. connect( d->sock.data(), SIGNAL( error( QAbstractSocket::SocketError ) ),
  343. SLOT( socketDisconnectedError( QAbstractSocket::SocketError ) ), Qt::QueuedConnection );
  344. connect( d->sock.data(), SIGNAL( readyRead() ),
  345. SLOT( readyRead() ), Qt::QueuedConnection );
  346. // if connection not authed/setup fast enough, kill it:
  347. QTimer::singleShot( AUTH_TIMEOUT, this, SLOT( authCheckTimeout() ) );
  348. if ( outbound() )
  349. {
  350. Q_ASSERT( !d->firstmsg.isNull() );
  351. sendMsg( d->firstmsg );
  352. }
  353. else
  354. {
  355. sendMsg( Msg::factory( PROTOVER, Msg::SETUP ) );
  356. }
  357. }
  358. else
  359. {
  360. tLog() << Q_FUNC_INFO << QThread::currentThread() << d->id << "Duplicate doSetup call";
  361. }
  362. // call readyRead incase we missed the signal in between the servent disconnecting and us
  363. // connecting to the signal - won't do anything if there are no bytesAvailable anyway.
  364. readyRead();
  365. }
  366. void
  367. Connection::socketDisconnected()
  368. {
  369. Q_D( Connection );
  370. qint64 bytesAvailable = 0;
  371. if ( !d->sock.isNull() )
  372. {
  373. bytesAvailable = d->sock->bytesAvailable();
  374. }
  375. tDebug( LOGVERBOSE ) << "SOCKET DISCONNECTED" << this->name() << id()
  376. << "shutdown will happen after incoming queue empties."
  377. << "bytesavail:" << bytesAvailable
  378. << "bytesRecvd" << bytesReceived();
  379. d->peer_disconnected = true;
  380. emit socketClosed();
  381. if ( d->msgprocessor_in.length() == 0 && bytesAvailable == 0 )
  382. {
  383. handleIncomingQueueEmpty();
  384. actualShutdown();
  385. }
  386. }
  387. void
  388. Connection::socketDisconnectedError( QAbstractSocket::SocketError e )
  389. {
  390. tDebug() << "SOCKET ERROR CODE" << e << this->name() << "CALLING Connection::shutdown(false)";
  391. if ( e == QAbstractSocket::RemoteHostClosedError )
  392. return;
  393. d_func()->peer_disconnected = true;
  394. emit socketErrored(e);
  395. emit socketClosed();
  396. shutdown( false );
  397. }
  398. QString
  399. Connection::id() const
  400. {
  401. return d_func()->id;
  402. }
  403. void
  404. Connection::setId( const QString& id )
  405. {
  406. d_func()->id = id;
  407. }
  408. QString
  409. Connection::nodeId() const
  410. {
  411. Q_D( const Connection );
  412. QReadLocker locker( &d->nodeidLock );
  413. return d->nodeid;
  414. }
  415. void
  416. Connection::setNodeId( const QString& nodeid )
  417. {
  418. Q_D( Connection );
  419. QWriteLocker locker( &d->nodeidLock );
  420. d->nodeid = nodeid;
  421. }
  422. void
  423. Connection::readyRead()
  424. {
  425. // qDebug() << "readyRead, bytesavail:" << m_sock->bytesAvailable();
  426. Q_D( Connection );
  427. if ( d->msg.isNull() )
  428. {
  429. if ( d->sock->bytesAvailable() < Msg::headerSize() )
  430. return;
  431. char msgheader[ Msg::headerSize() ];
  432. if ( d->sock->read( (char*) &msgheader, Msg::headerSize() ) != Msg::headerSize() )
  433. {
  434. tDebug() << "Failed reading msg header";
  435. this->markAsFailed();
  436. return;
  437. }
  438. d->msg = Msg::begin( (char*) &msgheader );
  439. d->rx_bytes += Msg::headerSize();
  440. }
  441. if ( d->sock->bytesAvailable() < d->msg->length() )
  442. return;
  443. QByteArray ba = d->sock->read( d->msg->length() );
  444. if ( ba.length() != (qint32)d->msg->length() )
  445. {
  446. tDebug() << "Failed to read full msg payload";
  447. this->markAsFailed();
  448. return;
  449. }
  450. d->msg->fill( ba );
  451. d->rx_bytes += ba.length();
  452. handleReadMsg(); // process m_msg and clear() it
  453. // since there is no explicit threading, use the event loop to schedule this:
  454. if ( d->sock->bytesAvailable() )
  455. {
  456. QTimer::singleShot( 0, this, SLOT( readyRead() ) );
  457. }
  458. }
  459. void
  460. Connection::handleReadMsg()
  461. {
  462. Q_D( Connection );
  463. if ( outbound() == false &&
  464. d->msg->is( Msg::SETUP ) &&
  465. d->msg->payload() == "ok" )
  466. {
  467. d->ready = true;
  468. tDebug( LOGVERBOSE ) << "Connection" << id() << "READY";
  469. setup();
  470. emit ready();
  471. }
  472. else if ( !d->ready &&
  473. outbound() &&
  474. d->msg->is( Msg::SETUP ) )
  475. {
  476. if ( d->msg->payload() == PROTOVER )
  477. {
  478. sendMsg( Msg::factory( "ok", Msg::SETUP ) );
  479. d->ready = true;
  480. tDebug( LOGVERBOSE ) << "Connection" << id() << "READY";
  481. setup();
  482. emit ready();
  483. }
  484. else
  485. {
  486. sendMsg( Msg::factory( "{\"method\":\"protovercheckfail\"}", Msg::JSON | Msg::SETUP ) );
  487. shutdown( true );
  488. }
  489. }
  490. else
  491. {
  492. d->msgprocessor_in.append( d->msg );
  493. }
  494. d->msg.clear();
  495. }
  496. void
  497. Connection::sendMsg( QVariant j )
  498. {
  499. Q_D( Connection );
  500. if ( d->do_shutdown )
  501. return;
  502. const QByteArray payload = TomahawkUtils::toJson( j );
  503. tLog( LOGVERBOSE ) << Q_FUNC_INFO << "Sending to" << id() << ":" << payload;
  504. sendMsg( Msg::factory( payload, Msg::JSON ) );
  505. }
  506. void
  507. Connection::sendMsg( msg_ptr msg )
  508. {
  509. if ( d_func()->do_shutdown )
  510. {
  511. tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "SHUTTING DOWN, NOT SENDING msg flags:"
  512. << (int)msg->flags() << "length:" << msg->length() << id();
  513. return;
  514. }
  515. d_func()->tx_bytes_requested += msg->length() + Msg::headerSize();
  516. d_func()->msgprocessor_out.append( msg );
  517. }
  518. void
  519. Connection::sendMsg_now( msg_ptr msg )
  520. {
  521. Q_D( Connection );
  522. Q_ASSERT( QThread::currentThread() == thread() );
  523. // Q_ASSERT( this->isRunning() );
  524. if ( d->sock.isNull() || !d->sock->isOpen() || !d->sock->isWritable() )
  525. {
  526. tDebug() << "***** Socket problem, whilst in sendMsg(). Cleaning up. *****";
  527. shutdown( false );
  528. return;
  529. }
  530. if ( !msg->write( d->sock.data() ) )
  531. {
  532. //qDebug() << "Error writing to socket in sendMsg() *************";
  533. shutdown( false );
  534. return;
  535. }
  536. }
  537. void
  538. Connection::bytesWritten( qint64 i )
  539. {
  540. d_func()->tx_bytes += i;
  541. // if we are waiting to shutdown, and have sent all queued data, do actual shutdown:
  542. if ( d_func()->do_shutdown && d_func()->tx_bytes == d_func()->tx_bytes_requested )
  543. actualShutdown();
  544. }
  545. void
  546. Connection::calcStats()
  547. {
  548. Q_D( Connection );
  549. int elapsed = d->statstimer_mark.restart(); // ms since last calc
  550. d->stats_tx_bytes_per_sec = (float)1000 * ( (d->tx_bytes - d->tx_bytes_last) / (float)elapsed );
  551. d->stats_rx_bytes_per_sec = (float)1000 * ( (d->rx_bytes - d->rx_bytes_last) / (float)elapsed );
  552. d->rx_bytes_last = d->rx_bytes;
  553. d->tx_bytes_last = d->tx_bytes;
  554. emit statsTick( d->stats_tx_bytes_per_sec, d->stats_rx_bytes_per_sec );
  555. }