TrackerResponseParser.cpp

Go to the documentation of this file.
00001 /*
00002 
00003 Copyright (C) 2006-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 "PeerInfo.h"
00025 #include "TrackerResponseParser.h"
00026 #include "TrackerResponse.h"
00027 #include "Imports.cpp"
00028 #include <limits>
00029 
00031 
00058 bool TrackerResponseParser::parseAndLoadTrackerResponse (
00059                                     const QByteArray &rawTrackerResponseData,
00060                                     TrackerResponse &trackerResponse)
00061 {
00062     TrackerResponse parsedResponse;
00063 
00064     bool loadedOk = loadAllResponseData (rawTrackerResponseData, parsedResponse);
00065     if (!loadedOk)
00066         return false;
00067 
00068     trackerResponse = parsedResponse;
00069     return true;
00070 }
00071 
00072 
00074 
00078 bool TrackerResponseParser::loadAllResponseData (const QByteArray &rawData,
00079                                                  TrackerResponse &response)
00080 {
00081     // Decode raw data into a BDictionary object (pointer)
00082     BDecoder bDecoder (rawData);
00083     auto_ptr <BItem> item = bDecoder.readNext();
00084     if (!bDecoder.hasReadAllCorrectly())
00085         return false;
00086 
00087     const BDictionary *bData = dynamic_cast <const BDictionary *> (item.get());
00088     if (!bData || bData->keys().size() == 0)
00089         return false;
00090 
00091     // Try to get a failure reason - if this field is present, no other data
00092     // must be present as well. If it's not present, just continue as if it
00093     // was an optional field.
00094     bool failureReasonLoadedOk = loadFailureReason (bData, response);
00095     if (failureReasonLoadedOk)
00096         return bData->keys().size() == 1;
00097 
00098     // Parse and load mandatory fields
00099     bool intervalLoaded = loadInterval (bData, response);
00100     if (!intervalLoaded)
00101         return false;
00102 
00103     bool peersLoaded = loadPeers (bData, response);
00104     if (!peersLoaded)
00105         return false;
00106 
00107     // Parse and load optional fields - I'm not testing the return value
00108     loadWarningMessage (bData, response);
00109     loadMinInterval (bData, response);
00110     loadComplete (bData, response);
00111     loadIncomplete (bData, response);
00112     loadTrackerId (bData, response);
00113 
00114     return true;
00115 }
00116 
00118 
00132 bool TrackerResponseParser::loadFailureReason (const BDictionary *bData,
00133                                                TrackerResponse &response)
00134 {
00135     Q_ASSERT (bData != 0);
00136 
00137     const BString *bFailureReason = dynamic_cast <const BString *>
00138         (bData->item (FailureReasonKeyName));
00139     if (!bFailureReason)
00140         return false;
00141 
00142     response.d->failureReason = QString::fromUtf8 (bFailureReason->value());
00143     return true;
00144 }
00145 
00147 bool TrackerResponseParser::loadWarningMessage (const BDictionary *bData,
00148                                                 TrackerResponse &response)
00149 {
00150     Q_ASSERT (bData != 0);
00151 
00152     const BString *bWarningMessage = dynamic_cast <const BString *>
00153         (bData->item (WarningMessageKeyName));
00154     if (!bWarningMessage)
00155         return false;
00156 
00157     response.d->warningMessage = QString::fromUtf8 (bWarningMessage->value());
00158     return true;
00159 }
00160 
00162 bool TrackerResponseParser::loadInterval (const BDictionary *bData,
00163                                           TrackerResponse &response)
00164 {
00165     Q_ASSERT (bData != 0);
00166 
00167     const BInt *bInterval = dynamic_cast <const BInt *>
00168         (bData->item (IntervalKeyName));
00169     if (!bInterval || !isValidInterval (bInterval->value()))
00170         return false;
00171 
00172     // Now the 'interval' value is valid so I can do the cast safely
00173     response.d->interval = static_cast <uint> (bInterval->value());
00174     return true;
00175 }
00176 
00178 bool TrackerResponseParser::loadMinInterval (const BDictionary *bData,
00179                                              TrackerResponse &response)
00180 {
00181     Q_ASSERT (bData != 0);
00182 
00183     const BInt *bMinInterval = dynamic_cast <const BInt *>
00184         (bData->item (MinIntervalKeyName));
00185     if (!bMinInterval || !isValidInterval (bMinInterval->value()))
00186         return false;
00187 
00188     // Now the 'min interval' value is valid so I can do the cast safely
00189     response.d->minInterval = static_cast <uint> (bMinInterval->value());
00190     return true;
00191 }
00192 
00194 bool TrackerResponseParser::loadTrackerId (const BDictionary *bData,
00195                                            TrackerResponse &response)
00196 {
00197     Q_ASSERT (bData != 0);
00198 
00199     const BString *bTrackerId = dynamic_cast <const BString *>
00200         (bData->item (TrackerIdKeyName));
00201     if (!bTrackerId)
00202         return false;
00203 
00204     response.d->trackerId = bTrackerId->value();
00205     return true;
00206 }
00207 
00209 bool TrackerResponseParser::loadComplete (const BDictionary *bData,
00210                                           TrackerResponse &response)
00211 {
00212     Q_ASSERT (bData != 0);
00213 
00214     const BInt *bComplete = dynamic_cast <const BInt *>
00215         (bData->item (CompleteKeyName));
00216     if (!bComplete || !isValidNumberOfPeers (bComplete->value()))
00217         return false;
00218 
00219     // Now the 'complete' value is valid so I can do the cast safely
00220     response.d->complete = static_cast <uint> (bComplete->value());
00221     return true;
00222 }
00223 
00225 bool TrackerResponseParser::loadIncomplete (const BDictionary *bData,
00226                                             TrackerResponse &response)
00227 {
00228     Q_ASSERT (bData != 0);
00229 
00230     const BInt *bIncomplete = dynamic_cast <const BInt *>
00231         (bData->item (IncompleteKeyName));
00232     if (!bIncomplete || !isValidNumberOfPeers (bIncomplete->value()))
00233         return false;
00234 
00235     // Now the 'incomplete' value is valid so I can do the cast safely
00236     response.d->incomplete = static_cast <uint> (bIncomplete->value());
00237     return true;
00238 }
00239 
00241 bool TrackerResponseParser::loadPeers (const BDictionary *bData,
00242                                        TrackerResponse &response)
00243 {
00244     Q_ASSERT (bData != 0);
00245 
00246     TrackerResponse::PeerInfoList peerInfoList;
00247     bool peersLoaded = false;
00248     const BItem *bPeers = bData->item (PeersKeyName);
00249     if (dynamic_cast <const BString *> (bPeers) != 0) {
00250         // Binary model
00251         peersLoaded = loadPeersBinaryModel (
00252             static_cast <const BString *> (bPeers), peerInfoList);
00253     } else if (dynamic_cast <const BList *> (bPeers) != 0) {
00254         // Dictionary model
00255         peersLoaded = loadPeersDictionaryModel (
00256             static_cast <const BList *> (bPeers), peerInfoList);
00257     } else {
00258         return false;
00259     }
00260 
00261     if (!peersLoaded)
00262         return false;
00263     response.d->peers = peerInfoList;
00264     return true;
00265 }
00266 
00268 bool TrackerResponseParser::loadPeersBinaryModel (const BString *bPeers,
00269                                     TrackerResponse::PeerInfoList &peerInfoList)
00270 {
00271     Q_ASSERT (bPeers != 0);
00272 
00273     QByteArray peers (bPeers->value());
00274     if ((peers.size() % OnePeerStringSizeBinaryModel) != 0)
00275         return false;
00276 
00277     for (int peerIndex = 0; peerIndex < peers.size();
00278          peerIndex += OnePeerStringSizeBinaryModel) {
00279         peerInfoList.push_back (parseRawPeerInfo (
00280             peers.mid (peerIndex, OnePeerStringSizeBinaryModel)));
00281     }
00282 
00283     return true;
00284 }
00285 
00287 bool TrackerResponseParser::loadPeersDictionaryModel (const BList *bPeers,
00288                                     TrackerResponse::PeerInfoList &peerInfoList)
00289 {
00290     Q_ASSERT (bPeers != 0);
00291 
00292     // For each peer info
00293     // (cannot use foreach because BList doesn't support it)
00294     for (int i = 0; i < bPeers->size(); ++i) {
00295         const BDictionary *bPeerInfo = dynamic_cast <const BDictionary *>
00296             (bPeers->item (i));
00297         if (!bPeerInfo)
00298             return false;
00299 
00300         PeerInfo peerInfo;
00301         bool peerInfoLoadedOk = loadPeerInfo (bPeerInfo, peerInfo);
00302         if (peerInfoLoadedOk)
00303             peerInfoList.push_back (peerInfo);
00304     }
00305 
00306     return true;
00307 }
00308 
00310 PeerInfo TrackerResponseParser::parseRawPeerInfo (const QByteArray &rawPeerInfo)
00311 {
00312     Q_ASSERT (rawPeerInfo.size() == OnePeerStringSizeBinaryModel);
00313 
00314     BinaryReader reader (rawPeerInfo, BinaryReader::BigEndian);
00315     // Read IP address
00316     QByteArray ipAddress;
00317     ipAddress += QByteArray::number (static_cast <uint> (reader.readByte()));
00318     ipAddress += '.';
00319     ipAddress += QByteArray::number (static_cast <uint> (reader.readByte()));
00320     ipAddress += '.';
00321     ipAddress += QByteArray::number (static_cast <uint> (reader.readByte()));
00322     ipAddress += '.';
00323     ipAddress += QByteArray::number (static_cast <uint> (reader.readByte()));
00324     // Read port
00325     quint16 port = reader.readUInt16();
00326 
00327     return PeerInfo (ipAddress, port, PeerInfo::PeerId());
00328 }
00329 
00331 bool TrackerResponseParser::loadPeerInfo (const BDictionary *bPeerInfo,
00332                                           PeerInfo &peerInfo)
00333 {
00334     Q_ASSERT (bPeerInfo != 0);
00335 
00336     PeerInfo::PeerId peerId;
00337     bool peerIdLoadedOk = loadPeerInfoPeerId (bPeerInfo, peerId);
00338     if (!peerIdLoadedOk)
00339         return false;
00340 
00341     QByteArray hostAddress;
00342     bool hostAddressLoadedOk = loadPeerInfoHostAddress (bPeerInfo, hostAddress);
00343     if (!hostAddressLoadedOk)
00344         return false;
00345 
00346     quint16 port;
00347     bool portLoadedOk = loadPeerInfoPort (bPeerInfo, port);
00348     if (!portLoadedOk)
00349         return false;
00350 
00351     peerInfo = PeerInfo (hostAddress, port, peerId);
00352     return true;
00353 }
00354 
00356 bool TrackerResponseParser::loadPeerInfoPeerId (const BDictionary *bPeerInfo,
00357                                                 PeerInfo::PeerId &peerId)
00358 {
00359     Q_ASSERT (bPeerInfo != 0);
00360 
00361     const BString *bPeerId = dynamic_cast <const BString *>
00362         (bPeerInfo->item (PeersPeerIdKeyName));
00363     if (!bPeerId)
00364         return false;
00365 
00366     peerId = isValidPeerId (bPeerId->value()) ?
00367         PeerInfo::PeerId (bPeerId->value()) : PeerInfo::PeerId();
00368     return true;
00369 }
00370 
00372 bool TrackerResponseParser::loadPeerInfoHostAddress (const BDictionary *bPeerInfo,
00373                                                      QByteArray &hostAddress)
00374 {
00375     Q_ASSERT (bPeerInfo != 0);
00376 
00377     const BString *bIpAddress = dynamic_cast <const BString *>
00378         (bPeerInfo->item (PeersIpKeyName));
00379     if (!bIpAddress)
00380         return false;
00381 
00382     hostAddress = bIpAddress->value();
00383     return true;
00384 }
00385 
00387 bool TrackerResponseParser::loadPeerInfoPort (const BDictionary *bPeerInfo,
00388                                               quint16 &port)
00389 {
00390     Q_ASSERT (bPeerInfo != 0);
00391 
00392     const BInt *bPort = dynamic_cast <const BInt *>
00393         (bPeerInfo->item (PeersPortKeyName));
00394     if (!bPort)
00395         return false;
00396 
00397     port = isValidPort (bPort->value()) ?
00398         static_cast <quint16> (bPort->value()) : 0;
00399     return true;
00400 }
00401 
00403 
00409 bool TrackerResponseParser::isValidInterval (qint64 interval)
00410 {
00411     return interval >= 0 && interval <= std::numeric_limits<uint>::max();
00412 }
00413 
00415 
00421 bool TrackerResponseParser::isValidNumberOfPeers (qint64 numOfPeers)
00422 {
00423     return numOfPeers >= 0 && numOfPeers <= std::numeric_limits<uint>::max();
00424 }
00425 
00427 
00431 bool TrackerResponseParser::isValidPeerId (const QByteArray &peerId)
00432 {
00433     return static_cast <uint> (peerId.size()) == PeerInfo::PeerId::size();
00434 }
00435 
00437 
00441 bool TrackerResponseParser::isValidPort (qint64 port)
00442 {
00443     return port >= 0 && port <= std::numeric_limits<quint16>::max();
00444 }
00445 
00446 // Static constants definitions
00447 const char *TrackerResponseParser::FailureReasonKeyName  = "failure reason";
00448 const char *TrackerResponseParser::WarningMessageKeyName = "warning message";
00449 const char *TrackerResponseParser::IntervalKeyName       = "interval";
00450 const char *TrackerResponseParser::MinIntervalKeyName    = "min interval";
00451 const char *TrackerResponseParser::TrackerIdKeyName      = "tracker id";
00452 const char *TrackerResponseParser::CompleteKeyName       = "complete";
00453 const char *TrackerResponseParser::IncompleteKeyName     = "incomplete";
00454 const char *TrackerResponseParser::PeersKeyName          = "peers";
00455 const char *TrackerResponseParser::PeersPeerIdKeyName    = "peer id";
00456 const char *TrackerResponseParser::PeersIpKeyName        = "ip";
00457 const char *TrackerResponseParser::PeersPortKeyName      = "port";
00458 const int   TrackerResponseParser::OnePeerStringSizeBinaryModel = 6;