diff --git a/agent/gpg-agent.c b/agent/gpg-agent.c --- a/agent/gpg-agent.c +++ b/agent/gpg-agent.c @@ -138,6 +138,7 @@ oS2KCalibration, oAutoExpandSecmem, oListenBacklog, + oLimitActiveConnections, oWriteEnvFile }; @@ -260,6 +261,8 @@ ARGPARSE_s_i (oListenBacklog, "listen-backlog", "@"), + ARGPARSE_s_i (oLimitActiveConnections, "limit-active-connections", "@"), + /* Dummy options for backward compatibility. */ ARGPARSE_o_s (oWriteEnvFile, "write-env-file", "@"), ARGPARSE_s_n (oUseStandardSocket, "use-standard-socket", "@"), @@ -416,6 +419,7 @@ /* Number of active connections. */ static int active_connections; +static int limit_active_connections; /* This object is used to dispatch progress messages from Libgcrypt to * the right thread. Given that we will have at max only a few dozen @@ -1263,6 +1267,10 @@ listen_backlog = pargs.r.ret_int; break; + case oLimitActiveConnections: + limit_active_connections = pargs.r.ret_int; + break; + case oDebugQuickRandom: /* Only used by the first stage command line parser. */ break; @@ -2711,7 +2719,6 @@ static void * do_start_connection_thread (ctrl_t ctrl) { - active_connections++; agent_init_default_ctrl (ctrl); if (opt.verbose && !DBG_IPC) log_info (_("handler 0x%lx for fd %d started\n"), @@ -2725,6 +2732,8 @@ agent_deinit_default_ctrl (ctrl); xfree (ctrl); active_connections--; + if (limit_active_connections && active_connections < limit_active_connections) + kill (0, SIGUSR1); return NULL; } @@ -2791,7 +2800,6 @@ if (check_nonce (ctrl, &socket_nonce_ssh)) return NULL; - active_connections++; agent_init_default_ctrl (ctrl); if (opt.verbose) log_info (_("ssh handler 0x%lx for fd %d started\n"), @@ -2805,6 +2813,8 @@ agent_deinit_default_ctrl (ctrl); xfree (ctrl); active_connections--; + if (limit_active_connections && active_connections < limit_active_connections) + kill (0, SIGUSR1); return NULL; } @@ -2983,20 +2993,34 @@ if (home_inotify_fd > nfd) nfd = home_inotify_fd; } - } + } /* POSIX says that fd_set should be implemented as a structure, thus a simple assignment is fine to copy the entire set. */ read_fdset = fdset; + if (limit_active_connections && active_connections >= limit_active_connections) + { + FD_CLR (FD2INT(listen_fd), &read_fdset); + + if (listen_fd_ssh != GNUPG_INVALID_FD) + FD_CLR (FD2INT(listen_fd_ssh), &read_fdset); + + if (listen_fd_extra != GNUPG_INVALID_FD) + FD_CLR (FD2INT(listen_fd_extra), &read_fdset); + + if (listen_fd_browser != GNUPG_INVALID_FD) + FD_CLR (FD2INT(listen_fd_browser), &read_fdset); + } + npth_clock_gettime (&curtime); if (!(npth_timercmp (&curtime, &abstime, <))) - { - /* Timeout. */ - handle_tick (); - npth_clock_gettime (&abstime); - abstime.tv_sec += TIMERTICK_INTERVAL; - } + { + /* Timeout. */ + handle_tick (); + npth_clock_gettime (&abstime); + abstime.tv_sec += TIMERTICK_INTERVAL; + } npth_timersub (&abstime, &curtime, &timeout); #ifndef HAVE_W32_SYSTEM @@ -3016,20 +3040,20 @@ /* This is valid even if npth_eselect returns an error. */ if (events_set & 1) - agent_sigusr2_action (); + agent_sigusr2_action (); #endif if (ret == -1 && saved_errno != EINTR) - { + { log_error (_("npth_pselect failed: %s - waiting 1s\n"), strerror (saved_errno)); npth_sleep (1); continue; - } + } if (ret <= 0) - /* Interrupt or timeout. Will be handled when calculating the - next timeout. */ - continue; + /* Interrupt or timeout. Will be handled when calculating the + next timeout. */ + continue; /* The inotify fds are set even when a shutdown is pending (see * above). So we must handle them in any case. To avoid that @@ -3090,6 +3114,7 @@ else { ctrl->thread_startup.fd = fd; + active_connections++; ret = npth_create (&thread, &tattr, listentbl[idx].func, ctrl); if (ret)