diff options
Diffstat (limited to 'client')
-rw-r--r-- | client/Config.cpp | 33 | ||||
-rw-r--r-- | client/Config.h | 28 | ||||
-rw-r--r-- | client/DownloadClient.cpp | 110 | ||||
-rw-r--r-- | client/DownloadClient.h | 95 | ||||
-rw-r--r-- | client/FileOpThread.cpp | 63 | ||||
-rw-r--r-- | client/FileOpThread.h | 25 | ||||
-rw-r--r-- | client/ProxyClientApp.cpp | 8 | ||||
-rw-r--r-- | client/ProxyClientApp.h | 3 | ||||
-rw-r--r-- | client/SslClient.cpp | 31 | ||||
-rw-r--r-- | client/SslClient.h | 19 | ||||
-rw-r--r-- | client/UpdatedConfig.cpp | 12 | ||||
-rw-r--r-- | client/UpdatedConfig.h | 5 | ||||
-rw-r--r-- | client/client.pro | 8 |
13 files changed, 411 insertions, 29 deletions
diff --git a/client/Config.cpp b/client/Config.cpp index ba62ee0..21b2c44 100644 --- a/client/Config.cpp +++ b/client/Config.cpp @@ -44,10 +44,11 @@ void Config::FirewallEntry::Parse(string entry) /* * FileEntry nested class section */ -void Config::FileEntry::Parse(string entry, ActionType action) +void Config::FileEntry::Parse(string entry, ActionType _action) { Logger::Trace("Parsing file action %s\n", entry.c_str()); + action = _action; size_t start = 0, end = 0; if (action == DeleteAction) { @@ -66,8 +67,6 @@ void Config::FileEntry::Parse(string entry, ActionType action) { Logger::Error("Unknown FileEntry action!\n"); } - - Logger::Debug("path: %s, md5: %s\n", path.c_str(), md5.c_str()); } @@ -238,6 +237,30 @@ unsigned Config::GetStaticProxyGuiLines() return maxLine; } +vector<Config::FileEntry> Config::GetDeleteList() +{ + vector<FileEntry> delLst; + for (unsigned i = 0; i < fileActions.size(); i++) + { + if (fileActions[i].action == FileEntry::DeleteAction) + delLst.push_back(fileActions[i]); + } + + return delLst; +} + +vector<Config::FileEntry> Config::GetDownloadList() +{ + vector<FileEntry> downloadLst; + for (unsigned i = 0; i < fileActions.size(); i++) + { + if (fileActions[i].action == FileEntry::DownloadAction) + downloadLst.push_back(fileActions[i]); + } + + return downloadLst; +} + void Config::ParseConfig(string data) { @@ -366,9 +389,7 @@ void Config::ParseFirewalls(string data) } void Config::ParseDeleteList(string data) -{ - Logger::Debug("Delete list:\n%s", data.c_str()); - +{ //delete all entries with DeleteAction for (unsigned i = 0; i < fileActions.size(); i++) { diff --git a/client/Config.h b/client/Config.h index 2392898..466f93a 100644 --- a/client/Config.h +++ b/client/Config.h @@ -86,7 +86,7 @@ public: /** * @brief Extract and set instance variables from config line */ - void Parse(string entry, ActionType action); + void Parse(string entry, ActionType _action); }; /** @@ -127,14 +127,6 @@ public: void AcquireConfig(); /** - * @brief Check whether current confguration is valid <br/> - * It may become invalid in case if server is not reachable. - * So every time you want to access Config members or methods you should check this value - * @return true if configuration is valid and false otherwise - */ - bool IsConfigValid(); - - /** * @brief Get list of country names where at least one proxy available<br/> * (generic proxy records only) * @return Alphabetically sorted vector<string> with unique country names @@ -200,9 +192,21 @@ public: unsigned GetStaticProxyGuiLines(); /** - * Static proxy speed value limit.<br/> - * This value is used to determine speed label color. - * All speed value below this constant will be red, higher values will be green + * @brief Get list of files to be deleted + * @return List of FileEntry wrapper object that describe files that should be deleted + */ + vector<FileEntry> GetDeleteList(); + + /** + * @brief Get list of files to be downloaded + * @return List of FileEntry wrapper object that describe files that should be downloaded + */ + vector<FileEntry> GetDownloadList(); + + /** + * @brief Static proxy speed value limit.<br/> + * This value is used to determine speed label color. + * All speed value below this constant will be red, higher values will be green */ const unsigned StaticProxySpeedLow; protected: diff --git a/client/DownloadClient.cpp b/client/DownloadClient.cpp new file mode 100644 index 0000000..df4da25 --- /dev/null +++ b/client/DownloadClient.cpp @@ -0,0 +1,110 @@ + +#include <QtCore> +#include "DownloadClient.h" + + +DownloadClient::DownloadClient(): isDownloading(false), current(NULL), currentId(-1) +{ + connect(this, SIGNAL(ReplyRecieved(SslClient::RequestType&, QByteArray&)), + this, SLOT(FileDataRecieved(SslClient::RequestType&, QByteArray&))); +} + +DownloadClient::DownloadClient(QString addr): SslClient(addr), isDownloading(false), current(NULL), currentId(-1) +{ + DownloadClient(); +} + +void DownloadClient::Download(const string &filename) +{ + pair<string, string> file(filename, 0); + vector<pair<string, string> > fileList; + fileList.push_back(file); + Download(fileList); +} + +void DownloadClient::Download(const pair<string, string> &file) +{ + vector<pair<string, string> > fileList; + fileList.push_back(file); + Download(fileList); +} + +void DownloadClient::Download(const vector<pair<string, string> > &fileList) +{ + if (server.isEmpty()) + { + Logger::Error("Server address isn't set! Aborting.\n"); + return; + } + if (isDownloading) + { + Logger::Error("Previous downloading process wasn't finished! Aborting.\n"); + return; + } + isDownloading = true; + files = fileList; + DoDownload(); +} + +void DownloadClient::FileDataRecieved(SslClient::RequestType &type, QByteArray &data) +{ + if (type != RegularFile) + { + Logger::Error("Invalid reply recieved: %x\n", type); + return; + } + + if ((current != NULL) && (current->isOpen())) + { + Logger::Error("File is not open or invalid state\n"); + return; + } + + pair<string, string> file = files[currentId]; + string filename = file.first; + if (data.size() == FRAGMENT_SIZE) + { + Logger::Debug("data:\n %s", data.constData()); + current->write(data); + SendFileRequest(filename); + } + else + { + if (data.size() != 0) + { + Logger::Debug("data:\n %s", data.constData()); + current->write(data); + } + current->close(); + delete current; + current = NULL; + + /** + * @todo md5 hash check + */ + + DoDownload(); + } +} + +void DownloadClient::DoDownload() +{ + if (currentId < (int)files.size()) + { + currentId++; + pair<string, string> file = files[currentId]; + QString filename = QString::fromLocal8Bit(file.first.c_str()); + string md5 = file.second; + current = new QFile(filename); + current->open(QIODevice::ReadWrite); + + Logger::Info("Downloading file %s\n", file.first.c_str()); + SendFileRequest(file.first); + } + else + { + Logger::Info("All files have been downloaded."); + isDownloading = false; + emit downloadFinished(); + } +} diff --git a/client/DownloadClient.h b/client/DownloadClient.h new file mode 100644 index 0000000..5b75c2c --- /dev/null +++ b/client/DownloadClient.h @@ -0,0 +1,95 @@ + + +#ifndef DOWNLOAD_CLIENT_H +#define DOWNLOAD_CLIENT_H + +#include <string> +#include <vector> +#include <QObject> +#include "SslClient.h" + +using std::pair; +using std::string; +using std::vector; + +class QFile; + +class DownloadClient: public SslClient +{ +Q_OBJECT + +public: + /** + * @brief Initialize new DownloadClient instance + */ + DownloadClient(); + + /** + * @brief Initialize new DownloadClient instance + * @param addr server address or hostname to connect to + */ + DownloadClient(QString addr); + + /** + * @brief Download file from server + * @param file file path on client machine + */ + void Download(const string &file); + + /** + * @brief Download file from server + * @param file pair of file name and it's md5 hash value + */ + void Download(const pair<string, string> &file); + + /** + * @brief Download list of files + * @param files associative array of file names and it's md5 hashes + * @note this is designated method among all + * @todo It seems that std::map isn't best choice for this purpose + * it's quite unsuitable to iterate through( + */ + void Download(const vector<pair<string, string> > &files); + +signals: + /** + * @brief This signal is emitted when all files have been downloaded + */ + void downloadFinished(); + +private slots: + void FileDataRecieved(SslClient::RequestType &type, QByteArray &confdata); + +private: + /** + * @brief size of file data fragment + */ + static const int FRAGMENT_SIZE = 4096; + + /** + * @brief indicates that program is downloading file(s) right now + */ + bool isDownloading; + + /** + * @brief name of file that is being downloaded + */ + QFile *current; + + /** + * @brief index of file that is being downloaded + */ + int currentId; + + /** + * @brief List of file to + */ + vector<pair<string, string> > files; + + /** + * @brief start file-by-file downloading process + */ + void DoDownload(); +}; + +#endif diff --git a/client/FileOpThread.cpp b/client/FileOpThread.cpp new file mode 100644 index 0000000..42cb51b --- /dev/null +++ b/client/FileOpThread.cpp @@ -0,0 +1,63 @@ + +#include <QtCore> +#include "DownloadClient.h" +#include "FileOpThread.h" +#include "UpdatedConfig.h" + +void FileOpThread::run() +{ + UpdatedConfig *cfg = UpdatedConfig::CurrentConfig(); + + /* delete files */ + vector<Config::FileEntry> toDelete = cfg->GetDeleteList(); + for (unsigned i = 0; i < toDelete.size(); i++) + { + Logger::Trace("Deleting file: \"%s\"\n", toDelete[i].path.c_str()); + + QString path = QString::fromLocal8Bit(toDelete[i].path.c_str()); + QFile file(path); + QFileInfo fileInfo(file); + if (fileInfo.exists()) + { + file.remove(); + } + else + { + Logger::Info("File \"%s\" has already been deleted\n", toDelete[i].path.c_str()); + } + } + + /* download files */ + vector<pair<string, string> > files; + vector<Config::FileEntry> downloadList = cfg->GetDownloadList(); + for (unsigned i = 0; i < downloadList.size(); i++) + { + QString path = QString::fromLocal8Bit(downloadList[i].path.c_str()); + QFileInfo fileInfo(path); + if (fileInfo.exists()) + { + Logger::Info("File \"%s\" already exists\n", downloadList[i].path.c_str()); + /** + * @todo Compute md5 hash and check if they are the same + */ + } + else + { + pair<string, string> file = make_pair(downloadList[i].path, downloadList[i].md5); + files.push_back(file); + } + } + + if (files.size() != 0) + { + Logger::Debug("Setting server address to %s\n", cfg->GetServerAddr().c_str()); + + QString addr = QString::fromLocal8Bit(cfg->GetServerAddr().c_str()); + DownloadClient downloadClient(addr); + downloadClient.Download(files); + } + else + { + Logger::Trace("No files to download from server.\n"); + } +}
\ No newline at end of file diff --git a/client/FileOpThread.h b/client/FileOpThread.h new file mode 100644 index 0000000..29731c9 --- /dev/null +++ b/client/FileOpThread.h @@ -0,0 +1,25 @@ + + +#ifndef FILE_OP_THREAD_H +#define FILE_OP_THREAD_H + +#include <QThread> + +/** + * @brief Special thread to process all file operations + */ +class FileOpThread: public QThread +{ +public: + /** + * @brief Initialize new FIleOpThread instance + */ + FileOpThread() {} + + /** + * @brief Thread main loop + */ + void run(); +}; + +#endif
\ No newline at end of file diff --git a/client/ProxyClientApp.cpp b/client/ProxyClientApp.cpp index 4b233e5..94d8a7c 100644 --- a/client/ProxyClientApp.cpp +++ b/client/ProxyClientApp.cpp @@ -5,6 +5,7 @@ #include "client.h" #include "Dialog.h" +#include "FileOpThread.h" #include "ProxyClientApp.h" #include "UpdatedConfig.h" @@ -84,6 +85,9 @@ void ProxyClientApp::showProxyDialog() void ProxyClientApp::configUpdated() { + FileOpThread fileOpThread; + fileOpThread.start(QThread::NormalPriority); + UpdatedConfig *cfg = UpdatedConfig::CurrentConfig(); QString msg = QString::fromLocal8Bit(cfg->ConfigLoadedMsg.c_str()); QMessageBox updatedMsg; @@ -92,10 +96,6 @@ void ProxyClientApp::configUpdated() updatedMsg.setStandardButtons(QMessageBox::Ok); updatedMsg.setIcon(QMessageBox::Information); updatedMsg.exec(); - - /* delete files */ - - /* download files */ } void ProxyClientApp::quitApp() diff --git a/client/ProxyClientApp.h b/client/ProxyClientApp.h index 83c7c31..5dd0a69 100644 --- a/client/ProxyClientApp.h +++ b/client/ProxyClientApp.h @@ -10,13 +10,16 @@ class ProxyClientApp: public QApplication { Q_OBJECT + public: ProxyClientApp(int &argc, char *argv[]); + private slots: void trayActivated(QSystemTrayIcon::ActivationReason reason); void showProxyDialog(); void configUpdated(); void quitApp(); + private: QSystemTrayIcon *trayIcon; }; diff --git a/client/SslClient.cpp b/client/SslClient.cpp index b3a2d15..b1841ed 100644 --- a/client/SslClient.cpp +++ b/client/SslClient.cpp @@ -1,4 +1,5 @@ +#include <string.h> #include <QtCore> #include <QtNetwork> #include "SslClient.h" @@ -72,7 +73,8 @@ void SslClient::SendRequest(RequestType type) if (sslSocket.state() != QAbstractSocket::ConnectedState) { Logger::Trace("Connecting to server %s:%u\n", server.toLocal8Bit().data(), port); - sslSocket.connectToHostEncrypted(server, port); + //sslSocket.connectToHostEncrypted(server, port); + sslSocket.connectToHostEncrypted("127.0.0.1", port); } else { @@ -100,6 +102,33 @@ void SslClient::SendRequest(RequestType type) sslSocket.write(pkt); } +void SslClient::SendFileRequest(string filename) +{ + Logger::Trace("Sending request w code %x\n", RegularFile); + if (sslSocket.state() != QAbstractSocket::ConnectedState) + { + 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 = 0x12; + const char *file = filename.c_str(); + size_t path_len = strlen(file); + char data[path_len + 5]; + data[0] = data[1] = 0x13; + data[2] = rcode; + strncpy(data + 3, file, path_len); + data[path_len - 1] = data[path_len - 2] = 0x14; + + QByteArray pkt(data); + sslSocket.write(pkt); +} + + /* * Signal handlers */ diff --git a/client/SslClient.h b/client/SslClient.h index 8172bad..a6b981c 100644 --- a/client/SslClient.h +++ b/client/SslClient.h @@ -88,13 +88,13 @@ public: }; /** - * @brief setup ssl socket ans it's type, certificates and key<br/> + * @brief Setup ssl socket ans it's type, certificates and key<br/> * Default server address will be used: 127.0.0.1 */ SslClient(); /** - * @brief setup ssl socket ans it's type, certificates and key + * @brief Setup ssl socket and it's type, certificates and key * @param addr server address or hostname to connect to */ SslClient(QString addr); @@ -106,15 +106,22 @@ public: void SetServerAddr(QString addr); /** - * @brief Request generic proxy list + * @brief Send request to server * @param type type of request to send */ void SendRequest(RequestType type); /** + * @brief Send file data request (RequestType::RegularFile) + * @param File name on client machine (will be sent to server) + */ + void SendFileRequest(string filename); + + /** * @brief disconnect from server */ void Disconnect(); + signals: /** * @brief This signal is emited when data is recieved as a reply to @@ -128,6 +135,7 @@ signals: * @todo emit this signal on all SSL errors too */ void ConnectionError(); + private slots: void Connected(); void Disconnected(); @@ -135,9 +143,12 @@ private slots: void Error(QAbstractSocket::SocketError socketError); void PeerVerifyError(const QSslError &error); void SslErrors(const QList<QSslError> &errors); + +protected: + QString server; + private: QSslSocket sslSocket; - QString server; unsigned short port; }; diff --git a/client/UpdatedConfig.cpp b/client/UpdatedConfig.cpp index 6c69f12..a59bc67 100644 --- a/client/UpdatedConfig.cpp +++ b/client/UpdatedConfig.cpp @@ -12,6 +12,16 @@ UpdatedConfig *UpdatedConfig::CurrentConfig() return self; } +string UpdatedConfig::GetServerAddr() +{ + if (! configValid) + { + Logger::Error("No valid server records present!\n"); + return string(""); + } + return servers[activeSrvIndex].host; +} + UpdatedConfig::UpdatedConfig() { activeSrvIndex = 0; @@ -36,6 +46,7 @@ UpdatedConfig::UpdatedConfig() void UpdatedConfig::update() { Logger::Trace("Going to update configuration\n"); + configValid = false; if (retryFailed) { @@ -147,6 +158,7 @@ end: { Logger::Info("Config successfully updated!\n"); client->Disconnect(); + configValid = true; /* reset retry params and setup timer to fire on next planned update */ time = 0; diff --git a/client/UpdatedConfig.h b/client/UpdatedConfig.h index 5470d4d..2e4deac 100644 --- a/client/UpdatedConfig.h +++ b/client/UpdatedConfig.h @@ -26,6 +26,11 @@ public: */ static UpdatedConfig *CurrentConfig(); + /** + * @brief Get valid server address to communicate with + * @return address of server to communicate with ot empty string + */ + string GetServerAddr(); signals: /** * @brief Signal is emitted when client configuration is updated diff --git a/client/client.pro b/client/client.pro index 16de7f0..6520c5d 100644 --- a/client/client.pro +++ b/client/client.pro @@ -20,7 +20,9 @@ HEADERS += client.h \ Logger.h \
Config.h \
UpdatedConfig.h \
- SslClient.h
+ SslClient.h \
+ FileOpThread.h \
+ DownloadClient.h
SOURCES += Dialog.cpp \
main.cpp \
@@ -29,7 +31,9 @@ SOURCES += Dialog.cpp \ Logger.cpp \
Config.cpp \
UpdatedConfig.cpp \
- SslClient.cpp
+ SslClient.cpp \
+ FileOpThread.cpp \
+ DownloadClient.cpp
OTHER_FILES +=
|