From d408ca514655b4fe6e477680f22c4387b52446a6 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 29 Apr 2016 14:26:05 +0200 Subject: [PATCH] Move socket write event handling in to the RFB core What to do when a socket is writeable should be handled in the RFB core code as there may be other events we want to fire off when this happens. --- common/network/Socket.h | 9 +++++++-- common/rfb/HTTPServer.cxx | 19 ++++++++++++++++++- common/rfb/HTTPServer.h | 9 +++++++-- common/rfb/VNCSConnectionST.cxx | 11 +++++++++++ common/rfb/VNCSConnectionST.h | 3 +++ common/rfb/VNCServerST.cxx | 15 ++++++++++++++- common/rfb/VNCServerST.h | 8 ++++++-- unix/x0vncserver/x0vncserver.cxx | 2 +- unix/xserver/hw/vnc/XserverDesktop.cc | 8 ++++---- win/rfb_win32/SocketManager.cxx | 2 +- 10 files changed, 72 insertions(+), 14 deletions(-) diff --git a/common/network/Socket.h b/common/network/Socket.h index 378a9006..13b12d1d 100644 --- a/common/network/Socket.h +++ b/common/network/Socket.h @@ -125,12 +125,17 @@ namespace network { // resources to be freed. virtual void removeSocket(network::Socket* sock) = 0; - // processSocketEvent() tells the server there is a Socket read event. + // processSocketReadEvent() tells the server there is a Socket read event. // The implementation can indicate that the Socket is no longer active // by calling shutdown() on it. The caller will then call removeSocket() // soon after processSocketEvent returns, to allow any pre-Socket // resources to be tidied up. - virtual void processSocketEvent(network::Socket* sock) = 0; + virtual void processSocketReadEvent(network::Socket* sock) = 0; + + // processSocketReadEvent() tells the server there is a Socket write event. + // This is only necessary if the Socket has been put in non-blocking + // mode and needs this callback to flush the buffer. + virtual void processSocketWriteEvent(network::Socket* sock) = 0; // checkTimeouts() allows the server to check socket timeouts, etc. The // return value is the number of milliseconds to wait before diff --git a/common/rfb/HTTPServer.cxx b/common/rfb/HTTPServer.cxx index f50722ab..54becbb2 100644 --- a/common/rfb/HTTPServer.cxx +++ b/common/rfb/HTTPServer.cxx @@ -337,7 +337,7 @@ HTTPServer::removeSocket(network::Socket* sock) { } void -HTTPServer::processSocketEvent(network::Socket* sock) { +HTTPServer::processSocketReadEvent(network::Socket* sock) { std::list::iterator i; for (i=sessions.begin(); i!=sessions.end(); i++) { if ((*i)->getSock() == sock) { @@ -356,6 +356,23 @@ HTTPServer::processSocketEvent(network::Socket* sock) { throw rdr::Exception("invalid Socket in HTTPServer"); } +void +HTTPServer::processSocketWriteEvent(network::Socket* sock) { + std::list::iterator i; + for (i=sessions.begin(); i!=sessions.end(); i++) { + if ((*i)->getSock() == sock) { + try { + sock->outStream().flush(); + } catch (rdr::Exception& e) { + vlog.error("untrapped: %s", e.str()); + sock->shutdown(); + } + return; + } + } + throw rdr::Exception("invalid Socket in HTTPServer"); +} + void HTTPServer::getSockets(std::list* sockets) { sockets->clear(); diff --git a/common/rfb/HTTPServer.h b/common/rfb/HTTPServer.h index 6412946a..d7ca69ad 100644 --- a/common/rfb/HTTPServer.h +++ b/common/rfb/HTTPServer.h @@ -58,11 +58,16 @@ namespace rfb { // Could clean up socket-specific resources here. virtual void removeSocket(network::Socket* sock); - // processSocketEvent() + // processSocketReadEvent() // The platform-specific side of the server implementation calls // this method whenever data arrives on one of the active // network sockets. - virtual void processSocketEvent(network::Socket* sock); + virtual void processSocketReadEvent(network::Socket* sock); + + // processSocketWriteEvent() + // Similar to processSocketReadEvent(), but called when it is + // possible to write more data to a socket. + virtual void processSocketWriteEvent(network::Socket* sock); // Check for socket timeouts virtual int checkTimeouts(); diff --git a/common/rfb/VNCSConnectionST.cxx b/common/rfb/VNCSConnectionST.cxx index 932f5796..0f4ca942 100644 --- a/common/rfb/VNCSConnectionST.cxx +++ b/common/rfb/VNCSConnectionST.cxx @@ -190,6 +190,17 @@ void VNCSConnectionST::processMessages() } } +void VNCSConnectionST::flushSocket() +{ + if (state() == RFBSTATE_CLOSING) return; + try { + setSocketTimeouts(); + sock->outStream().flush(); + } catch (rdr::Exception &e) { + close(e.str()); + } +} + void VNCSConnectionST::pixelBufferChange() { try { diff --git a/common/rfb/VNCSConnectionST.h b/common/rfb/VNCSConnectionST.h index 72ffc1df..55b7ca3e 100644 --- a/common/rfb/VNCSConnectionST.h +++ b/common/rfb/VNCSConnectionST.h @@ -65,6 +65,9 @@ namespace rfb { // Socket if an error occurs, via the close() call. void processMessages(); + // flushSocket() pushes any unwritten data on to the network. + void flushSocket(); + // Called when the underlying pixelbuffer is resized or replaced. void pixelBufferChange(); diff --git a/common/rfb/VNCServerST.cxx b/common/rfb/VNCServerST.cxx index 199524ec..d5010854 100644 --- a/common/rfb/VNCServerST.cxx +++ b/common/rfb/VNCServerST.cxx @@ -163,7 +163,7 @@ void VNCServerST::removeSocket(network::Socket* sock) { closingSockets.remove(sock); } -void VNCServerST::processSocketEvent(network::Socket* sock) +void VNCServerST::processSocketReadEvent(network::Socket* sock) { // - Find the appropriate VNCSConnectionST and process the event std::list::iterator ci; @@ -176,6 +176,19 @@ void VNCServerST::processSocketEvent(network::Socket* sock) throw rdr::Exception("invalid Socket in VNCServerST"); } +void VNCServerST::processSocketWriteEvent(network::Socket* sock) +{ + // - Find the appropriate VNCSConnectionST and process the event + std::list::iterator ci; + for (ci = clients.begin(); ci != clients.end(); ci++) { + if ((*ci)->getSock() == sock) { + (*ci)->flushSocket(); + return; + } + } + throw rdr::Exception("invalid Socket in VNCServerST"); +} + int VNCServerST::checkTimeouts() { int timeout = 0; diff --git a/common/rfb/VNCServerST.h b/common/rfb/VNCServerST.h index 1e055dd9..bd84c452 100644 --- a/common/rfb/VNCServerST.h +++ b/common/rfb/VNCServerST.h @@ -67,11 +67,15 @@ namespace rfb { // Clean up any resources associated with the Socket virtual void removeSocket(network::Socket* sock); - // processSocketEvent + // processSocketReadEvent // Read more RFB data from the Socket. If an error occurs during // processing then shutdown() is called on the Socket, causing // removeSocket() to be called by the caller at a later time. - virtual void processSocketEvent(network::Socket* sock); + virtual void processSocketReadEvent(network::Socket* sock); + + // processSocketWriteEvent + // Flush pending data from the Socket on to the network. + virtual void processSocketWriteEvent(network::Socket* sock); // checkTimeouts // Returns the number of milliseconds left until the next idle timeout diff --git a/unix/x0vncserver/x0vncserver.cxx b/unix/x0vncserver/x0vncserver.cxx index 6b5d479d..791714e9 100644 --- a/unix/x0vncserver/x0vncserver.cxx +++ b/unix/x0vncserver/x0vncserver.cxx @@ -593,7 +593,7 @@ int main(int argc, char** argv) // Process events on existing VNC connections for (i = sockets.begin(); i != sockets.end(); i++) { if (FD_ISSET((*i)->getFd(), &rfds)) - server.processSocketEvent(*i); + server.processSocketReadEvent(*i); } if (desktop.isRunning() && sched.goodTimeToPoll()) { diff --git a/unix/xserver/hw/vnc/XserverDesktop.cc b/unix/xserver/hw/vnc/XserverDesktop.cc index 9b91d9a4..f1c9b747 100644 --- a/unix/xserver/hw/vnc/XserverDesktop.cc +++ b/unix/xserver/hw/vnc/XserverDesktop.cc @@ -495,7 +495,7 @@ void XserverDesktop::readWakeupHandler(fd_set* fds, int nfds) int fd = (*i)->getFd(); if (FD_ISSET(fd, fds)) { FD_CLR(fd, fds); - server->processSocketEvent(*i); + server->processSocketReadEvent(*i); } } @@ -505,7 +505,7 @@ void XserverDesktop::readWakeupHandler(fd_set* fds, int nfds) int fd = (*i)->getFd(); if (FD_ISSET(fd, fds)) { FD_CLR(fd, fds); - httpServer->processSocketEvent(*i); + httpServer->processSocketReadEvent(*i); } } } @@ -581,7 +581,7 @@ void XserverDesktop::writeWakeupHandler(fd_set* fds, int nfds) int fd = (*i)->getFd(); if (FD_ISSET(fd, fds)) { FD_CLR(fd, fds); - (*i)->outStream().flush(); + server->processSocketWriteEvent(*i); } } @@ -591,7 +591,7 @@ void XserverDesktop::writeWakeupHandler(fd_set* fds, int nfds) int fd = (*i)->getFd(); if (FD_ISSET(fd, fds)) { FD_CLR(fd, fds); - (*i)->outStream().flush(); + httpServer->processSocketWriteEvent(*i); } } } diff --git a/win/rfb_win32/SocketManager.cxx b/win/rfb_win32/SocketManager.cxx index b073b8fb..5b211a0d 100644 --- a/win/rfb_win32/SocketManager.cxx +++ b/win/rfb_win32/SocketManager.cxx @@ -193,7 +193,7 @@ void SocketManager::processEvent(HANDLE event) { WSAResetEvent(event); // Call the socket server to process the event - ci.server->processSocketEvent(ci.sock); + ci.server->processSocketReadEvent(ci.sock); if (ci.sock->isShutdown()) { remSocket(ci.sock); return; -- 2.39.5