GeoIpCache.cpp

Go to the documentation of this file.
00001 /*
00002 **  This file is part of Vidalia, and is subject to the license terms in the
00003 **  LICENSE file, found in the top level directory of this distribution. If you
00004 **  did not receive the LICENSE file with this file, you may obtain it from the
00005 **  Vidalia source package distributed by the Vidalia Project at
00006 **  http://www.vidalia-project.net/. No part of Vidalia, including this file,
00007 **  may be copied, modified, propagated, or distributed except according to the
00008 **  terms described in the LICENSE file.
00009 */
00010 
00011 /*
00012 ** \file GeoIpCache.cpp
00013 ** \version $Id: GeoIpCache.cpp 3768 2009-05-13 19:07:26Z edmanm $
00014 ** \brief Caches the results of previous GeoIP requests
00015 */
00016 
00017 #include "GeoIpCache.h"
00018 #include "GeoIpCacheItem.h"
00019 #include "GeoIp.h"
00020 #include "Vidalia.h"
00021 
00022 #include "file.h"
00023 #include "stringutil.h"
00024 
00025 #include <QFile>
00026 #include <QDir>
00027 #include <QString>
00028 #include <QDateTime>
00029 #include <QTextStream>
00030 #include <QHostAddress>
00031 
00032 
00033 GeoIpCache::GeoIpCache(QObject *parent)
00034   : QObject(parent)
00035 {
00036   loadFromDisk();
00037 }
00038 
00039 QString
00040 GeoIpCache::cacheFileName() const
00041 {
00042   return (Vidalia::dataDirectory() + "/geoip-cache");
00043 }
00044 
00045 bool
00046 GeoIpCache::saveToDisk(QString *errmsg)
00047 {
00048   /* Make sure we have a data directory. */
00049   if (!create_path(Vidalia::dataDirectory())) {
00050     return false;
00051   }
00052   
00053   /* Try to open a temporary cache file for writing */
00054   QFile tmpCacheFile(cacheFileName() + ".tmp");
00055   if (!tmpCacheFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
00056     return err(errmsg, tmpCacheFile.errorString());
00057   }
00058 
00059   /* Write the cache entries to the file. */
00060   QTextStream cache(&tmpCacheFile);
00061   foreach (GeoIpCacheItem cacheItem, _cache) {
00062     /* Save the cache item if it's not too old. */
00063     if (!cacheItem.isExpired()) {
00064       cache << cacheItem.toCacheString() << endl;
00065     }
00066   }
00067 
00068   QFile cacheFile(cacheFileName());
00069   /* Check if an previous cache file exists. */
00070   if (cacheFile.exists()) {
00071     /* A previous cache file exists, so try to remove it */
00072     if (!cacheFile.remove()) {
00073       return err(errmsg, cacheFile.errorString());
00074     }
00075   }
00076   /* Rename the temporary file into place. */
00077   if (!tmpCacheFile.rename(cacheFile.fileName())) {
00078     return err(errmsg, tmpCacheFile.errorString());
00079   }
00080   return true;
00081 }
00082 
00083 bool
00084 GeoIpCache::loadFromDisk(QString *errmsg)
00085 {
00086   QFile cacheFile(cacheFileName());
00087 
00088   if (cacheFile.exists()) {
00089     /* Try to open the cache file */
00090     if (!cacheFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
00091       return err(errmsg, cacheFile.errorString());
00092     }
00093     
00094     /* Read the cached items from the cache file */
00095     QTextStream cache(&cacheFile);
00096     QString line = cache.readLine();
00097     while (! line.isNull()) {
00098       /* Create a GeoIpCacheItem from the line and save it */
00099       GeoIpCacheItem item = GeoIpCacheItem::fromCacheString(line);
00100       if (item.isValid() && ! item.isExpired())
00101         addToCache(item);
00102 
00103       line = cache.readLine();
00104     }
00105     vInfo("Parsed %1 GeoIP entries from '%2'").arg(_cache.size())
00106                                               .arg(cacheFileName());
00107   }
00108   return true;
00109 }
00110 
00111 void
00112 GeoIpCache::addToCache(const GeoIp &geoip)
00113 {
00114   /* Create a "range" consisting of only a single IP address. */
00115   if (! contains(geoip.ip()))
00116     addToCache(geoip.ip(), geoip.ip(), geoip);
00117 }
00118 
00119 void
00120 GeoIpCache::addToCache(const QHostAddress &from, const QHostAddress &to,
00121                        const GeoIp &geoip)
00122 {
00123   /* New cache entries expire 30 days from the time they are first cached. */
00124   QDateTime expires = QDateTime::currentDateTime().toUTC().addDays(30);
00125   
00126   /* Create a new GeoIpCacheItem and add it to the cache */
00127   addToCache(GeoIpCacheItem(from, to, geoip, expires));
00128 }
00129 
00130 void
00131 GeoIpCache::addToCache(const GeoIpCacheItem &ci)
00132 {
00133   if (! ci.isValid() || ci.isExpired())
00134     return;
00135 
00136   /* The key for the cache is the last IP address in the range of IP addresses
00137    * covered by the GeoIpCacheItem. We do this because QMap::upperBound() and 
00138    * QMap::lowerBound() return an iterator to the next item higher than the
00139    * search value (an IP address) if an exact match is not found.
00140    */
00141   _cache.insert(ci.ipRangeEnd().toIPv4Address(), ci);
00142 }
00143 
00144 GeoIp
00145 GeoIpCache::geoIpForAddress(const QHostAddress &ip)
00146 {
00147   GeoIpCacheMap::iterator i = _cache.upperBound(ip.toIPv4Address());
00148   if (i != _cache.end() && (*i).contains(ip)) 
00149     return (*i).toGeoIp(ip);
00150   return GeoIp();
00151 }
00152 
00153 bool
00154 GeoIpCache::contains(const QHostAddress &ip)
00155 {
00156   GeoIpCacheMap::iterator i = _cache.upperBound(ip.toIPv4Address());
00157   return (i != _cache.end() && (*i).contains(ip));
00158 }
00159 
00160 
Generated on Mon Aug 30 22:58:54 2010 for Vidalia by  doxygen 1.6.3