# include <signal.h>
#endif
#include <npth.h>
+#ifdef HAVE_PRCTL
+# include <sys/prctl.h>
+#endif
#define GNUPG_COMMON_NEED_AFLOCAL
#include "agent.h"
watched. */
static pid_t parent_pid = (pid_t)(-1);
+/* Record the pid of the main thread, for easier signalling */
+static pid_t main_thread_pid = (pid_t)(-1);
+
/* Number of active connections. */
static int active_connections;
early_system_init ();
+#if defined(HAVE_PRCTL) && defined(PR_SET_DUMPABLE)
+ /* Disable ptrace on Linux without sgid bit */
+ prctl(PR_SET_DUMPABLE, 0);
+#endif
+
/* Before we do anything else we save the list of currently open
file descriptors and the signal mask. This info is required to
do the exec call properly. We don't need it on Windows. */
GetCurrentProcess(), &h2,
EVENT_MODIFY_STATE|SYNCHRONIZE, TRUE, 0))
{
- log_error ("setting syncronize for scd notify event failed: %s\n",
+ log_error ("setting synchronize for scd notify event failed: %s\n",
w32_strerror (-1) );
CloseHandle (h);
}
}
+static int
+need_tick (void)
+{
+#ifdef HAVE_W32_SYSTEM
+ /* We do not know how to interrupt the select loop on Windows, so we
+ always need a short tick there. */
+ return 1;
+#else
+ /* if we were invoked like "gpg-agent cmd arg1 arg2" then we need to
+ watch our parent. */
+ if (parent_pid != (pid_t)(-1))
+ return 1;
+ /* if scdaemon is running, we need to check that it's alive */
+ if (agent_scd_check_running ())
+ return 1;
+ /* otherwise, nothing fine-grained to do. */
+ return 0;
+#endif /*HAVE_W32_SYSTEM*/
+}
+
/* This is the worker for the ticker. It is called every few seconds
and may only do fast operations. */
static void
handle_tick (void)
{
- static time_t last_minute;
-
- if (!last_minute)
- last_minute = time (NULL);
-
/* Check whether the scdaemon has died and cleanup in this case. */
agent_scd_check_aliveness ();
}
}
#endif /*HAVE_W32_SYSTEM*/
-
- /* Code to be run from time to time. */
-#if CHECK_OWN_SOCKET_INTERVAL > 0
- if (last_minute + CHECK_OWN_SOCKET_INTERVAL <= time (NULL))
- {
- check_own_socket ();
- last_minute = time (NULL);
- }
-#endif
-
}
#ifndef HAVE_W32_SYSTEM
/* The signal handler for this program. It is expected to be run in
- its own trhead and not in the context of a signal handler. */
+ its own thread and not in the context of a signal handler. */
static void
handle_signal (int signo)
{
agent_sigusr2_action ();
break;
+ /* nothing to do here, just take an extra cycle on the select loop */
+ case SIGCONT:
+ break;
+
case SIGTERM:
if (!shutdown_pending)
log_info ("SIGTERM received - shutting down ...\n");
agent_deinit_default_ctrl (ctrl);
xfree (ctrl);
- active_connections--;
+ if (--active_connections == 0)
+ interrupt_main_thread_loop();
return NULL;
}
agent_deinit_default_ctrl (ctrl);
xfree (ctrl);
- active_connections--;
+ if (--active_connections == 0)
+ interrupt_main_thread_loop();
return NULL;
}
+void interrupt_main_thread_loop (void)
+{
+#ifndef HAVE_W32_SYSTEM
+ kill (main_thread_pid, SIGCONT);
+#endif
+}
+
+/* helper function for readability: test whether a given struct
+ timespec is set to all-zeros */
+static inline int
+tv_is_set (struct timespec tv)
+{
+ return tv.tv_sec || tv.tv_nsec;
+}
+
+
/* Connection handler loop. Wait for connection requests and spawn a
thread after accepting a connection. */
static void
gnupg_fd_t fd;
int nfd;
int saved_errno;
+ int idx;
struct timespec abstime;
struct timespec curtime;
struct timespec timeout;
+ struct timespec *select_timeout;
#ifdef HAVE_W32_SYSTEM
HANDLE events[2];
unsigned int events_set;
{ "browser", start_connection_thread_browser },
{ "ssh", start_connection_thread_ssh }
};
+ struct {
+ struct timespec interval;
+ void (*func) (void);
+ struct timespec next;
+ } timertbl[] = {
+ { { TIMERTICK_INTERVAL, 0 }, handle_tick },
+ { { CHECK_OWN_SOCKET_INTERVAL, 0 }, check_own_socket }
+ };
ret = npth_attr_init(&tattr);
npth_sigev_add (SIGUSR1);
npth_sigev_add (SIGUSR2);
npth_sigev_add (SIGINT);
+ npth_sigev_add (SIGCONT);
npth_sigev_add (SIGTERM);
npth_sigev_fini ();
+ main_thread_pid = getpid ();
#else
# ifdef HAVE_W32CE_SYSTEM
/* Use a dummy event. */
listentbl[2].l_fd = listen_fd_browser;
listentbl[3].l_fd = listen_fd_ssh;
- npth_clock_gettime (&abstime);
- abstime.tv_sec += TIMERTICK_INTERVAL;
-
for (;;)
{
/* Shutdown test. */
thus a simple assignment is fine to copy the entire set. */
read_fdset = fdset;
+ /* avoid a fine-grained timer if we don't need one: */
+ timertbl[0].interval.tv_sec = need_tick () ? TIMERTICK_INTERVAL : 0;
+ /* avoid waking up to check sockets if we can count on inotify */
+ timertbl[1].interval.tv_sec = (my_inotify_fd == -1) ? CHECK_OWN_SOCKET_INTERVAL : 0;
+
+ /* loop through all timers, fire any registered functions, and
+ plan next timer to trigger */
npth_clock_gettime (&curtime);
- if (!(npth_timercmp (&curtime, &abstime, <)))
- {
- /* Timeout. */
- handle_tick ();
- npth_clock_gettime (&abstime);
- abstime.tv_sec += TIMERTICK_INTERVAL;
- }
- npth_timersub (&abstime, &curtime, &timeout);
+ abstime.tv_sec = abstime.tv_nsec = 0;
+ for (idx=0; idx < DIM(timertbl); idx++)
+ {
+ /* schedule any unscheduled timers */
+ if ((!tv_is_set (timertbl[idx].next)) && tv_is_set (timertbl[idx].interval))
+ npth_timeradd (&timertbl[idx].interval, &curtime, &timertbl[idx].next);
+ /* if a timer is due, fire it ... */
+ if (tv_is_set (timertbl[idx].next))
+ {
+ if (!(npth_timercmp (&curtime, &timertbl[idx].next, <)))
+ {
+ timertbl[idx].func ();
+ npth_clock_gettime (&curtime);
+ /* ...and reschedule it, if desired: */
+ if (tv_is_set (timertbl[idx].interval))
+ npth_timeradd (&timertbl[idx].interval, &curtime, &timertbl[idx].next);
+ else
+ timertbl[idx].next.tv_sec = timertbl[idx].next.tv_nsec = 0;
+ }
+ }
+ /* accumulate next timer to come due in abstime: */
+ if (tv_is_set (timertbl[idx].next) &&
+ ((!tv_is_set (abstime)) ||
+ (npth_timercmp (&abstime, &timertbl[idx].next, >))))
+ abstime = timertbl[idx].next;
+ }
+ /* choose a timeout for the select loop: */
+ if (tv_is_set (abstime))
+ {
+ npth_timersub (&abstime, &curtime, &timeout);
+ select_timeout = &timeout;
+ }
+ else
+ select_timeout = NULL;
+
#ifndef HAVE_W32_SYSTEM
- ret = npth_pselect (nfd+1, &read_fdset, NULL, NULL, &timeout,
+ ret = npth_pselect (nfd+1, &read_fdset, NULL, NULL, select_timeout,
npth_sigev_sigmask ());
saved_errno = errno;
handle_signal (signo);
}
#else
- ret = npth_eselect (nfd+1, &read_fdset, NULL, NULL, &timeout,
+ ret = npth_eselect (nfd+1, &read_fdset, NULL, NULL, select_timeout,
events, &events_set);
saved_errno = errno;
if (!shutdown_pending)
{
- int idx;
ctrl_t ctrl;
npth_t thread;