[svn] assuan - r199 - in trunk: . src tests
svn author wk
cvs at cvs.gnupg.org
Tue Sep 12 13:07:19 CEST 2006
Author: wk
Date: 2006-09-12 13:07:18 +0200 (Tue, 12 Sep 2006)
New Revision: 199
Added:
trunk/src/assuan-uds.c
Removed:
trunk/src/assuan-domain-connect.c
trunk/src/assuan-domain-server.c
Modified:
trunk/NEWS
trunk/TODO
trunk/src/ChangeLog
trunk/src/Makefile.am
trunk/src/assuan-defs.h
trunk/src/assuan-handler.c
trunk/src/assuan-io.c
trunk/src/assuan-pipe-connect.c
trunk/src/assuan-pipe-server.c
trunk/src/assuan-socket-server.c
trunk/src/assuan.h
trunk/tests/fdpassing.c
Log:
Integrated descriptor passing.
Modified: trunk/NEWS
===================================================================
--- trunk/NEWS 2006-09-11 13:15:48 UTC (rev 198)
+++ trunk/NEWS 2006-09-12 11:07:18 UTC (rev 199)
@@ -17,6 +17,11 @@
printing of the full data, a new environment variable
ASSUAN_FULL_LOGGING may be set to any value.
+ * Removed the assuan_domain fucntions. Added new function
+ assuan_pipe_connect_ext to allow connections on a socketpair and to
+ pass descriptors.
+
+
Noteworthy changes in version 0.6.10 (2005-06-20)
-------------------------------------------------
Modified: trunk/TODO
===================================================================
--- trunk/TODO 2006-09-11 13:15:48 UTC (rev 198)
+++ trunk/TODO 2006-09-12 11:07:18 UTC (rev 199)
@@ -13,3 +13,4 @@
* Check the system error to assuan error translation
* Do a configure test for SO_PEERCRED.
We already use HAVE_SO_PEERCRED buty it never gets defined.
+* Replace assuan_pipe_connect2 by assuan_pipe_connect.
\ No newline at end of file
Modified: trunk/src/ChangeLog
===================================================================
--- trunk/src/ChangeLog 2006-09-11 13:15:48 UTC (rev 198)
+++ trunk/src/ChangeLog 2006-09-12 11:07:18 UTC (rev 199)
@@ -1,3 +1,35 @@
+2006-09-12 Werner Koch <wk at g10code.com>
+
+ * assuan-defs.h (DIM, DIMof): New.
+
+ * assuan-domain-server.c: Removed.
+ * assuan-domain-connect.c: Renamed to ..
+ * assuan-uds.c: this.
+ (domain_reader, domain_writer, domain_sendfd, domain_receivefd)
+ (assuan_domain_connect, _assuan_domain_init): Removed.
+ (uds_reader, uds_writer, uds_sendfd, uds_receivefd)
+ (_assuan_init_uds_io): New.
+ (_assuan_uds_deinit): New.
+
+ * assuan-io.c (_assuan_simple_sendmsg, _assuan_simple_recvmsg): New.
+ (my_pth_fdmode, my_pth_select): New.
+
+2006-09-11 Werner Koch <wk at g10code.com>
+
+ * assuan-pipe-server.c (assuan_init_pipe_server): Allow for
+ FILEDES to be NULL and try to start as a socketpair server in this
+ case.
+
+ * assuan-pipe-connect.c (assuan_pipe_connect2): Split up into two
+ functions (unix and w32) for clarity.
+ (pipe_connect_unix): This is the new fucntion. Add USE_CMSG flag.
+ (pipe_connect_w32): Ditto.
+ (initial_handshake): Factored out code.
+ (socketpair_connect): New.
+ (assuan_pipe_connect_ext): New.
+ (do_finish): Handle case if outbound and inbound fd are the same.
+ This is to support socketpairs.
+
2006-09-10 Werner Koch <wk at g10code.com>
* assuan-util.c (_assuan_log_print_buffer)
Modified: trunk/src/Makefile.am
===================================================================
--- trunk/src/Makefile.am 2006-09-11 13:15:48 UTC (rev 198)
+++ trunk/src/Makefile.am 2006-09-12 11:07:18 UTC (rev 199)
@@ -46,9 +46,8 @@
assuan-socket-server.c \
assuan-pipe-connect.c \
assuan-socket-connect.c \
+ assuan-uds.c \
assuan-io.c \
- assuan-domain-connect.c \
- assuan-domain-server.c \
assuan-logging.c \
assuan-socket.c
Modified: trunk/src/assuan-defs.h
===================================================================
--- trunk/src/assuan-defs.h 2006-09-11 13:15:48 UTC (rev 198)
+++ trunk/src/assuan-defs.h 2006-09-12 11:07:18 UTC (rev 199)
@@ -106,7 +106,7 @@
char *hello_line;
char *okay_line; /* See assuan_set_okay_line() */
- void *user_pointer; /* For assuan_get_pointer and assuan-set_pointer (). */
+ void *user_pointer; /* For assuan_get_pointer and assuan_set_pointer (). */
FILE *log_fp;
@@ -116,7 +116,7 @@
char line[LINELENGTH];
int linelen; /* w/o CR, LF - might not be the same as
strlen(line) due to embedded nuls. However a nul
- is always written at this pos */
+ is always written at this pos. */
struct {
char line[LINELENGTH];
int linelen ;
@@ -135,7 +135,7 @@
} outbound;
int pipe_mode; /* We are in pipe mode, i.e. we can handle just one
- connection and must terminate then */
+ connection and must terminate then. */
pid_t pid; /* The pid of the peer. */
int listen_fd; /* The fd we are listening on (used by socket servers) */
int connected_fd; /* helper */
@@ -144,19 +144,19 @@
/* Used for Unix domain sockets. */
struct sockaddr_un myaddr;
struct sockaddr_un serveraddr;
- /* When reading from datagram sockets, we must read an entire
- message at a time. This means that we have to do our own
- buffering to be able to get the semantics of read. */
- void *domainbuffer;
- /* Offset of start of buffer. */
- int domainbufferoffset;
- /* Bytes buffered. */
- int domainbuffersize;
- /* Memory allocated. */
- int domainbufferallocated;
- int *pendingfds;
- int pendingfdscount;
+ /* Structure used for unix domain socket buffering. FIXME: We don't
+ use datagrams anymore thus we could get away with a simpler
+ buffering approach. */
+ struct {
+ void *buffer; /* Malloced buffer. */
+ int bufferallocated; /* Memory allocated. */
+ int bufferoffset; /* Offset of start of buffer. */
+ int buffersize; /* Bytes buffered. */
+
+ int pendingfds[5]; /* Array to save received descriptors. */
+ int pendingfdscount; /* Number of received descriptors. */
+ } uds;
void (*deinit_handler)(ASSUAN_CONTEXT);
int (*accept_handler)(ASSUAN_CONTEXT);
@@ -184,14 +184,11 @@
int _assuan_new_context (ASSUAN_CONTEXT *r_ctx);
void _assuan_release_context (ASSUAN_CONTEXT ctx);
-/*-- assuan-domain-connect.c --*/
-/* Make a connection to the Unix domain socket NAME and return a new
- Assuan context in CTX. SERVER_PID is currently not used but may
- become handy in the future. */
-assuan_error_t _assuan_domain_init (ASSUAN_CONTEXT *r_ctx,
- int rendezvousfd,
- pid_t peer);
+/*-- assuan-uds.c --*/
+void _assuan_uds_deinit (assuan_context_t ctx);
+void _assuan_init_uds_io (assuan_context_t ctx);
+
/*-- assuan-handler.c --*/
int _assuan_register_std_commands (ASSUAN_CONTEXT ctx);
@@ -259,6 +256,8 @@
ssize_t _assuan_simple_read (ASSUAN_CONTEXT ctx, void *buffer, size_t size);
ssize_t _assuan_simple_write (ASSUAN_CONTEXT ctx, const void *buffer,
size_t size);
+ssize_t _assuan_simple_sendmsg (assuan_context_t ctx, struct msghdr *msg);
+ssize_t _assuan_simple_recvmsg (assuan_context_t ctx, struct msghdr *msg);
/*-- assuan-socket.c --*/
int _assuan_close (int fd);
@@ -290,4 +289,9 @@
int setenv (const char *name, const char *value, int replace);
#endif
+
+#define DIM(v) (sizeof(v)/sizeof((v)[0]))
+#define DIMof(type,member) DIM(((type *)0)->member)
+
+
#endif /*ASSUAN_DEFS_H*/
Deleted: trunk/src/assuan-domain-connect.c
Deleted: trunk/src/assuan-domain-server.c
Modified: trunk/src/assuan-handler.c
===================================================================
--- trunk/src/assuan-handler.c 2006-09-11 13:15:48 UTC (rev 198)
+++ trunk/src/assuan-handler.c 2006-09-12 11:07:18 UTC (rev 199)
@@ -479,7 +479,7 @@
rc = assuan_write_line (ctx, ctx->okay_line? ctx->okay_line : "OK");
}
else if (err_is_eof (rc))
- { /* No error checking because the peer may have already disconnect */
+ { /* No error checking because the peer may have already disconnect. */
assuan_write_line (ctx, "OK closing connection");
ctx->finish_handler (ctx);
}
Modified: trunk/src/assuan-io.c
===================================================================
--- trunk/src/assuan-io.c 2006-09-11 13:15:48 UTC (rev 198)
+++ trunk/src/assuan-io.c 2006-09-12 11:07:18 UTC (rev 199)
@@ -1,5 +1,5 @@
/* assuan-io.c - Wraps the read and write functions.
- * Copyright (C) 2002, 2004 Free Software Foundation, Inc.
+ * Copyright (C) 2002, 2004, 2006 Free Software Foundation, Inc.
*
* This file is part of Assuan.
*
@@ -23,23 +23,69 @@
#include <config.h>
#endif
-#include "assuan-defs.h"
#include <sys/types.h>
+#include <sys/socket.h>
+#if HAVE_SYS_UIO_H
+#include <sys/uio.h>
+#endif
#include <unistd.h>
+#include <errno.h>
#ifdef HAVE_W32_SYSTEM
#include <windows.h>
#endif
+#include "assuan-defs.h"
+
+/* We can't include pth.h and we are not sure whether other headers
+ already included it. This we define macros with the same
+ values. */
+#define MY_PTH_FDMODE_ERROR (-1)
+#define MY_PTH_FDMODE_POLL 0
+#define MY_PTH_FDMODE_BLOCK 1
+#define MY_PTH_FDMODE_NONBLOCK 2
+
+
#ifndef _ASSUAN_NO_PTH
extern ssize_t pth_read (int fd, void *buffer, size_t size);
extern ssize_t pth_write (int fd, const void *buffer, size_t size);
+extern int pth_fdmode (int, int);
+extern int pth_select(int, fd_set*, fd_set*, fd_set*, struct timeval*);
#ifndef HAVE_W32_SYSTEM
#pragma weak pth_read
#pragma weak pth_write
+#pragma weak pth_fdmode
+#pragma weak pth_select
#endif
#endif /*!_ASSUAN_NO_PTH*/
+#ifndef _ASSUAN_NO_PTH
+/* Wrapper around pth_fdmode. */
+static int
+my_pth_fdmode (int fd, int mode)
+{
+ if (pth_fdmode)
+ return pth_fdmode (fd, mode);
+ else
+ return MY_PTH_FDMODE_NONBLOCK; /* This is okay, given the way we use it. */
+}
+#endif /*_ASSUAN_NO_PTH*/
+
+#ifndef _ASSUAN_NO_PTH
+/* Wrapper around pth_select. */
+static int
+my_pth_select (int nfd, fd_set *rfds, fd_set *wfds, fd_set *efds,
+ struct timeval *timeout)
+{
+ if (pth_select)
+ return pth_select (nfd, rfds, wfds, efds, timeout);
+ else
+ return 1; /* Fake one fd ready; this is okay, given the way we use it. */
+}
+#endif /*_ASSUAN_NO_PTH*/
+
+
+
ssize_t
_assuan_simple_read (assuan_context_t ctx, void *buffer, size_t size)
{
@@ -69,3 +115,87 @@
# endif
#endif
}
+
+
+ssize_t
+_assuan_simple_sendmsg (assuan_context_t ctx, struct msghdr *msg)
+{
+#if defined(HAVE_W32_SYSTEM)
+ return _assuan_error (ASSUAN_Not_Implemented);
+#elif defined(_ASSUAN_NO_PTH)
+ int ret;
+ while ( (ret = sendmsg (ctx->outbound.fd, msg, 0)) == -1 && errno == EINTR)
+ ;
+ return ret;
+#else
+ /* Pth does not provide a sendmsg function. Thus we implement it here. */
+ int ret;
+ int fd = ctx->outbound.fd;
+ int fdmode;
+
+ fdmode = my_pth_fdmode (fd, MY_PTH_FDMODE_POLL);
+ if (fdmode == MY_PTH_FDMODE_ERROR)
+ {
+ errno = EBADF;
+ return -1;
+ }
+ if (fdmode == MY_PTH_FDMODE_BLOCK)
+ {
+ fd_set fds;
+
+ FD_ZERO (&fds);
+ FD_SET (fd, &fds);
+ while ( (ret = my_pth_select (fd+1, NULL, &fds, NULL, NULL)) < 0
+ && errno == EINTR)
+ ;
+ if (ret < 0)
+ return -1;
+ }
+
+ while ((ret = sendmsg (fd, msg, 0)) == -1 && errno == EINTR)
+ ;
+ return ret;
+#endif
+}
+
+
+ssize_t
+_assuan_simple_recvmsg (assuan_context_t ctx, struct msghdr *msg)
+{
+#if defined(HAVE_W32_SYSTEM)
+ return _assuan_error (ASSUAN_Not_Implemented);
+#elif defined(_ASSUAN_NO_PTH)
+ int ret;
+ while ( (ret = recvmsg (ctx->inbound.fd, msg, 0)) == -1 && errno == EINTR)
+ ;
+ return ret;
+#else
+ /* Pth does not provide a recvmsg function. Thus we implement it here. */
+ int ret;
+ int fd = ctx->inbound.fd;
+ int fdmode;
+
+ fdmode = my_pth_fdmode (fd, MY_PTH_FDMODE_POLL);
+ if (fdmode == MY_PTH_FDMODE_ERROR)
+ {
+ errno = EBADF;
+ return -1;
+ }
+ if (fdmode == MY_PTH_FDMODE_BLOCK)
+ {
+ fd_set fds;
+
+ FD_ZERO (&fds);
+ FD_SET (fd, &fds);
+ while ( (ret = my_pth_select (fd+1, &fds, NULL, NULL, NULL)) < 0
+ && errno == EINTR)
+ ;
+ if (ret < 0)
+ return -1;
+ }
+
+ while ((ret = recvmsg (fd, msg, 0)) == -1 && errno == EINTR)
+ ;
+ return ret;
+#endif
+}
Modified: trunk/src/assuan-pipe-connect.c
===================================================================
--- trunk/src/assuan-pipe-connect.c 2006-09-11 13:15:48 UTC (rev 198)
+++ trunk/src/assuan-pipe-connect.c 2006-09-12 11:07:18 UTC (rev 199)
@@ -1,5 +1,5 @@
/* assuan-pipe-connect.c - Establish a pipe connection (client)
- * Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc.
+ * Copyright (C) 2001, 2002, 2003, 2005, 2006 Free Software Foundation, Inc.
*
* This file is part of Assuan.
*
@@ -112,6 +112,8 @@
if (ctx->inbound.fd != -1)
{
_assuan_close (ctx->inbound.fd);
+ if (ctx->inbound.fd == ctx->outbound.fd)
+ ctx->outbound.fd = -1;
ctx->inbound.fd = -1;
}
if (ctx->outbound.fd != -1)
@@ -139,6 +141,402 @@
}
+/* Helper for pipe_connect. */
+static assuan_error_t
+initial_handshake (assuan_context_t *ctx)
+{
+ int okay, off;
+ assuan_error_t err;
+
+ err = _assuan_read_from_server (*ctx, &okay, &off);
+ if (err)
+ _assuan_log_printf ("can't connect server: %s\n",
+ assuan_strerror (err));
+ else if (okay != 1)
+ {
+ _assuan_log_printf ("can't connect server: `%s'\n",
+ (*ctx)->inbound.line);
+ err = _assuan_error (ASSUAN_Connect_Failed);
+ }
+
+ if (err)
+ {
+ assuan_disconnect (*ctx);
+ *ctx = NULL;
+ }
+ return err;
+}
+
+
+#ifndef HAVE_W32_SYSTEM
+#define pipe_connect pipe_connect_unix
+/* Unix version of the pipe connection code. We use an extra macro to
+ make ChangeLog entries easier. */
+static assuan_error_t
+pipe_connect_unix (assuan_context_t *ctx,
+ const char *name, const char *const argv[],
+ int *fd_child_list,
+ void (*atfork) (void *opaque, int reserved),
+ void *atforkvalue)
+{
+ assuan_error_t err;
+ int rp[2];
+ int wp[2];
+ char mypidstr[50];
+
+ if (!ctx || !name || !argv || !argv[0])
+ return _assuan_error (ASSUAN_Invalid_Value);
+
+ fix_signals ();
+
+ sprintf (mypidstr, "%lu", (unsigned long)getpid ());
+
+ if (pipe (rp) < 0)
+ return _assuan_error (ASSUAN_General_Error);
+
+ if (pipe (wp) < 0)
+ {
+ close (rp[0]);
+ close (rp[1]);
+ return _assuan_error (ASSUAN_General_Error);
+ }
+
+ err = _assuan_new_context (ctx);
+ if (err)
+ {
+ close (rp[0]);
+ close (rp[1]);
+ close (wp[0]);
+ close (wp[1]);
+ return err;
+ }
+ (*ctx)->pipe_mode = 1;
+ (*ctx)->inbound.fd = rp[0]; /* Our inbound is read end of read pipe. */
+ (*ctx)->outbound.fd = wp[1]; /* Our outbound is write end of write pipe. */
+ (*ctx)->deinit_handler = do_deinit;
+ (*ctx)->finish_handler = do_finish;
+
+ /* FIXME: For GPGME we should better use _gpgme_io_spawn. The PID
+ stored here is actually soon useless. */
+ (*ctx)->pid = fork ();
+ if ((*ctx)->pid < 0)
+ {
+ close (rp[0]);
+ close (rp[1]);
+ close (wp[0]);
+ close (wp[1]);
+ _assuan_release_context (*ctx);
+ return _assuan_error (ASSUAN_General_Error);
+ }
+
+ if ((*ctx)->pid == 0)
+ {
+#ifdef _ASSUAN_USE_DOUBLE_FORK
+ pid_t pid;
+
+ if ((pid = fork ()) == 0)
+#endif
+ {
+ int i, n;
+ char errbuf[512];
+ int *fdp;
+
+ if (atfork)
+ atfork (atforkvalue, 0);
+
+ /* Dup handles to stdin/stdout. */
+ if (rp[1] != STDOUT_FILENO)
+ {
+ if (dup2 (rp[1], STDOUT_FILENO) == -1)
+ {
+ _assuan_log_printf ("dup2 failed in child: %s\n",
+ strerror (errno));
+ _exit (4);
+ }
+ }
+ if (wp[0] != STDIN_FILENO)
+ {
+ if (dup2 (wp[0], STDIN_FILENO) == -1)
+ {
+ _assuan_log_printf ("dup2 failed in child: %s\n",
+ strerror (errno));
+ _exit (4);
+ }
+ }
+
+ /* Dup stderr to /dev/null unless it is in the list of FDs to be
+ passed to the child. */
+ fdp = fd_child_list;
+ if (fdp)
+ {
+ for (; *fdp != -1 && *fdp != STDERR_FILENO; fdp++)
+ ;
+ }
+ if (!fdp || *fdp == -1)
+ {
+ int fd = open ("/dev/null", O_WRONLY);
+ if (fd == -1)
+ {
+ _assuan_log_printf ("can't open `/dev/null': %s\n",
+ strerror (errno));
+ _exit (4);
+ }
+ if (dup2 (fd, STDERR_FILENO) == -1)
+ {
+ _assuan_log_printf ("dup2(dev/null, 2) failed: %s\n",
+ strerror (errno));
+ _exit (4);
+ }
+ }
+
+
+ /* Close all files which will not be duped and are not in the
+ fd_child_list. */
+ n = sysconf (_SC_OPEN_MAX);
+ if (n < 0)
+ n = MAX_OPEN_FDS;
+ for (i=0; i < n; i++)
+ {
+ if ( i == STDIN_FILENO || i == STDOUT_FILENO
+ || i == STDERR_FILENO)
+ continue;
+ fdp = fd_child_list;
+ if (fdp)
+ {
+ while (*fdp != -1 && *fdp != i)
+ fdp++;
+ }
+
+ if (!(fdp && *fdp != -1))
+ close(i);
+ }
+ errno = 0;
+
+ /* We store our parents pid in the environment so that the
+ execed assuan server is able to read the actual pid of the
+ client. The server can't use getppid because it might have
+ been double forked before the assuan server has been
+ initialized. */
+ setenv ("_assuan_pipe_connect_pid", mypidstr, 1);
+
+ /* Make sure that we never pass a connection fd variable
+ when using a simple pipe. */
+ unsetenv ("_assuan_connection_fd");
+
+ execv (name, (char *const *) argv);
+ /* oops - use the pipe to tell the parent about it */
+ snprintf (errbuf, sizeof(errbuf)-1,
+ "ERR %d can't exec `%s': %.50s\n",
+ _assuan_error (ASSUAN_Problem_Starting_Server),
+ name, strerror (errno));
+ errbuf[sizeof(errbuf)-1] = 0;
+ writen (1, errbuf, strlen (errbuf));
+ _exit (4);
+ }
+#ifdef _ASSUAN_USE_DOUBLE_FORK
+ if (pid == -1)
+ _exit (1);
+ else
+ _exit (0);
+#endif
+ }
+
+#ifdef _ASSUAN_USE_DOUBLE_FORK
+ waitpid ((*ctx)->pid, NULL, 0);
+ (*ctx)->pid = -1;
+#endif
+
+ close (rp[1]);
+ close (wp[0]);
+
+ return initial_handshake (ctx);
+}
+#endif /*!HAVE_W32_SYSTEM*/
+
+
+#ifndef HAVE_W32_SYSTEM
+/* This function is similar to pipe_connect but uses a socketpair and
+ sets the I/O up to use sendmsg/recvmsg. */
+static assuan_error_t
+socketpair_connect (assuan_context_t *ctx,
+ const char *name, const char *const argv[],
+ int *fd_child_list,
+ void (*atfork) (void *opaque, int reserved),
+ void *atforkvalue)
+{
+ assuan_error_t err;
+ int fds[2];
+ char mypidstr[50];
+
+ if (!ctx
+ || (name && (!argv || !argv[0]))
+ || (!name && argv))
+ return _assuan_error (ASSUAN_Invalid_Value);
+
+ fix_signals ();
+
+ sprintf (mypidstr, "%lu", (unsigned long)getpid ());
+
+ if ( socketpair (AF_LOCAL, SOCK_STREAM, 0, fds) )
+ {
+ _assuan_log_printf ("socketpair failed: %s\n", strerror (errno));
+ return _assuan_error (ASSUAN_General_Error);
+ }
+
+ err = _assuan_new_context (ctx);
+ if (err)
+ {
+ close (fds[0]);
+ close (fds[1]);
+ return err;
+ }
+ (*ctx)->pipe_mode = 1;
+ (*ctx)->inbound.fd = fds[0];
+ (*ctx)->outbound.fd = fds[0];
+ _assuan_init_uds_io (*ctx);
+ (*ctx)->deinit_handler = _assuan_uds_deinit;
+ (*ctx)->finish_handler = do_finish;
+
+ (*ctx)->pid = fork ();
+ if ((*ctx)->pid < 0)
+ {
+ close (fds[0]);
+ close (fds[1]);
+ _assuan_release_context (*ctx);
+ *ctx = NULL;
+ return _assuan_error (ASSUAN_General_Error);
+ }
+
+ if ((*ctx)->pid == 0)
+ {
+#ifdef _ASSUAN_USE_DOUBLE_FORK
+ pid_t pid;
+
+ if ((pid = fork ()) == 0)
+#endif
+ {
+ int fd, i, n;
+ char errbuf[512];
+ int *fdp;
+
+ if (atfork)
+ atfork (atforkvalue, 0);
+
+ /* Connect stdin and stdout to /dev/null. */
+ fd = open ("/dev/null", O_RDONLY);
+ if (fd == -1 || dup2 (fd, STDIN_FILENO) == -1)
+ {
+ _assuan_log_printf ("dup2(dev/null) failed: %s\n",
+ strerror (errno));
+ _exit (4);
+ }
+ fd = open ("/dev/null", O_WRONLY);
+ if (fd == -1 || dup2 (fd, STDOUT_FILENO) == -1)
+ {
+ _assuan_log_printf ("dup2(dev/null) failed: %s\n",
+ strerror (errno));
+ _exit (4);
+ }
+
+ /* Dup stderr to /dev/null unless it is in the list of FDs to be
+ passed to the child. */
+ fdp = fd_child_list;
+ if (fdp)
+ {
+ for (; *fdp != -1 && *fdp != STDERR_FILENO; fdp++)
+ ;
+ }
+ if (!fdp || *fdp == -1)
+ {
+ fd = open ("/dev/null", O_WRONLY);
+ if (fd == -1 || dup2 (fd, STDERR_FILENO) == -1)
+ {
+ _assuan_log_printf ("dup2(dev/null) failed: %s\n",
+ strerror (errno));
+ _exit (4);
+ }
+ }
+
+
+ /* Close all files which will not be duped, are not in the
+ fd_child_list and are not the connection fd. */
+ n = sysconf (_SC_OPEN_MAX);
+ if (n < 0)
+ n = MAX_OPEN_FDS;
+ for (i=0; i < n; i++)
+ {
+ if ( i == STDIN_FILENO || i == STDOUT_FILENO
+ || i == STDERR_FILENO || i == fds[1])
+ continue;
+ fdp = fd_child_list;
+ if (fdp)
+ {
+ while (*fdp != -1 && *fdp != i)
+ fdp++;
+ }
+
+ if (!(fdp && *fdp != -1))
+ close(i);
+ }
+ errno = 0;
+
+ /* We store our parents pid in the environment so that the
+ execed assuan server is able to read the actual pid of the
+ client. The server can't use getppid becuase it might have
+ been double forked before the assuan server has been
+ initialized. */
+ setenv ("_assuan_pipe_connect_pid", mypidstr, 1);
+
+ /* Now set the environment variable used to convey the
+ connection's file descriptor. */
+ sprintf (mypidstr, "%d", fds[1]);
+ if (setenv ("_assuan_connection_fd", mypidstr, 1))
+ {
+ _assuan_log_printf ("setenv failed: %s\n", strerror (errno));
+ _exit (4);
+ }
+
+ if (!name && !argv)
+ {
+ /* No name and no args given, thus we don't do an exec
+ but continue the forked process. */
+ _assuan_release_context (*ctx);
+ *ctx = NULL;
+ return 0;
+ }
+
+ execv (name, (char *const *) argv);
+ /* oops - use the pipe to tell the parent about it */
+ snprintf (errbuf, sizeof(errbuf)-1,
+ "ERR %d can't exec `%s': %.50s\n",
+ _assuan_error (ASSUAN_Problem_Starting_Server),
+ name, strerror (errno));
+ errbuf[sizeof(errbuf)-1] = 0;
+ writen (1, errbuf, strlen (errbuf));
+ _exit (4);
+ }
+#ifdef _ASSUAN_USE_DOUBLE_FORK
+ if (pid == -1)
+ _exit (1);
+ else
+ _exit (0);
+#endif
+ }
+
+
+#ifdef _ASSUAN_USE_DOUBLE_FORK
+ waitpid ((*ctx)->pid, NULL, 0);
+ (*ctx)->pid = -1;
+#endif
+
+ close (fds[1]);
+
+ return initial_handshake (ctx);
+}
+#endif /*!HAVE_W32_SYSTEM*/
+
+
+
#ifdef HAVE_W32_SYSTEM
/* Build a command line for use with W32's CreateProcess. On success
CMDLINE gets the address of a newly allocated string. */
@@ -237,21 +635,16 @@
#endif /*HAVE_W32_SYSTEM*/
-/* Connect to a server over a pipe, creating the assuan context and
- returning it in CTX. The server filename is NAME, the argument
- vector in ARGV. FD_CHILD_LIST is a -1 terminated list of file
- descriptors not to close in the child. ATFORK is called in the
- child right after the fork; ATFORKVALUE is passed as the first
- argument and 0 is passed as the second argument. The ATFORK
- function should only act if the second value is 0. */
-assuan_error_t
-assuan_pipe_connect2 (assuan_context_t *ctx,
- const char *name, const char *const argv[],
- int *fd_child_list,
- void (*atfork) (void *opaque, int reserved),
- void *atforkvalue)
+#ifdef HAVE_W32_SYSTEM
+#define pipe_connect pipe_connect_w32
+/* W32 version of the pipe connection code. */
+static assuan_error_t
+pipe_connect_w32 (assuan_context_t *ctx,
+ const char *name, const char *const argv[],
+ int *fd_child_list,
+ void (*atfork) (void *opaque, int reserved),
+ void *atforkvalue)
{
-#ifdef HAVE_W32_SYSTEM
assuan_error_t err;
int rp[2];
int wp[2];
@@ -414,201 +807,11 @@
(*ctx)->pid = 0; /* We don't use the PID. */
CloseHandle (pi.hProcess); /* We don't need to wait for the process. */
-#else /*!HAVE_W32_SYSTEM*/
- assuan_error_t err;
- int rp[2];
- int wp[2];
- char mypidstr[50];
-
- if (!ctx || !name || !argv || !argv[0])
- return _assuan_error (ASSUAN_Invalid_Value);
-
- fix_signals ();
-
- sprintf (mypidstr, "%lu", (unsigned long)getpid ());
-
- if (pipe (rp) < 0)
- return _assuan_error (ASSUAN_General_Error);
-
- if (pipe (wp) < 0)
- {
- close (rp[0]);
- close (rp[1]);
- return _assuan_error (ASSUAN_General_Error);
- }
-
- err = _assuan_new_context (ctx);
- if (err)
- {
- close (rp[0]);
- close (rp[1]);
- close (wp[0]);
- close (wp[1]);
- return err;
- }
- (*ctx)->pipe_mode = 1;
- (*ctx)->inbound.fd = rp[0]; /* Our inbound is read end of read pipe. */
- (*ctx)->outbound.fd = wp[1]; /* Our outbound is write end of write pipe. */
- (*ctx)->deinit_handler = do_deinit;
- (*ctx)->finish_handler = do_finish;
-
- /* FIXME: For GPGME we should better use _gpgme_io_spawn. The PID
- stored here is actually soon useless. */
- (*ctx)->pid = fork ();
- if ((*ctx)->pid < 0)
- {
- close (rp[0]);
- close (rp[1]);
- close (wp[0]);
- close (wp[1]);
- _assuan_release_context (*ctx);
- return _assuan_error (ASSUAN_General_Error);
- }
-
- if ((*ctx)->pid == 0)
- {
-#ifdef _ASSUAN_USE_DOUBLE_FORK
- pid_t pid;
-
- if ((pid = fork ()) == 0)
-#endif
- {
- int i, n;
- char errbuf[512];
- int *fdp;
-
- if (atfork)
- atfork (atforkvalue, 0);
-
- /* Dup handles to stdin/stdout. */
- if (rp[1] != STDOUT_FILENO)
- {
- if (dup2 (rp[1], STDOUT_FILENO) == -1)
- {
- _assuan_log_printf ("dup2 failed in child: %s\n",
- strerror (errno));
- _exit (4);
- }
- }
- if (wp[0] != STDIN_FILENO)
- {
- if (dup2 (wp[0], STDIN_FILENO) == -1)
- {
- _assuan_log_printf ("dup2 failed in child: %s\n",
- strerror (errno));
- _exit (4);
- }
- }
-
- /* Dup stderr to /dev/null unless it is in the list of FDs to be
- passed to the child. */
- fdp = fd_child_list;
- if (fdp)
- {
- for (; *fdp != -1 && *fdp != STDERR_FILENO; fdp++)
- ;
- }
- if (!fdp || *fdp == -1)
- {
- int fd = open ("/dev/null", O_WRONLY);
- if (fd == -1)
- {
- _assuan_log_printf ("can't open `/dev/null': %s\n",
- strerror (errno));
- _exit (4);
- }
- if (dup2 (fd, STDERR_FILENO) == -1)
- {
- _assuan_log_printf ("dup2(dev/null, 2) failed: %s\n",
- strerror (errno));
- _exit (4);
- }
- }
-
-
- /* Close all files which will not be duped and are not in the
- fd_child_list. */
- n = sysconf (_SC_OPEN_MAX);
- if (n < 0)
- n = MAX_OPEN_FDS;
- for (i=0; i < n; i++)
- {
- if ( i == STDIN_FILENO || i == STDOUT_FILENO
- || i == STDERR_FILENO)
- continue;
- fdp = fd_child_list;
- if (fdp)
- {
- while (*fdp != -1 && *fdp != i)
- fdp++;
- }
-
- if (!(fdp && *fdp != -1))
- close(i);
- }
- errno = 0;
-
- /* We store our parents pid in the environment so that the
- execed assuan server is able to read the actual pid of the
- client. The server can't use getppid becuase it might have
- been double forked before the assuan server has been
- initialized. */
- setenv ("_assuan_pipe_connect_pid", mypidstr, 1);
-
- execv (name, (char *const *) argv);
- /* oops - use the pipe to tell the parent about it */
- snprintf (errbuf, sizeof(errbuf)-1,
- "ERR %d can't exec `%s': %.50s\n",
- _assuan_error (ASSUAN_Problem_Starting_Server),
- name, strerror (errno));
- errbuf[sizeof(errbuf)-1] = 0;
- writen (1, errbuf, strlen (errbuf));
- _exit (4);
- }
-#ifdef _ASSUAN_USE_DOUBLE_FORK
- if (pid == -1)
- _exit (1);
- else
- _exit (0);
-#endif
- }
-
-#ifdef _ASSUAN_USE_DOUBLE_FORK
- waitpid ((*ctx)->pid, NULL, 0);
- (*ctx)->pid = -1;
-#endif
-
- close (rp[1]);
- close (wp[0]);
-
-#endif /*!HAVE_W32_SYSTEM*/
-
- /* initial handshake */
- {
- int okay, off;
-
- err = _assuan_read_from_server (*ctx, &okay, &off);
- if (err)
- _assuan_log_printf ("can't connect server: %s\n",
- assuan_strerror (err));
- else if (okay != 1)
- {
- _assuan_log_printf ("can't connect server: `%s'\n",
- (*ctx)->inbound.line);
- err = _assuan_error (ASSUAN_Connect_Failed);
- }
- }
-
- if (err)
- {
- assuan_disconnect (*ctx);
- *ctx = NULL;
- }
-
- return err;
+ return initial_handshake (ctx);
}
+#endif /*HAVE_W32_SYSTEM*/
-
+
/* Connect to a server over a pipe, creating the assuan context and
returning it in CTX. The server filename is NAME, the argument
vector in ARGV. FD_CHILD_LIST is a -1 terminated list of file
@@ -617,5 +820,53 @@
assuan_pipe_connect (assuan_context_t *ctx, const char *name,
const char *const argv[], int *fd_child_list)
{
- return assuan_pipe_connect2 (ctx, name, argv, fd_child_list, NULL, NULL);
+ return pipe_connect (ctx, name, argv, fd_child_list, NULL, NULL);
}
+
+
+/* Connect to a server over a pipe, creating the assuan context and
+ returning it in CTX. The server filename is NAME, the argument
+ vector in ARGV. FD_CHILD_LIST is a -1 terminated list of file
+ descriptors not to close in the child. ATFORK is called in the
+ child right after the fork; ATFORKVALUE is passed as the first
+ argument and 0 is passed as the second argument. The ATFORK
+ function should only act if the second value is 0. */
+assuan_error_t
+assuan_pipe_connect2 (assuan_context_t *ctx,
+ const char *name, const char *const argv[],
+ int *fd_child_list,
+ void (*atfork) (void *opaque, int reserved),
+ void *atforkvalue)
+{
+ return pipe_connect (ctx, name, argv, fd_child_list, atfork, atforkvalue);
+}
+
+
+/* Connect to a server over a socketpair, creating the assuan context
+ and returning it in CTX. The server filename is NAME, the argument
+ vector in ARGV. FD_CHILD_LIST is a -1 terminated list of file
+ descriptors not to close in the child. ATFORK is called in the
+ child right after the fork; ATFORKVALUE is passed as the first
+ argument and 0 is passed as the second argument. The ATFORK
+ function should only act if the second value is 0.
+
+ If NAME as well as ARGV are NULL, no exec is done but the same
+ process is continued. However all file descriptors are closed and
+ some specila environment variables are set. To let the caller
+ detect whether the cild or the parent continues, the child returns
+ a CTX of NULL. */
+assuan_error_t
+assuan_pipe_connect_ext (assuan_context_t *ctx,
+ const char *name, const char *const argv[],
+ int *fd_child_list,
+ void (*atfork) (void *opaque, int reserved),
+ void *atforkvalue)
+{
+#ifdef HAVE_W32_SYSTEM
+ return _assuan_error (ASSUAN_Not_Implemented);
+#else
+ return socketpair_connect (ctx, name, argv, fd_child_list,
+ atfork, atforkvalue);
+#endif
+}
+
Modified: trunk/src/assuan-pipe-server.c
===================================================================
--- trunk/src/assuan-pipe-server.c 2006-09-11 13:15:48 UTC (rev 198)
+++ trunk/src/assuan-pipe-server.c 2006-09-12 11:07:18 UTC (rev 199)
@@ -111,8 +111,28 @@
ctx->inbound.fd = _get_osfhandle (filedes[0]);
ctx->outbound.fd = _get_osfhandle (filedes[1]);
#else
- ctx->inbound.fd = filedes[0];
- ctx->outbound.fd = filedes[1];
+ s = getenv ("_assuan_connection_fd");
+ if (!filedes && s && *s && atoi (s) >= 0 )
+ {
+ /* Well, we are called with an bi-directional file
+ descriptor. Prepare for using sendmsg/recvmsg. In this
+ case we ignore the passed file descriptors. */
+ ctx->inbound.fd = ctx->outbound.fd = atoi (s);
+ _assuan_init_uds_io (ctx);
+ ctx->deinit_handler = _assuan_uds_deinit;
+ }
+ else if (filedes)
+ {
+ /* Standard pipe server. */
+ ctx->inbound.fd = filedes[0];
+ ctx->outbound.fd = filedes[1];
+ }
+ else
+ {
+ _assuan_release_context (*r_ctx);
+ *r_ctx = NULL;
+ return ASSUAN_Problem_Starting_Server;
+ }
#endif
ctx->pipe_mode = 1;
Modified: trunk/src/assuan-socket-server.c
===================================================================
--- trunk/src/assuan-socket-server.c 2006-09-11 13:15:48 UTC (rev 198)
+++ trunk/src/assuan-socket-server.c 2006-09-12 11:07:18 UTC (rev 199)
@@ -34,6 +34,10 @@
#include "assuan-defs.h"
+static struct assuan_io io = { _assuan_simple_read,
+ _assuan_simple_write };
+
+
static int
accept_connection_bottom (assuan_context_t ctx)
{
@@ -105,9 +109,6 @@
finish_connection (ctx);
}
-static struct assuan_io io = { _assuan_simple_read,
- _assuan_simple_write };
-
/* Initialize a server for the socket LISTEN_FD which has already be
put into listen mode */
int
Copied: trunk/src/assuan-uds.c (from rev 196, trunk/src/assuan-domain-connect.c)
===================================================================
--- trunk/src/assuan-domain-connect.c 2006-09-06 16:36:45 UTC (rev 196)
+++ trunk/src/assuan-uds.c 2006-09-12 11:07:18 UTC (rev 199)
@@ -0,0 +1,273 @@
+/* assuan-uds.c - Assuan unix domain socket utilities
+ * Copyright (C) 2006 Free Software Foundation, Inc.
+ *
+ * This file is part of Assuan.
+ *
+ * Assuan 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.
+ *
+ * Assuan 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/types.h>
+#ifndef HAVE_W32_SYSTEM
+#include <sys/socket.h>
+#include <sys/un.h>
+#else
+#include <windows.h>
+#endif
+#if HAVE_SYS_UIO_H
+#include <sys/uio.h>
+#endif
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <assert.h>
+
+#include "assuan-defs.h"
+
+
+/* Read from a unix domain socket using sendmsg. */
+static ssize_t
+uds_reader (assuan_context_t ctx, void *buf, size_t buflen)
+{
+ int len = ctx->uds.buffersize;
+
+#ifndef HAVE_W32_SYSTEM
+
+ if (!ctx->uds.bufferallocated)
+ {
+ ctx->uds.buffer = xtrymalloc (2048);
+ if (!ctx->uds.buffer)
+ return _assuan_error (ASSUAN_Out_Of_Core);
+ ctx->uds.bufferallocated = 2048;
+ }
+
+ while (!len) /* No data is buffered. */
+ {
+ struct msghdr msg;
+ struct iovec iovec;
+ union {
+ struct cmsghdr cm;
+ char control[CMSG_SPACE(sizeof (int))];
+ } control_u;
+ struct cmsghdr *cmptr;
+
+ memset (&msg, 0, sizeof (msg));
+
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+ msg.msg_iov = &iovec;
+ msg.msg_iovlen = 1;
+ iovec.iov_base = ctx->uds.buffer;
+ iovec.iov_len = ctx->uds.bufferallocated;
+ msg.msg_control = control_u.control;
+ msg.msg_controllen = sizeof (control_u.control);
+
+ len = _assuan_simple_recvmsg (ctx, &msg);
+ if (len < 0)
+ return -1;
+
+ ctx->uds.buffersize = len;
+ ctx->uds.bufferoffset = 0;
+
+ cmptr = CMSG_FIRSTHDR (&msg);
+ if (cmptr && cmptr->cmsg_len == CMSG_LEN (sizeof(int)))
+ {
+ if (cmptr->cmsg_level != SOL_SOCKET
+ || cmptr->cmsg_type != SCM_RIGHTS)
+ _assuan_log_printf ("unexpected ancillary data received\n");
+ else
+ {
+ int fd = *((int*)CMSG_DATA (cmptr));
+
+ if (ctx->uds.pendingfdscount >= DIM (ctx->uds.pendingfds))
+ {
+ _assuan_log_printf ("too many descriptors pending - "
+ "closing received descriptor %d\n", fd);
+ _assuan_close (fd);
+ }
+ else
+ ctx->uds.pendingfds[ctx->uds.pendingfdscount++] = fd;
+ }
+ }
+ }
+#else /*HAVE_W32_SYSTEM*/
+ len = recvfrom (ctx->inbound.fd, buf, buflen, 0, NULL, NULL);
+#endif /*HAVE_W32_SYSTEM*/
+
+ /* Return some data to the user. */
+
+ if (len > buflen) /* We have more than the user requested. */
+ len = buflen;
+
+ memcpy (buf, ctx->uds.buffer + ctx->uds.bufferoffset, len);
+ ctx->uds.buffersize -= len;
+ assert (ctx->uds.buffersize >= 0);
+ ctx->uds.bufferoffset += len;
+ assert (ctx->uds.bufferoffset <= ctx->uds.bufferallocated);
+
+ return len;
+}
+
+
+/* Write to the domain server. */
+static ssize_t
+uds_writer (assuan_context_t ctx, const void *buf, size_t buflen)
+{
+#ifndef HAVE_W32_SYSTEM
+ struct msghdr msg;
+ struct iovec iovec;
+ ssize_t len;
+
+ memset (&msg, 0, sizeof (msg));
+
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+ msg.msg_iovlen = 1;
+ msg.msg_iov = &iovec;
+ iovec.iov_base = (void*)buf;
+ iovec.iov_len = buflen;
+ msg.msg_control = 0;
+ msg.msg_controllen = 0;
+
+ len = _assuan_simple_sendmsg (ctx, &msg);
+#else /*HAVE_W32_SYSTEM*/
+ int len;
+
+ len = sendto (ctx->outbound.fd, buf, buflen, 0,
+ (struct sockaddr *)&ctx->serveraddr,
+ sizeof (struct sockaddr_in));
+#endif /*HAVE_W32_SYSTEM*/
+ return len;
+}
+
+
+static assuan_error_t
+uds_sendfd (assuan_context_t ctx, int fd)
+{
+#ifndef HAVE_W32_SYSTEM
+ struct msghdr msg;
+ struct iovec iovec;
+ union {
+ struct cmsghdr cm;
+ char control[CMSG_SPACE(sizeof (int))];
+ } control_u;
+ struct cmsghdr *cmptr;
+ int len;
+ char buffer[80];
+
+ /* We need to send some real data so that a read won't return 0
+ which will be taken as an EOF. It also helps with debugging. */
+ snprintf (buffer, sizeof(buffer)-1, "# descriptor %d is in flight\n", fd);
+ buffer[sizeof(buffer)-1] = 0;
+
+ memset (&msg, 0, sizeof (msg));
+
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+ msg.msg_iovlen = 1;
+ msg.msg_iov = &iovec;
+ iovec.iov_base = buffer;
+ iovec.iov_len = strlen (buffer);
+
+ msg.msg_control = control_u.control;
+ msg.msg_controllen = sizeof (control_u.control);
+ cmptr = CMSG_FIRSTHDR (&msg);
+ cmptr->cmsg_len = CMSG_LEN(sizeof(int));
+ cmptr->cmsg_level = SOL_SOCKET;
+ cmptr->cmsg_type = SCM_RIGHTS;
+ *((int*)CMSG_DATA (cmptr)) = fd;
+
+ len = _assuan_simple_sendmsg (ctx, &msg);
+ if (len < 0)
+ {
+ _assuan_log_printf ("uds_sendfd: %s\n", strerror (errno));
+ return _assuan_error (ASSUAN_Write_Error);
+ }
+ else
+ return 0;
+#else
+ return _assuan_error (ASSUAN_Not_Implemented);
+#endif
+}
+
+
+static assuan_error_t
+uds_receivefd (assuan_context_t ctx, int *fd)
+{
+#ifndef HAVE_W32_SYSTEM
+ if (!ctx->uds.pendingfds)
+ {
+ _assuan_log_printf ("no pending file descriptors!\n");
+ return _assuan_error (ASSUAN_General_Error);
+ }
+
+ *fd = ctx->uds.pendingfds[0];
+ if (--ctx->uds.pendingfdscount)
+ memmove (ctx->uds.pendingfds, ctx->uds.pendingfds + 1,
+ ctx->uds.pendingfdscount * sizeof (int));
+
+ return 0;
+#else
+ return _assuan_error (ASSUAN_Not_Implemented);
+#endif
+}
+
+
+/* Deinitialize the unix domain socket I/O functions. */
+void
+_assuan_uds_deinit (assuan_context_t ctx)
+{
+ int i;
+
+ /* First call the finish_handler which should close descriptors etc. */
+ ctx->finish_handler (ctx);
+
+ if (ctx->uds.buffer)
+ {
+ assert (ctx->uds.bufferallocated);
+ ctx->uds.bufferallocated = 0;
+ xfree (ctx->uds.buffer);
+ }
+
+ for (i = 0; i < ctx->uds.pendingfdscount; i++)
+ _assuan_close (ctx->uds.pendingfds[i]);
+ ctx->uds.pendingfdscount = 0;
+}
+
+
+
+/* Helper function to initialize a context for domain I/O. */
+void
+_assuan_init_uds_io (assuan_context_t ctx)
+{
+ static struct assuan_io io = { uds_reader, uds_writer,
+ uds_sendfd, uds_receivefd };
+
+ ctx->io = &io;
+ ctx->uds.buffer = 0;
+ ctx->uds.bufferoffset = 0;
+ ctx->uds.buffersize = 0;
+ ctx->uds.bufferallocated = 0;
+ ctx->uds.pendingfdscount = 0;
+}
+
Modified: trunk/src/assuan.h
===================================================================
--- trunk/src/assuan.h 2006-09-11 13:15:48 UTC (rev 198)
+++ trunk/src/assuan.h 2006-09-12 11:07:18 UTC (rev 199)
@@ -347,7 +347,7 @@
file descriptor via CTX and stores it in *RDF (the CTX must be
capable of passing file descriptors). */
assuan_error_t assuan_command_parse_fd (assuan_context_t ctx, char *line,
- int *rfd);
+ int *rfd);
/*-- assuan-listen.c --*/
assuan_error_t assuan_set_hello_line (assuan_context_t ctx, const char *line);
@@ -368,38 +368,29 @@
/*-- assuan-pipe-connect.c --*/
-assuan_error_t assuan_pipe_connect (assuan_context_t *ctx, const char *name,
+assuan_error_t assuan_pipe_connect (assuan_context_t *ctx,
+ const char *name,
const char *const argv[],
int *fd_child_list);
-assuan_error_t assuan_pipe_connect2 (assuan_context_t *ctx, const char *name,
+assuan_error_t assuan_pipe_connect2 (assuan_context_t *ctx,
+ const char *name,
const char *const argv[],
int *fd_child_list,
void (*atfork) (void*, int),
void *atforkvalue);
+assuan_error_t assuan_pipe_connect_ext (assuan_context_t *ctx,
+ const char *name,
+ const char *const argv[],
+ int *fd_child_list,
+ void (*atfork) (void *, int),
+ void *atforkvalue);
+
/*-- assuan-socket-connect.c --*/
assuan_error_t assuan_socket_connect (assuan_context_t *ctx, const char *name,
pid_t server_pid);
-/*-- assuan-domain-connect.c --*/
-/* Connect to a Unix domain socket server. RENDEZVOUSFD is
- bidirectional file descriptor (normally returned via socketpair)
- which the client can use to rendezvous with the server. SERVER s
- the server's pid. */
-assuan_error_t assuan_domain_connect (assuan_context_t *r_ctx,
- int rendezvousfd,
- pid_t server);
-/*-- assuan-domain-server.c --*/
-
-/* RENDEZVOUSFD is a bidirectional file descriptor (normally returned
- via socketpair) that the domain server can use to rendezvous with
- the client. CLIENT is the client's pid. */
-assuan_error_t assuan_init_domain_server (assuan_context_t *r_ctx,
- int rendezvousfd,
- pid_t client);
-
-
/*-- assuan-connect.c --*/
void assuan_disconnect (assuan_context_t ctx);
pid_t assuan_get_pid (assuan_context_t ctx);
Modified: trunk/tests/fdpassing.c
===================================================================
--- trunk/tests/fdpassing.c 2006-09-11 13:15:48 UTC (rev 198)
+++ trunk/tests/fdpassing.c 2006-09-12 11:07:18 UTC (rev 199)
@@ -45,23 +45,28 @@
int fd;
int c;
FILE *fp;
+ int nbytes;
log_info ("got ECHO command (%s)\n", line);
fd = assuan_get_input_fd (ctx);
if (fd == -1)
return ASSUAN_No_Input;
- fp = fdopen (dup (fd), "r");
+ fp = fdopen (fd, "r");
if (!fp)
{
log_error ("fdopen failed on input fd: %s\n", strerror (errno));
return ASSUAN_General_Error;
}
log_info ("printing input to stdout:\n");
+ nbytes = 0;
while ( (c=getc (fp)) != -1)
- putc (c, stdout);
+ {
+ putc (c, stdout);
+ nbytes++;
+ }
fflush (stdout);
- log_info ("done printing input to stdout\n");
+ log_info ("done printing %d bytes to stdout\n", nbytes);
fclose (fp);
return 0;
@@ -93,22 +98,21 @@
static void
-server (int fd)
+server (void)
{
int rc;
assuan_context_t ctx;
- log_info ("server started on fd %d\n", fd);
+ log_info ("server started\n");
- rc = assuan_init_domain_server (&ctx, fd, (pid_t)(-1));
+ rc = assuan_init_pipe_server (&ctx, NULL);
if (rc)
- log_fatal ("assuan_init_domain_server failed: %s\n", assuan_strerror (rc));
+ log_fatal ("assuan_init_pipe_server failed: %s\n", assuan_strerror (rc));
rc = register_commands (ctx);
if (rc)
log_fatal ("register_commands failed: %s\n", assuan_strerror(rc));
- assuan_set_assuan_log_prefix (log_prefix);
assuan_set_log_stream (ctx, stderr);
for (;;)
@@ -116,7 +120,8 @@
rc = assuan_accept (ctx);
if (rc)
{
- log_error ("assuan_accept failed: %s\n", assuan_strerror (rc));
+ if (rc != -1)
+ log_error ("assuan_accept failed: %s\n", assuan_strerror (rc));
break;
}
@@ -140,53 +145,51 @@
/* Client main. If true is returned, a disconnect has not been done. */
static int
-client (int fd)
+client (assuan_context_t ctx)
{
int rc;
- assuan_context_t ctx;
FILE *fp;
int i;
- log_info ("client started on fd %d\n", fd);
+ log_info ("client started\n");
- rc = assuan_domain_connect (&ctx, fd, (pid_t)(-1));
- if (rc)
+ for (i=0; i < 8; i++)
{
- log_error ("assuan_domain_connect failed: %s\n", assuan_strerror (rc));
- return -1;
- }
+ fp = fopen ("/etc/motd", "r");
+ if (!fp)
+ {
+ log_error ("failed to open `%s': %s\n", "/etc/motd",
+ strerror (errno));
+ return -1;
+ }
+
+ rc = assuan_sendfd (ctx, fileno (fp));
+ if (rc)
+ {
+ log_error ("assuan_sendfd failed: %s\n", assuan_strerror (rc));
+ return -1;
+ }
+ fclose (fp);
- fp = fopen ("/etc/motd", "r");
- if (!fp)
- {
- log_error ("failed to open `%s': %s\n", "/etc/motd", strerror (errno));
- return -1;
- }
+ rc = assuan_transact (ctx, "INPUT FD", NULL, NULL, NULL, NULL,
+ NULL, NULL);
+ if (rc)
+ {
+ log_error ("sending INPUT FD failed: %s\n", assuan_strerror (rc));
+ return -1;
+ }
- rc = assuan_sendfd (ctx, fileno (fp));
- if (rc)
- {
- log_error ("assuan_sendfd failed: %s\n", assuan_strerror (rc));
- return -1;
+ rc = assuan_transact (ctx, "ECHO", NULL, NULL, NULL, NULL, NULL, NULL);
+ if (rc)
+ {
+ log_error ("sending ECHO failed: %s\n", assuan_strerror (rc));
+ return -1;
+ }
}
-
- rc = assuan_transact (ctx, "INPUT FD", NULL, NULL, NULL, NULL, NULL, NULL);
- if (rc)
- {
- log_error ("sending INPUT FD failed: %s\n", assuan_strerror (rc));
- return -1;
- }
+ /* Give us some time to check with lsof that all descriptors are closed. */
+/* sleep (10); */
- rc = assuan_transact (ctx, "ECHO", NULL, NULL, NULL, NULL, NULL, NULL);
- if (rc)
- {
- log_error ("sending ECHO failed: %s\n", assuan_strerror (rc));
- return -1;
- }
-
- sleep (100);
-
assuan_disconnect (ctx);
return 0;
}
@@ -204,8 +207,12 @@
{
int last_argc = -1;
const char *srcdir = getenv ("srcdir");
- int fds[2];
- pid_t pid;
+ assuan_context_t ctx;
+ int err;
+ int no_close_fds[2];
+ const char *arglist[10];
+ int is_server = 0;
+ int with_exec = 0;
if (!srcdir)
srcdir = ".";
@@ -223,7 +230,10 @@
puts (
"usage: ./fdpassing [options]\n"
"\n"
-" Options are --verbose and --debug");
+"Options:\n"
+" --verbose Show what is going on\n"
+" --with-exec Exec the child. Default is just a fork\n"
+);
exit (0);
}
if (!strcmp (*argv, "--verbose"))
@@ -236,29 +246,60 @@
verbose = debug = 1;
argc--; argv++;
}
+ else if (!strcmp (*argv, "--server"))
+ {
+ is_server = 1;
+ argc--; argv++;
+ }
+ else if (!strcmp (*argv, "--with-exec"))
+ {
+ with_exec = 1;
+ argc--; argv++;
+ }
}
- /* Create a socketpair. */
- if ( socketpair (AF_LOCAL, SOCK_STREAM, 0, fds) )
- log_fatal ("socketpair failed: %s\n", strerror (errno));
+ assuan_set_assuan_log_prefix (log_prefix);
+ assuan_set_assuan_log_stream (stderr);
- /* Fork and run server and client. */
- pid = fork ();
- if (pid == (pid_t)(-1))
- log_fatal ("fork failed: %s\n", strerror (errno));
- if (!pid)
+ if (is_server)
{
- server (fds[0]); /* The child is our server. */
+ server ();
log_info ("server finished\n");
}
else
{
- if (client (fds[1])) /* The parent is the client. */
+ no_close_fds[0] = 2;
+ no_close_fds[1] = -1;
+ if (with_exec)
{
- log_info ("waiting for server to terminate...\n");
- waitpid (pid, NULL, 0);
+ arglist[0] = "fdpassing";
+ arglist[1] = "--server";
+ arglist[2] = verbose? "--verbose":NULL;
+ arglist[3] = NULL;
}
- log_info ("client finished\n");
+ err = assuan_pipe_connect_ext (&ctx, with_exec? "./fdpassing":NULL,
+ with_exec? arglist :NULL,
+ no_close_fds, NULL, NULL);
+ if (err)
+ {
+ log_error ("assuan_pipe_connect failed: %s\n",assuan_strerror (err));
+ return 1;
+ }
+
+ if (!ctx)
+ {
+ server ();
+ log_info ("server finished\n");
+ }
+ else
+ {
+ if (client (ctx))
+ {
+ log_info ("waiting for server to terminate...\n");
+ assuan_disconnect (ctx);
+ }
+ log_info ("client finished\n");
+ }
}
return errorcount? 1:0;
More information about the Gnupg-commits
mailing list