# 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. */
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");
}
+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. */
# endif
#endif
+
if (disable_check_own_socket)
my_inotify_fd = -1;
else if ((err = gnupg_inotify_watch_socket (&my_inotify_fd, socket_name)))
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;