GLInjectInput.cpp (ssr-0.4.0) | : | GLInjectInput.cpp (ssr-0.4.1) | ||
---|---|---|---|---|
skipping to change at line 44 | skipping to change at line 44 | |||
char specials[] = "\\#&;`|*?~<>^()[]{}$\x0a\xff\""; // backslash must be first | char specials[] = "\\#&;`|*?~<>^()[]{}$\x0a\xff\""; // backslash must be first | |||
for(unsigned int i = 0; i < sizeof(specials); ++i) { | for(unsigned int i = 0; i < sizeof(specials); ++i) { | |||
str.replace(QChar(specials[i]), QString("\\") + QChar(specials[i] )); | str.replace(QChar(specials[i]), QString("\\") + QChar(specials[i] )); | |||
} | } | |||
return str; | return str; | |||
} | } | |||
// The highest expected latency between GLInject and the input thread. | // The highest expected latency between GLInject and the input thread. | |||
const int64_t GLInjectInput::MAX_COMMUNICATION_LATENCY = 100000; | const int64_t GLInjectInput::MAX_COMMUNICATION_LATENCY = 100000; | |||
bool ExecuteDetached(const char* command, const char* working_directory) { | ||||
// set up feedback pipe | ||||
int feedback_pipe[2]; | ||||
if(pipe2(feedback_pipe, O_CLOEXEC) == -1) { | ||||
return false; | ||||
} | ||||
// fork process | ||||
pid_t pid1 = fork(); | ||||
if(pid1 == -1) { | ||||
// fork failed | ||||
close(feedback_pipe[0]); | ||||
close(feedback_pipe[1]); | ||||
return false; | ||||
} else if(pid1 == 0) { | ||||
// we are the first child | ||||
close(feedback_pipe[0]); | ||||
setsid(); | ||||
// fork again | ||||
pid_t pid2 = fork(); | ||||
if(pid2 == -1) { | ||||
// fork failed, send feedback | ||||
char buf = 1; | ||||
write(feedback_pipe[1], &buf, 1); | ||||
close(feedback_pipe[1]); | ||||
_exit(EXIT_FAILURE); | ||||
} else if(pid2 == 0) { | ||||
// we are the second child | ||||
int devnull; | ||||
do { | ||||
devnull = open("/dev/null", O_RDWR); | ||||
} while(devnull == -1 && errno == EINTR); | ||||
if(devnull == -1) { | ||||
// failed, send feedback | ||||
char buf = 1; | ||||
write(feedback_pipe[1], &buf, 1); | ||||
close(feedback_pipe[1]); | ||||
_exit(EXIT_FAILURE); | ||||
} | ||||
// redirect stdin, stdout and stderr to /dev/null | ||||
int res; | ||||
do { res = dup2(devnull, STDIN_FILENO); } while(res == -1 | ||||
&& errno == EINTR); | ||||
do { res = dup2(devnull, STDOUT_FILENO); } while(res == - | ||||
1 && errno == EINTR); | ||||
do { res = dup2(devnull, STDERR_FILENO); } while(res == - | ||||
1 && errno == EINTR); | ||||
do { res = close(devnull); } while(res == -1 && errno == | ||||
EINTR); | ||||
// try to change working directory | ||||
if(working_directory != NULL) { | ||||
if(chdir(working_directory) == -1) { | ||||
// failed, send feedback | ||||
char buf = 1; | ||||
write(feedback_pipe[1], &buf, 1); | ||||
close(feedback_pipe[1]); | ||||
_exit(EXIT_FAILURE); | ||||
} | ||||
} | ||||
// try to execute command | ||||
do { | ||||
res = execl("/bin/sh", "/bin/sh", "-c", command, | ||||
(char*) NULL); | ||||
} while(res == -1 and errno == EINTR); | ||||
// failed, send feedback | ||||
char buf = 1; | ||||
write(feedback_pipe[1], &buf, 1); | ||||
close(feedback_pipe[1]); | ||||
_exit(EXIT_FAILURE); | ||||
} else { | ||||
// we are still the first child | ||||
close(feedback_pipe[1]); | ||||
_exit(EXIT_SUCCESS); | ||||
} | ||||
} else { | ||||
// we are still the original | ||||
close(feedback_pipe[1]); | ||||
char buf; | ||||
ssize_t num; | ||||
do { | ||||
num = read(feedback_pipe[0], &buf, 1); | ||||
} while(num == -1 && errno == EINTR); | ||||
close(feedback_pipe[0]); | ||||
// wait for first process | ||||
int res, status; | ||||
do { res = waitpid(pid1, &status, 0); } while(res == -1 && errno | ||||
== EINTR); | ||||
return (num == 0); | ||||
} | ||||
} | ||||
GLInjectInput::GLInjectInput(const QString& channel, bool relax_permissions, boo l record_cursor, bool limit_fps, unsigned int target_fps) { | GLInjectInput::GLInjectInput(const QString& channel, bool relax_permissions, boo l record_cursor, bool limit_fps, unsigned int target_fps) { | |||
m_channel = channel; | m_channel = channel; | |||
m_relax_permissions = relax_permissions; | m_relax_permissions = relax_permissions; | |||
m_flags = ((record_cursor)? GLINJECT_FLAG_RECORD_CURSOR : 0) | ((limit_fp s)? GLINJECT_FLAG_LIMIT_FPS : 0); | m_flags = ((record_cursor)? GLINJECT_FLAG_RECORD_CURSOR : 0) | ((limit_fp s)? GLINJECT_FLAG_LIMIT_FPS : 0); | |||
m_target_fps = target_fps; | m_target_fps = target_fps; | |||
try { | try { | |||
Init(); | Init(); | |||
} catch(...) { | } catch(...) { | |||
skipping to change at line 106 | skipping to change at line 216 | |||
bool GLInjectInput::LaunchApplication(const QString& channel, bool relax_permiss ions, const QString& command, const QString& working_directory) { | bool GLInjectInput::LaunchApplication(const QString& channel, bool relax_permiss ions, const QString& command, const QString& working_directory) { | |||
// prepare command | // prepare command | |||
QString full_command = "LD_PRELOAD=\"libssr-glinject.so\" "; | QString full_command = "LD_PRELOAD=\"libssr-glinject.so\" "; | |||
full_command += "SSR_CHANNEL=\"" + ShellEscape(channel) + "\" "; | full_command += "SSR_CHANNEL=\"" + ShellEscape(channel) + "\" "; | |||
if(relax_permissions) | if(relax_permissions) | |||
full_command += "SSR_STREAM_RELAX_PERMISSIONS=1 "; | full_command += "SSR_STREAM_RELAX_PERMISSIONS=1 "; | |||
full_command += command; | full_command += command; | |||
// execute it | // execute | |||
QStringList args; | QByteArray encoded_working_directory = QFile::encodeName(working_director | |||
args.push_back("-c"); | y); | |||
args.push_back(full_command); | QByteArray encoded_full_command = full_command.toLocal8Bit(); | |||
return QProcess::startDetached("/bin/sh", args, working_directory); | return ExecuteDetached(encoded_full_command.constData(), (encoded_working | |||
_directory.isEmpty())? NULL : encoded_working_directory.constData()); | ||||
} | } | |||
void GLInjectInput::Init() { | void GLInjectInput::Init() { | |||
// initialize shared data | // initialize shared data | |||
{ | { | |||
SharedLock lock(&m_shared_data); | SharedLock lock(&m_shared_data); | |||
lock->m_capturing = false; | lock->m_capturing = false; | |||
lock->m_stream_watcher.reset(new SSRVideoStreamWatcher(m_channel. toStdString(), m_relax_permissions)); | lock->m_stream_watcher.reset(new SSRVideoStreamWatcher(m_channel. toStdString(), m_relax_permissions)); | |||
End of changes. 2 change blocks. | ||||
5 lines changed or deleted | 122 lines changed or added |