Blame src/wait-private.c

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