Blame tests/gpg/t-cancel.c

Packit Service 672cf4
/* t-thread-cancel.c - Regression test.
Packit Service 6c01f9
   Copyright (C) 2000 Werner Koch (dd9jn)
Packit Service 6c01f9
   Copyright (C) 2001, 2003, 2004 g10 Code GmbH
Packit Service 6c01f9
Packit Service 6c01f9
   This file is part of GPGME.
Packit Service 6c01f9
Packit Service 6c01f9
   GPGME is free software; you can redistribute it and/or modify it
Packit Service 6c01f9
   under the terms of the GNU Lesser General Public License as
Packit Service 6c01f9
   published by the Free Software Foundation; either version 2.1 of
Packit Service 6c01f9
   the License, or (at your option) any later version.
Packit Service 6c01f9
Packit Service 6c01f9
   GPGME is distributed in the hope that it will be useful, but
Packit Service 6c01f9
   WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 6c01f9
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 6c01f9
   Lesser General Public License for more details.
Packit Service 6c01f9
Packit Service 6c01f9
   You should have received a copy of the GNU Lesser General Public
Packit Service 6c01f9
   License along with this program; if not, write to the Free Software
Packit Service 6c01f9
   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
Packit Service 6c01f9
   02111-1307, USA.  */
Packit Service 672cf4
Packit Service 672cf4
/* We need to include config.h so that we know whether we are building
Packit Service 672cf4
   with large file system (LFS) support. */
Packit Service 672cf4
#ifdef HAVE_CONFIG_H
Packit Service 672cf4
#include <config.h>
Packit Service 672cf4
#endif
Packit Service 672cf4
Packit Service 672cf4
#include <stdlib.h>
Packit Service 672cf4
#include <stdio.h>
Packit Service 672cf4
#include <string.h>
Packit Service 672cf4
#include <assert.h>
Packit Service 672cf4
#include <limits.h>
Packit Service 672cf4
#include <ctype.h>
Packit Service 672cf4
#include <errno.h>
Packit Service 672cf4
#ifdef HAVE_SYS_TIME_H
Packit Service 672cf4
# include <sys/time.h>
Packit Service 672cf4
#endif
Packit Service 672cf4
#include <sys/types.h>
Packit Service 672cf4
#include <unistd.h>
Packit Service 672cf4
#include <pthread.h>
Packit Service 672cf4
#ifdef HAVE_SYS_SELECT_H
Packit Service 672cf4
# include <sys/select.h>
Packit Service 672cf4
#endif
Packit Service 672cf4
Packit Service 672cf4
#include <gpgme.h>
Packit Service 672cf4
Packit Service 672cf4
#include "t-support.h"
Packit Service 672cf4
Packit Service 672cf4
struct op_result
Packit Service 672cf4
{
Packit Service 672cf4
  int done;
Packit Service 672cf4
  gpgme_error_t err;
Packit Service 672cf4
};
Packit Service 672cf4
Packit Service 672cf4
static struct op_result op_result;
Packit Service 672cf4
Packit Service 672cf4
struct one_fd
Packit Service 672cf4
{
Packit Service 672cf4
  int fd;
Packit Service 672cf4
  int dir;
Packit Service 672cf4
  gpgme_io_cb_t fnc;
Packit Service 672cf4
  void *fnc_data;
Packit Service 672cf4
};
Packit Service 672cf4
Packit Service 672cf4
#define FDLIST_MAX 32
Packit Service 672cf4
static struct one_fd fdlist[FDLIST_MAX];
Packit Service 672cf4
Packit Service 672cf4
static pthread_mutex_t lock;
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
add_io_cb (void *data, int fd, int dir, gpgme_io_cb_t fnc, void *fnc_data,
Packit Service 672cf4
           void **r_tag)
Packit Service 672cf4
{
Packit Service 672cf4
  struct one_fd *fds = data;
Packit Service 672cf4
  int i;
Packit Service 672cf4
Packit Service 672cf4
  pthread_mutex_lock (&lock);
Packit Service 672cf4
  for (i = 0; i < FDLIST_MAX; i++)
Packit Service 672cf4
    {
Packit Service 672cf4
      if (fds[i].fd == -1)
Packit Service 672cf4
        {
Packit Service 672cf4
          fds[i].fd = fd;
Packit Service 672cf4
          fds[i].dir = dir;
Packit Service 672cf4
          fds[i].fnc = fnc;
Packit Service 672cf4
          fds[i].fnc_data = fnc_data;
Packit Service 672cf4
          break;
Packit Service 672cf4
        }
Packit Service 672cf4
    }
Packit Service 672cf4
  pthread_mutex_unlock (&lock);
Packit Service 672cf4
  if (i == FDLIST_MAX)
Packit Service 672cf4
    return gpgme_err_make (GPG_ERR_SOURCE_USER_1, GPG_ERR_GENERAL);
Packit Service 672cf4
  *r_tag = &fds[i];
Packit Service 672cf4
  return 0;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
static void
Packit Service 672cf4
remove_io_cb (void *tag)
Packit Service 672cf4
{
Packit Service 672cf4
  struct one_fd *fd = tag;
Packit Service 672cf4
Packit Service 672cf4
  pthread_mutex_lock (&lock);
Packit Service 672cf4
  fd->fd = -1;
Packit Service 672cf4
  pthread_mutex_unlock (&lock);
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
static void
Packit Service 672cf4
io_event (void *data, gpgme_event_io_t type, void *type_data)
Packit Service 672cf4
{
Packit Service 672cf4
  struct op_result *result = data;
Packit Service 672cf4
Packit Service 672cf4
  if (type == GPGME_EVENT_DONE)
Packit Service 672cf4
    {
Packit Service 672cf4
      result->done = 1;
Packit Service 672cf4
      result->err = * (gpgme_error_t *) type_data;
Packit Service 672cf4
    }
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static int
Packit Service 672cf4
do_select (void)
Packit Service 672cf4
{
Packit Service 672cf4
  fd_set rfds;
Packit Service 672cf4
  fd_set wfds;
Packit Service 672cf4
  int i, n;
Packit Service 672cf4
  int any = 0;
Packit Service 672cf4
  struct timeval tv;
Packit Service 672cf4
Packit Service 672cf4
  pthread_mutex_lock (&lock);
Packit Service 672cf4
  FD_ZERO (&rfds);
Packit Service 672cf4
  FD_ZERO (&wfds);
Packit Service 672cf4
  for (i = 0; i < FDLIST_MAX; i++)
Packit Service 672cf4
    if (fdlist[i].fd != -1)
Packit Service 672cf4
      FD_SET (fdlist[i].fd, fdlist[i].dir ? &rfds : &wfds);
Packit Service 672cf4
  pthread_mutex_unlock (&lock);
Packit Service 672cf4
Packit Service 672cf4
  tv.tv_sec = 0;
Packit Service 672cf4
  tv.tv_usec = 1000;
Packit Service 672cf4
Packit Service 672cf4
  do
Packit Service 672cf4
    {
Packit Service 672cf4
      n = select (FD_SETSIZE, &rfds, &wfds, NULL, &tv;;
Packit Service 672cf4
    }
Packit Service 672cf4
  while (n < 0 && errno == EINTR);
Packit Service 672cf4
Packit Service 672cf4
  if (n < 0)
Packit Service 672cf4
    return n;   /* Error or timeout.  */
Packit Service 672cf4
Packit Service 672cf4
  pthread_mutex_lock (&lock);
Packit Service 672cf4
  for (i = 0; i < FDLIST_MAX && n; i++)
Packit Service 672cf4
    {
Packit Service 672cf4
      if (fdlist[i].fd != -1)
Packit Service 672cf4
        {
Packit Service 672cf4
          if (FD_ISSET (fdlist[i].fd, fdlist[i].dir ? &rfds : &wfds))
Packit Service 672cf4
            {
Packit Service 672cf4
              assert (n);
Packit Service 672cf4
              n--;
Packit Service 672cf4
              any = 1;
Packit Service 672cf4
              (*fdlist[i].fnc) (fdlist[i].fnc_data, fdlist[i].fd);
Packit Service 672cf4
            }
Packit Service 672cf4
        }
Packit Service 672cf4
    }
Packit Service 672cf4
  pthread_mutex_unlock (&lock);
Packit Service 672cf4
  return any;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
static int
Packit Service 672cf4
my_wait (void)
Packit Service 672cf4
{
Packit Service 672cf4
  int n;
Packit Service 672cf4
Packit Service 672cf4
  do
Packit Service 672cf4
    {
Packit Service 672cf4
      n = do_select ();
Packit Service 672cf4
    }
Packit Service 672cf4
  while (n >= 0 && !op_result.done);
Packit Service 672cf4
  return 0;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static struct gpgme_io_cbs io_cbs =
Packit Service 672cf4
  {
Packit Service 672cf4
    add_io_cb,
Packit Service 672cf4
    fdlist,
Packit Service 672cf4
    remove_io_cb,
Packit Service 672cf4
    io_event,
Packit Service 672cf4
    &op_result
Packit Service 672cf4
  };
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static void *
Packit Service 672cf4
thread_cancel (void *data)
Packit Service 672cf4
{
Packit Service 672cf4
  gpgme_ctx_t ctx = data;
Packit Service 672cf4
  gpgme_error_t err;
Packit Service 672cf4
Packit Service 672cf4
  usleep (100000);
Packit Service 672cf4
  err = gpgme_cancel (ctx);
Packit Service 672cf4
  fail_if_err (err);
Packit Service 672cf4
Packit Service 672cf4
  return NULL;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
int
Packit Service 672cf4
main (void)
Packit Service 672cf4
{
Packit Service 672cf4
  gpgme_ctx_t ctx;
Packit Service 672cf4
  gpgme_error_t err;
Packit Service 672cf4
  gpgme_engine_info_t info;
Packit Service 672cf4
  int i;
Packit Service 672cf4
  pthread_mutexattr_t attr;
Packit Service 672cf4
  pthread_t tcancel;
Packit Service 672cf4
  const char *parms = "<GnupgKeyParms format=\"internal\">\n"
Packit Service 672cf4
    "Key-Type: RSA\n"
Packit Service 672cf4
    "Key-Length: 2048\n"
Packit Service 672cf4
    "Subkey-Type: RSA\n"
Packit Service 672cf4
    "Subkey-Length: 2048\n"
Packit Service 672cf4
    "Name-Real: Joe Tester\n"
Packit Service 672cf4
    "Name-Comment: (pp=abc)\n"
Packit Service 672cf4
    "Name-Email: joe@foo.bar\n"
Packit Service 672cf4
    "Expire-Date: 0\n"
Packit Service 672cf4
    "Passphrase: abc\n"
Packit Service 672cf4
    "</GnupgKeyParms>\n";
Packit Service 672cf4
Packit Service 672cf4
  init_gpgme (GPGME_PROTOCOL_OpenPGP);
Packit Service 672cf4
Packit Service 672cf4
  err = gpgme_get_engine_info (&info;;
Packit Service 672cf4
  fail_if_err (err);
Packit Service 672cf4
Packit Service 672cf4
  /* The mutex must be recursive, since remove_io_cb (which acquires a
Packit Service 672cf4
     lock) can be called while holding a lock acquired in do_select.  */
Packit Service 672cf4
  pthread_mutexattr_init (&attr);
Packit Service 672cf4
  pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE);
Packit Service 672cf4
  pthread_mutex_init (&lock, &attr);
Packit Service 672cf4
  pthread_mutexattr_destroy (&attr);
Packit Service 672cf4
Packit Service 672cf4
  for (i = 0; i < FDLIST_MAX; i++)
Packit Service 672cf4
    fdlist[i].fd = -1;
Packit Service 672cf4
Packit Service 672cf4
  err = gpgme_new (&ctx;;
Packit Service 672cf4
  fail_if_err (err);
Packit Service 672cf4
  gpgme_set_armor (ctx, 1);
Packit Service 672cf4
  gpgme_set_io_cbs (ctx, &io_cbs);
Packit Service 672cf4
  op_result.done = 0;
Packit Service 672cf4
Packit Service 672cf4
  pthread_create (&tcancel, NULL, thread_cancel, ctx);
Packit Service 672cf4
Packit Service 672cf4
  err = gpgme_op_genkey_start (ctx, parms, NULL, NULL);
Packit Service 672cf4
  fail_if_err (err);
Packit Service 672cf4
Packit Service 672cf4
  my_wait ();
Packit Service 672cf4
Packit Service 672cf4
  pthread_join (tcancel, NULL);
Packit Service 672cf4
Packit Service 672cf4
  if (op_result.err)
Packit Service 672cf4
    {
Packit Service 672cf4
      if (gpgme_err_code (op_result.err) == GPG_ERR_CANCELED)
Packit Service 672cf4
	fputs ("Successfully cancelled\n", stdout);
Packit Service 672cf4
      else
Packit Service 672cf4
	{
Packit Service 672cf4
	  fprintf (stderr,
Packit Service 672cf4
		   "%s:%i: Operation finished with unexpected error: %s\n",
Packit Service 672cf4
		   __FILE__, __LINE__, gpgme_strerror (op_result.err));
Packit Service 672cf4
	  exit (1);
Packit Service 672cf4
	}
Packit Service 672cf4
    }
Packit Service 672cf4
  else
Packit Service 672cf4
    fputs ("Successfully finished before cancellation\n", stdout);
Packit Service 672cf4
Packit Service 672cf4
  gpgme_release (ctx);
Packit Service 672cf4
Packit Service 672cf4
  return 0;
Packit Service 672cf4
}