upnpcontrolthread.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 "upnpcontrolthread.h"
00018
00019 #include <QWaitCondition>
00020 #include <QMutex>
00021 #include <QTime>
00022 #include <QTextStream>
00023 #include <QString>
00024 #include <QMessageBox>
00025 #include <vidalia.h>
00026
00027 #ifdef Q_OS_WIN32
00028 #include <winsock2.h>
00029 #endif
00030
00031 #include "upnpcontrol.h"
00032
00033 #define UPNPCONTROL_REINIT_MSEC 300000 // 5 minutes
00034 #define UPNPCONTROL_MAX_WAIT_MSEC 60000 // 1 minute
00035
00036
00037
00038
00039 UPNPControlThread::UPNPControlThread(UPNPControl *control)
00040 {
00041 _upnpInitialized = QTime();
00042 _keepRunning = true;
00043 _control = control;
00044
00045 _dirPort = 0;
00046 _orPort = 0;
00047
00048 _waitCondition = new QWaitCondition();
00049 _waitMutex = new QMutex();
00050 }
00051
00052
00053
00054
00055
00056 UPNPControlThread::~UPNPControlThread()
00057 {
00058 delete _waitCondition;
00059 delete _waitMutex;
00060 }
00061
00062
00063
00064
00065 void
00066 UPNPControlThread::run()
00067 {
00068 bool shouldExit = false;
00069
00070 forever {
00071
00072
00073
00074 configurePorts();
00075
00076
00077 _waitMutex->lock();
00078 if (_keepRunning) {
00079
00080 UPNPControl::instance()->setState(UPNPControl::IdleState);
00081 _waitCondition->wait(_waitMutex, UPNPCONTROL_MAX_WAIT_MSEC);
00082
00083
00084 shouldExit = !_keepRunning;
00085 _waitMutex->unlock();
00086 if (shouldExit)
00087 break;
00088 } else {
00089
00090 _waitMutex->unlock();
00091 break;
00092 }
00093 }
00094
00095
00096 updatePort(_dirPort, 0);
00097 updatePort(_orPort, 0);
00098 }
00099
00100
00101
00102
00103
00104 void
00105 UPNPControlThread::configurePorts() {
00106 quint16 desiredDirPort, desiredOrPort;
00107 bool force_init = false;
00108 UPNPControl::UPNPError retval = UPNPControl::Success;
00109
00110
00111 _control->getDesiredState(&desiredDirPort, &desiredOrPort);
00112
00113
00114
00115
00116 if (_upnpInitialized.isNull() ||
00117 _upnpInitialized>QTime::currentTime() ||
00118 _upnpInitialized.addMSecs(UPNPCONTROL_REINIT_MSEC)<QTime::currentTime()
00119 ) {
00120 _upnpInitialized = QTime();
00121 force_init = true;
00122 }
00123
00124 if (!force_init) {
00125
00126 if (desiredDirPort != _dirPort) {
00127 UPNPControl::instance()->setState(UPNPControl::UpdatingDirPortState);
00128 retval = updatePort(_dirPort, desiredDirPort);
00129 if (retval == UPNPControl::Success)
00130 _dirPort = desiredDirPort;
00131 else
00132 goto err;
00133 }
00134
00135
00136 if (desiredOrPort != _orPort) {
00137 UPNPControl::instance()->setState(UPNPControl::UpdatingORPortState);
00138 retval = updatePort(_orPort, desiredOrPort);
00139 if (retval == UPNPControl::Success)
00140 _orPort = desiredOrPort;
00141 else
00142 goto err;
00143 }
00144 } else {
00145
00146 UPNPControl::instance()->setState(UPNPControl::UpdatingDirPortState);
00147 retval = updatePort(0, desiredDirPort);
00148 if (retval == UPNPControl::Success)
00149 _dirPort = desiredDirPort;
00150 else
00151 goto err;
00152
00153 UPNPControl::instance()->setState(UPNPControl::UpdatingORPortState);
00154 retval = updatePort(0, desiredOrPort);
00155 if (retval == UPNPControl::Success)
00156 _orPort = desiredOrPort;
00157 else goto err;
00158 }
00159
00160 UPNPControl::instance()->setState(UPNPControl::ForwardingCompleteState);
00161 return;
00162
00163 err:
00164 UPNPControl::instance()->setError(retval);
00165 UPNPControl::instance()->setState(UPNPControl::ErrorState);
00166 }
00167
00168
00169
00170
00171 void
00172 UPNPControlThread::stop()
00173 {
00174
00175 _waitMutex->lock();
00176
00177
00178 _keepRunning = false;
00179
00180
00181 _waitCondition->wakeAll();
00182
00183
00184 _waitMutex->unlock();
00185
00186
00187 wait();
00188 }
00189
00190
00191
00192
00193 void
00194 UPNPControlThread::wakeup()
00195 {
00196 _waitMutex->lock();
00197 _waitCondition->wakeAll();
00198 _waitMutex->unlock();
00199 }
00200
00201
00202
00203 UPNPControl::UPNPError
00204 UPNPControlThread::updatePort(quint16 oldPort, quint16 newPort)
00205 {
00206 UPNPControl::UPNPError retval;
00207
00208 #ifdef Q_OS_WIN32
00209
00210 WSAData wsadata;
00211 if (WSAStartup(MAKEWORD(2,0), &wsadata) != 0) {
00212 vWarn("WSAStartup failure while updating UPnP port forwarding");
00213 return UPNPControl::WSAStartupFailed;
00214 }
00215 #endif
00216
00217 if (_upnpInitialized.isNull() && (oldPort != 0 || newPort != 0)) {
00218 retval = initializeUPNP();
00219 if (retval == UPNPControl::Success)
00220 _upnpInitialized = QTime::currentTime();
00221 else
00222 _upnpInitialized = QTime();
00223 } else {
00224 retval = UPNPControl::Success;
00225 }
00226
00227 if (retval == UPNPControl::Success && oldPort != 0)
00228 retval = disablePort(oldPort);
00229
00230 if (retval == UPNPControl::Success && newPort != 0)
00231 retval = forwardPort(newPort);
00232
00233 #ifdef Q_OS_WIN32
00234 WSACleanup();
00235 #endif
00236
00237 return retval;
00238 }
00239
00240
00241
00242
00243 UPNPControl::UPNPError
00244 UPNPControlThread::initializeUPNP()
00245 {
00246 struct UPNPDev *devlist;
00247 int retval;
00248
00249 memset(&urls, 0, sizeof(struct UPNPUrls));
00250 memset(&data, 0, sizeof(struct IGDdatas));
00251
00252 UPNPControl::instance()->setState(UPNPControl::DiscoverState);
00253
00254 devlist = upnpDiscover(UPNPCONTROL_DISCOVER_TIMEOUT, NULL, NULL);
00255 if (NULL == devlist) {
00256 vWarn("upnpDiscover returned: NULL");
00257 return UPNPControl::NoUPNPDevicesFound;
00258 }
00259
00260 retval = UPNP_GetValidIGD(devlist, &urls, &data, lanaddr, sizeof(lanaddr));
00261
00262 vInfo("GetValidIGD returned: %1").arg(retval);
00263
00264 freeUPNPDevlist(devlist);
00265
00266 if (retval != 1 && retval != 2)
00267 return UPNPControl::NoValidIGDsFound;
00268
00269 return UPNPControl::Success;
00270 }
00271
00272
00273
00274 UPNPControl::UPNPError
00275 UPNPControlThread::forwardPort(quint16 port)
00276 {
00277 int retval;
00278
00279 char sPort[6];
00280
00281 char intClient[16];
00282 char intPort[6];
00283
00284
00285 snprintf(sPort, sizeof(sPort), "%d", port);
00286
00287
00288 retval = UPNP_AddPortMapping(urls.controlURL, data.servicetype,
00289 sPort, sPort, lanaddr, "Tor relay", "TCP");
00290 if(UPNPCOMMAND_SUCCESS != retval) {
00291 vWarn("AddPortMapping(%1, %2, %3) failed with code %4")
00292 .arg(sPort).arg(sPort).arg(lanaddr).arg(retval);
00293 return UPNPControl::AddPortMappingFailed;
00294 }
00295
00296
00297 retval = UPNP_GetSpecificPortMappingEntry(urls.controlURL, data.servicetype,
00298 sPort, "TCP", intClient, intPort);
00299 if(UPNPCOMMAND_SUCCESS != retval) {
00300 vWarn("GetSpecificPortMappingEntry() failed with code %1").arg(retval);
00301 return UPNPControl::GetPortMappingFailed;
00302 }
00303
00304 if(! intClient[0]) {
00305 vWarn("GetSpecificPortMappingEntry failed.");
00306 return UPNPControl::GetPortMappingFailed;
00307 }
00308
00309
00310 vInfo("(external):%1 -> %2:%3").arg(sPort).arg(intClient).arg(intPort);
00311
00312 return UPNPControl::Success;
00313 }
00314
00315
00316
00317 UPNPControl::UPNPError
00318 UPNPControlThread::disablePort(quint16 port)
00319 {
00320 char sPort[6];
00321
00322
00323 snprintf(sPort, sizeof(sPort), "%d", port);
00324
00325
00326 int retval = UPNP_DeletePortMapping(urls.controlURL, data.servicetype,
00327 sPort, "TCP");
00328 if(UPNPCOMMAND_SUCCESS != retval) {
00329 vWarn("DeletePortMapping() failed with code %1").arg(retval);
00330 return UPNPControl::DeletePortMappingFailed;
00331 }
00332
00333
00334 vInfo("(external):%1 -> <>").arg(sPort);
00335
00336 return UPNPControl::Success;
00337 }
00338