2006-12-17 Marcus Brinkmann <marcus@g10code.de>

* configure.ac: Fix two typos in last change.

gpgme/
2006-12-17  Marcus Brinkmann  <marcus@g10code.de>

	* gpgme.c (gpgme_set_protocol): Shut down the engine when
	switching protocols.
	(gpgme_ctx_set_engine_info): Likewise for engine info.
	* engine.h (_gpgme_engine_reset): New function prototype.
	* engine.c (_gpgme_engine_reset): New function.
	* engine-backend.h (struct engine_ops): New member RESET.
	* rungpg.c (_gpgme_engine_ops_gpg): Add NULL for reset function.
	* engine-gpgsm.c (_gpgme_engine_ops_gpgsm)
	[USE_DESCRIPTOR_PASSING]: Add gpgsm_reset for reset.
	(_gpgme_engine_ops_gpgsm) [!USE_DESCRIPTOR_PASSING]: Add NULL for
	reset function.
	(gpgsm_reset) [USE_DESCRIPTOR_PASSING]: New function.
	* op-support.c (_gpgme_op_reset): Try to use the engine's reset
	function if available.
	* engine-gpgsm.c (gpgsm_new): Move code to dup status_fd to ...
	(start): ... here.
	* posix-io.c (_gpgme_io_recvmsg, _gpgme_io_sendmsg): New functions.
This commit is contained in:
Marcus Brinkmann 2006-12-17 21:12:40 +00:00
parent f9bf0d5b79
commit 13d2e5d1c7
14 changed files with 223 additions and 61 deletions

View File

@ -1,3 +1,7 @@
2006-12-17 Marcus Brinkmann <marcus@g10code.de>
* configure.ac: Fix two typos in last change.
2006-12-03 Marcus Brinkmann <marcus@g10code.de> 2006-12-03 Marcus Brinkmann <marcus@g10code.de>
* configure.ac: Use descriptor passing only if --enable-fd-passing * configure.ac: Use descriptor passing only if --enable-fd-passing

2
TODO
View File

@ -78,6 +78,8 @@ Hey Emacs, this is -*- outline -*- mode!
release everything properly at a reset and at an error. Think hard release everything properly at a reset and at an error. Think hard
about where to guarantee what (ie, what happens if start fails, are about where to guarantee what (ie, what happens if start fails, are
the fds unregistered immediately - i think so?) the fds unregistered immediately - i think so?)
Note that we need support in gpgsm to set include-certs to default
as RESET does not reset it.
** Optimize the case where a data object has 0an underlying fd we can pass ** Optimize the case where a data object has 0an underlying fd we can pass
directly to the engine. This will be automatic with socket I/O and directly to the engine. This will be automatic with socket I/O and
descriptor passing. descriptor passing.

View File

@ -75,6 +75,8 @@ int _gpgme_ath_accept (int s, struct sockaddr *addr, socklen_t *length_ptr);
int _gpgme_ath_connect (int s, struct sockaddr *addr, socklen_t length); int _gpgme_ath_connect (int s, struct sockaddr *addr, socklen_t length);
int _gpgme_ath_sendmsg (int s, const struct msghdr *msg, int flags); int _gpgme_ath_sendmsg (int s, const struct msghdr *msg, int flags);
int _gpgme_ath_recvmsg (int s, struct msghdr *msg, int flags); int _gpgme_ath_recvmsg (int s, struct msghdr *msg, int flags);
int _gpgme_io_sendmsg (int sock, const struct msghdr *msg, int flags);
int _gpgme_io_recvmsg (int sock, struct msghdr *msg, int flags);
#endif /*!HAVE_W32_SYSTEM*/ #endif /*!HAVE_W32_SYSTEM*/
#define read _gpgme_io_read #define read _gpgme_io_read
@ -83,8 +85,8 @@ int _gpgme_ath_recvmsg (int s, struct msghdr *msg, int flags);
#define select _gpgme_ath_select #define select _gpgme_ath_select
#define accept _gpgme_ath_accept #define accept _gpgme_ath_accept
#define connect _gpgme_ath_connect #define connect _gpgme_ath_connect
#define sendmsg _gpgme_ath_sendmsg #define sendmsg _gpgme_io_sendmsg
#define recvmsg _gpgme_ath_recvmsg #define recvmsg _gpgme_io_recvmsg
#endif /*_ASSUAN_IN_GPGME_BUILD_ASSUAN*/ #endif /*_ASSUAN_IN_GPGME_BUILD_ASSUAN*/
/**** End GPGME specific modifications. ******/ /**** End GPGME specific modifications. ******/

View File

@ -491,7 +491,7 @@ AC_CHECK_MEMBER(struct cmsghdr.cmsg_len,
AC_ARG_ENABLE(fd-passing, AC_ARG_ENABLE(fd-passing,
AC_HELP_STRING([--enable-fd-passing], [use FD passing if supported]), AC_HELP_STRING([--enable-fd-passing], [use FD passing if supported]),
use_desciptor_passing=$withval) use_descriptor_passing=$enableval)
if test "$supports_descriptor_passing" != "yes"; then if test "$supports_descriptor_passing" != "yes"; then
use_descriptor_passing=no use_descriptor_passing=no

View File

@ -1,5 +1,23 @@
2006-12-17 Marcus Brinkmann <marcus@g10code.de> 2006-12-17 Marcus Brinkmann <marcus@g10code.de>
* gpgme.c (gpgme_set_protocol): Shut down the engine when
switching protocols.
(gpgme_ctx_set_engine_info): Likewise for engine info.
* engine.h (_gpgme_engine_reset): New function prototype.
* engine.c (_gpgme_engine_reset): New function.
* engine-backend.h (struct engine_ops): New member RESET.
* rungpg.c (_gpgme_engine_ops_gpg): Add NULL for reset function.
* engine-gpgsm.c (_gpgme_engine_ops_gpgsm)
[USE_DESCRIPTOR_PASSING]: Add gpgsm_reset for reset.
(_gpgme_engine_ops_gpgsm) [!USE_DESCRIPTOR_PASSING]: Add NULL for
reset function.
(gpgsm_reset) [USE_DESCRIPTOR_PASSING]: New function.
* op-support.c (_gpgme_op_reset): Try to use the engine's reset
function if available.
* engine-gpgsm.c (gpgsm_new): Move code to dup status_fd to ...
(start): ... here.
* posix-io.c (_gpgme_io_recvmsg, _gpgme_io_sendmsg): New functions.
* engine.h (_gpgme_engine_new): Remove arguments lc_ctype and * engine.h (_gpgme_engine_new): Remove arguments lc_ctype and
lc_messages from prototype. lc_messages from prototype.
(_gpgme_engine_set_locale): New prototype. (_gpgme_engine_set_locale): New prototype.

View File

@ -49,6 +49,7 @@ struct engine_ops
/* Member functions. */ /* Member functions. */
void (*release) (void *engine); void (*release) (void *engine);
gpgme_error_t (*reset) (void *engine);
void (*set_status_handler) (void *engine, engine_status_handler_t fnc, void (*set_status_handler) (void *engine, engine_status_handler_t fnc,
void *fnc_value); void *fnc_value);
gpgme_error_t (*set_command_handler) (void *engine, gpgme_error_t (*set_command_handler) (void *engine,

View File

@ -334,15 +334,15 @@ gpgsm_new (void **engine, const char *file_name, const char *home_dir)
char dft_ttyname[64]; char dft_ttyname[64];
char *dft_ttytype = NULL; char *dft_ttytype = NULL;
char *optstr; char *optstr;
int fdlist[5];
int nfds;
gpgsm = calloc (1, sizeof *gpgsm); gpgsm = calloc (1, sizeof *gpgsm);
if (!gpgsm) if (!gpgsm)
return gpg_error_from_errno (errno); return gpg_error_from_errno (errno);
gpgsm->status_cb.fd = -1; gpgsm->status_cb.fd = -1;
gpgsm->status_cb.dir = 1;
gpgsm->status_cb.tag = 0; gpgsm->status_cb.tag = 0;
gpgsm->status_cb.data = gpgsm;
gpgsm->input_cb.fd = -1; gpgsm->input_cb.fd = -1;
gpgsm->input_cb.dir = 0; gpgsm->input_cb.dir = 0;
@ -423,30 +423,6 @@ gpgsm_new (void **engine, const char *file_name, const char *home_dir)
if (err) if (err)
goto leave; goto leave;
/* We need to know the fd used by assuan for reads. We do this by
using the assumption that the first returned fd from
assuan_get_active_fds() is always this one. */
nfds = assuan_get_active_fds (gpgsm->assuan_ctx, 0 /* read fds */,
fdlist, DIM (fdlist));
if (nfds < 1)
{
err = gpg_error (GPG_ERR_GENERAL); /* FIXME */
goto leave;
}
/* We duplicate the file descriptor, so we can close it without
disturbing assuan. Alternatively, we could special case
status_fd and register/unregister it manually as needed, but this
increases code duplication and is more complicated as we can not
use the close notifications etc. */
gpgsm->status_cb.fd = dup (fdlist[0]);
if (gpgsm->status_cb.fd < 0)
{
err = gpg_error (GPG_ERR_GENERAL); /* FIXME */
goto leave;
}
gpgsm->status_cb.dir = 1;
gpgsm->status_cb.data = gpgsm;
err = _gpgme_getenv ("DISPLAY", &dft_display); err = _gpgme_getenv ("DISPLAY", &dft_display);
if (err) if (err)
goto leave; goto leave;
@ -518,14 +494,6 @@ gpgsm_new (void **engine, const char *file_name, const char *home_dir)
} }
} }
if (!err
&& (_gpgme_io_set_close_notify (gpgsm->status_cb.fd,
close_notify_handler, gpgsm)))
{
err = gpg_error (GPG_ERR_GENERAL);
goto leave;
}
#if !USE_DESCRIPTOR_PASSING #if !USE_DESCRIPTOR_PASSING
if (!err if (!err
&& (_gpgme_io_set_close_notify (gpgsm->input_cb.fd, && (_gpgme_io_set_close_notify (gpgsm->input_cb.fd,
@ -997,6 +965,33 @@ static gpgme_error_t
start (engine_gpgsm_t gpgsm, const char *command) start (engine_gpgsm_t gpgsm, const char *command)
{ {
gpgme_error_t err; gpgme_error_t err;
int fdlist[5];
int nfds;
/* We need to know the fd used by assuan for reads. We do this by
using the assumption that the first returned fd from
assuan_get_active_fds() is always this one. */
nfds = assuan_get_active_fds (gpgsm->assuan_ctx, 0 /* read fds */,
fdlist, DIM (fdlist));
if (nfds < 1)
return gpg_error (GPG_ERR_GENERAL); /* FIXME */
/* We duplicate the file descriptor, so we can close it without
disturbing assuan. Alternatively, we could special case
status_fd and register/unregister it manually as needed, but this
increases code duplication and is more complicated as we can not
use the close notifications etc. */
gpgsm->status_cb.fd = dup (fdlist[0]);
if (gpgsm->status_cb.fd < 0)
return gpg_error_from_syserror ();
if (_gpgme_io_set_close_notify (gpgsm->status_cb.fd,
close_notify_handler, gpgsm))
{
close (gpgsm->status_cb.fd);
gpgsm->status_cb.fd = -1;
return gpg_error (GPG_ERR_GENERAL);
}
err = add_io_cb (gpgsm, &gpgsm->status_cb, status_handler); err = add_io_cb (gpgsm, &gpgsm->status_cb, status_handler);
if (!err && gpgsm->input_cb.fd != -1) if (!err && gpgsm->input_cb.fd != -1)
@ -1016,6 +1011,19 @@ start (engine_gpgsm_t gpgsm, const char *command)
} }
#if USE_DESCRIPTOR_PASSING
static gpgme_error_t
gpgsm_reset (void *engine)
{
engine_gpgsm_t gpgsm = engine;
/* We must send a reset because we need to reset the list of
signers. Note that RESET does not reset OPTION commands. */
return gpgsm_assuan_simple_command (gpgsm->assuan_ctx, "RESET", NULL, NULL);
}
#endif
static gpgme_error_t static gpgme_error_t
gpgsm_decrypt (void *engine, gpgme_data_t ciph, gpgme_data_t plain) gpgsm_decrypt (void *engine, gpgme_data_t ciph, gpgme_data_t plain)
{ {
@ -1385,6 +1393,7 @@ gpgsm_keylist (void *engine, const char *pattern, int secret_only,
if (!pattern) if (!pattern)
pattern = ""; pattern = "";
/* Always send list-mode option because RESET does not reset it. */
if (asprintf (&line, "OPTION list-mode=%d", (list_mode & 3)) < 0) if (asprintf (&line, "OPTION list-mode=%d", (list_mode & 3)) < 0)
return gpg_error_from_errno (errno); return gpg_error_from_errno (errno);
err = gpgsm_assuan_simple_command (gpgsm->assuan_ctx, line, NULL, NULL); err = gpgsm_assuan_simple_command (gpgsm->assuan_ctx, line, NULL, NULL);
@ -1393,6 +1402,8 @@ gpgsm_keylist (void *engine, const char *pattern, int secret_only,
return err; return err;
/* Always send key validation because RESET does not reset it. */
/* Use the validation mode if required. We don't check for an error /* Use the validation mode if required. We don't check for an error
yet because this is a pretty fresh gpgsm features. */ yet because this is a pretty fresh gpgsm features. */
gpgsm_assuan_simple_command (gpgsm->assuan_ctx, gpgsm_assuan_simple_command (gpgsm->assuan_ctx,
@ -1448,6 +1459,7 @@ gpgsm_keylist_ext (void *engine, const char *pattern[], int secret_only,
if (mode & GPGME_KEYLIST_MODE_EXTERN) if (mode & GPGME_KEYLIST_MODE_EXTERN)
list_mode |= 2; list_mode |= 2;
/* Always send list-mode option because RESET does not reset it. */
if (asprintf (&line, "OPTION list-mode=%d", (list_mode & 3)) < 0) if (asprintf (&line, "OPTION list-mode=%d", (list_mode & 3)) < 0)
return gpg_error_from_errno (errno); return gpg_error_from_errno (errno);
err = gpgsm_assuan_simple_command (gpgsm->assuan_ctx, line, NULL, NULL); err = gpgsm_assuan_simple_command (gpgsm->assuan_ctx, line, NULL, NULL);
@ -1455,6 +1467,7 @@ gpgsm_keylist_ext (void *engine, const char *pattern[], int secret_only,
if (err) if (err)
return err; return err;
/* Always send key validation because RESET does not reset it. */
/* Use the validation mode if required. We don't check for an error /* Use the validation mode if required. We don't check for an error
yet because this is a pretty fresh gpgsm features. */ yet because this is a pretty fresh gpgsm features. */
gpgsm_assuan_simple_command (gpgsm->assuan_ctx, gpgsm_assuan_simple_command (gpgsm->assuan_ctx,
@ -1561,12 +1574,8 @@ gpgsm_sign (void *engine, gpgme_data_t in, gpgme_data_t out,
if (!gpgsm) if (!gpgsm)
return gpg_error (GPG_ERR_INV_VALUE); return gpg_error (GPG_ERR_INV_VALUE);
/* We must send a reset because we need to reset the list of /* FIXME: This does not work as RESET does not reset it so we can't
signers. Note that RESET does not reset OPTION commands. */ revert back to default. */
err = gpgsm_assuan_simple_command (gpgsm->assuan_ctx, "RESET", NULL, NULL);
if (err)
return err;
if (include_certs != GPGME_INCLUDE_CERTS_DEFAULT) if (include_certs != GPGME_INCLUDE_CERTS_DEFAULT)
{ {
/* FIXME: Make sure that if we run multiple operations, that we /* FIXME: Make sure that if we run multiple operations, that we
@ -1704,6 +1713,11 @@ struct engine_ops _gpgme_engine_ops_gpgsm =
/* Member functions. */ /* Member functions. */
gpgsm_release, gpgsm_release,
#if USE_DESCRIPTOR_PASSING
gpgsm_reset,
#else
NULL, /* reset */
#endif
gpgsm_set_status_handler, gpgsm_set_status_handler,
NULL, /* set_command_handler */ NULL, /* set_command_handler */
gpgsm_set_colon_line_handler, gpgsm_set_colon_line_handler,

View File

@ -420,6 +420,19 @@ _gpgme_engine_new (gpgme_engine_info_t info, engine_t *r_engine)
} }
gpgme_error_t
_gpgme_engine_reset (engine_t engine)
{
if (!engine)
return gpg_error (GPG_ERR_INV_VALUE);
if (!engine->ops->reset)
return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
return (*engine->ops->reset) (engine->engine);
}
void void
_gpgme_engine_release (engine_t engine) _gpgme_engine_release (engine_t engine)
{ {

View File

@ -52,6 +52,7 @@ gpgme_error_t _gpgme_set_engine_info (gpgme_engine_info_t info,
gpgme_error_t _gpgme_engine_new (gpgme_engine_info_t info, gpgme_error_t _gpgme_engine_new (gpgme_engine_info_t info,
engine_t *r_engine); engine_t *r_engine);
gpgme_error_t _gpgme_engine_reset (engine_t engine);
gpgme_error_t _gpgme_engine_set_locale (engine_t engine, int category, gpgme_error_t _gpgme_engine_set_locale (engine_t engine, int category,
const char *value); const char *value);

View File

@ -159,7 +159,17 @@ gpgme_set_protocol (gpgme_ctx_t ctx, gpgme_protocol_t protocol)
if (protocol != GPGME_PROTOCOL_OpenPGP && protocol != GPGME_PROTOCOL_CMS) if (protocol != GPGME_PROTOCOL_OpenPGP && protocol != GPGME_PROTOCOL_CMS)
return gpg_error (GPG_ERR_INV_VALUE); return gpg_error (GPG_ERR_INV_VALUE);
ctx->protocol = protocol; if (ctx->protocol != protocol)
{
/* Shut down the engine when switching protocols. */
if (ctx->engine)
{
_gpgme_engine_release (ctx->engine);
ctx->engine = NULL;
}
ctx->protocol = protocol;
}
return 0; return 0;
} }
@ -417,8 +427,12 @@ gpgme_error_t
gpgme_ctx_set_engine_info (gpgme_ctx_t ctx, gpgme_protocol_t proto, gpgme_ctx_set_engine_info (gpgme_ctx_t ctx, gpgme_protocol_t proto,
const char *file_name, const char *home_dir) const char *file_name, const char *home_dir)
{ {
/* FIXME: Make sure to reset the context if we are running in daemon /* Shut down the engine when changing engine info. */
mode. */ if (ctx->engine)
{
_gpgme_engine_release (ctx->engine);
ctx->engine = NULL;
}
return _gpgme_set_engine_info (ctx->engine_info, proto, return _gpgme_set_engine_info (ctx->engine_info, proto,
file_name, home_dir); file_name, home_dir);
} }

View File

@ -72,7 +72,7 @@ extern "C" {
AM_PATH_GPGME macro) check that this header matches the installed AM_PATH_GPGME macro) check that this header matches the installed
library. Warning: Do not edit the next line. configure will do library. Warning: Do not edit the next line. configure will do
that for you! */ that for you! */
#define GPGME_VERSION "1.1.3-cvs1188" #define GPGME_VERSION "1.1.3-cvs1196"

View File

@ -68,28 +68,37 @@ gpgme_error_t
_gpgme_op_reset (gpgme_ctx_t ctx, int type) _gpgme_op_reset (gpgme_ctx_t ctx, int type)
{ {
gpgme_error_t err = 0; gpgme_error_t err = 0;
gpgme_engine_info_t info;
struct gpgme_io_cbs io_cbs; struct gpgme_io_cbs io_cbs;
info = ctx->engine_info;
while (info && info->protocol != ctx->protocol)
info = info->next;
if (!info)
return gpg_error (GPG_ERR_UNSUPPORTED_PROTOCOL);
_gpgme_release_result (ctx); _gpgme_release_result (ctx);
if (ctx->engine) if (ctx->engine)
{ {
_gpgme_engine_release (ctx->engine); /* Attempt to reset an existing engine. */
ctx->engine = NULL;
err = _gpgme_engine_reset (ctx->engine);
if (gpg_err_code (err) == GPG_ERR_NOT_IMPLEMENTED)
{
_gpgme_engine_release (ctx->engine);
ctx->engine = NULL;
}
} }
/* Create an engine object. */ if (!ctx->engine)
err = _gpgme_engine_new (info, &ctx->engine); {
if (err) gpgme_engine_info_t info;
return err; info = ctx->engine_info;
while (info && info->protocol != ctx->protocol)
info = info->next;
if (!info)
return gpg_error (GPG_ERR_UNSUPPORTED_PROTOCOL);
/* Create an engine object. */
err = _gpgme_engine_new (info, &ctx->engine);
if (err)
return err;
}
err = _gpgme_engine_set_locale (ctx->engine, LC_CTYPE, ctx->lc_ctype); err = _gpgme_engine_set_locale (ctx->engine, LC_CTYPE, ctx->lc_ctype);
if (!err) if (!err)

View File

@ -412,3 +412,86 @@ _gpgme_io_select (struct io_select_fd_s *fds, size_t nfds, int nonblock)
} }
return count; return count;
} }
int
_gpgme_io_recvmsg (int fd, struct msghdr *msg, int flags)
{
int nread;
int saved_errno;
struct iovec *iov;
nread = 0;
iov = msg->msg_iov;
while (iov < msg->msg_iov + msg->msg_iovlen)
{
nread += iov->iov_len;
iov++;
}
DEBUG2 ("fd %d: about to receive %d bytes\n",
fd, (int) nread);
do
{
nread = _gpgme_ath_recvmsg (fd, msg, flags);
}
while (nread == -1 && errno == EINTR);
saved_errno = errno;
DEBUG2 ("fd %d: got %d bytes\n", fd, nread);
if (nread > 0)
{
int nr = nread;
iov = msg->msg_iov;
while (nr > 0)
{
int len = nr > iov->iov_len ? iov->iov_len : nr;
_gpgme_debug (2, "fd %d: got `%.*s'\n", fd, len,
msg->msg_iov->iov_base);
iov++;
nr -= len;
}
}
errno = saved_errno;
return nread;
}
int
_gpgme_io_sendmsg (int fd, const struct msghdr *msg, int flags)
{
int saved_errno;
int nwritten;
struct iovec *iov;
nwritten = 0;
iov = msg->msg_iov;
while (iov < msg->msg_iov + msg->msg_iovlen)
{
nwritten += iov->iov_len;
iov++;
}
DEBUG2 ("fd %d: about to write %d bytes\n", fd, (int) nwritten);
iov = msg->msg_iov;
while (nwritten > 0)
{
int len = nwritten > iov->iov_len ? iov->iov_len : nwritten;
_gpgme_debug (2, "fd %d: write `%.*s'\n", fd, len,
msg->msg_iov->iov_base);
iov++;
nwritten -= len;
}
do
{
nwritten = _gpgme_ath_sendmsg (fd, msg, flags);
}
while (nwritten == -1 && errno == EINTR);
saved_errno = errno;
DEBUG2 ("fd %d: wrote %d bytes\n", fd, (int) nwritten);
errno = saved_errno;
return nwritten;
}

View File

@ -2078,6 +2078,7 @@ struct engine_ops _gpgme_engine_ops_gpg =
/* Member functions. */ /* Member functions. */
gpg_release, gpg_release,
NULL, /* reset */
gpg_set_status_handler, gpg_set_status_handler,
gpg_set_command_handler, gpg_set_command_handler,
gpg_set_colon_line_handler, gpg_set_colon_line_handler,