diff options
Diffstat (limited to 'src/wait-private.c')
-rw-r--r-- | src/wait-private.c | 179 |
1 files changed, 179 insertions, 0 deletions
diff --git a/src/wait-private.c b/src/wait-private.c new file mode 100644 index 0000000..c5cbd3c --- /dev/null +++ b/src/wait-private.c @@ -0,0 +1,179 @@ +/* wait-private.c + Copyright (C) 2000 Werner Koch (dd9jn) + Copyright (C) 2001, 2002, 2003, 2004, 2005 g10 Code GmbH + + This file is part of GPGME. + + GPGME is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + GPGME is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#if HAVE_CONFIG_H +#include <config.h> +#endif +#include <assert.h> +#include <errno.h> + +#include "gpgme.h" +#include "context.h" +#include "wait.h" +#include "ops.h" +#include "priv-io.h" +#include "util.h" + + +/* The private event loops are used for all blocking operations, and + for the key and trust item listing operations. They are completely + separated from each other. */ + + +/* Internal I/O callback functions. */ + +/* The add_io_cb and remove_io_cb handlers are shared with the global + event loops. */ + +void +_gpgme_wait_private_event_cb (void *data, gpgme_event_io_t type, + void *type_data) +{ + switch (type) + { + case GPGME_EVENT_START: + /* Nothing to do here, as the wait routine is called after the + initialization is finished. */ + break; + + case GPGME_EVENT_DONE: + break; + + case GPGME_EVENT_NEXT_KEY: + _gpgme_op_keylist_event_cb (data, type, type_data); + break; + + case GPGME_EVENT_NEXT_TRUSTITEM: + _gpgme_op_trustlist_event_cb (data, type, type_data); + break; + } +} + + +/* If COND is a null pointer, wait until the blocking operation in CTX + finished and return its error value. Otherwise, wait until COND is + satisfied or the operation finished. */ +gpgme_error_t +_gpgme_wait_on_condition (gpgme_ctx_t ctx, volatile int *cond, + gpgme_error_t *op_err_p) +{ + gpgme_error_t err = 0; + int hang = 1; + + if (op_err_p) + *op_err_p = 0; + + do + { + int nr = _gpgme_io_select (ctx->fdt.fds, ctx->fdt.size, 0); + unsigned int i; + + if (nr < 0) + { + /* An error occured. Close all fds in this context, and + signal it. */ + err = gpg_error_from_errno (errno); + _gpgme_cancel_with_err (ctx, err, 0); + + return err; + } + + for (i = 0; i < ctx->fdt.size && nr; i++) + { + if (ctx->fdt.fds[i].fd != -1 && ctx->fdt.fds[i].signaled) + { + gpgme_error_t op_err = 0; + + ctx->fdt.fds[i].signaled = 0; + assert (nr); + nr--; + + LOCK (ctx->lock); + if (ctx->canceled) + err = gpg_error (GPG_ERR_CANCELED); + UNLOCK (ctx->lock); + + if (!err) + err = _gpgme_run_io_cb (&ctx->fdt.fds[i], 0, &op_err); + if (err) + { + /* An error occured. Close all fds in this context, + and signal it. */ + _gpgme_cancel_with_err (ctx, err, 0); + + return err; + } + else if (op_err) + { + /* An operational error occured. Cancel the current + operation but not the session, and signal it. */ + _gpgme_cancel_with_err (ctx, 0, op_err); + + /* NOTE: This relies on the operational error being + generated after the operation really has + completed, for example after no further status + line output is generated. Otherwise the + following I/O will spill over into the next + operation. */ + if (op_err_p) + *op_err_p = op_err; + return 0; + } + } + } + + for (i = 0; i < ctx->fdt.size; i++) + if (ctx->fdt.fds[i].fd != -1) + break; + if (i == ctx->fdt.size) + { + struct gpgme_io_event_done_data data; + data.err = 0; + data.op_err = 0; + _gpgme_engine_io_event (ctx->engine, GPGME_EVENT_DONE, &data); + hang = 0; + } + if (cond && *cond) + hang = 0; + } + while (hang); + + return 0; +} + + +/* Wait until the blocking operation in context CTX has finished and + return the error value. This variant can not be used for + session-based protocols. */ +gpgme_error_t +_gpgme_wait_one (gpgme_ctx_t ctx) +{ + return _gpgme_wait_on_condition (ctx, NULL, NULL); +} + +/* Wait until the blocking operation in context CTX has finished and + return the error value. This is the right variant to use for + sesion-based protocols. */ +gpgme_error_t +_gpgme_wait_one_ext (gpgme_ctx_t ctx, gpgme_error_t *op_err) +{ + return _gpgme_wait_on_condition (ctx, NULL, op_err); +} |