diff --git a/DDV_Controller/Makefile b/DDV_Controller/Makefile new file mode 100644 index 00000000..d297d255 --- /dev/null +++ b/DDV_Controller/Makefile @@ -0,0 +1,18 @@ +SRC = main.cpp ../util/json/json_reader.cpp ../util/json/json_value.cpp ../util/json/json_writer.cpp ../util/socket.cpp ../util/http_parser.cpp ../util/md5.cpp +OBJ = $(SRC:.cpp=.o) +OUT = DDV_Controller +INCLUDES = +CCFLAGS = -Wall -Wextra -funsigned-char -g +CC = $(CROSS)g++ +LD = $(CROSS)ld +AR = $(CROSS)ar +LIBS = +.SUFFIXES: .cpp +.PHONY: clean default +default: $(OUT) +.cpp.o: + $(CC) $(INCLUDES) $(CCFLAGS) $(LIBS) -c $< -o $@ +$(OUT): $(OBJ) + $(CC) $(LIBS) -o $(OUT) $(OBJ) +clean: + rm -rf $(OBJ) $(OUT) Makefile.bak *~ diff --git a/DDV_Controller/main.cpp b/DDV_Controller/main.cpp new file mode 100644 index 00000000..d41eddbb --- /dev/null +++ b/DDV_Controller/main.cpp @@ -0,0 +1,155 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../util/socket.h" +#include "../util/http_parser.h" +#include "../util/md5.h" +#include "../util/json/json.h" + + +void WriteFile( std::string Filename, std::string contents ) { + std::ofstream File; + File.open( Filename.c_str( ) ); + File << contents << std::endl; + File.close( ); +} + +std::string ReadFile( std::string Filename ) { + std::string Result; + std::ifstream File; + File.open( Filename.c_str( ) ); + while( File.good( ) ) { Result += File.get( ); } + File.close( ); + return Result; +} + +class ConnectedUser{ + public: + Socket::Connection C; + HTTP::Parser H; + bool Authorized; + std::string Username; + ConnectedUser(Socket::Connection c){ + C = c; + H.Clean(); + Authorized = false; + } +}; + +void Log(std::string kind, std::string message, Json::Value & Storage){ + Json::Value m; + m.append((Json::Value::UInt)time(0)); + m.append(kind); + m.append(message); + Storage["log"].append(m); + std::cout << "[" << kind << "] " << message << std::endl; +} + +void Authorize( Json::Value & Request, Json::Value & Storage, Json::Value & Response, ConnectedUser & conn ) { + time_t Time = time(0); + tm * TimeInfo = localtime(&Time); + std::stringstream Date; + std::string retval; + Date << TimeInfo->tm_mday << "-" << TimeInfo->tm_mon << "-" << TimeInfo->tm_year + 1900; + std::string Challenge = md5( Date.str().c_str() + conn.C.getHost() ); + if( Request.isMember( "authorize" ) ) { + std::string UserID = Request["authorize"]["username"].asString(); + if (Storage["account"].isMember(UserID)){ + if( md5( Storage["account"][UserID]["password"].asString() + Challenge ) == Request["authorize"]["password"].asString() ) { + Response["authorize"]["status"] = "OK"; + conn.Username = UserID; + conn.Authorized = true; + return; + } + } + Log("AUTH", "Failed login attempt "+UserID+" @ "+conn.C.getHost(), Storage); + } + conn.Username = ""; + conn.Authorized = false; + Response["authorize"]["status"] = "CHALL"; + Response["authorize"]["challenge"] = Challenge; + return; +} + +void CheckConfig(Json::Value & in, Json::Value & out){ + +} + +void CheckStreams(Json::Value & in, Json::Value & out){ + +} + +int main() { + Socket::Server API_Socket = Socket::Server( 4242, "0.0.0.0", true ); + Socket::Connection TempConn; + std::vector< ConnectedUser > users; + HTTP::Parser HTTP_R, HTTP_S; + Json::Value Request; + Json::Value Response; + Json::Value Storage; + Json::Reader JsonParse; + JsonParse.parse(ReadFile("config.json"), Storage, false); + Storage["account"]["gearbox"]["password"] = Json::Value("7e0f87b116377621a75a6440ac74dcf4"); + while (API_Socket.connected()){ + usleep(10000); //sleep for 10 ms - prevents 100% CPU time + TempConn = API_Socket.accept(); + if (TempConn.connected()){users.push_back(TempConn);} + if (users.size() > 0){ + for( std::vector< ConnectedUser >::iterator it = users.end() - 1; it >= users.begin(); it-- ) { + if( !(*it).C.connected() ) { + (*it).C.close(); + users.erase( it ); + } + if ((*it).H.Read((*it).C)){ + Response.clear(); //make sure no data leaks from previous requests + std::cout << "Body: " << HTTP_R.body << std::endl; + std::cout << "Command: " << HTTP_R.GetVar("command") << std::endl; + JsonParse.parse(HTTP_R.GetVar("command"), Request, false); + std::cout << Request.toStyledString() << std::endl; + Authorize(Request, Storage, Response, (*it)); + if ((*it).Authorized){ + //Parse config and streams from the request. + if (Request.isMember("config")){CheckConfig(Request["config"], Storage["config"]);} + if (Request.isMember("streams")){CheckStreams(Request["streams"], Storage["streams"]);} + //sent current configuration, no matter if it was changed or not + Response["streams"] = Storage["streams"]; + Response["config"] = Storage["config"]; + //add the current unix time to the config, for syncing reasons + Response["config"]["time"] = (Json::Value::UInt)time(0); + //sent any available logs and statistics + Response["log"] = Storage["log"]; + Response["statistics"] = Storage["statistics"]; + //clear log and statistics to prevent useless data transfer + Storage["log"].clear(); + Storage["statistics"].clear(); + } + (*it).H.Clean(); + (*it).H.protocol = "HTTP/1.1"; + (*it).H.SetHeader( "Content-Type", "text/javascript" ); + (*it).H.SetBody( Response.toStyledString() + "\n\n" ); + (*it).C.write( (*it).H.BuildResponse( "200", "OK" ) ); + (*it).H.Clean(); + } + } + } + } + return 0; +} diff --git a/spawntest/main.cpp b/spawntest/main.cpp index c622bdba..d06bff34 100644 --- a/spawntest/main.cpp +++ b/spawntest/main.cpp @@ -5,11 +5,22 @@ #include #include "../util/proc.h" //Process utility +/// Sleeps a maximum of five seconds, each second being interruptable by a signal. +void sleepFive(){ + sleep(1); sleep(1); sleep(1); sleep(1); sleep(1); +} + /// Testing program for Util::Proc utility class. int main(){ Util::Procs::Start("number1", "./test.sh Koekjes"); - sleep(1); sleep(1); sleep(1); sleep(1); sleep(1); + sleepFive(); Util::Procs::Start("number2", "./testpipein.sh", "./testpipeout.sh"); - sleep(1); sleep(1); sleep(1); sleep(1); sleep(1); + sleepFive(); + Util::Procs::Start("number3", "./infitest.sh"); + sleepFive(); + Util::Procs::Stop("number3"); + Util::Procs::Start("number4", "./infitest.sh", "./testpipeout.sh"); + sleepFive(); + Util::Procs::Stop("number4"); return 0; }//main diff --git a/util/proc.cpp b/util/proc.cpp index db004d0d..b5257065 100644 --- a/util/proc.cpp +++ b/util/proc.cpp @@ -19,9 +19,16 @@ void Util::Procs::childsig_handler(int signum){ if (signum != SIGCHLD){return;} pid_t ret = wait(0); #if DEBUG >= 1 - std::cerr << "Process " << plist[ret] << " terminated." << std::endl; + std::string pname = plist[ret]; #endif plist.erase(ret); + #if DEBUG >= 1 + if (isActive(pname)){ + std::cerr << "Process " << pname << " half-terminated." << std::endl; + }else{ + std::cerr << "Process " << pname << " fully terminated." << std::endl; + } + #endif } /// Attempts to run the command cmd. @@ -99,53 +106,66 @@ pid_t Util::Procs::Start(std::string name, std::string cmd, std::string cmd2){ sigaction(SIGCHLD, &new_action, NULL); handler_set = true; } + int pfildes[2]; + if (pipe(pfildes) == -1){ + #if DEBUG >= 1 + std::cerr << "Process " << name << " could not be started. Pipe creation failed." << std::endl; + #endif + return 0; + } + pid_t ret = fork(); if (ret == 0){ - int pfildes[2]; - if (pipe(pfildes) == -1){ - #if DEBUG >= 1 - std::cerr << "Process " << name << " could not be started. Pipe creation failed." << std::endl; - #endif - _exit(41); - } - pid_t pid; - if ((pid = fork()) == -1){ - #if DEBUG >= 1 - std::cerr << "Process " << name << " could not be started. Second fork() failed." << std::endl; - #endif - _exit(41); - }else if (pid == 0){ - close(pfildes[0]); - dup2(pfildes[1],1); - close(pfildes[1]); - runCmd(cmd); - }else{ - close(pfildes[1]); - dup2(pfildes[0],0); - close(pfildes[0]); - runCmd(cmd2); - } + close(pfildes[0]); + dup2(pfildes[1],1); + close(pfildes[1]); + runCmd(cmd); }else{ if (ret > 0){ - #if DEBUG >= 1 - std::cerr << "Process " << name << " started, PID " << ret << ": " << cmd << " | " << cmd2 << std::endl; - #endif plist.insert(std::pair(ret, name)); }else{ #if DEBUG >= 1 std::cerr << "Process " << name << " could not be started. fork() failed." << std::endl; #endif + close(pfildes[1]); + close(pfildes[0]); return 0; } } + + pid_t ret2 = fork(); + if (ret2 == 0){ + close(pfildes[1]); + dup2(pfildes[0],0); + close(pfildes[0]); + runCmd(cmd2); + }else{ + if (ret2 > 0){ + #if DEBUG >= 1 + std::cerr << "Process " << name << " started, PIDs (" << ret << ", " << ret2 << "): " << cmd << " | " << cmd2 << std::endl; + #endif + plist.insert(std::pair(ret2, name)); + }else{ + #if DEBUG >= 1 + std::cerr << "Process " << name << " could not be started. fork() failed." << std::endl; + #endif + Stop(name); + close(pfildes[1]); + close(pfildes[0]); + return 0; + } + } + close(pfildes[1]); + close(pfildes[0]); return ret; } /// Stops the named process, if running. /// \arg name (Internal) name of process to stop void Util::Procs::Stop(std::string name){ - if (!isActive(name)){return;} - Stop(getPid(name)); + while (isActive(name)){ + Stop(getPid(name)); + } } /// Stops the process with this pid, if running.