1
0
Fork 0
mirror of git://git.gnupg.org/gnupg.git synced 2025-07-03 22:56:33 +02:00

Initial port to Npth.

This commit is contained in:
Marcus Brinkmann 2011-09-29 03:14:37 +02:00
parent 6cf8890dc1
commit 2959e9e4d1
43 changed files with 1012 additions and 1058 deletions

View file

@ -1,3 +1,8 @@
2011-10-13 Marcus Brinkmann <marcus@g10code.com>
* Makefile.am, certcache.c, crlfetch.c, dirmngr.c, ldap-wrapper.c:
Port to NPth.
2011-06-01 Marcus Brinkmann <mb@g10code.com>
* Makefile.am (dirmngr_ldap_CFLAGS): Add $(LIBGCRYPT_CFLAGS),

View file

@ -32,7 +32,7 @@ AM_CPPFLAGS = -I$(top_srcdir)/gl -I$(top_srcdir)/intl -I$(top_srcdir)/common
include $(top_srcdir)/am/cmacros.am
AM_CFLAGS = $(LIBGCRYPT_CFLAGS) $(KSBA_CFLAGS) \
$(LIBASSUAN_CFLAGS) $(GPG_ERROR_CFLAGS) $(PTH_CFLAGS)
$(LIBASSUAN_CFLAGS) $(GPG_ERROR_CFLAGS) $(NPTH_CFLAGS)
BUILT_SOURCES = no-libgcrypt.c
@ -61,7 +61,7 @@ endif
dirmngr_LDADD = $(libcommonpth) ../gl/libgnu.a $(DNSLIBS) $(LIBASSUAN_LIBS) \
$(LIBGCRYPT_LIBS) $(KSBA_LIBS) $(PTH_LIBS) $(LIBINTL) $(LIBICONV)
$(LIBGCRYPT_LIBS) $(KSBA_LIBS) $(NPTH_LIBS) $(LIBINTL) $(LIBICONV)
if !USE_LDAPWRAPPER
dirmngr_LDADD += $(LDAPLIBS)
endif

View file

@ -25,7 +25,7 @@
#include <assert.h>
#include <sys/types.h>
#include <dirent.h>
#include <pth.h>
#include <npth.h>
#include "dirmngr.h"
#include "misc.h"
@ -80,10 +80,10 @@ static cert_item_t cert_cache[256];
/* This is the global cache_lock variable. In general looking is not
needed but it would take extra efforts to make sure that no
indirect use of pth functions is done, so we simply lock it always.
Note: We can't use static initialization, as that is not available
through w32-pth. */
static pth_rwlock_t cert_cache_lock;
indirect use of npth functions is done, so we simply lock it
always. Note: We can't use static initialization, as that is not
available through w32-pth. */
static npth_rwlock_t cert_cache_lock;
/* Flag to track whether the cache has been initialized. */
static int initialization_done;
@ -99,33 +99,45 @@ static unsigned int total_extra_certificates;
static void
init_cache_lock (void)
{
if (!pth_rwlock_init (&cert_cache_lock))
int err;
err = npth_rwlock_init (&cert_cache_lock, NULL);
if (err)
log_fatal (_("can't initialize certificate cache lock: %s\n"),
strerror (errno));
strerror (err));
}
static void
acquire_cache_read_lock (void)
{
if (!pth_rwlock_acquire (&cert_cache_lock, PTH_RWLOCK_RD, FALSE, NULL))
int err;
err = npth_rwlock_rdlock (&cert_cache_lock);
if (err)
log_fatal (_("can't acquire read lock on the certificate cache: %s\n"),
strerror (errno));
strerror (err));
}
static void
acquire_cache_write_lock (void)
{
if (!pth_rwlock_acquire (&cert_cache_lock, PTH_RWLOCK_RW, FALSE, NULL))
int err;
err = npth_rwlock_wrlock (&cert_cache_lock);
if (err)
log_fatal (_("can't acquire write lock on the certificate cache: %s\n"),
strerror (errno));
strerror (err));
}
static void
release_cache_lock (void)
{
if (!pth_rwlock_release (&cert_cache_lock))
int err;
err = npth_rwlock_unlock (&cert_cache_lock);
if (err)
log_fatal (_("can't release lock on the certificate cache: %s\n"),
strerror (errno));
strerror (err));
}

View file

@ -22,7 +22,7 @@
#include <stdio.h>
#include <errno.h>
#include <pth.h>
#include <npth.h>
#include "crlfetch.h"
#include "dirmngr.h"
@ -72,7 +72,7 @@ register_file_reader (ksba_reader_t reader, struct reader_cb_context_s *cb_ctx)
return;
}
log_info (_("reader to file mapping table full - waiting\n"));
pth_sleep (2);
npth_sleep (2);
}
}

View file

@ -40,7 +40,7 @@
#ifdef HAVE_SIGNAL_H
# include <signal.h>
#endif
#include <pth.h>
#include <npth.h>
#define JNLIB_NEED_LOG_LOGV
@ -254,7 +254,7 @@ static int active_connections;
/* This union is used to avoid compiler warnings in case a pointer is
64 bit and an int 32 bit. We store an integer in a pointer and get
it back later (pth_key_getdata et al.). */
it back later (npth_getspecific et al.). */
union int_and_ptr_u
{
int aint;
@ -277,21 +277,8 @@ static ldap_server_t parse_ldapserver_file (const char* filename);
static fingerprint_list_t parse_ocsp_signer (const char *string);
static void handle_connections (assuan_fd_t listen_fd);
/* Pth wrapper function definitions. */
ASSUAN_SYSTEM_PTH_IMPL;
GCRY_THREAD_OPTION_PTH_IMPL;
static int fixed_gcry_pth_init (void)
{
return pth_self ()? 0 : (pth_init () == FALSE) ? errno : 0;
}
#ifndef PTH_HAVE_PTH_THREAD_ID
static unsigned long pth_thread_id (void)
{
return (unsigned long)pth_self ();
}
#endif
/* NPth wrapper function definitions. */
ASSUAN_SYSTEM_NPTH_IMPL;
static const char *
my_strusage( int level )
@ -551,7 +538,7 @@ pid_suffix_callback (unsigned long *r_suffix)
{
union int_and_ptr_u value;
value.aptr = pth_key_getdata (my_tlskey_current_fd);
value.aptr = npth_getspecific (my_tlskey_current_fd);
*r_suffix = value.aint;
return (*r_suffix != -1); /* Use decimal representation. */
}
@ -618,15 +605,8 @@ main (int argc, char **argv)
i18n_init ();
init_common_subsystems (&argc, &argv);
/* Libgcrypt requires us to register the threading model first.
Note that this will also do the pth_init. */
gcry_threads_pth.init = fixed_gcry_pth_init;
rc = gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pth);
if (rc)
{
log_fatal ("can't register GNU Pth with Libgcrypt: %s\n",
gpg_strerror (rc));
}
npth_init ();
gcry_control (GCRYCTL_DISABLE_SECMEM, 0);
/* Check that the libraries are suitable. Do it here because
@ -650,7 +630,7 @@ main (int argc, char **argv)
assuan_set_malloc_hooks (&malloc_hooks);
assuan_set_assuan_log_prefix (log_get_prefix (NULL));
assuan_set_gpg_err_source (GPG_ERR_SOURCE_DEFAULT);
assuan_set_system_hooks (ASSUAN_SYSTEM_PTH);
assuan_set_system_hooks (ASSUAN_SYSTEM_NPTH);
assuan_sock_init ();
setup_libassuan_logging (&opt.debug);
@ -663,12 +643,12 @@ main (int argc, char **argv)
opt.homedir = default_homedir ();
/* Now with Pth running we can set the logging callback. Our
windows implementation does not yet feature the Pth TLS
/* Now with NPth running we can set the logging callback. Our
windows implementation does not yet feature the NPth TLS
functions. */
#ifndef HAVE_W32_SYSTEM
if (pth_key_create (&my_tlskey_current_fd, NULL))
if (pth_key_setdata (my_tlskey_current_fd, NULL))
if (npth_key_create (&my_tlskey_current_fd, NULL) == 0)
if (npth_setspecific (my_tlskey_current_fd, NULL) == 0)
log_set_pid_suffix_cb (pid_suffix_callback);
#endif /*!HAVE_W32_SYSTEM*/
@ -1028,7 +1008,7 @@ main (int argc, char **argv)
pid = getpid ();
es_printf ("set DIRMNGR_INFO=%s;%lu;1\n", socket_name, (ulong) pid);
#else
pid = pth_fork ();
pid = fork();
if (pid == (pid_t)-1)
{
log_fatal (_("error forking process: %s\n"), strerror (errno));
@ -1554,7 +1534,7 @@ parse_ocsp_signer (const char *string)
/* Reread parts of the configuration. Note, that this function is
obviously not thread-safe and should only be called from the PTH
obviously not thread-safe and should only be called from the NPTH
signal handler.
Fixme: Due to the way the argument parsing works, we create a
@ -1715,12 +1695,12 @@ start_connection_thread (void *arg)
if (check_nonce (fd, &socket_nonce))
{
log_error ("handler 0x%lx nonce check FAILED\n", pth_thread_id ());
log_error ("handler nonce check FAILED\n");
return NULL;
}
#ifndef HAVE_W32_SYSTEM
pth_key_setdata (my_tlskey_current_fd, argval.aptr);
npth_setspecific (my_tlskey_current_fd, argval.aptr);
#endif
active_connections++;
@ -1735,7 +1715,7 @@ start_connection_thread (void *arg)
#ifndef HAVE_W32_SYSTEM
argval.afd = ASSUAN_INVALID_FD;
pth_key_setdata (my_tlskey_current_fd, argval.aptr);
npth_setspecific (my_tlskey_current_fd, argval.aptr);
#endif
return NULL;
@ -1746,53 +1726,33 @@ start_connection_thread (void *arg)
static void
handle_connections (assuan_fd_t listen_fd)
{
pth_attr_t tattr;
pth_event_t ev, time_ev;
sigset_t sigs;
npth_attr_t tattr;
int signo;
struct sockaddr_un paddr;
socklen_t plen = sizeof( paddr );
gnupg_fd_t fd;
int nfd, ret;
fd_set fdset, read_fdset;
struct timespec abstime;
struct timespec curtime;
struct timespec timeout;
int saved_errno;
tattr = pth_attr_new();
pth_attr_set (tattr, PTH_ATTR_JOINABLE, 0);
pth_attr_set (tattr, PTH_ATTR_STACK_SIZE, 1024*1024);
pth_attr_set (tattr, PTH_ATTR_NAME, "dirmngr");
npth_attr_init (&tattr);
npth_attr_setdetachstate (&tattr, NPTH_CREATE_DETACHED);
#ifndef HAVE_W32_SYSTEM /* FIXME */
/* Make sure that the signals we are going to handle are not blocked
and create an event object for them. We also set the default
action to ignore because we use an Pth event to get notified
about signals. This avoids that the default action is taken in
case soemthing goes wrong within Pth. The problem might also be
a Pth bug. */
sigemptyset (&sigs );
{
static const int mysigs[] = { SIGHUP, SIGUSR1, SIGUSR2, SIGINT, SIGTERM };
struct sigaction sa;
int i;
for (i=0; i < DIM (mysigs); i++)
{
sigemptyset (&sa.sa_mask);
sa.sa_handler = SIG_IGN;
sa.sa_flags = 0;
sigaction (mysigs[i], &sa, NULL);
sigaddset (&sigs, mysigs[i]);
}
}
pth_sigmask (SIG_UNBLOCK, &sigs, NULL);
ev = pth_event (PTH_EVENT_SIGS, &sigs, &signo);
npth_sigev_init ();
npth_sigev_add (SIGHUP);
npth_sigev_add (SIGUSR1);
npth_sigev_add (SIGUSR2);
npth_sigev_add (SIGINT);
npth_sigev_add (SIGTERM);
npth_sigev_fini ();
#else
/* Use a dummy event. */
sigs = 0;
ev = pth_event (PTH_EVENT_SIGS, &sigs, &signo);
#endif
time_ev = NULL;
/* Setup the fdset. It has only one member. This is because we use
pth_select instead of pth_accept to properly sync timeouts with
@ -1801,12 +1761,12 @@ handle_connections (assuan_fd_t listen_fd)
FD_SET (FD2INT (listen_fd), &fdset);
nfd = FD2INT (listen_fd);
npth_clock_gettime (&abstime);
abstime.tv_sec += TIMERTICK_INTERVAL;
/* Main loop. */
for (;;)
{
/* Make sure that our signals are not blocked. */
pth_sigmask (SIG_UNBLOCK, &sigs, NULL);
/* Shutdown test. */
if (shutdown_pending)
{
@ -1818,76 +1778,45 @@ handle_connections (assuan_fd_t listen_fd)
FD_ZERO (&fdset);
}
/* Create a timeout event if needed. To help with power saving
we syncronize the ticks to the next full second. */
if (!time_ev)
{
pth_time_t nexttick;
nexttick = pth_timeout (TIMERTICK_INTERVAL, 0);
if (nexttick.tv_usec > 10) /* Use a 10 usec threshhold. */
{
nexttick.tv_sec++;
nexttick.tv_usec = 0;
}
time_ev = pth_event (PTH_EVENT_TIME, nexttick);
}
/* Take a copy of the fdset. */
read_fdset = fdset;
if (time_ev)
pth_event_concat (ev, time_ev, NULL);
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);
ret = pth_select_ev (nfd+1, &read_fdset, NULL, NULL, NULL, ev);
ret = npth_pselect (nfd+1, &read_fdset, NULL, NULL, &timeout, npth_sigev_sigmask());
saved_errno = errno;
if (time_ev)
pth_event_isolate (time_ev);
#ifndef HAVE_W32_SYSTEM
while (npth_sigev_get_pending(&signo))
handle_signal (signo);
#endif
if (ret == -1)
{
if (pth_event_occurred (ev)
|| (time_ev && pth_event_occurred (time_ev)) )
{
if (pth_event_occurred (ev))
handle_signal (signo);
if (time_ev && pth_event_occurred (time_ev))
{
pth_event_free (time_ev, PTH_FREE_ALL);
time_ev = NULL;
handle_tick ();
}
continue;
}
log_error (_("pth_select failed: %s - waiting 1s\n"),
strerror (errno));
pth_sleep (1);
if (ret == -1 && saved_errno != EINTR)
{
log_error (_("npth_pselect failed: %s - waiting 1s\n"),
strerror (saved_errno));
npth_sleep (1);
continue;
}
if (pth_event_occurred (ev))
{
handle_signal (signo);
}
if (time_ev && pth_event_occurred (time_ev))
{
pth_event_free (time_ev, PTH_FREE_ALL);
time_ev = NULL;
handle_tick ();
}
/* We now might create a new thread and because we don't want
any signals (as we are handling them here) to be delivered to
a new thread we need to block those signals. */
pth_sigmask (SIG_BLOCK, &sigs, NULL);
if (ret <= 0)
/* Interrupt or timeout. Will be handled when calculating the
next timeout. */
continue;
if (!shutdown_pending && FD_ISSET (FD2INT (listen_fd), &read_fdset))
{
plen = sizeof paddr;
fd = INT2FD (pth_accept (FD2INT(listen_fd),
(struct sockaddr *)&paddr, &plen));
fd = INT2FD (npth_accept (FD2INT(listen_fd),
(struct sockaddr *)&paddr, &plen));
if (fd == GNUPG_INVALID_FD)
{
log_error ("accept failed: %s\n", strerror (errno));
@ -1896,27 +1825,27 @@ handle_connections (assuan_fd_t listen_fd)
{
char threadname[50];
union int_and_ptr_u argval;
npth_t thread;
argval.afd = fd;
snprintf (threadname, sizeof threadname-1,
"conn fd=%d", FD2INT(fd));
threadname[sizeof threadname -1] = 0;
pth_attr_set (tattr, PTH_ATTR_NAME, threadname);
if (!pth_spawn (tattr, start_connection_thread, argval.aptr))
ret = npth_create (&thread, &tattr, start_connection_thread, argval.aptr);
if (ret)
{
log_error ("error spawning connection handler: %s\n",
strerror (errno) );
strerror (ret) );
assuan_sock_close (fd);
}
npth_setname_np (thread, threadname);
}
fd = GNUPG_INVALID_FD;
}
}
pth_event_free (ev, PTH_FREE_ALL);
if (time_ev)
pth_event_free (time_ev, PTH_FREE_ALL);
pth_attr_destroy (tattr);
npth_attr_destroy (&tattr);
cleanup ();
log_info ("%s %s stopped\n", strusage(11), strusage(13));
}

View file

@ -33,7 +33,7 @@
#include <sys/time.h>
#include <unistd.h>
#ifndef USE_LDAPWRAPPER
# include <pth.h>
# include <npth.h>
#endif
#ifdef HAVE_W32_SYSTEM

View file

@ -35,7 +35,7 @@
#include <unistd.h>
#include <fcntl.h>
#include <time.h>
#include <pth.h>
#include <npth.h>
#include <assert.h>
#include "dirmngr.h"

View file

@ -55,7 +55,7 @@
#include <unistd.h>
#include <fcntl.h>
#include <time.h>
#include <pth.h>
#include <npth.h>
#include "dirmngr.h"
#include "exechelp.h"
@ -82,7 +82,7 @@
#define INACTIVITY_TIMEOUT (opt.ldaptimeout + 60*5) /* seconds */
#define TIMERTICK_INTERVAL 2
/* To keep track of the LDAP wrapper state we use this structure. */
struct wrapper_context_s
@ -96,7 +96,6 @@ struct wrapper_context_s
gpg_error_t fd_error; /* Set to the gpg_error of the last read error
if any. */
int log_fd; /* Connected with stderr of the ldap wrapper. */
pth_event_t log_ev;
ctrl_t ctrl; /* Connection data. */
int ready; /* Internally used to mark to be removed contexts. */
ksba_reader_t reader; /* The ksba reader object or NULL. */
@ -117,8 +116,8 @@ static struct wrapper_context_s *wrapper_list;
static int shutting_down;
/* Close the pth file descriptor FD and set it to -1. */
#define SAFE_PTH_CLOSE(fd) \
do { int _fd = fd; if (_fd != -1) { pth_close (_fd); fd = -1;} } while (0)
#define SAFE_CLOSE(fd) \
do { int _fd = fd; if (_fd != -1) { close (_fd); fd = -1;} } while (0)
@ -152,10 +151,8 @@ destroy_wrapper (struct wrapper_context_s *ctx)
gnupg_release_process (ctx->pid);
}
ksba_reader_release (ctx->reader);
SAFE_PTH_CLOSE (ctx->fd);
SAFE_PTH_CLOSE (ctx->log_fd);
if (ctx->log_ev)
pth_event_free (ctx->log_ev, PTH_FREE_THIS);
SAFE_CLOSE (ctx->fd);
SAFE_CLOSE (ctx->log_fd);
xfree (ctx->line);
xfree (ctx);
}
@ -228,9 +225,9 @@ read_log_data (struct wrapper_context_s *ctx)
int n;
char line[256];
/* We must use the pth_read function for pipes, always. */
/* We must use the npth_read function for pipes, always. */
do
n = pth_read (ctx->log_fd, line, sizeof line - 1);
n = npth_read (ctx->log_fd, line, sizeof line - 1);
while (n < 0 && errno == EINTR);
if (n <= 0) /* EOF or error. */
@ -239,9 +236,7 @@ read_log_data (struct wrapper_context_s *ctx)
log_error (_("error reading log from ldap wrapper %d: %s\n"),
ctx->pid, strerror (errno));
print_log_line (ctx, NULL);
SAFE_PTH_CLOSE (ctx->log_fd);
pth_event_free (ctx->log_ev, PTH_FREE_THIS);
ctx->log_ev = NULL;
SAFE_CLOSE (ctx->log_fd);
return 1;
}
@ -261,58 +256,72 @@ ldap_wrapper_thread (void *dummy)
int nfds;
struct wrapper_context_s *ctx;
struct wrapper_context_s *ctx_prev;
time_t current_time;
struct timespec abstime;
struct timespec curtime;
struct timespec timeout;
int saved_errno;
fd_set fdset, read_fdset;
int ret;
time_t exptime;
(void)dummy;
FD_ZERO (&fdset);
nfds = -1;
for (ctx = wrapper_list; ctx; ctx = ctx->next)
{
if (ctx->log_fd != -1)
{
FD_SET (ctx->log_fd, &fdset);
if (ctx->log_fd > nfds)
nfds = ctx->log_fd;
}
}
nfds++;
npth_clock_gettime (&abstime);
abstime.tv_sec += TIMERTICK_INTERVAL;
for (;;)
{
pth_event_t timeout_ev;
int any_action = 0;
pth_time_t nexttick;
/* We timeout the pth_wait every 2 seconds. To help with power
saving we syncronize the timeouts to the next full second. */
nexttick = pth_timeout (2, 0);
if (nexttick.tv_usec > 10) /* Use a 10 usec threshhold. */
{
nexttick.tv_sec++;
nexttick.tv_usec = 0;
}
timeout_ev = pth_event (PTH_EVENT_TIME, nexttick);
if (! timeout_ev)
/* 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;
npth_clock_gettime (&curtime);
if (!(npth_timercmp (&curtime, &abstime, <)))
{
log_error (_("pth_event failed: %s\n"), strerror (errno));
pth_sleep (10);
continue;
/* Inactivity is checked below. Nothing else to do. */
// handle_tick ();
npth_clock_gettime (&abstime);
abstime.tv_sec += TIMERTICK_INTERVAL;
}
npth_timersub (&abstime, &curtime, &timeout);
/* FIXME: For Windows, we have to use a reader thread on the
pipe that signals an event (and a npth_select_ev variant). */
ret = npth_pselect (nfds + 1, &read_fdset, NULL, NULL, &timeout, NULL);
saved_errno = errno;
if (ret == -1 && saved_errno != EINTR)
{
log_error (_("npth_select failed: %s - waiting 1s\n"),
strerror (saved_errno));
npth_sleep (1);
continue;
}
for (ctx = wrapper_list; ctx; ctx = ctx->next)
{
if (ctx->log_fd != -1)
{
pth_event_isolate (ctx->log_ev);
pth_event_concat (timeout_ev, ctx->log_ev, NULL);
}
}
if (ret <= 0)
/* Interrupt or timeout. Will be handled when calculating the
next timeout. */
continue;
/* Note that the read FDs are actually handles. Thus, we can
not use pth_select, but have to use pth_wait. */
nfds = pth_wait (timeout_ev);
if (nfds < 0)
{
pth_event_free (timeout_ev, PTH_FREE_THIS);
log_error (_("pth_wait failed: %s\n"), strerror (errno));
pth_sleep (10);
continue;
}
if (pth_event_status (timeout_ev) == PTH_STATUS_OCCURRED)
nfds--;
pth_event_free (timeout_ev, PTH_FREE_THIS);
current_time = time (NULL);
if (current_time > INACTIVITY_TIMEOUT)
current_time -= INACTIVITY_TIMEOUT;
/* All timestamps before exptime should be considered expired. */
exptime = time (NULL);
if (exptime > INACTIVITY_TIMEOUT)
exptime -= INACTIVITY_TIMEOUT;
/* Note that there is no need to lock the list because we always
add entries at the head (with a pending event status) and
@ -322,8 +331,7 @@ ldap_wrapper_thread (void *dummy)
for (ctx = wrapper_list; ctx; ctx = ctx->next)
{
/* Check whether there is any logging to be done. */
if (nfds && ctx->log_fd != -1
&& pth_event_status (ctx->log_ev) == PTH_STATUS_OCCURRED)
if (nfds && ctx->log_fd != -1 && FD_ISSET (ctx->log_fd, &read_fdset))
{
if (read_log_data (ctx))
any_action = 1;
@ -368,7 +376,7 @@ ldap_wrapper_thread (void *dummy)
/* Check whether we should terminate the process. */
if (ctx->pid != (pid_t)(-1)
&& ctx->stamp != (time_t)(-1) && ctx->stamp < current_time)
&& ctx->stamp != (time_t)(-1) && ctx->stamp < exptime)
{
gnupg_kill_process (ctx->pid);
ctx->stamp = (time_t)(-1);
@ -376,7 +384,7 @@ ldap_wrapper_thread (void *dummy)
(int)ctx->pid);
/* We need to close the log fd because the cleanup loop
waits for it. */
SAFE_PTH_CLOSE (ctx->log_fd);
SAFE_CLOSE (ctx->log_fd);
any_action = 1;
}
}
@ -426,24 +434,26 @@ void
ldap_wrapper_launch_thread (void)
{
static int done;
pth_attr_t tattr;
npth_attr_t tattr;
npth_t thread;
int err;
if (done)
return;
done = 1;
tattr = pth_attr_new();
pth_attr_set (tattr, PTH_ATTR_JOINABLE, 0);
pth_attr_set (tattr, PTH_ATTR_STACK_SIZE, 256*1024);
pth_attr_set (tattr, PTH_ATTR_NAME, "ldap-reaper");
npth_attr_init (&tattr);
npth_attr_setdetachstate (&tattr, NPTH_CREATE_DETACHED);
if (!pth_spawn (tattr, ldap_wrapper_thread, NULL))
err = npth_create (&thread, &tattr, ldap_wrapper_thread, NULL);
if (err)
{
log_error (_("error spawning ldap wrapper reaper thread: %s\n"),
strerror (errno) );
strerror (err) );
dirmngr_exit (1);
}
pth_attr_destroy (tattr);
npth_setname_np (thread, "ldap-reaper");
npth_attr_destroy (&tattr);
}
@ -456,8 +466,9 @@ void
ldap_wrapper_wait_connections ()
{
shutting_down = 1;
/* FIXME: This is a busy wait. */
while (wrapper_list)
pth_yield (NULL);
npth_yield ();
}
@ -482,7 +493,7 @@ ldap_wrapper_release_context (ksba_reader_t reader)
ctx->ctrl, ctx->ctrl? ctx->ctrl->refcount:0);
ctx->reader = NULL;
SAFE_PTH_CLOSE (ctx->fd);
SAFE_CLOSE (ctx->fd);
if (ctx->ctrl)
{
ctx->ctrl->refcount--;
@ -515,6 +526,7 @@ ldap_wrapper_connection_cleanup (ctrl_t ctrl)
}
}
/* This is the callback used by the ldap wrapper to feed the ksba
reader with the wrappers stdout. See the description of
ksba_reader_set_cb for details. */
@ -523,6 +535,13 @@ reader_callback (void *cb_value, char *buffer, size_t count, size_t *nread)
{
struct wrapper_context_s *ctx = cb_value;
size_t nleft = count;
int nfds;
struct timespec abstime;
struct timespec curtime;
struct timespec timeout;
int saved_errno;
fd_set fdset, read_fdset;
int ret;
/* FIXME: We might want to add some internal buffering because the
ksba code does not do any buffering for itself (because a ksba
@ -542,57 +561,73 @@ reader_callback (void *cb_value, char *buffer, size_t count, size_t *nread)
return -1;
}
FD_ZERO (&fdset);
FD_SET (ctx->fd, &fdset);
nfds = ctx->fd + 1;
npth_clock_gettime (&abstime);
abstime.tv_sec += TIMERTICK_INTERVAL;
while (nleft > 0)
{
int n;
pth_event_t evt;
gpg_error_t err;
evt = pth_event (PTH_EVENT_TIME, pth_timeout (1, 0));
n = pth_read_ev (ctx->fd, buffer, nleft, evt);
if (n < 0 && evt && pth_event_occurred (evt))
{
n = 0;
err = dirmngr_tick (ctx->ctrl);
npth_clock_gettime (&curtime);
if (!(npth_timercmp (&curtime, &abstime, <)))
{
err = dirmngr_tick (ctx->ctrl);
if (err)
{
ctx->fd_error = err;
SAFE_PTH_CLOSE (ctx->fd);
if (evt)
pth_event_free (evt, PTH_FREE_THIS);
SAFE_CLOSE (ctx->fd);
return -1;
}
npth_clock_gettime (&abstime);
abstime.tv_sec += TIMERTICK_INTERVAL;
}
npth_timersub (&abstime, &curtime, &timeout);
read_fdset = fdset;
ret = npth_pselect (nfds, &read_fdset, NULL, NULL, &timeout, NULL);
saved_errno = errno;
if (ret == -1 && saved_errno != EINTR)
{
ctx->fd_error = gpg_error_from_errno (errno);
SAFE_CLOSE (ctx->fd);
return -1;
}
else if (n < 0)
if (ret <= 0)
/* Timeout. Will be handled when calculating the next timeout. */
continue;
/* This should not block now that select returned with a file
descriptor. So it shouldn't be necessary to use npth_read
(and it is slightly dangerous in the sense that a concurrent
thread might (accidentially?) change the status of ctx->fd
before we read. FIXME: Set ctx->fd to nonblocking? */
n = read (ctx->fd, buffer, nleft);
if (n < 0)
{
ctx->fd_error = gpg_error_from_errno (errno);
SAFE_PTH_CLOSE (ctx->fd);
if (evt)
pth_event_free (evt, PTH_FREE_THIS);
SAFE_CLOSE (ctx->fd);
return -1;
}
else if (!n)
{
if (nleft == count)
{
if (evt)
pth_event_free (evt, PTH_FREE_THIS);
return -1; /* EOF. */
}
return -1; /* EOF. */
break;
}
nleft -= n;
buffer += n;
if (evt)
pth_event_free (evt, PTH_FREE_THIS);
if (n > 0 && ctx->stamp != (time_t)(-1))
ctx->stamp = time (NULL);
}
*nread = count - nleft;
return 0;
}
/* Fork and exec the LDAP wrapper and returns a new libksba reader
@ -702,12 +737,6 @@ ldap_wrapper (ctrl_t ctrl, ksba_reader_t *reader, const char *argv[])
ctx->printable_pid = (int) pid;
ctx->fd = outpipe[0];
ctx->log_fd = errpipe[0];
ctx->log_ev = pth_event (PTH_EVENT_FD | PTH_UNTIL_FD_READABLE, ctx->log_fd);
if (! ctx->log_ev)
{
xfree (ctx);
return gpg_error_from_syserror ();
}
ctx->ctrl = ctrl;
ctrl->refcount++;
ctx->stamp = time (NULL);

View file

@ -28,7 +28,7 @@
#include <unistd.h>
#include <fcntl.h>
#include <time.h>
#include <pth.h>
#include <npth.h>
#include "dirmngr.h"
#include "exechelp.h"