aboutsummaryrefslogtreecommitdiffstats
path: root/agent/call-scd.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--agent/call-scd.c81
1 files changed, 59 insertions, 22 deletions
diff --git a/agent/call-scd.c b/agent/call-scd.c
index fc81e2fa3..617ef0d48 100644
--- a/agent/call-scd.c
+++ b/agent/call-scd.c
@@ -185,26 +185,15 @@ start_scd (ctrl_t ctrl)
}
ctrl->scd_local->locked++;
- /* If we already have a context, we better do a sanity check now to
- see whether it has accidently died. This avoids annoying
- timeouts and hung connections. */
if (ctrl->scd_local->ctx)
- {
- pid_t pid;
-#ifndef HAVE_W32_SYSTEM
- pid = assuan_get_pid (ctrl->scd_local->ctx);
- if (pid != (pid_t)(-1) && pid
- && ((rc=waitpid (pid, NULL, WNOHANG))==-1 || (rc == pid)) )
- {
- assuan_disconnect (ctrl->scd_local->ctx);
- ctrl->scd_local->ctx = NULL;
- }
- else
-#endif
- return 0; /* Okay, the context is fine. */
- }
+ return 0; /* Okay, the context is fine. We used to test for an
+ alive context here and do an disconnect. How that we
+ have a ticker function to check for it, it is easier
+ not to check here but to let the connection run on an
+ error instead. */
- /* We need to protect the lowwing code. */
+
+ /* We need to protect the following code. */
if (!pth_mutex_acquire (&start_scd_lock, 0, NULL))
{
log_error ("failed to acquire the start_scd lock: %s\n",
@@ -350,6 +339,50 @@ start_scd (ctrl_t ctrl)
}
+/* Check whether the Scdaemon is still alive and clean it up if not. */
+void
+agent_scd_check_aliveness (void)
+{
+ pid_t pid;
+ int rc;
+
+ /* We can do so only if there is no more active primary connection.
+ With an active primary connection, this is all no problem because
+ with the end of gpg-agent's session a disconnect is send and the
+ this function will be used at a later time. */
+ if (!primary_scd_ctx || !primary_scd_ctx_reusable)
+ return;
+
+ if (!pth_mutex_acquire (&start_scd_lock, 0, NULL))
+ {
+ log_error ("failed to acquire the start_scd lock while"
+ " doing an aliveness check: %s\n",
+ strerror (errno));
+ return;
+ }
+
+ if (primary_scd_ctx && primary_scd_ctx_reusable)
+ {
+ pid = assuan_get_pid (primary_scd_ctx);
+ if (pid != (pid_t)(-1) && pid
+ && ((rc=waitpid (pid, NULL, WNOHANG))==-1 || (rc == pid)) )
+ {
+ /* Okay, scdaemon died. Disconnect the primary connection now
+ but take care that it won't do another wait. */
+ assuan_set_flag (primary_scd_ctx, ASSUAN_NO_WAITPID, 1);
+ assuan_disconnect (primary_scd_ctx);
+ primary_scd_ctx = NULL;
+ primary_scd_ctx_reusable = 0;
+ xfree (socket_name);
+ socket_name = NULL;
+ }
+ }
+
+ if (!pth_mutex_release (&start_scd_lock))
+ log_error ("failed to release the start_scd lock while"
+ " doing the aliveness check: %s\n", strerror (errno));
+}
+
/* Reset the SCD if it has been used. */
int
@@ -359,15 +392,19 @@ agent_reset_scd (ctrl_t ctrl)
{
if (ctrl->scd_local->ctx)
{
- /* We can't disconnect the primary context becuase libassuan
+ /* We can't disconnect the primary context because libassuan
does a waitpid on it and thus the system would hang.
Instead we send a reset and keep that connection for
reuse. */
if (ctrl->scd_local->ctx == primary_scd_ctx)
{
- if (!assuan_transact (primary_scd_ctx, "RESET",
- NULL, NULL, NULL, NULL, NULL, NULL))
- primary_scd_ctx_reusable = 1;
+ /* The RESET may fail for example if the scdaemon has
+ already been terminated. We need to set the reusable
+ flag anyway to make sure that the aliveness check can
+ clean it up. */
+ assuan_transact (primary_scd_ctx, "RESET",
+ NULL, NULL, NULL, NULL, NULL, NULL);
+ primary_scd_ctx_reusable = 1;
}
else
assuan_disconnect (ctrl->scd_local->ctx);