Parcourir la source

Begin rework into allowing multiple server sessions from one CLI session
Can connect and disconnect multiple times from the same CLI session
Can not exit from CLI without Ctrl-C

Sander, Paul il y a 5 ans
Parent
commit
b5558de178

+ 1 - 1
cli/include/batchioman.h

@@ -76,7 +76,7 @@ public:
 	/**
 	/**
 	 * Constructor and destructor
 	 * Constructor and destructor
 	 */
 	 */
-	BatchIoMan(char *ipcstring, bool usessl, bool beverbose, string batchpath);
+	BatchIoMan(bool usessl, bool beverbose, string batchpath);
 	~BatchIoMan();
 	~BatchIoMan();
 
 
 	bool init();
 	bool init();

+ 9 - 2
cli/include/cmdman.h

@@ -29,7 +29,7 @@ public:
 	 * close	- terminate the connection
 	 * close	- terminate the connection
 	 * seton	- contextually change state, used for version check and login
 	 * seton	- contextually change state, used for version check and login
 	 */
 	 */
-	enum rettype { print = (1 << 0), send = (1 << 1), error = (1 << 2), close = (1 << 3), seton = (1 << 4) };
+	enum rettype { none = 0, print = (1 << 1), send = (1 << 2), error = (1 << 3), close = (1 << 4), connect = (1 << 5), exit = (1 << 6) };
 	/**
 	/**
 	 * Response to user or command input
 	 * Response to user or command input
 	 *
 	 *
@@ -61,6 +61,8 @@ public:
 	 */
 	 */
 	Json::CharReader *reader;
 	Json::CharReader *reader;
 
 
+	void stateSetConnectionOk();
+
 private:
 private:
 	/**
 	/**
 	 * internal json writer and error string member
 	 * internal json writer and error string member
@@ -91,7 +93,8 @@ private:
 	 * handlemap and to disallow the use of certain commands when logged in/not
 	 * handlemap and to disallow the use of certain commands when logged in/not
 	 * logged in.
 	 * logged in.
 	 */
 	 */
-	bool doversion, loginpossible, dologin, dosignup;
+	enum state { connectionpossible, versionpossible, doversion, loginpossible, dologin, dosignup, normal, disconnecttoexit, disconnecttoexitearly };
+	state currentState;
 
 
 	/**
 	/**
 	 * Help strings and method prototypes for commands to be used by a user
 	 * Help strings and method prototypes for commands to be used by a user
@@ -117,6 +120,10 @@ private:
 	CmdRet cmdKeyfile(vector<string> args);
 	CmdRet cmdKeyfile(vector<string> args);
 	const string descClosekey = "stop using the previously selected keyfile";
 	const string descClosekey = "stop using the previously selected keyfile";
 	CmdRet cmdClosekey(vector<string> args);
 	CmdRet cmdClosekey(vector<string> args);
+	const string descConnect = "connect to server";
+	CmdRet cmdConnect(vector<string> args);
+	const string descExit = "exit the application";
+	CmdRet cmdExit(vector<string> args);
 
 
 	const string descLogin = "login to the server";
 	const string descLogin = "login to the server";
 	CmdRet cmdLogin(vector<string> args);
 	CmdRet cmdLogin(vector<string> args);

+ 1 - 12
cli/include/ioman.h

@@ -59,16 +59,6 @@ protected:
 	virtual void printWelcomeMessage() = 0;
 	virtual void printWelcomeMessage() = 0;
 	virtual std::string getCmdPrompt() = 0;
 	virtual std::string getCmdPrompt() = 0;
 
 
-	/**
-	 * Enum for internal login and version state
-	 * Variables for keeping said state
-	 * Matching mutex and condition variable
-	 */
-	enum Status { off, on, err };
-	Status loginstatus;
-	Status versionstatus;
-	std::mutex initmutex;
-	std::condition_variable initcv;
 	bool connected;
 	bool connected;
 
 
 	virtual void handleInCmdResponse(CmdMan::CmdRet cmdret);
 	virtual void handleInCmdResponse(CmdMan::CmdRet cmdret);
@@ -136,8 +126,7 @@ public:
 	/**
 	/**
 	 * Constructor and destructor
 	 * Constructor and destructor
 	 */
 	 */
-	IoMan(char *ipcstring);
-	IoMan(char *ipcstring, bool enablessl);
+	IoMan(bool enablessl);
 	virtual ~IoMan();
 	virtual ~IoMan();
 
 
 	/**
 	/**

+ 1 - 1
cli/include/machineioman.h

@@ -14,7 +14,7 @@ private:
 	bool verbose;
 	bool verbose;
 
 
 public:
 public:
-	MachineIoMan(char *ipcstring, bool usessl, bool beverbose);
+	MachineIoMan(bool usessl, bool beverbose);
 
 
 protected:
 protected:
 	/**
 	/**

+ 1 - 1
cli/include/userioman.h

@@ -64,7 +64,7 @@ public:
 	/**
 	/**
 	 * Constructor and destructor
 	 * Constructor and destructor
 	 */
 	 */
-	UserIoMan(char *ipcstring, bool usessl, bool verbose);
+	UserIoMan(bool usessl, bool verbose);
 	~UserIoMan();
 	~UserIoMan();
 
 
 protected:
 protected:

+ 3 - 21
cli/src/batchioman.cpp

@@ -4,7 +4,7 @@
 #include <string>
 #include <string>
 #include <vector>
 #include <vector>
 
 
-BatchIoMan::BatchIoMan(char *ipcstring, bool usessl, bool beverbose, std::string batchpath) : IoMan(ipcstring, usessl) {
+BatchIoMan::BatchIoMan(bool usessl, bool beverbose, std::string batchpath) : IoMan(usessl) {
 	/* setup json stuff */
 	/* setup json stuff */
 	Json::CharReaderBuilder rbuilder;
 	Json::CharReaderBuilder rbuilder;
 	wbuilder.settings_["indentation"] = "";
 	wbuilder.settings_["indentation"] = "";
@@ -168,13 +168,6 @@ void BatchIoMan::handleOutCmdResponse(CmdMan::CmdRet cmdret, std::vector<std::st
 		return;
 		return;
 	}
 	}
 	if (cmdret.type & CmdMan::rettype::error) {
 	if (cmdret.type & CmdMan::rettype::error) {
-		initmutex.lock();
-		if (versionstatus == off)
-			versionstatus = err;
-		else if (loginstatus == off)
-			loginstatus = err;
-		initmutex.unlock();
-		initcv.notify_all();
 		printMessage(Json::writeString(wbuilder, cmdret.msg), error);
 		printMessage(Json::writeString(wbuilder, cmdret.msg), error);
 		mainmutex.lock();
 		mainmutex.lock();
 		runmain = false;
 		runmain = false;
@@ -187,15 +180,6 @@ void BatchIoMan::handleOutCmdResponse(CmdMan::CmdRet cmdret, std::vector<std::st
 		linecv.notify_all();
 		linecv.notify_all();
 		return;
 		return;
 	}
 	}
-	if (cmdret.type & CmdMan::rettype::seton) {
-		initmutex.lock();
-		if (versionstatus == off)
-			versionstatus = on;
-		else
-			loginstatus = on;
-		initmutex.unlock();
-		initcv.notify_all();
-	}
 	if (cmdret.type & CmdMan::rettype::print) {
 	if (cmdret.type & CmdMan::rettype::print) {
 		printMessage(Json::writeString(wbuilder, cmdret.msg), normal);
 		printMessage(Json::writeString(wbuilder, cmdret.msg), normal);
 	}
 	}
@@ -205,7 +189,7 @@ void BatchIoMan::handleOutCmdResponse(CmdMan::CmdRet cmdret, std::vector<std::st
 			toput.push_back(cmdret.nextcommand);
 			toput.push_back(cmdret.nextcommand);
 		}
 		}
 	}
 	}
-	if (versionstatus == on && !(cmdret.type & CmdMan::rettype::send)) {
+	if (!(cmdret.type & CmdMan::rettype::send)) {
 		// only fetch next line if we did not send a new command on our own
 		// only fetch next line if we did not send a new command on our own
 		// if we managed to get here, get next command from file
 		// if we managed to get here, get next command from file
 		linemutex.lock();
 		linemutex.lock();
@@ -241,7 +225,7 @@ void BatchIoMan::run() {
 		while (!line.size()) {
 		while (!line.size()) {
 			// skip empty lines until either eof or non-empty line
 			// skip empty lines until either eof or non-empty line
 			if (batchin.eof()) {
 			if (batchin.eof()) {
-				line = "disconnect";
+				line = "exit";
 			} else
 			} else
 				std::getline(batchin, line);
 				std::getline(batchin, line);
 		}
 		}
@@ -258,8 +242,6 @@ void BatchIoMan::run() {
 
 
 		if (!connected)
 		if (!connected)
 			break;
 			break;
-		if (loginstatus == err)
-			break;
 
 
 		mainmutex.lock();
 		mainmutex.lock();
 	}
 	}

+ 113 - 33
cli/src/cmdman.cpp

@@ -14,10 +14,7 @@ CmdMan::CmdMan(FileMan &fm, void (*dpf)(string)) : fileman(fm) {
 	wbuilder.settings_["indentation"] = "";
 	wbuilder.settings_["indentation"] = "";
 	reader = rbuilder.newCharReader();
 	reader = rbuilder.newCharReader();
 
 
-	doversion = false;
-	loginpossible = false;
-	dologin = false;
-	dosignup = false;
+	currentState = connectionpossible;
 
 
 	/* initialize execute command map */
 	/* initialize execute command map */
 	execmap["help"] = &CmdMan::cmdHelp;
 	execmap["help"] = &CmdMan::cmdHelp;
@@ -37,6 +34,8 @@ CmdMan::CmdMan(FileMan &fm, void (*dpf)(string)) : fileman(fm) {
 	execmap["deleteme"] = &CmdMan::cmdDeleteme;
 	execmap["deleteme"] = &CmdMan::cmdDeleteme;
 	execmap["keyfile"] = &CmdMan::cmdKeyfile;
 	execmap["keyfile"] = &CmdMan::cmdKeyfile;
 	execmap["closekey"] = &CmdMan::cmdClosekey;
 	execmap["closekey"] = &CmdMan::cmdClosekey;
+	execmap["connect"] = &CmdMan::cmdConnect;
+	execmap["exit"] = &CmdMan::cmdExit;
 
 
 	/* initialize description map */
 	/* initialize description map */
 	helpmap["help"] = descHelp;
 	helpmap["help"] = descHelp;
@@ -52,6 +51,8 @@ CmdMan::CmdMan(FileMan &fm, void (*dpf)(string)) : fileman(fm) {
 	helpmap["deleteme"] = descDeleteme;
 	helpmap["deleteme"] = descDeleteme;
 	helpmap["keyfile"] = descKeyfile;
 	helpmap["keyfile"] = descKeyfile;
 	helpmap["closekey"] = descClosekey;
 	helpmap["closekey"] = descClosekey;
+	helpmap["connect"] = descConnect;
+	helpmap["exit"] = descExit;
 
 
 	/* initialize handle command map */
 	/* initialize handle command map */
 	handlemap["status"] = &CmdMan::handleStatus;
 	handlemap["status"] = &CmdMan::handleStatus;
@@ -74,6 +75,8 @@ CmdMan::CmdMan(FileMan &fm, void (*dpf)(string)) : fileman(fm) {
 
 
 CmdMan::~CmdMan() { delete reader; }
 CmdMan::~CmdMan() { delete reader; }
 
 
+void CmdMan::stateSetConnectionOk() { currentState = versionpossible; }
+
 CmdMan::CmdRet CmdMan::cmdHelp(vector<string> args) {
 CmdMan::CmdRet CmdMan::cmdHelp(vector<string> args) {
 	CmdRet retval;
 	CmdRet retval;
 	Json::Value root, arr;
 	Json::Value root, arr;
@@ -105,13 +108,17 @@ CmdMan::CmdRet CmdMan::cmdDisconnect(vector<string> args) {
 	DEBUGPRINT(string(__PRETTY_FUNCTION__) + " begin");
 	DEBUGPRINT(string(__PRETTY_FUNCTION__) + " begin");
 	Json::Value root;
 	Json::Value root;
 	retval.type = send;
 	retval.type = send;
-	if (loginpossible) {
+	if (currentState == loginpossible || currentState == disconnecttoexitearly) {
 		// not logged in, send appropriate login message instead of normal close
 		// not logged in, send appropriate login message instead of normal close
 		root["login"] = false;
 		root["login"] = false;
 		root["user"] = "";
 		root["user"] = "";
 		root["pass"] = "";
 		root["pass"] = "";
 		root["cancel"] = true;
 		root["cancel"] = true;
 		retval.type |= close;
 		retval.type |= close;
+		if (currentState == disconnecttoexitearly) {
+			retval.nextcommand = "exit";
+		}
+		currentState = connectionpossible;
 	} else {
 	} else {
 		root["command"] = "close";
 		root["command"] = "close";
 	}
 	}
@@ -290,6 +297,30 @@ CmdMan::CmdRet CmdMan::cmdDeletefile(vector<string> args) {
 	return retval;
 	return retval;
 }
 }
 
 
+CmdMan::CmdRet CmdMan::cmdConnect(vector<string> args) {
+	CmdRet retval;
+	DEBUGPRINT(string(__PRETTY_FUNCTION__) + " begin");
+	Json::Value root;
+
+	root["command"] = "connect";
+
+	if (args.size() < 1) {
+		retval.type = error;
+		root["error"] = "not enough arguments, at least 1 argument required";
+	} else if (args.size() < 2) {
+		retval.type = connect;
+		root["address"] = args[0];
+		root["port"] = 1234;
+	} else {
+		retval.type = connect;
+		root["address"] = args[0];
+		root["port"] = (unsigned int)stoul(args[1]);
+	}
+	retval.msg = root;
+
+	return retval;
+}
+
 CmdMan::CmdRet CmdMan::execute(string cmd, vector<string> args) {
 CmdMan::CmdRet CmdMan::execute(string cmd, vector<string> args) {
 	DEBUGPRINT(string(__PRETTY_FUNCTION__) + " begin");
 	DEBUGPRINT(string(__PRETTY_FUNCTION__) + " begin");
 	DEBUGPRINT(string(__PRETTY_FUNCTION__) + " using command \"" + cmd + "\" with arguments [ ");
 	DEBUGPRINT(string(__PRETTY_FUNCTION__) + " using command \"" + cmd + "\" with arguments [ ");
@@ -306,7 +337,9 @@ CmdMan::CmdRet CmdMan::execute(string cmd, vector<string> args) {
 		root["error"] = string(__PRETTY_FUNCTION__) + " unknown command \"" + cmd + "\".\ntype help to list available commands.";
 		root["error"] = string(__PRETTY_FUNCTION__) + " unknown command \"" + cmd + "\".\ntype help to list available commands.";
 		retval.msg = root;
 		retval.msg = root;
 		return retval;
 		return retval;
-	} else if (loginpossible || dologin || dosignup) {
+	} else if (!cmd.compare("help") || !cmd.compare("exit")) {
+		// allow help and exit in all cases
+	} else if (currentState == loginpossible || currentState == dologin || currentState == dosignup) {
 		DEBUGPRINT("execute does login");
 		DEBUGPRINT("execute does login");
 		DEBUGPRINT(string("comparison is ") +
 		DEBUGPRINT(string("comparison is ") +
 		           std::to_string(cmd.compare("login") && cmd.compare("signup") && cmd.compare("disconnect") && cmd.compare("help")));
 		           std::to_string(cmd.compare("login") && cmd.compare("signup") && cmd.compare("disconnect") && cmd.compare("help")));
@@ -318,6 +351,26 @@ CmdMan::CmdRet CmdMan::execute(string cmd, vector<string> args) {
 			retval.msg = root;
 			retval.msg = root;
 			return retval;
 			return retval;
 		}
 		}
+	} else if (currentState == versionpossible || currentState == doversion) {
+		DEBUGPRINT("execute does version");
+		DEBUGPRINT(string("comparison is ") + std::to_string(cmd.compare("version")));
+		if (cmd.compare("version")) {
+			retval.type = error;
+			root["command"] = "error";
+			root["error"] = string("Version not checked yet. No commands avalable.");
+			retval.msg = root;
+			return retval;
+		}
+	} else if (currentState == connectionpossible) {
+		DEBUGPRINT("execute does connect");
+		DEBUGPRINT(string("comparison is ") + std::to_string(cmd.compare("connect")));
+		if (cmd.compare("version") && cmd.compare("connect")) {
+			retval.type = error;
+			root["command"] = "error";
+			root["error"] = string("Not connected. Connect using \"connect ip [port]\".");
+			retval.msg = root;
+			return retval;
+		}
 	}
 	}
 	return (this->*(execmap[cmd]))(args);
 	return (this->*(execmap[cmd]))(args);
 }
 }
@@ -387,6 +440,26 @@ CmdMan::CmdRet CmdMan::cmdClosekey(vector<string> args) {
 	return retval;
 	return retval;
 }
 }
 
 
+CmdMan::CmdRet CmdMan::cmdExit(vector<string> args) {
+	CmdRet retval;
+	Json::Value root;
+	DEBUGPRINT(string(__PRETTY_FUNCTION__) + " begin");
+	root["command"] = "exit";
+	if (currentState != connectionpossible) {
+		// we are connected, disconnect first
+		retval.nextcommand = "disconnect";
+		if (currentState == loginpossible)
+			currentState = disconnecttoexitearly;
+		else
+			currentState = disconnecttoexit;
+		retval.type = none;
+	} else {
+		retval.type = exit;
+	}
+	retval.msg = root;
+	return retval;
+}
+
 /* login and signup commands */
 /* login and signup commands */
 CmdMan::CmdRet CmdMan::cmdLogin(vector<string> args) {
 CmdMan::CmdRet CmdMan::cmdLogin(vector<string> args) {
 	CmdRet retval;
 	CmdRet retval;
@@ -399,9 +472,8 @@ CmdMan::CmdRet CmdMan::cmdLogin(vector<string> args) {
 		root["accept"] = false;
 		root["accept"] = false;
 		root["error"] = "not enough arguments, at least 2 argument required";
 		root["error"] = "not enough arguments, at least 2 argument required";
 	} else {
 	} else {
-		if (loginpossible) {
-			dologin = true;
-			loginpossible = false;
+		if (currentState == loginpossible) {
+			currentState = dologin;
 			root["user"] = args[0];
 			root["user"] = args[0];
 			root["pass"] = args[1];
 			root["pass"] = args[1];
 			root["login"] = true;
 			root["login"] = true;
@@ -431,9 +503,8 @@ CmdMan::CmdRet CmdMan::cmdSignup(vector<string> args) {
 		root["accept"] = false;
 		root["accept"] = false;
 		root["error"] = "not enough arguments, at least 2 argument required";
 		root["error"] = "not enough arguments, at least 2 argument required";
 	} else {
 	} else {
-		if (loginpossible) {
-			dosignup = true;
-			loginpossible = false;
+		if (currentState == loginpossible) {
+			currentState = dosignup;
 			root["user"] = args[0];
 			root["user"] = args[0];
 			root["pass"] = args[1];
 			root["pass"] = args[1];
 			root["login"] = false;
 			root["login"] = false;
@@ -457,13 +528,18 @@ CmdMan::CmdRet CmdMan::cmdVersion(vector<string> args) {
 	CmdRet retval;
 	CmdRet retval;
 	DEBUGPRINT(string(__PRETTY_FUNCTION__) + " begin");
 	DEBUGPRINT(string(__PRETTY_FUNCTION__) + " begin");
 	Json::Value root;
 	Json::Value root;
-	root["major"] = protocolMajorVersion;
-	root["minor"] = protocolMinorVersion;
-	retval.type = send;
+	if (currentState == versionpossible) {
+		root["major"] = protocolMajorVersion;
+		root["minor"] = protocolMinorVersion;
+		retval.type = send;
+		currentState = doversion;
+	} else {
+		retval.type = error;
+		root["command"] = "error";
+		root["error"] = "Executing version command not possible. Type help to list available commands.";
+	}
 	retval.msg = root;
 	retval.msg = root;
 
 
-	doversion = true;
-
 	return retval;
 	return retval;
 }
 }
 
 
@@ -471,11 +547,11 @@ CmdMan::CmdRet CmdMan::handle(Json::Value root) {
 	CmdRet retval;
 	CmdRet retval;
 	Json::Value output;
 	Json::Value output;
 	DEBUGPRINT(string(__PRETTY_FUNCTION__) + " begin");
 	DEBUGPRINT(string(__PRETTY_FUNCTION__) + " begin");
-	if (doversion)
+	if (currentState == doversion)
 		root["command"] = "version";
 		root["command"] = "version";
-	else if (dosignup)
+	else if (currentState == dosignup)
 		root["command"] = "signup";
 		root["command"] = "signup";
-	else if (dologin)
+	else if (currentState == dologin)
 		root["command"] = "login";
 		root["command"] = "login";
 	DEBUGPRINT(string(__PRETTY_FUNCTION__) + " using json\n" + Json::writeString(wbuilder, root) + "\n");
 	DEBUGPRINT(string(__PRETTY_FUNCTION__) + " using json\n" + Json::writeString(wbuilder, root) + "\n");
 	string retmsg;
 	string retmsg;
@@ -509,6 +585,11 @@ CmdMan::CmdRet CmdMan::handleClose(Json::Value root) {
 	retval.type = close | print;
 	retval.type = close | print;
 	retval.msg = output;
 	retval.msg = output;
 
 
+	if (currentState == disconnecttoexit) {
+		retval.nextcommand = "exit";
+	}
+	currentState = connectionpossible;
+
 	return retval;
 	return retval;
 }
 }
 
 
@@ -723,17 +804,17 @@ CmdMan::CmdRet CmdMan::handleVersion(Json::Value root) {
 	DEBUGPRINT(string(__PRETTY_FUNCTION__) + " begin");
 	DEBUGPRINT(string(__PRETTY_FUNCTION__) + " begin");
 
 
 	output["command"] = "version";
 	output["command"] = "version";
-	output["serverversion"] = root["major"].asString() + "." + root["minor"].asString();
+	output["serverversion"] = std::to_string(root["major"].asInt()) + "." + std::to_string(root["minor"].asInt());
 	output["clientversion"] = std::to_string(protocolMajorVersion) + "." + std::to_string(protocolMinorVersion);
 	output["clientversion"] = std::to_string(protocolMajorVersion) + "." + std::to_string(protocolMinorVersion);
 
 
 	if (!root["accept"].asBool()) {
 	if (!root["accept"].asBool()) {
-		retval.type = error;
+		retval.type = error | close;
 		output["accept"] = false;
 		output["accept"] = false;
+		currentState = connectionpossible;
 	} else {
 	} else {
-		retval.type = print | seton;
+		retval.type = print;
 		output["accept"] = true;
 		output["accept"] = true;
-		doversion = false;
-		loginpossible = true;
+		currentState = loginpossible;
 	}
 	}
 	retval.msg = output;
 	retval.msg = output;
 
 
@@ -751,13 +832,12 @@ CmdMan::CmdRet CmdMan::handleLogin(Json::Value root) {
 		retval.type = error;
 		retval.type = error;
 		output["error"] = root["error"].asString();
 		output["error"] = root["error"].asString();
 		output["accept"] = false;
 		output["accept"] = false;
-		loginpossible = true;
-		dologin = false;
+		currentState = loginpossible;
 	} else {
 	} else {
-		retval.type = print | seton;
+		retval.type = print;
 		output["error"] = "";
 		output["error"] = "";
 		output["accept"] = true;
 		output["accept"] = true;
-		dologin = false;
+		currentState = normal;
 	}
 	}
 	retval.msg = output;
 	retval.msg = output;
 
 
@@ -775,13 +855,12 @@ CmdMan::CmdRet CmdMan::handleSignup(Json::Value root) {
 		retval.type = error;
 		retval.type = error;
 		output["error"] = root["error"].asString();
 		output["error"] = root["error"].asString();
 		output["accept"] = false;
 		output["accept"] = false;
-		loginpossible = true;
-		dosignup = false;
+		currentState = loginpossible;
 	} else {
 	} else {
-		retval.type = print | seton;
+		retval.type = print;
 		output["error"] = "";
 		output["error"] = "";
 		output["accept"] = true;
 		output["accept"] = true;
-		dosignup = false;
+		currentState = normal;
 	}
 	}
 	retval.msg = output;
 	retval.msg = output;
 
 
@@ -834,6 +913,7 @@ CmdMan::CmdRet CmdMan::handleDeleteme(Json::Value root) {
 		retval.type = error;
 		retval.type = error;
 	} else {
 	} else {
 		retval.type = close | print;
 		retval.type = close | print;
+		currentState = connectionpossible;
 	}
 	}
 	retval.msg = root;
 	retval.msg = root;
 	return retval;
 	return retval;

+ 60 - 68
cli/src/ioman.cpp

@@ -25,12 +25,11 @@ extern IoMan *gIOMAN;
 
 
 void ioman_externalDebugPrint(string msg) { gIOMAN->printMessage(msg, gIOMAN->OutMsgType::debug); }
 void ioman_externalDebugPrint(string msg) { gIOMAN->printMessage(msg, gIOMAN->OutMsgType::debug); }
 
 
-IoMan::IoMan(char *ipcstring, bool enablessl) : cmdman(fileman, &ioman_externalDebugPrint), recvbuf(16384) {
-	ipstring = std::string(ipcstring);
-	port = 1234;
+IoMan::IoMan(bool enablessl) : cmdman(fileman, &ioman_externalDebugPrint), recvbuf(16384) {
+	ipstring = "";
+	port = 0;
 	tcpsock = new tcp::socket(ios);
 	tcpsock = new tcp::socket(ios);
 	connected = false;
 	connected = false;
-	usessl = false;
 
 
 	/* to be put elsewhere */
 	/* to be put elsewhere */
 
 
@@ -41,8 +40,6 @@ IoMan::IoMan(char *ipcstring, bool enablessl) : cmdman(fileman, &ioman_externalD
 	runnetwork = false;
 	runnetwork = false;
 	runinput = false;
 	runinput = false;
 	runresponse = false;
 	runresponse = false;
-	versionstatus = off;
-	loginstatus = off;
 	usessl = enablessl;
 	usessl = enablessl;
 	if (usessl) {
 	if (usessl) {
 		sslctx = new boost::asio::ssl::context(boost::asio::ssl::context::sslv23);
 		sslctx = new boost::asio::ssl::context(boost::asio::ssl::context::sslv23);
@@ -54,8 +51,6 @@ IoMan::IoMan(char *ipcstring, bool enablessl) : cmdman(fileman, &ioman_externalD
 }
 }
 
 
 IoMan::~IoMan() {
 IoMan::~IoMan() {
-	initcv.notify_all();
-
 	if (connected) {
 	if (connected) {
 		disconnect();
 		disconnect();
 	}
 	}
@@ -161,6 +156,8 @@ bool IoMan::connect() {
 		root["error"] = errcode.message();
 		root["error"] = errcode.message();
 		connected = false;
 		connected = false;
 	} else {
 	} else {
+		if(!ios.stopped()) ios.stop();
+		ios.restart();
 		// establish connection
 		// establish connection
 		printMessage(string(__PRETTY_FUNCTION__) + string(" connecting to ") + ipstring, debug);
 		printMessage(string(__PRETTY_FUNCTION__) + string(" connecting to ") + ipstring, debug);
 		ep = new tcp::endpoint(addr, port);
 		ep = new tcp::endpoint(addr, port);
@@ -202,7 +199,10 @@ void IoMan::disconnect() {
 	printMessage("IoMan::disconnect()", debug);
 	printMessage("IoMan::disconnect()", debug);
 	tcpsock->shutdown(tcp::socket::shutdown_both, errcode);
 	tcpsock->shutdown(tcp::socket::shutdown_both, errcode);
 	if (errcode)
 	if (errcode)
-		printMessage(string(__PRETTY_FUNCTION__) + string("tcp shutdown says ") + errcode.message(), error);
+		printMessage(string(__PRETTY_FUNCTION__) + string("tcp shutdown says ") + errcode.message(), debug);
+	tcpsock->close(errcode);
+	if (errcode)
+		printMessage(string(__PRETTY_FUNCTION__) + string("tcp shutdown says ") + errcode.message(), debug);
 	connected = false;
 	connected = false;
 }
 }
 
 
@@ -212,43 +212,13 @@ bool IoMan::init() {
 	Json::Value root;
 	Json::Value root;
 	std::unique_lock<std::mutex> ulock;
 	std::unique_lock<std::mutex> ulock;
 
 
-	printMessage("IoMan::Init() begin", debug);
-
-	if (!connect())
-		return false;
-
-	printMessage("IoMan::Init() versioncheck", debug);
-
-	localmutex.lock();
-	printMessage(string(__PRETTY_FUNCTION__) + string(" get localmutex"), debug);
-	localinput.push_back("version");
-	localmutex.unlock();
-	printMessage(string(__PRETTY_FUNCTION__) + string(" release localmutex"), debug);
-	localcv.notify_all();
-
-	printMessage("IoMan::Init() begin", debug);
-
-	runnetwork = true;
+	printMessage(string(__PRETTY_FUNCTION__) + string(" begin"), debug);
 	runinput = true;
 	runinput = true;
 	runresponse = true;
 	runresponse = true;
 
 
-	tnetwork = std::thread(&IoMan::networkMain, this);
 	tinput = std::thread(&IoMan::inputMain, this);
 	tinput = std::thread(&IoMan::inputMain, this);
 	tresponse = std::thread(&IoMan::responseMain, this);
 	tresponse = std::thread(&IoMan::responseMain, this);
 
 
-	ulock = std::unique_lock<std::mutex>(initmutex);
-	while (versionstatus == off) {
-		initcv.wait(ulock);
-	}
-	if (versionstatus == err) {
-		runnetwork = false;
-		runinput = false;
-		runresponse = false;
-		return false;
-	}
-	initmutex.unlock();
-	initcv.notify_all();
-
 	printWelcomeMessage();
 	printWelcomeMessage();
 	return true;
 	return true;
 }
 }
@@ -341,7 +311,7 @@ void IoMan::inputMain() {
 	CmdMan::CmdRet cmdret;
 	CmdMan::CmdRet cmdret;
 	std::unique_lock<std::mutex> ulock;
 	std::unique_lock<std::mutex> ulock;
 
 
-	printMessage("IoMan::inputMain() begin", debug);
+	printMessage(string(__PRETTY_FUNCTION__) + string(" begin"), debug);
 	inputmutex.lock();
 	inputmutex.lock();
 	while (runinput) {
 	while (runinput) {
 		inputmutex.unlock();
 		inputmutex.unlock();
@@ -408,11 +378,43 @@ void IoMan::handleInCmdResponse(CmdMan::CmdRet cmdret) {
 		printMessage(Json::writeString(wbuilder, cmdret.msg), error);
 		printMessage(Json::writeString(wbuilder, cmdret.msg), error);
 	}
 	}
 	if (cmdret.type & CmdMan::rettype::close) {
 	if (cmdret.type & CmdMan::rettype::close) {
-		/* TODO i dunno */
+		// connection closed, stop network thread and shutdown any operations remaining
+		networkmutex.lock();
+		runnetwork = false;
+		networkmutex.unlock();
+		disconnect();
+		tnetwork.join();
+	}
+	if (cmdret.type & CmdMan::rettype::connect) {
+		ipstring = cmdret.msg["address"].asString();
+		port = cmdret.msg["port"].asUInt();
+		if (connect()) {
+			runnetwork = true;
+			tnetwork = std::thread(&IoMan::networkMain, this);
+
+			// put new commands into global vector
+			localmutex.lock();
+			printMessage(string(__PRETTY_FUNCTION__) + string(" get localmutex"), debug);
+			localinput.push_back("version");
+			cmdman.stateSetConnectionOk();
+			localmutex.unlock();
+			printMessage(string(__PRETTY_FUNCTION__) + string(" release localmutex"), debug);
+			localcv.notify_all();
+		}
+	}
+	if (cmdret.type & CmdMan::rettype::exit) {
 		mainmutex.lock();
 		mainmutex.lock();
 		runmain = false;
 		runmain = false;
 		mainmutex.unlock();
 		mainmutex.unlock();
 	}
 	}
+	if (cmdret.nextcommand.size()) {
+		localmutex.lock();
+		printMessage(string(__PRETTY_FUNCTION__) + string(" get localmutex"), debug);
+		localinput.push_back(cmdret.nextcommand);
+		localmutex.unlock();
+		printMessage(string(__PRETTY_FUNCTION__) + string(" release localmutex"), debug);
+		localcv.notify_all();
+	}
 }
 }
 
 
 /* loop to handle responses that have been fetched by netMain and possibly add
 /* loop to handle responses that have been fetched by netMain and possibly add
@@ -423,7 +425,7 @@ void IoMan::responseMain() {
 	CmdMan::CmdRet cmdret;
 	CmdMan::CmdRet cmdret;
 	std::unique_lock<std::mutex> ulock;
 	std::unique_lock<std::mutex> ulock;
 
 
-	printMessage("IoMan::responseMain() begin", debug);
+	printMessage(string(__PRETTY_FUNCTION__) + string(" begin"), debug);
 	responsemutex.lock();
 	responsemutex.lock();
 	while (runresponse) {
 	while (runresponse) {
 		responsemutex.unlock();
 		responsemutex.unlock();
@@ -482,30 +484,19 @@ void IoMan::responseMain() {
 
 
 void IoMan::handleOutCmdResponse(CmdMan::CmdRet cmdret, vector<string> &toput) {
 void IoMan::handleOutCmdResponse(CmdMan::CmdRet cmdret, vector<string> &toput) {
 	if (cmdret.type & CmdMan::rettype::close) {
 	if (cmdret.type & CmdMan::rettype::close) {
-		/* TODO i dunno */
-		mainmutex.lock();
-		runmain = false;
-		mainmutex.unlock();
+		// connection closed, stop network thread and shutdown any operations remaining
+		networkmutex.lock();
+		runnetwork = false;
+		networkmutex.unlock();
+		disconnect();
+		tnetwork.join();
+		if (cmdret.nextcommand.size()) {
+			toput.push_back(cmdret.nextcommand);
+		}
 	}
 	}
 	if (cmdret.type & CmdMan::rettype::error) {
 	if (cmdret.type & CmdMan::rettype::error) {
-		initmutex.lock();
-		if (versionstatus == off)
-			versionstatus = err;
-		else if (loginstatus == off)
-			loginstatus = err;
-		initmutex.unlock();
-		initcv.notify_all();
 		printMessage(Json::writeString(wbuilder, cmdret.msg), error);
 		printMessage(Json::writeString(wbuilder, cmdret.msg), error);
 	}
 	}
-	if (cmdret.type & CmdMan::rettype::seton) {
-		initmutex.lock();
-		if (versionstatus == off)
-			versionstatus = on;
-		else
-			loginstatus = on;
-		initmutex.unlock();
-		initcv.notify_all();
-	}
 	if (cmdret.type & CmdMan::rettype::print) {
 	if (cmdret.type & CmdMan::rettype::print) {
 		printMessage(Json::writeString(wbuilder, cmdret.msg), normal);
 		printMessage(Json::writeString(wbuilder, cmdret.msg), normal);
 	}
 	}
@@ -514,6 +505,11 @@ void IoMan::handleOutCmdResponse(CmdMan::CmdRet cmdret, vector<string> &toput) {
 			toput.push_back(cmdret.nextcommand);
 			toput.push_back(cmdret.nextcommand);
 		}
 		}
 	}
 	}
+	if (cmdret.type & CmdMan::rettype::exit) {
+		mainmutex.lock();
+		runmain = false;
+		mainmutex.unlock();
+	}
 }
 }
 
 
 /* this is the handler that readlines alternative interface will use to process
 /* this is the handler that readlines alternative interface will use to process
@@ -544,7 +540,7 @@ void ioman_readlineHandler(char *line) {
 
 
 /* main user input loop */
 /* main user input loop */
 void IoMan::run() {
 void IoMan::run() {
-	printMessage("IoMan::run() begin", debug);
+	printMessage(string(__PRETTY_FUNCTION__) + string(" begin"), debug);
 	struct pollfd inpipestatus;
 	struct pollfd inpipestatus;
 	inpipestatus.fd = STDIN_FILENO;
 	inpipestatus.fd = STDIN_FILENO;
 	inpipestatus.events = POLLIN;
 	inpipestatus.events = POLLIN;
@@ -563,10 +559,6 @@ void IoMan::run() {
 		if (inpipestatus.revents & POLLIN) {
 		if (inpipestatus.revents & POLLIN) {
 			rl_callback_read_char();
 			rl_callback_read_char();
 		}
 		}
-		if (!connected)
-			break;
-		if (loginstatus == err)
-			break;
 		mainmutex.lock();
 		mainmutex.lock();
 	}
 	}
 	mainmutex.unlock();
 	mainmutex.unlock();

+ 1 - 1
cli/src/machineioman.cpp

@@ -3,7 +3,7 @@
 #include <iostream>
 #include <iostream>
 #include <vector>
 #include <vector>
 
 
-MachineIoMan::MachineIoMan(char *ipcstring, bool usessl, bool beverbose) : IoMan(ipcstring, usessl) { verbose = beverbose; }
+MachineIoMan::MachineIoMan(bool usessl, bool beverbose) : IoMan(usessl) { verbose = beverbose; }
 
 
 void MachineIoMan::printMessage(std::string msg, OutMsgType type) {
 void MachineIoMan::printMessage(std::string msg, OutMsgType type) {
 	switch (type) {
 	switch (type) {

+ 6 - 13
cli/src/main.cpp

@@ -13,8 +13,7 @@ IoMan *gIOMAN = NULL;
 
 
 void show_help(char *exec) {
 void show_help(char *exec) {
 	std::printf("ccats command line interface\n");
 	std::printf("ccats command line interface\n");
-	std::printf("usage: %s IP [Options]\n", exec);
-	std::printf("IP should be in the format \"xxx.xxx.xxx.xxx\"\n");
+	std::printf("usage: %s [Options]\n", exec);
 }
 }
 
 
 int main(int argc, char **argv) {
 int main(int argc, char **argv) {
@@ -28,14 +27,8 @@ int main(int argc, char **argv) {
 	const char *file = NULL;
 	const char *file = NULL;
 	IoMan *ioman;
 	IoMan *ioman;
 
 
-	if (argc < 2 || !std::strncmp(argv[1], "--help", 6)) {
-		show_help(argv[0]);
-		std::cout << desc;
-		return 1;
-	}
-
 	try {
 	try {
-		store(parse_command_line(argc - 1, argv + 1, desc), vm);
+		store(parse_command_line(argc, argv, desc), vm);
 		notify(vm);
 		notify(vm);
 
 
 		if (vm.count("help")) {
 		if (vm.count("help")) {
@@ -61,13 +54,13 @@ int main(int argc, char **argv) {
 	} catch (const bpo::error &ex) {
 	} catch (const bpo::error &ex) {
 		std::fprintf(stderr, "%s\n", ex.what());
 		std::fprintf(stderr, "%s\n", ex.what());
 	}
 	}
-	std::printf("ip %s machine mode is %d file is %s enablessl is %d verbose is %d\n", argv[1], machine, file ? file : "", usessl, verbose);
+	std::printf("machine mode is %d file is %s enablessl is %d verbose is %d\n", machine, file ? file : "", usessl, verbose);
 	if (batch) {
 	if (batch) {
-		ioman = new BatchIoMan(argv[1], usessl, verbose, file);
+		ioman = new BatchIoMan(usessl, verbose, file);
 	} else if (machine) {
 	} else if (machine) {
-		ioman = new MachineIoMan(argv[1], usessl, verbose);
+		ioman = new MachineIoMan(usessl, verbose);
 	} else {
 	} else {
-		ioman = new UserIoMan(argv[1], usessl, verbose);
+		ioman = new UserIoMan(usessl, verbose);
 	}
 	}
 	gIOMAN = ioman;
 	gIOMAN = ioman;
 	if (ioman->init()) {
 	if (ioman->init()) {

+ 1 - 1
cli/src/userioman.cpp

@@ -4,7 +4,7 @@
 #include <readline/readline.h>
 #include <readline/readline.h>
 #include <vector>
 #include <vector>
 
 
-UserIoMan::UserIoMan(char *ipcstring, bool usessl, bool beverbose) : IoMan(ipcstring, usessl) {
+UserIoMan::UserIoMan(bool usessl, bool beverbose) : IoMan(usessl) {
 	/* setup json stuff */
 	/* setup json stuff */
 	Json::CharReaderBuilder rbuilder;
 	Json::CharReaderBuilder rbuilder;
 	wbuilder.settings_["indentation"] = "";
 	wbuilder.settings_["indentation"] = "";