GeoIpResolver.cpp
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #include "GeoIpResolver.h"
00018 #include "GeoIpRequest.h"
00019 #include "GeoIpResponse.h"
00020 #include "GeoIp.h"
00021 #include "Vidalia.h"
00022
00023 #include "stringutil.h"
00024 #include "TorSslSocket.h"
00025
00026
00027 #define GEOIP_HOST "geoips.vidalia-project.net"
00028
00029 #define GEOIP_SSL_PORT 443
00030
00031 #define GEOIP_PAGE "/cgi-bin/geoip.py"
00032
00033
00034
00035 GeoIpResolver::GeoIpResolver(QObject *parent)
00036 : QObject(parent)
00037 {
00038 _socksAddr = QHostAddress::LocalHost;
00039 _socksPort = 9050;
00040 _cache = new GeoIpCache(this);
00041 }
00042
00043
00044
00045 void
00046 GeoIpResolver::setSocksHost(const QHostAddress &addr, quint16 port)
00047 {
00048 _socksAddr = addr;
00049 _socksPort = port;
00050 }
00051
00052
00053
00054
00055 bool
00056 GeoIpResolver::resolveFromCache(const QHostAddress &ip)
00057 {
00058 if (_cache->contains(ip)) {
00059 emit resolved(-1, QList<GeoIp>() << _cache->geoIpForAddress(ip));
00060 return true;
00061 }
00062 return false;
00063 }
00064
00065
00066
00067 QList<QHostAddress>
00068 GeoIpResolver::resolveFromCache(const QList<QHostAddress> &ips)
00069 {
00070 QList<GeoIp> cached;
00071
00072
00073 foreach (QHostAddress ip, ips) {
00074 if (_cache->contains(ip))
00075 cached << _cache->geoIpForAddress(ip);
00076 }
00077
00078
00079 if (cached.size() > 0) {
00080 vInfo("Resolved %1 GeoIP entries from cache.").arg(cached.size());
00081 emit resolved(-1, cached);
00082 }
00083 return ips;
00084 }
00085
00086
00087 int
00088 GeoIpResolver::resolve(const QHostAddress &ip)
00089 {
00090 return resolve(QList<QHostAddress>() << ip);
00091 }
00092
00093
00094 void
00095 GeoIpResolver::connected()
00096 {
00097
00098 QAbstractSocket *socket = dynamic_cast<QAbstractSocket *>(sender());
00099 if (!_requestList.contains(socket)) {
00100 return;
00101 }
00102 GeoIpRequest *req = static_cast<GeoIpRequest *>(_requestList.value(socket));
00103
00104 vInfo("Connected to the GeoIP host. Sending request for %1 uncached "
00105 "GeoIP entries. (request id %2)").arg(req->size()).arg(req->id());
00106
00107
00108 socket->write(req->request());
00109 }
00110
00111
00112 void
00113 GeoIpResolver::disconnected()
00114 {
00115
00116 QAbstractSocket *socket = dynamic_cast<QAbstractSocket *>(sender());
00117 if (!_requestList.contains(socket)) {
00118 return;
00119 }
00120 GeoIpRequest *req = static_cast<GeoIpRequest *>(_requestList.take(socket));
00121
00122
00123 GeoIpResponse response = GeoIpResponse(socket->readAll());
00124
00125
00126 if (response.statusCode() == 200) {
00127
00128
00129 parseGeoIpResponse(response.content(), req);
00130 } else {
00131
00132
00133 vWarn("GeoIP resolution failed (request id %1): %2").arg(req->id())
00134 .arg(response.statusMessage());
00135 emit resolveFailed(req->id(), response.statusMessage());
00136 }
00137
00138 socket->close();
00139 delete socket;
00140 delete req;
00141 }
00142
00143 void
00144 GeoIpResolver::parseGeoIpResponse(const QByteArray &response,
00145 GeoIpRequest *request)
00146 {
00147 QList<GeoIp> geoIpList;
00148 QHash<QString,QString> keyvals;
00149 QHostAddress ip, from, to;
00150 QString city, region, country, cc;
00151 float latitude, longitude;
00152 GeoIp geoIp;
00153 int numCached = 0;
00154 bool ok;
00155
00156 QStringList lines = QString(response).split("\n", QString::SkipEmptyParts);
00157 foreach (QString line, lines) {
00158
00159 QHash<QString,QString> keyvals = string_parse_keyvals(line.trimmed(), &ok);
00160 if (! ok)
00161 goto err;
00162
00163
00164 ip = QHostAddress(keyvals.value("IP"));
00165 if (ip.isNull())
00166 goto err;
00167 latitude = keyvals.value("LAT").toFloat(&ok);
00168 if (! ok)
00169 goto err;
00170 longitude = keyvals.value("LON").toFloat(&ok);
00171 if (! ok)
00172 goto err;
00173
00174
00175 city = keyvals.value("CITY");
00176 region = keyvals.value("REGION");
00177 country = keyvals.value("COUNTRY");
00178 cc = keyvals.value("CC");
00179
00180 geoIp = GeoIp(ip, latitude, longitude, city, region, country, cc);
00181 if (! geoIp.isValid())
00182 goto err;
00183
00184 if (request->contains(ip)) {
00185 if (! _cache->contains(ip)) {
00186 from = QHostAddress(keyvals.value("FROM"));
00187 to = QHostAddress(keyvals.value("TO"));
00188 if (! from.isNull() && ! to.isNull())
00189 _cache->addToCache(from, to, geoIp);
00190 else
00191 _cache->addToCache(geoIp);
00192 numCached++;
00193 }
00194
00195 geoIpList << geoIp;
00196 continue;
00197
00198 err:
00199 vInfo("Ignored improperly formatted GeoIP record (request id %1): %2")
00200 .arg(line).arg(request->id());
00201 } else {
00202
00203 vWarn("Received a GeoIP entry for IP address %1 that was not included "
00204 "in the initial request. (request id %2)").arg(ip)
00205 .arg(request->id());
00206 }
00207 }
00208
00209 if (numCached > 0)
00210 _cache->saveToDisk();
00211
00212
00213 vInfo("Parsed %1 entries from the GeoIP response. (request id %2)")
00214 .arg(geoIpList.size()).arg(request->id());
00215 emit resolved(request->id(), geoIpList);
00216 }
00217
00218
00219 void
00220 GeoIpResolver::socketError(const QString &errorString)
00221 {
00222
00223 QAbstractSocket *socket = dynamic_cast<QAbstractSocket *>(sender());
00224 if (!_requestList.contains(socket)) {
00225 return;
00226 }
00227
00228
00229
00230 if (socket->error() != QAbstractSocket::RemoteHostClosedError) {
00231
00232 GeoIpRequest *req = static_cast<GeoIpRequest *>(_requestList.take(socket));
00233 emit resolveFailed(req->id(), errorString);
00234 socket->abort();
00235 vWarn("GeoIP request socket error (request id %1): %2").arg(req->id())
00236 .arg(errorString);
00237 delete socket;
00238 delete req;
00239 }
00240 }
00241
00242
00243 GeoIpRequest*
00244 GeoIpResolver::createRequest(const QList<QHostAddress> &ips)
00245 {
00246 static int id = -1;
00247 GeoIpRequest *request = new GeoIpRequest(++id);
00248 request->setHost(GEOIP_HOST);
00249 request->setPage(GEOIP_PAGE);
00250 request->setRequest(ips);
00251 return request;
00252 }
00253
00254
00255 int
00256 GeoIpResolver::resolve(const QList<QHostAddress> &ips)
00257 {
00258
00259
00260 QList<QHostAddress> uncached = resolveFromCache(ips);
00261 if (! uncached.size())
00262 return -1;
00263
00264
00265 TorSslSocket *socket = new TorSslSocket(_socksAddr, _socksPort);
00266 connect(socket, SIGNAL(connectedToRemoteHost()), this, SLOT(connected()),
00267 Qt::QueuedConnection);
00268 connect(socket, SIGNAL(socketError(QString)),
00269 this, SLOT(socketError(QString)),
00270 Qt::QueuedConnection);
00271 connect(socket, SIGNAL(disconnected()), this, SLOT(disconnected()),
00272 Qt::QueuedConnection);
00273 GeoIpRequest *request = createRequest(uncached);
00274 _requestList.insert(socket, request);
00275
00276
00277 vInfo("Opening an SSL connection to the GeoIP host at %1:%2 (request id %3)")
00278 .arg(GEOIP_HOST).arg(GEOIP_SSL_PORT).arg(request->id());
00279 socket->connectToRemoteHost(GEOIP_HOST, GEOIP_SSL_PORT, true);
00280
00281 return request->id();
00282 }
00283