serverpage.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 serverpage.cpp
00024  * \version $Id: serverpage.cpp 1238 2006-09-25 17:50:57Z edmanm $
00025  * \brief Tor server configuration options
00026  */
00027 
00028 #include <vidalia.h>
00029 #include <util/net.h>
00030 #include <util/http.h>
00031 #include <util/html.h>
00032 #include <gui/common/vmessagebox.h>
00033 
00034 #include "serverpage.h"
00035 #include "ipvalidator.h"
00036 #include "portvalidator.h"
00037 #include "domainvalidator.h"
00038 #include "nicknamevalidator.h"
00039 
00040 /* Default Exit Policy */
00041 #define DEFAULT_POLICY    Policy(AcceptAll)
00042 /* Columns of the Exit Policy list */
00043 #define COL_ACTION    0
00044 #define COL_ADDRESS   1
00045 #define COL_PORT      2
00046 
00047 /** Delay between updating our server IP address (in ms). */
00048 #define AUTO_UPDATE_ADDR_INTERVAL  1000*60*60
00049 
00050 /** Help topics */
00051 #define EXIT_POLICY_HELP      "server.exitpolicy"
00052 #define BANDWIDTH_HELP        "server.bandwidth"
00053 /** Minimum allowed bandwidth rate (20KB) */
00054 #define MIN_RATE      20
00055 /** Maximum bandwidth rate. This is limited to 2147483646 bytes, 
00056  * or 2097151 kilobytes. (2147483646/1024) */ 
00057 #define MAX_RATE      2097151
00058 
00059 
00060 /** Constructor */
00061 ServerPage::ServerPage(QWidget *parent)
00062 : ConfigPage(parent)
00063 {
00064   /* Invoke the Qt Designer generated object setup routine */
00065   ui.setupUi(this);
00066   
00067   /* Keep a pointer to the TorControl object used to talk to Tor */
00068   _torControl = Vidalia::torControl();
00069 
00070   /* Create ServerSettings object */
00071   _settings = new ServerSettings(_torControl);
00072 
00073   /* Create a timer that we can use to remind ourselves to check if our IP
00074    * changed since last time we looked. */
00075   _autoUpdateTimer = new QTimer(this);
00076   connect(_autoUpdateTimer, SIGNAL(timeout()), 
00077           this, SLOT(updateServerIP()));
00078  
00079   /* Bind events to actions */
00080   connect(ui.btnAddPolicy, SIGNAL(clicked()), this, SLOT(addPolicy()));
00081   connect(ui.btnRemovePolicy, SIGNAL(clicked()), this, SLOT(removePolicy()));
00082   connect(ui.btnRaisePriority, SIGNAL(clicked()), this, SLOT(raisePriority()));
00083   connect(ui.btnLowerPriority, SIGNAL(clicked()), this, SLOT(lowerPriority()));
00084   connect(ui.btnGetAddress, SIGNAL(clicked()), this, SLOT(getServerAddress()));
00085   connect(ui.btnRateHelp, SIGNAL(clicked()), this, SLOT(bandwidthHelp()));
00086   connect(ui.btnExitHelp, SIGNAL(clicked()), this, SLOT(exitPolicyHelp()));
00087   
00088   connect(ui.lineAvgRateLimit, SIGNAL(editingFinished()), 
00089                          this, SLOT(rateChanged()));
00090   connect(ui.lineMaxRateLimit, SIGNAL(editingFinished()), 
00091                          this, SLOT(rateChanged()));
00092 
00093   /* Set validators for address, mask and various port number fields */
00094   ui.lineServerNickname->setValidator(new NicknameValidator(this));
00095   ui.lineServerAddress->setValidator(new DomainValidator(this));
00096   ui.lineServerPort->setValidator(new QIntValidator(1, 65535, this));
00097   ui.lineDirPort->setValidator(new QIntValidator(1, 65535, this));
00098   ui.lineExitAddress->setValidator(new IPValidator(this));
00099   ui.lineExitMask->setValidator(new QIntValidator(0, 32, this));
00100   ui.lineExitFromPort->setValidator(new PortValidator(this));
00101   ui.lineExitToPort->setValidator(new PortValidator(this));
00102   ui.lineAvgRateLimit->setValidator(new QIntValidator(MIN_RATE, MAX_RATE, this));
00103   ui.lineMaxRateLimit->setValidator(new QIntValidator(MIN_RATE, MAX_RATE, this));
00104 }
00105 
00106 /** Destructor */
00107 ServerPage::~ServerPage()
00108 {
00109   delete _settings;
00110 }
00111 
00112 /** Enables or disables the automatic IP address update timer. */
00113 void
00114 ServerPage::setAutoUpdateTimer(bool enabled)
00115 {
00116   if (enabled && _settings->isServerEnabled()) {
00117     _autoUpdateTimer->start(AUTO_UPDATE_ADDR_INTERVAL);
00118   } else {
00119     _autoUpdateTimer->stop();
00120   }
00121 }
00122 
00123 /** Saves changes made to settings on the Server settings page. */
00124 bool
00125 ServerPage::save(QString &errmsg)
00126 {
00127   /* Force the bandwidth rate limits to validate */
00128   rateChanged();
00129   
00130   if (ui.chkEnableServer->isChecked()) {
00131     /* A server must have an ORPort and a nickname */
00132     if (ui.lineServerPort->text().isEmpty() ||
00133         ui.lineServerNickname->text().isEmpty()) {
00134       errmsg = tr("You must specify at least a server nickname and port.");
00135       return false;
00136     }
00137     /* If the bandwidth rates aren't set, use some defaults before saving */
00138     if (ui.lineAvgRateLimit->text().isEmpty()) {
00139       ui.lineAvgRateLimit->setText(QString::number(2097152/1024) /* 2MB */);
00140     }
00141     if (ui.lineMaxRateLimit->text().isEmpty()) {
00142       ui.lineMaxRateLimit->setText(QString::number(5242880/1024) /* 5MB */);
00143     }
00144   }
00145   _settings->setServerEnabled(ui.chkEnableServer->isChecked());
00146   _settings->setDirectoryMirror(ui.chkMirrorDirectory->isChecked());
00147   _settings->setMiddleman(ui.chkMiddleMan->isChecked());
00148   _settings->setAutoUpdateAddress(ui.chkAutoUpdate->isChecked()); 
00149   _settings->setNickname(ui.lineServerNickname->text());
00150   _settings->setORPort(ui.lineServerPort->text().toUInt());
00151   _settings->setDirPort(ui.lineDirPort->text().toUInt());
00152   _settings->setAddress(ui.lineServerAddress->text());
00153   _settings->setContactInfo(ui.lineServerContact->text());
00154   _settings->setBandwidthAvgRate(ui.lineAvgRateLimit->text().toUInt()*1024);
00155   _settings->setBandwidthBurstRate(ui.lineMaxRateLimit->text().toUInt()*1024);
00156   setAutoUpdateTimer(ui.chkAutoUpdate->isChecked());
00157 
00158   /* Save exit polices */
00159   ExitPolicy exitPolicy;
00160   for (int i = 0; i < ui.lstExitPolicies->topLevelItemCount(); ++i) {
00161     savePolicy(ui.lstExitPolicies->topLevelItem(i), exitPolicy);
00162   }
00163   _settings->setExitPolicy(exitPolicy);
00164   
00165   /* If we're connectd to Tor and we've changed the server settings, attempt
00166    * to apply the new settings now. */
00167   if (_torControl->isConnected() && _settings->changedSinceLastApply()) {
00168     if (!_settings->apply(&errmsg)) {
00169       _settings->revert();
00170       return false;
00171     }
00172   }
00173   return true;
00174 }
00175 
00176 /** Loads previously saved settings */
00177 void
00178 ServerPage::load()
00179 {
00180   ui.chkEnableServer->setChecked(_settings->isServerEnabled());
00181   ui.chkMirrorDirectory->setChecked(_settings->isDirectoryMirror());
00182   ui.chkMiddleMan->setChecked(_settings->isMiddleman());
00183   ui.chkAutoUpdate->setChecked(_settings->getAutoUpdateAddress());
00184   setAutoUpdateTimer(_settings->getAutoUpdateAddress());
00185 
00186   ui.lineServerNickname->setText(_settings->getNickname());
00187   ui.lineServerPort->setText(QString::number(_settings->getORPort()));
00188   ui.lineDirPort->setText(QString::number(_settings->getDirPort()));
00189   ui.lineServerAddress->setText(_settings->getAddress());
00190   ui.lineServerContact->setText(_settings->getContactInfo());
00191   ui.lineAvgRateLimit->setText(
00192     QString::number((uint)(_settings->getBandwidthAvgRate()/1024)));
00193   ui.lineMaxRateLimit->setText(
00194     QString::number((uint)(_settings->getBandwidthBurstRate()/1024)));
00195   
00196   /* Load the exit policies into the list */
00197   ui.lstExitPolicies->clear();
00198   
00199   foreach (Policy policy, _settings->getExitPolicy().policyList()) {
00200     addPolicyItem(policy);
00201   }
00202   
00203   ui.frmExitPolicy->setHidden(ui.chkMiddleMan->isChecked());
00204   ui.frmServer->setVisible(ui.chkEnableServer->isChecked());
00205 }
00206 
00207 /** Adds the exit policy contained in item to the exitPolicy */
00208 void
00209 ServerPage::savePolicy(QTreeWidgetItem *item, ExitPolicy &exitPolicy)
00210 {
00211   /* Add policy to ServerSettings */
00212   exitPolicy.addPolicy(Policy(item->text(COL_ACTION),
00213                               item->text(COL_ADDRESS),
00214                               item->text(COL_PORT)));
00215 }
00216 
00217 /** Adds a new exit policy to the user's configuration */
00218 void
00219 ServerPage::addPolicy()
00220 {
00221   /* They must enter a valid address */
00222   QString address = ui.lineExitAddress->text();
00223   if (!address.isEmpty()) {
00224     if (((IPValidator *)ui.lineExitAddress->validator())->
00225         validate(address) != QValidator::Acceptable) {
00226       return;
00227     }
00228   }
00229   
00230   /* If port range specified, must be valid */
00231   QString fromPort = ui.lineExitFromPort->text();
00232   QString toPort = ui.lineExitToPort->text();
00233   
00234   if (!fromPort.isEmpty() && !toPort.isEmpty() && toPort != fromPort) {
00235     if (toPort == "*") toPort = "65535";
00236     if (fromPort == "*") fromPort = "1";
00237     if (fromPort.toUShort() > toPort.toUShort()) {
00238       return;
00239     }
00240   }
00241   
00242   /* Add the policy to the list */
00243   addPolicyItem(Policy(Policy::toAction(ui.cmboExitAction->currentText()), 
00244                        QHostAddress(ui.lineExitAddress->text()),
00245                        ui.lineExitMask->text().toUShort(), 
00246                        fromPort.toUShort(),
00247                        toPort.toUShort()), false);
00248 
00249   /* Clear input text boxes */
00250   ui.lineExitAddress->clear();
00251   ui.lineExitMask->clear();
00252   ui.lineExitFromPort->clear();
00253   ui.lineExitToPort->clear();
00254 }
00255 
00256 /** Adds a new QTreeWidget item to the exit policy list */
00257 void
00258 ServerPage::addPolicyItem(Policy policy, bool append)
00259 {
00260   QTreeWidgetItem *newPolicy = new QTreeWidgetItem();
00261 
00262   newPolicy->setText(COL_ACTION,  policy.action());
00263   newPolicy->setText(COL_ADDRESS, policy.address());
00264   newPolicy->setText(COL_PORT,    policy.ports());
00265  
00266   for (int i = 0; i < newPolicy->columnCount(); i++) {
00267     newPolicy->setTextAlignment(i, Qt::AlignHCenter);
00268   }
00269 
00270   if (append) {
00271     ui.lstExitPolicies->addTopLevelItem(newPolicy);
00272   } else {
00273     ui.lstExitPolicies->insertTopLevelItem(0, newPolicy);
00274   }
00275 }
00276 
00277 /** Removes selected exit policy from the user's configuration */
00278 void
00279 ServerPage::removePolicy()
00280 {
00281   int index = selectedIndex();
00282   
00283   if (index > -1) {
00284     delete ui.lstExitPolicies->takeTopLevelItem(index);
00285   }
00286 }
00287 
00288 /** Raises selected exit policy's priority level */
00289 void
00290 ServerPage::raisePriority()
00291 {
00292   int index = selectedIndex();
00293   
00294   if (index > 0) {
00295       ui.lstExitPolicies->insertTopLevelItem(index - 1, 
00296                                   ui.lstExitPolicies->takeTopLevelItem(index));
00297   }
00298 }
00299 
00300 /** Lowers selected exit policy's priority level */
00301 void
00302 ServerPage::lowerPriority()
00303 {
00304   int index = selectedIndex();
00305   int lastItem = ui.lstExitPolicies->topLevelItemCount() - 1;
00306 
00307   if (index > -1 && index < lastItem) {
00308     ui.lstExitPolicies->insertTopLevelItem(index + 1, 
00309                                   ui.lstExitPolicies->takeTopLevelItem(index));
00310   }
00311 }
00312 
00313 /** Returns the index of the selected list item, -1 if none selected */
00314 int
00315 ServerPage::selectedIndex()
00316 {
00317   if (ui.lstExitPolicies->selectedItems().isEmpty()) return -1;
00318   
00319   /* This list only contains one element so take it */
00320   QTreeWidgetItem *selectedItem = ui.lstExitPolicies->selectedItems()[0];
00321   return ui.lstExitPolicies->indexOfTopLevelItem(selectedItem);
00322 }
00323 
00324 /** Shows exit policy related help information */
00325 void
00326 ServerPage::exitPolicyHelp()
00327 {
00328   Vidalia::help(EXIT_POLICY_HELP);
00329 }
00330 
00331 /** Shows the bandwidth rate limiting help information */
00332 void
00333 ServerPage::bandwidthHelp()
00334 {
00335   Vidalia::help(BANDWIDTH_HELP);
00336 }
00337 
00338 /** Accesses an external site to try to get the user's public IP address. */
00339 void
00340 ServerPage::getServerPublicIP()
00341 {
00342   QString ip;
00343   bool success;
00344 
00345   /* This could take a bit, so show the wait cursor. */
00346   QApplication::setOverrideCursor(Qt::WaitCursor);
00347   success = net_get_public_ip(ip);
00348   QApplication::restoreOverrideCursor();
00349   
00350   /* Handle the result */
00351   if (success) {
00352     ui.lineServerAddress->setText(ip);
00353   } else {
00354     VMessageBox::warning(this, tr("Error"),
00355       p(tr("Vidalia was unable to determine your public IP address.")),
00356       VMessageBox::Ok);
00357   }
00358 }
00359 
00360 /** Attempts to determine this machine's IP address. If the local IP address
00361  * is a private address, then the user is asked whether they would like to
00362  * access an external site to try to get their public IP. */
00363 void
00364 ServerPage::getServerAddress()
00365 {
00366   QHostAddress addr = net_local_address();
00367   if (net_is_private_address(addr)) {
00368     int button = VMessageBox::information(this, tr("Get Address"),
00369                    tr("Vidalia was only able to find a private IP " 
00370                       "address for your server.\n\nWould you like to "
00371                       "access an external service to determine your public " 
00372                       "IP address?"),
00373                     VMessageBox::Yes, VMessageBox::No);
00374     if (button == VMessageBox::Yes) {
00375       getServerPublicIP();
00376       return;
00377     }
00378   } else {
00379     ui.lineServerAddress->setText(addr.toString());
00380   }
00381 }
00382 
00383 /** Checks to see if this server's public IP had changed. If it has, then
00384  * update the UI, and Tor (if it's running). */
00385 void
00386 ServerPage::updateServerIP()
00387 {
00388   bool changed = false;
00389   QString ip;
00390   QHostAddress addr = net_local_address();
00391   
00392   if (net_is_private_address(addr)) {
00393     /* Try to get our public IP and see if it changed recently. */
00394     if (net_get_public_ip(ip) && ip != _settings->getAddress()) {
00395       changed = true;
00396     }
00397   } else if (addr.toString() != _settings->getAddress()) {
00398     ip = addr.toString();
00399     changed = true;
00400   }
00401   
00402   if (changed) {
00403     /* It changed so update our settings and the UI. */
00404     _settings->setAddress(ip);
00405     ui.lineServerAddress->setText(ip);
00406 
00407     /* If Tor is running, let it know about the change */
00408     if (_torControl->isConnected()) {
00409       _settings->apply();
00410     }
00411   }
00412 }
00413 
00414 /** Called when the user edits the long-term average or maximum bandwidth limit. 
00415  * This ensures that the average bandwidth rate is greater than MIN_RATE
00416  * (20KB/s) and that the max rate is greater than the average rate. */
00417 void
00418 ServerPage::rateChanged()
00419 {
00420   /* Make sure the average rate isn't too low or too high */
00421   quint32 avgRate = (quint32)ui.lineAvgRateLimit->text().toUInt();
00422   if (avgRate < MIN_RATE) {
00423     ui.lineAvgRateLimit->setText(QString::number(MIN_RATE));    
00424   }
00425   if (avgRate > MAX_RATE) {
00426     ui.lineAvgRateLimit->setText(QString::number(MAX_RATE));
00427   }
00428   /* Ensure the max burst rate is greater than the average rate but less than
00429    * the maximum allowed rate. */
00430   quint32 burstRate = (quint32)ui.lineMaxRateLimit->text().toUInt();
00431   if (avgRate > burstRate) {
00432     ui.lineMaxRateLimit->setText(QString::number(avgRate));
00433   }
00434   if (burstRate > MAX_RATE) {
00435     ui.lineMaxRateLimit->setText(QString::number(MAX_RATE));
00436   }
00437 }
00438 

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