#include "../include/global.h" #include "../include/ioman.h" #include #include #include #include #include #include #include using std::string; using std::vector; using boost::asio::ip::tcp; using boost::asio::buffer; IoMan::IoMan(char *ipcstring) : cmdman(fileman) { ipstring = std::string(ipcstring); port = 1234; tcpsock = new tcp::socket(ios); connected = false; /* to be put elsewhere */ /* setup json stuff */ Json::CharReaderBuilder rbuilder; wbuilder.settings_["indentation"] = ""; reader = rbuilder.newCharReader(); runnetwork = false; runinput = false; runresponse = false; startlist = false; versionstatus = off; loginstatus = off; } IoMan::~IoMan() { runnetwork = false; runinput = false; runresponse = false; tnetwork.join(); tinput.join(); tresponse.join(); if(connected) { disconnect(); } delete tcpsock; delete reader; } void IoMan::printNormalMessage(string nouse) { } void IoMan::printErrorMessage(string nouse) { } void IoMan::printDebugMessage(string nouse) { } bool IoMan::connect() { tcp::endpoint *ep; ep = new tcp::endpoint(boost::asio::ip::address::from_string(ipstring), 1234); // establish connection printDebugMessage("IoMan::connect() connecting to " + ipstring); tcpsock->connect(*ep, errcode); if (errcode) { delete ep; printErrorMessage("IoMan::connect() couldnt connect to " + ipstring + "\n" + errcode.message()); return false; } connected = true; delete ep; return true; } void IoMan::disconnect() { printDebugMessage("IoMan::disconnect()"); tcpsock->close(); connected = false; } bool IoMan::init() { CmdMan::CmdRet ret; string work; Json::Value root; printDebugMessage("IoMan::Init() begin"); if(!connect()) return false; printDebugMessage("IoMan::Init() versioncheck"); localmutex.lock(); printDebugMessage(string(__PRETTY_FUNCTION__) + string(" get localmutex")); localinput.push_back("version " + protocolVersion); localmutex.unlock(); printDebugMessage(string(__PRETTY_FUNCTION__) + string(" release localmutex")); printDebugMessage("IoMan::Init() begin"); runnetwork = true; runinput = true; runresponse = true; tnetwork = std::thread(&IoMan::networkMain, this); tinput = std::thread(&IoMan::inputMain, this); tresponse = std::thread(&IoMan::responseMain, this); while(versionstatus == off); if(versionstatus == err) { runnetwork = false; runinput = false; runresponse = false; return false; } printWelcomeMessage(); return true; } void IoMan::networkMain() { vector toput; char *recvjson; Json::Value root; unsigned int jsonsize, readsize; printDebugMessage("IoMan::networkMain() begin"); while(runnetwork) { std::this_thread::yield(); std::this_thread::sleep_for(std::chrono::milliseconds(10)); /* read from network until \n try to parse json - output error if not ok store all ok json in local vector get networkmutex put all local jsons into network vector release networkmutex */ // read from network readsize = boost::asio::read_until(*tcpsock, recvbuf, '\n', errcode); printDebugMessage(string(__PRETTY_FUNCTION__) + string(" asio::read() ok")); if (errcode && errcode != boost::asio::error::eof) { printErrorMessage("IoMan::networkMain() couldnt read json data\n" + errcode.message()); continue; } recvjson = (char *)(boost::asio::buffer_cast(recvbuf.data())); while(strchr(recvjson, '\n')) { // parse jsonsize = strchr(recvjson, '\n') - recvjson + 1; printDebugMessage(string(__PRETTY_FUNCTION__) + string(" found jsondata ") + string(recvjson)); if (!reader->parse(recvjson, recvjson + jsonsize, &root, &jsonerror)) { printErrorMessage("IoMan::networkMain() couldnt parse json data: " + jsonerror); recvbuf.consume(jsonsize); continue; } recvbuf.consume(jsonsize); readsize -= jsonsize; printDebugMessage(string(__PRETTY_FUNCTION__) + string(" remaining recvbuf ") + string(boost::asio::buffer_cast(recvbuf.data()))); for(int i = 0; i < jsonsize; i++) recvjson++; // store locally toput.push_back(root); } if(toput.size()){ // put into global vector netmutex.lock(); printDebugMessage(string(__PRETTY_FUNCTION__) + string(" get netmutex")); netinput.insert(netinput.end(), toput.begin(), toput.end()); netmutex.unlock(); printDebugMessage(string(__PRETTY_FUNCTION__) + string(" release netmutex")); } // clean up local stuff toput = vector(); recvbuf.consume(readsize); } } void IoMan::inputMain() { vector toprocess; string command; vector args; CmdMan::CmdRet cmdret; size_t prev, index, quot; printDebugMessage("IoMan::inputMain() begin"); while(runinput) { std::this_thread::yield(); std::this_thread::sleep_for(std::chrono::milliseconds(10)); /* get inputmutex read all input vector into local vector release inputmutex process inputs send to server if required */ // read into local vector if(localinput.size()) { localmutex.lock(); printDebugMessage(string(__PRETTY_FUNCTION__) + string(" has localmutex")); toprocess = vector(localinput); localinput = vector(); localmutex.unlock(); printDebugMessage(string(__PRETTY_FUNCTION__) + string(" release localmutex")); } // printDebugMessage(string("have ") + std::to_string(toprocess.size()) + string(" commands")); // process for(string cmd : toprocess) { args = vector(); if((index = cmd.find(" ")) == string::npos) { // only command no args command = cmd; } else { command = cmd.substr(0, index); //~ index++; while(true) { // find first char thats not a space while(cmd[index] == ' ') { index++; // bounds check if(index == cmd.size()) goto end_tokenizing; } cmd = cmd.substr(index); if(cmd[0] == '\"') { // quoted string index = cmd.find("\""); args.push_back(cmd.substr(1, index-1)); index++; /* tokens.push_back(cmd.substr(0, ++index)); */ // char after closing quote should be space while within bounds if(index == cmd.size()) goto end_tokenizing; } else { // non-quoted string index = cmd.find(" "); if(index == string::npos) { // no spaces, last arg args.push_back(cmd); goto end_tokenizing; } else { args.push_back(cmd.substr(0, index)); } } } end_tokenizing: ; } cmdret = cmdman.execute(command, args); // determine wether to send something and do so if required switch(cmdret.type) { case CmdMan::rettype::send: { printDebugMessage("IoMan::inputMain() sending json \"" + cmdret.msg + "\""); boost::asio::write(*tcpsock, buffer(cmdret.msg + "\n"), errcode); if (errcode) { printErrorMessage("IoMan::inputMain() couldnt send json data\n" + errcode.message() + "\n"); continue; } break; } case CmdMan::rettype::notsend: { printNormalMessage(cmdret.msg); break; } case CmdMan::rettype::error: { printErrorMessage(cmdret.msg); break; } } } // clean up local stuff toprocess = vector(); } } void IoMan::responseMain() { vector toprocess; vector toput; CmdMan::CmdRet cmdret; printDebugMessage("IoMan::responseMain() begin"); while(runresponse) { std::this_thread::yield(); std::this_thread::sleep_for(std::chrono::milliseconds(10)); /* get networkmutex read all network vector into local vector release networkmutex process all jsons process putdata process getdata process listdata get inputmutex place new commands into input vector release inputmutex */ // read into local vector if(netinput.size()) { netmutex.lock(); printDebugMessage(string(__PRETTY_FUNCTION__) + string(" get netmutex")); toprocess = vector(netinput); netinput = vector(); netmutex.unlock(); printDebugMessage(string(__PRETTY_FUNCTION__) + string(" release netmutex")); } // process jsons for(Json::Value root : toprocess) { cmdret = cmdman.handle(root); switch(cmdret.type) { case CmdMan::rettype::startlist: { startlist = true; break; } case CmdMan::rettype::stoplist: { startlist = false; break; } case CmdMan::rettype::close: { /* TODO i dunno */ runmain = false; break; } case CmdMan::rettype::error: { if(versionstatus == off) versionstatus = err; else if(loginstatus == off) loginstatus = err; printErrorMessage(cmdret.msg); break; } case CmdMan::rettype::seton: { if(versionstatus == off) versionstatus = on; else loginstatus = on; } case CmdMan::rettype::notsend: { printNormalMessage(cmdret.msg); break; } case CmdMan::rettype::send: { toput.push_back(cmdret.msg); break; } } } if(toput.size()) { // put new commands into global vector localmutex.lock(); printDebugMessage(string(__PRETTY_FUNCTION__) + string(" get localmutex")); localinput.insert(localinput.end(), toput.begin(), toput.end()); localmutex.unlock(); printDebugMessage(string(__PRETTY_FUNCTION__) + string(" release localmutex")); } // clean up local stuff toprocess = vector(); toput = vector(); } } void IoMan::run() { printDebugMessage("IoMan::run() begin"); char *line = NULL, *user = NULL, *pass = NULL; vector tokens; string work, command; CmdMan::CmdRet cmdret; Json::Value root; runmain = true; while(!user) { user = readline(getUserPrompt().c_str()); printErrorMessage("Using user: " + string(user)); } while(!pass) { pass = readline(getPassPrompt().c_str()); printErrorMessage("Using pass: " + string(pass)); } printDebugMessage("IoMan::run() login"); localmutex.lock(); printDebugMessage(string(__PRETTY_FUNCTION__) + string(" get localmutex")); localinput.push_back("login " + string(user) + " " + string(pass)); localmutex.unlock(); printDebugMessage(string(__PRETTY_FUNCTION__) + string(" release localmutex")); free(user); free(pass); while(loginstatus == off); if(loginstatus == err) return; while(runmain) { free(line); line = readline(getCmdPrompt().c_str()); if(!runmain) break; // if no input, do not add to history, and go to reading next line if (strlen(line) == 0) { continue; } // split input line into tokens boost::algorithm::split(tokens, std::string(line), boost::algorithm::is_any_of(" "), boost::algorithm::token_compress_on); // if input contains only spaces, do not add to history, and go to reading // next line if (tokens.size() < 1) { continue; } // add the line to history add_history(line); localmutex.lock(); printDebugMessage(string(__PRETTY_FUNCTION__) + string(" get localmutex")); localinput.push_back(line); localmutex.unlock(); printDebugMessage(string(__PRETTY_FUNCTION__) + string(" release localmutex")); if(!connected) break; } free(line); }