diff options
Diffstat (limited to 'unix/x0vncserver/x0vncserver.cxx')
-rw-r--r-- | unix/x0vncserver/x0vncserver.cxx | 195 |
1 files changed, 122 insertions, 73 deletions
diff --git a/unix/x0vncserver/x0vncserver.cxx b/unix/x0vncserver/x0vncserver.cxx index 7ea427ed..b8b631aa 100644 --- a/unix/x0vncserver/x0vncserver.cxx +++ b/unix/x0vncserver/x0vncserver.cxx @@ -31,13 +31,20 @@ #include <errno.h> #include <pwd.h> -#include <rfb/Logger_stdio.h> -#include <rfb/LogWriter.h> +#include <core/Configuration.h> +#include <core/Logger_stdio.h> +#include <core/LogWriter.h> +#include <core/Timer.h> + +#include <rdr/FdInStream.h> +#include <rdr/FdOutStream.h> + +#include <rfb/UnixPasswordValidator.h> #include <rfb/VNCServerST.h> -#include <rfb/Configuration.h> -#include <rfb/Timer.h> + #include <network/TcpSocket.h> #include <network/UnixSocket.h> + #ifdef HAVE_LIBSYSTEMD # include <systemd/sd-daemon.h> #endif @@ -54,30 +61,40 @@ extern char buildtime[]; -using namespace rfb; -using namespace network; - -static LogWriter vlog("Main"); +static core::LogWriter vlog("Main"); static const char* defaultDesktopName(); -IntParameter pollingCycle("PollingCycle", "Milliseconds per one polling " - "cycle; actual interval may be dynamically " - "adjusted to satisfy MaxProcessorUsage setting", 30); -IntParameter maxProcessorUsage("MaxProcessorUsage", "Maximum percentage of " - "CPU time to be consumed", 35); -StringParameter desktopName("desktop", "Name of VNC desktop", defaultDesktopName()); -StringParameter displayname("display", "The X display", ""); -IntParameter rfbport("rfbport", "TCP port to listen for RFB protocol",5900); -StringParameter rfbunixpath("rfbunixpath", "Unix socket to listen for RFB protocol", ""); -IntParameter rfbunixmode("rfbunixmode", "Unix socket access mode", 0600); -StringParameter hostsFile("HostsFile", "File with IP access control rules", ""); -BoolParameter localhostOnly("localhost", - "Only allow connections from localhost", - false); -StringParameter interface("interface", - "Listen on the specified network address", - "all"); +core::IntParameter + pollingCycle("PollingCycle", + "Milliseconds per one polling cycle; actual interval " + "may be dynamically adjusted to satisfy " + "MaxProcessorUsage setting", 30, 0, INT_MAX); +core::IntParameter + maxProcessorUsage("MaxProcessorUsage", + "Maximum percentage of CPU time to be consumed", + 35, 0, 100); +core::StringParameter + desktopName("desktop", "Name of VNC desktop", defaultDesktopName()); +core::StringParameter + displayname("display", "The X display", ""); +core::IntParameter + rfbport("rfbport", + "TCP port to listen for RFB protocol", 5900, -1, 65535); +core::StringParameter + rfbunixpath("rfbunixpath", + "Unix socket to listen for RFB protocol", ""); +core::IntParameter + rfbunixmode("rfbunixmode", + "Unix socket access mode", 0600, 0000, 0777); +core::StringParameter + hostsFile("HostsFile", "File with IP access control rules", ""); +core::BoolParameter + localhostOnly("localhost", + "Only allow connections from localhost", false); +core::StringParameter + interface("interface", + "Listen on the specified network address", "all"); static const char* defaultDesktopName() { @@ -127,7 +144,7 @@ static bool hasSystemdListeners() #endif } -static int createSystemdListeners(std::list<SocketListener*> *listeners) +static int createSystemdListeners(std::list<network::SocketListener*> *listeners) { #ifdef HAVE_LIBSYSTEMD int count = sd_listen_fds(0); @@ -138,7 +155,7 @@ static int createSystemdListeners(std::list<SocketListener*> *listeners) } for (int i = 0; i < count; ++i) - listeners->push_back(new TcpListener(SD_LISTEN_FDS_START + i)); + listeners->push_back(new network::TcpListener(SD_LISTEN_FDS_START + i)); return count; #else @@ -148,7 +165,7 @@ static int createSystemdListeners(std::list<SocketListener*> *listeners) } -class FileTcpFilter : public TcpFilter +class FileTcpFilter : public network::TcpFilter { public: @@ -166,7 +183,7 @@ public: free(fileName); } - bool verifyConnection(Socket* s) override + bool verifyConnection(network::Socket* s) override { if (!reloadRules()) { vlog.error("Could not read IP filtering rules, rejecting all clients"); @@ -267,59 +284,72 @@ static void usage() "Other valid forms are <param>=<value> -<param>=<value> " "--<param>=<value>\n" "Parameter names are case-insensitive. The parameters are:\n\n"); - Configuration::listParams(79, 14); + core::Configuration::listParams(79, 14); exit(1); } int main(int argc, char** argv) { - initStdIOLoggers(); - LogWriter::setLogParams("*:stderr:30"); + core::initStdIOLoggers(); + core::LogWriter::setLogParams("*:stderr:30"); programName = argv[0]; Display* dpy; - Configuration::enableServerParams(); - // Assume different defaults when socket activated if (hasSystemdListeners()) rfbport.setParam(-1); - for (int i = 1; i < argc; i++) { - if (Configuration::setParam(argv[i])) + for (int i = 1; i < argc;) { + int ret; + + ret = core::Configuration::handleParamArg(argc, argv, i); + if (ret > 0) { + i += ret; continue; + } - if (argv[i][0] == '-') { - if (i+1 < argc) { - if (Configuration::setParam(&argv[i][1], argv[i+1])) { - i++; - continue; - } - } - if (strcmp(argv[i], "-v") == 0 || - strcmp(argv[i], "-version") == 0 || - strcmp(argv[i], "--version") == 0) { - printVersion(stdout); - return 0; - } + if (strcmp(argv[i], "-h") == 0 || + strcmp(argv[i], "-help") == 0 || + strcmp(argv[i], "--help") == 0) { usage(); } - usage(); + if (strcmp(argv[i], "-v") == 0 || + strcmp(argv[i], "-version") == 0 || + strcmp(argv[i], "--version") == 0) { + printVersion(stdout); + return 0; + } + + if (argv[i][0] == '-') { + fprintf(stderr, "%s: Unrecognized option '%s'\n", + programName, argv[i]); + fprintf(stderr, "See '%s --help' for more information.\n", + programName); + exit(1); + } + + fprintf(stderr, "%s: Extra argument '%s'\n", programName, argv[i]); + fprintf(stderr, "See '%s --help' for more information.\n", + programName); + exit(1); } + const char *displayName = XDisplayName(displayname); if (!(dpy = XOpenDisplay(displayname))) { // FIXME: Why not vlog.error(...)? fprintf(stderr,"%s: Unable to open display \"%s\"\r\n", - programName, XDisplayName(displayname)); + programName, displayName); exit(1); } + rfb::UnixPasswordValidator::setDisplayName(displayName); signal(SIGHUP, CleanupSignalHandler); signal(SIGINT, CleanupSignalHandler); signal(SIGTERM, CleanupSignalHandler); - std::list<SocketListener*> listeners; + std::list<network::SocketListener*> listeners; try { TXWindow::init(dpy,"x0vncserver"); @@ -331,7 +361,9 @@ int main(int argc, char** argv) } XDesktop desktop(dpy, &geo); - VNCServerST server(desktopName, &desktop); + rfb::VNCServerST server(desktopName, &desktop); + + FileTcpFilter fileTcpFilter(hostsFile); if (createSystemdListeners(&listeners) > 0) { // When systemd is in charge of listeners, do not listen to anything else @@ -361,9 +393,8 @@ int main(int argc, char** argv) (int)rfbport); } - FileTcpFilter fileTcpFilter(hostsFile); if (strlen(hostsFile) != 0) - for (SocketListener* listener : listeners) + for (network::SocketListener* listener : listeners) listener->setFilter(&fileTcpFilter); } @@ -378,8 +409,8 @@ int main(int argc, char** argv) int wait_ms, nextTimeout; struct timeval tv; fd_set rfds, wfds; - std::list<Socket*> sockets; - std::list<Socket*>::iterator i; + std::list<network::Socket*> sockets; + std::list<network::Socket*>::iterator i; // Process any incoming X events TXWindow::handleXEvents(dpy); @@ -388,21 +419,16 @@ int main(int argc, char** argv) FD_ZERO(&wfds); FD_SET(ConnectionNumber(dpy), &rfds); - for (SocketListener* listener : listeners) + for (network::SocketListener* listener : listeners) FD_SET(listener->getFd(), &rfds); server.getSockets(&sockets); int clients_connected = 0; for (i = sockets.begin(); i != sockets.end(); i++) { - if ((*i)->isShutdown()) { - server.removeSocket(*i); - delete (*i); - } else { - FD_SET((*i)->getFd(), &rfds); - if ((*i)->outStream().hasBufferedData()) - FD_SET((*i)->getFd(), &wfds); - clients_connected++; - } + FD_SET((*i)->getFd(), &rfds); + if ((*i)->outStream().hasBufferedData()) + FD_SET((*i)->getFd(), &wfds); + clients_connected++; } if (!clients_connected) @@ -418,7 +444,7 @@ int main(int argc, char** argv) } // Trigger timers and check when the next will expire - nextTimeout = Timer::checkTimeouts(); + nextTimeout = core::Timer::checkTimeouts(); if (nextTimeout >= 0 && (wait_ms == -1 || nextTimeout < wait_ms)) wait_ms = nextTimeout; @@ -436,14 +462,14 @@ int main(int argc, char** argv) vlog.debug("Interrupted select() system call"); continue; } else { - throw rdr::socket_error("select", errno); + throw core::socket_error("select", errno); } } // Accept new VNC connections - for (SocketListener* listener : listeners) { + for (network::SocketListener* listener : listeners) { if (FD_ISSET(listener->getFd(), &rfds)) { - Socket* sock = listener->accept(); + network::Socket* sock = listener->accept(); if (sock) { server.addSocket(sock); } else { @@ -452,7 +478,7 @@ int main(int argc, char** argv) } } - Timer::checkTimeouts(); + core::Timer::checkTimeouts(); // Client list could have been changed. server.getSockets(&sockets); @@ -467,6 +493,29 @@ int main(int argc, char** argv) server.processSocketReadEvent(*i); if (FD_ISSET((*i)->getFd(), &wfds)) server.processSocketWriteEvent(*i); + + // Do a graceful close by waiting for the peer to close their + // end + if ((*i)->isShutdown()) { + bool done; + + done = false; + while (true) { + try { + (*i)->inStream().skip((*i)->inStream().avail()); + if (!(*i)->inStream().hasData(1)) + break; + } catch (std::exception&) { + done = true; + break; + } + } + + if (done) { + server.removeSocket(*i); + delete (*i); + } + } } if (desktop.isRunning() && sched.goodTimeToPoll()) { @@ -483,7 +532,7 @@ int main(int argc, char** argv) TXWindow::handleXEvents(dpy); // Run listener destructors; remove UNIX sockets etc - for (SocketListener* listener : listeners) + for (network::SocketListener* listener : listeners) delete listener; vlog.info("Terminated"); |