PageRenderTime 290ms CodeModel.GetById 55ms RepoModel.GetById 1ms app.codeStats 0ms

/src/core/CoreConnection.cpp

https://gitlab.com/cnchyan/beebeep
C++ | 363 lines | 289 code | 49 blank | 25 comment | 67 complexity | 89d91883c98cac55056a964860c56531 MD5 | raw file
  1. //////////////////////////////////////////////////////////////////////
  2. //
  3. // This file is part of BeeBEEP.
  4. //
  5. // BeeBEEP is free software: you can redistribute it and/or modify
  6. // it under the terms of the GNU General Public License as published
  7. // by the Free Software Foundation, either version 3 of the License,
  8. // or (at your option) any later version.
  9. //
  10. // BeeBEEP is distributed in the hope that it will be useful,
  11. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. // GNU General Public License for more details.
  14. //
  15. // You should have received a copy of the GNU General Public License
  16. // along with BeeBEEP. If not, see <http://www.gnu.org/licenses/>.
  17. //
  18. // Author: Marco Mastroddi <marco.mastroddi(AT)gmail.com>
  19. //
  20. // $Id$
  21. //
  22. //////////////////////////////////////////////////////////////////////
  23. #include "Avatar.h"
  24. #include "BeeUtils.h"
  25. #include "ChatManager.h"
  26. #include "ColorManager.h"
  27. #include "Connection.h"
  28. #include "Core.h"
  29. #include "FileShare.h"
  30. #include "NetworkManager.h"
  31. #include "Protocol.h"
  32. #include "Settings.h"
  33. #include "UserManager.h"
  34. Connection* Core::connection( VNumber user_id ) const
  35. {
  36. QList<Connection*>::const_iterator it = m_connections.begin();
  37. while( it != m_connections.end() )
  38. {
  39. if( (*it)->userId() == user_id )
  40. return *it;
  41. ++it;
  42. }
  43. return 0;
  44. }
  45. bool Core::hasConnection( const QHostAddress& sender_ip, int sender_port ) const
  46. {
  47. QList<Connection*>::const_iterator it = m_connections.begin();
  48. while( it != m_connections.end() )
  49. {
  50. if( (sender_port == -1 || (*it)->peerPort() == sender_port) && (*it)->peerAddress() == sender_ip )
  51. {
  52. if( (*it)->isConnected() || (*it)->isConnecting() )
  53. {
  54. #ifdef BEEBEEP_DEBUG
  55. qDebug() << "Connection from" << sender_ip.toString() << sender_port << "is already open";
  56. #endif
  57. return true;
  58. }
  59. }
  60. ++it;
  61. }
  62. User u = UserManager::instance().findUserByHostAddressAndPort( sender_ip, sender_port );
  63. if( u.isValid() && isUserConnected( u.id() ) )
  64. {
  65. #ifdef BEEBEEP_DEBUG
  66. qDebug() << "User from" << sender_ip.toString() << sender_port << "is already connected";
  67. #endif
  68. return true;
  69. }
  70. return false;
  71. }
  72. void Core::checkUserRecord( const UserRecord& ur )
  73. {
  74. if( ur.hostAddress() == Settings::instance().localUser().hostAddress() &&
  75. ur.hostPort() == Settings::instance().localUser().hostPort() )
  76. {
  77. #ifdef BEEBEEP_DEBUG
  78. qDebug() << "Skip local user record" << ur.hostAddressAndPort();
  79. #endif
  80. return;
  81. }
  82. newPeerFound( ur.hostAddress(), ur.hostPort() );
  83. }
  84. void Core::newPeerFound( const QHostAddress& sender_ip, int sender_port )
  85. {
  86. if( hasConnection( sender_ip, sender_port ) )
  87. return;
  88. qDebug() << "Connecting to new peer" << qPrintable( sender_ip.toString() ) << sender_port;
  89. Connection *c = new Connection( this );
  90. setupNewConnection( c );
  91. c->connectToNetworkAddress( sender_ip, sender_port );
  92. }
  93. void Core::checkNewConnection( Connection *c )
  94. {
  95. // Has connection never return true because peer port is always different.
  96. // It comes from Listener. If I want to prevent multiple users from single
  97. // ip, I can pass -1 to peer_port and check only host address
  98. qDebug() << "New connection from" << qPrintable( c->hostAndPort() );
  99. if( Settings::instance().preventMultipleConnectionsFromSingleHostAddress() )
  100. {
  101. if( hasConnection( c->peerAddress(), -1 ) )
  102. {
  103. #ifdef BEEBEEP_DEBUG
  104. qDebug() << c->peerAddress().toString() << "is already connected and blocked by prevent multiple connections";
  105. #endif
  106. closeConnection( c );
  107. return;
  108. }
  109. }
  110. setupNewConnection( c );
  111. }
  112. void Core::setupNewConnection( Connection *c )
  113. {
  114. #ifdef BEEBEEP_DEBUG
  115. if( !c->peerAddress().isNull() )
  116. qDebug() << "Connecting SIGNAL/SLOT to connection from" << qPrintable( c->hostAndPort() );
  117. #endif
  118. connect( c, SIGNAL( error( QAbstractSocket::SocketError ) ), this, SLOT( setConnectionError( QAbstractSocket::SocketError ) ) );
  119. connect( c, SIGNAL( disconnected() ), this, SLOT( setConnectionClosed() ) );
  120. connect( c, SIGNAL( abortRequest() ), this, SLOT( setConnectionClosed() ) );
  121. connect( c, SIGNAL( authenticationRequested( const Message& ) ), this, SLOT( checkUserAuthentication( const Message& ) ) );
  122. }
  123. void Core::addConnectionReadyForUse( Connection* c )
  124. {
  125. #ifdef BEEBEEP_DEBUG
  126. qDebug() << "Connection from" << qPrintable( c->hostAndPort() ) << "is ready for use";
  127. #endif
  128. connect( c, SIGNAL( newMessage( VNumber, const Message& ) ), this, SLOT( parseMessage( VNumber, const Message& ) ) );
  129. m_connections.append( c );
  130. }
  131. void Core::setConnectionError( QAbstractSocket::SocketError se )
  132. {
  133. Connection* c = qobject_cast<Connection*>( sender() );
  134. if( c )
  135. {
  136. if( c->userId() != ID_INVALID )
  137. {
  138. qWarning() << "Connection from" << qPrintable( c->hostAndPort() ) << "has an error:" << c->errorString() << "-" << (int)se;
  139. }
  140. else
  141. {
  142. if( !c->peerAddress().isNull() )
  143. qWarning() << "Connection from" << qPrintable( c->hostAndPort() ) << "has refused connection:" << c->errorString() << "-" << (int)se;
  144. }
  145. closeConnection( c );
  146. }
  147. else
  148. qWarning() << "Connection error" << se << "occurred but the object caller is invalid";
  149. }
  150. void Core::setConnectionClosed()
  151. {
  152. Connection* c = qobject_cast<Connection*>( sender() );
  153. if( c )
  154. closeConnection( c );
  155. else
  156. qWarning() << "Connection closed but the object caller is invalid";
  157. }
  158. void Core::closeConnection( Connection *c )
  159. {
  160. int number_of_connection_pointers = m_connections.removeAll( c );
  161. #ifdef BEEBEEP_DEBUG
  162. if( !c->peerAddress().isNull() )
  163. {
  164. if( number_of_connection_pointers <= 0 )
  165. qDebug() << "Connection pointer is not present (or already removed from list)";
  166. else if( number_of_connection_pointers != 1 )
  167. qDebug() << number_of_connection_pointers << "pointers of a single connection found in connection list";
  168. else
  169. qDebug() << "Connection pointer removed from connection list";
  170. }
  171. #else
  172. if( number_of_connection_pointers > 1 )
  173. qWarning() << number_of_connection_pointers << "similar connections found in list and removed";
  174. #endif
  175. if( c->userId() != ID_INVALID )
  176. {
  177. User u = UserManager::instance().findUser( c->userId() );
  178. if( u.isValid() )
  179. {
  180. qDebug() << "User" << u.path() << "goes offline";
  181. u.setStatus( User::Offline );
  182. UserManager::instance().setUser( u );
  183. showUserStatusChanged( u );
  184. userConnectionStatusChanged( u );
  185. Chat default_chat = ChatManager::instance().defaultChat();
  186. if( default_chat.removeUser( u.id() ) )
  187. ChatManager::instance().setChat( default_chat );
  188. FileShare::instance().removeFromNetwork( c->userId() );
  189. if( u.isValid() )
  190. emit fileShareAvailable( u );
  191. QString sHtmlMsg = QString( "%1 " ).arg( Bee::iconToHtml( ":/images/network-disconnected.png", "*C*" ) );
  192. sHtmlMsg += tr( "%1 (%2) is disconnected from %3 network." ).arg( u.name(), u.accountPath(), Settings::instance().programName() );
  193. dispatchSystemMessage( ID_DEFAULT_CHAT, u.id(), sHtmlMsg, DispatchToChat, ChatMessage::UserInfo );
  194. }
  195. else
  196. qWarning() << "User" << c->userId() << "not found while closing connection";
  197. }
  198. c->disconnect();
  199. c->abortConnection();
  200. c->deleteLater();
  201. if( isConnected() && m_connections.isEmpty() )
  202. QTimer::singleShot( 0, this, SLOT( checkNetworkInterface() ) );
  203. }
  204. void Core::checkUserAuthentication( const Message& m )
  205. {
  206. Connection* c = qobject_cast<Connection*>( sender() );
  207. if( !c )
  208. {
  209. qWarning() << "Unable to check authentication for an invalid connection object";
  210. return;
  211. }
  212. QString sHtmlMsg;
  213. User u = Protocol::instance().createUser( m, c->peerAddress() );
  214. if( !u.isValid() )
  215. {
  216. qWarning() << "Unable to create a new user (invalid protocol or password) from the message arrived from:" << qPrintable( c->hostAndPort() );
  217. closeConnection( c );
  218. return;
  219. }
  220. else
  221. qDebug() << u.path() << "has completed the authentication";
  222. bool user_path_changed = false;
  223. User user_found = UserManager::instance().findUserBySessionId( u.sessionId() );
  224. if( !user_found.isValid() )
  225. {
  226. if( Settings::instance().trustSystemAccount() )
  227. {
  228. user_found = UserManager::instance().findUserByAccountName( u.accountName() );
  229. if( user_found.isValid() )
  230. qDebug() << "User found in list with account name:" << u.accountName();
  231. }
  232. else
  233. {
  234. user_found = UserManager::instance().findUserByPath( u.path() );
  235. if( user_found.isValid() )
  236. qDebug() << "User found in list with path:" << u.path();
  237. }
  238. }
  239. if( user_found.isValid() )
  240. {
  241. if( user_found.isLocal() )
  242. {
  243. qDebug() << "User with account" << u.accountName() << "and path" << u.path() << "is recognized to be Local";
  244. closeConnection( c );
  245. return;
  246. }
  247. if( isUserConnected( user_found.id() ) )
  248. {
  249. qDebug() << "User with account" << u.accountName() << "and path" << u.path() << "is already connected with account name" << user_found.accountName() << "path" << user_found.path();
  250. closeConnection( c );
  251. return;
  252. }
  253. if( u.path() != user_found.path() )
  254. {
  255. user_path_changed = true;
  256. qDebug() << "On connection old user found" << user_found.path() << "and associated to" << u.path();
  257. }
  258. else
  259. qDebug() << "User" << u.path() << "reconnected";
  260. u.setId( user_found.id() );
  261. u.setIsFavorite( user_found.isFavorite() );
  262. }
  263. else
  264. {
  265. qDebug() << "New user is connected from" << u.path();
  266. }
  267. #if QT_VERSION < 0x040700
  268. if( u.color() == QString( "#000000" ) || !QColor( u.color() ).isValid() )
  269. #else
  270. if( u.color() == QString( "#000000" ) || !QColor::isValidColor( u.color() ) )
  271. #endif
  272. {
  273. if( user_found.isValid() && user_found.color() != QString( "#000000" ) )
  274. u.setColor( user_found.color() );
  275. else
  276. u.setColor( ColorManager::instance().unselectedQString() );
  277. }
  278. u.setProtocolVersion( c->protoVersion() );
  279. UserManager::instance().setUser( u );
  280. qDebug() << "User" << u.path() << "added with id" << u.id() << "and color" << u.color();
  281. Chat default_chat = ChatManager::instance().defaultChat();
  282. if( default_chat.addUser( u.id() ) )
  283. {
  284. qDebug() << "Adding user" << u.path() << "to default chat";
  285. ChatManager::instance().setChat( default_chat );
  286. }
  287. if( !ChatManager::instance().privateChatForUser( u.id() ).isValid() )
  288. createPrivateChat( u );
  289. c->setReadyForUse( u.id() );
  290. addConnectionReadyForUse( c );
  291. if( user_path_changed )
  292. ChatManager::instance().changePrivateChatNameAfterUserNameChanged( user_found.id(), u.path() );
  293. sHtmlMsg = QString( "%1 " ).arg( Bee::iconToHtml( ":/images/network-connected.png", "*C*" ) );
  294. sHtmlMsg += tr( "%1 (%2) is connected to %3 network." ).arg( u.name(), u.accountPath(), Settings::instance().programName() );
  295. dispatchSystemMessage( ID_DEFAULT_CHAT, u.id(), sHtmlMsg, DispatchToChat, ChatMessage::UserInfo );
  296. showUserStatusChanged( u );
  297. emit userConnectionStatusChanged( u );
  298. if( !Settings::instance().localUser().vCard().hasOnlyNickName() )
  299. {
  300. if( c->protoVersion() > 1 )
  301. {
  302. #ifdef BEEBEEP_DEBUG
  303. qDebug() << "Sending my VCard to" << u.path();
  304. #endif
  305. c->sendData( Protocol::instance().localVCardMessage() );
  306. }
  307. }
  308. if( user_found.isValid() )
  309. checkGroupChatAfterUserReconnect( u );
  310. checkUserHostAddress( u );
  311. checkOfflineMessagesForUser( u );
  312. if( Settings::instance().useHive() && u.protocolVersion() >= HIVE_PROTO_VERSION )
  313. sendLocalConnectedUsersTo( u );
  314. }