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.
diff --git a/common/network/Socket.h b/common/network/Socket.h
index 378a900..13b12d1 100644
--- a/common/network/Socket.h
+++ b/common/network/Socket.h
@@ -125,12 +125,17 @@
// 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 f50722a..54becbb 100644
--- a/common/rfb/HTTPServer.cxx
+++ b/common/rfb/HTTPServer.cxx
@@ -337,7 +337,7 @@
}
void
-HTTPServer::processSocketEvent(network::Socket* sock) {
+HTTPServer::processSocketReadEvent(network::Socket* sock) {
std::list<Session*>::iterator i;
for (i=sessions.begin(); i!=sessions.end(); i++) {
if ((*i)->getSock() == sock) {
@@ -356,6 +356,23 @@
throw rdr::Exception("invalid Socket in HTTPServer");
}
+void
+HTTPServer::processSocketWriteEvent(network::Socket* sock) {
+ std::list<Session*>::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<network::Socket*>* sockets)
{
sockets->clear();
diff --git a/common/rfb/HTTPServer.h b/common/rfb/HTTPServer.h
index 6412946..d7ca69a 100644
--- a/common/rfb/HTTPServer.h
+++ b/common/rfb/HTTPServer.h
@@ -58,11 +58,16 @@
// 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 932f579..0f4ca94 100644
--- a/common/rfb/VNCSConnectionST.cxx
+++ b/common/rfb/VNCSConnectionST.cxx
@@ -190,6 +190,17 @@
}
}
+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 72ffc1d..55b7ca3 100644
--- a/common/rfb/VNCSConnectionST.h
+++ b/common/rfb/VNCSConnectionST.h
@@ -65,6 +65,9 @@
// 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 199524e..d501085 100644
--- a/common/rfb/VNCServerST.cxx
+++ b/common/rfb/VNCServerST.cxx
@@ -163,7 +163,7 @@
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<VNCSConnectionST*>::iterator ci;
@@ -176,6 +176,19 @@
throw rdr::Exception("invalid Socket in VNCServerST");
}
+void VNCServerST::processSocketWriteEvent(network::Socket* sock)
+{
+ // - Find the appropriate VNCSConnectionST and process the event
+ std::list<VNCSConnectionST*>::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 1e055dd..bd84c45 100644
--- a/common/rfb/VNCServerST.h
+++ b/common/rfb/VNCServerST.h
@@ -67,11 +67,15 @@
// 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