[Pkg-gnupg-commit] [libassuan] 154/437: Integrated descriptor passing.
Eric Dorland
eric at moszumanska.debian.org
Fri May 22 05:33:36 UTC 2015
This is an automated email from the git hooks/post-receive script.
eric pushed a commit to branch master
in repository libassuan.
commit d1210ab25c96e60fc439cfa9b50ec431642ada36
Author: Werner Koch <wk at gnupg.org>
Date: Tue Sep 12 11:07:18 2006 +0000
Integrated descriptor passing.
---
NEWS | 5 +
TODO | 1 +
src/ChangeLog | 32 +++
src/Makefile.am | 3 +-
src/assuan-defs.h | 50 ++--
src/assuan-domain-connect.c | 534 -----------------------------------
src/assuan-domain-server.c | 50 ----
src/assuan-handler.c | 2 +-
src/assuan-io.c | 134 ++++++++-
src/assuan-pipe-connect.c | 669 ++++++++++++++++++++++++++++++--------------
src/assuan-pipe-server.c | 24 +-
src/assuan-socket-server.c | 7 +-
src/assuan-uds.c | 273 ++++++++++++++++++
src/assuan.h | 33 +--
tests/fdpassing.c | 161 +++++++----
15 files changed, 1071 insertions(+), 907 deletions(-)
diff --git a/NEWS b/NEWS
index 8aebb0f..b85188e 100644
--- a/NEWS
+++ b/NEWS
@@ -17,6 +17,11 @@ Noteworthy changes in version 0.9.0
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)
-------------------------------------------------
diff --git a/TODO b/TODO
index fceeb2b..aa547c9 100644
--- a/TODO
+++ b/TODO
@@ -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
diff --git a/src/ChangeLog b/src/ChangeLog
index 77649e6..fd4e3d3 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -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)
diff --git a/src/Makefile.am b/src/Makefile.am
index 1774875..e90b7af 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -46,9 +46,8 @@ libassuan_a_SOURCES = \
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
diff --git a/src/assuan-defs.h b/src/assuan-defs.h
index e6bacf5..1f908fb 100644
--- a/src/assuan-defs.h
+++ b/src/assuan-defs.h
@@ -106,7 +106,7 @@ struct assuan_context_s
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 @@ struct assuan_context_s
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 @@ struct assuan_context_s
} 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 @@ struct assuan_context_s
/* 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,13 +184,10 @@ struct assuan_context_s
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 @@ void _assuan_log_sanitized_string (const char *string);
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 @@ char *stpcpy (char *dest, const char *src);
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*/
diff --git a/src/assuan-domain-connect.c b/src/assuan-domain-connect.c
deleted file mode 100644
index bc98e39..0000000
--- a/src/assuan-domain-connect.c
+++ /dev/null
@@ -1,534 +0,0 @@
-/* assuan-domain-connect.c - Assuan unix domain socket based client
- * Copyright (C) 2002, 2003, 2005 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"
-
-#ifndef PF_LOCAL
-# ifdef PF_UNIX
-# define PF_LOCAL PF_UNIX
-# else
-# define PF_LOCAL AF_UNIX
-# endif
-# ifndef AF_LOCAL
-# define AF_LOCAL AF_UNIX
-# endif
-#endif
-
-
-
-/* Read an integer from byte address ADDR. Works even if ADDR is
- misaligned. */
-static int
-read_int (const void *addr)
-{
- int val;
-
- memcpy (&val, addr, sizeof (int));
-
- return val;
-}
-
-
-/* Write the integer VAL to byte address ADDR. Works even if ADDR is
- misaligned. */
-static void
-write_int (void *addr, int val)
-{
- memcpy (addr, &val, sizeof (int));
-}
-
-
-static void
-do_deinit (assuan_context_t ctx)
-{
- if (ctx->inbound.fd != -1)
- _assuan_close (ctx->inbound.fd);
- ctx->inbound.fd = -1;
- ctx->outbound.fd = -1;
-
- if (ctx->domainbuffer)
- {
- assert (ctx->domainbufferallocated);
- xfree (ctx->domainbuffer);
- }
-
- if (ctx->pendingfds)
- {
- int i;
-
- assert (ctx->pendingfdscount > 0);
- for (i = 0; i < ctx->pendingfdscount; i ++)
- _assuan_close (ctx->pendingfds[i]);
-
- xfree (ctx->pendingfds);
- }
-
- unlink (ctx->myaddr.sun_path);
-}
-
-
-/* Read from the socket server. */
-static ssize_t
-domain_reader (assuan_context_t ctx, void *buf, size_t buflen)
-{
- int len = ctx->domainbuffersize;
-
-#ifndef HAVE_W32_SYSTEM
- start:
- if (len == 0)
- /* No data is buffered. */
- {
- struct msghdr msg;
- struct iovec iovec;
- struct sockaddr_un sender;
- struct
- {
- struct cmsghdr hdr;
- int fd;
- } cmsg;
-
- memset (&msg, 0, sizeof (msg));
-
- for (;;)
- {
- msg.msg_name = &sender;
- msg.msg_namelen = sizeof (struct sockaddr_un);
- msg.msg_iov = &iovec;
- msg.msg_iovlen = 1;
- iovec.iov_base = ctx->domainbuffer;
- iovec.iov_len = ctx->domainbufferallocated;
- msg.msg_control = &cmsg;
- msg.msg_controllen = sizeof cmsg;
-
- /* Peek first: if the buffer we have is too small then it
- will be truncated. */
- len = recvmsg (ctx->inbound.fd, &msg, MSG_PEEK);
- if (len < 0)
- {
- _assuan_log_printf ("domain_reader: %s\n", strerror (errno));
- return -1;
- }
-
- if (strcmp (ctx->serveraddr.sun_path,
- ((struct sockaddr_un *) msg.msg_name)->sun_path) != 0)
- {
- /* XXX: Arg. Not from whom we expected! What do we
- want to do? Should we just ignore it? Either way,
- we still need to consume the message. */
- break;
- }
-
- if (msg.msg_flags & MSG_TRUNC)
- /* Enlarge the buffer and try again. */
- {
- int size = ctx->domainbufferallocated;
- void *tmp;
-
- if (size == 0)
- size = 4 * 1024;
- else
- size *= 2;
-
- tmp = xtrymalloc (size);
- if (! tmp)
- return -1;
-
- xfree (ctx->domainbuffer);
- ctx->domainbuffer = tmp;
- ctx->domainbufferallocated = size;
- }
- else
- /* We have enough space! */
- break;
- }
-
- /* Now we have to actually consume it (remember, we only
- peeked). */
- msg.msg_name = &sender;
- msg.msg_namelen = sizeof (struct sockaddr_un);
- msg.msg_iov = &iovec;
- msg.msg_iovlen = 1;
- iovec.iov_base = ctx->domainbuffer;
- iovec.iov_len = ctx->domainbufferallocated;
- msg.msg_control = &cmsg;
- msg.msg_controllen = sizeof cmsg;
-
- if (strcmp (ctx->serveraddr.sun_path,
- ((struct sockaddr_un *) msg.msg_name)->sun_path) != 0)
- {
- /* XXX: Arg. Not from whom we expected! What do we want to
- do? Should we just ignore it? We shall do the latter
- for the moment. */
- _assuan_log_printf ("not setup to receive messages from `%s'\n",
- ((struct sockaddr_un *) msg.msg_name)->sun_path);
- goto start;
- }
-
- len = recvmsg (ctx->inbound.fd, &msg, 0);
- if (len < 0)
- {
- _assuan_log_printf ("domain_reader: %s\n", strerror (errno));
- return -1;
- }
-
- ctx->domainbuffersize = len;
- ctx->domainbufferoffset = 0;
-
- if (sizeof (cmsg) == msg.msg_controllen)
- /* We received a file descriptor. */
- {
- void *tmp;
-
- tmp = xtryrealloc (ctx->pendingfds,
- sizeof (int) * (ctx->pendingfdscount + 1));
- if (! tmp)
- {
- _assuan_log_printf ("domain_reader: %s\n", strerror (errno));
- return -1;
- }
-
- ctx->pendingfds = tmp;
- ctx->pendingfds[ctx->pendingfdscount++]
- = read_int (CMSG_DATA (&cmsg.hdr));
-
- _assuan_log_printf ("received file descriptor %d from peer\n",
- ctx->pendingfds[ctx->pendingfdscount - 1]);
- }
-
- if (len == 0)
- goto start;
- }
-#else
- len = recvfrom (ctx->inbound.fd, buf, buflen, 0, NULL, NULL);
-#endif
-
- /* Return some data to the user. */
-
- if (len > buflen)
- /* We have more than the user requested. */
- len = buflen;
-
- memcpy (buf, ctx->domainbuffer + ctx->domainbufferoffset, len);
- ctx->domainbuffersize -= len;
- assert (ctx->domainbuffersize >= 0);
- ctx->domainbufferoffset += len;
- assert (ctx->domainbufferoffset <= ctx->domainbufferallocated);
-
- return len;
-}
-
-/* Write to the domain server. */
-static ssize_t
-domain_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 = &ctx->serveraddr;
- msg.msg_namelen = offsetof (struct sockaddr_un, sun_path)
- + strlen (ctx->serveraddr.sun_path) + 1;
-
- 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 = sendmsg (ctx->outbound.fd, &msg, 0);
- if (len < 0)
- _assuan_log_printf ("domain_writer: %s\n", strerror (errno));
-#else
- int len;
-
- len = sendto (ctx->outbound.fd, buf, buflen, 0,
- (struct sockaddr *)&ctx->serveraddr,
- sizeof (struct sockaddr_in));
-#endif
- return len;
-}
-
-static assuan_error_t
-domain_sendfd (assuan_context_t ctx, int fd)
-{
-#ifndef HAVE_W32_SYSTEM
- struct msghdr msg;
- struct
- {
- struct cmsghdr hdr;
- int fd;
- } cmsg;
- int len;
-
- memset (&msg, 0, sizeof (msg));
-
- msg.msg_name = &ctx->serveraddr;
- msg.msg_namelen = offsetof (struct sockaddr_un, sun_path)
- + strlen (ctx->serveraddr.sun_path) + 1;
-
- msg.msg_iovlen = 0;
- msg.msg_iov = 0;
-
- cmsg.hdr.cmsg_level = SOL_SOCKET;
- cmsg.hdr.cmsg_type = SCM_RIGHTS;
- cmsg.hdr.cmsg_len = sizeof (cmsg);
-
- msg.msg_control = &cmsg;
- msg.msg_controllen = sizeof (cmsg);
-
- write_int (CMSG_DATA (&cmsg.hdr), fd);
-
- len = sendmsg (ctx->outbound.fd, &msg, 0);
- if (len < 0)
- {
- _assuan_log_printf ("domain_sendfd: %s\n", strerror (errno));
- return _assuan_error (ASSUAN_General_Error);
- }
- else
- return 0;
-#else
- return 0;
-#endif
-}
-
-static assuan_error_t
-domain_receivefd (assuan_context_t ctx, int *fd)
-{
-#ifndef HAVE_W32_SYSTEM
- if (ctx->pendingfds == 0)
- {
- _assuan_log_printf ("no pending file descriptors!\n");
- return _assuan_error (ASSUAN_General_Error);
- }
-
- *fd = ctx->pendingfds[0];
- if (-- ctx->pendingfdscount == 0)
- {
- xfree (ctx->pendingfds);
- ctx->pendingfds = 0;
- }
- else /* Fix the array. */
- {
- void *tmp;
-
- memmove (ctx->pendingfds, ctx->pendingfds + 1,
- ctx->pendingfdscount * sizeof (int));
- tmp = xtryrealloc (ctx->pendingfds,
- ctx->pendingfdscount * sizeof (int));
- if (tmp)
- ctx->pendingfds = tmp;
- /* Note: we ignore an shrinking error here thus the next realloc
- to increase the size will succeed as the block is already of
- the then requested size. */
- }
-#endif
- return 0;
-}
-
-
-
-assuan_error_t
-_assuan_domain_init (assuan_context_t *r_ctx, int rendezvousfd, pid_t peer)
-{
- static struct assuan_io io = { domain_reader, domain_writer,
- domain_sendfd, domain_receivefd };
-
- assuan_error_t err;
- assuan_context_t ctx;
- int fd;
- size_t len;
- int tries;
-
- if (!r_ctx)
- return _assuan_error (ASSUAN_Invalid_Value);
- *r_ctx = NULL;
-
- err = _assuan_new_context (&ctx);
- if (err)
- return err;
-
- /* Save it in case we need it later. */
- ctx->pid = peer;
-
- /* Override the default (NOP) handlers. */
- ctx->deinit_handler = do_deinit;
-
- /* Setup the socket. */
-
- fd = _assuan_sock_new (PF_LOCAL, SOCK_DGRAM, 0);
- if (fd == -1)
- {
- _assuan_log_printf ("can't create socket: %s\n", strerror (errno));
- _assuan_release_context (ctx);
- return _assuan_error (ASSUAN_General_Error);
- }
-
- ctx->inbound.fd = fd;
- ctx->outbound.fd = fd;
-
- /* And the io buffers. */
-
- ctx->io = &io;
- ctx->domainbuffer = 0;
- ctx->domainbufferoffset = 0;
- ctx->domainbuffersize = 0;
- ctx->domainbufferallocated = 0;
- ctx->pendingfds = 0;
- ctx->pendingfdscount = 0;
-
- /* Get usable name and bind to it. */
-
- for (tries = 0; tries < TMP_MAX; tries ++)
- {
- char *p;
- char buf[L_tmpnam];
-
- /* XXX: L_tmpnam must be shorter than sizeof (sun_path)! */
- assert (L_tmpnam < sizeof (ctx->myaddr.sun_path));
-
- /* XXX: W32 tmpnam is broken */
- p = tmpnam (buf);
- if (! p)
- {
- _assuan_log_printf ("cannot determine an appropriate temporary file "
- "name. DoS in progress?\n");
- _assuan_release_context (ctx);
- _assuan_close (fd);
- return _assuan_error (ASSUAN_General_Error);
- }
-
- memset (&ctx->myaddr, 0, sizeof ctx->myaddr);
- ctx->myaddr.sun_family = AF_LOCAL;
- len = strlen (buf) + 1;
- memcpy (ctx->myaddr.sun_path, buf, len);
- len += offsetof (struct sockaddr_un, sun_path);
-
- err = _assuan_sock_bind (fd, (struct sockaddr *) &ctx->myaddr, len);
- if (! err)
- break;
- }
-
- if (err)
- {
- _assuan_log_printf ("can't bind to `%s': %s\n", ctx->myaddr.sun_path,
- strerror (errno));
- _assuan_release_context (ctx);
- _assuan_close (fd);
- return _assuan_error (ASSUAN_Connect_Failed);
- }
-
- /* Rendezvous with our peer. */
- {
- FILE *fp;
- char *p;
-
- fp = fdopen (rendezvousfd, "w+");
- if (! fp)
- {
- _assuan_log_printf ("can't open rendezvous port: %s\n",
- strerror (errno));
- return _assuan_error (ASSUAN_Connect_Failed);
- }
-
- /* Send our address. */
- fprintf (fp, "%s\n", ctx->myaddr.sun_path);
- fflush (fp);
-
- /* And receive our peer's. */
- memset (&ctx->serveraddr, 0, sizeof ctx->serveraddr);
- for (p = ctx->serveraddr.sun_path;
- p < (ctx->serveraddr.sun_path
- + sizeof ctx->serveraddr.sun_path - 1);
- p ++)
- {
- *p = fgetc (fp);
- if (*p == '\n')
- break;
- }
- *p = '\0';
- fclose (fp);
-
- ctx->serveraddr.sun_family = AF_LOCAL;
- }
-
- *r_ctx = ctx;
- return 0;
-}
-
-/* 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 is
- the server's pid. */
-assuan_error_t
-assuan_domain_connect (assuan_context_t *r_ctx, int rendezvousfd, pid_t server)
-{
- assuan_error_t aerr;
- int okay, off;
-
- aerr = _assuan_domain_init (r_ctx, rendezvousfd, server);
- if (aerr)
- return aerr;
-
- /* Initial handshake. */
- aerr = _assuan_read_from_server (*r_ctx, &okay, &off);
- if (aerr)
- _assuan_log_printf ("can't connect to server: %s\n",
- assuan_strerror (aerr));
- else if (okay != 1)
- {
- _assuan_log_printf ("can't connect to server: `");
- _assuan_log_sanitized_string ((*r_ctx)->inbound.line);
- fprintf (assuan_get_assuan_log_stream (), "'\n");
- aerr = _assuan_error (ASSUAN_Connect_Failed);
- }
-
- if (aerr)
- assuan_disconnect (*r_ctx);
-
- return aerr;
-}
diff --git a/src/assuan-domain-server.c b/src/assuan-domain-server.c
deleted file mode 100644
index 2194c39..0000000
--- a/src/assuan-domain-server.c
+++ /dev/null
@@ -1,50 +0,0 @@
-/* assuan-socket-server.c - Assuan socket based server
- * Copyright (C) 2002 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 <unistd.h>
-
-#include "assuan-defs.h"
-
-/* Initialize a server. 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 *r_ctx,
- int rendezvousfd,
- pid_t client)
-{
- assuan_error_t err;
-
- err = _assuan_domain_init (r_ctx, rendezvousfd, client);
- if (err)
- return err;
-
- (*r_ctx)->is_server = 1;
- /* A domain server can only be used once. */
- (*r_ctx)->pipe_mode = 1;
-
- return 0;
-}
diff --git a/src/assuan-handler.c b/src/assuan-handler.c
index d2e90a2..0624305 100644
--- a/src/assuan-handler.c
+++ b/src/assuan-handler.c
@@ -479,7 +479,7 @@ process_request (ASSUAN_CONTEXT ctx)
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);
}
diff --git a/src/assuan-io.c b/src/assuan-io.c
index 30302d6..3a3a017 100644
--- a/src/assuan-io.c
+++ b/src/assuan-io.c
@@ -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 @@ _assuan_simple_write (assuan_context_t ctx, const void *buffer, size_t size)
# 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
+}
diff --git a/src/assuan-pipe-connect.c b/src/assuan-pipe-connect.c
index 4a6b436..c3ceb53 100644
--- a/src/assuan-pipe-connect.c
+++ b/src/assuan-pipe-connect.c
@@ -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 @@ do_finish (assuan_context_t ctx)
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 @@ do_deinit (assuan_context_t ctx)
}
+/* 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 @@ create_inheritable_pipe (int filedes[2], int for_write)
#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)
+{
assuan_error_t err;
int rp[2];
int wp[2];
@@ -414,201 +807,11 @@ assuan_pipe_connect2 (assuan_context_t *ctx,
(*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_error_t
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
}
+
diff --git a/src/assuan-pipe-server.c b/src/assuan-pipe-server.c
index 1ad85dc..509fc12 100644
--- a/src/assuan-pipe-server.c
+++ b/src/assuan-pipe-server.c
@@ -111,8 +111,28 @@ assuan_init_pipe_server (ASSUAN_CONTEXT *r_ctx, int filedes[2])
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;
diff --git a/src/assuan-socket-server.c b/src/assuan-socket-server.c
index aab1b5a..91adb71 100644
--- a/src/assuan-socket-server.c
+++ b/src/assuan-socket-server.c
@@ -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 @@ deinit_socket_server (assuan_context_t ctx)
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
diff --git a/src/assuan-uds.c b/src/assuan-uds.c
new file mode 100644
index 0000000..52988d4
--- /dev/null
+++ b/src/assuan-uds.c
@@ -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;
+}
+
diff --git a/src/assuan.h b/src/assuan.h
index b85e642..e16d821 100644
--- a/src/assuan.h
+++ b/src/assuan.h
@@ -347,7 +347,7 @@ assuan_error_t assuan_write_status (assuan_context_t ctx,
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,36 +368,27 @@ int assuan_init_connected_socket_server (assuan_context_t *r_ctx, int fd);
/*-- 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 --*/
diff --git a/tests/fdpassing.c b/tests/fdpassing.c
index c2f4bf6..f62be62 100644
--- a/tests/fdpassing.c
+++ b/tests/fdpassing.c
@@ -45,23 +45,28 @@ cmd_echo (assuan_context_t ctx, char *line)
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 @@ register_commands (assuan_context_t ctx)
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 @@ server (int fd)
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,52 +145,50 @@ server (int fd)
/* 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);
-
- rc = assuan_domain_connect (&ctx, fd, (pid_t)(-1));
- if (rc)
- {
- log_error ("assuan_domain_connect failed: %s\n", assuan_strerror (rc));
- return -1;
- }
+ log_info ("client started\n");
- fp = fopen ("/etc/motd", "r");
- if (!fp)
+ for (i=0; i < 8; i++)
{
- 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;
- }
-
- 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;
- }
+ 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);
+ 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_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, "ECHO", NULL, NULL, NULL, NULL, NULL, NULL);
+ if (rc)
+ {
+ log_error ("sending ECHO failed: %s\n", assuan_strerror (rc));
+ return -1;
+ }
}
- sleep (100);
+ /* Give us some time to check with lsof that all descriptors are closed. */
+/* sleep (10); */
assuan_disconnect (ctx);
return 0;
@@ -204,8 +207,12 @@ main (int argc, char **argv)
{
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 @@ main (int argc, char **argv)
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 @@ main (int argc, char **argv)
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)
+ {
+ arglist[0] = "fdpassing";
+ arglist[1] = "--server";
+ arglist[2] = verbose? "--verbose":NULL;
+ arglist[3] = NULL;
+ }
+ 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
{
- log_info ("waiting for server to terminate...\n");
- waitpid (pid, NULL, 0);
+ if (client (ctx))
+ {
+ log_info ("waiting for server to terminate...\n");
+ assuan_disconnect (ctx);
+ }
+ log_info ("client finished\n");
}
- log_info ("client finished\n");
}
return errorcount? 1:0;
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-gnupg/libassuan.git
More information about the Pkg-gnupg-commit
mailing list