Example #1
0
/* The writer does use a simple buffering strategy so that we are
   informed about write errors as soon as possible (i. e. with the the
   next call to the write function.  */
static DWORD CALLBACK 
writer (void *arg)
{
  struct writer_context_s *ctx = arg;
  DWORD nwritten;
  TRACE_BEG1 (DEBUG_SYSIO, "gpgme:writer", ctx->file_hd,
	      "thread=%p", ctx->thread_hd);

  for (;;)
    {
      LOCK (ctx->mutex);
      if (ctx->stop_me)
	{
	  UNLOCK (ctx->mutex);
	  break;
        }
      if (!ctx->nbytes)
	{ 
	  if (!SetEvent (ctx->is_empty))
	    TRACE_LOG1 ("SetEvent failed: ec=%d", (int) GetLastError ());
	  if (!ResetEvent (ctx->have_data))
	    TRACE_LOG1 ("ResetEvent failed: ec=%d", (int) GetLastError ());
	  UNLOCK (ctx->mutex);
	  TRACE_LOG ("idle");
	  WaitForSingleObject (ctx->have_data, INFINITE);
	  TRACE_LOG ("got data to send");
	  LOCK (ctx->mutex);
       	}
      if (ctx->stop_me)
	{
	  UNLOCK (ctx->mutex);
	  break;
        }
      UNLOCK (ctx->mutex);
      
      TRACE_LOG1 ("writing %d bytes", ctx->nbytes);
      /* Note that CTX->nbytes is not zero at this point, because
	 _gpgme_io_write always writes at least 1 byte before waking
	 us up, unless CTX->stop_me is true, which we catch above.  */
      if (!WriteFile (ctx->file_hd, ctx->buffer,
		      ctx->nbytes, &nwritten, NULL))
	{
	  ctx->error_code = (int) GetLastError ();
	  ctx->error = 1;
	  TRACE_LOG1 ("write error: ec=%d", ctx->error_code);
	  break;
	}
      TRACE_LOG1 ("wrote %d bytes", (int) nwritten);
      
      LOCK (ctx->mutex);
      ctx->nbytes -= nwritten;
      UNLOCK (ctx->mutex);
    }
  /* Indicate that we have an error.  */
  if (!SetEvent (ctx->is_empty))
    TRACE_LOG1 ("SetEvent failed: ec=%d", (int) GetLastError ());
  SetEvent (ctx->stopped);

  return TRACE_SUC ();
}
Example #2
0
/* Add KEY to list of signers in CTX.  */
gpgme_error_t
gpgme_signers_add (gpgme_ctx_t ctx, const gpgme_key_t key)
{
  TRACE_BEG2 (DEBUG_CTX, "gpgme_signers_add", ctx,
	      "key=%p (%s)", key, (key->subkeys && key->subkeys->fpr) ?
	      key->subkeys->fpr : "invalid");

  if (!ctx || !key)
    return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));

  if (ctx->signers_len == ctx->signers_size)
    {
      gpgme_key_t *newarr;
      int n = ctx->signers_size + 5;
      int j;

      newarr = realloc (ctx->signers, n * sizeof (*newarr));
      if (!newarr)
	return TRACE_ERR (gpg_error_from_errno (errno));
      for (j = ctx->signers_size; j < n; j++)
	newarr[j] = NULL;
      ctx->signers = newarr;
      ctx->signers_size = n;
    }

  gpgme_key_ref (key);
  ctx->signers[ctx->signers_len++] = key;
  return TRACE_SUC ();
}
Example #3
0
int
_gpgme_io_connect (int fd, struct sockaddr *addr, int addrlen)
{
  int res;

  TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_connect", fd,
	      "addr=%p, addrlen=%i", addr, addrlen);

  res = connect (fd, addr, addrlen);
  if (!res)
    {
      errno = wsa2errno (WSAGetLastError ());
      return TRACE_SYSRES (-1);
    }

  return TRACE_SUC ();
}
Example #4
0
int
_gpgme_io_close (int fd)
{
  TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_close", fd);

  if (fd < 0 || fd >= MAX_SLAFD)
    {
      errno = EBADF;
      return TRACE_SYSRES (-1);
    }

  assert (giochannel_table[fd].used);

  /* First call the notify handler.  */
  if (notify_table[fd].handler)
    {
      notify_table[fd].handler (fd, notify_table[fd].value);
      notify_table[fd].handler = NULL;
      notify_table[fd].value = NULL;
    }

  /* Then do the close.  */
  if (giochannel_table[fd].chan)
    {
      if (giochannel_table[fd].primary)
	g_io_channel_shutdown (giochannel_table[fd].chan, 1, NULL);
      
      g_io_channel_unref (giochannel_table[fd].chan);
    }
  else
    {
      /* Dummy entry, just close.  */
      assert (giochannel_table[fd].fd != -1);
      _close (giochannel_table[fd].fd);
    }
	
  giochannel_table[fd].used = 0;
  giochannel_table[fd].fd = -1;
  giochannel_table[fd].socket = INVALID_SOCKET;
  giochannel_table[fd].chan = NULL;
  giochannel_table[fd].primary = 0;

  TRACE_SUC ();
  return 0;
}
Example #5
0
int
_gpgme_io_connect (int fd, struct sockaddr *addr, int addrlen)
{
  GIOChannel *chan; 
  int sockfd;
  int res;
  GIOFlags flags;
  GIOStatus status;
  GError *err = NULL;

  TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_connect", fd,
	      "addr=%p, addrlen=%i", addr, addrlen);

  chan = find_channel (fd);
  if (! chan)
    {
      errno = EINVAL;
      return TRACE_SYSRES (-1);
    }

  flags = g_io_channel_get_flags (chan);
  if (flags & G_IO_FLAG_NONBLOCK)
    {
      status = g_io_channel_set_flags (chan, flags & ~G_IO_FLAG_NONBLOCK, &err);
      if (err)
	{
	  TRACE_LOG1 ("setting flags error: %s", err->message);
	  g_error_free (err);
	  err = NULL;
	}
      if (status != G_IO_STATUS_NORMAL)
	{
	  errno = EIO;
	  return TRACE_SYSRES (-1);
	}
    }

  sockfd = giochannel_table[fd].socket;
  if (sockfd == INVALID_SOCKET)
    {
      errno = EINVAL;
      return TRACE_SYSRES (-1);
    }

  TRACE_LOG1 ("connect sockfd=0x%x", sockfd);
  res = connect (sockfd, addr, addrlen);

  /* FIXME: Error ignored here.  */
  if (! (flags & G_IO_FLAG_NONBLOCK))
    g_io_channel_set_flags (chan, flags, NULL);

  if (res)
    {
      TRACE_LOG2 ("connect failed: %i %i", res, WSAGetLastError ());

      errno = wsa2errno (WSAGetLastError ());
      return TRACE_SYSRES (-1);
    }

  return TRACE_SUC ();
}
Example #6
0
static struct writer_context_s *
create_writer (HANDLE fd)
{
  struct writer_context_s *ctx;
  SECURITY_ATTRIBUTES sec_attr;
  DWORD tid;

  TRACE_BEG (DEBUG_SYSIO, "gpgme:create_writer", fd);

  memset (&sec_attr, 0, sizeof sec_attr);
  sec_attr.nLength = sizeof sec_attr;
  sec_attr.bInheritHandle = FALSE;

  ctx = calloc (1, sizeof *ctx);
  if (!ctx)
    {
      TRACE_SYSERR (errno);
      return NULL;
    }
  
  ctx->file_hd = fd;
  ctx->refcount = 1;
  ctx->have_data = CreateEvent (&sec_attr, TRUE, FALSE, NULL);
  if (ctx->have_data)
    ctx->is_empty  = CreateEvent (&sec_attr, TRUE, TRUE, NULL);
  if (ctx->is_empty)
    ctx->stopped = CreateEvent (&sec_attr, TRUE, FALSE, NULL);
  if (!ctx->have_data || !ctx->is_empty || !ctx->stopped)
    {
      TRACE_LOG1 ("CreateEvent failed: ec=%d", (int) GetLastError ());
      if (ctx->have_data)
	CloseHandle (ctx->have_data);
      if (ctx->is_empty)
	CloseHandle (ctx->is_empty);
      if (ctx->stopped)
	CloseHandle (ctx->stopped);
      free (ctx);
      /* FIXME: Translate the error code.  */
      TRACE_SYSERR (EIO);
      return NULL;
    }

  ctx->is_empty = set_synchronize (ctx->is_empty);
  INIT_LOCK (ctx->mutex);

  ctx->thread_hd = CreateThread (&sec_attr, 0, writer, ctx, 0, &tid );
  if (!ctx->thread_hd)
    {
      TRACE_LOG1 ("CreateThread failed: ec=%d", (int) GetLastError ());
      DESTROY_LOCK (ctx->mutex);
      if (ctx->have_data)
	CloseHandle (ctx->have_data);
      if (ctx->is_empty)
	CloseHandle (ctx->is_empty);
      if (ctx->stopped)
	CloseHandle (ctx->stopped);
      free (ctx);
      TRACE_SYSERR (EIO);
      return NULL;
    }    
  else
    {
      /* We set the priority of the thread higher because we know
	 that it only runs for a short time.  This greatly helps to
	 increase the performance of the I/O.  */
      SetThreadPriority (ctx->thread_hd, get_desired_thread_priority ());
    }

  TRACE_SUC ();
  return ctx;
}
Example #7
0
static DWORD CALLBACK 
reader (void *arg)
{
  struct reader_context_s *ctx = arg;
  int nbytes;
  DWORD nread;
  TRACE_BEG1 (DEBUG_SYSIO, "gpgme:reader", ctx->file_hd,
	      "thread=%p", ctx->thread_hd);

  for (;;)
    {
      LOCK (ctx->mutex);
      /* Leave a 1 byte gap so that we can see whether it is empty or
	 full.  */
      if ((ctx->writepos + 1) % READBUF_SIZE == ctx->readpos)
	{ 
	  /* Wait for space.  */
	  if (!ResetEvent (ctx->have_space_ev))
	    TRACE_LOG1 ("ResetEvent failed: ec=%d", (int) GetLastError ());
	  UNLOCK (ctx->mutex);
	  TRACE_LOG ("waiting for space");
	  WaitForSingleObject (ctx->have_space_ev, INFINITE);
	  TRACE_LOG ("got space");
	  LOCK (ctx->mutex);
       	}
      if (ctx->stop_me)
	{
	  UNLOCK (ctx->mutex);
	  break;
        }
      nbytes = (ctx->readpos + READBUF_SIZE
		- ctx->writepos - 1) % READBUF_SIZE;
      if (nbytes > READBUF_SIZE - ctx->writepos)
	nbytes = READBUF_SIZE - ctx->writepos;
      UNLOCK (ctx->mutex);
      
      TRACE_LOG1 ("reading %d bytes", nbytes);
      if (!ReadFile (ctx->file_hd,
		     ctx->buffer + ctx->writepos, nbytes, &nread, NULL))
	{
	  ctx->error_code = (int) GetLastError ();
	  if (ctx->error_code == ERROR_BROKEN_PIPE)
	    {
	      ctx->eof = 1;
	      TRACE_LOG ("got EOF (broken pipe)");
            }
	  else
	    {
	      ctx->error = 1;
	      TRACE_LOG1 ("read error: ec=%d", ctx->error_code);
            }
	  break;
        }
      if (!nread)
	{
	  ctx->eof = 1;
	  TRACE_LOG ("got eof");
	  break;
        }
      TRACE_LOG1 ("got %u bytes", nread);
      
      LOCK (ctx->mutex);
      if (ctx->stop_me)
	{
	  UNLOCK (ctx->mutex);
	  break;
        }
      ctx->writepos = (ctx->writepos + nread) % READBUF_SIZE;
      if (!SetEvent (ctx->have_data_ev))
	TRACE_LOG2 ("SetEvent (0x%x) failed: ec=%d", ctx->have_data_ev,
		    (int) GetLastError ());
      UNLOCK (ctx->mutex);
    }
  /* Indicate that we have an error or EOF.  */
  if (!SetEvent (ctx->have_data_ev))
	TRACE_LOG2 ("SetEvent (0x%x) failed: ec=%d", ctx->have_data_ev,
		    (int) GetLastError ());
  SetEvent (ctx->stopped);
  
  return TRACE_SUC ();
}
/* This actually is a int file descriptor (and not assuan_fd_t) as
   _get_osfhandle is called on W32 systems.  */
gpg_error_t
assuan_init_pipe_server (assuan_context_t ctx, assuan_fd_t filedes[2])
{
  const char *s;
  unsigned long ul;
  gpg_error_t rc;
  assuan_fd_t infd = ASSUAN_INVALID_FD;
  assuan_fd_t outfd = ASSUAN_INVALID_FD;
  int is_usd = 0;
  TRACE_BEG (ctx, ASSUAN_LOG_CTX, "assuan_init_pipe_server", ctx);
  if (filedes)
    {
      TRACE_LOG2 ("fd[0]=0x%x, fd[1]=0x%x", filedes[0], filedes[1]);
    }
  
  rc = _assuan_register_std_commands (ctx);
  if (rc)
    return TRACE_ERR (rc);

#ifdef HAVE_W32_SYSTEM
  infd  = filedes[0];
  outfd = filedes[1];
#else
  s = getenv ("_assuan_connection_fd");
  if (s && *s && is_valid_socket (s))
    {
      /* Well, we are called with an bi-directional file descriptor.
	 Prepare for using sendmsg/recvmsg.  In this case we ignore
	 the passed file descriptors. */
      infd = atoi (s);
      outfd = atoi (s);
      is_usd = 1;

    }
  else if (filedes && filedes[0] != ASSUAN_INVALID_FD 
	   && filedes[1] != ASSUAN_INVALID_FD )
    {
      /* Standard pipe server. */
      infd = filedes[0];
      outfd = filedes[1];
    }
  else
    {
      rc = _assuan_error (ctx, GPG_ERR_ASS_SERVER_START);
      return TRACE_ERR (rc);
    }
#endif

  ctx->is_server = 1;
  ctx->engine.release = _assuan_server_release;
  ctx->engine.readfnc = _assuan_simple_read;
  ctx->engine.writefnc = _assuan_simple_write;
  ctx->engine.sendfd = NULL;
  ctx->engine.receivefd = NULL;
  ctx->max_accepts = 1;

  s = getenv ("_assuan_pipe_connect_pid");
  if (s && (ul=strtoul (s, NULL, 10)) && ul)
    ctx->pid = (pid_t)ul;
  else
    ctx->pid = (pid_t)-1;
  ctx->accept_handler = NULL;
  ctx->finish_handler = _assuan_server_finish;
  ctx->inbound.fd = infd;
  ctx->outbound.fd = outfd;

  if (is_usd)
    _assuan_init_uds_io (ctx);

  return TRACE_SUC();
}