Removed unused code from procs library, updated and simplified connector handler in controller.
This commit is contained in:
parent
184f7ad6c8
commit
243a05c8af
4 changed files with 56 additions and 439 deletions
400
lib/procs.cpp
400
lib/procs.cpp
|
@ -21,8 +21,7 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "timing.h"
|
#include "timing.h"
|
||||||
|
|
||||||
std::map<pid_t, std::string> Util::Procs::plist;
|
std::set<pid_t> Util::Procs::plist;
|
||||||
std::map<pid_t, Util::TerminationNotifier> Util::Procs::exitHandlers;
|
|
||||||
bool Util::Procs::handler_set = false;
|
bool Util::Procs::handler_set = false;
|
||||||
|
|
||||||
|
|
||||||
|
@ -39,7 +38,7 @@ static bool childRunning(pid_t p) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// sends sig 0 to process (pid). returns true if process is running
|
/// sends sig 0 to process (pid). returns true if process is running
|
||||||
bool Util::Procs::isRunnning(pid_t pid){
|
bool Util::Procs::isRunning(pid_t pid){
|
||||||
return !kill(pid, 0);
|
return !kill(pid, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,8 +48,8 @@ bool Util::Procs::isRunnning(pid_t pid){
|
||||||
/// all remaining children. Waits one more second for cleanup to finish, then exits.
|
/// all remaining children. Waits one more second for cleanup to finish, then exits.
|
||||||
void Util::Procs::exit_handler() {
|
void Util::Procs::exit_handler() {
|
||||||
int waiting = 0;
|
int waiting = 0;
|
||||||
std::map<pid_t, std::string> listcopy = plist;
|
std::set<pid_t> listcopy = plist;
|
||||||
std::map<pid_t, std::string>::iterator it;
|
std::set<pid_t>::iterator it;
|
||||||
if (listcopy.empty()) {
|
if (listcopy.empty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -58,7 +57,7 @@ void Util::Procs::exit_handler() {
|
||||||
//wait up to 0.5 second for applications to shut down
|
//wait up to 0.5 second for applications to shut down
|
||||||
while (!listcopy.empty() && waiting <= 25) {
|
while (!listcopy.empty() && waiting <= 25) {
|
||||||
for (it = listcopy.begin(); it != listcopy.end(); it++) {
|
for (it = listcopy.begin(); it != listcopy.end(); it++) {
|
||||||
if (!childRunning((*it).first)) {
|
if (!childRunning(*it)) {
|
||||||
listcopy.erase(it);
|
listcopy.erase(it);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -76,8 +75,8 @@ void Util::Procs::exit_handler() {
|
||||||
//send sigint to all remaining
|
//send sigint to all remaining
|
||||||
if (!listcopy.empty()) {
|
if (!listcopy.empty()) {
|
||||||
for (it = listcopy.begin(); it != listcopy.end(); it++) {
|
for (it = listcopy.begin(); it != listcopy.end(); it++) {
|
||||||
DEBUG_MSG(DLVL_DEVEL, "SIGINT %d: %s", (*it).first, (*it).second.c_str());
|
DEBUG_MSG(DLVL_DEVEL, "SIGINT %d", *it);
|
||||||
kill((*it).first, SIGINT);
|
kill(*it, SIGINT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,7 +85,7 @@ void Util::Procs::exit_handler() {
|
||||||
//wait up to 5 seconds for applications to shut down
|
//wait up to 5 seconds for applications to shut down
|
||||||
while (!listcopy.empty() && waiting <= 250) {
|
while (!listcopy.empty() && waiting <= 250) {
|
||||||
for (it = listcopy.begin(); it != listcopy.end(); it++) {
|
for (it = listcopy.begin(); it != listcopy.end(); it++) {
|
||||||
if (!childRunning((*it).first)) {
|
if (!childRunning(*it)) {
|
||||||
listcopy.erase(it);
|
listcopy.erase(it);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -104,8 +103,8 @@ void Util::Procs::exit_handler() {
|
||||||
//send sigkill to all remaining
|
//send sigkill to all remaining
|
||||||
if (!listcopy.empty()) {
|
if (!listcopy.empty()) {
|
||||||
for (it = listcopy.begin(); it != listcopy.end(); it++) {
|
for (it = listcopy.begin(); it != listcopy.end(); it++) {
|
||||||
DEBUG_MSG(DLVL_DEVEL, "SIGKILL %d: %s", (*it).first, (*it).second.c_str());
|
DEBUG_MSG(DLVL_DEVEL, "SIGKILL %d", *it);
|
||||||
kill((*it).first, SIGKILL);
|
kill(*it, SIGKILL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,7 +113,7 @@ void Util::Procs::exit_handler() {
|
||||||
//wait up to 1 second for applications to shut down
|
//wait up to 1 second for applications to shut down
|
||||||
while (!listcopy.empty() && waiting <= 50) {
|
while (!listcopy.empty() && waiting <= 50) {
|
||||||
for (it = listcopy.begin(); it != listcopy.end(); it++) {
|
for (it = listcopy.begin(); it != listcopy.end(); it++) {
|
||||||
if (!childRunning((*it).first)) {
|
if (!childRunning(*it)) {
|
||||||
listcopy.erase(it);
|
listcopy.erase(it);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -170,23 +169,15 @@ void Util::Procs::childsig_handler(int signum) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if DEBUG >= DLVL_HIGH
|
|
||||||
std::string pname = plist[ret];
|
|
||||||
#endif
|
|
||||||
plist.erase(ret);
|
plist.erase(ret);
|
||||||
#if DEBUG >= DLVL_HIGH
|
#if DEBUG >= DLVL_HIGH
|
||||||
if (!isActive(pname)) {
|
if (!isActive(pname)) {
|
||||||
DEBUG_MSG(DLVL_HIGH, "Process %s fully terminated", pname.c_str());
|
DEBUG_MSG(DLVL_HIGH, "Process %d fully terminated", ret);
|
||||||
} else {
|
} else {
|
||||||
DEBUG_MSG(DLVL_HIGH, "Child process %d exited", ret);
|
DEBUG_MSG(DLVL_HIGH, "Child process %d exited", ret);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (exitHandlers.count(ret) > 0) {
|
|
||||||
TerminationNotifier tn = exitHandlers[ret];
|
|
||||||
exitHandlers.erase(ret);
|
|
||||||
tn(ret, exitcode);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -195,8 +186,8 @@ void Util::Procs::childsig_handler(int signum) {
|
||||||
std::string Util::Procs::getOutputOf(char * const * argv) {
|
std::string Util::Procs::getOutputOf(char * const * argv) {
|
||||||
std::string ret;
|
std::string ret;
|
||||||
int fin = 0, fout = -1, ferr = 0;
|
int fin = 0, fout = -1, ferr = 0;
|
||||||
StartPiped("output_getter", argv, &fin, &fout, &ferr);
|
pid_t myProc = StartPiped(argv, &fin, &fout, &ferr);
|
||||||
while (isActive("output_getter")) {
|
while (isActive(myProc)) {
|
||||||
Util::sleep(100);
|
Util::sleep(100);
|
||||||
}
|
}
|
||||||
FILE * outFile = fdopen(fout, "r");
|
FILE * outFile = fdopen(fout, "r");
|
||||||
|
@ -210,258 +201,12 @@ std::string Util::Procs::getOutputOf(char * const * argv) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Runs the given command and returns the stdout output as a string.
|
|
||||||
std::string Util::Procs::getOutputOf(std::string cmd) {
|
|
||||||
std::string ret;
|
|
||||||
int fin = 0, fout = -1, ferr = 0;
|
|
||||||
StartPiped("output_getter", cmd, &fin, &fout, &ferr);
|
|
||||||
while (isActive("output_getter")) {
|
|
||||||
Util::sleep(100);
|
|
||||||
}
|
|
||||||
FILE * outFile = fdopen(fout, "r");
|
|
||||||
char * fileBuf = 0;
|
|
||||||
size_t fileBufLen = 0;
|
|
||||||
while (!(feof(outFile) || ferror(outFile)) && (getline(&fileBuf, &fileBufLen, outFile) != -1)) {
|
|
||||||
ret += fileBuf;
|
|
||||||
}
|
|
||||||
free(fileBuf);
|
|
||||||
fclose(outFile);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// Attempts to run the command cmd.
|
|
||||||
/// Replaces the current process - use after forking first!
|
|
||||||
/// This function will never return - it will either run the given
|
|
||||||
/// command or kill itself with return code 42.
|
|
||||||
void Util::Procs::runCmd(std::string & cmd) {
|
|
||||||
//split cmd into arguments
|
|
||||||
//supports a maximum of 20 arguments
|
|
||||||
char * tmp = (char *)cmd.c_str();
|
|
||||||
char * tmp2 = 0;
|
|
||||||
char * args[21];
|
|
||||||
int i = 0;
|
|
||||||
tmp2 = strtok(tmp, " ");
|
|
||||||
args[0] = tmp2;
|
|
||||||
while (tmp2 != 0 && (i < 20)) {
|
|
||||||
tmp2 = strtok(0, " ");
|
|
||||||
++i;
|
|
||||||
args[i] = tmp2;
|
|
||||||
}
|
|
||||||
if (i == 20) {
|
|
||||||
args[20] = 0;
|
|
||||||
}
|
|
||||||
//execute the command
|
|
||||||
execvp(args[0], args);
|
|
||||||
DEBUG_MSG(DLVL_ERROR, "Error running %s: %s", cmd.c_str(), strerror(errno));
|
|
||||||
_exit(42);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Starts a new process if the name is not already active.
|
|
||||||
/// \return 0 if process was not started, process PID otherwise.
|
|
||||||
/// \arg name Name for this process - only used internally.
|
|
||||||
/// \arg cmd Commandline for this process.
|
|
||||||
pid_t Util::Procs::Start(std::string name, std::string cmd) {
|
|
||||||
if (isActive(name)) {
|
|
||||||
return getPid(name);
|
|
||||||
}
|
|
||||||
setHandler();
|
|
||||||
pid_t ret = fork();
|
|
||||||
if (ret == 0) {
|
|
||||||
runCmd(cmd);
|
|
||||||
} else {
|
|
||||||
if (ret > 0) {
|
|
||||||
DEBUG_MSG(DLVL_HIGH, "Process %s started, PID %d: %s", name.c_str(), ret, cmd.c_str());
|
|
||||||
plist.insert(std::pair<pid_t, std::string>(ret, name));
|
|
||||||
} else {
|
|
||||||
DEBUG_MSG(DLVL_ERROR, "Process %s could not be started: fork() failed", name.c_str());
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Starts two piped processes if the name is not already active.
|
|
||||||
/// \return 0 if process was not started, sub (sending) process PID otherwise.
|
|
||||||
/// \arg name Name for this process - only used internally.
|
|
||||||
/// \arg cmd Commandline for sub (sending) process.
|
|
||||||
/// \arg cmd2 Commandline for main (receiving) process.
|
|
||||||
pid_t Util::Procs::Start(std::string name, std::string cmd, std::string cmd2) {
|
|
||||||
if (isActive(name)) {
|
|
||||||
return getPid(name);
|
|
||||||
}
|
|
||||||
setHandler();
|
|
||||||
int pfildes[2];
|
|
||||||
if (pipe(pfildes) == -1) {
|
|
||||||
DEBUG_MSG(DLVL_ERROR, "Process %s could not be started. Pipe creation failed.", name.c_str());
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int devnull = open("/dev/null", O_RDWR);
|
|
||||||
pid_t ret = fork();
|
|
||||||
if (ret == 0) {
|
|
||||||
close(pfildes[0]);
|
|
||||||
dup2(pfildes[1], STDOUT_FILENO);
|
|
||||||
close(pfildes[1]);
|
|
||||||
dup2(devnull, STDIN_FILENO);
|
|
||||||
dup2(devnull, STDERR_FILENO);
|
|
||||||
runCmd(cmd);
|
|
||||||
} else {
|
|
||||||
if (ret > 0) {
|
|
||||||
plist.insert(std::pair<pid_t, std::string>(ret, name));
|
|
||||||
} else {
|
|
||||||
DEBUG_MSG(DLVL_ERROR, "Process %s could not be started. fork() failed.", name.c_str());
|
|
||||||
close(pfildes[1]);
|
|
||||||
close(pfildes[0]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pid_t ret2 = fork();
|
|
||||||
if (ret2 == 0) {
|
|
||||||
close(pfildes[1]);
|
|
||||||
dup2(pfildes[0], STDIN_FILENO);
|
|
||||||
close(pfildes[0]);
|
|
||||||
dup2(devnull, STDOUT_FILENO);
|
|
||||||
dup2(devnull, STDERR_FILENO);
|
|
||||||
runCmd(cmd2);
|
|
||||||
} else {
|
|
||||||
if (ret2 > 0) {
|
|
||||||
DEBUG_MSG(DLVL_HIGH, "Process %s started, PIDs (%d, %d): %s | %s", name.c_str(), ret, ret2, cmd.c_str(), cmd2.c_str());
|
|
||||||
plist.insert(std::pair<pid_t, std::string>(ret2, name));
|
|
||||||
} else {
|
|
||||||
DEBUG_MSG(DLVL_ERROR, "Process %s could not be started. fork() failed.", name.c_str());
|
|
||||||
Stop(name);
|
|
||||||
close(pfildes[1]);
|
|
||||||
close(pfildes[0]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
close(pfildes[1]);
|
|
||||||
close(pfildes[0]);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Starts three piped processes if the name is not already active.
|
|
||||||
/// \return 0 if process was not started, sub (sending) process PID otherwise.
|
|
||||||
/// \arg name Name for this process - only used internally.
|
|
||||||
/// \arg cmd Commandline for sub (sending) process.
|
|
||||||
/// \arg cmd2 Commandline for sub (middle) process.
|
|
||||||
/// \arg cmd3 Commandline for main (receiving) process.
|
|
||||||
pid_t Util::Procs::Start(std::string name, std::string cmd, std::string cmd2, std::string cmd3) {
|
|
||||||
if (isActive(name)) {
|
|
||||||
return getPid(name);
|
|
||||||
}
|
|
||||||
setHandler();
|
|
||||||
int pfildes[2];
|
|
||||||
int pfildes2[2];
|
|
||||||
if (pipe(pfildes) == -1) {
|
|
||||||
DEBUG_MSG(DLVL_ERROR, "Process %s could not be started. Pipe creation failed.", name.c_str());
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (pipe(pfildes2) == -1) {
|
|
||||||
DEBUG_MSG(DLVL_ERROR, "Process %s could not be started. Pipe creation failed.", name.c_str());
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int devnull = open("/dev/null", O_RDWR);
|
|
||||||
pid_t ret = fork();
|
|
||||||
if (ret == 0) {
|
|
||||||
close(pfildes[0]);
|
|
||||||
dup2(pfildes[1], STDOUT_FILENO);
|
|
||||||
close(pfildes[1]);
|
|
||||||
dup2(devnull, STDIN_FILENO);
|
|
||||||
dup2(devnull, STDERR_FILENO);
|
|
||||||
close(pfildes2[1]);
|
|
||||||
close(pfildes2[0]);
|
|
||||||
runCmd(cmd);
|
|
||||||
} else {
|
|
||||||
if (ret > 0) {
|
|
||||||
plist.insert(std::pair<pid_t, std::string>(ret, name));
|
|
||||||
} else {
|
|
||||||
DEBUG_MSG(DLVL_ERROR, "Process %s could not be started. fork() failed.", name.c_str());
|
|
||||||
close(pfildes[1]);
|
|
||||||
close(pfildes[0]);
|
|
||||||
close(pfildes2[1]);
|
|
||||||
close(pfildes2[0]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pid_t ret2 = fork();
|
|
||||||
if (ret2 == 0) {
|
|
||||||
close(pfildes[1]);
|
|
||||||
close(pfildes2[0]);
|
|
||||||
dup2(pfildes[0], STDIN_FILENO);
|
|
||||||
close(pfildes[0]);
|
|
||||||
dup2(pfildes2[1], STDOUT_FILENO);
|
|
||||||
close(pfildes2[1]);
|
|
||||||
dup2(devnull, STDERR_FILENO);
|
|
||||||
runCmd(cmd2);
|
|
||||||
} else {
|
|
||||||
if (ret2 > 0) {
|
|
||||||
DEBUG_MSG(DLVL_HIGH, "Process %s started, PIDs (%d, %d): %s | %s", name.c_str(), ret, ret2, cmd.c_str(), cmd2.c_str());
|
|
||||||
plist.insert(std::pair<pid_t, std::string>(ret2, name));
|
|
||||||
} else {
|
|
||||||
DEBUG_MSG(DLVL_ERROR, "Process %s could not be started. fork() failed.", name.c_str());
|
|
||||||
Stop(name);
|
|
||||||
close(pfildes[1]);
|
|
||||||
close(pfildes[0]);
|
|
||||||
close(pfildes2[1]);
|
|
||||||
close(pfildes2[0]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
close(pfildes[1]);
|
|
||||||
close(pfildes[0]);
|
|
||||||
|
|
||||||
pid_t ret3 = fork();
|
|
||||||
if (ret3 == 0) {
|
|
||||||
close(pfildes[1]);
|
|
||||||
close(pfildes[0]);
|
|
||||||
close(pfildes2[1]);
|
|
||||||
dup2(pfildes2[0], STDIN_FILENO);
|
|
||||||
close(pfildes2[0]);
|
|
||||||
dup2(devnull, STDOUT_FILENO);
|
|
||||||
dup2(devnull, STDERR_FILENO);
|
|
||||||
runCmd(cmd3);
|
|
||||||
} else {
|
|
||||||
if (ret3 > 0) {
|
|
||||||
DEBUG_MSG(DLVL_HIGH, "Process %s started, PIDs (%d, %d, %d): %s | %s | %s", name.c_str(), ret, ret2, ret3, cmd.c_str(), cmd2.c_str(), cmd3.c_str());
|
|
||||||
plist.insert(std::pair<pid_t, std::string>(ret3, name));
|
|
||||||
} else {
|
|
||||||
DEBUG_MSG(DLVL_ERROR, "Process %s could not be started. fork() failed.", name.c_str());
|
|
||||||
Stop(name);
|
|
||||||
close(pfildes[1]);
|
|
||||||
close(pfildes[0]);
|
|
||||||
close(pfildes2[1]);
|
|
||||||
close(pfildes2[0]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret3;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Starts a new process with given fds if the name is not already active.
|
/// Starts a new process with given fds if the name is not already active.
|
||||||
/// \return 0 if process was not started, process PID otherwise.
|
/// \return 0 if process was not started, process PID otherwise.
|
||||||
/// \arg name Name for this process - only used internally.
|
|
||||||
/// \arg argv Command for this process.
|
/// \arg argv Command for this process.
|
||||||
/// \arg fdin Standard input file descriptor. If null, /dev/null is assumed. Otherwise, if arg contains -1, a new fd is automatically allocated and written into this arg. Then the arg will be used as fd.
|
/// \arg fdin Standard input file descriptor. If null, /dev/null is assumed. Otherwise, if arg contains -1, a new fd is automatically allocated and written into this arg. Then the arg will be used as fd.
|
||||||
/// \arg fdout Same as fdin, but for stdout.
|
/// \arg fdout Same as fdin, but for stdout.
|
||||||
/// \arg fdout Same as fdin, but for stderr.
|
/// \arg fdout Same as fdin, but for stderr.
|
||||||
pid_t Util::Procs::StartPiped(std::string name, char * const * argv, int * fdin, int * fdout, int * fderr) {
|
|
||||||
if (isActive(name)) {
|
|
||||||
DEBUG_MSG(DLVL_WARN, "Process %s already active - skipping start", name.c_str());
|
|
||||||
return getPid(name);
|
|
||||||
}
|
|
||||||
int pidtemp = StartPiped(argv, fdin, fdout, fderr);
|
|
||||||
if (pidtemp > 0) {
|
|
||||||
plist.insert(std::pair<pid_t, std::string>(pidtemp, name));
|
|
||||||
}
|
|
||||||
return pidtemp;
|
|
||||||
}
|
|
||||||
|
|
||||||
pid_t Util::Procs::StartPiped(char * const * argv, int * fdin, int * fdout, int * fderr) {
|
pid_t Util::Procs::StartPiped(char * const * argv, int * fdin, int * fdout, int * fderr) {
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
int pipein[2], pipeout[2], pipeerr[2];
|
int pipein[2], pipeout[2], pipeerr[2];
|
||||||
|
@ -574,6 +319,7 @@ pid_t Util::Procs::StartPiped(char * const * argv, int * fdin, int * fdout, int
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
} else { //parent
|
} else { //parent
|
||||||
|
plist.insert(pid);
|
||||||
DEBUG_MSG(DLVL_HIGH, "Piped process %s started, PID %d", argv[0], pid);
|
DEBUG_MSG(DLVL_HIGH, "Piped process %s started, PID %d", argv[0], pid);
|
||||||
if (devnull != -1) {
|
if (devnull != -1) {
|
||||||
close(devnull);
|
close(devnull);
|
||||||
|
@ -594,70 +340,6 @@ pid_t Util::Procs::StartPiped(char * const * argv, int * fdin, int * fdout, int
|
||||||
return pid;
|
return pid;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Starts a new process with given fds if the name is not already active.
|
|
||||||
/// \return 0 if process was not started, process PID otherwise.
|
|
||||||
/// \arg name Name for this process - only used internally.
|
|
||||||
/// \arg cmd Command for this process.
|
|
||||||
/// \arg fdin Standard input file descriptor. If null, /dev/null is assumed. Otherwise, if arg contains -1, a new fd is automatically allocated and written into this arg. Then the arg will be used as fd.
|
|
||||||
/// \arg fdout Same as fdin, but for stdout.
|
|
||||||
/// \arg fdout Same as fdin, but for stderr.
|
|
||||||
pid_t Util::Procs::StartPiped(std::string name, std::string cmd, int * fdin, int * fdout, int * fderr) {
|
|
||||||
//Convert the given command to a char * []
|
|
||||||
char * tmp = (char *)cmd.c_str();
|
|
||||||
char * tmp2 = 0;
|
|
||||||
char * args[21];
|
|
||||||
int i = 0;
|
|
||||||
tmp2 = strtok(tmp, " ");
|
|
||||||
args[0] = tmp2;
|
|
||||||
while (tmp2 != 0 && (i < 20)) {
|
|
||||||
tmp2 = strtok(0, " ");
|
|
||||||
++i;
|
|
||||||
args[i] = tmp2;
|
|
||||||
}
|
|
||||||
if (i == 20) {
|
|
||||||
args[20] = 0;
|
|
||||||
}
|
|
||||||
return StartPiped(name, args, fdin, fdout, fderr);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
pid_t Util::Procs::StartPiped2(std::string name, std::string cmd1, std::string cmd2, int * fdin, int * fdout, int * fderr1, int * fderr2) {
|
|
||||||
int pfildes[2];
|
|
||||||
if (pipe(pfildes) == -1) {
|
|
||||||
DEBUG_MSG(DLVL_ERROR, "Pipe creation failed for process %s", name.c_str());
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
pid_t res1 = StartPiped(name, cmd1, fdin, &pfildes[1], fderr1);
|
|
||||||
if (!res1) {
|
|
||||||
close(pfildes[1]);
|
|
||||||
close(pfildes[0]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
pid_t res2 = StartPiped(name + "receiving", cmd2, &pfildes[0], fdout, fderr2);
|
|
||||||
if (!res2) {
|
|
||||||
Stop(res1);
|
|
||||||
close(pfildes[1]);
|
|
||||||
close(pfildes[0]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
//we can close these because the fork in StartPiped() copies them.
|
|
||||||
close(pfildes[1]);
|
|
||||||
close(pfildes[0]);
|
|
||||||
return res1;
|
|
||||||
}
|
|
||||||
/// Stops the named process, if running.
|
|
||||||
/// \arg name (Internal) name of process to stop
|
|
||||||
void Util::Procs::Stop(std::string name) {
|
|
||||||
int max = 5;
|
|
||||||
while (isActive(name)) {
|
|
||||||
Stop(getPid(name));
|
|
||||||
max--;
|
|
||||||
if (max <= 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Stops the process with this pid, if running.
|
/// Stops the process with this pid, if running.
|
||||||
/// \arg name The PID of the process to stop.
|
/// \arg name The PID of the process to stop.
|
||||||
void Util::Procs::Stop(pid_t name) {
|
void Util::Procs::Stop(pid_t name) {
|
||||||
|
@ -672,10 +354,10 @@ void Util::Procs::Murder(pid_t name) {
|
||||||
|
|
||||||
/// (Attempts to) stop all running child processes.
|
/// (Attempts to) stop all running child processes.
|
||||||
void Util::Procs::StopAll() {
|
void Util::Procs::StopAll() {
|
||||||
std::map<pid_t, std::string> listcopy = plist;
|
std::set<pid_t> listcopy = plist;
|
||||||
std::map<pid_t, std::string>::iterator it;
|
std::set<pid_t>::iterator it;
|
||||||
for (it = listcopy.begin(); it != listcopy.end(); it++) {
|
for (it = listcopy.begin(); it != listcopy.end(); it++) {
|
||||||
Stop((*it).first);
|
Stop(*it);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -684,54 +366,8 @@ int Util::Procs::Count() {
|
||||||
return plist.size();
|
return plist.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if a process by this name is currently active.
|
|
||||||
bool Util::Procs::isActive(std::string name) {
|
|
||||||
std::map<pid_t, std::string> listcopy = plist;
|
|
||||||
std::map<pid_t, std::string>::iterator it;
|
|
||||||
for (it = listcopy.begin(); it != listcopy.end(); it++) {
|
|
||||||
if ((*it).second == name) {
|
|
||||||
if (childRunning((*it).first)) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
plist.erase((*it).first);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns true if a process with this PID is currently active.
|
/// Returns true if a process with this PID is currently active.
|
||||||
bool Util::Procs::isActive(pid_t name) {
|
bool Util::Procs::isActive(pid_t name) {
|
||||||
return (plist.count(name) == 1) && (kill(name, 0) == 0);
|
return (plist.count(name) == 1) && (kill(name, 0) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets PID for this named process, if active.
|
|
||||||
/// \return NULL if not active, process PID otherwise.
|
|
||||||
pid_t Util::Procs::getPid(std::string name) {
|
|
||||||
std::map<pid_t, std::string>::iterator it;
|
|
||||||
for (it = plist.begin(); it != plist.end(); it++) {
|
|
||||||
if ((*it).second == name) {
|
|
||||||
return (*it).first;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Gets name for this process PID, if active.
|
|
||||||
/// \return Empty string if not active, name otherwise.
|
|
||||||
std::string Util::Procs::getName(pid_t name) {
|
|
||||||
if (plist.count(name) == 1) {
|
|
||||||
return plist[name];
|
|
||||||
}
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Registers one notifier function for when a process indentified by PID terminates.
|
|
||||||
/// \return true if the notifier could be registered, false otherwise.
|
|
||||||
bool Util::Procs::SetTerminationNotifier(pid_t pid, TerminationNotifier notifier) {
|
|
||||||
if (plist.find(pid) != plist.end()) {
|
|
||||||
exitHandlers[pid] = notifier;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
21
lib/procs.h
21
lib/procs.h
|
@ -4,19 +4,16 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <map>
|
#include <set>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
/// Contains utility code, not directly related to streaming media
|
/// Contains utility code, not directly related to streaming media
|
||||||
namespace Util {
|
namespace Util {
|
||||||
|
|
||||||
typedef void (*TerminationNotifier)(pid_t pid, int exitCode);
|
|
||||||
|
|
||||||
/// Deals with spawning, monitoring and stopping child processes
|
/// Deals with spawning, monitoring and stopping child processes
|
||||||
class Procs {
|
class Procs {
|
||||||
private:
|
private:
|
||||||
static std::map<pid_t, std::string> plist; ///< Holds active processes
|
static std::set<pid_t> plist; ///< Holds active processes
|
||||||
static std::map<pid_t, TerminationNotifier> exitHandlers; ///< termination function, if any
|
|
||||||
static bool handler_set; ///< If true, the sigchld handler has been setup.
|
static bool handler_set; ///< If true, the sigchld handler has been setup.
|
||||||
static void childsig_handler(int signum);
|
static void childsig_handler(int signum);
|
||||||
static void exit_handler();
|
static void exit_handler();
|
||||||
|
@ -24,25 +21,13 @@ namespace Util {
|
||||||
static void setHandler();
|
static void setHandler();
|
||||||
public:
|
public:
|
||||||
static std::string getOutputOf(char * const * argv);
|
static std::string getOutputOf(char * const * argv);
|
||||||
static std::string getOutputOf(std::string cmd);
|
|
||||||
static pid_t Start(std::string name, std::string cmd);
|
|
||||||
static pid_t Start(std::string name, std::string cmd, std::string cmd2);
|
|
||||||
static pid_t Start(std::string name, std::string cmd, std::string cmd2, std::string cmd3);
|
|
||||||
static pid_t StartPiped(char * const * argv, int * fdin, int * fdout, int * fderr);
|
static pid_t StartPiped(char * const * argv, int * fdin, int * fdout, int * fderr);
|
||||||
static pid_t StartPiped(std::string name, char * const * argv, int * fdin, int * fdout, int * fderr);
|
|
||||||
static pid_t StartPiped(std::string name, std::string cmd, int * fdin, int * fdout, int * fderr);
|
|
||||||
static pid_t StartPiped2(std::string name, std::string cmd1, std::string cmd2, int * fdin, int * fdout, int * fderr1, int * fderr2);
|
|
||||||
static void Stop(std::string name);
|
|
||||||
static void Stop(pid_t name);
|
static void Stop(pid_t name);
|
||||||
static void Murder(pid_t name);
|
static void Murder(pid_t name);
|
||||||
static void StopAll();
|
static void StopAll();
|
||||||
static int Count();
|
static int Count();
|
||||||
static bool isActive(std::string name);
|
|
||||||
static bool isActive(pid_t name);
|
static bool isActive(pid_t name);
|
||||||
static bool isRunnning(pid_t pid);
|
static bool isRunning(pid_t pid);
|
||||||
static pid_t getPid(std::string name);
|
|
||||||
static std::string getName(pid_t name);
|
|
||||||
static bool SetTerminationNotifier(pid_t pid, TerminationNotifier notifier);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -305,12 +305,12 @@ namespace IPC {
|
||||||
} while (i < 10 && !handle && autoBackoff);
|
} while (i < 10 && !handle && autoBackoff);
|
||||||
}
|
}
|
||||||
if (!handle) {
|
if (!handle) {
|
||||||
FAIL_MSG("%s for page %s failed: %s", (master ? "CreateFileMapping" : "OpenFileMapping"), name.c_str(), strerror(errno));
|
FAIL_MSG("%s for page %s failed with error code %u", (master ? "CreateFileMapping" : "OpenFileMapping"), name.c_str(), GetLastError());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mapped = (char *)MapViewOfFile(handle, FILE_MAP_ALL_ACCESS, 0, 0, 0);
|
mapped = (char *)MapViewOfFile(handle, FILE_MAP_ALL_ACCESS, 0, 0, 0);
|
||||||
if (!mapped) {
|
if (!mapped) {
|
||||||
FAIL_MSG("MapViewOfFile for page %s failed: %s", name.c_str(), strerror(errno));
|
FAIL_MSG("MapViewOfFile for page %s failed with error code %u", name.c_str(), GetLastError());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
//Under cygwin, the extra 4 bytes contain the real size of the page.
|
//Under cygwin, the extra 4 bytes contain the real size of the page.
|
||||||
|
@ -740,7 +740,7 @@ namespace IPC {
|
||||||
DEBUG_MSG(DLVL_VERYHIGH, "Shared memory %s is now at count %u", baseName.c_str(), amount);
|
DEBUG_MSG(DLVL_VERYHIGH, "Shared memory %s is now at count %u", baseName.c_str(), amount);
|
||||||
}
|
}
|
||||||
unsigned short tmpPID = *((unsigned short *)(it->mapped+1+offset+payLen-2));
|
unsigned short tmpPID = *((unsigned short *)(it->mapped+1+offset+payLen-2));
|
||||||
if(!Util::Procs::isRunnning(tmpPID) && !(*counter == 126 || *counter == 127 || *counter == 254 || *counter == 255)){
|
if(!Util::Procs::isRunning(tmpPID) && !(*counter == 126 || *counter == 127 || *counter == 254 || *counter == 255)){
|
||||||
WARN_MSG("process disappeared, timing out. (pid %d)", tmpPID);
|
WARN_MSG("process disappeared, timing out. (pid %d)", tmpPID);
|
||||||
*counter = 126; //if process is already dead, instant timeout.
|
*counter = 126; //if process is already dead, instant timeout.
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,21 +18,16 @@
|
||||||
///\brief Holds everything unique to the controller.
|
///\brief Holds everything unique to the controller.
|
||||||
namespace Controller {
|
namespace Controller {
|
||||||
|
|
||||||
static std::map<long long, std::string> currentConnectors; ///<The currently running connectors.
|
static std::map<std::string, pid_t> currentConnectors; ///<The currently running connectors.
|
||||||
|
|
||||||
|
|
||||||
static inline std::string toConn(long long i){
|
|
||||||
return std::string("Conn") + JSON::Value(i).asString();
|
|
||||||
}
|
|
||||||
|
|
||||||
///\brief Checks if the binary mentioned in the protocol argument is currently active, if so, restarts it.
|
///\brief Checks if the binary mentioned in the protocol argument is currently active, if so, restarts it.
|
||||||
///\param protocol The protocol to check.
|
///\param protocol The protocol to check.
|
||||||
void UpdateProtocol(std::string protocol){
|
void UpdateProtocol(std::string protocol){
|
||||||
std::map<long long, std::string>::iterator iter;
|
std::map<std::string, pid_t>::iterator iter;
|
||||||
for (iter = currentConnectors.begin(); iter != currentConnectors.end(); iter++){
|
for (iter = currentConnectors.begin(); iter != currentConnectors.end(); iter++){
|
||||||
if (iter->second.substr(0, protocol.size()) == protocol){
|
if (iter->first.substr(0, protocol.size()) == protocol){
|
||||||
Log("CONF", "Killing connector for update: " + iter->second);
|
Log("CONF", "Killing connector for update: " + iter->first);
|
||||||
Util::Procs::Stop(toConn(iter->first));
|
Util::Procs::Stop(iter->second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -65,7 +60,8 @@ namespace Controller {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void buildPipedArguments(JSON::Value & p, char * argarr[], JSON::Value & capabilities){
|
static inline void buildPipedArguments(const std::string & proto, char * argarr[], JSON::Value & capabilities){
|
||||||
|
JSON::Value p = JSON::fromString(proto);
|
||||||
int argnum = 0;
|
int argnum = 0;
|
||||||
static std::string tmparg;
|
static std::string tmparg;
|
||||||
tmparg = Util::getMyPath() + std::string("MistOut") + p["connector"].asStringRef();
|
tmparg = Util::getMyPath() + std::string("MistOut") + p["connector"].asStringRef();
|
||||||
|
@ -82,12 +78,11 @@ namespace Controller {
|
||||||
if (pipedCapa.isMember("optional")){builPipedPart(p, argarr, argnum, pipedCapa["optional"]);}
|
if (pipedCapa.isMember("optional")){builPipedPart(p, argarr, argnum, pipedCapa["optional"]);}
|
||||||
}
|
}
|
||||||
|
|
||||||
///\brief Checks current protocol coguration, updates state of enabled connectors if neccesary.
|
///\brief Checks current protocol configuration, updates state of enabled connectors if neccessary.
|
||||||
///\param p An object containing all protocols.
|
///\param p An object containing all protocols.
|
||||||
///\param capabilities An object containing the detected capabilities.
|
///\param capabilities An object containing the detected capabilities.
|
||||||
void CheckProtocols(JSON::Value & p, JSON::Value & capabilities){
|
void CheckProtocols(JSON::Value & p, JSON::Value & capabilities){
|
||||||
std::map<long long, std::string> new_connectors;
|
std::set<std::string> runningConns;
|
||||||
std::map<long long, std::string>::iterator iter;
|
|
||||||
|
|
||||||
// used for building args
|
// used for building args
|
||||||
int zero = 0;
|
int zero = 0;
|
||||||
|
@ -102,12 +97,13 @@ namespace Controller {
|
||||||
for (JSON::ArrIter ait = p.ArrBegin(); ait != p.ArrEnd(); ait++){
|
for (JSON::ArrIter ait = p.ArrBegin(); ait != p.ArrEnd(); ait++){
|
||||||
counter = ait - p.ArrBegin();
|
counter = ait - p.ArrBegin();
|
||||||
std::string prevOnline = ( *ait)["online"].asString();
|
std::string prevOnline = ( *ait)["online"].asString();
|
||||||
#define connName (*ait)["connector"].asStringRef()
|
const std::string & connName = (*ait)["connector"].asStringRef();
|
||||||
|
//do not further parse if there's no connector name
|
||||||
if ( !(*ait).isMember("connector") || connName == ""){
|
if ( !(*ait).isMember("connector") || connName == ""){
|
||||||
( *ait)["online"] = "Missing connector name";
|
( *ait)["online"] = "Missing connector name";
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
//ignore connectors that are not installed
|
||||||
if ( !capabilities["connectors"].isMember(connName)){
|
if ( !capabilities["connectors"].isMember(connName)){
|
||||||
( *ait)["online"] = "Not installed";
|
( *ait)["online"] = "Not installed";
|
||||||
if (( *ait)["online"].asString() != prevOnline){
|
if (( *ait)["online"].asString() != prevOnline){
|
||||||
|
@ -115,14 +111,13 @@ namespace Controller {
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
//list connectors that go through HTTP as 'enabled' without actually running them.
|
||||||
#define connCapa capabilities["connectors"][connName]
|
JSON::Value & connCapa = capabilities["connectors"][connName];
|
||||||
|
|
||||||
if (connCapa.isMember("socket") || (connCapa.isMember("deps") && connCapa["deps"].asStringRef() == "HTTP")){
|
if (connCapa.isMember("socket") || (connCapa.isMember("deps") && connCapa["deps"].asStringRef() == "HTTP")){
|
||||||
( *ait)["online"] = "Enabled";
|
( *ait)["online"] = "Enabled";
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
//check required parameters, skip if anything is missing
|
||||||
if (connCapa.isMember("required")){
|
if (connCapa.isMember("required")){
|
||||||
bool gotAll = true;
|
bool gotAll = true;
|
||||||
for (JSON::ObjIter it = connCapa["required"].ObjBegin(); it != connCapa["required"].ObjEnd(); ++it){
|
for (JSON::ObjIter it = connCapa["required"].ObjBegin(); it != connCapa["required"].ObjEnd(); ++it){
|
||||||
|
@ -137,12 +132,13 @@ namespace Controller {
|
||||||
}
|
}
|
||||||
if (!gotAll){continue;}
|
if (!gotAll){continue;}
|
||||||
}
|
}
|
||||||
|
//remove current online status
|
||||||
( *ait).removeMember("online");
|
( *ait).removeMember("online");
|
||||||
/// \todo Check dependencies?
|
/// \todo Check dependencies?
|
||||||
|
//set current online status
|
||||||
new_connectors[counter] = (*ait).toString();
|
std::string myCmd = (*ait).toString();
|
||||||
if (Util::Procs::isActive(toConn(counter))){
|
runningConns.insert(myCmd);
|
||||||
|
if (currentConnectors.count(myCmd) && Util::Procs::isActive(currentConnectors[myCmd])){
|
||||||
( *ait)["online"] = 1;
|
( *ait)["online"] = 1;
|
||||||
}else{
|
}else{
|
||||||
( *ait)["online"] = 0;
|
( *ait)["online"] = 0;
|
||||||
|
@ -150,28 +146,28 @@ namespace Controller {
|
||||||
}
|
}
|
||||||
|
|
||||||
//shut down deleted/changed connectors
|
//shut down deleted/changed connectors
|
||||||
for (iter = currentConnectors.begin(); iter != currentConnectors.end(); iter++){
|
std::map<std::string, pid_t>::iterator it;
|
||||||
if (new_connectors.count(iter->first) != 1 || new_connectors[iter->first] != iter->second){
|
for (it = currentConnectors.begin(); it != currentConnectors.end(); it++){
|
||||||
Log("CONF", "Stopping connector " + iter->second);
|
if (!runningConns.count(it->first)){
|
||||||
Util::Procs::Stop(toConn(iter->first));
|
Log("CONF", "Stopping connector " + it->first);
|
||||||
|
Util::Procs::Stop(it->second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//start up new/changed connectors
|
//start up new/changed connectors
|
||||||
for (iter = new_connectors.begin(); iter != new_connectors.end(); iter++){
|
while (runningConns.size() && conf.is_active){
|
||||||
if (currentConnectors.count(iter->first) != 1 || currentConnectors[iter->first] != iter->second || !Util::Procs::isActive(toConn(iter->first))){
|
if (!currentConnectors.count(*runningConns.begin()) || !Util::Procs::isActive(currentConnectors[*runningConns.begin()])){
|
||||||
Log("CONF", "Starting connector: " + iter->second);
|
Log("CONF", "Starting connector: " + *runningConns.begin());
|
||||||
// clear out old args
|
// clear out old args
|
||||||
for (i=0; i<15; i++){argarr[i] = 0;}
|
for (i=0; i<15; i++){argarr[i] = 0;}
|
||||||
// get args for this connector
|
// get args for this connector
|
||||||
buildPipedArguments(p[(long long unsigned)iter->first], (char **)&argarr, capabilities);
|
buildPipedArguments(*runningConns.begin(), (char **)&argarr, capabilities);
|
||||||
// start piped w/ generated args
|
// start piped w/ generated args
|
||||||
Util::Procs::StartPiped(toConn(iter->first), argarr, &zero, &out, &err);//redirects output to out. Must make a new pipe, redirect std err
|
currentConnectors[*runningConns.begin()] = Util::Procs::StartPiped(argarr, &zero, &out, &err);
|
||||||
|
}
|
||||||
|
runningConns.erase(runningConns.begin());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//store new state
|
|
||||||
currentConnectors = new_connectors;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue