summaryrefslogtreecommitdiffstats
path: root/agent
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>2016-01-25 11:20:23 +0100
committerWerner Koch <wk@gnupg.org>2016-01-25 11:20:23 +0100
commitee87c653bf4b495714e8e6b024d0a8ace3a33452 (patch)
tree3ee9f5311b62b1943615db16a9f4f02c98a51e9c /agent
parentspeedo: Allow use of SHA-256 checksums (diff)
downloadgnupg2-ee87c653bf4b495714e8e6b024d0a8ace3a33452.tar.xz
gnupg2-ee87c653bf4b495714e8e6b024d0a8ace3a33452.zip
agent: Send PROGRESS status lines to the client.
* agent/gpg-agent.c (struct progress_dispatch_s): New. (progress_dispatch_list): New. (main): Register libgcrypt pogress handler. (agent_libgcrypt_progress_cb): New. (agent_set_progress_cb): New. (unregister_progress_cb): New. (agent_deinit_default_ctrl): Call unregister. * agent/command.c (progress_cb): New. (start_command_handler): Register progress callback. -- Signed-off-by: Werner Koch <wk@gnupg.org>
Diffstat (limited to 'agent')
-rw-r--r--agent/agent.h3
-rw-r--r--agent/command.c18
-rw-r--r--agent/gpg-agent.c113
3 files changed, 134 insertions, 0 deletions
diff --git a/agent/agent.h b/agent/agent.h
index c7e14332c..c2726bbbc 100644
--- a/agent/agent.h
+++ b/agent/agent.h
@@ -336,6 +336,9 @@ typedef int (*lookup_ttl_t)(const char *hexgrip);
/*-- gpg-agent.c --*/
void agent_exit (int rc)
GPGRT_ATTR_NORETURN; /* Also implemented in other tools */
+void agent_set_progress_cb (void (*cb)(ctrl_t ctrl, const char *what,
+ int printchar, int current, int total),
+ ctrl_t ctrl);
gpg_error_t agent_copy_startup_env (ctrl_t ctrl);
const char *get_agent_socket_name (void);
const char *get_agent_ssh_socket_name (void);
diff --git a/agent/command.c b/agent/command.c
index a09da607d..421df0044 100644
--- a/agent/command.c
+++ b/agent/command.c
@@ -446,6 +446,23 @@ agent_inq_pinentry_launched (ctrl_t ctrl, unsigned long pid)
}
+/* An agent progress callback for Libgcrypt. This has been registered
+ * to be called via the progress dispatcher mechanism from
+ * gpg-agent.c */
+static void
+progress_cb (ctrl_t ctrl, const char *what, int printchar,
+ int current, int total)
+{
+ if (!ctrl || !ctrl->server_local || !ctrl->server_local->assuan_ctx)
+ ;
+ else if (printchar == '\n' && what && !strcmp (what, "primegen"))
+ agent_print_status (ctrl, "PROGRESS", "%.20s X 100 100", what);
+ else
+ agent_print_status (ctrl, "PROGRESS", "%.20s %c %d %d",
+ what, printchar=='\n'?'X':printchar, current, total);
+}
+
+
/* Helper to print a message while leaving a command. */
static gpg_error_t
leave_cmd (assuan_context_t ctx, gpg_error_t err)
@@ -3205,6 +3222,7 @@ start_command_handler (ctrl_t ctrl, gnupg_fd_t listen_fd, gnupg_fd_t fd)
ctrl->digest.raw_value = 0;
assuan_set_io_monitor (ctx, io_monitor, NULL);
+ agent_set_progress_cb (progress_cb, ctrl);
for (;;)
{
diff --git a/agent/gpg-agent.c b/agent/gpg-agent.c
index 3095531a5..8aab2b951 100644
--- a/agent/gpg-agent.c
+++ b/agent/gpg-agent.c
@@ -372,6 +372,32 @@ static pid_t parent_pid = (pid_t)(-1);
/* Number of active connections. */
static int active_connections;
+/* This object is used to dispatch progress messages from Libgcrypt to
+ * the right thread. Given that we won't have at max a few dozen
+ * connections at the same time using a linked list is the easiest way
+ * to handle this. */
+struct progress_dispatch_s
+{
+ struct progress_dispatch_s *next;
+ /* The control object of the connection. If this is NULL no
+ * connection is associated with this item and it is free for reuse
+ * by new connections. */
+ ctrl_t ctrl;
+
+ /* The thread id of (npth_self) of the connection. */
+ npth_t tid;
+
+ /* The callback set by the connection. This is similar to the
+ * Libgcrypt callback but with the control object passed as the
+ * first argument. */
+ void (*cb)(ctrl_t ctrl,
+ const char *what, int printchar,
+ int current, int total);
+};
+struct progress_dispatch_s *progress_dispatch_list;
+
+
+
/*
Local prototypes.
@@ -383,6 +409,9 @@ static gnupg_fd_t create_server_socket (char *name, int primary, int cygwin,
assuan_sock_nonce_t *nonce);
static void create_directories (void);
+static void agent_libgcrypt_progress_cb (void *data, const char *what,
+ int printchar,
+ int current, int total);
static void agent_init_default_ctrl (ctrl_t ctrl);
static void agent_deinit_default_ctrl (ctrl_t ctrl);
@@ -760,6 +789,7 @@ main (int argc, char **argv )
setup_libgcrypt_logging ();
gcry_control (GCRYCTL_USE_SECURE_RNDPOOL);
+ gcry_set_progress_handler (agent_libgcrypt_progress_cb, NULL);
disable_core_dumps ();
@@ -1445,6 +1475,88 @@ agent_exit (int rc)
}
+/* This is our callback function for gcrypt progress messages. It is
+ set once at startup and dispatches progress messages to the
+ corresponding threads of the agent. */
+static void
+agent_libgcrypt_progress_cb (void *data, const char *what, int printchar,
+ int current, int total)
+{
+ struct progress_dispatch_s *dispatch;
+ npth_t mytid = npth_self ();
+
+ (void)data;
+
+ for (dispatch = progress_dispatch_list; dispatch; dispatch = dispatch->next)
+ if (dispatch->ctrl && dispatch->tid == mytid)
+ break;
+ if (dispatch && dispatch->cb)
+ dispatch->cb (dispatch->ctrl, what, printchar, current, total);
+}
+
+
+/* If a progress dispatcher callback has been associated with the
+ * current connection unregister it. */
+static void
+unregister_progress_cb (void)
+{
+ struct progress_dispatch_s *dispatch;
+ npth_t mytid = npth_self ();
+
+ for (dispatch = progress_dispatch_list; dispatch; dispatch = dispatch->next)
+ if (dispatch->ctrl && dispatch->tid == mytid)
+ break;
+ if (dispatch)
+ {
+ dispatch->ctrl = NULL;
+ dispatch->cb = NULL;
+ }
+}
+
+
+/* Setup a progress callback CB for the current connection. Using a
+ * CB of NULL disables the callback. */
+void
+agent_set_progress_cb (void (*cb)(ctrl_t ctrl, const char *what,
+ int printchar, int current, int total),
+ ctrl_t ctrl)
+{
+ struct progress_dispatch_s *dispatch, *firstfree;
+ npth_t mytid = npth_self ();
+
+ firstfree = NULL;
+ for (dispatch = progress_dispatch_list; dispatch; dispatch = dispatch->next)
+ {
+ if (dispatch->ctrl && dispatch->tid == mytid)
+ break;
+ if (!dispatch->ctrl && !firstfree)
+ firstfree = dispatch;
+ }
+ if (!dispatch) /* None allocated: Reuse or allocate a new one. */
+ {
+ if (firstfree)
+ {
+ dispatch = firstfree;
+ }
+ else if ((dispatch = xtrycalloc (1, sizeof *dispatch)))
+ {
+ dispatch->next = progress_dispatch_list;
+ progress_dispatch_list = dispatch;
+ }
+ else
+ {
+ log_error ("error allocating new progress dispatcher slot: %s\n",
+ gpg_strerror (gpg_error_from_syserror ()));
+ return;
+ }
+ dispatch->ctrl = ctrl;
+ dispatch->tid = mytid;
+ }
+
+ dispatch->cb = cb;
+}
+
+
/* Each thread has its own local variables conveyed by a control
structure usually identified by an argument named CTRL. This
function is called immediately after allocating the control
@@ -1481,6 +1593,7 @@ agent_init_default_ctrl (ctrl_t ctrl)
static void
agent_deinit_default_ctrl (ctrl_t ctrl)
{
+ unregister_progress_cb ();
session_env_release (ctrl->session_env);
if (ctrl->lc_ctype)