core: Replace the posix close notify mechanism by a new generic one.
* src/fdtable.c, src/fdtable.h: New. * src/posix-io.c (notify_table_item_s): Remove. (notify_table, notify_table_size, notify_table_lock): Remove. (_gpgme_io_pipe): Put new fds into the table. (_gpgme_io_dup): Ditto. (_gpgme_io_close): Replace notify stuff by a call to the fdtable. (_gpgme_io_set_close_notify): Remove. Change all callers to to use _gpgme_fdtable_add_close_notify. * src/Makefile.am (main_sources): Add new files. -- This is the first part or a larger change to unify the tracking of file descriptors. Right now this has only been implemented for Posix and thus the code will not yet build for Windows. Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
parent
f6fd90c99a
commit
52d8ed8dfb
@ -74,6 +74,7 @@ main_sources = \
|
|||||||
data-estream.c \
|
data-estream.c \
|
||||||
data-compat.c data-identify.c \
|
data-compat.c data-identify.c \
|
||||||
signers.c sig-notation.c \
|
signers.c sig-notation.c \
|
||||||
|
fdtable.c fdtable.h \
|
||||||
wait.c wait-global.c wait-private.c wait-user.c wait.h \
|
wait.c wait-global.c wait-private.c wait-user.c wait.h \
|
||||||
op-support.c \
|
op-support.c \
|
||||||
encrypt.c encrypt-sign.c decrypt.c decrypt-verify.c verify.c \
|
encrypt.c encrypt-sign.c decrypt.c decrypt-verify.c verify.c \
|
||||||
|
@ -145,7 +145,7 @@ llass_get_req_version (void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static gpg_error_t
|
||||||
close_notify_handler (int fd, void *opaque)
|
close_notify_handler (int fd, void *opaque)
|
||||||
{
|
{
|
||||||
engine_llass_t llass = opaque;
|
engine_llass_t llass = opaque;
|
||||||
@ -158,6 +158,7 @@ close_notify_handler (int fd, void *opaque)
|
|||||||
llass->status_cb.fd = -1;
|
llass->status_cb.fd = -1;
|
||||||
llass->status_cb.tag = NULL;
|
llass->status_cb.tag = NULL;
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -720,8 +721,8 @@ start (engine_llass_t llass, const char *command)
|
|||||||
if (llass->status_cb.fd < 0)
|
if (llass->status_cb.fd < 0)
|
||||||
return gpg_error_from_syserror ();
|
return gpg_error_from_syserror ();
|
||||||
|
|
||||||
if (_gpgme_io_set_close_notify (llass->status_cb.fd,
|
if (_gpgme_fdtable_add_close_notify (llass->status_cb.fd,
|
||||||
close_notify_handler, llass))
|
close_notify_handler, llass))
|
||||||
{
|
{
|
||||||
_gpgme_io_close (llass->status_cb.fd);
|
_gpgme_io_close (llass->status_cb.fd);
|
||||||
llass->status_cb.fd = -1;
|
llass->status_cb.fd = -1;
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#define ENGINE_BACKEND_H
|
#define ENGINE_BACKEND_H
|
||||||
|
|
||||||
#include "engine.h"
|
#include "engine.h"
|
||||||
|
#include "fdtable.h"
|
||||||
|
|
||||||
struct engine_ops
|
struct engine_ops
|
||||||
{
|
{
|
||||||
|
@ -111,7 +111,7 @@ g13_get_req_version (void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static gpg_error_t
|
||||||
close_notify_handler (int fd, void *opaque)
|
close_notify_handler (int fd, void *opaque)
|
||||||
{
|
{
|
||||||
engine_g13_t g13 = opaque;
|
engine_g13_t g13 = opaque;
|
||||||
@ -124,6 +124,7 @@ close_notify_handler (int fd, void *opaque)
|
|||||||
g13->status_cb.fd = -1;
|
g13->status_cb.fd = -1;
|
||||||
g13->status_cb.tag = NULL;
|
g13->status_cb.tag = NULL;
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -686,8 +687,8 @@ start (engine_g13_t g13, const char *command)
|
|||||||
if (g13->status_cb.fd < 0)
|
if (g13->status_cb.fd < 0)
|
||||||
return gpg_error_from_syserror ();
|
return gpg_error_from_syserror ();
|
||||||
|
|
||||||
if (_gpgme_io_set_close_notify (g13->status_cb.fd,
|
if (_gpgme_fdtable_add_close_notify (g13->status_cb.fd,
|
||||||
close_notify_handler, g13))
|
close_notify_handler, g13))
|
||||||
{
|
{
|
||||||
_gpgme_io_close (g13->status_cb.fd);
|
_gpgme_io_close (g13->status_cb.fd);
|
||||||
g13->status_cb.fd = -1;
|
g13->status_cb.fd = -1;
|
||||||
|
@ -173,7 +173,7 @@ gpg_io_event (void *engine, gpgme_event_io_t type, void *type_data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static gpg_error_t
|
||||||
close_notify_handler (int fd, void *opaque)
|
close_notify_handler (int fd, void *opaque)
|
||||||
{
|
{
|
||||||
engine_gpg_t gpg = opaque;
|
engine_gpg_t gpg = opaque;
|
||||||
@ -217,6 +217,7 @@ close_notify_handler (int fd, void *opaque)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If FRONT is true, push at the front of the list. Use this for
|
/* If FRONT is true, push at the front of the list. Use this for
|
||||||
@ -525,10 +526,10 @@ gpg_new (void **engine, const char *file_name, const char *home_dir,
|
|||||||
rc = gpg_error_from_syserror ();
|
rc = gpg_error_from_syserror ();
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
if (_gpgme_io_set_close_notify (gpg->status.fd[0],
|
if (_gpgme_fdtable_add_close_notify (gpg->status.fd[0],
|
||||||
close_notify_handler, gpg)
|
close_notify_handler, gpg)
|
||||||
|| _gpgme_io_set_close_notify (gpg->status.fd[1],
|
|| _gpgme_fdtable_add_close_notify (gpg->status.fd[1],
|
||||||
close_notify_handler, gpg))
|
close_notify_handler, gpg))
|
||||||
{
|
{
|
||||||
rc = gpg_error (GPG_ERR_GENERAL);
|
rc = gpg_error (GPG_ERR_GENERAL);
|
||||||
goto leave;
|
goto leave;
|
||||||
@ -778,9 +779,10 @@ gpg_set_colon_line_handler (void *engine, engine_colon_line_handler_t fnc,
|
|||||||
gpg->colon.buffer = NULL;
|
gpg->colon.buffer = NULL;
|
||||||
return saved_err;
|
return saved_err;
|
||||||
}
|
}
|
||||||
if (_gpgme_io_set_close_notify (gpg->colon.fd[0], close_notify_handler, gpg)
|
if (_gpgme_fdtable_add_close_notify (gpg->colon.fd[0],
|
||||||
|| _gpgme_io_set_close_notify (gpg->colon.fd[1],
|
close_notify_handler, gpg)
|
||||||
close_notify_handler, gpg))
|
|| _gpgme_fdtable_add_close_notify (gpg->colon.fd[1],
|
||||||
|
close_notify_handler, gpg))
|
||||||
return gpg_error (GPG_ERR_GENERAL);
|
return gpg_error (GPG_ERR_GENERAL);
|
||||||
gpg->colon.eof = 0;
|
gpg->colon.eof = 0;
|
||||||
gpg->colon.fnc = fnc;
|
gpg->colon.fnc = fnc;
|
||||||
@ -1112,11 +1114,11 @@ build_argv (engine_gpg_t gpg, const char *pgmname)
|
|||||||
free_argv (argv);
|
free_argv (argv);
|
||||||
return saved_err;
|
return saved_err;
|
||||||
}
|
}
|
||||||
if (_gpgme_io_set_close_notify (fds[0],
|
if (_gpgme_fdtable_add_close_notify (fds[0],
|
||||||
close_notify_handler, gpg)
|
close_notify_handler, gpg)
|
||||||
|| _gpgme_io_set_close_notify (fds[1],
|
|| _gpgme_fdtable_add_close_notify (fds[1],
|
||||||
close_notify_handler,
|
close_notify_handler,
|
||||||
gpg))
|
gpg))
|
||||||
{
|
{
|
||||||
/* We leak fd_data_map and the fds. This is not easy
|
/* We leak fd_data_map and the fds. This is not easy
|
||||||
to avoid and given that we reach this here only
|
to avoid and given that we reach this here only
|
||||||
|
@ -138,11 +138,13 @@ gpgsm_get_req_version (void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static gpg_error_t
|
||||||
close_notify_handler (int fd, void *opaque)
|
close_notify_handler (int fd, void *opaque)
|
||||||
{
|
{
|
||||||
engine_gpgsm_t gpgsm = opaque;
|
engine_gpgsm_t gpgsm = opaque;
|
||||||
|
|
||||||
|
TRACE_BEG (DEBUG_SYSIO, "gpgsm:close_notify_handler", NULL,
|
||||||
|
"fd=%d", fd);
|
||||||
assert (fd != -1);
|
assert (fd != -1);
|
||||||
if (gpgsm->status_cb.fd == fd)
|
if (gpgsm->status_cb.fd == fd)
|
||||||
{
|
{
|
||||||
@ -156,6 +158,7 @@ close_notify_handler (int fd, void *opaque)
|
|||||||
* The status fd however is closed right after it received the
|
* The status fd however is closed right after it received the
|
||||||
* "OK" from the command. So we use this event to also close
|
* "OK" from the command. So we use this event to also close
|
||||||
* the diag fd. */
|
* the diag fd. */
|
||||||
|
TRACE_LOG ("closing diag fd");
|
||||||
_gpgme_io_close (gpgsm->diag_cb.fd);
|
_gpgme_io_close (gpgsm->diag_cb.fd);
|
||||||
}
|
}
|
||||||
else if (gpgsm->input_cb.fd == fd)
|
else if (gpgsm->input_cb.fd == fd)
|
||||||
@ -174,6 +177,7 @@ close_notify_handler (int fd, void *opaque)
|
|||||||
free (gpgsm->input_helper_memory);
|
free (gpgsm->input_helper_memory);
|
||||||
gpgsm->input_helper_memory = NULL;
|
gpgsm->input_helper_memory = NULL;
|
||||||
}
|
}
|
||||||
|
TRACE_LOG ("ready with input_fd");
|
||||||
}
|
}
|
||||||
else if (gpgsm->output_cb.fd == fd)
|
else if (gpgsm->output_cb.fd == fd)
|
||||||
{
|
{
|
||||||
@ -181,6 +185,7 @@ close_notify_handler (int fd, void *opaque)
|
|||||||
(*gpgsm->io_cbs.remove) (gpgsm->output_cb.tag);
|
(*gpgsm->io_cbs.remove) (gpgsm->output_cb.tag);
|
||||||
gpgsm->output_cb.fd = -1;
|
gpgsm->output_cb.fd = -1;
|
||||||
gpgsm->output_cb.tag = NULL;
|
gpgsm->output_cb.tag = NULL;
|
||||||
|
TRACE_LOG ("ready with output_fd");
|
||||||
}
|
}
|
||||||
else if (gpgsm->message_cb.fd == fd)
|
else if (gpgsm->message_cb.fd == fd)
|
||||||
{
|
{
|
||||||
@ -188,6 +193,7 @@ close_notify_handler (int fd, void *opaque)
|
|||||||
(*gpgsm->io_cbs.remove) (gpgsm->message_cb.tag);
|
(*gpgsm->io_cbs.remove) (gpgsm->message_cb.tag);
|
||||||
gpgsm->message_cb.fd = -1;
|
gpgsm->message_cb.fd = -1;
|
||||||
gpgsm->message_cb.tag = NULL;
|
gpgsm->message_cb.tag = NULL;
|
||||||
|
TRACE_LOG ("ready with message_fd");
|
||||||
}
|
}
|
||||||
else if (gpgsm->diag_cb.fd == fd)
|
else if (gpgsm->diag_cb.fd == fd)
|
||||||
{
|
{
|
||||||
@ -195,7 +201,10 @@ close_notify_handler (int fd, void *opaque)
|
|||||||
(*gpgsm->io_cbs.remove) (gpgsm->diag_cb.tag);
|
(*gpgsm->io_cbs.remove) (gpgsm->diag_cb.tag);
|
||||||
gpgsm->diag_cb.fd = -1;
|
gpgsm->diag_cb.fd = -1;
|
||||||
gpgsm->diag_cb.tag = NULL;
|
gpgsm->diag_cb.tag = NULL;
|
||||||
|
TRACE_LOG ("ready with diag_fd");
|
||||||
}
|
}
|
||||||
|
TRACE_SUC ("");
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -544,19 +553,19 @@ gpgsm_new (void **engine, const char *file_name, const char *home_dir,
|
|||||||
|
|
||||||
#if !USE_DESCRIPTOR_PASSING
|
#if !USE_DESCRIPTOR_PASSING
|
||||||
if (!err
|
if (!err
|
||||||
&& (_gpgme_io_set_close_notify (gpgsm->input_cb.fd,
|
&& (_gpgme_fdtable_add_close_notify (gpgsm->input_cb.fd,
|
||||||
close_notify_handler, gpgsm)
|
close_notify_handler, gpgsm)
|
||||||
|| _gpgme_io_set_close_notify (gpgsm->output_cb.fd,
|
|| _gpgme_fdtable_add_close_notify (gpgsm->output_cb.fd,
|
||||||
close_notify_handler, gpgsm)
|
close_notify_handler, gpgsm)
|
||||||
|| _gpgme_io_set_close_notify (gpgsm->message_cb.fd,
|
|| _gpgme_fdtable_add_close_notify (gpgsm->message_cb.fd,
|
||||||
close_notify_handler, gpgsm)))
|
close_notify_handler, gpgsm)))
|
||||||
{
|
{
|
||||||
err = gpg_error (GPG_ERR_GENERAL);
|
err = gpg_error (GPG_ERR_GENERAL);
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (!err && _gpgme_io_set_close_notify (gpgsm->diag_cb.fd,
|
if (!err && _gpgme_fdtable_add_close_notify (gpgsm->diag_cb.fd,
|
||||||
close_notify_handler, gpgsm))
|
close_notify_handler, gpgsm))
|
||||||
{
|
{
|
||||||
err = gpg_error (GPG_ERR_GENERAL);
|
err = gpg_error (GPG_ERR_GENERAL);
|
||||||
goto leave;
|
goto leave;
|
||||||
@ -816,8 +825,8 @@ gpgsm_set_fd (engine_gpgsm_t gpgsm, fd_type_t fd_type, const char *opt)
|
|||||||
iocb_data->fd = dir ? fds[0] : fds[1];
|
iocb_data->fd = dir ? fds[0] : fds[1];
|
||||||
iocb_data->server_fd = dir ? fds[1] : fds[0];
|
iocb_data->server_fd = dir ? fds[1] : fds[0];
|
||||||
|
|
||||||
if (_gpgme_io_set_close_notify (iocb_data->fd,
|
if (_gpgme_fdtable_add_close_notify (iocb_data->fd,
|
||||||
close_notify_handler, gpgsm))
|
close_notify_handler, gpgsm))
|
||||||
{
|
{
|
||||||
err = gpg_error (GPG_ERR_GENERAL);
|
err = gpg_error (GPG_ERR_GENERAL);
|
||||||
goto leave_set_fd;
|
goto leave_set_fd;
|
||||||
@ -1188,8 +1197,8 @@ start (engine_gpgsm_t gpgsm, const char *command)
|
|||||||
if (gpgsm->status_cb.fd < 0)
|
if (gpgsm->status_cb.fd < 0)
|
||||||
return gpg_error_from_syserror ();
|
return gpg_error_from_syserror ();
|
||||||
|
|
||||||
if (_gpgme_io_set_close_notify (gpgsm->status_cb.fd,
|
if (_gpgme_fdtable_add_close_notify (gpgsm->status_cb.fd,
|
||||||
close_notify_handler, gpgsm))
|
close_notify_handler, gpgsm))
|
||||||
{
|
{
|
||||||
_gpgme_io_close (gpgsm->status_cb.fd);
|
_gpgme_io_close (gpgsm->status_cb.fd);
|
||||||
gpgsm->status_cb.fd = -1;
|
gpgsm->status_cb.fd = -1;
|
||||||
|
@ -84,7 +84,7 @@ static gpgme_error_t engspawn_cancel (void *engine);
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
static gpg_error_t
|
||||||
close_notify_handler (int fd, void *opaque)
|
close_notify_handler (int fd, void *opaque)
|
||||||
{
|
{
|
||||||
engine_spawn_t esp = opaque;
|
engine_spawn_t esp = opaque;
|
||||||
@ -110,6 +110,7 @@ close_notify_handler (int fd, void *opaque)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -180,8 +181,10 @@ build_fd_data_map (engine_spawn_t esp)
|
|||||||
esp->fd_data_map = NULL;
|
esp->fd_data_map = NULL;
|
||||||
return gpg_error_from_syserror ();
|
return gpg_error_from_syserror ();
|
||||||
}
|
}
|
||||||
if (_gpgme_io_set_close_notify (fds[0], close_notify_handler, esp)
|
if (_gpgme_fdtable_add_close_notify (fds[0],
|
||||||
|| _gpgme_io_set_close_notify (fds[1], close_notify_handler, esp))
|
close_notify_handler, esp)
|
||||||
|
|| _gpgme_fdtable_add_close_notify (fds[1],
|
||||||
|
close_notify_handler, esp))
|
||||||
{
|
{
|
||||||
/* FIXME: Need error cleanup. */
|
/* FIXME: Need error cleanup. */
|
||||||
return gpg_error (GPG_ERR_GENERAL);
|
return gpg_error (GPG_ERR_GENERAL);
|
||||||
|
@ -135,7 +135,7 @@ uiserver_get_req_version (void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static gpg_error_t
|
||||||
close_notify_handler (int fd, void *opaque)
|
close_notify_handler (int fd, void *opaque)
|
||||||
{
|
{
|
||||||
engine_uiserver_t uiserver = opaque;
|
engine_uiserver_t uiserver = opaque;
|
||||||
@ -179,6 +179,8 @@ close_notify_handler (int fd, void *opaque)
|
|||||||
uiserver->message_cb.fd = -1;
|
uiserver->message_cb.fd = -1;
|
||||||
uiserver->message_cb.tag = NULL;
|
uiserver->message_cb.tag = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -585,8 +587,8 @@ uiserver_set_fd (engine_uiserver_t uiserver, fd_type_t fd_type, const char *opt)
|
|||||||
iocb_data->fd = dir ? fds[0] : fds[1];
|
iocb_data->fd = dir ? fds[0] : fds[1];
|
||||||
iocb_data->server_fd = dir ? fds[1] : fds[0];
|
iocb_data->server_fd = dir ? fds[1] : fds[0];
|
||||||
|
|
||||||
if (_gpgme_io_set_close_notify (iocb_data->fd,
|
if (_gpgme_fdtable_add_close_notify (iocb_data->fd,
|
||||||
close_notify_handler, uiserver))
|
close_notify_handler, uiserver))
|
||||||
{
|
{
|
||||||
err = gpg_error (GPG_ERR_GENERAL);
|
err = gpg_error (GPG_ERR_GENERAL);
|
||||||
goto leave_set_fd;
|
goto leave_set_fd;
|
||||||
@ -921,8 +923,8 @@ start (engine_uiserver_t uiserver, const char *command)
|
|||||||
if (uiserver->status_cb.fd < 0)
|
if (uiserver->status_cb.fd < 0)
|
||||||
return gpg_error_from_syserror ();
|
return gpg_error_from_syserror ();
|
||||||
|
|
||||||
if (_gpgme_io_set_close_notify (uiserver->status_cb.fd,
|
if (_gpgme_fdtable_add_close_notify (uiserver->status_cb.fd,
|
||||||
close_notify_handler, uiserver))
|
close_notify_handler, uiserver))
|
||||||
{
|
{
|
||||||
_gpgme_io_close (uiserver->status_cb.fd);
|
_gpgme_io_close (uiserver->status_cb.fd);
|
||||||
uiserver->status_cb.fd = -1;
|
uiserver->status_cb.fd = -1;
|
||||||
|
205
src/fdtable.c
Normal file
205
src/fdtable.c
Normal file
@ -0,0 +1,205 @@
|
|||||||
|
/* fdtable.c - Keep track of file descriptors.
|
||||||
|
* Copyright (C) 2019 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, see <https://gnu.org/licenses/>.
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if HAVE_CONFIG_H
|
||||||
|
#include <config.h>
|
||||||
|
#endif
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "gpgme.h"
|
||||||
|
#include "debug.h"
|
||||||
|
#include "context.h"
|
||||||
|
#include "fdtable.h"
|
||||||
|
|
||||||
|
|
||||||
|
/* The table to hold information about file descriptors. Currently we
|
||||||
|
* use a linear search and extend the table as needed. Eventually we
|
||||||
|
* may swicth to a hash table and allocate items on the fly. */
|
||||||
|
struct fdtable_item_s
|
||||||
|
{
|
||||||
|
int fd; /* -1 indicates an unused entry. */
|
||||||
|
|
||||||
|
/* The callback to be called before the descriptor is actually closed. */
|
||||||
|
struct {
|
||||||
|
fdtable_handler_t handler;
|
||||||
|
void *value;
|
||||||
|
} close_notify;
|
||||||
|
};
|
||||||
|
typedef struct fdtable_item_s *fdtable_item_t;
|
||||||
|
|
||||||
|
/* The actual table, its size and the lock to guard access. */
|
||||||
|
static fdtable_item_t fdtable;
|
||||||
|
static unsigned int fdtablesize;
|
||||||
|
DEFINE_STATIC_LOCK (fdtable_lock);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Insert FD into our file descriptor table. This function checks
|
||||||
|
* that FD is not yet in the table. On success 0 is returned; if FD
|
||||||
|
* is already in the table GPG_ERR_DUP_KEY is returned. Other error
|
||||||
|
* codes may also be returned. */
|
||||||
|
gpg_error_t
|
||||||
|
_gpgme_fdtable_insert (int fd)
|
||||||
|
{
|
||||||
|
gpg_error_t err;
|
||||||
|
int firstunused, idx;
|
||||||
|
|
||||||
|
TRACE_BEG (DEBUG_SYSIO, __func__, NULL, "fd=%d", fd);
|
||||||
|
|
||||||
|
if (fd < 0 )
|
||||||
|
return TRACE_ERR (gpg_error (GPG_ERR_INV_ARG));
|
||||||
|
|
||||||
|
LOCK (fdtable_lock);
|
||||||
|
|
||||||
|
firstunused = -1;
|
||||||
|
for (idx=0; idx < fdtablesize; idx++)
|
||||||
|
if (fdtable[idx].fd == -1)
|
||||||
|
{
|
||||||
|
if (firstunused == -1)
|
||||||
|
firstunused = idx;
|
||||||
|
}
|
||||||
|
else if (fdtable[idx].fd == fd)
|
||||||
|
{
|
||||||
|
err = gpg_error (GPG_ERR_DUP_KEY);
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (firstunused == -1)
|
||||||
|
{
|
||||||
|
/* We need to increase the size of the table. The approach we
|
||||||
|
* take is straightforward to minimize the risk of bugs. */
|
||||||
|
fdtable_item_t newtbl;
|
||||||
|
size_t newsize = fdtablesize + 64;
|
||||||
|
|
||||||
|
newtbl = calloc (newsize, sizeof *newtbl);
|
||||||
|
if (!newtbl)
|
||||||
|
{
|
||||||
|
err = gpg_error_from_syserror ();
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
for (idx=0; idx < fdtablesize; idx++)
|
||||||
|
newtbl[idx] = fdtable[idx];
|
||||||
|
for (; idx < newsize; idx++)
|
||||||
|
newtbl[idx].fd = -1;
|
||||||
|
|
||||||
|
free (fdtable);
|
||||||
|
fdtable = newtbl;
|
||||||
|
idx = fdtablesize;
|
||||||
|
fdtablesize = newsize;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
idx = firstunused;
|
||||||
|
|
||||||
|
fdtable[idx].fd = fd;
|
||||||
|
fdtable[idx].close_notify.handler = NULL;
|
||||||
|
fdtable[idx].close_notify.value = NULL;
|
||||||
|
err = 0;
|
||||||
|
|
||||||
|
leave:
|
||||||
|
UNLOCK (fdtable_lock);
|
||||||
|
return TRACE_ERR (err);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Add the close notification HANDLER to the table under the key FD.
|
||||||
|
* FD must exist. VALUE is a pointer passed to the handler along with
|
||||||
|
* the FD. */
|
||||||
|
gpg_error_t
|
||||||
|
_gpgme_fdtable_add_close_notify (int fd,
|
||||||
|
fdtable_handler_t handler, void *value)
|
||||||
|
{
|
||||||
|
gpg_error_t err;
|
||||||
|
int idx;
|
||||||
|
|
||||||
|
TRACE_BEG (DEBUG_SYSIO, __func__, NULL, "fd=%d", fd);
|
||||||
|
|
||||||
|
if (fd < 0 )
|
||||||
|
return TRACE_ERR (gpg_error (GPG_ERR_INV_ARG));
|
||||||
|
|
||||||
|
LOCK (fdtable_lock);
|
||||||
|
|
||||||
|
for (idx=0; idx < fdtablesize; idx++)
|
||||||
|
if (fdtable[idx].fd == fd)
|
||||||
|
break;
|
||||||
|
if (idx == fdtablesize)
|
||||||
|
{
|
||||||
|
err = gpg_error (GPG_ERR_NO_KEY);
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fdtable[idx].close_notify.handler)
|
||||||
|
{
|
||||||
|
err = gpg_error (GPG_ERR_DUP_VALUE);
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
fdtable[idx].close_notify.handler = handler;
|
||||||
|
fdtable[idx].close_notify.value = value;
|
||||||
|
err = 0;
|
||||||
|
|
||||||
|
leave:
|
||||||
|
UNLOCK (fdtable_lock);
|
||||||
|
return TRACE_ERR (err);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Remove FD from the table after calling the close handler. Note
|
||||||
|
* that at the time the close handler is called the FD has been
|
||||||
|
* removed form the table. Thus the close handler may not access the
|
||||||
|
* fdtable anymore and assume that FD is still there. Callers may
|
||||||
|
* want to handle the error code GPG_ERR_NO_KEY which indicates that
|
||||||
|
* FD is not anymore or not yet in the table. */
|
||||||
|
gpg_error_t
|
||||||
|
_gpgme_fdtable_remove (int fd)
|
||||||
|
{
|
||||||
|
gpg_error_t err;
|
||||||
|
int idx;
|
||||||
|
fdtable_handler_t handler;
|
||||||
|
void *handlervalue;
|
||||||
|
|
||||||
|
TRACE_BEG (DEBUG_SYSIO, __func__, NULL, "fd=%d", fd);
|
||||||
|
|
||||||
|
if (fd < 0 )
|
||||||
|
return TRACE_ERR (gpg_error (GPG_ERR_INV_ARG));
|
||||||
|
|
||||||
|
LOCK (fdtable_lock);
|
||||||
|
|
||||||
|
for (idx=0; idx < fdtablesize; idx++)
|
||||||
|
if (fdtable[idx].fd == fd)
|
||||||
|
break;
|
||||||
|
if (idx == fdtablesize)
|
||||||
|
{
|
||||||
|
UNLOCK (fdtable_lock);
|
||||||
|
return TRACE_ERR (gpg_error (GPG_ERR_NO_KEY));
|
||||||
|
}
|
||||||
|
|
||||||
|
handler = fdtable[idx].close_notify.handler;
|
||||||
|
fdtable[idx].close_notify.handler = NULL;
|
||||||
|
handlervalue = fdtable[idx].close_notify.value;
|
||||||
|
fdtable[idx].close_notify.value = NULL;
|
||||||
|
fdtable[idx].fd = -1;
|
||||||
|
|
||||||
|
UNLOCK (fdtable_lock);
|
||||||
|
|
||||||
|
err = handler? handler (fd, handlervalue) : 0;
|
||||||
|
|
||||||
|
return TRACE_ERR (err);
|
||||||
|
}
|
43
src/fdtable.h
Normal file
43
src/fdtable.h
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
/* fdtable.h - Keep track of file descriptors.
|
||||||
|
* Copyright (C) 2019 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, see <https://gnu.org/licenses/>.
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef GPGME_FDTABLE_H
|
||||||
|
#define GPGME_FDTABLE_H
|
||||||
|
|
||||||
|
/* The handler type associated with an FD. It is called with the FD
|
||||||
|
* and the registered pointer. The handler may return an error code
|
||||||
|
* but there is no guarantee that this code is used; in particular
|
||||||
|
* errors from close notifications can't inhibit the the closing. */
|
||||||
|
typedef gpg_error_t (*fdtable_handler_t) (int, void*);
|
||||||
|
|
||||||
|
|
||||||
|
/* Insert a new FD into the table. */
|
||||||
|
gpg_error_t _gpgme_fdtable_insert (int fd);
|
||||||
|
|
||||||
|
/* Add a close notification handler to the FD item. */
|
||||||
|
gpg_error_t _gpgme_fdtable_add_close_notify (int fd,
|
||||||
|
fdtable_handler_t handler,
|
||||||
|
void *value);
|
||||||
|
|
||||||
|
/* Remove FD from the table. This also runs the close handlers. */
|
||||||
|
gpg_error_t _gpgme_fdtable_remove (int fd);
|
||||||
|
|
||||||
|
|
||||||
|
#endif /*GPGME_FDTABLE_H*/
|
153
src/posix-io.c
153
src/posix-io.c
@ -59,6 +59,7 @@
|
|||||||
#include "priv-io.h"
|
#include "priv-io.h"
|
||||||
#include "sema.h"
|
#include "sema.h"
|
||||||
#include "ath.h"
|
#include "ath.h"
|
||||||
|
#include "fdtable.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
|
|
||||||
|
|
||||||
@ -152,22 +153,6 @@ _gpgme_io_fd2str (char *buf, int buflen, int fd)
|
|||||||
return snprintf (buf, buflen, "%d", fd);
|
return snprintf (buf, buflen, "%d", fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* The table to hold notification handlers. We use a linear search
|
|
||||||
and extend the table as needed. */
|
|
||||||
struct notify_table_item_s
|
|
||||||
{
|
|
||||||
int fd; /* -1 indicates an unused entry. */
|
|
||||||
_gpgme_close_notify_handler_t handler;
|
|
||||||
void *value;
|
|
||||||
};
|
|
||||||
typedef struct notify_table_item_s *notify_table_item_t;
|
|
||||||
|
|
||||||
static notify_table_item_t notify_table;
|
|
||||||
static size_t notify_table_size;
|
|
||||||
DEFINE_STATIC_LOCK (notify_table_lock);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
_gpgme_io_read (int fd, void *buffer, size_t count)
|
_gpgme_io_read (int fd, void *buffer, size_t count)
|
||||||
@ -208,27 +193,43 @@ _gpgme_io_write (int fd, const void *buffer, size_t count)
|
|||||||
int
|
int
|
||||||
_gpgme_io_pipe (int filedes[2], int inherit_idx)
|
_gpgme_io_pipe (int filedes[2], int inherit_idx)
|
||||||
{
|
{
|
||||||
|
gpg_error_t err;
|
||||||
|
int res;
|
||||||
int saved_errno;
|
int saved_errno;
|
||||||
int err;
|
int i;
|
||||||
TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_pipe", NULL,
|
TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_pipe", NULL,
|
||||||
"inherit_idx=%i (GPGME uses it for %s)",
|
"inherit_idx=%i (GPGME uses it for %s)",
|
||||||
inherit_idx, inherit_idx ? "reading" : "writing");
|
inherit_idx, inherit_idx ? "reading" : "writing");
|
||||||
|
|
||||||
err = pipe (filedes);
|
res = pipe (filedes);
|
||||||
if (err < 0)
|
if (res < 0)
|
||||||
return TRACE_SYSRES (err);
|
return TRACE_SYSRES (res);
|
||||||
|
|
||||||
/* FIXME: Should get the old flags first. */
|
/* FIXME: Should get the old flags first. */
|
||||||
err = fcntl (filedes[1 - inherit_idx], F_SETFD, FD_CLOEXEC);
|
res = fcntl (filedes[1 - inherit_idx], F_SETFD, FD_CLOEXEC);
|
||||||
saved_errno = errno;
|
saved_errno = errno;
|
||||||
if (err < 0)
|
if (res < 0)
|
||||||
{
|
{
|
||||||
close (filedes[0]);
|
close (filedes[0]);
|
||||||
close (filedes[1]);
|
close (filedes[1]);
|
||||||
}
|
}
|
||||||
errno = saved_errno;
|
errno = saved_errno;
|
||||||
if (err)
|
if (res)
|
||||||
return TRACE_SYSRES (err);
|
return TRACE_SYSRES (res);
|
||||||
|
|
||||||
|
for (i=0; i < 2; i++)
|
||||||
|
{
|
||||||
|
err = _gpgme_fdtable_insert (filedes[i]);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
TRACE_LOG ("fdtable_insert failed for fd=%d: %s\n",
|
||||||
|
filedes[i], gpg_strerror (err));
|
||||||
|
close (filedes[0]);
|
||||||
|
close (filedes[1]);
|
||||||
|
gpg_err_set_errno (EIO);
|
||||||
|
return TRACE_SYSRES (-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
TRACE_SUC ("read fd=%d write fd=%d", filedes[0], filedes[1]);
|
TRACE_SUC ("read fd=%d write fd=%d", filedes[0], filedes[1]);
|
||||||
return 0;
|
return 0;
|
||||||
@ -238,38 +239,23 @@ _gpgme_io_pipe (int filedes[2], int inherit_idx)
|
|||||||
int
|
int
|
||||||
_gpgme_io_close (int fd)
|
_gpgme_io_close (int fd)
|
||||||
{
|
{
|
||||||
|
gpg_error_t err;
|
||||||
int res;
|
int res;
|
||||||
_gpgme_close_notify_handler_t handler = NULL;
|
|
||||||
void *handler_value;
|
|
||||||
int idx;
|
|
||||||
|
|
||||||
TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_close", NULL, "fd=%d", fd);
|
TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_close", NULL, "fd=%d", fd);
|
||||||
|
|
||||||
if (fd == -1)
|
if (fd == -1)
|
||||||
{
|
return TRACE_SYSRES (0); /* Igore invalid FDs. */
|
||||||
errno = EINVAL;
|
|
||||||
return TRACE_SYSRES (-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* First call the notify handler. */
|
/* First remove from the table which also runs the close handlers.
|
||||||
LOCK (notify_table_lock);
|
* Having the FD not (yet) in the table is possible and thus we
|
||||||
for (idx=0; idx < notify_table_size; idx++)
|
* ignore that error code. */
|
||||||
|
err = _gpgme_fdtable_remove (fd);
|
||||||
|
if (err && gpg_err_code (err) != GPG_ERR_NO_KEY)
|
||||||
{
|
{
|
||||||
if (notify_table[idx].fd == fd)
|
TRACE_LOG ("fdtable_remove failed for fd=%d: %s\n",
|
||||||
{
|
fd, gpg_strerror (err));
|
||||||
handler = notify_table[idx].handler;
|
gpg_err_set_errno (EINVAL);
|
||||||
handler_value = notify_table[idx].value;
|
return TRACE_SYSRES (-1);
|
||||||
notify_table[idx].handler = NULL;
|
|
||||||
notify_table[idx].value = NULL;
|
|
||||||
notify_table[idx].fd = -1; /* Mark slot as free. */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
UNLOCK (notify_table_lock);
|
|
||||||
if (handler)
|
|
||||||
{
|
|
||||||
TRACE_LOG ("invoking close handler %p/%p", handler, handler_value);
|
|
||||||
handler (fd, handler_value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Then do the close. */
|
/* Then do the close. */
|
||||||
@ -278,59 +264,6 @@ _gpgme_io_close (int fd)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
|
||||||
_gpgme_io_set_close_notify (int fd, _gpgme_close_notify_handler_t handler,
|
|
||||||
void *value)
|
|
||||||
{
|
|
||||||
int res = 0;
|
|
||||||
int idx;
|
|
||||||
|
|
||||||
TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_set_close_notify", NULL,
|
|
||||||
"fd=%d close_handler=%p/%p", fd, handler, value);
|
|
||||||
|
|
||||||
assert (fd != -1);
|
|
||||||
|
|
||||||
LOCK (notify_table_lock);
|
|
||||||
for (idx=0; idx < notify_table_size; idx++)
|
|
||||||
if (notify_table[idx].fd == -1)
|
|
||||||
break;
|
|
||||||
if (idx == notify_table_size)
|
|
||||||
{
|
|
||||||
/* We need to increase the size of the table. The approach we
|
|
||||||
take is straightforward to minimize the risk of bugs. */
|
|
||||||
notify_table_item_t newtbl;
|
|
||||||
size_t newsize = notify_table_size + 64;
|
|
||||||
|
|
||||||
newtbl = calloc (newsize, sizeof *newtbl);
|
|
||||||
if (!newtbl)
|
|
||||||
{
|
|
||||||
res = -1;
|
|
||||||
goto leave;
|
|
||||||
}
|
|
||||||
for (idx=0; idx < notify_table_size; idx++)
|
|
||||||
newtbl[idx] = notify_table[idx];
|
|
||||||
for (; idx < newsize; idx++)
|
|
||||||
{
|
|
||||||
newtbl[idx].fd = -1;
|
|
||||||
newtbl[idx].handler = NULL;
|
|
||||||
newtbl[idx].value = NULL;
|
|
||||||
}
|
|
||||||
free (notify_table);
|
|
||||||
notify_table = newtbl;
|
|
||||||
idx = notify_table_size;
|
|
||||||
notify_table_size = newsize;
|
|
||||||
}
|
|
||||||
notify_table[idx].fd = fd;
|
|
||||||
notify_table[idx].handler = handler;
|
|
||||||
notify_table[idx].value = value;
|
|
||||||
|
|
||||||
leave:
|
|
||||||
UNLOCK (notify_table_lock);
|
|
||||||
|
|
||||||
return TRACE_SYSRES (res);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
_gpgme_io_set_nonblocking (int fd)
|
_gpgme_io_set_nonblocking (int fd)
|
||||||
{
|
{
|
||||||
@ -885,17 +818,29 @@ _gpgme_io_sendmsg (int fd, const struct msghdr *msg, int flags)
|
|||||||
int
|
int
|
||||||
_gpgme_io_dup (int fd)
|
_gpgme_io_dup (int fd)
|
||||||
{
|
{
|
||||||
|
gpg_error_t err;
|
||||||
int new_fd;
|
int new_fd;
|
||||||
|
|
||||||
do
|
do
|
||||||
new_fd = dup (fd);
|
new_fd = dup (fd);
|
||||||
while (new_fd == -1 && errno == EINTR);
|
while (new_fd == -1 && errno == EINTR);
|
||||||
|
|
||||||
TRACE (DEBUG_SYSIO, "_gpgme_io_dup", NULL, "fd=%d -> fd=%d", fd, new_fd);
|
TRACE (DEBUG_SYSIO, __func__, NULL, "fd=%d -> fd=%d", fd, new_fd);
|
||||||
|
err = _gpgme_fdtable_insert (new_fd);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
TRACE (DEBUG_SYSIO, __func__, NULL,
|
||||||
|
"fdtable_insert failed for fd=%d: %s\n",
|
||||||
|
new_fd, gpg_strerror (err));
|
||||||
|
close (new_fd);
|
||||||
|
new_fd = -1;
|
||||||
|
gpg_err_set_errno (EIO);
|
||||||
|
}
|
||||||
|
|
||||||
return new_fd;
|
return new_fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
_gpgme_io_socket (int domain, int type, int proto)
|
_gpgme_io_socket (int domain, int type, int proto)
|
||||||
|
@ -68,9 +68,6 @@ int _gpgme_io_read (int fd, void *buffer, size_t count);
|
|||||||
int _gpgme_io_write (int fd, const void *buffer, size_t count);
|
int _gpgme_io_write (int fd, const void *buffer, size_t count);
|
||||||
int _gpgme_io_pipe (int filedes[2], int inherit_idx);
|
int _gpgme_io_pipe (int filedes[2], int inherit_idx);
|
||||||
int _gpgme_io_close (int fd);
|
int _gpgme_io_close (int fd);
|
||||||
typedef void (*_gpgme_close_notify_handler_t) (int,void*);
|
|
||||||
int _gpgme_io_set_close_notify (int fd, _gpgme_close_notify_handler_t handler,
|
|
||||||
void *value);
|
|
||||||
int _gpgme_io_set_nonblocking (int fd);
|
int _gpgme_io_set_nonblocking (int fd);
|
||||||
|
|
||||||
/* Under Windows do not allocate a console. */
|
/* Under Windows do not allocate a console. */
|
||||||
|
@ -143,7 +143,7 @@ static struct
|
|||||||
/* The context of an associated writer object or NULL. */
|
/* The context of an associated writer object or NULL. */
|
||||||
struct writer_context_s *writer;
|
struct writer_context_s *writer;
|
||||||
|
|
||||||
/* A notification handler. Noet that we current support only one
|
/* A notification handler. Note that we current support only one
|
||||||
* callback per fd. */
|
* callback per fd. */
|
||||||
struct {
|
struct {
|
||||||
_gpgme_close_notify_handler_t handler;
|
_gpgme_close_notify_handler_t handler;
|
||||||
|
Loading…
Reference in New Issue
Block a user