geoipresolver.cpp

Go to the documentation of this file.
00001 /****************************************************************
00002  *  Vidalia is distributed under the following license:
00003  *
00004  *  Copyright (C) 2006,  Matt Edman, Justin Hipple
00005  *
00006  *  This program is free software; you can redistribute it and/or
00007  *  modify it under the terms of the GNU General Public License
00008  *  as published by the Free Software Foundation; either version 2
00009  *  of the License, or (at your option) any later version.
00010  *
00011  *  This program is distributed in the hope that it will be useful,
00012  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  *  GNU General Public License for more details.
00015  *
00016  *  You should have received a copy of the GNU General Public License
00017  *  along with this program; if not, write to the Free Software
00018  *  Foundation, Inc., 51 Franklin Street, Fifth Floor,
00019  *  Boston, MA  02110-1301, USA.
00020  ****************************************************************/
00021 
00022 /**
00023  * \file geoipresolver.cpp
00024  * \version $Id: geoipresolver.cpp 1238 2006-09-25 17:50:57Z edmanm $
00025  * \brief Requests GeoIP information and caches the result
00026  */
00027 
00028 #include "geoipresolver.h"
00029 
00030 /** Host for the geo ip information. This hostname round-robins between
00031  * pasiphae.vidalia-project.net, thebe.vidalia-project.net, and
00032  * cups.cs.cmu.edu. */ 
00033 #define GEOIP_HOST    "geoip.vidalia-project.net"
00034 /** Page that we request the geo ip information from. */
00035 #define GEOIP_PAGE    "/cgi-bin/geoip"
00036 
00037 
00038 /** Resolves a list of IPs to a geographic location, but only those which are
00039  * cached. Returns a list of IPs that were not in the cache. */
00040 QList<QHostAddress>
00041 GeoIpResolver::resolveFromCache(QList<QHostAddress> ips)
00042 {
00043   QList<GeoIp> cached;
00044 
00045   /* Build a list of which IPs have cached GeoIp information */
00046   foreach (QHostAddress ip, ips) {
00047     if (_cache.contains(ip)) {
00048       ips.removeAt(ips.indexOf(ip));
00049       cached << _cache.geoip(ip);
00050     }
00051   }
00052 
00053   /* If any were cached, emit their results now */
00054   if (cached.size() > 0) {
00055     emit resolved(-1, cached);
00056   }
00057   return ips;
00058 }
00059 
00060 /** Resolves a single IP to a geographic location. */
00061 int
00062 GeoIpResolver::resolve(QHostAddress ip)
00063 {
00064   return resolve(QList<QHostAddress>() << ip);
00065 }
00066 
00067 /** Called when the socket has connected to the Geo IP host. */
00068 void
00069 GeoIpResolver::connected()
00070 {
00071   /* Find the socket and request for whoever called this slot */ 
00072   TorSocket *socket = (TorSocket *)sender();
00073   if (!_requestList.contains(socket)) {
00074     return;
00075   }
00076   GeoIpRequest *req = (GeoIpRequest *)_requestList.value(socket);
00077   
00078   /* Send the request */
00079   socket->write(req->request());
00080 }
00081 
00082 /** Called when the socket has disconnected from the Geo IP host. */
00083 void
00084 GeoIpResolver::disconnected()
00085 {
00086   /* Find the socket and request for whoever called this slot */ 
00087   TorSocket *socket = (TorSocket *)sender();
00088   if (!_requestList.contains(socket)) {
00089     return;
00090   }
00091   GeoIpRequest *request = (GeoIpRequest *)_requestList.take(socket);
00092 
00093   /* Read and parse the response */
00094   GeoIpResponse response = GeoIpResponse(socket->readAll());
00095 
00096   /* Check the response code and see what we got */
00097   if (response.statusCode() == 200) {
00098     /* We got a 200 OK, so get the Geo IP information and cache the results */
00099     int numCached = 0;
00100     QList<GeoIp> geoips = response.geoIps();
00101     foreach (GeoIp geoip, geoips) {
00102       if (!_cache.contains(geoip.ip())) {
00103         _cache.cache(geoip);
00104         numCached++;
00105       }
00106     }
00107     /* If new results were cached, save them to disk */
00108     if (numCached > 0) {
00109       _cache.saveToDisk();
00110     }
00111     /* Emit the results */
00112     emit resolved(request->id(), geoips);
00113   } else {
00114     /* We failed to get the Geo IP information, so emit resolveFailed and
00115      * include the HTTP status message. */
00116     emit resolveFailed(request->id(), response.statusMessage());
00117   }
00118   /* Close the socket and clean up */
00119   socket->close();
00120   delete socket;
00121   delete request;
00122 }
00123 
00124 /** Called when an error has occurred requesting Geo IP information. */
00125 void
00126 GeoIpResolver::socketError(QString errorString)
00127 {
00128   /* Find the socket and request for whoever called this slot */ 
00129   TorSocket *socket = (TorSocket *)sender();
00130   if (!_requestList.contains(socket)) {
00131     return;
00132   }
00133   
00134   /* We expect a remote host to close the socket, because that's how the HTTP
00135    * server tells us he's done talkig to us. */
00136   if (socket->error() != QAbstractSocket::RemoteHostClosedError) {
00137     /* Emit the failure and clean up */
00138     GeoIpRequest *request = (GeoIpRequest *)_requestList.take(socket);
00139     emit resolveFailed(request->id(), errorString);
00140     socket->abort();
00141     delete socket;
00142     delete request;
00143   }
00144 }
00145 
00146 /** Creates an HTTP request for Geo IP information. */
00147 GeoIpRequest*
00148 GeoIpResolver::createRequest(QList<QHostAddress> ips)
00149 {
00150   static int id = -1;
00151   GeoIpRequest *request = new GeoIpRequest(++id);
00152   request->setHost(GEOIP_HOST);
00153   request->setPage(GEOIP_PAGE);
00154   request->setRequest(ips);
00155   return request;
00156 }
00157 
00158 /** Creates a TorSocket used to connect to the Geo IP host. */
00159 TorSocket*
00160 GeoIpResolver::createRequestSocket()
00161 {
00162   TorSocket *socket = new TorSocket(QHostAddress::LocalHost, 9050);
00163   connect(socket, SIGNAL(connectedToHost()), this, SLOT(connected()),
00164           Qt::QueuedConnection);
00165   connect(socket, SIGNAL(socketError(QString)), 
00166             this,   SLOT(socketError(QString)),
00167           Qt::QueuedConnection);
00168   connect(socket, SIGNAL(disconnected()), this, SLOT(disconnected()),
00169           Qt::QueuedConnection);
00170   return socket;
00171 }
00172 
00173 /** Resolves a list of IPs to a geographic location. */
00174 int
00175 GeoIpResolver::resolve(QList<QHostAddress> ips)
00176 {
00177   /* Resolve the cached IPs and get a list of IPs that still need to be
00178    * resolved to a lat and long. */
00179   QList<QHostAddress> uncached = resolveFromCache(ips);
00180   if (!uncached.size()) {
00181     return -1;
00182   }
00183 
00184   /* Create a socket used ot request the geo ip information. */
00185   TorSocket *socket = createRequestSocket();
00186   GeoIpRequest *request = createRequest(ips);
00187   _requestList.insert(socket, request);
00188   
00189   /* Connect so we can send our request and return the request ID. */
00190   socket->connectToHost(GEOIP_HOST, 80);
00191   return request->id();
00192 }
00193 

Generated on Mon Oct 23 20:08:15 2006 for Vidalia by  doxygen 1.5.0