From 30af52eb324f6bf5551869033605e3141d745a40 Mon Sep 17 00:00:00 2001 From: Vadim Troshchinskiy Date: Tue, 18 Oct 2016 09:19:28 +0200 Subject: Slave channel implementation When enabled and a connection is made to the port, launches the process specified in NX_SLAVE_CMD on the other side, and connects stdin and stdout to the socket. This is used for VM/client and client/VM communication. --- nxcomp/Loop.cpp | 4 +- nxcomp/Proxy.cpp | 183 +++++++++++++++++++++++++++++++++++++++++++++---------- nxcomp/Proxy.h | 3 + 3 files changed, 156 insertions(+), 34 deletions(-) diff --git a/nxcomp/Loop.cpp b/nxcomp/Loop.cpp index 46031e70d..09ba6f952 100644 --- a/nxcomp/Loop.cpp +++ b/nxcomp/Loop.cpp @@ -359,7 +359,7 @@ static void RestoreSignal(int signal); static int HandleChildren(); -static int HandleChild(int child); +int HandleChild(int child); static int CheckChild(int pid, int status); static int WaitChild(int child, const char *label, int force); @@ -6250,6 +6250,8 @@ int HandleChildren() return 1; } + proxy->checkSlaves(); + // // This can actually happen either because we // reset the pid of the child process as soon diff --git a/nxcomp/Proxy.cpp b/nxcomp/Proxy.cpp index e499b443e..123181489 100644 --- a/nxcomp/Proxy.cpp +++ b/nxcomp/Proxy.cpp @@ -29,6 +29,8 @@ #include #include #include +#include + #ifdef ANDROID #include #include @@ -92,6 +94,8 @@ struct sockaddr_un extern void CleanupListeners(); +extern int HandleChild(int); + // // Default size of string buffers. // @@ -165,6 +169,7 @@ Proxy::Proxy(int fd) fdMap_[channelId] = nothing; channelMap_[channelId] = nothing; + slavePidMap_[channelId] = nothing; } inputChannel_ = nothing; @@ -296,6 +301,66 @@ Proxy::~Proxy() } } + // + // Kill all active slave channel children, and + // give them 5 seconds to exit nicely. + + #ifdef DEBUG + *logofs << "Proxy: Killing active slaves" << endl; + #endif + + int slave_count = 999; + int loop_count = 0; + + while(slave_count > 0 && loop_count < 50) + { + slave_count = 0; + + for (int channelId = 0; channelId 1) { + slave_count++; + + #ifdef DEBUG + *logofs << "Proxy: Active slave with pid " << pid << logofs_flush; + #endif + + if ( loop_count == 0 ) + { + #ifdef DEBUG + *logofs << "Proxy: Sending SIGTERM to " << pid << logofs_flush; + #endif + kill(pid, SIGTERM); + } + else if ( loop_count == 25 ) + { + #ifdef DEBUG + *logofs << "Proxy: Sending SIGKILL to " << pid << logofs_flush; + #endif + kill(pid, SIGKILL); + } + + if (HandleChild(pid)) + { + #ifdef DEBUG + *logofs << "Proxy: Slave " << pid << " terminated" << logofs_flush; + #endif + slavePidMap_[channelId] = nothing; + } + } + } + + if ( slave_count > 0 ) + { + cerr << "Proxy: Error: Failed to kill all slave channel processes. " << slave_count << " processes still remaining." << endl; + } + + usleep(200000); + loop_count++; + } + delete transport_; delete compressor_; @@ -6308,42 +6373,94 @@ int Proxy::handleNewGenericConnectionFromProxyUnix(int channelId, T_channel_type int Proxy::handleNewSlaveConnectionFromProxy(int channelId) { - // - // Implementation is incomplete. Opening a - // slave channel should let the proxy fork - // a new client and pass to it the channel - // descriptors. For now we make the channel - // fail immediately. - // - // #include - // #include - // #include - // - // char *slaveServer = "/dev/null"; - // - // #ifdef TEST - // *logofs << "Proxy: Opening file '" << slaveServer - // << "'.\n" << logofs_flush; - // #endif - // - // int serverFd = open(slaveServer, O_RDWR); - // - // if (handlePostConnectionFromProxy(channelId, serverFd, channel_slave, "slave") < 0) - // { - // return -1; - // } - // - #ifdef WARNING - *logofs << "Proxy: Refusing new slave connection for " - << "channel ID#" << channelId << "\n" - << logofs_flush; - #endif + cerr << "Info" << ": New slave connection on " + << "channel ID#" << channelId << "\n"; + + char *nx_slave_cmd = getenv("NX_SLAVE_CMD"); + if (nx_slave_cmd == NULL) { + return -1; + } - cerr << "Warning" << ": Refusing new slave connection for " - << "channel ID#" << channelId << "\n"; + int spair[2]; + if (socketpair(AF_UNIX, SOCK_STREAM, 0, spair) == -1) { + perror("socketpair"); + return -1; + } - return -1; + int serverFd = spair[0]; + int clientFd = spair[1]; + + if (handlePostConnectionFromProxy(channelId, serverFd, channel_slave, "slave") < 0) + { + close(serverFd); + close(clientFd); + return -1; + } + + + int pid = fork(); + if (pid == 0) + { + + if (dup2(clientFd, 0) == -1) + { + perror("dup2"); + exit(1); + } + + if (dup2(clientFd, 1) == -1) + { + perror("dup2"); + exit(1); + } + + close(serverFd); + close(clientFd); + + /* Close FDs used by NX, QVD #1208 */ + for (int fd = 3; fd < 256; fd++) { + close(fd); + } + + char *const argv[2] = {nx_slave_cmd, NULL}; + + if (execv(nx_slave_cmd, argv) == -1) + { + perror("execv"); + } + exit(1); + + } + else if (pid == -1) + { + // TODO Test this! + perror("fork"); + close(serverFd); + close(clientFd); + return -1; + } + + close(clientFd); + slavePidMap_[channelId] = pid; + + cerr << "Info" << ": slave channel ID#" << channelId << " handler has PID " << pid << endl; + + return 1; +} + +void Proxy::checkSlaves() +{ + for (int channelId = 0; channelId 1 && HandleChild(pid)) + { + slavePidMap_[channelId] = nothing; + cerr << "Info:" << " Handled death of slave with pid " << pid << endl; + } + } } int Proxy::handlePostConnectionFromProxy(int channelId, int serverFd, diff --git a/nxcomp/Proxy.h b/nxcomp/Proxy.h index 8259ddbb7..ea60c827a 100644 --- a/nxcomp/Proxy.h +++ b/nxcomp/Proxy.h @@ -302,6 +302,8 @@ class Proxy int handleNewSlaveConnectionFromProxy(int channelId); + void checkSlaves(); + // // Force closure of channels. // @@ -1268,6 +1270,7 @@ class Proxy int channelMap_[CONNECTIONS_LIMIT]; int fdMap_[CONNECTIONS_LIMIT]; + int slavePidMap_[CONNECTIONS_LIMIT]; }; #endif /* Proxy_H */ -- cgit v1.2.3 From c7eac1f95626e376b17ccd684b2a4e9402b3c17c Mon Sep 17 00:00:00 2001 From: Vadim Troshchinskiy Date: Mon, 24 Oct 2016 13:27:52 +0200 Subject: Add description of NX_SLAVE_CMD to man and help --- nxcomp/Misc.cpp | 7 +++++++ nxproxy/man/nxproxy.1 | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/nxcomp/Misc.cpp b/nxcomp/Misc.cpp index 71013fc6f..09a0b29d2 100644 --- a/nxcomp/Misc.cpp +++ b/nxcomp/Misc.cpp @@ -357,6 +357,13 @@ tolerancechecks=s\n\ Mac where nxclient is located in a different direct-\n\ ory compared to the other programs, to make easier\n\ for the user to execute the program from the shell.\n\ +\n\ + NX_SLAVE_CMD The full path to the slave channel handler. When the\n\ + slave channel is enabled, the agent will listen on a\n\ + port and forward the connection to the NX_SLAVE_CMD\n\ + program. This can be used to implement agent/proxy\n\ + communication for applications such as serial port and\n\ + USB forwarding.\n\ \n\ Shell environment:\n\ \n\ diff --git a/nxproxy/man/nxproxy.1 b/nxproxy/man/nxproxy.1 index 7b950a607..3cf95c992 100644 --- a/nxproxy/man/nxproxy.1 +++ b/nxproxy/man/nxproxy.1 @@ -339,6 +339,13 @@ where is located in a different directory compared to the other programs, to make easier for the user to execute the program from the shell. +.TP 8 +.B NX_SLAVE_CMD +The full path to the slave channel handler. When the slave channel is +enabled, the agent will listen on a port and forward the connection to +the NX_SLAVE_CMD program. This can be used to implement agent/proxy +communication for applications such as serial port and USB forwarding. + .SH SHELL ENVIRONMENT VARIABLES .TP 8 -- cgit v1.2.3