commit 699b60db566aeba8f6265e7d474f2686d5ca5b83
Author: Nathan Freitas <nathan(a)freitas.net>
Date: Wed Dec 30 09:52:56 2015 -0500
add linancillary for badvpn tun2socks update for DNS
---
jni/libancillary/API | 139 ++++++++++++++++++++++++++++++++++++++++++
jni/libancillary/COPYING | 21 +++++++
jni/libancillary/Makefile | 73 ++++++++++++++++++++++
jni/libancillary/ancillary.h | 131 +++++++++++++++++++++++++++++++++++++++
jni/libancillary/fd_recv.c | 98 +++++++++++++++++++++++++++++
jni/libancillary/fd_send.c | 92 ++++++++++++++++++++++++++++
jni/libancillary/test.c | 112 ++++++++++++++++++++++++++++++++++
7 files changed, 666 insertions(+)
diff --git a/jni/libancillary/API b/jni/libancillary/API
new file mode 100644
index 0000000..b558995
--- /dev/null
+++ b/jni/libancillary/API
@@ -0,0 +1,139 @@
+ This library provide an easy interface to the black magic that can be done
+ on Unix domain sockets, like passing file descriptors from one process to
+ another.
+
+ Programs that uses this library should include the ancillary.h header file.
+ Nothing else is required.
+
+ All functions of this library require the following header:
+
+ #include <ancillary.h>
+
+ At this time, the only ancillary data defined by the Single Unix
+ Specification (v3) is file descriptors.
+
+Passing file descriptors
+
+ int ancil_send_fd(socket, file_descriptor)
+ int socket: the Unix socket
+ int file_descriptor: the file descriptor
+ Return value: 0 for success, -1 for failure.
+
+ Sends one file descriptor on a socket.
+ In case of failure, errno is set; the possible values are the ones of the
+ sendmsg(2) system call.
+
+
+ int ancil_recv_fd(socket, file_descriptor)
+ int socket: the Unix socket
+ int *file_descriptor: pointer to the returned file descriptor
+ Return value: 0 for success, -1 for failure
+
+ Receives one file descriptor from a socket.
+ In case of success, the file descriptor is stored in the integer pointed
+ to by file_descriptor.
+ In case of failure, errno is set; the possible values are the ones of the
+ recvmsg(2) system call.
+ The behavior is undefined if the recv_fd does not match a send_fd* on the
+ other side.
+
+
+ int ancil_send_fds(socket, file_descriptors, num_file_descriptors)
+ int socket: the Unix socket
+ const int *file_descriptors: array of file descriptors
+ unsigned num_file_descriptors: number of file descriptors
+ Return value: 0 for success, -1 for failure
+
+ Sends several file descriptors on a socket.
+ In case of failure, errno is set; the possible values are the ones of the
+ sendmsg(2) system call.
+ The maximum number of file descriptors that can be sent using this
+ function is ANCIL_MAX_N_FDS; the behavior is undefined in case of
+ overflow, probably a stack corruption.
+
+
+ int ancil_recv_fds(socket, file_descriptors, num_file_descriptors)
+ int socket: the Unix socket
+ int *file_descriptors: return array of file descriptors
+ unsigned num_file_descriptors: number of file descriptors
+ Return value: number of received fd for success, -1 for failure
+
+ Receives several file descriptors from a socket, no more than
+ num_file_descriptors.
+ In case of success, the received file descriptors are stored in the array
+ pointed to by file_descriptors.
+ In case of failure, errno is set; the possible values are the ones of the
+ recvmsg(2) system call.
+ The maximum number of file descriptors that can be received using this
+ function is ANCIL_MAX_N_FDS; the behavior is undefined in case of
+ overflow, probably a stack corruption.
+ The behavior is undefined if the recv_fds does not match a send_fd* on
+ the other side, or if the number of received file descriptors is more than
+ num_file_descriptors.
+
+
+ int ancil_send_fds_with_buffer(socket, fds, num, buffer)
+ int socket: the Unix socket
+ const int *fds: array of file descriptors
+ unsigned num: number of file descriptors
+ void *buffer: buffer to hold the system data structures
+ Return value: 0 for success, -1 for failure
+
+ Sends several file descriptors on a socket.
+ In case of failure, errno is set; the possible values are the ones of the
+ sendmsg(2) system call.
+ The buffer argument must point to a memory area large enough to hold the
+ system data structures, see ANCIL_FD_BUFFER.
+
+
+ int ancil_send_fds_with_buffer(socket, fds, num, buffer)
+ int socket: the Unix socket
+ int *fds: return array of file descriptors
+ unsigned num: number of file descriptors
+ void *buffer: buffer to hold the system data structures
+ Return value: number of received fd for success, -1 for failure
+
+ Receives several file descriptors from a socket, no more than
+ num_file_descriptors.
+ In case of success, the received file descriptors are stored in the array
+ pointed to by file_descriptors.
+ In case of failure, errno is set; the possible values are the ones of the
+ recvmsg(2) system call.
+ The behavior is undefined if the recv_fds does not match a send_fd* on
+ the other side, or if the number of received file descriptors is more than
+ num_file_descriptors.
+ The buffer argument must point to a memory area large enough to hold the
+ system data structures, see ANCIL_FD_BUFFER.
+
+
+ ANCIL_MAX_N_FDS
+
+ Maximum number of file descriptors that can be sent with the sent_fds and
+ recv_fds functions. If you have to send more at once, use the
+ *_with_buffer versions. The value is enough to send "quite a few" file
+ descriptors.
+
+
+ ANCIL_FD_BUFFER(n)
+ int n: number of file descriptors
+
+ Expands to a structure data type large enough to hold the system data
+ structures for n file descriptors. So the address of a variable declared
+ of type ANCIL_FD_BUFFER(n) is suitable as the buffer argument for
+ *_with_buffer on n file descriptors.
+ To use this macro, you need <sys/types.h> and <sys/socket.h>. Bevare: with
+ Solaris, the _XPG4_2 macro must be defined before sys/socket is included.
+
+
+Tuning the compilation
+
+ This library is designed to be included in projects, not installed in
+ /usr/lib. If your project does not use some of the functions, the
+ TUNE_OPTS variable in the Makefile allows not to build them. It is a list
+ of proprocessor options:
+
+ -DNDEBUG: turn assertions off (see assert(3))
+ -DSPARE_SEND_FDS: do not build ancil_send_fds
+ -DSPARE_SEND_FD: do not build ancil_send_fd
+ -DSPARE_RECV_FDS: do not build ancil_recv_fds
+ -DSPARE_RECV_FD: do not build ancil_recv_fd
diff --git a/jni/libancillary/COPYING b/jni/libancillary/COPYING
new file mode 100644
index 0000000..5bcd9c2
--- /dev/null
+++ b/jni/libancillary/COPYING
@@ -0,0 +1,21 @@
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/jni/libancillary/Makefile b/jni/libancillary/Makefile
new file mode 100644
index 0000000..3d32533
--- /dev/null
+++ b/jni/libancillary/Makefile
@@ -0,0 +1,73 @@
+###########################################################################
+# libancillary - black magic on Unix domain sockets
+# (C) Nicolas George
+# Makefile - guess what
+###########################################################################
+
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. The name of the author may not be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+# EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+CC=gcc
+CFLAGS=-Wall -g -O2
+LDFLAGS=
+LIBS=
+AR=ar
+RANLIB=ranlib
+RM=rm
+CP=cp
+MKDIR=mkdir
+TAR=tar
+GZIP=gzip -9
+
+NAME=libancillary
+DISTRIBUTION=API COPYING Makefile ancillary.h fd_send.c fd_recv.c test.c
+VERSION=0.9.1
+
+OBJECTS=fd_send.o fd_recv.o
+
+TUNE_OPTS=-DNDEBUG
+#TUNE_OPTS=-DNDEBUG \
+ -DSPARE_SEND_FDS -DSPARE_SEND_FD -DSPARE_RECV_FDS -DSPARE_RECV_FD
+
+.c.o:
+ $(CC) -c $(CFLAGS) $(TUNE_OPTS) $<
+
+all: libancillary.a
+
+libancillary.a: $(OBJECTS)
+ $(AR) cr $@ $(OBJECTS)
+ $(RANLIB) $@
+
+fd_send.o: ancillary.h
+fd_recv.o: ancillary.h
+
+test: test.c libancillary.a
+ $(CC) -o $@ $(CFLAGS) $(LDFLAGS) -L. test.c -lancillary $(LIBS)
+
+clean:
+ -$(RM) -f *.o *.a test
+
+dist:
+ $(MKDIR) $(NAME)-$(VERSION)
+ $(CP) $(DISTRIBUTION) $(NAME)-$(VERSION)
+ $(TAR) -cf - $(NAME)-$(VERSION) | $(GZIP) > $(NAME)-$(VERSION).tar.gz
+ $(RM) -rf $(NAME)-$(VERSION)
diff --git a/jni/libancillary/ancillary.h b/jni/libancillary/ancillary.h
new file mode 100644
index 0000000..636d867
--- /dev/null
+++ b/jni/libancillary/ancillary.h
@@ -0,0 +1,131 @@
+/***************************************************************************
+ * libancillary - black magic on Unix domain sockets
+ * (C) Nicolas George
+ * ancillary.c - public header
+ ***************************************************************************/
+
+/*
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ANCILLARY_H__
+#define ANCILLARY_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/***************************************************************************
+ * Start of the readable part.
+ ***************************************************************************/
+
+#define ANCIL_MAX_N_FDS 960
+/*
+ * Maximum number of fds that can be sent or received using the "esay"
+ * functions; this is so that all can fit in one page.
+ */
+
+extern int
+ancil_send_fds_with_buffer(int, const int *, unsigned, void *);
+/*
+ * ancil_send_fds_with_buffer(sock, n_fds, fds, buffer)
+ *
+ * Sends the file descriptors in the array pointed by fds, of length n_fds
+ * on the socket sock.
+ * buffer is a writeable memory area large enough to hold the required data
+ * structures.
+ * Returns: -1 and errno in case of error, 0 in case of success.
+ */
+
+extern int
+ancil_recv_fds_with_buffer(int, int *, unsigned, void *);
+/*
+ * ancil_recv_fds_with_buffer(sock, n_fds, fds, buffer)
+ *
+ * Receives *n_fds file descriptors into the array pointed by fds
+ * from the socket sock.
+ * buffer is a writeable memory area large enough to hold the required data
+ * structures.
+ * Returns: -1 and errno in case of error, the actual number of received fd
+ * in case of success
+ */
+
+#define ANCIL_FD_BUFFER(n) \
+ struct { \
+ struct cmsghdr h; \
+ int fd[n]; \
+ }
+/* ANCIL_FD_BUFFER(n)
+ *
+ * A structure type suitable to be used as buffer for n file descriptors.
+ * Requires <sys/socket.h>.
+ * Example:
+ * ANCIL_FD_BUFFER(42) buffer;
+ * ancil_recv_fds_with_buffer(sock, 42, my_fds, &buffer);
+ */
+
+extern int
+ancil_send_fds(int, const int *, unsigned);
+/*
+ * ancil_send_fds(sock, n_fds, fds)
+ *
+ * Sends the file descriptors in the array pointed by fds, of length n_fds
+ * on the socket sock.
+ * n_fds must not be greater than ANCIL_MAX_N_FDS.
+ * Returns: -1 and errno in case of error, 0 in case of success.
+ */
+
+extern int
+ancil_recv_fds(int, int *, unsigned);
+/*
+ * ancil_recv_fds(sock, n_fds, fds)
+ *
+ * Receives *n_fds file descriptors into the array pointed by fds
+ * from the socket sock.
+ * *n_fds must not be greater than ANCIL_MAX_N_FDS.
+ * Returns: -1 and errno in case of error, the actual number of received fd
+ * in case of success.
+ */
+
+
+extern int
+ancil_send_fd(int, int);
+/* ancil_recv_fd(sock, fd);
+ *
+ * Sends the file descriptor fd on the socket sock.
+ * Returns : -1 and errno in case of error, 0 in case of success.
+ */
+
+extern int
+ancil_recv_fd(int, int *);
+/* ancil_send_fd(sock, &fd);
+ *
+ * Receives the file descriptor fd from the socket sock.
+ * Returns : -1 and errno in case of error, 0 in case of success.
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ANCILLARY_H__ */
diff --git a/jni/libancillary/fd_recv.c b/jni/libancillary/fd_recv.c
new file mode 100644
index 0000000..46c2e69
--- /dev/null
+++ b/jni/libancillary/fd_recv.c
@@ -0,0 +1,98 @@
+/***************************************************************************
+ * libancillary - black magic on Unix domain sockets
+ * (C) Nicolas George
+ * fd_send.c - receiving file descriptors
+ ***************************************************************************/
+
+/*
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _XPG4_2 /* Solaris sucks */
+# define _XPG4_2
+#endif
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <assert.h>
+#if defined(__FreeBSD__)
+# include <sys/param.h> /* FreeBSD sucks */
+#endif
+
+#include "ancillary.h"
+
+int
+ancil_recv_fds_with_buffer(int sock, int *fds, unsigned n_fds, void *buffer)
+{
+ struct msghdr msghdr;
+ char nothing;
+ struct iovec nothing_ptr;
+ struct cmsghdr *cmsg;
+ int i;
+
+ nothing_ptr.iov_base = ¬hing;
+ nothing_ptr.iov_len = 1;
+ msghdr.msg_name = NULL;
+ msghdr.msg_namelen = 0;
+ msghdr.msg_iov = ¬hing_ptr;
+ msghdr.msg_iovlen = 1;
+ msghdr.msg_flags = 0;
+ msghdr.msg_control = buffer;
+ msghdr.msg_controllen = sizeof(struct cmsghdr) + sizeof(int) * n_fds;
+ cmsg = CMSG_FIRSTHDR(&msghdr);
+ cmsg->cmsg_len = msghdr.msg_controllen;
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ for(i = 0; i < n_fds; i++)
+ ((int *)CMSG_DATA(cmsg))[i] = -1;
+
+ if(recvmsg(sock, &msghdr, 0) < 0)
+ return(-1);
+ for(i = 0; i < n_fds; i++)
+ fds[i] = ((int *)CMSG_DATA(cmsg))[i];
+ n_fds = (msghdr.msg_controllen - sizeof(struct cmsghdr)) / sizeof(int);
+ return(n_fds);
+}
+
+#ifndef SPARE_RECV_FDS
+int
+ancil_recv_fds(int sock, int *fd, unsigned n_fds)
+{
+ ANCIL_FD_BUFFER(ANCIL_MAX_N_FDS) buffer;
+
+ assert(n_fds <= ANCIL_MAX_N_FDS);
+ return(ancil_recv_fds_with_buffer(sock, fd, n_fds, &buffer));
+}
+#endif /* SPARE_RECV_FDS */
+
+#ifndef SPARE_RECV_FD
+int
+ancil_recv_fd(int sock, int *fd)
+{
+ ANCIL_FD_BUFFER(1) buffer;
+
+ return(ancil_recv_fds_with_buffer(sock, fd, 1, &buffer) == 1 ? 0 : -1);
+}
+#endif /* SPARE_RECV_FD */
diff --git a/jni/libancillary/fd_send.c b/jni/libancillary/fd_send.c
new file mode 100644
index 0000000..01de87f
--- /dev/null
+++ b/jni/libancillary/fd_send.c
@@ -0,0 +1,92 @@
+/***************************************************************************
+ * libancillary - black magic on Unix domain sockets
+ * (C) Nicolas George
+ * fd_send.c - sending file descriptors
+ ***************************************************************************/
+
+/*
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _XPG4_2 /* Solaris sucks */
+# define _XPG4_2
+#endif
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <assert.h>
+#if defined(__FreeBSD__)
+# include <sys/param.h> /* FreeBSD sucks */
+#endif
+
+#include "ancillary.h"
+
+int
+ancil_send_fds_with_buffer(int sock, const int *fds, unsigned n_fds, void *buffer)
+{
+ struct msghdr msghdr;
+ char nothing = '!';
+ struct iovec nothing_ptr;
+ struct cmsghdr *cmsg;
+ int i;
+
+ nothing_ptr.iov_base = ¬hing;
+ nothing_ptr.iov_len = 1;
+ msghdr.msg_name = NULL;
+ msghdr.msg_namelen = 0;
+ msghdr.msg_iov = ¬hing_ptr;
+ msghdr.msg_iovlen = 1;
+ msghdr.msg_flags = 0;
+ msghdr.msg_control = buffer;
+ msghdr.msg_controllen = sizeof(struct cmsghdr) + sizeof(int) * n_fds;
+ cmsg = CMSG_FIRSTHDR(&msghdr);
+ cmsg->cmsg_len = msghdr.msg_controllen;
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ for(i = 0; i < n_fds; i++)
+ ((int *)CMSG_DATA(cmsg))[i] = fds[i];
+ return(sendmsg(sock, &msghdr, 0) >= 0 ? 0 : -1);
+}
+
+#ifndef SPARE_SEND_FDS
+int
+ancil_send_fds(int sock, const int *fds, unsigned n_fds)
+{
+ ANCIL_FD_BUFFER(ANCIL_MAX_N_FDS) buffer;
+
+ assert(n_fds <= ANCIL_MAX_N_FDS);
+ return(ancil_send_fds_with_buffer(sock, fds, n_fds, &buffer));
+}
+#endif /* SPARE_SEND_FDS */
+
+#ifndef SPARE_SEND_FD
+int
+ancil_send_fd(int sock, int fd)
+{
+ ANCIL_FD_BUFFER(1) buffer;
+
+ return(ancil_send_fds_with_buffer(sock, &fd, 1, &buffer));
+}
+#endif /* SPARE_SEND_FD */
diff --git a/jni/libancillary/test.c b/jni/libancillary/test.c
new file mode 100644
index 0000000..d3c1fda
--- /dev/null
+++ b/jni/libancillary/test.c
@@ -0,0 +1,112 @@
+/***************************************************************************
+ * libancillary - black magic on Unix domain sockets
+ * (C) Nicolas George
+ * test.c - testing and example program
+ ***************************************************************************/
+
+/*
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <sys/socket.h>
+#include "ancillary.h"
+
+void child_process(int sock)
+{
+ int fd;
+ int fds[3], nfds;
+ char b[] = "This is on the received fd!\n";
+
+ if(ancil_recv_fd(sock, &fd)) {
+ perror("ancil_recv_fd");
+ exit(1);
+ } else {
+ printf("Received fd: %d\n", fd);
+ }
+ write(fd, b, sizeof(b));
+ close(fd);
+ sleep(2);
+
+ nfds = ancil_recv_fds(sock, fds, 3);
+ if(nfds < 0) {
+ perror("ancil_recv_fds");
+ exit(1);
+ } else {
+ printf("Received %d/3 fds : %d %d %d.\n", nfds,
+ fds[0], fds[1], fds[2]);
+ }
+}
+
+void parent_process(int sock)
+{
+ int fds[2] = { 1, 2 };
+
+ if(ancil_send_fd(sock, 1)) {
+ perror("ancil_send_fd");
+ exit(1);
+ } else {
+ printf("Sent fd.\n");
+ }
+ sleep(1);
+
+ if(ancil_send_fds(sock, fds, 2)) {
+ perror("ancil_send_fds");
+ exit(1);
+ } else {
+ printf("Sent two fds.\n");
+ }
+}
+
+int main(void)
+{
+ int sock[2];
+
+ if(socketpair(PF_UNIX, SOCK_STREAM, 0, sock)) {
+ perror("socketpair");
+ exit(1);
+ } else {
+ printf("Established socket pair: (%d, %d)\n", sock[0], sock[1]);
+ }
+
+ switch(fork()) {
+ case 0:
+ close(sock[0]);
+ child_process(sock[1]);
+ break;
+ case -1:
+ perror("fork");
+ exit(1);
+ default:
+ close(sock[1]);
+ parent_process(sock[0]);
+ wait(NULL);
+ break;
+ }
+ return(0);
+}