00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "Qt.h"
00024 #include "HandshakeSession.h"
00025 #include "Handshaker.h"
00026 #include "RequestHeader.h"
00027 #include "ResponseHeader.h"
00028 #include "Imports.cpp"
00029
00030 using namespace Gnutella::Handshaking;
00031
00032 namespace Gnutella {
00033 namespace Handshaking {
00034
00035
00036 static const int CodeOK = 200;
00037 static const int CodeNotAcceptable = 406;
00038 static const int CodeBusy = 503;
00039
00040 struct StatusLine
00041 {
00042 int code;
00043 QString phrase;
00044 };
00045
00046 static const StatusLine statusLines[] = {
00047 { CodeOK, "OK" },
00048 { CodeBusy, "No Slots Available" },
00049 { CodeNotAcceptable, "You Don't Support Required Features" },
00050 { CodeNotAcceptable, "I'm an Ultrapeer" },
00051 { CodeNotAcceptable, "I'm a Shielded Leaf" }
00052 };
00053
00054 enum Constants
00055 {
00056 HandshakingTimeout = 10000,
00057 TryUltrapeersCount = 20
00058 };
00059
00060 }
00061 }
00062
00063 HandshakeSession::HandshakeSession (Connection *connection,
00064 const NodeAddress & othersAddress,
00065 Handshaker *handshaker,
00066 NodeCache *nodeCache)
00067 : d()
00068 {
00069 d.handshaker = handshaker;
00070 d.nodeCache = nodeCache;
00071 d.reader = new HeaderReader (connection);
00072 d.writer = new HeaderWriter (connection);
00073 d.connection = connection;
00074 d.state = UnknownState;
00075 d.error = NoError;
00076 d.otherNodeInfo.address = othersAddress;
00077
00078
00079 if (othersAddress != NodeAddress::Null)
00080 d.nodeCache->updateNode (othersAddress, NodeCache::CheckingAvailability);
00081
00082 connect (d.connection, SIGNAL (connectionEstablished()),
00083 this, SLOT (connectionEstablished()));
00084 connect (d.connection, SIGNAL (connectionFailed()),
00085 this, SLOT (connectionFailed()));
00086 connect (d.connection, SIGNAL (connectionClosed()),
00087 this, SLOT (connectionClosed()));
00088 connect (d.reader, SIGNAL (headerRead()),
00089 this, SLOT (handshakeRead()));
00090 connect (d.reader, SIGNAL (readError()),
00091 this, SLOT (readError()));
00092 connect (d.writer, SIGNAL (headerWritten()),
00093 this, SLOT (handshakeWritten()));
00094 connect (d.writer, SIGNAL (writeError()),
00095 this, SLOT (writeError()));
00096
00097 connect (&d.timer, SIGNAL (timeout()), this, SLOT (timeout()));
00098 d.timer.setSingleShot (true);
00099 d.timer.setInterval (HandshakingTimeout);
00100 }
00101
00102 HandshakeSession::~HandshakeSession()
00103 {
00104 qDebug() << "HandshakeSession::~HandshakeSession()";
00105
00106 d.reader->disconnect (this);
00107 d.writer->disconnect (this);
00108 d.timer.disconnect (this);
00109
00110 d.timer.stop();
00111
00112 delete d.reader;
00113 delete d.writer;
00114
00115 qDebug() << "HandshakeSession::~HandshakeSession() exit";
00116 }
00117
00118 inline void HandshakeSession::completed()
00119 {
00120 d.state = HandshakingCompleted;
00121 d.error = NoError;
00122
00132 if (d.otherNodeInfo.address != NodeAddress::Null)
00133 d.nodeCache->addNode (d.otherNodeInfo, NodeCache::NodeAvailable);
00134 else if (d.connection->remoteNodeAddress() != NodeAddress::Null)
00135 d.nodeCache->updateNode (d.connection->remoteNodeAddress(),
00136 NodeCache::NodeUnavailable);
00137 emit handshakingCompleted (this);
00138 }
00139
00140 inline void HandshakeSession::failed (HandshakeError error)
00141 {
00142 if (d.state == HandshakingFailed)
00143 return;
00144
00145 d.state = HandshakingFailed;
00146 d.error = error;
00147
00148
00149 if (d.otherNodeInfo.address != NodeAddress::Null)
00150 d.nodeCache->updateNode (d.otherNodeInfo.address,
00151 NodeCache::NodeUnavailable);
00152 else if (d.connection->remoteNodeAddress() != NodeAddress::Null)
00153 d.nodeCache->updateNode (d.connection->remoteNodeAddress(),
00154 NodeCache::NodeUnavailable);
00155
00156
00157
00158
00159
00160
00161 if (error != ErrorCannotEstablishConnection)
00162 d.connection->disconnectFromNode();
00163 }
00164
00165 void HandshakeSession::request(const NodeInfo &myNodeInfo)
00166 {
00167 d.state = SendingPhase1Handshake;
00168
00169 RequestHeader request (0, 6);
00170 setHandshakeHeaders (request, myNodeInfo);
00171 qDebug() << "Write:\n" << request.toString();
00172 d.timer.start();
00173 d.writer->write (request);
00174 }
00175
00176 void HandshakeSession::waitRequest()
00177 {
00178 d.state = WaitingPhase1Handshake;
00179 d.timer.start();
00180 d.reader->startReading (new RequestHeader);
00181 }
00182
00183 void HandshakeSession::sendResponse (RejectReason reason, const NodeInfo &myNodeInfo)
00184 {
00185 int code = statusLines [reason].code;
00186 QString phrase = statusLines [reason].phrase;
00187 ResponseHeader response (code, phrase, 0, 6);
00188 setHandshakeHeaders (response, myNodeInfo);
00189 qDebug() << "Write:\n" << response.toString();
00190 d.writer->write (response);
00191 }
00192
00193 void HandshakeSession::respond (const NodeInfo &myNodeInfo)
00194 {
00195 d.state = SendingPhase2Handshake;
00196 sendResponse (NotRejecting, myNodeInfo);
00197 }
00198
00199 void HandshakeSession::waitResponse()
00200 {
00201 d.state = WaitingPhase2Handshake;
00202 d.reader->startReading (new ResponseHeader);
00203 }
00204
00205 void HandshakeSession::waitAcknowledgement()
00206 {
00207 d.state = WaitingPhase3Handshake;
00208 d.reader->startReading (new ResponseHeader);
00209 }
00210
00211 void HandshakeSession::acknowledge (const NodeInfo &nodeInfo)
00212 {
00213 d.state = SendingPhase3Handshake;
00214 sendResponse (NotRejecting, nodeInfo);
00215 }
00216
00217 void HandshakeSession::reject (RejectReason reason, const NodeInfo &myNodeInfo)
00218 {
00219 d.state = RejectingConnection;
00220 sendResponse (reason, myNodeInfo);
00221 }
00222
00223 void HandshakeSession::handshakeRead()
00224 {
00225 const Header *handshake = d.reader->header();
00226 qDebug() << "Read:\n" << handshake->toString();
00227 getHandshakeHeaders (*handshake);
00228
00229 const RequestHeader *request =
00230 dynamic_cast <const RequestHeader *> (handshake);
00231 const ResponseHeader *response =
00232 dynamic_cast <const ResponseHeader *> (handshake);
00233
00234
00235 if ((request == 0 && d.state == WaitingPhase1Handshake)
00236 || (response == 0 && d.state != WaitingPhase1Handshake)) {
00237 failed (ErrorInvalidHeadersRead);
00238 } else if (response && response->statusCode() != CodeOK) {
00239 failed (ErrorRejectedByRemoteNode);
00240 } else if (d.state == WaitingPhase1Handshake) {
00241 emit receivedRequest (this);
00242 } else if (d.state == WaitingPhase2Handshake) {
00243 emit receivedResponse (this);
00244 } else if (d.state == WaitingPhase3Handshake) {
00245 completed();
00246 } else {
00247 Q_ASSERT (false);
00248 }
00249 }
00250
00251 void HandshakeSession::readError()
00252 {
00253 qDebug() << "HandshakeSession::readError()";
00254 failed (ErrorReadDevice);
00255 }
00256
00257 void HandshakeSession::handshakeWritten()
00258 {
00259 switch (d.state)
00260 {
00261 case SendingPhase1Handshake:
00262 waitResponse();
00263 break;
00264 case SendingPhase2Handshake:
00265 waitAcknowledgement();
00266 break;
00267 case SendingPhase3Handshake:
00268 completed();
00269 break;
00270 case RejectingConnection:
00271 failed (ErrorRemoteNodeRejected);
00272 break;
00273 case UnknownState:
00274 case WaitingPhase1Handshake:
00275 case WaitingPhase2Handshake:
00276 case WaitingPhase3Handshake:
00277 case HandshakingTimedOut:
00278 case HandshakingFailed:
00279 case HandshakingCompleted:
00280 default:
00281 Q_ASSERT (false);
00282 break;
00283 }
00284 }
00285
00286 void HandshakeSession::writeError()
00287 {
00288 qDebug() << "HandshakeSession::writeError()";
00289 failed (ErrorWriteDevice);
00290 }
00291
00292 void HandshakeSession::connectionEstablished()
00293 {
00294 qDebug() << "HandshakeSession::connectionEstablished()";
00295 emit connectionEstablished (this);
00296 }
00297
00298 void HandshakeSession::connectionFailed()
00299 {
00300 qDebug() << "HandshakeSession::connectionFailed()";
00301 failed (ErrorCannotEstablishConnection);
00302 emit handshakingFailed (this);
00303 }
00304
00305 void HandshakeSession::connectionClosed()
00306 {
00307 qDebug() << "HandshakeSession::connectionClosed()";
00308 d.timer.stop();
00309 d.timer.disconnect (this);
00310
00311
00312 if (d.state != HandshakingFailed)
00313 failed (ErrorRemoteClosedConnection);
00314
00315
00316
00317 if (d.state != HandshakingCompleted)
00318 emit handshakingFailed (this);
00319 }
00320
00321 void HandshakeSession::timeout()
00322 {
00323 qDebug() << "HandshakeSession::timeout()";
00324 failed (ErrorTimeout);
00325 }
00326
00327 void HandshakeSession::setHandshakeHeaders (Header &header, const NodeInfo &myNodeInfo)
00328 {
00329
00330 if (d.myNodeInfo.identification != myNodeInfo.identification)
00331 header.setFieldValue ("User-Agent", myNodeInfo.identification);
00332 if (d.state == SendingPhase1Handshake
00333 || d.state == SendingPhase2Handshake) {
00334
00335 header.setFieldValue ("Listen-IP", myNodeInfo.address.toString());
00336
00337
00338 d.otherNodeInfo.address = d.connection->remoteNodeAddress();
00339 QString remoteIp = d.otherNodeInfo.address.hostAddress().toString();
00340 header.setFieldValue ("Remote-IP", remoteIp);
00341 }
00342
00343 {
00344 bool isUltrapeer = myNodeInfo.type != TypeLeaf;
00345 header.setFieldValue ("X-Ultrapeer", isUltrapeer ? "true" : "false");
00346 }
00347
00348
00349 if (d.myNodeInfo.ultrapeerNeeded != myNodeInfo.ultrapeerNeeded
00350 && d.state != SendingPhase3Handshake) {
00351 QString neededString = myNodeInfo.ultrapeerNeeded ? "true" : "false";
00352 header.setFieldValue ("X-Ultrapeer-Needed", neededString);
00353 }
00354
00355 if (d.state == SendingPhase1Handshake
00356 || d.state == SendingPhase2Handshake) {
00357 header.setFieldValue ("Pong-Caching",
00358 myNodeInfo.pongCaching.toString());
00359 header.setFieldValue ("GGEP",
00360 myNodeInfo.ggep.toString());
00361 header.setFieldValue ("X-Query-Routing",
00362 myNodeInfo.queryRouting.toString());
00363 header.setFieldValue ("X-Ultrapeer-Query-Routing",
00364 myNodeInfo.ultrapeerQueryRouting.toString());
00365 header.setFieldValue ("X-Dynamic-Querying",
00366 myNodeInfo.dynamicQuerying.toString());
00367 header.setFieldValue ("X-Degree",
00368 QString ("%1").arg (myNodeInfo.degree));
00369 header.setFieldValue ("X-Max-TTL",
00370 QString ("%1").arg (myNodeInfo.maxTtl));
00371 header.setFieldValue ("X-Requeries", "false");
00372
00373 header.setFieldValue ("Vendor-Message",
00374 myNodeInfo.vendorMessage.toString());
00375
00376 header.setFieldValue ("Bye-Packet",
00377 myNodeInfo.byePacket.toString());
00378
00379 }
00380
00381 if (d.state == SendingPhase2Handshake) {
00383 NodeSet addresses = d.nodeCache->getNodes (TryUltrapeersCount,
00384 NodeCache::NodeAvailable,
00385 true);
00386 foreach (NodeAddress address, addresses) {
00387 header.addFieldValue ("X-Try-Ultrapeers", address.toString());
00388 }
00389 }
00390 d.myNodeInfo = myNodeInfo;
00391 }
00392
00393 void HandshakeSession::getHandshakeHeaders (const Header &header)
00394 {
00395 if (header.hasField ("User-Agent")) {
00396 d.otherNodeInfo.identification = header.fieldValue ("User-Agent");
00397 }
00398 if (header.hasField ("Listen-IP")) {
00399 QString listenIp = header.fieldValue ("Listen-IP");
00400 d.otherNodeInfo.address = NodeAddress (listenIp);
00401 }
00402 if (header.hasField ("Remote-IP")) {
00403 QHostAddress remoteIp = QHostAddress (header.fieldValue ("Remote-IP"));
00404 d.handshaker->setVisibleIp (remoteIp);
00405 d.myNodeInfo.address.setHostAddress (remoteIp);
00406 }
00407 if (header.hasField ("X-Ultrapeer")) {
00408 bool isUltrapeer = header.fieldValue ("X-Ultrapeer").toLower() == "true";
00409 d.otherNodeInfo.type = isUltrapeer ? TypePeer : TypeLeaf;
00410 if (isUltrapeer && d.myNodeInfo.type == TypeLeaf)
00411 d.otherNodeInfo.type = TypeUltrapeer;
00412 }
00413 if (header.hasField ("X-Ultrapeer-Needed")) {
00414 d.otherNodeInfo.ultrapeerNeeded = header.fieldValue ("X-Ultrapeer-Needed").toLower() == "true";
00415 } else {
00416 d.otherNodeInfo.ultrapeerNeeded = true;
00417 }
00418 if (header.hasField ("X-Try") || header.hasField ("X-Try-Ultrapeers")) {
00419 QStringList values = header.fieldValues("X-Try");
00420 values += header.fieldValues("X-Try-Ultrapeers");
00421 for (int i = values.size() - 1; i >= 0; i--) {
00422 using Gnutella::Bootstrapping::NodeCache;
00423 NodeAddress nodeAddress (values.at (i));
00424 NodeInfo nodeInfo;
00425 nodeInfo.address = nodeAddress;
00426 d.nodeCache->addNode (nodeInfo, NodeCache::UnknownAvailability);
00427 }
00428 }
00429 if (header.hasField ("GGEP")) {
00430 QString version = header.fieldValue ("GGEP");
00431 d.otherNodeInfo.ggep = Version (version);
00432 }
00433 if (header.hasField ("X-Query-Routing")) {
00434 QString version = header.fieldValue ("X-Query-Routing");
00435 d.otherNodeInfo.queryRouting = Version (version);
00436 }
00437 if (header.hasField ("X-Ultrapeer-Query-Routing")) {
00438 QString version = header.fieldValue ("X-Ultrapeer-Query-Routing");
00439 d.otherNodeInfo.ultrapeerQueryRouting = Version (version);
00440 }
00441 if (header.hasField ("Bye-Packet")) {
00442 QString version = header.fieldValue ("Bye-Packet");
00443 d.otherNodeInfo.byePacket = Version (version);
00444 }
00445 }