Browse Source

US42 (former US39): GUI CLI Multisession

Wach, Tobias Alexander 4 years ago
parent
commit
96c60c3803
7 changed files with 179 additions and 150 deletions
  1. 1 1
      gui/CMakeLists.txt
  2. 18 0
      gui/include/climanager.h
  3. 0 4
      gui/include/qmlhandler.h
  4. 134 0
      gui/src/climanager.cpp
  5. 3 6
      gui/src/cmdmanager.cpp
  6. 3 2
      gui/src/main.cpp
  7. 20 137
      gui/src/qmlhandler.cpp

+ 1 - 1
gui/CMakeLists.txt

@@ -16,7 +16,7 @@ pkg_check_modules(JSONCPP REQUIRED jsoncpp)
 
 add_definitions(-DQT_NO_DEBUG_OUTPUT)
 
-add_executable(${PROJECT_NAME} src/main.cpp src/cmdmanager.cpp src/qmlhandler.cpp src/jsonhandler.cpp src/qml.qrc src/config.cpp include/qmlhandler.h)
+add_executable(${PROJECT_NAME} src/main.cpp src/cmdmanager.cpp src/qmlhandler.cpp src/jsonhandler.cpp src/qml.qrc src/config.cpp src/climanager.cpp include/qmlhandler.h)
 
 include_directories(${Boost_INCLUDE_DIR} ${JSONCPP_INCLUDEDIR} include)
 target_link_libraries(${PROJECT_NAME} PRIVATE ${CMAKE_THREAD_LIBS_INIT} ${JSONCPP_LIBRARIES} ${Boost_LIBRARIES} Qt5::Core Qt5::Quick)

+ 18 - 0
gui/include/climanager.h

@@ -0,0 +1,18 @@
+#ifndef CLIMANAGER_H
+#define CLIMANAGER_H
+
+#include "config.h"
+#include "qmlhandler.h"
+#include <QGuiApplication>
+
+namespace CliManager {
+void setQmlHandler(QMLHandler *q);
+
+void startCli();
+void writeToCli(QString s);
+void readPipeLoop();
+void onExit();
+void setProgramActive(bool active);
+} // namespace CliManager
+
+#endif // CLIMANAGER_H

+ 0 - 4
gui/include/qmlhandler.h

@@ -10,16 +10,12 @@ class QMLHandler : public QObject {
 	Q_OBJECT
 
 private:
-	void readPipeLoop();
 	void fileExists(std::string name);
 
 public:
 	explicit QMLHandler(QObject *parent = 0);
 	void onExit();
-	void setProgramActive(bool active);
-	void reopenCLI(QString ip);
 	void closeCLI();
-	void writeToCLI(QString command);
 	void loadSettingsToGUI();
 	QString getIP();
 	void setRestart(bool restart);

+ 134 - 0
gui/src/climanager.cpp

@@ -0,0 +1,134 @@
+#include <QDebug>
+#include <QGuiApplication>
+
+#include <csignal>
+#include <cstdio>
+#include <cstdlib>
+#include <iostream>
+#include <poll.h>
+#include <string>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <thread>
+#include <unistd.h>
+
+#include <boost/asio.hpp>
+#include <boost/filesystem.hpp>
+#include <boost/lexical_cast.hpp>
+#include <iostream>
+#include <json/json.h>
+
+#include "../include/climanager.h"
+#include "../include/jsonhandler.h"
+
+using namespace std;
+
+namespace CliManager {
+QMLHandler *qmlHandler;
+bool programActive = true;
+int inpipefd[2];
+int outpipefd[2];
+
+char buf[1025];
+pid_t childpid;
+
+} // namespace CliManager
+
+void CliManager::writeToCli(QString command) {
+	command += "\n";
+	write(outpipefd[1], command.toUtf8().constData(), strlen(command.toUtf8().constData()));
+}
+
+void CliManager::onExit() { writeToCli("exit"); }
+
+void CliManager::setQmlHandler(QMLHandler *q) { qmlHandler = q; }
+
+void CliManager::startCli() {
+	pipe(inpipefd);
+	pipe(outpipefd);
+
+	childpid = fork();
+	if (childpid == 0) {
+		// Child
+		dup2(outpipefd[0], STDIN_FILENO);
+		dup2(inpipefd[1], STDOUT_FILENO);
+		// dup2(inpipefd[1], STDERR_FILENO);
+
+		// ask kernel to deliver SIGTERM in case the parent dies
+		prctl(PR_SET_PDEATHSIG, SIGTERM);
+
+		execl(Config::getValue("CLI-Path").c_str(), "ccats-cli", "--machine", (char *)NULL);
+
+		exit(1);
+	}
+
+	close(outpipefd[0]);
+	close(inpipefd[1]);
+	std::thread(&CliManager::readPipeLoop).detach();
+}
+
+std::vector<std::string> tokenizeByNewlines(std::string in) {
+	vector<string> res;
+	size_t index;
+	for (index = in.find("\n"); index != std::string::npos; index = in.find("\n")) {
+		if (index != 0)
+			res.push_back(in.substr(0, index));
+		in = in.substr(index + 1);
+	}
+	if (in.length() > 0)
+		res.push_back(in);
+	return res;
+}
+
+void CliManager::readPipeLoop() {
+	unsigned int readOffset = 0;
+	unsigned int pollCount = 0;
+	struct pollfd inPipeStatus;
+	inPipeStatus.fd = inpipefd[0];
+	inPipeStatus.events = POLLIN;
+	vector<string> inputs;
+	string pipeInput;
+
+	while (programActive) {
+		inputs = vector<string>();
+		poll(&inPipeStatus, 1, 100);
+
+		if (inPipeStatus.revents & POLLIN) {
+			readOffset += read(inpipefd[0], buf + readOffset, 1);
+			pollCount = 0;
+
+		} else {
+			pollCount++;
+		}
+
+		if (pollCount > 4 && (readOffset || pipeInput.size())) {
+			pipeInput.append(buf);
+			inputs = tokenizeByNewlines(pipeInput);
+			for (string s : inputs) {
+				emit qmlHandler->log(QString::fromStdString(s));
+				qInfo() << QString::fromStdString(s);
+				// handleJSON(s);
+				JsonHandler::parseJSON(s);
+			}
+			pipeInput = string();
+			memset(buf, 0, 1025);
+			pollCount = 0;
+			readOffset = 0;
+			if (waitpid(childpid, NULL, WNOHANG)) {
+				// nonzero means error or childid has changed state
+				// for us that means child has exited -> CLI is dead
+				break;
+			}
+		}
+
+		if (readOffset >= 1024) {
+			pipeInput.append(buf);
+			readOffset = 0;
+			pollCount = 0;
+			memset(buf, 0, 1025);
+		}
+	}
+}
+
+void CliManager::setProgramActive(bool active) { programActive = active; }

+ 3 - 6
gui/src/cmdmanager.cpp

@@ -1,6 +1,7 @@
 #include <QDebug>
 #include <QGuiApplication>
 
+#include "../include/climanager.h"
 #include "../include/cmdmanager.h"
 #include "../include/config.h"
 #include <boost/asio.hpp>
@@ -39,7 +40,7 @@ void CmdManager::executeCmd(string cmd, Json::Value root) { cmdmap[cmd](root); }
 
 void CmdManager::handleStatus(Json::Value root) { emit qmlHandler->footerSetStatus(root["response"].asString().c_str()); }
 
-void CmdManager::handleClose(Json::Value root) { qmlHandler->setProgramActive(false); }
+void CmdManager::handleClose(Json::Value root) { CliManager::setProgramActive(false); }
 
 void CmdManager::handleList(Json::Value root) {
 	if (root["accept"] == true) {
@@ -58,7 +59,6 @@ void CmdManager::handleList(Json::Value root) {
 void CmdManager::handleConnect(Json::Value root) {
 	if (!root["accept"].asBool()) {
 		emit qmlHandler->ipPopupSetStatus(root["error"].asString().c_str());
-		qmlHandler->closeCLI();
 		emit qmlHandler->ipPopupEnableConnectButton();
 	}
 }
@@ -71,7 +71,6 @@ void CmdManager::handleVersion(Json::Value root) {
 		QString errorMessage =
 		    QString::fromStdString(string("Version mismatch: \nClient: " + root["clientversion"].asString() + "\nServer: " + root["serverversion"].asString()));
 		emit qmlHandler->ipPopupSetStatus(errorMessage);
-		qmlHandler->closeCLI();
 		emit qmlHandler->ipPopupEnableConnectButton();
 	}
 }
@@ -79,11 +78,10 @@ void CmdManager::handleVersion(Json::Value root) {
 void CmdManager::handleLogin(Json::Value root) {
 	if (root["accept"] == true) {
 		emit qmlHandler->loginSignupPopupClose();
-		qmlHandler->writeToCLI("list\n");
+		CliManager::writeToCli("list");
 		qmlHandler->loadSettingsToGUI();
 	} else {
 		emit qmlHandler->loginSetStatus(root["error"].asString().c_str());
-		qmlHandler->reopenCLI(qmlHandler->getIP());
 		emit qmlHandler->loginEnableLoginButton();
 	}
 }
@@ -93,7 +91,6 @@ void CmdManager::handleSignup(Json::Value root) {
 		emit qmlHandler->loginSignupPopupClose();
 	} else {
 		emit qmlHandler->signupSetStatus(root["error"].asString().c_str());
-		qmlHandler->reopenCLI(qmlHandler->getIP());
 		emit qmlHandler->signupEnableRegisterButton();
 	}
 }

+ 3 - 2
gui/src/main.cpp

@@ -13,6 +13,7 @@
 #include <thread>
 #include <unistd.h>
 
+#include "../include/climanager.h"
 #include "../include/cmdmanager.h"
 #include "../include/jsonhandler.h"
 #include "../include/qmlhandler.h"
@@ -32,6 +33,7 @@ int main(int argc, char *argv[]) {
 	QMLHandler qmlHandler;
 	CmdManager::setQmlHandler(&qmlHandler);
 	CmdManager::init();
+	CliManager::setQmlHandler(&qmlHandler);
 
 	// Set the context for the window, so that the qml files can be connected to
 	// the qmlHandler
@@ -49,10 +51,9 @@ int main(int argc, char *argv[]) {
 
 	// If we land here, the window has been closed. Properly disconnect from the
 	// server now
-	qmlHandler.onExit();
+	CliManager::onExit();
 
 	if (_RESTART) {
-		// DO SHIT
 		pid_t pid = 0;
 		pid = fork();
 		if (pid == 0) {

+ 20 - 137
gui/src/qmlhandler.cpp

@@ -12,6 +12,7 @@
 #include <thread>
 #include <unistd.h>
 
+#include "../include/climanager.h"
 #include "../include/config.h"
 #include "../include/jsonhandler.h"
 #include "../include/qmlhandler.h"
@@ -26,22 +27,11 @@ using boost::asio::buffer;
 
 using namespace std;
 
-int inpipefd[2];
-int outpipefd[2];
-
-char buf[1025];
 QUrl sendFileUrl = QUrl("");
-QString _IP = "";
-bool _CLI_RUNNING = false;
 bool _RESTART = false;
-pid_t childpid;
-
-bool programActive = true;
 
 QMLHandler::QMLHandler(QObject *parent) : QObject(parent) {}
 
-void QMLHandler::closeCLI() { _CLI_RUNNING = false; }
-
 void QMLHandler::loadSettingsToGUI() {
 	int covertMethod = lexical_cast<int>(Config::getValue("Covert-Channel-Method"));
 	bool saveIP = lexical_cast<bool>(Config::getValue("Autofill-IP"));
@@ -50,111 +40,6 @@ void QMLHandler::loadSettingsToGUI() {
 	emit loadSettings(covertMethod, saveIP, saveUsername, cliPath);
 }
 
-void QMLHandler::reopenCLI(QString ip) {
-	if (_CLI_RUNNING) {
-		waitpid(childpid, NULL, 0);
-		closeCLI();
-	}
-
-	_IP = ip;
-
-	pipe(inpipefd);
-	pipe(outpipefd);
-
-	childpid = fork();
-	if (childpid == 0) {
-		// Child
-		dup2(outpipefd[0], STDIN_FILENO);
-		dup2(inpipefd[1], STDOUT_FILENO);
-		// dup2(inpipefd[1], STDERR_FILENO);
-
-		// ask kernel to deliver SIGTERM in case the parent dies
-		prctl(PR_SET_PDEATHSIG, SIGTERM);
-
-		// Set the path to the CLI - pass argument h (help) for now
-		// TODO: Change hardcoded path
-		// execl("../../cli/build/ccats-cli", "ccats-cli", ip.toUtf8().constData(), "--machine", (char *)NULL);
-		execl(Config::getValue("CLI-Path").c_str(), "ccats-cli", ip.toUtf8().constData(), "--machine", (char *)NULL);
-
-		exit(1);
-	}
-
-	_CLI_RUNNING = true;
-
-	close(outpipefd[0]);
-	close(inpipefd[1]);
-	std::thread(&QMLHandler::readPipeLoop, this).detach();
-}
-
-std::vector<std::string> tokenizeByNewlines(std::string in) {
-	vector<string> res;
-	size_t index;
-	for (index = in.find("\n"); index != std::string::npos; index = in.find("\n")) {
-		if (index != 0)
-			res.push_back(in.substr(0, index));
-		in = in.substr(index + 1);
-	}
-	if (in.length() > 0)
-		res.push_back(in);
-	return res;
-}
-
-void QMLHandler::onExit() { write(outpipefd[1], "disconnect\n", strlen("disconnect\n")); }
-
-// This method is a loop which runs in a seperate thread.
-// If will read the Input Pipe, which containts the string that get printed
-// on stdout by the CLI/Server, and calls handleJSON with the read content
-// one it reads a newline.
-void QMLHandler::readPipeLoop() {
-	unsigned int readOffset = 0;
-	unsigned int pollCount = 0;
-	struct pollfd inPipeStatus;
-	inPipeStatus.fd = inpipefd[0];
-	inPipeStatus.events = POLLIN;
-	vector<string> inputs;
-	string pipeInput;
-
-	while (programActive && _CLI_RUNNING) {
-		inputs = vector<string>();
-		poll(&inPipeStatus, 1, 100);
-
-		if (inPipeStatus.revents & POLLIN) {
-			readOffset += read(inpipefd[0], buf + readOffset, 1);
-			pollCount = 0;
-
-		} else {
-			pollCount++;
-		}
-
-		if (pollCount > 4 && (readOffset || pipeInput.size())) {
-			pipeInput.append(buf);
-			inputs = tokenizeByNewlines(pipeInput);
-			for (string s : inputs) {
-				emit log(QString::fromStdString(s));
-				qInfo() << QString::fromStdString(s);
-				// handleJSON(s);
-				JsonHandler::parseJSON(s);
-			}
-			pipeInput = string();
-			memset(buf, 0, 1025);
-			pollCount = 0;
-			readOffset = 0;
-			if (waitpid(childpid, NULL, WNOHANG)) {
-				// nonzero means error or childid has changed state
-				// for us that means child has exited -> CLI is dead
-				break;
-			}
-		}
-
-		if (readOffset >= 1024) {
-			pipeInput.append(buf);
-			readOffset = 0;
-			pollCount = 0;
-			memset(buf, 0, 1025);
-		}
-	}
-}
-
 // ### QML Handlers ###
 
 void QMLHandler::onStart() {
@@ -186,6 +71,8 @@ void QMLHandler::onStart() {
 		Config::setupDefaultConfig();
 		emit noConfigFoundPopupOpen();
 	}
+
+	CliManager::startCli();
 }
 
 // No Config Found Popup
@@ -219,8 +106,8 @@ void QMLHandler::onSendingSelectFileButton(QUrl url) {
 }
 
 void QMLHandler::onSendingSendFileButton() {
-	QString command = "put " + sendFileUrl.toString() + "\n";
-	write(outpipefd[1], command.toUtf8().constData(), strlen(command.toUtf8().constData()));
+	QString command = "put " + sendFileUrl.toString();
+	CliManager::writeToCli(command);
 }
 
 void QMLHandler::onSendingClearSelectionButton() {
@@ -231,16 +118,16 @@ void QMLHandler::onSendingClearSelectionButton() {
 }
 
 // Receiving
-void QMLHandler::onReceivingListFilesButton() { write(outpipefd[1], "list\n", strlen("list\n")); }
+void QMLHandler::onReceivingListFilesButton() { CliManager::writeToCli("list"); }
 
 void QMLHandler::onReceivingDownloadFileButton(QString fileName) {
-	QString command = "get " + fileName + "\n";
-	write(outpipefd[1], command.toUtf8().constData(), strlen(command.toUtf8().constData()));
+	QString command = "get " + fileName;
+	CliManager::writeToCli(command);
 }
 
 void QMLHandler::onReceivingConfirmDeleteFileButton(QString fileName) {
-	QString command = "deletefile " + fileName + "\n";
-	write(outpipefd[1], command.toUtf8().constData(), strlen(command.toUtf8().constData()));
+	QString command = "deletefile " + fileName;
+	CliManager::writeToCli(command);
 }
 
 // Messages
@@ -248,8 +135,8 @@ void QMLHandler::onMessagesSendButton(QString msg) { emit message(msg); }
 
 // Settings
 void QMLHandler::onSettingsDeleteMeButton(QString password) {
-	QString command = "deleteme " + password + "\n";
-	write(outpipefd[1], command.toUtf8().constData(), strlen(command.toUtf8().constData()));
+	QString command = "deleteme " + password;
+	CliManager::writeToCli(command);
 }
 
 void QMLHandler::onSettingsRevertChangesButton() {
@@ -276,7 +163,9 @@ void QMLHandler::onSettingsSaveButton(int covertMethod, bool saveIP, bool saveUs
 
 // Ip Popup
 void QMLHandler::onIpPopupConnectButton(QString ip, bool saveAsDefault) {
-	reopenCLI(ip);
+	QString command = "connect " + ip;
+	CliManager::writeToCli(command);
+
 	emit ipPopupDisableConnectButton();
 	if (saveAsDefault) {
 		Config::setValue("Default-IP", ip.toUtf8().constData());
@@ -287,8 +176,8 @@ void QMLHandler::onIpPopupConnectButton(QString ip, bool saveAsDefault) {
 
 // Login
 void QMLHandler::onLoginLoginButton(QString username, QString password, bool saveAsDefault) {
-	QString command = "login " + username + " " + password + "\n";
-	write(outpipefd[1], command.toUtf8().constData(), strlen(command.toUtf8().constData()));
+	QString command = "login " + username + " " + password;
+	CliManager::writeToCli(command);
 	emit loginDisableLoginButton();
 	if (saveAsDefault) {
 		Config::setValue("Default-Username", username.toUtf8().constData());
@@ -303,8 +192,8 @@ void QMLHandler::onSignupRegisterButton(QString username, QString passwordOne, Q
 		emit signupSetStatus("Passwords don't match");
 		return;
 	}
-	QString command = "signup " + username + " " + passwordOne + "\n";
-	write(outpipefd[1], command.toUtf8().constData(), strlen(command.toUtf8().constData()));
+	QString command = "signup " + username + " " + passwordOne;
+	CliManager::writeToCli(command);
 	emit signupDisableRegisterButton();
 	if (saveAsDefault) {
 		Config::setValue("Default-Username", username.toUtf8().constData());
@@ -314,12 +203,6 @@ void QMLHandler::onSignupRegisterButton(QString username, QString passwordOne, Q
 }
 
 // Footer
-void QMLHandler::onFooterGetStatusButton() { write(outpipefd[1], "status\n", strlen("status\n")); }
-
-void QMLHandler::setProgramActive(bool active) { programActive = active; }
-
-void QMLHandler::writeToCLI(QString command) { write(outpipefd[1], command.toUtf8().constData(), strlen(command.toUtf8().constData())); }
-
-QString QMLHandler::getIP() { return _IP; }
+void QMLHandler::onFooterGetStatusButton() { CliManager::writeToCli("status"); }
 
 void QMLHandler::setRestart(bool restart) { _RESTART = restart; }