core: Link all context objects and add _gpgme_get_ctx.

* src/context.h (struct gpgme_context): Add field 'next_ctx'.
* src/gpgme.c (def_lc_lock): Replace by ...
(context_list_lock): new.
(context_list): New variable.
(gpgme_new): Add new context object to the list.
(gpgme_release): Remove context object from the list.
(_gpgme_get_ctx): New function.
--

To allow mapping a context serial number back to a context object and
to check whether a serialno has still a context object, we need to
link them all together.  We already take a lock to setup the locale
and thus the only overhead is in freeing the context.

Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
Werner Koch 2019-06-12 10:49:34 +02:00
parent 92883efe71
commit 5cfdf878fb
No known key found for this signature in database
GPG Key ID: E3FDFF218E45B72B
3 changed files with 91 additions and 17 deletions

View File

@ -73,9 +73,10 @@ struct ctx_op_data
}; };
typedef struct ctx_op_data *ctx_op_data_t; typedef struct ctx_op_data *ctx_op_data_t;
/* The context defines an environment in which crypto operations can /* The context defines an environment in which crypto operations can
be performed (sequentially). */ * be performed (sequentially). */
struct gpgme_context struct gpgme_context
{ {
DECLARE_LOCK (lock); DECLARE_LOCK (lock);
@ -86,6 +87,11 @@ struct gpgme_context
* freed and reused. */ * freed and reused. */
uint64_t serial; uint64_t serial;
/* A link to the next context. We keep all contex object in the
* linked list to so that we are abale to find a context by its
* serial number. */
gpgme_ctx_t next_ctx;
/* True if the context was canceled asynchronously. */ /* True if the context was canceled asynchronously. */
int canceled; int canceled;
@ -198,5 +204,13 @@ struct gpgme_context
/* Macro to retrieve the serial number. Returns 0 if CTX is NULL. */ /* Macro to retrieve the serial number. Returns 0 if CTX is NULL. */
#define CTXSERIAL(ctx) (ctx? (unsigned long)ctx->serial : 0) #define CTXSERIAL(ctx) (ctx? (unsigned long)ctx->serial : 0)
/*-- gpgme.c --*/
gpg_error_t _gpgme_get_ctx (uint64_t serial, gpgme_ctx_t *r_ctx);
gpgme_error_t _gpgme_cancel_with_err (gpgme_ctx_t ctx, gpg_error_t ctx_err,
gpg_error_t op_err);
#endif /* CONTEXT_H */ #endif /* CONTEXT_H */

View File

@ -1,7 +1,7 @@
/* gpgme.c - GnuPG Made Easy. /* gpgme.c - GnuPG Made Easy.
* Copyright (C) 2000 Werner Koch (dd9jn) * Copyright (C) 2000 Werner Koch (dd9jn)
* Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007, 2012, * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007, 2012,
* 2014, 2015 g10 Code GmbH * 2014, 2015, 2019 g10 Code GmbH
* *
* This file is part of GPGME. * This file is part of GPGME.
* *
@ -42,26 +42,32 @@
#include "mbox-util.h" #include "mbox-util.h"
/* The default locale and its lock. This lock is also used for the /* The lock used to protect access to the default locale, the global
* context serial number. */ * serial counter, and the list of context objects. */
DEFINE_STATIC_LOCK (def_lc_lock); DEFINE_STATIC_LOCK (context_list_lock);
/* The default locale. Access is protected by CONTEXT_LIST_LOCK. */
static char *def_lc_ctype; static char *def_lc_ctype;
static char *def_lc_messages; static char *def_lc_messages;
/* A serial number to identify a context. To make debugging easier by /* A serial number to identify a context. To make debugging easier by
* distinguishing this from the data object s/n we initialize it with * distinguishing this from the data object s/n we initialize it with
* an arbitrary offset. Debug output of this should be done using * an arbitrary offset. Debug output of this should be done using
* decimal notation. Updates are protected by the DEF_LC_LOCK. */ * decimal notation. Updates are protected by CONTEXT_LIST_LOCK. */
static uint64_t last_ctx_serial = 200000; static uint64_t last_ctx_serial = 200000;
/* A linked list of all context objects. Protected by
* CONTEXT_LIST_LOCK. */
static gpgme_ctx_t context_list;
gpgme_error_t _gpgme_selftest = GPG_ERR_NOT_OPERATIONAL; gpgme_error_t _gpgme_selftest = GPG_ERR_NOT_OPERATIONAL;
/* Protects all reference counters in result structures. All other /* Protects all reference counters in result structures. All other
accesses to a result structure are read only. */ * accesses to a result structure are read only. */
DEFINE_STATIC_LOCK (result_ref_lock); DEFINE_STATIC_LOCK (result_ref_lock);
/* Set the global flag NAME to VALUE. Return 0 on success. Note that /* Set the global flag NAME to VALUE. Return 0 on success. Note that
this function does not use gpgme_error and thus a non-zero return this function does not use gpgme_error and thus a non-zero return
@ -131,14 +137,14 @@ gpgme_new (gpgme_ctx_t *r_ctx)
ctx->sub_protocol = GPGME_PROTOCOL_DEFAULT; ctx->sub_protocol = GPGME_PROTOCOL_DEFAULT;
_gpgme_fd_table_init (&ctx->fdt); _gpgme_fd_table_init (&ctx->fdt);
LOCK (def_lc_lock); LOCK (context_list_lock);
if (def_lc_ctype) if (def_lc_ctype)
{ {
ctx->lc_ctype = strdup (def_lc_ctype); ctx->lc_ctype = strdup (def_lc_ctype);
if (!ctx->lc_ctype) if (!ctx->lc_ctype)
{ {
int saved_err = gpg_error_from_syserror (); int saved_err = gpg_error_from_syserror ();
UNLOCK (def_lc_lock); UNLOCK (context_list_lock);
_gpgme_engine_info_release (ctx->engine_info); _gpgme_engine_info_release (ctx->engine_info);
free (ctx); free (ctx);
return TRACE_ERR (saved_err); return TRACE_ERR (saved_err);
@ -153,7 +159,7 @@ gpgme_new (gpgme_ctx_t *r_ctx)
if (!ctx->lc_messages) if (!ctx->lc_messages)
{ {
int saved_err = gpg_error_from_syserror (); int saved_err = gpg_error_from_syserror ();
UNLOCK (def_lc_lock); UNLOCK (context_list_lock);
if (ctx->lc_ctype) if (ctx->lc_ctype)
free (ctx->lc_ctype); free (ctx->lc_ctype);
_gpgme_engine_info_release (ctx->engine_info); _gpgme_engine_info_release (ctx->engine_info);
@ -166,7 +172,11 @@ gpgme_new (gpgme_ctx_t *r_ctx)
ctx->serial = ++last_ctx_serial; ctx->serial = ++last_ctx_serial;
UNLOCK (def_lc_lock); /* Put the object itno a list. */
ctx->next_ctx = context_list;
context_list = ctx;
UNLOCK (context_list_lock);
*r_ctx = ctx; *r_ctx = ctx;
@ -175,6 +185,39 @@ gpgme_new (gpgme_ctx_t *r_ctx)
} }
/* Check the status of the context described by SERIAL.
* Returns:
* 0 - All fine
* GPG_ERR_CANCELED - Context operation has been canceled.
* GPG_ERR_NO_OBJ - Context ist not anymore known.
* If R_CTX is not NULl and the context exists, it is stored there.
*/
gpg_error_t
_gpgme_get_ctx (uint64_t serial, gpgme_ctx_t *r_ctx)
{
gpg_error_t err;
gpgme_ctx_t ctx = NULL;
LOCK (context_list_lock);
for (ctx = context_list; ctx; ctx = ctx->next_ctx)
if (ctx->serial == serial)
break;
UNLOCK (context_list_lock);
if (ctx)
{
/* FIXME: The lock is only used for the canceled flag. We
* should remove it and rely on the global
* context_list_lock. */
LOCK (ctx->lock);
err = ctx->canceled? gpg_error (GPG_ERR_CANCELED) : 0;
UNLOCK (ctx->lock);
}
else
err = gpg_error (GPG_ERR_NO_OBJ);
if (r_ctx)
*r_ctx = ctx;
return err;
}
gpgme_error_t gpgme_error_t
_gpgme_cancel_with_err (gpgme_ctx_t ctx, gpg_error_t ctx_err, _gpgme_cancel_with_err (gpgme_ctx_t ctx, gpg_error_t ctx_err,
gpg_error_t op_err) gpg_error_t op_err)
@ -252,6 +295,26 @@ gpgme_release (gpgme_ctx_t ctx)
if (!ctx) if (!ctx)
return; return;
LOCK (context_list_lock);
if (context_list == ctx)
{
context_list = ctx->next_ctx;
ctx->next_ctx = NULL;
}
else
{
gpgme_ctx_t tmpctx;
for (tmpctx = context_list; tmpctx; tmpctx = tmpctx->next_ctx)
if (tmpctx->next_ctx == ctx)
{
tmpctx->next_ctx = ctx->next_ctx;
ctx->next_ctx = NULL;
break;
}
}
UNLOCK (context_list_lock);
_gpgme_engine_release (ctx->engine); _gpgme_engine_release (ctx->engine);
ctx->engine = NULL; ctx->engine = NULL;
_gpgme_fd_table_deinit (&ctx->fdt); _gpgme_fd_table_deinit (&ctx->fdt);
@ -1054,7 +1117,7 @@ gpgme_set_locale (gpgme_ctx_t ctx, int category, const char *value)
} }
if (!ctx) if (!ctx)
LOCK (def_lc_lock); LOCK (context_list_lock);
#ifdef LC_CTYPE #ifdef LC_CTYPE
SET_ONE_LOCALE (ctype, CTYPE); SET_ONE_LOCALE (ctype, CTYPE);
#endif #endif
@ -1062,7 +1125,7 @@ gpgme_set_locale (gpgme_ctx_t ctx, int category, const char *value)
SET_ONE_LOCALE (messages, MESSAGES); SET_ONE_LOCALE (messages, MESSAGES);
#endif #endif
if (!ctx) if (!ctx)
UNLOCK (def_lc_lock); UNLOCK (context_list_lock);
return TRACE_ERR (0); return TRACE_ERR (0);
} }

View File

@ -26,9 +26,6 @@
#include "context.h" #include "context.h"
/* From gpgme.c. */
gpgme_error_t _gpgme_cancel_with_err (gpgme_ctx_t ctx, gpg_error_t ctx_err,
gpg_error_t op_err);
/* Clear all notation data from the context. */ /* Clear all notation data from the context. */
void _gpgme_sig_notation_clear (gpgme_ctx_t ctx); void _gpgme_sig_notation_clear (gpgme_ctx_t ctx);