Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

libvncserver: fix hanging on connection if fd limit is too high. #626

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 26 additions & 21 deletions src/libvncserver/sockets.c
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,8 @@ struct timeval
;
#endif

#ifdef LIBVNCSERVER_HAVE_FCNTL_H
#include <fcntl.h>
#if LIBVNCSERVER_HAVE_DIRENT_H
#include <dirent.h>
#endif

#include <errno.h>
Expand Down Expand Up @@ -476,10 +476,6 @@ rfbProcessNewConnection(rfbScreenInfoPtr rfbScreen)
rfbSocket sock = RFB_INVALID_SOCKET;
fd_set listen_fds;
rfbSocket chosen_listen_sock = RFB_INVALID_SOCKET;
#if defined LIBVNCSERVER_HAVE_SYS_RESOURCE_H && defined LIBVNCSERVER_HAVE_FCNTL_H
struct rlimit rlim;
size_t maxfds, curfds, i;
#endif
/* Do another select() call to find out which listen socket
has an incoming connection pending. We know that at least
one of them has, so this should not block for too long! */
Expand All @@ -505,23 +501,32 @@ rfbProcessNewConnection(rfbScreenInfoPtr rfbScreen)
Our approach is to deny new clients when we have reached a certain fraction of the per-process limit of file descriptors.
TODO: add Windows support.
*/
#if defined LIBVNCSERVER_HAVE_SYS_RESOURCE_H && defined LIBVNCSERVER_HAVE_FCNTL_H
if(getrlimit(RLIMIT_NOFILE, &rlim) < 0)
maxfds = 100; /* use a sane default if getting the limit fails */
else
maxfds = rlim.rlim_cur;
#if defined LIBVNCSERVER_HAVE_SYS_RESOURCE_H && defined LIBVNCSERVER_HAVE_DIRENT_H
DIR* fd_dir = opendir("/proc/self/fd");
// Warning: only supports Linux
if (fd_dir) {
struct rlimit rlim;
int maxfds = 100; /* use a sane default if getting the limit fails */
int curfds = 0;

if (getrlimit(RLIMIT_NOFILE, &rlim) >= 0)
maxfds = rlim.rlim_cur;

struct dirent* entry;
while(entry = readdir(fd_dir)) {
curfds++;
}

/* get the number of currently open fds as per https://stackoverflow.com/a/7976880/361413 */
curfds = 0;
for(i = 0; i < maxfds; ++i)
if(fcntl(i, F_GETFD) != -1)
++curfds;
closedir(fd_dir);

if(curfds > maxfds * rfbScreen->fdQuota) {
rfbErr("rfbProcessNewconnection: open fd count of %lu exceeds quota %.1f of limit %lu, denying connection\n", curfds, rfbScreen->fdQuota, maxfds);
sock = accept(chosen_listen_sock, NULL, NULL);
rfbCloseSocket(sock);
return FALSE;
if (curfds > maxfds * rfbScreen->fdQuota) {
rfbErr("rfbProcessNewconnection: open fd count of %lu exceeds quota "
"%.1f of limit %lu, denying connection\n",
curfds, rfbScreen->fdQuota, maxfds);
sock = accept(chosen_listen_sock, NULL, NULL);
rfbCloseSocket(sock);
return FALSE;
}
}
#endif

Expand Down
Loading