diff --git a/src/context.h b/src/context.h index 076d0731..7333d2d5 100644 --- a/src/context.h +++ b/src/context.h @@ -73,9 +73,10 @@ struct ctx_op_data }; typedef struct ctx_op_data *ctx_op_data_t; + /* The context defines an environment in which crypto operations can - be performed (sequentially). */ + * be performed (sequentially). */ struct gpgme_context { DECLARE_LOCK (lock); @@ -86,6 +87,11 @@ struct gpgme_context * freed and reused. */ 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. */ int canceled; @@ -198,5 +204,13 @@ struct gpgme_context /* Macro to retrieve the serial number. Returns 0 if CTX is NULL. */ #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 */ diff --git a/src/gpgme.c b/src/gpgme.c index 53189aa7..283290f4 100644 --- a/src/gpgme.c +++ b/src/gpgme.c @@ -1,7 +1,7 @@ /* gpgme.c - GnuPG Made Easy. * Copyright (C) 2000 Werner Koch (dd9jn) * 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. * @@ -42,26 +42,32 @@ #include "mbox-util.h" -/* The default locale and its lock. This lock is also used for the - * context serial number. */ -DEFINE_STATIC_LOCK (def_lc_lock); +/* The lock used to protect access to the default locale, the global + * serial counter, and the list of context objects. */ +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_messages; /* A serial number to identify a context. To make debugging easier by * distinguishing this from the data object s/n we initialize it with * 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; +/* 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; /* 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); + + /* 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 @@ -131,14 +137,14 @@ gpgme_new (gpgme_ctx_t *r_ctx) ctx->sub_protocol = GPGME_PROTOCOL_DEFAULT; _gpgme_fd_table_init (&ctx->fdt); - LOCK (def_lc_lock); + LOCK (context_list_lock); if (def_lc_ctype) { ctx->lc_ctype = strdup (def_lc_ctype); if (!ctx->lc_ctype) { int saved_err = gpg_error_from_syserror (); - UNLOCK (def_lc_lock); + UNLOCK (context_list_lock); _gpgme_engine_info_release (ctx->engine_info); free (ctx); return TRACE_ERR (saved_err); @@ -153,7 +159,7 @@ gpgme_new (gpgme_ctx_t *r_ctx) if (!ctx->lc_messages) { int saved_err = gpg_error_from_syserror (); - UNLOCK (def_lc_lock); + UNLOCK (context_list_lock); if (ctx->lc_ctype) free (ctx->lc_ctype); _gpgme_engine_info_release (ctx->engine_info); @@ -166,7 +172,11 @@ gpgme_new (gpgme_ctx_t *r_ctx) 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; @@ -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_cancel_with_err (gpgme_ctx_t ctx, gpg_error_t ctx_err, gpg_error_t op_err) @@ -252,6 +295,26 @@ gpgme_release (gpgme_ctx_t ctx) if (!ctx) 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); ctx->engine = NULL; _gpgme_fd_table_deinit (&ctx->fdt); @@ -1054,7 +1117,7 @@ gpgme_set_locale (gpgme_ctx_t ctx, int category, const char *value) } if (!ctx) - LOCK (def_lc_lock); + LOCK (context_list_lock); #ifdef LC_CTYPE SET_ONE_LOCALE (ctype, CTYPE); #endif @@ -1062,7 +1125,7 @@ gpgme_set_locale (gpgme_ctx_t ctx, int category, const char *value) SET_ONE_LOCALE (messages, MESSAGES); #endif if (!ctx) - UNLOCK (def_lc_lock); + UNLOCK (context_list_lock); return TRACE_ERR (0); } diff --git a/src/ops.h b/src/ops.h index 3b9728dd..013b2cd2 100644 --- a/src/ops.h +++ b/src/ops.h @@ -26,9 +26,6 @@ #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. */ void _gpgme_sig_notation_clear (gpgme_ctx_t ctx);