aboutsummaryrefslogtreecommitdiffstats
path: root/unix/xserver/hw/vnc/XserverDesktop.cc
diff options
context:
space:
mode:
Diffstat (limited to 'unix/xserver/hw/vnc/XserverDesktop.cc')
-rw-r--r--unix/xserver/hw/vnc/XserverDesktop.cc183
1 files changed, 183 insertions, 0 deletions
diff --git a/unix/xserver/hw/vnc/XserverDesktop.cc b/unix/xserver/hw/vnc/XserverDesktop.cc
index 4f82a544..8cc0b0b7 100644
--- a/unix/xserver/hw/vnc/XserverDesktop.cc
+++ b/unix/xserver/hw/vnc/XserverDesktop.cc
@@ -90,6 +90,30 @@ public:
XserverDesktop* desktop;
};
+#if XORG >= 119
+extern "C" {
+/*
+ * xserver NotifyFd callbacks. Note we also expect write notifies to work,
+ * which only works with xserver >= 1.19.
+ */
+#include "os.h"
+
+static void HandleListenFd(int fd, int xevents, void *data)
+{
+ XserverDesktop *desktop = (XserverDesktop *)data;
+
+ desktop->handleListenFd(fd);
+}
+
+static void HandleSocketFd(int fd, int xevents, void *data)
+{
+ XserverDesktop *desktop = (XserverDesktop *)data;
+
+ desktop->handleSocketFd(fd, xevents);
+}
+
+}
+#endif
XserverDesktop::XserverDesktop(int screenIndex_,
std::list<network::TcpListener*> listeners_,
@@ -111,15 +135,35 @@ XserverDesktop::XserverDesktop(int screenIndex_,
if (!httpListeners.empty ())
httpServer = new FileHTTPServer(this);
+
+#if XORG >= 119
+ for (std::list<TcpListener*>::iterator i = listeners.begin();
+ i != listeners.end();
+ i++) {
+ SetNotifyFd((*i)->getFd(), HandleListenFd, X_NOTIFY_READ, this);
+ }
+
+ for (std::list<TcpListener*>::iterator i = httpListeners.begin();
+ i != httpListeners.end();
+ i++) {
+ SetNotifyFd((*i)->getFd(), HandleListenFd, X_NOTIFY_READ, this);
+ }
+#endif
}
XserverDesktop::~XserverDesktop()
{
while (!listeners.empty()) {
+#if XORG >= 119
+ RemoveNotifyFd(listeners.back()->getFd());
+#endif
delete listeners.back();
listeners.pop_back();
}
while (!httpListeners.empty()) {
+#if XORG >= 119
+ RemoveNotifyFd(listeners.back()->getFd());
+#endif
delete httpListeners.back();
httpListeners.pop_back();
}
@@ -389,6 +433,140 @@ void XserverDesktop::add_copied(const rfb::Region &dest, const rfb::Point &delta
}
}
+#if XORG >= 119
+void XserverDesktop::handleListenFd(int fd)
+{
+ std::list<TcpListener*>::iterator i;
+ SocketServer *fd_server = NULL;
+ bool is_http = false;
+
+ for (i = listeners.begin(); i != listeners.end(); i++) {
+ if ((*i)->getFd() == fd) {
+ fd_server = server;
+ break;
+ }
+ }
+ if (httpServer && !fd_server) {
+ for (i = httpListeners.begin(); i != httpListeners.end(); i++) {
+ if ((*i)->getFd() == fd) {
+ fd_server = httpServer;
+ is_http = true;
+ break;
+ }
+ }
+ }
+ if (!fd_server) {
+ vlog.error("XserverDesktop::handleListenFd: Error cannot find fd");
+ return;
+ }
+
+ Socket* sock = (*i)->accept();
+ sock->outStream().setBlocking(false);
+ vlog.debug("new %sclient, sock %d", is_http ? "http " : "", sock->getFd());
+ fd_server->addSocket(sock);
+ SetNotifyFd(sock->getFd(), HandleSocketFd, X_NOTIFY_READ, this);
+}
+
+void XserverDesktop::handleSocketFd(int fd, int xevents)
+{
+ std::list<Socket*> sockets;
+ std::list<Socket*>::iterator i;
+ SocketServer *fd_server = NULL;
+ bool is_http = false;
+
+ server->getSockets(&sockets);
+ for (i = sockets.begin(); i != sockets.end(); i++) {
+ if ((*i)->getFd() == fd) {
+ fd_server = server;
+ break;
+ }
+ }
+ if (httpServer && !fd_server) {
+ httpServer->getSockets(&sockets);
+ for (i = sockets.begin(); i != sockets.end(); i++) {
+ if ((*i)->getFd() == fd) {
+ fd_server = httpServer;
+ is_http = true;
+ break;
+ }
+ }
+ }
+ if (!fd_server) {
+ vlog.error("XserverDesktop::handleSocketFd: Error cannot find fd");
+ return;
+ }
+
+ if (xevents & X_NOTIFY_READ)
+ fd_server->processSocketReadEvent(*i);
+
+ if (xevents & X_NOTIFY_WRITE)
+ fd_server->processSocketWriteEvent(*i);
+
+ if ((*i)->isShutdown()) {
+ vlog.debug("%sclient gone, sock %d", is_http ? "http " : "", fd);
+ RemoveNotifyFd(fd);
+ fd_server->removeSocket(*i);
+ if (!is_http)
+ vncClientGone(fd);
+ delete (*i);
+ }
+}
+
+void XserverDesktop::blockHandler(int* timeout)
+{
+ // We don't have a good callback for when we can init input devices[1],
+ // so we abuse the fact that this routine will be called first thing
+ // once the dix is done initialising.
+ // [1] Technically Xvnc has InitInput(), but libvnc.so has nothing.
+ vncInitInputDevice();
+
+ try {
+ std::list<Socket*> sockets;
+ std::list<Socket*>::iterator i;
+ server->getSockets(&sockets);
+ for (i = sockets.begin(); i != sockets.end(); i++) {
+ int fd = (*i)->getFd();
+ if ((*i)->isShutdown()) {
+ vlog.debug("client gone, sock %d",fd);
+ server->removeSocket(*i);
+ vncClientGone(fd);
+ delete (*i);
+ } else {
+ /* Update existing NotifyFD to listen for write (or not) */
+ if ((*i)->outStream().bufferUsage() > 0)
+ SetNotifyFd(fd, HandleSocketFd, X_NOTIFY_READ | X_NOTIFY_WRITE, this);
+ else
+ SetNotifyFd(fd, HandleSocketFd, X_NOTIFY_READ, this);
+ }
+ }
+ if (httpServer) {
+ httpServer->getSockets(&sockets);
+ for (i = sockets.begin(); i != sockets.end(); i++) {
+ int fd = (*i)->getFd();
+ if ((*i)->isShutdown()) {
+ vlog.debug("http client gone, sock %d",fd);
+ httpServer->removeSocket(*i);
+ delete (*i);
+ } else {
+ /* Update existing NotifyFD to listen for write (or not) */
+ if ((*i)->outStream().bufferUsage() > 0)
+ SetNotifyFd(fd, HandleSocketFd, X_NOTIFY_READ | X_NOTIFY_WRITE, this);
+ else
+ SetNotifyFd(fd, HandleSocketFd, X_NOTIFY_READ, this);
+ }
+ }
+ }
+
+ int nextTimeout = server->checkTimeouts();
+ if (nextTimeout > 0 && (*timeout == -1 || nextTimeout < *timeout))
+ *timeout = nextTimeout;
+ } catch (rdr::Exception& e) {
+ vlog.error("XserverDesktop::blockHandler: %s",e.str());
+ }
+}
+
+#else
+
void XserverDesktop::readBlockHandler(fd_set* fds, struct timeval ** timeout)
{
// We don't have a good callback for when we can init input devices[1],
@@ -603,10 +781,15 @@ void XserverDesktop::writeWakeupHandler(fd_set* fds, int nfds)
}
}
+#endif
+
void XserverDesktop::addClient(Socket* sock, bool reverse)
{
vlog.debug("new client, sock %d reverse %d",sock->getFd(),reverse);
server->addSocket(sock, reverse);
+#if XORG >= 119
+ SetNotifyFd(sock->getFd(), HandleSocketFd, X_NOTIFY_READ, this);
+#endif
}
void XserverDesktop::disconnectClients()