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.tags/v1.6.90
@@ -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 |
@@ -337,7 +337,7 @@ HTTPServer::removeSocket(network::Socket* sock) { | |||
} | |||
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 @@ HTTPServer::processSocketEvent(network::Socket* sock) { | |||
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(); |
@@ -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(); |
@@ -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 { |
@@ -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(); | |||
@@ -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<VNCSConnectionST*>::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<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; |
@@ -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 |
@@ -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()) { |
@@ -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); | |||
} | |||
} | |||
} |
@@ -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; |