LocalPeer.cpp

Go to the documentation of this file.
00001 /*
00002 
00003 Copyright (C) 2005-2007 by Peter Dimov.
00004 
00005 This file is part of Calitko (http://www.calitko.org).
00006 
00007 Calitko is free software; you can redistribute it and/or modify
00008 it under the terms of the GNU General Public License as published by
00009 the Free Software Foundation; either version 2 of the License, or
00010 (at your option) any later version.
00011 
00012 Calitko is distributed in the hope that it will be useful,
00013 but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 GNU General Public License for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Calitko; if not, write to the Free Software
00019 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00020 
00021 */
00022 
00023 #include "Qt.h"
00024 #include "LocalPeer.h"
00025 #include "Http/Header.h"
00026 #include "Gnutella/Bootstrapping/ConnectionKeeper.h"
00027 #include "Gnutella/Bootstrapping/NodeCache.h"
00028 #include "Gnutella/Bootstrapping/PingHandler.h"
00029 #include "Gnutella/Bootstrapping/PongHandler.h"
00030 #include "Gnutella/Bootstrapping/UdpHostCache.h"
00031 #include "Protocols/Transports/TcpConnection.h"
00032 #include "Protocols/Transports/UdpConnection.h"
00033 #include "Protocols/Transports/UdpSwitch.h"
00034 #include "Gnutella/Handshaking/Handshaker.h"
00035 #include "Gnutella/Handshaking/SlotAllocator.h"
00036 #include "Gnutella/PacketProcessing/PacketProcessor.h"
00037 #include "Gnutella/PacketProcessing/PongCache.h"
00038 #include "Gnutella/Packets/Extensions/Ggeps/DailyUptime.h"
00039 #include "Gnutella/Packets/Query.h"
00040 #include "Gnutella/Searching/LocalSearch.h"
00041 #include "Gnutella/Searching/Searcher.h"
00042 #include "UIs/NodeModel.h"
00043 #include "PacketModel.h"
00044 #include "UIs/Searching/SearchModel.h"
00045 
00046 using Gnutella::LocalPeer;
00047 using Gnutella::LocalPeerPrivate;
00048 using Gnutella::NodeInfo;
00049 using Gnutella::Bootstrapping::ConnectionKeeper;
00050 using Gnutella::Bootstrapping::NodeCache;
00051 using Gnutella::Bootstrapping::PingHandler;
00052 using Gnutella::Bootstrapping::PongHandler;
00053 using Gnutella::Bootstrapping::UdpHostCache;
00054 using Protocols::Transports::Connection;
00055 using Protocols::Transports::TcpConnection;
00056 using Protocols::Transports::UdpConnection;
00057 using Protocols::Transports::UdpSwitch;
00058 using Gnutella::Handshaking::HandshakeError;
00059 using Gnutella::Handshaking::Handshaker;
00060 using Gnutella::Handshaking::SlotAllocator;
00061 using Gnutella::PacketProcessing::PacketProcessor;
00062 using Gnutella::Searching::LocalSearch;
00063 using Gnutella::Searching::Searcher;
00064 using UIs::Searching::SearchModel;
00065 
00066 
00067 // \todo that should be superfluos now - p is initialized correctly in the
00068 // initialization list of the LocalPeer ctor.
00069 class Gnutella::Workaround {
00070 public:
00071     Workaround (LocalPeer *lp, LocalPeerPrivate *p)
00072     { lp->p = p; }
00073 };
00074 
00075 class LocalPeerPrivate
00076 {
00077 public:
00078     Workaround                  workaround; // \todo avoid!
00079     NodeCache                   nodeCache;
00080     UdpHostCache                udpHostCache;
00081     Handshaker                  handshaker;
00082     ConnectionKeeper            connectionKeeper;
00083     SlotAllocator               slotAllocator;
00084     LocalSearch                 localSearch;
00085     Searcher                    searcher;
00086     PacketProcessor             packetProcessor;
00087     PingHandler                 pingHandler;
00088     PongHandler                 pongHandler;
00089 
00090     NodeInfo                    nodeInfo;
00091     bool                        serverIsFirewalled;
00092 
00093     QTcpServer                  server;
00094     UdpSwitch                   udpSwitch;
00095 
00096     NodeModel                   nodeModel;
00097     PacketModel                 packetModel;
00098 
00099     LocalPeerPrivate (LocalPeer *localPeer)
00100       : workaround (localPeer, this),
00101         nodeCache(),
00102         udpHostCache (&udpSwitch, &pingHandler),
00103         handshaker (localPeer, &nodeCache, &slotAllocator),
00104         connectionKeeper (localPeer),
00105         slotAllocator (localPeer),
00106         localSearch (localPeer, &packetProcessor),
00107         searcher (localPeer),
00108         packetProcessor (localPeer),
00109         pingHandler (localPeer),
00110         pongHandler (localPeer),
00111         nodeInfo(),
00112         serverIsFirewalled (false),
00113         server(),
00114         udpSwitch(),
00115         nodeModel(),
00116         packetModel()
00117     {
00118         nodeInfo.type = Gnutella::TypeUltrapeer;
00119         //nodeInfo.type = Gnutella::TypeLeaf;
00120 
00121         qRegisterMetaType <qint64> ("qint64"); // \todo maybe move elsewhere - needed by handshake/packet wirters
00122     }
00123 };
00124 
00125 LocalPeer::LocalPeer()
00126  : p (new LocalPeerPrivate (this))
00127 {
00128     connect (&p->slotAllocator, SIGNAL (handshakingSlotFreed()),
00129              &p->connectionKeeper, SLOT (keepConnection()));
00130     connect (&p->slotAllocator, SIGNAL (ultrapeerSlotFreed()),
00131              &p->connectionKeeper, SLOT (keepConnection()));
00132     connect (&p->slotAllocator, SIGNAL (peerSlotFreed()),
00133              &p->connectionKeeper, SLOT (keepConnection()));
00134     connect (&p->packetProcessor, SIGNAL (receivedPong (const Pong &)),
00135              &p->pongHandler, SLOT (processPong (const Pong &)));
00136     connect (&p->packetProcessor, SIGNAL (receivedQueryHits (const QueryHits &)),
00137              &p->searcher, SLOT (processQueryHits (const QueryHits &)));
00138     connect (&p->packetProcessor, SIGNAL (processQueryStatusRequest (const QueryStatusRequest &)),
00139              &p->searcher, SLOT (processQueryStatusRequest (const QueryStatusRequest &)));
00140     connect (&p->udpHostCache, SIGNAL (receivedPong (const Pong &)),
00141              &p->pongHandler, SLOT (processPong (const Pong &)));
00142     connect (&p->udpSwitch, SIGNAL (connectionAccepted (UdpConnection *)),
00143              &p->udpHostCache, SLOT (connectionAcceptedSlot (UdpConnection *)));
00144     connect (&p->handshaker, SIGNAL (handshakingStarted (Connection *)),
00145              &p->nodeModel, SLOT (setHandshaking (Connection *)));
00146     connect (&p->handshaker, SIGNAL (handshakingCompleted (Connection *, NodeInfo)),
00147              &p->nodeModel, SLOT (setConnected (Connection *, NodeInfo)));
00148     connect (&p->handshaker, SIGNAL (handshakingCompleted (Connection *, NodeInfo)),
00149              &p->packetProcessor, SLOT (addConnection (Connection *, NodeInfo)));
00150 }
00151 
00152 LocalPeer::~LocalPeer()
00153 {
00154     disconnectFromNetwork();
00155     delete p;
00156 }
00157 
00158 bool LocalPeer::isUltrapeer() const
00159 { return p->nodeInfo.type == TypeUltrapeer; }
00160 
00161 QHostAddress LocalPeer::serverIpAddress() const
00162 { return p->nodeInfo.address.hostAddress(); }
00163 
00164 quint16 LocalPeer::serverPort() const
00165 { return p->nodeInfo.address.hostPort(); }
00166 
00167 const NodeInfo & LocalPeer::nodeInfo() const
00168 { return p->nodeInfo; }
00169 
00170 UdpHostCache * LocalPeer::udpHostCache()
00171 { return &p->udpHostCache; }
00172 
00173 SlotAllocator * LocalPeer::slotAllocator()
00174 { return &p->slotAllocator; }
00175 
00176 NodeCache * LocalPeer::nodeCache()
00177 { return &p->nodeCache; }
00178 
00179 PacketProcessor * LocalPeer::packetProcessor()
00180 { return &p->packetProcessor; }
00181 
00182 Searcher* LocalPeer::searcher()
00183 { return &p->searcher; }
00184 
00185 QAbstractItemModel * LocalPeer::nodeModel()
00186 { return &p->nodeModel; }
00187 
00188 QAbstractItemModel * LocalPeer::packetModel()
00189 { return &p->packetModel; }
00190 
00191 bool LocalPeer::connectToNetwork()
00192 {
00193     // <pd_todo> Add error notifications (maybe signals?)
00194     if (p->nodeInfo.address.hostPort() == 0)
00195         return false;
00196 
00197     connect (&p->server, SIGNAL(newConnection()), this, SLOT(newConnection()));
00198     if (!p->server.listen (QHostAddress::Any, p->nodeInfo.address.hostPort()))
00199         return false;
00200 
00201     setServerIpAddress (p->server.serverAddress());
00202 
00203     // If the second argument is true, and the signal udpSwitch::connectionAccepted()
00204     // is not connected, some resources would be leaked.
00205     p->udpSwitch.start (NodeAddress (QHostAddress::Any, p->nodeInfo.address.hostPort()), true);
00206 
00207     p->nodeCache.loadNodes (tr ("hosts.dat"));
00208 
00209     p->connectionKeeper.bootstrap();
00210     return true;
00211 }
00212 
00213 void LocalPeer::setServerIpAddress (const QHostAddress &ipAddress)
00214 {
00215     // \todo How to determine our firewall status?
00216     // \todo Whould we chech whether we are connecteed before updating the pongCache?
00217     p->nodeInfo.address.setHostAddress (ipAddress);
00218     /*if (!serverIsFirewalled)
00219         pongCache.setHostAddress (serverIpAddress);
00220     else
00221         pongCache.setHostAddress (QHostAddress::Null);
00222     */
00223 }
00224 
00225 void LocalPeer::setServerPort (quint16 port)
00226 {
00227     // \todo Whould we chech whether we are connecteed before updating the pongCache?
00228     p->nodeInfo.address.setHostPort (port);
00229     /*if (!serverIsFirewalled)
00230         pongCache.setHostPort (serverPort);
00231     else
00232         pongCache.setHostPort (0);
00233     */
00234 }
00235 
00236 bool LocalPeer::disconnectFromNetwork()
00237 {
00238     p->nodeCache.storeNodes (tr ("hosts.dat"));
00239     // \todo Delegate to handshaker and packetProcessor
00240     return true;
00241 }
00242 
00243 void LocalPeer::connectToPeer (const QString &hostName, quint16 port)
00244 {
00245     qDebug() << "Connecting to " << hostName << ":" << port;
00246 
00247     TcpConnection *connection = new TcpConnection;
00248     NodeAddress nodeAddress = NodeAddress (hostName, port);
00249     p->nodeModel.nodeConnecting (connection, nodeAddress);
00250     p->handshaker.requestConnection (connection, nodeAddress);
00251 }
00252 
00253 void LocalPeer::disconnectFromPeer (Connection *connection)
00254 {
00255     connection->disconnectFromNode();
00256 }
00257 
00258 void LocalPeer::newConnection()
00259 {
00260     QTcpSocket *socket = p->server.nextPendingConnection();
00261     qDebug() << "Accepting connection from " << socket->peerAddress().toString() << ":" << socket->peerPort();
00262     // \todo Peek some data to make sure whether this is a handshake or transfer connection
00263     acceptHandshakeConnection (socket);
00264 }
00265 
00266 void LocalPeer::acceptHandshakeConnection (QTcpSocket *socket)
00267 {
00268     Connection      *connection     = new TcpConnection (socket);
00269 
00270     NodeAddress nodeAddress = connection->remoteNodeAddress();
00271 
00272     p->nodeModel.nodeConnecting (connection, nodeAddress);
00273     p->handshaker.acceptConnection (connection);
00274 }
00275 
00276 // \todo Just pass a query string. Create a packet here!
00277 void LocalPeer::startSearch (SearchModel *searchModel, QString &query)
00278 {
00279      searcher()->startSearch (searchModel, query);
00280 }
00281 
00285 void LocalPeer::stopSearch (SearchModel *searchModel)
00286 {
00287      searcher()->stopSearch (searchModel);
00288 }