diff options
Diffstat (limited to 'client')
-rwxr-xr-x | client/Config.cpp | 277 | ||||
-rw-r--r-- | client/Config.h | 52 | ||||
-rw-r--r-- | client/Dialog.cpp | 15 | ||||
-rwxr-xr-x | client/ProxyClientApp.cpp | 4 | ||||
-rw-r--r-- | client/SslClient.cpp | 29 | ||||
-rw-r--r-- | client/SslClient.h | 5 | ||||
-rw-r--r-- | client/UpdatedConfig.cpp | 134 | ||||
-rw-r--r-- | client/UpdatedConfig.h | 72 | ||||
-rwxr-xr-x | client/client.pro | 2 |
9 files changed, 404 insertions, 186 deletions
diff --git a/client/Config.cpp b/client/Config.cpp index acb3684..79a4aae 100755 --- a/client/Config.cpp +++ b/client/Config.cpp @@ -9,117 +9,38 @@ using namespace std; -Config* Config::self = NULL; -Config *Config::CurrentConfig() -{ - if (self == NULL) - self = new Config(); - return self; -} - -Config::Config(): QObject(), StaticProxySpeedLow(50) -{ - configValid = false; - +Config::Config(): StaticProxySpeedLow(50) +{ Logger::Info("Parsing config.cfg to determine initial configuration\n"); - ifstream configFile(QString(this_app->applicationDirPath()+ "/config.cfg").toLocal8Bit().data(), std::ios::in); + QString configPath = this_app->applicationDirPath()+ "/config.cfg"; + ifstream configFile(configPath.toLocal8Bit().data(), std::ios::in); if (!configFile) { Logger::Fatal("Can't open file: config.cfg\n"); return; } + string config = ""; const int str_size = 512; char str[str_size] = {0}; while (!configFile.eof()) { - configFile.getline(str, str_size, ';'); - configFile.ignore(2, '\n'); - if (configFile.eof()) - break; - string entry = str; - size_t eqpos = entry.find('='); - if (eqpos == string::npos) - { - Logger::Warn("No '=' at the config line: %s\n", entry.c_str()); - continue; - } - string key = entry.substr(0, eqpos); - string value = entry.substr(eqpos+1); - Logger::Trace("Found option: %s = %s\n", key.c_str(), value.c_str()); - if (key.compare("config_update_interval") == 0) - { - updateInterval = atoi(value.c_str()); - } - else if (key.compare("client_update_interval") == 0) - { - ClientUpdateInterval = atoi(value.c_str()); - } - else if (key.compare("server") == 0) - { - ServerEntry server(value); - servers.push_back(server); - } - else if (key.compare("welcome_msg") == 0) - { - WelcomeMsg = value; - } - else if (key.compare("config_downloaded_msg") == 0) - { - ConfigLoadedMsg = value; - } - else if (key.compare("top_panel_text") == 0) - { - TopPanelText = value; - } - else if (key.compare("bottom_panel_text") == 0) - { - BottomPanelText = value; - } - else if (key.compare("speed_visibility") == 0) - { - IsSpeedVisible = false; - if (value.compare("1") == 0) - { - IsSpeedVisible = true; - } - } - else - { - Logger::Warn("Unrecognized config option: %s\n", key.c_str()); - } + configFile.read(str, str_size); + config += str; } - - configUpdateTimer = new QTimer; - configUpdateTimer->setInterval(updateInterval * 1000); - connect(configUpdateTimer, SIGNAL(timeout()), - this, SLOT(updateConfig())); - - client = new SslClient(QString::fromStdString(servers[0].host)); - connect(client, SIGNAL(ReplyRecieved(SslClient::RequestType&, QByteArray&)), - this, SLOT(gotServerReply(SslClient::RequestType&, QByteArray&))); - client->SendRequest(SslClient::Config); + ParseConfig(str); } void Config::AcquireConfig() { /* reset existing values */ - configValid = false; genericProxy.clear(); staticProxy.clear(); /* read new values */ - if (ReadGenericProxy()) - return ; - if (ReadStaticProxy()) - return ; - configValid = true; -} - -bool Config::IsConfigValid() -{ - return configValid; + ReadGenericProxy(); + ReadStaticProxy(); } vector<string> Config::GetCountries() @@ -233,86 +154,180 @@ unsigned Config::GetStaticProxyGuiLines() return maxLine; } -int Config::ReadGenericProxy() + +void Config::ParseConfig(string data) +{ + stringstream config(data, ios_base::in); + + const int str_size = 512; + char str[str_size] = {0}; + while (! config.eof()) + { + config.getline(str, str_size, ';'); + config.ignore(2, '\n'); + if (config.eof()) + break; + string entry = str; + size_t eqpos = entry.find('='); + if (eqpos == string::npos) + { + Logger::Warn("No '=' at the config line: %s\n", entry.c_str()); + continue; + } + string key = entry.substr(0, eqpos); + string value = entry.substr(eqpos+1); + Logger::Trace("Found option: %s = %s\n", key.c_str(), value.c_str()); + if (key.compare("config_update_interval") == 0) + { + updateInterval = atoi(value.c_str()); + } + else if (key.compare("client_update_interval") == 0) + { + ClientUpdateInterval = atoi(value.c_str()); + } + else if (key.compare("server") == 0) + { + ServerEntry server(value); + servers.push_back(server); + } + else if (key.compare("welcome_msg") == 0) + { + WelcomeMsg = value; + } + else if (key.compare("config_downloaded_msg") == 0) + { + ConfigLoadedMsg = value; + } + else if (key.compare("top_panel_text") == 0) + { + TopPanelText = value; + } + else if (key.compare("bottom_panel_text") == 0) + { + BottomPanelText = value; + } + else if (key.compare("speed_visibility") == 0) + { + IsSpeedVisible = false; + if (value.compare("1") == 0) + { + IsSpeedVisible = true; + } + } + else + { + Logger::Warn("Unrecognized config option: %s\n", key.c_str()); + } + } +} + +void Config::ParseGenericProxies(string data) +{ + stringstream proxies(data, ios_base::in); + + const int str_size = 512; + char str[str_size] = {0}; + while (! proxies.eof()) + { + proxies.getline(str, str_size, ';'); + proxies.ignore(2, '\n'); + if (proxies.eof()) + break; + string entry = str; + ProxyEntryGeneric *proxy = new ProxyEntryGeneric; + proxy->Parse(entry); + genericProxy.push_back(*proxy); + } +} + +void Config::ParseStaticPorxies(string data) +{ + stringstream proxies(data, ios_base::in); + + const int str_size = 512; + char str[str_size] = {0}; + while (! proxies.eof()) + { + proxies.getline(str, str_size, ';'); + proxies.ignore(2, '\n'); + if (proxies.eof()) + break; + string entry = str; + ProxyEntryStatic *proxy = new ProxyEntryStatic; + proxy->Parse(entry); + staticProxy.push_back(*proxy); + } +} + +void Config::ParseFirewalls(string data) +{ + +} + + +/** + * @todo remove Config::ReadGenericProxy method + */ +void Config::ReadGenericProxy() { Logger::Info("Parsing generic proxy list\n"); string filname = QCoreApplication::applicationDirPath().toStdString() + "/config/proxy_list.cfg"; ifstream proxyFile(filname.c_str(), std::ios::in); - if (!proxyFile) + if (! proxyFile) { Logger::Error("Can't open file %s\n", filname.c_str()); - return -1; + return; } - + + string proxies = ""; const int str_size = 512; char str[str_size] = {0}; while (!proxyFile.eof()) { - proxyFile.getline(str, str_size, ';'); - proxyFile.ignore(2, '\n'); - if (proxyFile.eof()) - break; - string entry = str; - ProxyEntryGeneric *proxy = new ProxyEntryGeneric; - proxy->Parse(entry); - genericProxy.push_back(*proxy); + proxyFile.read(str, str_size); + proxies += str; } proxyFile.close(); - return 0; + + ParseGenericProxies(proxies); } -int Config::ReadStaticProxy() +/** + * @todo remove Config::ReadStaticProxy method + */ +void Config::ReadStaticProxy() { Logger::Info("Parsing static proxy list\n"); string filename = QCoreApplication::applicationDirPath().toStdString() + "/config/static_proxy_list.cfg"; ifstream proxyFile(filename.c_str(), std::ios::in); - if (!proxyFile) + if (! proxyFile) { Logger::Error("Can't open file %s\n", filename.c_str()); - return -1; + return; } + string proxies = ""; const int str_size = 512; char str[str_size] = {0}; while (!proxyFile.eof()) { - proxyFile.getline(str, str_size, ';'); - proxyFile.ignore(2, '\n'); - if (proxyFile.eof()) - break; - string entry = str; - ProxyEntryStatic *proxy = new ProxyEntryStatic; - proxy->Parse(entry); - staticProxy.push_back(*proxy); + proxyFile.read(str, str_size); + proxies += str; } proxyFile.close(); - return 0; -} - -void Config::updateConfig() -{ - Logger::Trace("Going to update entire configuration\n"); - /** - * @todo Count retries and switch between server records - */ -} - -void Config::gotServerReply(SslClient::RequestType &type, QByteArray &confdata) -{ - Logger::Trace("Got server reply w type: %x\n", type); - Logger::Trace("%s\n", confdata.data()); + ParseStaticPorxies(proxies); } /*** * Nested class section */ -Config::ServerEntry::ServerEntry(): host("127.0.0.1"), timeout(120), retry(60) +Config::ServerEntry::ServerEntry(): host("127.0.0.1"), timeout(120), retryTimeout(60) { } @@ -320,7 +335,7 @@ Config::ServerEntry::ServerEntry(string entry) { ServerEntry(); - /* processing string: "8.8.8.8 600 60" */ + /* processing server entry e.g.: "8.8.8.8 600 60" */ size_t start = 0, end = 0; end = entry.find(' '); host = entry.substr(start, end); @@ -329,5 +344,5 @@ Config::ServerEntry::ServerEntry(string entry) timeout = atoi(entry.substr(start, end).c_str()); start = end+1; end = entry.find(' '); - retry = atoi(entry.substr(start, end).c_str()); + retryTimeout = atoi(entry.substr(start, end).c_str()); } diff --git a/client/Config.h b/client/Config.h index 11bed90..8640d1e 100644 --- a/client/Config.h +++ b/client/Config.h @@ -4,16 +4,11 @@ #define CONFIG_H #include <client.h> -#include <QObject> #include "Proxy.h" -#include <SslClient.h> using std::vector; using std::string; -class SslClient; -class QTimer; - /** * @brief Singleton class that represents client configuration<br/> * At the first time this object is accessed config.cfg is read to @@ -21,9 +16,8 @@ class QTimer; * Then retries is made to connect to server and acqire actual config, * firewall list, etc. */ -class Config: public QObject +class Config { - Q_OBJECT public: /** * @brief Class to represent 'firewall' record in the config file @@ -46,12 +40,6 @@ public: }; /** - * @brief Retrieve application-wide instance of Config class - * @return Pointer to singleton instance of Config class - */ - static Config *CurrentConfig(); - - /** * @brief Time between consecutive program updates */ unsigned ClientUpdateInterval; @@ -168,8 +156,6 @@ public: */ const unsigned StaticProxySpeedLow; protected: - Config(); -private: /** * @brief Class to represend 'server' record in the config file */ @@ -203,39 +189,27 @@ private: /** * @brief Time (in seconds) between consecutive retries */ - unsigned retry; + unsigned retryTimeout; }; /** - * @brief Pointer to the singleton Config instance - */ - static Config *self; - - /** - * @brief time interval between consequtive config updates + * @brief create new instance (not allowed for use by other classes and functions) */ - unsigned updateInterval; + Config(); - /** - * @brief SslCLient instance that connects to server and retrieves config - */ - SslClient *client; + void ParseConfig(string data); + void ParseGenericProxies(string data); + void ParseStaticPorxies(string data); + void ParseFirewalls(string data); - /** - * @brief timer that is responsible on config updates - */ - QTimer *configUpdateTimer; - bool configValid; + unsigned updateInterval; + vector<ServerEntry> servers; +private: vector<ProxyEntryGeneric> genericProxy; vector<ProxyEntryStatic> staticProxy; vector<FirewallEntry> firewalls; - vector<ServerEntry> servers; - int ReadGenericProxy(); - int ReadStaticProxy(); -private slots: - void updateConfig(); - void gotServerReply(SslClient::RequestType &type, QByteArray &confdata); + void ReadGenericProxy(); + void ReadStaticProxy(); }; - #endif
\ No newline at end of file diff --git a/client/Dialog.cpp b/client/Dialog.cpp index 45ef01b..3a7f473 100644 --- a/client/Dialog.cpp +++ b/client/Dialog.cpp @@ -3,7 +3,7 @@ #include <iostream> #include <sstream> #include "client.h" -#include "Config.h" +#include "UpdatedConfig.h" #include "Dialog.h" #include "Proxy.h" @@ -12,13 +12,8 @@ using namespace std; ProxyDialog::ProxyDialog(QWidget *parent): QDialog(parent) { //WIPE it out!!! COnfig shoud be reread by timer event! - Config *cfg = Config::CurrentConfig(); + UpdatedConfig *cfg = UpdatedConfig::CurrentConfig(); cfg->AcquireConfig(); - if (! cfg->IsConfigValid()) - { - Logger::Fatal((string)"No valid configuration found! Can't proceed."); - return ; - } /* generic proxy panel */ topLabel = new QLabel(QString::fromLocal8Bit(cfg->TopPanelText.c_str())); @@ -109,7 +104,7 @@ void ProxyDialog::CountryActivated(int index) string country(countryBox->currentText().toUtf8().constData()); Logger::Info("Country %s was selected\n", country.c_str()); - Config *cfg = Config::CurrentConfig(); + UpdatedConfig *cfg = UpdatedConfig::CurrentConfig(); vector<string> states = cfg->GetStates(country); if (states.empty()) { @@ -152,7 +147,7 @@ void ProxyDialog::StateActivated(int index) string state(stateBox->currentText().toUtf8().constData()); Logger::Info("State %s was selected\n", state.c_str()); - Config *cfg = Config::CurrentConfig(); + UpdatedConfig *cfg = UpdatedConfig::CurrentConfig(); vector<string> cities = cfg->GetCities(country, state); cityBox->clear(); for (unsigned i = 0; i < cities.size(); i++) @@ -174,7 +169,7 @@ void ProxyDialog::CityActivated(int index) } vector<string> proxies; - Config *cfg = Config::CurrentConfig(); + UpdatedConfig *cfg = UpdatedConfig::CurrentConfig(); string country(countryBox->currentText().toUtf8().constData()); string city(cityBox->currentText().toUtf8().constData()); if (stateBox->isVisible()) diff --git a/client/ProxyClientApp.cpp b/client/ProxyClientApp.cpp index 8f06473..9d1b797 100755 --- a/client/ProxyClientApp.cpp +++ b/client/ProxyClientApp.cpp @@ -5,9 +5,13 @@ #include "client.h" #include "Dialog.h" #include "ProxyClientApp.h" +#include "UpdatedConfig.h" ProxyClientApp::ProxyClientApp(int &argc, char *argv[]): QApplication(argc, argv) { + /* initiates UpdatedConfig singleton that start sending configuration requests */ + UpdatedConfig *cfg = UpdatedConfig::CurrentConfig(); + if (!QSystemTrayIcon::isSystemTrayAvailable()) { Logger::Fatal("No system tray available! Terminating.\n"); diff --git a/client/SslClient.cpp b/client/SslClient.cpp index 831a1f3..6d13369 100644 --- a/client/SslClient.cpp +++ b/client/SslClient.cpp @@ -38,7 +38,12 @@ SslClient::SslClient(QString addr): port(13666) sslSocket.setLocalCertificate(cert); sslSocket.setPrivateKey(key); sslSocket.setCaCertificates(ca_certs); + +#ifdef DEBUG sslSocket.setPeerVerifyMode(QSslSocket::VerifyNone); +#else + sslSocket.setPeerVerifyMode(QSslSocket::VerifyPeer); +#endif sslSocket.setProtocol(QSsl::SslV3); /* setup signal handlers */ @@ -69,6 +74,10 @@ void SslClient::SendRequest(RequestType type) Logger::Trace("Connecting to server %s:%u\n", server.toLocal8Bit().data(), port); sslSocket.connectToHostEncrypted(server, port); } + else + { + Logger::Trace("Already connected to %s:%u\n", server.toLocal8Bit().data(), port); + } unsigned char rcode = 0x00; switch (type) @@ -106,14 +115,21 @@ void SslClient::DataRecieved() { Logger::Trace("Recieved reply from %s\n", server.toStdString().c_str()); QByteArray data = sslSocket.readAll(); - int length = data.size(); + if (length < 6) + { + Logger::Error("Server packet too short. Aborting.\n"); + return; + } + char h1 = data[0]; char h2 = data[1]; - char t1 = data[length-1]; - char t2 = data[length]; + char t1 = data[length-3]; + char t2 = data[length-2]; + char t3 = data[length-1]; + if ((h1 != 0x13) || (h2 != 0x13) || - (t1 != 0x14) || (t2 != 0x14)) + (t1 != 0x14) || (t2 != 0x14) || (t3 != 0x00)) { Logger::Error("Invalid data packet recieved!\n"); return; @@ -136,7 +152,7 @@ void SslClient::DataRecieved() /* remove header and tail */ data.remove(0, 3); - data.remove(length-1, 2); + data.remove(length-1, 3); emit ReplyRecieved(type, data); } @@ -208,6 +224,7 @@ void SslClient::Error(QAbstractSocket::SocketError e) } Logger::Fatal("Socket error! ( %s)\n", desc.toLocal8Bit().data()); + emit ConnectionError(); } void SslClient::PeerVerifyError(const QSslError &error) @@ -219,7 +236,7 @@ void SslClient::PeerVerifyError(const QSslError &error) case QSslError::UnspecifiedError: case QSslError::AuthorityIssuerSerialNumberMismatch: Logger::Fatal("Critical peer verify error!, Aborting connection\n" - "Error description: %s", + "Error description: %s\n", error.errorString().toStdString().c_str()); sslSocket.abort(); break; diff --git a/client/SslClient.h b/client/SslClient.h index d99fd47..4c91da3 100644 --- a/client/SslClient.h +++ b/client/SslClient.h @@ -83,6 +83,11 @@ signals: * @param type of request this reply corresponds to */ void ReplyRecieved(SslClient::RequestType &type, QByteArray &confdata); + + /** + * @brief This ssignal is emited when data request can't be completed + */ + void ConnectionError(); private slots: void Connected(); void Disconnected(); diff --git a/client/UpdatedConfig.cpp b/client/UpdatedConfig.cpp new file mode 100644 index 0000000..a08d417 --- /dev/null +++ b/client/UpdatedConfig.cpp @@ -0,0 +1,134 @@ + +#include <QTimer> +#include "UpdatedConfig.h" + + +UpdatedConfig* UpdatedConfig::self = NULL; + +UpdatedConfig *UpdatedConfig::CurrentConfig() +{ + if (self == NULL) + self = new UpdatedConfig(); + return self; +} + +UpdatedConfig::UpdatedConfig() +{ + activeSrvIndex = 0; + time = 0; + retryFailed = false; + + client = new SslClient(QString::fromStdString(servers[0].host)); + connect(client, SIGNAL(ReplyRecieved(SslClient::RequestType&, QByteArray&)), + this, SLOT(gotServerReply(SslClient::RequestType&, QByteArray&))); + connect(client, SIGNAL(ConnectionError()), + this, SLOT(connectionError())); + + configUpdateTimer = new QTimer; + configUpdateTimer->setInterval(servers[activeSrvIndex].retryTimeout * 1000); + connect(configUpdateTimer, SIGNAL(timeout()), + this, SLOT(update())); + configUpdateTimer->stop(); + + update(); +} + +void UpdatedConfig::update() +{ + Logger::Trace("Going to update configuration\n"); + + if (retryFailed) + { + /* count retries and switch between server records */ + time += servers[activeSrvIndex].retryTimeout; + Logger::Trace("Previous connection attempt failed or there were connection problems\n"); + if (time >= servers[activeSrvIndex].timeout) + { + time = 0; + activeSrvIndex++; + if (activeSrvIndex == servers.size()) + { + activeSrvIndex = 0; + } + } + retryFailed = false; + } + + /*if (! (updateStatus & SslClient::Config)) + { + client->SendRequest(SslClient::Config); + } + else*/ + if (! (updateStatus & SslClient::GenericProxyList)) + { + client->SendRequest(SslClient::GenericProxyList); + } + else if (! (updateStatus & SslClient::StaticProxyList)) + { + client->SendRequest(SslClient::StaticProxyList); + } + else if (! (updateStatus & SslClient::FirewallList)) + { + client->SendRequest(SslClient::FirewallList); + } + else + { + Logger::Warn("Unknown config update status: %x\n", updateStatus); + } +} + +void UpdatedConfig::connectionError() +{ + retryFailed = true; + Logger::Trace("Connection error. Starting reconnection timer\n"); + + /* start update timer (the case if working server is no longer responding) */ + if (! configUpdateTimer->isActive()) + { + time = 0; + configUpdateTimer->start(); + } +} + +void UpdatedConfig::gotServerReply(SslClient::RequestType &type, QByteArray &confdata) +{ + Logger::Trace("Got server reply w type: %x\n", type); + if (confdata.size() == 0) + { + Logger::Warn("Empty server reply recieved"); + goto end; + } + + /* stop timer - working server found */ + configUpdateTimer->stop(); + + switch (type) + { + case SslClient::Config: + ParseConfig(confdata.constData()); + updateStatus |= type; + break; + case SslClient::GenericProxyList: + ParseGenericProxies(confdata.constData()); + updateStatus |= type; + break; + case SslClient::StaticProxyList: + ParseStaticPorxies(confdata.constData()); + updateStatus |= type; + break; + case SslClient::FirewallList: + ParseFirewalls(confdata.constData()); + updateStatus |= type; + break; + default: + Logger::Warn("Unknown reply type: %x\n", type); + break; + } + +end: + if ((updateStatus & 0x0F) != 0x0F) + { + Logger::Trace("Still need to update other config parts\n"); + update(); + } +}
\ No newline at end of file diff --git a/client/UpdatedConfig.h b/client/UpdatedConfig.h new file mode 100644 index 0000000..669c126 --- /dev/null +++ b/client/UpdatedConfig.h @@ -0,0 +1,72 @@ + +#ifndef UPDATED_CONFIG_H +#define UPDATED_CONFIG_H + +#include <QObject> +#include "Config.h" +#include "SslClient.h" + +class QTimer; + +class UpdatedConfig: public QObject, public Config +{ + Q_OBJECT +public: + + /** + * @brief Retrieve application-wide instance of Config class + * @return Pointer to singleton instance of Config class + */ + static UpdatedConfig *CurrentConfig(); +private: + UpdatedConfig(); + + /** + * @brief Pointer to the singleton Config instance + */ + static UpdatedConfig *self; + + /** + * @brief SslCLient instance that connects to server and retrieves config + */ + SslClient *client; + + /** + * @brief timer that is responsible on config updates + */ + QTimer *configUpdateTimer; + + /** + * @brief bool value that is true if config is actual and was updated recently<br/> + * and false if it isn't actual and has to be updated + */ + bool configValid; + + /** + * @brief Count time between subsequent request retries + */ + unsigned time; + + /** + * @brief index of Config::servers that is currently being tried to connect or being worked with + */ + unsigned activeSrvIndex; + + /** + * @brief value indicating whether last connetion attempt failed or not + */ + bool retryFailed; + + /** + * @brief value indicating which config parts are already updated<br/> + * to check if some part is updated just apply && to this<br/> + * value and any of SslClient::RequestType values + */ + unsigned char updateStatus; +private slots: + void update(); + void connectionError(); + void gotServerReply(SslClient::RequestType &type, QByteArray &confdata); +}; + +#endif
\ No newline at end of file diff --git a/client/client.pro b/client/client.pro index 1e6185e..16de7f0 100755 --- a/client/client.pro +++ b/client/client.pro @@ -19,6 +19,7 @@ HEADERS += client.h \ ProxyClientApp.h \
Logger.h \
Config.h \
+ UpdatedConfig.h \
SslClient.h
SOURCES += Dialog.cpp \
@@ -27,6 +28,7 @@ SOURCES += Dialog.cpp \ ProxyClientApp.cpp \
Logger.cpp \
Config.cpp \
+ UpdatedConfig.cpp \
SslClient.cpp
OTHER_FILES +=
|