[PATCH] prepare streams based messaging

Volker Lendecke Volker.Lendecke at SerNet.DE
Fri May 27 15:01:20 UTC 2016


Hi!

Attached find two patches: The first is a set of patches preparing the
second one. "look" cleans up some dependencies, making some
infrastructure more generally useful. I'd like to put that in now.
Review appreciated!

The second one, "tfd", is the start of what I've talked about @
sambaxp. It's the stream socket introducer. Our plan is to also use it
for ctdb communication, I've already done some changes after talking
to Amitay about it. So, not really used yet, but if you're curious,
feel free to take a look :-)

Thanks, Volker

-- 
SerNet GmbH, Bahnhofsallee 1b, 37081 Göttingen
phone: +49-551-370000-0, fax: +49-551-370000-9
AG Göttingen, HRB 2816, GF: Dr. Johannes Loxen
http://www.sernet.de, mailto:kontakt at sernet.de

SerNet & BSI laden ein: 29. Juni 2016,
2. IT-Grundschutztag 2016, BPA Berlin.
Anmeldung: https://www.sernet.de/gstag
-------------- next part --------------
From 51c3ec668e10bdb6a6e49c999c1422b4adfb3c73 Mon Sep 17 00:00:00 2001
From: Amitay Isaacs <amitay at gmail.com>
Date: Sun, 15 May 2016 21:43:26 +1000
Subject: [PATCH 1/7] lib/async_req: Reduce the dependency to tevent_unix_util

Signed-off-by: Amitay Isaacs <amitay at gmail.com>
Reviewed-by: Volker Lendecke <vl at samba.org>
---
 lib/async_req/wscript_build | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/async_req/wscript_build b/lib/async_req/wscript_build
index bf79fdd..dcfc699 100644
--- a/lib/async_req/wscript_build
+++ b/lib/async_req/wscript_build
@@ -4,7 +4,7 @@
 bld.SAMBA_SUBSYSTEM('LIBASYNC_REQ',
 	source='async_sock.c',
 	public_deps='talloc tevent iov_buf',
-	deps='tevent-util socket-blocking'
+	deps='tevent-unix-util socket-blocking'
 	)
 
 bld.SAMBA_BINARY('async_connect_send_test',
-- 
2.1.4


From 6d47760c4af3ceb319bf1c5f44a4ebd4a70691e4 Mon Sep 17 00:00:00 2001
From: Amitay Isaacs <amitay at gmail.com>
Date: Sun, 15 May 2016 21:43:57 +1000
Subject: [PATCH 2/7] lib/poll_funcs: Build as SAMBA_SUBSYSTEM

Signed-off-by: Amitay Isaacs <amitay at gmail.com>
Reviewed-by: Volker Lendecke <vl at samba.org>
---
 source3/lib/poll_funcs/wscript_build | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/source3/lib/poll_funcs/wscript_build b/source3/lib/poll_funcs/wscript_build
index ab24814..df9a298 100644
--- a/source3/lib/poll_funcs/wscript_build
+++ b/source3/lib/poll_funcs/wscript_build
@@ -1,5 +1,5 @@
 #!/usr/bin/env python
 
-bld.SAMBA3_SUBSYSTEM('POLL_FUNCS_TEVENT',
-                     source='poll_funcs_tevent.c',
-		     deps='tevent')
+bld.SAMBA_SUBSYSTEM('POLL_FUNCS_TEVENT',
+                    source='poll_funcs_tevent.c',
+                    deps='tevent')
-- 
2.1.4


From eb76a28ec4856343b77106bb97663057505cc6dc Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Sat, 14 May 2016 09:45:49 +0200
Subject: [PATCH 3/7] lib: Move msghdr to lib/util/

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 lib/util/msghdr.c               | 260 ++++++++++++++++++++++++++++++++++++++++
 lib/util/msghdr.h               |  42 +++++++
 lib/util/wscript_build          |   6 +
 source3/lib/msghdr.c            | 260 ----------------------------------------
 source3/lib/msghdr.h            |  42 -------
 source3/lib/unix_msg/unix_msg.c |   2 +-
 source3/modules/vfs_aio_fork.c  |   2 +-
 source3/wscript_build           |   5 -
 8 files changed, 310 insertions(+), 309 deletions(-)
 create mode 100644 lib/util/msghdr.c
 create mode 100644 lib/util/msghdr.h
 delete mode 100644 source3/lib/msghdr.c
 delete mode 100644 source3/lib/msghdr.h

diff --git a/lib/util/msghdr.c b/lib/util/msghdr.c
new file mode 100644
index 0000000..1aeadfc
--- /dev/null
+++ b/lib/util/msghdr.c
@@ -0,0 +1,260 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Copyright (C) Volker Lendecke 2014
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "replace.h"
+#include "lib/util/msghdr.h"
+#include "lib/util/iov_buf.h"
+#include <sys/socket.h>
+
+#if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
+
+ssize_t msghdr_prep_fds(struct msghdr *msg, uint8_t *buf, size_t bufsize,
+			const int *fds, size_t num_fds)
+{
+	size_t fds_size = sizeof(int) * MIN(num_fds, INT8_MAX);
+	size_t cmsg_len = CMSG_LEN(fds_size);
+	size_t cmsg_space = CMSG_SPACE(fds_size);
+	struct cmsghdr *cmsg;
+	void *fdptr;
+
+	if (num_fds == 0) {
+		if (msg != NULL) {
+			msg->msg_control = NULL;
+			msg->msg_controllen = 0;
+		}
+		return 0;
+	}
+	if (num_fds > INT8_MAX) {
+		return -1;
+	}
+	if ((msg == NULL) || (cmsg_space > bufsize)) {
+		return cmsg_space;
+	}
+
+	msg->msg_control = buf;
+	msg->msg_controllen = cmsg_space;
+
+	cmsg = CMSG_FIRSTHDR(msg);
+	cmsg->cmsg_level = SOL_SOCKET;
+	cmsg->cmsg_type = SCM_RIGHTS;
+	cmsg->cmsg_len = cmsg_len;
+	fdptr = CMSG_DATA(cmsg);
+	memcpy(fdptr, fds, fds_size);
+	msg->msg_controllen = cmsg->cmsg_len;
+
+	return cmsg_space;
+}
+
+size_t msghdr_prep_recv_fds(struct msghdr *msg, uint8_t *buf, size_t bufsize,
+			    size_t num_fds)
+{
+	size_t ret = CMSG_SPACE(sizeof(int) * num_fds);
+
+	if (bufsize < ret) {
+		return ret;
+	}
+	if (msg != NULL) {
+		if (num_fds != 0) {
+			msg->msg_control = buf;
+			msg->msg_controllen = ret;
+		} else {
+			msg->msg_control = NULL;
+			msg->msg_controllen = 0;
+		}
+	}
+	return ret;
+}
+
+size_t msghdr_extract_fds(struct msghdr *msg, int *fds, size_t fds_size)
+{
+	struct cmsghdr *cmsg;
+	size_t num_fds;
+
+	for(cmsg = CMSG_FIRSTHDR(msg);
+	    cmsg != NULL;
+	    cmsg = CMSG_NXTHDR(msg, cmsg))
+	{
+		if ((cmsg->cmsg_type == SCM_RIGHTS) &&
+		    (cmsg->cmsg_level == SOL_SOCKET)) {
+			break;
+		}
+	}
+
+	if (cmsg == NULL) {
+		return 0;
+	}
+
+	num_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
+
+	if ((num_fds != 0) && (fds != NULL) && (fds_size >= num_fds)) {
+		memcpy(fds, CMSG_DATA(cmsg), num_fds * sizeof(int));
+	}
+
+	return num_fds;
+}
+
+#elif defined(HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS)
+
+ssize_t msghdr_prep_fds(struct msghdr *msg, uint8_t *buf, size_t bufsize,
+			const int *fds, size_t num_fds)
+{
+	size_t needed;
+
+	if (num_fds > INT8_MAX) {
+		return -1;
+	}
+
+	needed = sizeof(int) * num_fds;
+
+	if ((msg == NULL) || (needed > bufsize)) {
+		return needed;
+	}
+
+	memcpy(buf, fds, needed);
+
+	msg->msg_accrights = (caddr_t) buf;
+	msg->msg_accrightslen = needed;
+
+	return needed;
+}
+
+size_t msghdr_prep_recv_fds(struct msghdr *msg, uint8_t *buf, size_t bufsize,
+			    size_t num_fds)
+{
+	size_t ret = num_fds * sizeof(int);
+
+	if (bufsize < ret) {
+		return ret;
+	}
+
+	if (msg != NULL) {
+		if (num_fds != 0) {
+			msg->msg_accrights = (caddr_t) buf;
+			msg->msg_accrightslen = ret;
+		} else {
+			msg->msg_accrights = NULL;
+			msg->msg_accrightslen = 0;
+		}
+	}
+	return ret;
+}
+
+size_t msghdr_extract_fds(struct msghdr *msg, int *fds, size_t fds_size)
+{
+	size_t num_fds = msg->msg_accrightslen / sizeof(int);
+
+	if ((fds != 0) && (num_fds <= fds_size)) {
+		memcpy(fds, msg->msg_accrights, msg->msg_accrightslen);
+	}
+
+	return num_fds;
+}
+
+#else
+
+ssize_t msghdr_prep_fds(struct msghdr *msg, uint8_t *buf, size_t bufsize,
+			const int *fds, size_t num_fds)
+{
+	return -1;
+}
+
+size_t msghdr_prep_recv_fds(struct msghdr *msg, uint8_t *buf, size_t bufsize,
+			    size_t num_fds)
+{
+	return 0;
+}
+
+size_t msghdr_extract_fds(struct msghdr *msg, int *fds, size_t fds_size)
+{
+	return 0;
+}
+
+#endif
+
+struct msghdr_buf {
+	struct msghdr msg;
+	struct sockaddr_storage addr;
+	struct iovec iov;
+	uint8_t buf[];
+};
+
+ssize_t msghdr_copy(struct msghdr_buf *msg, size_t msgsize,
+		    const void *addr, socklen_t addrlen,
+		    const struct iovec *iov, int iovcnt,
+		    const int *fds, size_t num_fds)
+{
+	ssize_t fd_len;
+	size_t iov_len, needed, bufsize;
+
+	bufsize = (msgsize > offsetof(struct msghdr_buf, buf)) ?
+		msgsize - offsetof(struct msghdr_buf, buf) : 0;
+
+	fd_len = msghdr_prep_fds(&msg->msg, msg->buf, bufsize, fds, num_fds);
+
+	if (fd_len == -1) {
+		return -1;
+	}
+
+	if (bufsize >= fd_len) {
+		bufsize -= fd_len;
+	} else {
+		bufsize = 0;
+	}
+
+	if (msg != NULL) {
+
+		if (addr != NULL) {
+			if (addrlen > sizeof(struct sockaddr_storage)) {
+				errno = EMSGSIZE;
+				return -1;
+			}
+			memcpy(&msg->addr, addr, addrlen);
+			msg->msg.msg_name = &msg->addr;
+			msg->msg.msg_namelen = addrlen;
+		} else {
+			msg->msg.msg_name = NULL;
+			msg->msg.msg_namelen = 0;
+		}
+
+		msg->iov.iov_base = msg->buf + fd_len;
+		msg->iov.iov_len = iov_buf(
+			iov, iovcnt, msg->iov.iov_base, bufsize);
+		iov_len = msg->iov.iov_len;
+
+		msg->msg.msg_iov = &msg->iov;
+		msg->msg.msg_iovlen = 1;
+	} else {
+		iov_len = iov_buflen(iov, iovcnt);
+	}
+
+	needed = offsetof(struct msghdr_buf, buf) + fd_len;
+	if (needed < fd_len) {
+		return -1;
+	}
+	needed += iov_len;
+	if (needed < iov_len) {
+		return -1;
+	}
+
+	return needed;
+}
+
+struct msghdr *msghdr_buf_msghdr(struct msghdr_buf *msg)
+{
+	return &msg->msg;
+}
diff --git a/lib/util/msghdr.h b/lib/util/msghdr.h
new file mode 100644
index 0000000..c1676d2
--- /dev/null
+++ b/lib/util/msghdr.h
@@ -0,0 +1,42 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Copyright (C) Volker Lendecke 2014
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __LIB_MSGHDR_H__
+#define __LIB_MSGHDR_H__
+
+#include <stddef.h>
+#include <stdint.h>
+#include <sys/uio.h>
+#include <sys/socket.h>
+
+ssize_t msghdr_prep_fds(struct msghdr *msg, uint8_t *buf, size_t bufsize,
+			const int *fds, size_t num_fds);
+
+struct msghdr_buf;
+
+ssize_t msghdr_copy(struct msghdr_buf *msg, size_t msgsize,
+		    const void *addr, socklen_t addrlen,
+		    const struct iovec *iov, int iovcnt,
+		    const int *fds, size_t num_fds);
+struct msghdr *msghdr_buf_msghdr(struct msghdr_buf *msg);
+
+size_t msghdr_prep_recv_fds(struct msghdr *msg, uint8_t *buf, size_t bufsize,
+			    size_t num_fds);
+size_t msghdr_extract_fds(struct msghdr *msg, int *fds, size_t num_fds);
+
+#endif
diff --git a/lib/util/wscript_build b/lib/util/wscript_build
index aa0586c..0d67c10 100755
--- a/lib/util/wscript_build
+++ b/lib/util/wscript_build
@@ -189,6 +189,12 @@ if not bld.env.SAMBA_UTIL_CORE_ONLY:
                       local_include=False,
                       private_library=True)
 
+    bld.SAMBA_LIBRARY('msghdr',
+                      source='msghdr.c',
+                      deps='replace iov_buf',
+                      local_include=False,
+                      private_library=True)
+
     bld.SAMBA3_LIBRARY('sys_rw',
                        source='sys_rw.c sys_rw_data.c',
                        deps='replace iov_buf',
diff --git a/source3/lib/msghdr.c b/source3/lib/msghdr.c
deleted file mode 100644
index 2aa2f2e..0000000
--- a/source3/lib/msghdr.c
+++ /dev/null
@@ -1,260 +0,0 @@
-/*
- * Unix SMB/CIFS implementation.
- * Copyright (C) Volker Lendecke 2014
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "replace.h"
-#include "lib/msghdr.h"
-#include "lib/util/iov_buf.h"
-#include <sys/socket.h>
-
-#if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
-
-ssize_t msghdr_prep_fds(struct msghdr *msg, uint8_t *buf, size_t bufsize,
-			const int *fds, size_t num_fds)
-{
-	size_t fds_size = sizeof(int) * MIN(num_fds, INT8_MAX);
-	size_t cmsg_len = CMSG_LEN(fds_size);
-	size_t cmsg_space = CMSG_SPACE(fds_size);
-	struct cmsghdr *cmsg;
-	void *fdptr;
-
-	if (num_fds == 0) {
-		if (msg != NULL) {
-			msg->msg_control = NULL;
-			msg->msg_controllen = 0;
-		}
-		return 0;
-	}
-	if (num_fds > INT8_MAX) {
-		return -1;
-	}
-	if ((msg == NULL) || (cmsg_space > bufsize)) {
-		return cmsg_space;
-	}
-
-	msg->msg_control = buf;
-	msg->msg_controllen = cmsg_space;
-
-	cmsg = CMSG_FIRSTHDR(msg);
-	cmsg->cmsg_level = SOL_SOCKET;
-	cmsg->cmsg_type = SCM_RIGHTS;
-	cmsg->cmsg_len = cmsg_len;
-	fdptr = CMSG_DATA(cmsg);
-	memcpy(fdptr, fds, fds_size);
-	msg->msg_controllen = cmsg->cmsg_len;
-
-	return cmsg_space;
-}
-
-size_t msghdr_prep_recv_fds(struct msghdr *msg, uint8_t *buf, size_t bufsize,
-			    size_t num_fds)
-{
-	size_t ret = CMSG_SPACE(sizeof(int) * num_fds);
-
-	if (bufsize < ret) {
-		return ret;
-	}
-	if (msg != NULL) {
-		if (num_fds != 0) {
-			msg->msg_control = buf;
-			msg->msg_controllen = ret;
-		} else {
-			msg->msg_control = NULL;
-			msg->msg_controllen = 0;
-		}
-	}
-	return ret;
-}
-
-size_t msghdr_extract_fds(struct msghdr *msg, int *fds, size_t fds_size)
-{
-	struct cmsghdr *cmsg;
-	size_t num_fds;
-
-	for(cmsg = CMSG_FIRSTHDR(msg);
-	    cmsg != NULL;
-	    cmsg = CMSG_NXTHDR(msg, cmsg))
-	{
-		if ((cmsg->cmsg_type == SCM_RIGHTS) &&
-		    (cmsg->cmsg_level == SOL_SOCKET)) {
-			break;
-		}
-	}
-
-	if (cmsg == NULL) {
-		return 0;
-	}
-
-	num_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
-
-	if ((num_fds != 0) && (fds != NULL) && (fds_size >= num_fds)) {
-		memcpy(fds, CMSG_DATA(cmsg), num_fds * sizeof(int));
-	}
-
-	return num_fds;
-}
-
-#elif defined(HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS)
-
-ssize_t msghdr_prep_fds(struct msghdr *msg, uint8_t *buf, size_t bufsize,
-			const int *fds, size_t num_fds)
-{
-	size_t needed;
-
-	if (num_fds > INT8_MAX) {
-		return -1;
-	}
-
-	needed = sizeof(int) * num_fds;
-
-	if ((msg == NULL) || (needed > bufsize)) {
-		return needed;
-	}
-
-	memcpy(buf, fds, needed);
-
-	msg->msg_accrights = (caddr_t) buf;
-	msg->msg_accrightslen = needed;
-
-	return needed;
-}
-
-size_t msghdr_prep_recv_fds(struct msghdr *msg, uint8_t *buf, size_t bufsize,
-			    size_t num_fds)
-{
-	size_t ret = num_fds * sizeof(int);
-
-	if (bufsize < ret) {
-		return ret;
-	}
-
-	if (msg != NULL) {
-		if (num_fds != 0) {
-			msg->msg_accrights = (caddr_t) buf;
-			msg->msg_accrightslen = ret;
-		} else {
-			msg->msg_accrights = NULL;
-			msg->msg_accrightslen = 0;
-		}
-	}
-	return ret;
-}
-
-size_t msghdr_extract_fds(struct msghdr *msg, int *fds, size_t fds_size)
-{
-	size_t num_fds = msg->msg_accrightslen / sizeof(int);
-
-	if ((fds != 0) && (num_fds <= fds_size)) {
-		memcpy(fds, msg->msg_accrights, msg->msg_accrightslen);
-	}
-
-	return num_fds;
-}
-
-#else
-
-ssize_t msghdr_prep_fds(struct msghdr *msg, uint8_t *buf, size_t bufsize,
-			const int *fds, size_t num_fds)
-{
-	return -1;
-}
-
-size_t msghdr_prep_recv_fds(struct msghdr *msg, uint8_t *buf, size_t bufsize,
-			    size_t num_fds)
-{
-	return 0;
-}
-
-size_t msghdr_extract_fds(struct msghdr *msg, int *fds, size_t fds_size)
-{
-	return 0;
-}
-
-#endif
-
-struct msghdr_buf {
-	struct msghdr msg;
-	struct sockaddr_storage addr;
-	struct iovec iov;
-	uint8_t buf[];
-};
-
-ssize_t msghdr_copy(struct msghdr_buf *msg, size_t msgsize,
-		    const void *addr, socklen_t addrlen,
-		    const struct iovec *iov, int iovcnt,
-		    const int *fds, size_t num_fds)
-{
-	ssize_t fd_len;
-	size_t iov_len, needed, bufsize;
-
-	bufsize = (msgsize > offsetof(struct msghdr_buf, buf)) ?
-		msgsize - offsetof(struct msghdr_buf, buf) : 0;
-
-	fd_len = msghdr_prep_fds(&msg->msg, msg->buf, bufsize, fds, num_fds);
-
-	if (fd_len == -1) {
-		return -1;
-	}
-
-	if (bufsize >= fd_len) {
-		bufsize -= fd_len;
-	} else {
-		bufsize = 0;
-	}
-
-	if (msg != NULL) {
-
-		if (addr != NULL) {
-			if (addrlen > sizeof(struct sockaddr_storage)) {
-				errno = EMSGSIZE;
-				return -1;
-			}
-			memcpy(&msg->addr, addr, addrlen);
-			msg->msg.msg_name = &msg->addr;
-			msg->msg.msg_namelen = addrlen;
-		} else {
-			msg->msg.msg_name = NULL;
-			msg->msg.msg_namelen = 0;
-		}
-
-		msg->iov.iov_base = msg->buf + fd_len;
-		msg->iov.iov_len = iov_buf(
-			iov, iovcnt, msg->iov.iov_base, bufsize);
-		iov_len = msg->iov.iov_len;
-
-		msg->msg.msg_iov = &msg->iov;
-		msg->msg.msg_iovlen = 1;
-	} else {
-		iov_len = iov_buflen(iov, iovcnt);
-	}
-
-	needed = offsetof(struct msghdr_buf, buf) + fd_len;
-	if (needed < fd_len) {
-		return -1;
-	}
-	needed += iov_len;
-	if (needed < iov_len) {
-		return -1;
-	}
-
-	return needed;
-}
-
-struct msghdr *msghdr_buf_msghdr(struct msghdr_buf *msg)
-{
-	return &msg->msg;
-}
diff --git a/source3/lib/msghdr.h b/source3/lib/msghdr.h
deleted file mode 100644
index c1676d2..0000000
--- a/source3/lib/msghdr.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Unix SMB/CIFS implementation.
- * Copyright (C) Volker Lendecke 2014
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __LIB_MSGHDR_H__
-#define __LIB_MSGHDR_H__
-
-#include <stddef.h>
-#include <stdint.h>
-#include <sys/uio.h>
-#include <sys/socket.h>
-
-ssize_t msghdr_prep_fds(struct msghdr *msg, uint8_t *buf, size_t bufsize,
-			const int *fds, size_t num_fds);
-
-struct msghdr_buf;
-
-ssize_t msghdr_copy(struct msghdr_buf *msg, size_t msgsize,
-		    const void *addr, socklen_t addrlen,
-		    const struct iovec *iov, int iovcnt,
-		    const int *fds, size_t num_fds);
-struct msghdr *msghdr_buf_msghdr(struct msghdr_buf *msg);
-
-size_t msghdr_prep_recv_fds(struct msghdr *msg, uint8_t *buf, size_t bufsize,
-			    size_t num_fds);
-size_t msghdr_extract_fds(struct msghdr *msg, int *fds, size_t num_fds);
-
-#endif
diff --git a/source3/lib/unix_msg/unix_msg.c b/source3/lib/unix_msg/unix_msg.c
index bcfef28..aed1f75 100644
--- a/source3/lib/unix_msg/unix_msg.c
+++ b/source3/lib/unix_msg/unix_msg.c
@@ -24,7 +24,7 @@
 #include "lib/util/dlinklist.h"
 #include "pthreadpool/pthreadpool.h"
 #include "lib/util/iov_buf.h"
-#include "lib/msghdr.h"
+#include "lib/util/msghdr.h"
 #include <fcntl.h>
 
 /*
diff --git a/source3/modules/vfs_aio_fork.c b/source3/modules/vfs_aio_fork.c
index 7d06b98..e9ba4a3 100644
--- a/source3/modules/vfs_aio_fork.c
+++ b/source3/modules/vfs_aio_fork.c
@@ -28,7 +28,7 @@
 #include "lib/util/tevent_unix.h"
 #include "lib/util/sys_rw.h"
 #include "lib/util/sys_rw_data.h"
-#include "lib/msghdr.h"
+#include "lib/util/msghdr.h"
 #include "smbprofile.h"
 
 #if !defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL) && !defined(HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS)
diff --git a/source3/wscript_build b/source3/wscript_build
index ed2424d..e348e65 100755
--- a/source3/wscript_build
+++ b/source3/wscript_build
@@ -783,11 +783,6 @@ bld.SAMBA3_SUBSYSTEM('tdb-wrap3',
                     source='lib/util_tdb.c',
                     deps='talloc samba3-util')
 
-bld.SAMBA3_LIBRARY('msghdr',
-                   source='lib/msghdr.c',
-                   deps='replace iov_buf',
-                   private_library=True)
-
 bld.SAMBA3_LIBRARY('samba3-util',
                    source='''lib/util_sec.c lib/util_str.c lib/adt_tree.c lib/util_malloc.c lib/namearray.c lib/file_id.c''',
                    deps='samba-util charset',
-- 
2.1.4


From dc3effc30a01c7fcb3d1c29807ba0d278df1a8f9 Mon Sep 17 00:00:00 2001
From: Amitay Isaacs <amitay at gmail.com>
Date: Sun, 15 May 2016 21:44:22 +1000
Subject: [PATCH 4/7] lib/util: Expose few more subsystems for standalone ctdb
 build

Signed-off-by: Amitay Isaacs <amitay at gmail.com>
Reviewed-by: Volker Lendecke <vl at samba.org>
---
 lib/util/wscript_build | 34 +++++++++++++++++-----------------
 1 file changed, 17 insertions(+), 17 deletions(-)

diff --git a/lib/util/wscript_build b/lib/util/wscript_build
index 0d67c10..e139090 100755
--- a/lib/util/wscript_build
+++ b/lib/util/wscript_build
@@ -79,6 +79,23 @@ bld.SAMBA_LIBRARY('tevent-unix-util',
                   pc_files=[],
                   vnum='0.0.1')
 
+bld.SAMBA_LIBRARY('iov_buf',
+                  source='iov_buf.c',
+                  local_include=False,
+                  private_library=True)
+
+bld.SAMBA_LIBRARY('msghdr',
+                  source='msghdr.c',
+                  deps='replace iov_buf',
+                  local_include=False,
+                  private_library=True)
+
+bld.SAMBA_LIBRARY('sys_rw',
+                  source='sys_rw.c sys_rw_data.c',
+                  deps='replace iov_buf',
+                  local_include=False,
+                  private_library=True)
+
 if not bld.env.SAMBA_UTIL_CORE_ONLY:
 
     bld.env.public_headers_skip.append('charset_compat.h')
@@ -183,20 +200,3 @@ if not bld.env.SAMBA_UTIL_CORE_ONLY:
                       deps='talloc tdb strv util_tdb tdb-wrap samba-util',
                       local_include=False,
                       private_library=True)
-
-    bld.SAMBA_LIBRARY('iov_buf',
-                      source='iov_buf.c',
-                      local_include=False,
-                      private_library=True)
-
-    bld.SAMBA_LIBRARY('msghdr',
-                      source='msghdr.c',
-                      deps='replace iov_buf',
-                      local_include=False,
-                      private_library=True)
-
-    bld.SAMBA3_LIBRARY('sys_rw',
-                       source='sys_rw.c sys_rw_data.c',
-                       deps='replace iov_buf',
-                       local_include=False,
-                       private_library=True)
-- 
2.1.4


From ab165fda1d9e0fe92281ce22a2087894b3cf62ac Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Mon, 12 Jan 2015 17:47:19 +0100
Subject: [PATCH 5/7] lib: Fix uninitialized read in msghdr_copy

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 lib/util/msghdr.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/lib/util/msghdr.c b/lib/util/msghdr.c
index 1aeadfc..ceff218 100644
--- a/lib/util/msghdr.c
+++ b/lib/util/msghdr.c
@@ -218,6 +218,8 @@ ssize_t msghdr_copy(struct msghdr_buf *msg, size_t msgsize,
 
 	if (msg != NULL) {
 
+		msg->msg = (struct msghdr) {};
+
 		if (addr != NULL) {
 			if (addrlen > sizeof(struct sockaddr_storage)) {
 				errno = EMSGSIZE;
-- 
2.1.4


From 8424d7693c0f211115b6d19546e615a4530c8732 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Sat, 14 May 2016 10:07:24 +0200
Subject: [PATCH 6/7] lib: Move poll_funcs to lib/

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 lib/poll_funcs/poll_funcs.h                | 131 ++++++++
 lib/poll_funcs/poll_funcs_tevent.c         | 463 +++++++++++++++++++++++++++++
 lib/poll_funcs/poll_funcs_tevent.h         |  38 +++
 lib/poll_funcs/wscript_build               |   5 +
 source3/lib/poll_funcs/poll_funcs.h        | 131 --------
 source3/lib/poll_funcs/poll_funcs_tevent.c | 463 -----------------------------
 source3/lib/poll_funcs/poll_funcs_tevent.h |  38 ---
 source3/lib/poll_funcs/wscript_build       |   5 -
 source3/wscript_build                      |   1 -
 wscript_build                              |   1 +
 10 files changed, 638 insertions(+), 638 deletions(-)
 create mode 100644 lib/poll_funcs/poll_funcs.h
 create mode 100644 lib/poll_funcs/poll_funcs_tevent.c
 create mode 100644 lib/poll_funcs/poll_funcs_tevent.h
 create mode 100644 lib/poll_funcs/wscript_build
 delete mode 100644 source3/lib/poll_funcs/poll_funcs.h
 delete mode 100644 source3/lib/poll_funcs/poll_funcs_tevent.c
 delete mode 100644 source3/lib/poll_funcs/poll_funcs_tevent.h
 delete mode 100644 source3/lib/poll_funcs/wscript_build

diff --git a/lib/poll_funcs/poll_funcs.h b/lib/poll_funcs/poll_funcs.h
new file mode 100644
index 0000000..6072eb5
--- /dev/null
+++ b/lib/poll_funcs/poll_funcs.h
@@ -0,0 +1,131 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Copyright (C) Volker Lendecke 2013
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * @file poll_funcs.h
+ *
+ * @brief event loop abstraction
+ */
+
+/*
+ * This is inspired by AvahiWatch, the avahi event loop abstraction.
+ */
+
+#ifndef __POLL_FUNCS_H__
+#define __POLL_FUNCS_H__
+
+#include "replace.h"
+
+/**
+ * poll_watch and poll_timeout are undefined here, every implementation can
+ * implement its own structures.
+ */
+
+struct poll_watch;
+struct poll_timeout;
+
+struct poll_funcs {
+
+	/**
+	 * @brief Create a new file descriptor watch
+	 *
+	 * @param[in] funcs The callback array
+	 * @param[in] fd The fd to watch
+	 * @param[in] events POLLIN and POLLOUT or'ed together
+	 * @param[in] callback Function to call by the implementation
+	 * @param[in] private_data Pointer to give back to callback
+	 *
+	 * @return A new poll_watch struct
+	 */
+
+	struct poll_watch *(*watch_new)(
+		const struct poll_funcs *funcs, int fd, short events,
+		void (*callback)(struct poll_watch *w, int fd,
+				 short events, void *private_data),
+		void *private_data);
+
+	/**
+	 * @brief Change the watched events for a struct poll_watch
+	 *
+	 * @param[in] w The poll_watch to change
+	 * @param[in] events new POLLIN and POLLOUT or'ed together
+	 */
+
+	void (*watch_update)(struct poll_watch *w, short events);
+
+	/**
+	 * @brief Read events currently watched
+	 *
+	 * @param[in] w The poll_watch to inspect
+	 *
+	 * @returns The events currently watched
+	 */
+
+	short (*watch_get_events)(struct poll_watch *w);
+
+	/**
+	 * @brief Free a struct poll_watch
+	 *
+	 * @param[in] w The poll_watch struct to free
+	 */
+
+	void (*watch_free)(struct poll_watch *w);
+
+
+	/**
+	 * @brief Create a new timeout watch
+	 *
+	 * @param[in] funcs The callback array
+	 * @param[in] tv The time when the timeout should trigger
+	 * @param[in] callback Function to call at time "ts"
+	 * @param[in] private_data Pointer to give back to callback
+	 *
+	 * @return A new poll_timeout struct
+	 */
+
+	struct poll_timeout *(*timeout_new)(
+		const struct poll_funcs *funcs, const struct timeval *tv,
+		void (*callback)(struct poll_timeout *t, void *private_data),
+		void *private_data);
+
+	/**
+	 * @brief Change the timeout of a watch
+	 *
+	 * @param[in] t The timeout watch to change
+	 * @param[in] ts The new trigger time
+	 */
+
+	void (*timeout_update)(struct poll_timeout *t,
+			       const struct timespec *ts);
+
+	/**
+	 * @brief Free a poll_timeout
+	 *
+	 * @param[in] t The poll_timeout to free
+	 */
+
+	void (*timeout_free)(struct poll_timeout *t);
+
+	/**
+	 * @brief private data for use by the implementation
+	 */
+
+	void *private_data;
+};
+
+#endif
diff --git a/lib/poll_funcs/poll_funcs_tevent.c b/lib/poll_funcs/poll_funcs_tevent.c
new file mode 100644
index 0000000..8fdf080
--- /dev/null
+++ b/lib/poll_funcs/poll_funcs_tevent.c
@@ -0,0 +1,463 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Copyright (C) Volker Lendecke 2013,2014
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "poll_funcs_tevent.h"
+#include "tevent.h"
+#include "system/select.h"
+#include "lib/util/dlinklist.h"
+
+/*
+ * A poll_watch is asked for by the engine using this library via
+ * funcs->watch_new(). It represents interest in "fd" becoming readable or
+ * writable.
+ */
+
+struct poll_watch {
+	struct poll_funcs_state *state;
+	unsigned slot; 		/* index into state->watches[] */
+	int fd;
+	int events;
+	void (*callback)(struct poll_watch *w, int fd, short events,
+			 void *private_data);
+	void *private_data;
+};
+
+struct poll_funcs_state {
+	/*
+	 * "watches" is the array of all watches that we have handed out via
+	 * funcs->watch_new(). The "watches" array can contain NULL pointers.
+	 */
+	unsigned num_watches;
+	struct poll_watch **watches;
+
+	/*
+	 * "contexts is the array of tevent_contexts that serve
+	 * "watches". "contexts" can contain NULL pointers.
+	 */
+	unsigned num_contexts;
+	struct poll_funcs_tevent_context **contexts;
+};
+
+struct poll_funcs_tevent_context {
+	struct poll_funcs_tevent_handle *handles;
+	struct poll_funcs_state *state;
+	unsigned slot;		/* index into state->contexts[] */
+	struct tevent_context *ev;
+	struct tevent_fd **fdes; /* same indexes as state->watches[] */
+};
+
+/*
+ * poll_funcs_tevent_register() hands out a struct poll_funcs_tevent_handle as
+ * a void *. poll_funcs_tevent_register allows tevent_contexts to be
+ * registered multiple times, and we can't add a tevent_fd for the same fd's
+ * multiple times. So we have to share one poll_funcs_tevent_context.
+ */
+struct poll_funcs_tevent_handle {
+	struct poll_funcs_tevent_handle *prev, *next;
+	struct poll_funcs_tevent_context *ctx;
+};
+
+static uint16_t poll_events_to_tevent(short events)
+{
+	uint16_t ret = 0;
+
+	if (events & POLLIN) {
+		ret |= TEVENT_FD_READ;
+	}
+	if (events & POLLOUT) {
+		ret |= TEVENT_FD_WRITE;
+	}
+	return ret;
+}
+
+static short tevent_to_poll_events(uint16_t flags)
+{
+	short ret = 0;
+
+	if (flags & TEVENT_FD_READ) {
+		ret |= POLLIN;
+	}
+	if (flags & TEVENT_FD_WRITE) {
+		ret |= POLLOUT;
+	}
+	return ret;
+}
+
+/*
+ * Find or create a free slot in state->watches[]
+ */
+static bool poll_funcs_watch_find_slot(struct poll_funcs_state *state,
+				       unsigned *slot)
+{
+	struct poll_watch **watches;
+	unsigned i;
+
+	for (i=0; i<state->num_watches; i++) {
+		if (state->watches[i] == NULL) {
+			*slot = i;
+			return true;
+		}
+	}
+
+	watches = talloc_realloc(state, state->watches, struct poll_watch *,
+				 state->num_watches + 1);
+	if (watches == NULL) {
+		return false;
+	}
+	watches[state->num_watches] = NULL;
+	state->watches = watches;
+
+	for (i=0; i<state->num_contexts; i++) {
+		struct tevent_fd **fdes;
+		struct poll_funcs_tevent_context *c = state->contexts[i];
+		if (c == NULL) {
+			continue;
+		}
+		fdes = talloc_realloc(c, c->fdes, struct tevent_fd *,
+				      state->num_watches + 1);
+		if (fdes == NULL) {
+			return false;
+		}
+		c->fdes = fdes;
+
+		fdes[state->num_watches] = NULL;
+	}
+
+	*slot = state->num_watches;
+	state->num_watches += 1;
+
+	return true;
+}
+
+static void poll_funcs_fde_handler(struct tevent_context *ev,
+				   struct tevent_fd *fde, uint16_t flags,
+				   void *private_data);
+static int poll_watch_destructor(struct poll_watch *w);
+
+static struct poll_watch *tevent_watch_new(
+	const struct poll_funcs *funcs, int fd, short events,
+	void (*callback)(struct poll_watch *w, int fd, short events,
+			 void *private_data),
+	void *private_data)
+{
+	struct poll_funcs_state *state = talloc_get_type_abort(
+		funcs->private_data, struct poll_funcs_state);
+	struct poll_watch *w;
+	unsigned i, slot;
+
+	if (!poll_funcs_watch_find_slot(state, &slot)) {
+		return NULL;
+	}
+
+	w = talloc(state->watches, struct poll_watch);
+	if (w == NULL) {
+		return NULL;
+	}
+	w->state = state;
+	w->slot = slot;
+	w->fd = fd;
+	w->events = poll_events_to_tevent(events);
+	w->fd = fd;
+	w->callback = callback;
+	w->private_data = private_data;
+	state->watches[slot] = w;
+
+	talloc_set_destructor(w, poll_watch_destructor);
+
+	for (i=0; i<state->num_contexts; i++) {
+		struct poll_funcs_tevent_context *c = state->contexts[i];
+		if (c == NULL) {
+			continue;
+		}
+		c->fdes[slot] = tevent_add_fd(c->ev, c->fdes, w->fd, w->events,
+					      poll_funcs_fde_handler, w);
+		if (c->fdes[slot] == NULL) {
+			goto fail;
+		}
+	}
+	return w;
+
+fail:
+	TALLOC_FREE(w);
+	return NULL;
+}
+
+static int poll_watch_destructor(struct poll_watch *w)
+{
+	struct poll_funcs_state *state = w->state;
+	unsigned slot = w->slot;
+	unsigned i;
+
+	TALLOC_FREE(state->watches[slot]);
+
+	for (i=0; i<state->num_contexts; i++) {
+		struct poll_funcs_tevent_context *c = state->contexts[i];
+		if (c == NULL) {
+			continue;
+		}
+		TALLOC_FREE(c->fdes[slot]);
+	}
+
+	return 0;
+}
+
+static void tevent_watch_update(struct poll_watch *w, short events)
+{
+	struct poll_funcs_state *state = w->state;
+	unsigned slot = w->slot;
+	unsigned i;
+
+	w->events = poll_events_to_tevent(events);
+
+	for (i=0; i<state->num_contexts; i++) {
+		struct poll_funcs_tevent_context *c = state->contexts[i];
+		if (c == NULL) {
+			continue;
+		}
+		tevent_fd_set_flags(c->fdes[slot], w->events);
+	}
+}
+
+static short tevent_watch_get_events(struct poll_watch *w)
+{
+	return tevent_to_poll_events(w->events);
+}
+
+static void tevent_watch_free(struct poll_watch *w)
+{
+	TALLOC_FREE(w);
+}
+
+static struct poll_timeout *tevent_timeout_new(
+	const struct poll_funcs *funcs, const struct timeval *tv,
+	void (*callback)(struct poll_timeout *t, void *private_data),
+	void *private_data)
+{
+	/* not implemented yet */
+	return NULL;
+}
+
+static void tevent_timeout_update(struct poll_timeout *t,
+				  const struct timespec *ts)
+{
+	return;
+}
+
+static void tevent_timeout_free(struct poll_timeout *t)
+{
+	return;
+}
+
+static int poll_funcs_state_destructor(struct poll_funcs_state *state);
+
+struct poll_funcs *poll_funcs_init_tevent(TALLOC_CTX *mem_ctx)
+{
+	struct poll_funcs *f;
+	struct poll_funcs_state *state;
+
+	f = talloc(mem_ctx, struct poll_funcs);
+	if (f == NULL) {
+		return NULL;
+	}
+	state = talloc_zero(f, struct poll_funcs_state);
+	if (state == NULL) {
+		TALLOC_FREE(f);
+		return NULL;
+	}
+	talloc_set_destructor(state, poll_funcs_state_destructor);
+
+	f->watch_new = tevent_watch_new;
+	f->watch_update = tevent_watch_update;
+	f->watch_get_events = tevent_watch_get_events;
+	f->watch_free = tevent_watch_free;
+	f->timeout_new = tevent_timeout_new;
+	f->timeout_update = tevent_timeout_update;
+	f->timeout_free = tevent_timeout_free;
+	f->private_data = state;
+	return f;
+}
+
+static int poll_funcs_state_destructor(struct poll_funcs_state *state)
+{
+	unsigned i;
+	/*
+	 * Make sure the watches are cleared before the contexts. The watches
+	 * have destructors attached to them that clean up the fde's
+	 */
+	for (i=0; i<state->num_watches; i++) {
+		TALLOC_FREE(state->watches[i]);
+	}
+	return 0;
+}
+
+/*
+ * Find or create a free slot in state->contexts[]
+ */
+static bool poll_funcs_context_slot_find(struct poll_funcs_state *state,
+					 struct tevent_context *ev,
+					 unsigned *slot)
+{
+	struct poll_funcs_tevent_context **contexts;
+	unsigned i;
+
+	for (i=0; i<state->num_contexts; i++) {
+		struct poll_funcs_tevent_context *ctx = state->contexts[i];
+
+		if ((ctx == NULL) || (ctx->ev == ev)) {
+			*slot = i;
+			return true;
+		}
+	}
+
+	contexts = talloc_realloc(state, state->contexts,
+				  struct poll_funcs_tevent_context *,
+				  state->num_contexts + 1);
+	if (contexts == NULL) {
+		return false;
+	}
+	state->contexts = contexts;
+	state->contexts[state->num_contexts] = NULL;
+
+	*slot = state->num_contexts;
+	state->num_contexts += 1;
+
+	return true;
+}
+
+static int poll_funcs_tevent_context_destructor(
+	struct poll_funcs_tevent_context *ctx);
+
+static struct poll_funcs_tevent_context *poll_funcs_tevent_context_new(
+	TALLOC_CTX *mem_ctx, struct poll_funcs_state *state,
+	struct tevent_context *ev, unsigned slot)
+{
+	struct poll_funcs_tevent_context *ctx;
+	unsigned i;
+
+	ctx = talloc(mem_ctx, struct poll_funcs_tevent_context);
+	if (ctx == NULL) {
+		return NULL;
+	}
+
+	ctx->handles = NULL;
+	ctx->state = state;
+	ctx->ev = ev;
+	ctx->slot = slot;
+
+	ctx->fdes = talloc_array(ctx, struct tevent_fd *, state->num_watches);
+	if (ctx->fdes == NULL) {
+		goto fail;
+	}
+
+	for (i=0; i<state->num_watches; i++) {
+		struct poll_watch *w = state->watches[i];
+
+		if (w == NULL) {
+			ctx->fdes[i] = NULL;
+			continue;
+		}
+		ctx->fdes[i] = tevent_add_fd(ev, ctx->fdes, w->fd, w->events,
+					     poll_funcs_fde_handler, w);
+		if (ctx->fdes[i] == NULL) {
+			goto fail;
+		}
+	}
+	talloc_set_destructor(ctx, poll_funcs_tevent_context_destructor);
+	return ctx;
+fail:
+	TALLOC_FREE(ctx);
+	return NULL;
+}
+
+static int poll_funcs_tevent_context_destructor(
+	struct poll_funcs_tevent_context *ctx)
+{
+	struct poll_funcs_tevent_handle *h;
+
+	ctx->state->contexts[ctx->slot] = NULL;
+
+	for (h = ctx->handles; h != NULL; h = h->next) {
+		h->ctx = NULL;
+	}
+
+	return 0;
+}
+
+static void poll_funcs_fde_handler(struct tevent_context *ev,
+				   struct tevent_fd *fde, uint16_t flags,
+				   void *private_data)
+{
+	struct poll_watch *w = talloc_get_type_abort(
+		private_data, struct poll_watch);
+	short events = tevent_to_poll_events(flags);
+	w->callback(w, w->fd, events, w->private_data);
+}
+
+static int poll_funcs_tevent_handle_destructor(
+	struct poll_funcs_tevent_handle *handle);
+
+void *poll_funcs_tevent_register(TALLOC_CTX *mem_ctx, struct poll_funcs *f,
+				 struct tevent_context *ev)
+{
+	struct poll_funcs_state *state = talloc_get_type_abort(
+		f->private_data, struct poll_funcs_state);
+	struct poll_funcs_tevent_handle *handle;
+	unsigned slot;
+
+	handle = talloc(mem_ctx, struct poll_funcs_tevent_handle);
+	if (handle == NULL) {
+		return NULL;
+	}
+
+	if (!poll_funcs_context_slot_find(state, ev, &slot)) {
+		goto fail;
+	}
+	if (state->contexts[slot] == NULL) {
+		state->contexts[slot] = poll_funcs_tevent_context_new(
+			state->contexts, state, ev, slot);
+		if (state->contexts[slot] == NULL) {
+			goto fail;
+		}
+	}
+
+	handle->ctx = state->contexts[slot];
+	DLIST_ADD(handle->ctx->handles, handle);
+	talloc_set_destructor(handle, poll_funcs_tevent_handle_destructor);
+	return handle;
+fail:
+	TALLOC_FREE(handle);
+	return NULL;
+}
+
+static int poll_funcs_tevent_handle_destructor(
+	struct poll_funcs_tevent_handle *handle)
+{
+	if (handle->ctx == NULL) {
+		return 0;
+	}
+	if (handle->ctx->handles == NULL) {
+		abort();
+	}
+
+	DLIST_REMOVE(handle->ctx->handles, handle);
+
+	if (handle->ctx->handles == NULL) {
+		TALLOC_FREE(handle->ctx);
+	}
+	return 0;
+}
diff --git a/lib/poll_funcs/poll_funcs_tevent.h b/lib/poll_funcs/poll_funcs_tevent.h
new file mode 100644
index 0000000..8b2964c
--- /dev/null
+++ b/lib/poll_funcs/poll_funcs_tevent.h
@@ -0,0 +1,38 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Copyright (C) Volker Lendecke 2013,2014
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __POLL_FUNCS_TEVENT_H__
+#define __POLL_FUNCS_TEVENT_H__
+
+#include "poll_funcs.h"
+#include "tevent.h"
+
+/*
+ * Create a new, empty instance of "struct poll_funcs" to be served by tevent.
+ */
+struct poll_funcs *poll_funcs_init_tevent(TALLOC_CTX *mem_ctx);
+
+/*
+ * Register a tevent_context to handle the watches that the user of
+ * "poll_funcs" showed interest in. talloc_free() the returned pointer when
+ * "ev" is not supposed to handle the events anymore.
+ */
+void *poll_funcs_tevent_register(TALLOC_CTX *mem_ctx, struct poll_funcs *f,
+				 struct tevent_context *ev);
+
+#endif
diff --git a/lib/poll_funcs/wscript_build b/lib/poll_funcs/wscript_build
new file mode 100644
index 0000000..df9a298
--- /dev/null
+++ b/lib/poll_funcs/wscript_build
@@ -0,0 +1,5 @@
+#!/usr/bin/env python
+
+bld.SAMBA_SUBSYSTEM('POLL_FUNCS_TEVENT',
+                    source='poll_funcs_tevent.c',
+                    deps='tevent')
diff --git a/source3/lib/poll_funcs/poll_funcs.h b/source3/lib/poll_funcs/poll_funcs.h
deleted file mode 100644
index 6072eb5..0000000
--- a/source3/lib/poll_funcs/poll_funcs.h
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Unix SMB/CIFS implementation.
- * Copyright (C) Volker Lendecke 2013
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-/**
- * @file poll_funcs.h
- *
- * @brief event loop abstraction
- */
-
-/*
- * This is inspired by AvahiWatch, the avahi event loop abstraction.
- */
-
-#ifndef __POLL_FUNCS_H__
-#define __POLL_FUNCS_H__
-
-#include "replace.h"
-
-/**
- * poll_watch and poll_timeout are undefined here, every implementation can
- * implement its own structures.
- */
-
-struct poll_watch;
-struct poll_timeout;
-
-struct poll_funcs {
-
-	/**
-	 * @brief Create a new file descriptor watch
-	 *
-	 * @param[in] funcs The callback array
-	 * @param[in] fd The fd to watch
-	 * @param[in] events POLLIN and POLLOUT or'ed together
-	 * @param[in] callback Function to call by the implementation
-	 * @param[in] private_data Pointer to give back to callback
-	 *
-	 * @return A new poll_watch struct
-	 */
-
-	struct poll_watch *(*watch_new)(
-		const struct poll_funcs *funcs, int fd, short events,
-		void (*callback)(struct poll_watch *w, int fd,
-				 short events, void *private_data),
-		void *private_data);
-
-	/**
-	 * @brief Change the watched events for a struct poll_watch
-	 *
-	 * @param[in] w The poll_watch to change
-	 * @param[in] events new POLLIN and POLLOUT or'ed together
-	 */
-
-	void (*watch_update)(struct poll_watch *w, short events);
-
-	/**
-	 * @brief Read events currently watched
-	 *
-	 * @param[in] w The poll_watch to inspect
-	 *
-	 * @returns The events currently watched
-	 */
-
-	short (*watch_get_events)(struct poll_watch *w);
-
-	/**
-	 * @brief Free a struct poll_watch
-	 *
-	 * @param[in] w The poll_watch struct to free
-	 */
-
-	void (*watch_free)(struct poll_watch *w);
-
-
-	/**
-	 * @brief Create a new timeout watch
-	 *
-	 * @param[in] funcs The callback array
-	 * @param[in] tv The time when the timeout should trigger
-	 * @param[in] callback Function to call at time "ts"
-	 * @param[in] private_data Pointer to give back to callback
-	 *
-	 * @return A new poll_timeout struct
-	 */
-
-	struct poll_timeout *(*timeout_new)(
-		const struct poll_funcs *funcs, const struct timeval *tv,
-		void (*callback)(struct poll_timeout *t, void *private_data),
-		void *private_data);
-
-	/**
-	 * @brief Change the timeout of a watch
-	 *
-	 * @param[in] t The timeout watch to change
-	 * @param[in] ts The new trigger time
-	 */
-
-	void (*timeout_update)(struct poll_timeout *t,
-			       const struct timespec *ts);
-
-	/**
-	 * @brief Free a poll_timeout
-	 *
-	 * @param[in] t The poll_timeout to free
-	 */
-
-	void (*timeout_free)(struct poll_timeout *t);
-
-	/**
-	 * @brief private data for use by the implementation
-	 */
-
-	void *private_data;
-};
-
-#endif
diff --git a/source3/lib/poll_funcs/poll_funcs_tevent.c b/source3/lib/poll_funcs/poll_funcs_tevent.c
deleted file mode 100644
index 8fdf080..0000000
--- a/source3/lib/poll_funcs/poll_funcs_tevent.c
+++ /dev/null
@@ -1,463 +0,0 @@
-/*
- * Unix SMB/CIFS implementation.
- * Copyright (C) Volker Lendecke 2013,2014
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "poll_funcs_tevent.h"
-#include "tevent.h"
-#include "system/select.h"
-#include "lib/util/dlinklist.h"
-
-/*
- * A poll_watch is asked for by the engine using this library via
- * funcs->watch_new(). It represents interest in "fd" becoming readable or
- * writable.
- */
-
-struct poll_watch {
-	struct poll_funcs_state *state;
-	unsigned slot; 		/* index into state->watches[] */
-	int fd;
-	int events;
-	void (*callback)(struct poll_watch *w, int fd, short events,
-			 void *private_data);
-	void *private_data;
-};
-
-struct poll_funcs_state {
-	/*
-	 * "watches" is the array of all watches that we have handed out via
-	 * funcs->watch_new(). The "watches" array can contain NULL pointers.
-	 */
-	unsigned num_watches;
-	struct poll_watch **watches;
-
-	/*
-	 * "contexts is the array of tevent_contexts that serve
-	 * "watches". "contexts" can contain NULL pointers.
-	 */
-	unsigned num_contexts;
-	struct poll_funcs_tevent_context **contexts;
-};
-
-struct poll_funcs_tevent_context {
-	struct poll_funcs_tevent_handle *handles;
-	struct poll_funcs_state *state;
-	unsigned slot;		/* index into state->contexts[] */
-	struct tevent_context *ev;
-	struct tevent_fd **fdes; /* same indexes as state->watches[] */
-};
-
-/*
- * poll_funcs_tevent_register() hands out a struct poll_funcs_tevent_handle as
- * a void *. poll_funcs_tevent_register allows tevent_contexts to be
- * registered multiple times, and we can't add a tevent_fd for the same fd's
- * multiple times. So we have to share one poll_funcs_tevent_context.
- */
-struct poll_funcs_tevent_handle {
-	struct poll_funcs_tevent_handle *prev, *next;
-	struct poll_funcs_tevent_context *ctx;
-};
-
-static uint16_t poll_events_to_tevent(short events)
-{
-	uint16_t ret = 0;
-
-	if (events & POLLIN) {
-		ret |= TEVENT_FD_READ;
-	}
-	if (events & POLLOUT) {
-		ret |= TEVENT_FD_WRITE;
-	}
-	return ret;
-}
-
-static short tevent_to_poll_events(uint16_t flags)
-{
-	short ret = 0;
-
-	if (flags & TEVENT_FD_READ) {
-		ret |= POLLIN;
-	}
-	if (flags & TEVENT_FD_WRITE) {
-		ret |= POLLOUT;
-	}
-	return ret;
-}
-
-/*
- * Find or create a free slot in state->watches[]
- */
-static bool poll_funcs_watch_find_slot(struct poll_funcs_state *state,
-				       unsigned *slot)
-{
-	struct poll_watch **watches;
-	unsigned i;
-
-	for (i=0; i<state->num_watches; i++) {
-		if (state->watches[i] == NULL) {
-			*slot = i;
-			return true;
-		}
-	}
-
-	watches = talloc_realloc(state, state->watches, struct poll_watch *,
-				 state->num_watches + 1);
-	if (watches == NULL) {
-		return false;
-	}
-	watches[state->num_watches] = NULL;
-	state->watches = watches;
-
-	for (i=0; i<state->num_contexts; i++) {
-		struct tevent_fd **fdes;
-		struct poll_funcs_tevent_context *c = state->contexts[i];
-		if (c == NULL) {
-			continue;
-		}
-		fdes = talloc_realloc(c, c->fdes, struct tevent_fd *,
-				      state->num_watches + 1);
-		if (fdes == NULL) {
-			return false;
-		}
-		c->fdes = fdes;
-
-		fdes[state->num_watches] = NULL;
-	}
-
-	*slot = state->num_watches;
-	state->num_watches += 1;
-
-	return true;
-}
-
-static void poll_funcs_fde_handler(struct tevent_context *ev,
-				   struct tevent_fd *fde, uint16_t flags,
-				   void *private_data);
-static int poll_watch_destructor(struct poll_watch *w);
-
-static struct poll_watch *tevent_watch_new(
-	const struct poll_funcs *funcs, int fd, short events,
-	void (*callback)(struct poll_watch *w, int fd, short events,
-			 void *private_data),
-	void *private_data)
-{
-	struct poll_funcs_state *state = talloc_get_type_abort(
-		funcs->private_data, struct poll_funcs_state);
-	struct poll_watch *w;
-	unsigned i, slot;
-
-	if (!poll_funcs_watch_find_slot(state, &slot)) {
-		return NULL;
-	}
-
-	w = talloc(state->watches, struct poll_watch);
-	if (w == NULL) {
-		return NULL;
-	}
-	w->state = state;
-	w->slot = slot;
-	w->fd = fd;
-	w->events = poll_events_to_tevent(events);
-	w->fd = fd;
-	w->callback = callback;
-	w->private_data = private_data;
-	state->watches[slot] = w;
-
-	talloc_set_destructor(w, poll_watch_destructor);
-
-	for (i=0; i<state->num_contexts; i++) {
-		struct poll_funcs_tevent_context *c = state->contexts[i];
-		if (c == NULL) {
-			continue;
-		}
-		c->fdes[slot] = tevent_add_fd(c->ev, c->fdes, w->fd, w->events,
-					      poll_funcs_fde_handler, w);
-		if (c->fdes[slot] == NULL) {
-			goto fail;
-		}
-	}
-	return w;
-
-fail:
-	TALLOC_FREE(w);
-	return NULL;
-}
-
-static int poll_watch_destructor(struct poll_watch *w)
-{
-	struct poll_funcs_state *state = w->state;
-	unsigned slot = w->slot;
-	unsigned i;
-
-	TALLOC_FREE(state->watches[slot]);
-
-	for (i=0; i<state->num_contexts; i++) {
-		struct poll_funcs_tevent_context *c = state->contexts[i];
-		if (c == NULL) {
-			continue;
-		}
-		TALLOC_FREE(c->fdes[slot]);
-	}
-
-	return 0;
-}
-
-static void tevent_watch_update(struct poll_watch *w, short events)
-{
-	struct poll_funcs_state *state = w->state;
-	unsigned slot = w->slot;
-	unsigned i;
-
-	w->events = poll_events_to_tevent(events);
-
-	for (i=0; i<state->num_contexts; i++) {
-		struct poll_funcs_tevent_context *c = state->contexts[i];
-		if (c == NULL) {
-			continue;
-		}
-		tevent_fd_set_flags(c->fdes[slot], w->events);
-	}
-}
-
-static short tevent_watch_get_events(struct poll_watch *w)
-{
-	return tevent_to_poll_events(w->events);
-}
-
-static void tevent_watch_free(struct poll_watch *w)
-{
-	TALLOC_FREE(w);
-}
-
-static struct poll_timeout *tevent_timeout_new(
-	const struct poll_funcs *funcs, const struct timeval *tv,
-	void (*callback)(struct poll_timeout *t, void *private_data),
-	void *private_data)
-{
-	/* not implemented yet */
-	return NULL;
-}
-
-static void tevent_timeout_update(struct poll_timeout *t,
-				  const struct timespec *ts)
-{
-	return;
-}
-
-static void tevent_timeout_free(struct poll_timeout *t)
-{
-	return;
-}
-
-static int poll_funcs_state_destructor(struct poll_funcs_state *state);
-
-struct poll_funcs *poll_funcs_init_tevent(TALLOC_CTX *mem_ctx)
-{
-	struct poll_funcs *f;
-	struct poll_funcs_state *state;
-
-	f = talloc(mem_ctx, struct poll_funcs);
-	if (f == NULL) {
-		return NULL;
-	}
-	state = talloc_zero(f, struct poll_funcs_state);
-	if (state == NULL) {
-		TALLOC_FREE(f);
-		return NULL;
-	}
-	talloc_set_destructor(state, poll_funcs_state_destructor);
-
-	f->watch_new = tevent_watch_new;
-	f->watch_update = tevent_watch_update;
-	f->watch_get_events = tevent_watch_get_events;
-	f->watch_free = tevent_watch_free;
-	f->timeout_new = tevent_timeout_new;
-	f->timeout_update = tevent_timeout_update;
-	f->timeout_free = tevent_timeout_free;
-	f->private_data = state;
-	return f;
-}
-
-static int poll_funcs_state_destructor(struct poll_funcs_state *state)
-{
-	unsigned i;
-	/*
-	 * Make sure the watches are cleared before the contexts. The watches
-	 * have destructors attached to them that clean up the fde's
-	 */
-	for (i=0; i<state->num_watches; i++) {
-		TALLOC_FREE(state->watches[i]);
-	}
-	return 0;
-}
-
-/*
- * Find or create a free slot in state->contexts[]
- */
-static bool poll_funcs_context_slot_find(struct poll_funcs_state *state,
-					 struct tevent_context *ev,
-					 unsigned *slot)
-{
-	struct poll_funcs_tevent_context **contexts;
-	unsigned i;
-
-	for (i=0; i<state->num_contexts; i++) {
-		struct poll_funcs_tevent_context *ctx = state->contexts[i];
-
-		if ((ctx == NULL) || (ctx->ev == ev)) {
-			*slot = i;
-			return true;
-		}
-	}
-
-	contexts = talloc_realloc(state, state->contexts,
-				  struct poll_funcs_tevent_context *,
-				  state->num_contexts + 1);
-	if (contexts == NULL) {
-		return false;
-	}
-	state->contexts = contexts;
-	state->contexts[state->num_contexts] = NULL;
-
-	*slot = state->num_contexts;
-	state->num_contexts += 1;
-
-	return true;
-}
-
-static int poll_funcs_tevent_context_destructor(
-	struct poll_funcs_tevent_context *ctx);
-
-static struct poll_funcs_tevent_context *poll_funcs_tevent_context_new(
-	TALLOC_CTX *mem_ctx, struct poll_funcs_state *state,
-	struct tevent_context *ev, unsigned slot)
-{
-	struct poll_funcs_tevent_context *ctx;
-	unsigned i;
-
-	ctx = talloc(mem_ctx, struct poll_funcs_tevent_context);
-	if (ctx == NULL) {
-		return NULL;
-	}
-
-	ctx->handles = NULL;
-	ctx->state = state;
-	ctx->ev = ev;
-	ctx->slot = slot;
-
-	ctx->fdes = talloc_array(ctx, struct tevent_fd *, state->num_watches);
-	if (ctx->fdes == NULL) {
-		goto fail;
-	}
-
-	for (i=0; i<state->num_watches; i++) {
-		struct poll_watch *w = state->watches[i];
-
-		if (w == NULL) {
-			ctx->fdes[i] = NULL;
-			continue;
-		}
-		ctx->fdes[i] = tevent_add_fd(ev, ctx->fdes, w->fd, w->events,
-					     poll_funcs_fde_handler, w);
-		if (ctx->fdes[i] == NULL) {
-			goto fail;
-		}
-	}
-	talloc_set_destructor(ctx, poll_funcs_tevent_context_destructor);
-	return ctx;
-fail:
-	TALLOC_FREE(ctx);
-	return NULL;
-}
-
-static int poll_funcs_tevent_context_destructor(
-	struct poll_funcs_tevent_context *ctx)
-{
-	struct poll_funcs_tevent_handle *h;
-
-	ctx->state->contexts[ctx->slot] = NULL;
-
-	for (h = ctx->handles; h != NULL; h = h->next) {
-		h->ctx = NULL;
-	}
-
-	return 0;
-}
-
-static void poll_funcs_fde_handler(struct tevent_context *ev,
-				   struct tevent_fd *fde, uint16_t flags,
-				   void *private_data)
-{
-	struct poll_watch *w = talloc_get_type_abort(
-		private_data, struct poll_watch);
-	short events = tevent_to_poll_events(flags);
-	w->callback(w, w->fd, events, w->private_data);
-}
-
-static int poll_funcs_tevent_handle_destructor(
-	struct poll_funcs_tevent_handle *handle);
-
-void *poll_funcs_tevent_register(TALLOC_CTX *mem_ctx, struct poll_funcs *f,
-				 struct tevent_context *ev)
-{
-	struct poll_funcs_state *state = talloc_get_type_abort(
-		f->private_data, struct poll_funcs_state);
-	struct poll_funcs_tevent_handle *handle;
-	unsigned slot;
-
-	handle = talloc(mem_ctx, struct poll_funcs_tevent_handle);
-	if (handle == NULL) {
-		return NULL;
-	}
-
-	if (!poll_funcs_context_slot_find(state, ev, &slot)) {
-		goto fail;
-	}
-	if (state->contexts[slot] == NULL) {
-		state->contexts[slot] = poll_funcs_tevent_context_new(
-			state->contexts, state, ev, slot);
-		if (state->contexts[slot] == NULL) {
-			goto fail;
-		}
-	}
-
-	handle->ctx = state->contexts[slot];
-	DLIST_ADD(handle->ctx->handles, handle);
-	talloc_set_destructor(handle, poll_funcs_tevent_handle_destructor);
-	return handle;
-fail:
-	TALLOC_FREE(handle);
-	return NULL;
-}
-
-static int poll_funcs_tevent_handle_destructor(
-	struct poll_funcs_tevent_handle *handle)
-{
-	if (handle->ctx == NULL) {
-		return 0;
-	}
-	if (handle->ctx->handles == NULL) {
-		abort();
-	}
-
-	DLIST_REMOVE(handle->ctx->handles, handle);
-
-	if (handle->ctx->handles == NULL) {
-		TALLOC_FREE(handle->ctx);
-	}
-	return 0;
-}
diff --git a/source3/lib/poll_funcs/poll_funcs_tevent.h b/source3/lib/poll_funcs/poll_funcs_tevent.h
deleted file mode 100644
index 8b2964c..0000000
--- a/source3/lib/poll_funcs/poll_funcs_tevent.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Unix SMB/CIFS implementation.
- * Copyright (C) Volker Lendecke 2013,2014
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __POLL_FUNCS_TEVENT_H__
-#define __POLL_FUNCS_TEVENT_H__
-
-#include "poll_funcs.h"
-#include "tevent.h"
-
-/*
- * Create a new, empty instance of "struct poll_funcs" to be served by tevent.
- */
-struct poll_funcs *poll_funcs_init_tevent(TALLOC_CTX *mem_ctx);
-
-/*
- * Register a tevent_context to handle the watches that the user of
- * "poll_funcs" showed interest in. talloc_free() the returned pointer when
- * "ev" is not supposed to handle the events anymore.
- */
-void *poll_funcs_tevent_register(TALLOC_CTX *mem_ctx, struct poll_funcs *f,
-				 struct tevent_context *ev);
-
-#endif
diff --git a/source3/lib/poll_funcs/wscript_build b/source3/lib/poll_funcs/wscript_build
deleted file mode 100644
index df9a298..0000000
--- a/source3/lib/poll_funcs/wscript_build
+++ /dev/null
@@ -1,5 +0,0 @@
-#!/usr/bin/env python
-
-bld.SAMBA_SUBSYSTEM('POLL_FUNCS_TEVENT',
-                    source='poll_funcs_tevent.c',
-                    deps='tevent')
diff --git a/source3/wscript_build b/source3/wscript_build
index e348e65..365b250 100755
--- a/source3/wscript_build
+++ b/source3/wscript_build
@@ -1511,7 +1511,6 @@ bld.RECURSE('auth')
 bld.RECURSE('libgpo/gpext')
 bld.RECURSE('lib/pthreadpool')
 bld.RECURSE('lib/asys')
-bld.RECURSE('lib/poll_funcs')
 bld.RECURSE('lib/unix_msg')
 bld.RECURSE('librpc')
 bld.RECURSE('librpc/idl')
diff --git a/wscript_build b/wscript_build
index 27dc675..3813cff 100644
--- a/wscript_build
+++ b/wscript_build
@@ -43,6 +43,7 @@ bld.RECURSE('lib/texpect')
 bld.RECURSE('lib/addns')
 bld.RECURSE('lib/ldb')
 bld.RECURSE('lib/param')
+bld.RECURSE('lib/poll_funcs')
 bld.RECURSE('dynconfig')
 bld.RECURSE('lib/util/charset')
 bld.RECURSE('python')
-- 
2.1.4


From 060b7fcfca76de2a7fc23fa769f5ddd721180858 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Sun, 30 Nov 2014 16:10:32 +0100
Subject: [PATCH 7/7] lib: Add accept_send/recv

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 lib/async_req/async_sock.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++
 lib/async_req/async_sock.h |  5 +++
 2 files changed, 87 insertions(+)

diff --git a/lib/async_req/async_sock.c b/lib/async_req/async_sock.c
index c0ad8f3..6383c7c 100644
--- a/lib/async_req/async_sock.c
+++ b/lib/async_req/async_sock.c
@@ -635,3 +635,85 @@ bool wait_for_read_recv(struct tevent_req *req, int *perr)
 
 	return true;
 }
+
+struct accept_state {
+	struct tevent_fd *fde;
+	int listen_sock;
+	socklen_t addrlen;
+	struct sockaddr addr;
+	int sock;
+};
+
+static void accept_handler(struct tevent_context *ev, struct tevent_fd *fde,
+			   uint16_t flags, void *private_data);
+
+struct tevent_req *accept_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			       int listen_sock)
+{
+	struct tevent_req *req;
+	struct accept_state *state;
+
+	req = tevent_req_create(mem_ctx, &state, struct accept_state);
+	if (req == NULL) {
+		return NULL;
+	}
+
+	state->listen_sock = listen_sock;
+
+	state->fde = tevent_add_fd(ev, state, listen_sock, TEVENT_FD_READ,
+				   accept_handler, req);
+	if (tevent_req_nomem(state->fde, req)) {
+		return tevent_req_post(req, ev);
+	}
+	return req;
+}
+
+static void accept_handler(struct tevent_context *ev, struct tevent_fd *fde,
+			   uint16_t flags, void *private_data)
+{
+	struct tevent_req *req = talloc_get_type_abort(
+		private_data, struct tevent_req);
+	struct accept_state *state = tevent_req_data(req, struct accept_state);
+	int ret;
+
+	TALLOC_FREE(state->fde);
+
+	if ((flags & TEVENT_FD_READ) == 0) {
+		tevent_req_error(req, EIO);
+		return;
+	}
+	state->addrlen = sizeof(state->addr);
+
+	ret = accept(state->listen_sock, &state->addr, &state->addrlen);
+	if ((ret == -1) && (errno == EINTR)) {
+		/* retry */
+		return;
+	}
+	if (ret == -1) {
+		tevent_req_error(req, errno);
+		return;
+	}
+	state->sock = ret;
+	tevent_req_done(req);
+}
+
+int accept_recv(struct tevent_req *req, struct sockaddr *paddr,
+		socklen_t *paddrlen, int *perr)
+{
+	struct accept_state *state = tevent_req_data(req, struct accept_state);
+	int err;
+
+	if (tevent_req_is_unix_error(req, &err)) {
+		if (perr != NULL) {
+			*perr = err;
+		}
+		return -1;
+	}
+	if (paddr != NULL) {
+		*paddr = state->addr;
+	}
+	if (paddrlen != NULL) {
+		*paddrlen = state->addrlen;
+	}
+	return state->sock;
+}
diff --git a/lib/async_req/async_sock.h b/lib/async_req/async_sock.h
index abbf822..679e9d9 100644
--- a/lib/async_req/async_sock.h
+++ b/lib/async_req/async_sock.h
@@ -57,4 +57,9 @@ struct tevent_req *wait_for_read_send(TALLOC_CTX *mem_ctx,
 				      bool check_errors);
 bool wait_for_read_recv(struct tevent_req *req, int *perr);
 
+struct tevent_req *accept_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			       int listen_sock);
+int accept_recv(struct tevent_req *req, struct sockaddr *paddr,
+		socklen_t *paddrlen, int *perr);
+
 #endif
-- 
2.1.4

-------------- next part --------------
From e86534ca0419952f5b8413b4241ffd8d90019c33 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Sat, 14 May 2016 10:30:50 +0200
Subject: [PATCH] lib: Add tfd

This is a small daemon that can connect processes with stream sockets
and provide unique IDs.

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 lib/tfd/fddrn.c       |  92 ++++++++
 lib/tfd/fdsrc.c       | 118 +++++++++++
 lib/tfd/sockclnt.c    | 115 ++++++++++
 lib/tfd/socksrv.c     | 106 ++++++++++
 lib/tfd/tfd.c         | 440 ++++++++++++++++++++++++++++++++++++++
 lib/tfd/tfd.h         | 104 +++++++++
 lib/tfd/tfdd.c        | 572 ++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/tfd/wscript_build |  25 +++
 wscript_build         |   1 +
 9 files changed, 1573 insertions(+)
 create mode 100644 lib/tfd/fddrn.c
 create mode 100644 lib/tfd/fdsrc.c
 create mode 100644 lib/tfd/sockclnt.c
 create mode 100644 lib/tfd/socksrv.c
 create mode 100644 lib/tfd/tfd.c
 create mode 100644 lib/tfd/tfd.h
 create mode 100644 lib/tfd/tfdd.c
 create mode 100644 lib/tfd/wscript_build

diff --git a/lib/tfd/fddrn.c b/lib/tfd/fddrn.c
new file mode 100644
index 0000000..e283552
--- /dev/null
+++ b/lib/tfd/fddrn.c
@@ -0,0 +1,92 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Copyright (C) Volker Lendecke 2016
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "replace.h"
+#include "tfd.h"
+#include "poll_funcs/poll_funcs_tevent.h"
+#include <string.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+static void recv_fd_cb(uint64_t src, int fd, void *private_data);
+
+int main(int argc, const char *argv[])
+{
+	struct tevent_context *ev;
+	struct poll_funcs *tevent_poll_funcs;
+	void *poll_funcs_handle;
+	int ret;
+	bool done = false;
+
+	if (argc != 3) {
+		fprintf(stderr, "Usage: %s <tfdd_exec> <sockname>\n",
+			argv[0]);
+		exit(1);
+	}
+
+	ev = tevent_context_init(NULL);
+	if (ev == NULL) {
+		fprintf(stderr, "tevent_context_init failed\n");
+		exit(1);
+	}
+
+	tevent_poll_funcs = poll_funcs_init_tevent(ev);
+	if (tevent_poll_funcs == NULL) {
+		fprintf(stderr, "poll_funcs_init_tevent failed\n");
+		exit(1);
+	}
+
+	poll_funcs_handle = poll_funcs_tevent_register(
+		ev, tevent_poll_funcs, ev);
+	if (poll_funcs_handle == NULL) {
+		fprintf(stderr, "poll_funcs_tevent_register failed\n");
+		exit(1);
+	}
+
+	ret = tfd_init(argv[1], argv[2], tevent_poll_funcs, NULL, 0,
+		       recv_fd_cb, &done, NULL);
+	if (ret != 0) {
+		fprintf(stderr, "tfd_init failed: %s\n", strerror(ret));
+		exit(1);
+	}
+
+	while (!done) {
+		ret = tevent_loop_once(ev);
+		if (ret != 0) {
+			fprintf(stderr, "tevent_loop_once failed: %s\n",
+				strerror(errno));
+			exit(1);
+		}
+	}
+
+	return 0;
+}
+
+static void recv_fd_cb(uint64_t src, int fd, void *private_data)
+{
+	bool *done = private_data;
+
+	if (fd == -1) {
+		*done = true;
+		return;
+	}
+
+	close(fd);
+}
diff --git a/lib/tfd/fdsrc.c b/lib/tfd/fdsrc.c
new file mode 100644
index 0000000..776751f
--- /dev/null
+++ b/lib/tfd/fdsrc.c
@@ -0,0 +1,118 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Copyright (C) Volker Lendecke 2016
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "replace.h"
+#include "tfd.h"
+#include "poll_funcs/poll_funcs_tevent.h"
+#include <string.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+static void recv_fd_cb(uint64_t src, int fd, void *private_data);
+
+int main(int argc, const char *argv[])
+{
+	struct tevent_context *ev;
+	struct poll_funcs *tevent_poll_funcs;
+	void *poll_funcs_handle;
+	int ret;
+	uint64_t dst;
+	bool done = false;
+	uint64_t unique;
+	struct timeval tp1;
+	unsigned count = 0;
+
+	if (argc != 4) {
+		fprintf(stderr, "Usage: %s <tfdd-exec> <sockname> dst\n",
+			argv[0]);
+		exit(1);
+	}
+
+	dst = atoi(argv[3]);
+
+	ev = tevent_context_init(NULL);
+	if (ev == NULL) {
+		fprintf(stderr, "tevent_context_init failed\n");
+		exit(1);
+	}
+
+	tevent_poll_funcs = poll_funcs_init_tevent(ev);
+	if (tevent_poll_funcs == NULL) {
+		fprintf(stderr, "poll_funcs_init_tevent failed\n");
+		exit(1);
+	}
+
+	poll_funcs_handle = poll_funcs_tevent_register(
+		ev, tevent_poll_funcs, ev);
+	if (poll_funcs_handle == NULL) {
+		fprintf(stderr, "poll_funcs_tevent_register failed\n");
+		exit(1);
+	}
+
+	ret = tfd_init(argv[1], argv[2], tevent_poll_funcs, NULL, 0,
+			  recv_fd_cb, &done, &unique);
+	if (ret != 0) {
+		fprintf(stderr, "tfd_init failed: %s\n", strerror(ret));
+		exit(1);
+	}
+
+	printf("I'm unique id %"PRIu64"\n", unique);
+
+	gettimeofday(&tp1, NULL);
+
+	while (true) {
+		struct timeval tp2, diff;
+		int sock;
+
+		ret = tfd_connect(dst, &sock, &unique);
+		if (ret != 0) {
+			fprintf(stderr, "tfd_connect failed: %s\n",
+				strerror(ret));
+			exit(1);
+		}
+		close(sock);
+
+		gettimeofday(&tp2, NULL);
+		diff = tevent_timeval_until(&tp1, &tp2);
+		if (diff.tv_sec != 0) {
+			printf("%8u fds/sec\r", count);
+			fflush(stdout);
+			tp1 = tp2;
+			count = 0;
+		}
+
+		count += 1;
+	}
+
+	printf("Sent to unique id %"PRIu64"\n", unique);
+
+	return 0;
+}
+
+static void recv_fd_cb(uint64_t src, int fd, void *private_data)
+{
+	bool *done = private_data;
+
+	if (fd == -1) {
+		*done = true;
+		return;
+	}
+
+	close(fd);
+}
diff --git a/lib/tfd/sockclnt.c b/lib/tfd/sockclnt.c
new file mode 100644
index 0000000..ca0cefe
--- /dev/null
+++ b/lib/tfd/sockclnt.c
@@ -0,0 +1,115 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Copyright (C) Volker Lendecke 2016
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "replace.h"
+#include "tfd.h"
+#include "poll_funcs/poll_funcs_tevent.h"
+#include <string.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+static void recv_fd_cb(uint64_t src, int fd, void *private_data);
+
+int main(int argc, const char *argv[])
+{
+	struct tevent_context *ev;
+	struct poll_funcs *tevent_poll_funcs;
+	void *poll_funcs_handle;
+	int sock;
+	int ret;
+	uint64_t dst;
+	bool done = false;
+	uint64_t unique;
+	struct timeval tp1;
+
+	if (argc != 4) {
+		fprintf(stderr, "Usage: %s <tfdd_exec> <sockname> dst\n",
+			argv[0]);
+		exit(1);
+	}
+
+	dst = atoi(argv[3]);
+
+	ev = tevent_context_init(NULL);
+	if (ev == NULL) {
+		fprintf(stderr, "tevent_context_init failed\n");
+		exit(1);
+	}
+
+	tevent_poll_funcs = poll_funcs_init_tevent(ev);
+	if (tevent_poll_funcs == NULL) {
+		fprintf(stderr, "poll_funcs_init_tevent failed\n");
+		exit(1);
+	}
+
+	poll_funcs_handle = poll_funcs_tevent_register(
+		ev, tevent_poll_funcs, ev);
+	if (poll_funcs_handle == NULL) {
+		fprintf(stderr, "poll_funcs_tevent_register failed\n");
+		exit(1);
+	}
+
+	ret = tfd_init(argv[1], argv[2], tevent_poll_funcs, NULL, 0,
+			  recv_fd_cb, &done, &unique);
+	if (ret != 0) {
+		fprintf(stderr, "tfd_init failed: %s\n", strerror(ret));
+		exit(1);
+	}
+
+	printf("I'm unique id %"PRIu64"\n", unique);
+
+	gettimeofday(&tp1, NULL);
+
+	ret = tfd_connect(dst, &sock, &unique);
+	if (ret != 0) {
+		fprintf(stderr, "tfd_connect failed: %s\n", strerror(ret));
+		exit(1);
+	}
+
+	printf("Sent to unique id %"PRIu64"\n", unique);
+
+	while (true) {
+		ret = tevent_loop_once(ev);
+		if (ret != 0) {
+			fprintf(stderr, "tevent_loop_once failed: %s\n",
+				strerror(errno));
+			exit(1);
+		}
+	}
+
+	return 0;
+}
+
+static void recv_fd_cb(uint64_t src, int fd, void *private_data)
+{
+	bool *done = private_data;
+	char c;
+	ssize_t ret;
+
+	if (fd == -1) {
+		*done = true;
+		return;
+	}
+
+	do {
+		ret = read(fd, &c, 1);
+	} while ((ret == -1) && (errno == EINTR));
+
+	exit(0);
+}
diff --git a/lib/tfd/socksrv.c b/lib/tfd/socksrv.c
new file mode 100644
index 0000000..7c225da
--- /dev/null
+++ b/lib/tfd/socksrv.c
@@ -0,0 +1,106 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Copyright (C) Volker Lendecke 2016
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "replace.h"
+#include "tfd.h"
+#include "poll_funcs/poll_funcs_tevent.h"
+#include <string.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+static void recv_fd_cb(uint64_t src, int fd, void *private_data);
+
+int main(int argc, const char *argv[])
+{
+	struct tevent_context *ev;
+	struct poll_funcs *tevent_poll_funcs;
+	void *poll_funcs_handle;
+	int ret;
+	bool done = false;
+	int socks[2];
+
+	if (argc != 3) {
+		fprintf(stderr, "Usage: %s <tfdd_exec> <sockname>\n",
+			argv[0]);
+		exit(1);
+	}
+
+	ret = socketpair(AF_UNIX, SOCK_STREAM, 0, socks);
+	if (ret == -1) {
+		fprintf(stderr, "socketpair failed: %s\n", strerror(ret));
+		exit(1);
+	}
+
+	ev = tevent_context_init(NULL);
+	if (ev == NULL) {
+		fprintf(stderr, "tevent_context_init failed\n");
+		exit(1);
+	}
+
+	tevent_poll_funcs = poll_funcs_init_tevent(ev);
+	if (tevent_poll_funcs == NULL) {
+		fprintf(stderr, "poll_funcs_init_tevent failed\n");
+		exit(1);
+	}
+
+	poll_funcs_handle = poll_funcs_tevent_register(
+		ev, tevent_poll_funcs, ev);
+	if (poll_funcs_handle == NULL) {
+		fprintf(stderr, "poll_funcs_tevent_register failed\n");
+		exit(1);
+	}
+
+	ret = tfd_init(argv[1], argv[2], tevent_poll_funcs, NULL, 0,
+			  recv_fd_cb, socks, NULL);
+	if (ret != 0) {
+		fprintf(stderr, "tfd_init failed: %s\n", strerror(ret));
+		exit(1);
+	}
+
+	while (!done) {
+		ret = tevent_loop_once(ev);
+		if (ret != 0) {
+			fprintf(stderr, "tevent_loop_once failed: %s\n",
+				strerror(errno));
+			exit(1);
+		}
+	}
+
+	return 0;
+}
+
+static void recv_fd_cb(uint64_t src, int fd, void *private_data)
+{
+	uint64_t unique;
+	int ret;
+
+	if (fd == -1) {
+		exit(1);
+		return;
+	}
+	close(fd);
+
+	ret = tfd_connect(src, &fd, &unique);
+	if (ret != 0) {
+		fprintf(stderr, "tfd_connect failed: %s\n", strerror(ret));
+		exit(1);
+	}
+	close(fd);
+}
diff --git a/lib/tfd/tfd.c b/lib/tfd/tfd.c
new file mode 100644
index 0000000..ed866c2
--- /dev/null
+++ b/lib/tfd/tfd.c
@@ -0,0 +1,440 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Copyright (C) Volker Lendecke 2016
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "replace.h"
+#include "tfd.h"
+#include "lib/poll_funcs/poll_funcs.h"
+#include "lib/util/msghdr.h"
+#include "lib/util/iov_buf.h"
+#include <poll.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/uio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+
+struct tfd_queue;
+
+struct tfd_state {
+	struct sockaddr_un addr;
+	char tfdd_exec[MAXPATHLEN];
+	int sock;
+	const struct poll_funcs *ev_funcs;
+	struct poll_watch *read_watch;
+	void (*recv_callback)(uint64_t src, int fd, void *private_data);
+	void *private_data;
+	struct tfd_queue *queue;
+};
+
+static struct tfd_state global_tfd_state = { .sock = -1 };
+
+static void tfd_read_cb(struct poll_watch *w, int fd,
+			   short events, void *private_data);
+static int tfd_spawn_tfdd(const char *tfdd_exe, const char *tfdd_sock);
+
+int tfd_init(const char *tfdd_exec, const char *tfdd_sock,
+	     const struct poll_funcs *ev_funcs,
+	     const uint64_t *tfdids, uint64_t num_tfdids,
+	     void (*recv_callback)(uint64_t src, int fd, void *private_data),
+	     void *private_data,
+	     uint64_t *my_unique)
+{
+	struct tfd_state *state = &global_tfd_state;
+	uint64_t pid;
+	ssize_t to_write, rw_ret;
+	int ret;
+	uint64_t unique;
+	struct iovec iov[3];
+
+	if (state->sock != -1) {
+		return EBUSY;
+	}
+
+	if (num_tfdids > 15) {
+		return EMSGSIZE;
+	}
+
+	if (tfdd_exec != NULL) {
+		if (strlcpy(state->tfdd_exec, tfdd_exec,
+			    sizeof(state->tfdd_exec)) >=
+		    sizeof(state->tfdd_exec)) {
+			return ENAMETOOLONG;
+		}
+	} else {
+		state->tfdd_exec[0] = '\0';
+	}
+
+	state->addr.sun_family = AF_UNIX;
+	if (strlcpy(state->addr.sun_path, tfdd_sock,
+		    sizeof(state->addr.sun_path)) >=
+	    sizeof(state->addr.sun_path)) {
+		return ENAMETOOLONG;
+	}
+
+	state->ev_funcs = ev_funcs;
+	state->recv_callback = recv_callback;
+	state->private_data = private_data;
+
+	state->sock = socket(PF_LOCAL, SOCK_STREAM, 0);
+	if (state->sock == -1) {
+		return errno;
+	}
+
+	ret = connect(state->sock, (const struct sockaddr *)&state->addr,
+		      sizeof(state->addr));
+	if ((ret == -1) && (state->tfdd_exec[0] != '\0')) {
+		ret = tfd_spawn_tfdd(state->tfdd_exec, tfdd_sock);
+		if (ret == -1) {
+			goto fail;
+		}
+		ret = connect(state->sock,
+			      (const struct sockaddr *)&state->addr,
+			      sizeof(state->addr));
+		if (ret == -1) {
+			ret = errno;
+			goto fail;
+		}
+	}
+
+	do {
+		rw_ret = read(state->sock, &unique, sizeof(unique));
+	} while ((rw_ret == -1) && (errno == EINTR));
+
+	if (rw_ret == -1) {
+		ret = errno;
+		goto fail;
+	}
+	if (rw_ret != sizeof(unique)) {
+		ret = EPIPE;
+		goto fail;
+	}
+
+	if (my_unique != NULL) {
+		*my_unique = unique;
+	}
+
+	pid = getpid();
+
+	iov[0].iov_base = &num_tfdids;
+	iov[0].iov_len = sizeof(num_tfdids);
+	iov[1].iov_base = &pid;
+	iov[1].iov_len = sizeof(pid);
+
+	iov[2].iov_base = discard_const_p(uint64_t, tfdids);
+	iov[2].iov_len = sizeof(uint64_t) * num_tfdids;
+
+	num_tfdids += 1;
+
+	to_write = iov_buflen(iov, ARRAY_SIZE(iov));
+	if (to_write == -1) {
+		ret = EMSGSIZE;
+		goto fail;
+	}
+
+	do {
+		rw_ret = writev(state->sock, iov, ARRAY_SIZE(iov));
+	} while ((rw_ret == -1) && (errno == EINTR));
+
+	if (rw_ret == -1) {
+		ret = errno;
+		goto fail;
+	}
+	if (rw_ret != to_write) {
+		ret = EPIPE;
+		goto fail;
+	}
+
+	state->read_watch = ev_funcs->watch_new(
+		ev_funcs, state->sock, POLLIN, tfd_read_cb, NULL);
+	if (state->read_watch == NULL) {
+		ret = ENOMEM;
+		goto fail;
+	}
+	return 0;
+
+fail:
+	close(state->sock);
+	state->sock = -1;
+	return ret;
+}
+
+static bool tfd_read(int sock, uint64_t *src, int *fd)
+{
+	size_t bufsize = msghdr_prep_recv_fds(NULL, NULL, 0, 1);
+	uint8_t buf[bufsize];
+	ssize_t ret;
+
+	struct iovec iov = {
+		.iov_base = src, .iov_len = sizeof(*src),
+	};
+	struct msghdr msg = {
+		.msg_iov = &iov, .msg_iovlen = 1,
+	};
+
+	msghdr_prep_recv_fds(&msg, buf, bufsize, 1);
+
+	do {
+		ret = recvmsg(sock, &msg, MSG_NOSIGNAL);
+	} while ((ret == -1) && (errno == EINTR));
+
+	{
+		size_t num_fds = msghdr_extract_fds(&msg, NULL, 0);
+		int fds[num_fds];
+		size_t i;
+
+		msghdr_extract_fds(&msg, fds, num_fds);
+
+		if (ret == iov.iov_len) {
+			if (num_fds == 1) {
+				*fd = fds[0];
+			} else {
+				*fd = -1;
+			}
+			return true;
+		}
+
+		/*
+		 * Close the fds we just received, this is a protocol error
+		 */
+		for (i=0; i<num_fds; i++) {
+			close(fds[i]);
+		}
+	}
+
+	return false;
+}
+
+static void tfd_read_cb(struct poll_watch *w, int fd,
+			short events, void *private_data)
+{
+	struct tfd_state *state = &global_tfd_state;
+	bool ok;
+	uint64_t src;
+	int new_fd;
+
+	if ((events & POLLIN) == 0) {
+		return;
+	}
+
+	ok = tfd_read(state->sock, &src, &new_fd);
+	if (ok) {
+		state->recv_callback(src, new_fd, state->private_data);
+		return;
+	}
+
+	/*
+	 * Protocol error, tell the caller
+	 */
+	state->recv_callback(0, -1, state->private_data);
+}
+
+/*
+ * "local_fd" must NOT have O_NONBLOCK set, otherwise this won't work
+ */
+
+int tfd_connect(uint64_t dst, int *psock, uint64_t *dst_unique)
+{
+	struct tfd_state *state = &global_tfd_state;
+	int socks[2] = { -1, -1 };
+	struct iovec iov = { .iov_base = &dst, .iov_len = sizeof(dst) };
+	struct msghdr msg = { .msg_iov = &iov, .msg_iovlen = 1 };
+	size_t msg_len = msghdr_prep_fds(&msg, NULL, 0, &socks[1], 1);
+	uint8_t msg_buf[msg_len];
+	ssize_t rw_ret;
+	int ret;
+
+	uint8_t result_buf[sizeof(ret) + sizeof(*dst_unique)];
+
+	if (state->sock == -1) {
+		return ENOTCONN;
+	}
+
+	ret = socketpair(AF_UNIX, SOCK_STREAM, 0, socks);
+	if (ret == -1) {
+		return errno;
+	}
+
+	msghdr_prep_fds(&msg, msg_buf, msg_len, &socks[1], 1);
+
+	do {
+		rw_ret = sendmsg(state->sock, &msg, MSG_NOSIGNAL);
+	} while ((rw_ret == -1) && (errno == EINTR));
+
+	if (rw_ret == -1) {
+		ret = errno;
+		goto fail;
+	}
+
+	if (rw_ret != sizeof(dst)) {
+		ret = EIO;
+		goto fail;
+	}
+
+	close(socks[1]);
+	socks[1] = -1;
+
+	do {
+		rw_ret = recv(socks[0], result_buf, sizeof(result_buf),
+			      MSG_NOSIGNAL);
+	} while ((rw_ret == -1) && (errno == EINTR));
+
+	if (rw_ret == -1) {
+		ret = errno;
+		goto fail;
+	}
+	if (rw_ret != sizeof(result_buf)) {
+		ret = EIO;
+		goto fail;
+	}
+
+	memcpy(&ret, result_buf, sizeof(ret));
+	if (dst_unique != NULL) {
+		memcpy(dst_unique, result_buf + sizeof(ret),
+		       sizeof(*dst_unique));
+	}
+
+	if (ret == 0) {
+		*psock = socks[0];
+		socks[0] = -1;
+	}
+
+fail:
+	if (socks[0] != -1) {
+		close(socks[0]);
+	}
+	if (socks[1] != -1) {
+		close(socks[1]);
+	}
+
+	return ret;
+
+}
+
+int tfd_fini(void)
+{
+	struct tfd_state *state = &global_tfd_state;
+
+	if (state->sock == -1) {
+		return ENOTCONN;
+	}
+	state->ev_funcs->watch_free(state->read_watch);
+	close(state->sock);
+	state->sock = -1;
+	return 0;
+}
+
+static void tfd_tfdd_child(const char *tfdd_exec, const char *tfdd_sock)
+{
+	char *argvec[3];
+	char *envvec[1];
+	const char *argv0;
+	pid_t pid;
+	int ret;
+
+	setsid();
+
+	pid = fork();
+	if (pid != 0) {
+		exit(0);
+	}
+	umask(0);
+
+	ret = chdir("/");
+	if (ret == -1) {
+		exit(1);
+	}
+
+	argv0 = strrchr(tfdd_exec, '/');
+	if (argv0 != NULL) {
+		argv0 += 1;
+	} else {
+		argv0 = tfdd_exec;
+	}
+
+	argvec[0] = discard_const_p(char, argv0);
+	argvec[1] = discard_const_p(char, tfdd_sock);
+	argvec[2] = NULL;
+	envvec[0] = NULL;
+
+	execve(tfdd_exec, argvec, envvec);
+	exit(1);
+}
+
+static int tfd_spawn_tfdd(const char *tfdd_exec, const char *tfdd_sock)
+{
+	sigset_t mask, omask;
+	int stdout_pipe[2];
+	int ret;
+	pid_t pid, waited_pid;
+	char ok;
+	ssize_t nread;
+
+	sigemptyset(&mask);
+	sigaddset(&mask, SIGCHLD);
+
+	ret = pthread_sigmask(SIG_BLOCK, &mask, &omask);
+	if (ret != 0) {
+		return ret;
+	}
+
+	ret = pipe(stdout_pipe);
+	if (ret == -1) {
+		ret = errno;
+		pthread_sigmask(SIG_SETMASK, &omask, NULL);
+		return ret;
+	}
+
+	pid = fork();
+	if (pid == -1) {
+		ret = errno;
+		pthread_sigmask(SIG_SETMASK, &omask, NULL);
+		return ret;
+	}
+
+	if (pid == 0) {
+		close(stdout_pipe[0]);
+		dup2(stdout_pipe[1], 1);
+		close(stdout_pipe[1]);
+		tfd_tfdd_child(tfdd_exec, tfdd_sock);
+	}
+
+	close(stdout_pipe[1]);
+
+	do {
+		waited_pid = waitpid(pid, NULL, 0);
+	} while ((waited_pid == -1) && (errno == EINTR));
+
+	pthread_sigmask(SIG_SETMASK, &omask, NULL);
+
+	do {
+		nread = read(stdout_pipe[0], &ok, sizeof(ok));
+	} while ((nread == -1) && (errno == EINTR));
+
+	close(stdout_pipe[0]);
+
+	if (nread == sizeof(ok) && (ok == '1')) {
+		return 0;
+	}
+
+	return EBUSY;
+}
diff --git a/lib/tfd/tfd.h b/lib/tfd/tfd.h
new file mode 100644
index 0000000..ee97451
--- /dev/null
+++ b/lib/tfd/tfd.h
@@ -0,0 +1,104 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Copyright (C) Volker Lendecke 2016
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __TFD_TFD_H__
+#define __TFD_TFD_H__
+
+#include "replace.h"
+
+/**
+ * @file tfd.h
+ *
+ * @brief Routines to connect processes via stream sockets
+ *
+ * To support IPC, this subsystem connects participating processes
+ * with unix domain stream sockets. The function tfd_connect() creates
+ * such a socket pair and sends one end to another process that registered
+ * with the subsystem via tfd_init().
+ *
+ * tfd_init() will fork/exec a central tfdd daemon on demand. tfdd
+ * creates one unix domain stream socket that everybody will connect
+ * to.
+ *
+ * Every participating process has one stream socket open to
+ * tfdd. This stream socket carries file descriptors from and to other
+ * participants, forwarded via tfdd. No IPC data between participants
+ * is transmitted via this stream socket to tfdd, the IPC is done via
+ * the socketpairs created in tfd_connect().
+ *
+ * When connecting, a participant can register 64-bit tfdids that it
+ * can receive messages on. In addition to the explicitly listed
+ * tfdids, tfd_init() will register the current process id.
+ *
+ * As a central point of contact, tfdd assigns a unique 64-bit ID to
+ * every participant. Every time a process calls tfd_connect(), tfdd
+ * increments the unique id that is assigned. This number space is
+ * completely orthogonal to the tfdids a process registers. Samba uses
+ * the unique IDs to protect against recycled PIDs. If a process locks
+ * a file, it registers itself in for example locking.tdb with its
+ * pid/unique combination. A lock contender can make sure that the
+ * lock holder still exists, even if the pid has been recycled by a
+ * different smbd.
+ */
+
+struct poll_funcs;
+
+/**
+ * @brief Connect to the tfdd socket
+ *
+ * Connect to and register the process with tfdd. If tfdd is not
+ * around fork/exec it on demand.
+ *
+ * The current pid is always registered with tfdd.
+ *
+ * @param[in] tfdd_exec tfdd executable, started on demand
+ * @param[in] tfdd_sock Path to tfdd socket
+ * @param[in] ev_funcs poll_funcs structure to register for async fds
+ * @param[in] tfdids IDs to be registered with tfdd
+ * @param[in] num_tfids Number of tfdids
+ * @param[in] recv_callback Callback to receive file descriptors
+ * @param[in] private_data Pointer passed back to recv_callback
+ * @param[out] my_unique Unique ID assigned to the process by tfdd
+ * @return 0 / errno
+ */
+
+int tfd_init(const char *tfdd_exec, const char *tfdd_sock,
+	     const struct poll_funcs *ev_funcs,
+	     const uint64_t *tfdids, uint64_t num_tfdids,
+	     void (*recv_callback)(uint64_t src, int fd, void *private_data),
+	     void *private_data,
+	     uint64_t *my_unique);
+
+/**
+ * @brief Disconnect from the tfdd
+ *
+ * @return 0 / errno
+ */
+int tfd_fini(void);
+
+/**
+ * @brief Connect to a remote process with a stream socket
+ *
+ * @param[in] dst The tfdid of the remote process
+ * @param[out] psock The local end of the stream socket
+ * @param[out] dst_unique The unique id of "dst"
+ * @return 0 / errno
+ */
+int tfd_connect(uint64_t dst, int *psock, uint64_t *dst_unique);
+
+#endif
diff --git a/lib/tfd/tfdd.c b/lib/tfd/tfdd.c
new file mode 100644
index 0000000..7966b5d
--- /dev/null
+++ b/lib/tfd/tfdd.c
@@ -0,0 +1,572 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Copyright (C) Volker Lendecke 2016
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "replace.h"
+#include <stdio.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <talloc.h>
+#include <tevent.h>
+#include <assert.h>
+#include "lib/async_req/async_sock.h"
+#include "lib/util/tevent_unix.h"
+#include "lib/util/dlinklist.h"
+#include "lib/util/blocking.h"
+#include "lib/util/sys_rw_data.h"
+#include "lib/util/msghdr.h"
+
+struct tfdd_state {
+	struct tevent_context *ev;
+	struct tfdd_client_state *clients;
+	uint64_t next_unique;
+	int listen_sock;
+};
+
+struct tfdd_client_state {
+	struct tfdd_client_state *prev, *next;
+	struct tfdd_state *tfdd;
+	int sock;
+	uint64_t unique;
+	uint64_t *tfdids;
+};
+
+static int tfdd_client_state_destructor(struct tfdd_client_state *s);
+static void tfdd_client_handler(struct tevent_context *ev,
+				struct tevent_fd *fde,
+				uint16_t flags,
+				void *private_data);
+
+static struct tevent_req *tfdd_client_send(TALLOC_CTX *mem_ctx,
+					   struct tevent_context *ev,
+					   struct tfdd_state *tfdd,
+					   int sock)
+{
+	struct tevent_req *req;
+	struct tfdd_client_state *state;
+	struct tevent_fd *fde;
+	ssize_t written;
+	int ret;
+
+	req = tevent_req_create(mem_ctx, &state, struct tfdd_client_state);
+	if (req == NULL) {
+		return NULL;
+	}
+	state->sock = sock;
+	state->tfdd = tfdd;
+
+	DLIST_ADD(tfdd->clients, state);
+	talloc_set_destructor(state, tfdd_client_state_destructor);
+
+	fde = tevent_add_fd(ev, state, state->sock, TEVENT_FD_READ,
+			    tfdd_client_handler, req);
+	if (tevent_req_nomem(fde, req)) {
+		return tevent_req_post(req, ev);
+	}
+	tevent_fd_set_auto_close(fde);
+
+	ret = set_blocking(sock, false);
+	if (tevent_req_error(req, ret)) {
+		return tevent_req_post(req, ev);
+	}
+
+	do {
+		written = write(sock, &tfdd->next_unique,
+				sizeof(tfdd->next_unique));
+	} while ((written == -1) && (errno == EINTR));
+
+	if (written != sizeof(tfdd->next_unique)) {
+		tevent_req_done(req);
+		return tevent_req_post(req, ev);
+	}
+
+	state->unique = tfdd->next_unique;
+
+	tfdd->next_unique += 1;
+
+	return req;
+}
+
+static int tfdd_client_state_destructor(struct tfdd_client_state *s)
+{
+	struct tfdd_state *tfdd = s->tfdd;
+
+	DLIST_REMOVE(tfdd->clients, s);
+
+	return 0;
+}
+
+static struct tfdd_client_state *tfdd_find_client(struct tfdd_state *tfdd,
+						  uint64_t tfdid)
+{
+	struct tfdd_client_state *cl;
+
+	for (cl = tfdd->clients; cl; cl = cl->next) {
+		uint64_t *tfdids = cl->tfdids;
+		size_t num_tfdids = talloc_array_length(cl->tfdids);
+		size_t i;
+
+		for (i = 0; i<num_tfdids; i++) {
+			if (tfdids[i] == tfdid) {
+				return cl;
+			}
+		}
+	}
+	return NULL;
+}
+
+static void tfdd_send_fd(struct tfdd_state *tfdd,
+			 uint64_t src, uint64_t dst, int fd)
+{
+	size_t msg_len = msghdr_prep_fds(NULL, NULL, 0, &fd, 1);
+	uint8_t msg_buf[msg_len];
+
+	struct iovec iov = { .iov_base = &src,
+			     .iov_len = sizeof(src) };
+	struct msghdr msg = { .msg_iov = &iov, .msg_iovlen = 1 };
+	struct tfdd_client_state *dst_cli;
+
+	int err = ENOENT;
+	uint64_t dst_unique = UINT64_MAX;
+	uint8_t result_buf[sizeof(err) + sizeof(dst_unique)];
+
+	ssize_t ret;
+
+	msghdr_prep_fds(&msg, msg_buf, msg_len, &fd, 1);
+
+	dst_cli = tfdd_find_client(tfdd, dst);
+
+	/*
+	 * Send the destination unique id to the originating client
+	 * through the newly passed fd
+	 */
+	if (dst_cli != NULL) {
+		dst_unique = dst_cli->unique;
+
+		do {
+			ret = sendmsg(dst_cli->sock, &msg,
+				      MSG_DONTWAIT|MSG_NOSIGNAL);
+		} while ((ret == -1) && (errno == EINTR));
+
+		switch (ret) {
+		    case sizeof(src):
+			    err = 0;
+			    break;
+		    case -1:
+			    err = errno;
+			    break;
+		    default:
+			    err = EIO;
+			    break;
+		}
+	}
+
+	memcpy(result_buf, &err, sizeof(err));
+	memcpy(result_buf + sizeof(err), &dst_unique, sizeof(dst_unique));
+
+	do {
+		ret = send(fd, result_buf, sizeof(result_buf),
+			   MSG_DONTWAIT|MSG_NOSIGNAL);
+	} while ((ret == -1) && (errno == EINTR));
+
+	/*
+	 * Ignore failure here: This was the status response to the fd
+	 * that we just sent across. The most likely error is EAGAIN,
+	 * but we need to protect ourselves from a DoS. A client could
+	 * send us a full socket, so we would block here or consume
+	 * memory if we queued thing. Normally this is one end of a
+	 * fresh socketpair, so this should never be full at this
+	 * point.
+	 */
+}
+
+static void tfdd_client_handle_msg(struct tevent_context *ev,
+				   struct tevent_req *req,
+				   struct msghdr *msg, uint64_t dst,
+				   struct tfdd_client_state *state)
+{
+	size_t num_fds = msghdr_extract_fds(msg, NULL, 0);
+	int fds[num_fds];
+	size_t i;
+
+	msghdr_extract_fds(msg, fds, num_fds);
+
+	if (state->tfdids == NULL) {
+		ssize_t to_read, nread;
+
+		if (num_fds != 0) {
+			goto fail;
+		}
+
+		if (dst == 0) {
+			goto fail;
+		}
+
+		/*
+		 * The very first client->tfdd destination is the
+		 * number of ids to be registered.
+		 */
+
+		state->tfdids = talloc_array(state, uint64_t, dst);
+		if (state->tfdids == NULL) {
+			goto fail;
+		}
+
+		/*
+		 * To avoid an async engine, assume the client sent
+		 * the number together with the tfdids in one call. If
+		 * this turns out to be a problem, we can always add
+		 * some more complexity here.
+		 */
+
+		to_read = talloc_get_size(state->tfdids);
+
+		nread = read_data(state->sock, state->tfdids, to_read);
+		if (nread != to_read) {
+			goto fail;
+		}
+		return;
+	}
+
+	assert(talloc_array_length(state->tfdids) > 0);
+
+	if (num_fds == 1) {
+		/*
+		 * Pass a fd to the dest
+		 */
+		tfdd_send_fd(state->tfdd, state->tfdids[0], dst, fds[0]);
+		close(fds[0]);
+		return;
+	}
+
+	/*
+	 * Protocol error: We only pass at most one fd
+	 */
+
+fail:
+	for (i=0; i<num_fds; i++) {
+		close(fds[i]);
+	}
+	tevent_req_error(req, EINVAL);
+}
+
+static void tfdd_client_handler(struct tevent_context *ev,
+				struct tevent_fd *fde,
+				uint16_t flags,
+				void *private_data)
+{
+	struct tevent_req *req = talloc_get_type_abort(
+		private_data, struct tevent_req);
+	struct tfdd_client_state *state = tevent_req_data(
+		req, struct tfdd_client_state);
+	size_t bufsize = msghdr_prep_recv_fds(NULL, NULL, 0, 1);
+	uint8_t buf[bufsize];
+	uint64_t dst;
+	ssize_t ret;
+
+	struct iovec iov = {
+		.iov_base = &dst, .iov_len = sizeof(dst)
+	};
+	struct msghdr msg = {
+		.msg_iov = &iov, .msg_iovlen = 1,
+	};
+
+	msghdr_prep_recv_fds(&msg, buf, bufsize, 1);
+
+	do {
+		ret = recvmsg(state->sock, &msg, MSG_NOSIGNAL);
+	} while ((ret == -1) && (errno == EINTR));
+
+	if (ret == 0) {
+		tevent_req_done(req);
+		return;
+	}
+
+	if (ret == -1) {
+		tevent_req_error(req, errno);
+		return;
+	}
+
+	if (ret != sizeof(dst)) {
+		tevent_req_error(req, EINVAL);
+		return;
+	}
+
+	{
+		size_t num_fds = msghdr_extract_fds(&msg, NULL, 0);
+		int fds[num_fds];
+
+		msghdr_extract_fds(&msg, fds, num_fds);
+
+		tfdd_client_handle_msg(ev, req, &msg, dst, state);
+	}
+}
+
+static int tfdd_client_recv(struct tevent_req *req)
+{
+	return tevent_req_simple_recv_unix(req);
+}
+
+static void tfdd_accepted(struct tevent_req *subreq);
+static void tfdd_client_exited(struct tevent_req *subreq);
+
+static struct tevent_req *tfdd_send(TALLOC_CTX *mem_ctx,
+				    struct tevent_context *ev,
+				    int listen_sock)
+{
+	struct tevent_req *req, *subreq;
+	struct tfdd_state *state;
+
+	req = tevent_req_create(mem_ctx, &state, struct tfdd_state);
+	if (req == NULL) {
+		return NULL;
+	}
+	state->ev = ev;
+	state->listen_sock = listen_sock;
+	state->next_unique = 1;
+
+	subreq = accept_send(state, state->ev, state->listen_sock);
+	if (tevent_req_nomem(subreq, req)) {
+		return tevent_req_post(req, ev);
+	}
+	tevent_req_set_callback(subreq, tfdd_accepted, req);
+	return req;
+}
+
+static void tfdd_accepted(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct tfdd_state *state = tevent_req_data(
+		req, struct tfdd_state);
+	int sock, err;
+
+	sock = accept_recv(subreq, NULL, NULL, &err);
+	TALLOC_FREE(subreq);
+	if (sock == -1) {
+		tevent_req_error(req, err);
+		return;
+	}
+
+	subreq = tfdd_client_send(state, state->ev, state, sock);
+	if (tevent_req_nomem(subreq, req)) {
+		return;
+	}
+	tevent_req_set_callback(subreq, tfdd_client_exited, req);
+
+	subreq = accept_send(state, state->ev, state->listen_sock);
+	if (tevent_req_nomem(subreq, req)) {
+		return;
+	}
+	tevent_req_set_callback(subreq, tfdd_accepted, req);
+}
+
+static void tfdd_client_exited(struct tevent_req *subreq)
+{
+	tfdd_client_recv(subreq);
+	TALLOC_FREE(subreq);
+}
+
+static int tfdd_recv(struct tevent_req *req)
+{
+	return tevent_req_simple_recv_unix(req);
+}
+
+static int tfdd_create_lockfile(const char *sockname, int *pfd, bool *locked)
+{
+	size_t len = strlen(sockname);
+	char name[len+5];
+	char pidbuf[64];
+	struct flock lck;
+	ssize_t written;
+	int ret, fd;
+
+	snprintf(name, sizeof(name), "%s.lck", sockname);
+
+	fd = open(name, O_NONBLOCK|O_CREAT|O_WRONLY, 0644);
+	if (fd == -1) {
+		return errno;
+	}
+
+	*locked = false;
+
+	lck = (struct flock) { .l_type = F_WRLCK, .l_whence = SEEK_SET };
+	do {
+		ret = fcntl(fd, F_SETLK, &lck);
+	} while ((ret == -1) && (errno == EINTR));
+
+	if (ret == -1) {
+		if (errno == EAGAIN) {
+			*locked = true;
+		}
+		goto fail;
+	}
+
+	do {
+		ret = ftruncate(fd, 0);
+	} while ((ret == -1) && (errno == EINTR));
+
+	if (ret == -1) {
+		goto fail;
+	}
+
+	len = snprintf(pidbuf, sizeof(pidbuf), "%ju\n", (uintmax_t)getpid());
+
+	do {
+		written = pwrite(fd, pidbuf, len, 0);
+	} while ((written == -1) && (errno == EINTR));
+
+	if (written == -1) {
+		goto fail;
+	}
+	if (written != len) {
+		errno = EIO;
+		goto fail;
+	}
+
+	*pfd = fd;
+	return 0;
+fail:
+	ret = errno;
+	close(fd);
+	return ret;
+}
+
+static bool tfdd_try_connect(const struct sockaddr_un *addr)
+{
+	int i, sock;
+
+	sock = socket(PF_LOCAL, SOCK_STREAM, 0);
+	if (sock == -1) {
+		return false;
+	}
+
+	for (i=0; i<5; i++) {
+		int ret;
+		ret = connect(sock, (const struct sockaddr *)addr, sizeof(*addr));
+		if (ret == 0) {
+			close(sock);
+			return true;
+		}
+		poll(NULL, 0, i);
+	}
+
+	close(sock);
+	return false;
+}
+
+static bool write_ok(int fd)
+{
+	const char ok = '1';
+	ssize_t written;
+
+	do {
+		written = write(fd, &ok, sizeof(ok));
+	} while ((written == -1) && (errno == EINTR));
+
+	return written == sizeof(ok);
+}
+
+int main(int argc, const char *argv[])
+{
+	struct tevent_context *ev;
+	struct tevent_req *req;
+	struct sockaddr_un un_addr = { .sun_family = AF_UNIX };
+	size_t len;
+	int sock, ret, lockfd;
+	bool locked = false;
+
+	if (argc < 2) {
+		fprintf(stderr, "Usage: %s <sockname>\n", argv[0]);
+		exit(1);
+	}
+
+	len = strlcpy(un_addr.sun_path, argv[1], sizeof(un_addr.sun_path));
+	if (len >= sizeof(un_addr.sun_path)) {
+		fprintf(stderr, "Socket name (%s) too long, max %u\n",
+			argv[1], (unsigned)sizeof(un_addr.sun_path));
+		exit(1);
+	}
+
+	ev = tevent_context_init(NULL);
+	if (ev == NULL) {
+		perror("tevent_context_create failed");
+		exit(1);
+	}
+
+	ret = tfdd_create_lockfile(un_addr.sun_path, &lockfd, &locked);
+	if (ret != 0) {
+		if (locked && tfdd_try_connect(&un_addr)) {
+			write_ok(1);
+		}
+		fprintf(stderr, "Could not create lockfile: %s\n",
+			strerror(ret));
+		exit(1);
+	}
+
+	sock = socket(PF_LOCAL, SOCK_STREAM, 0);
+	if (sock == -1) {
+		perror("socket failed");
+		exit(1);
+	}
+
+	ret = unlink(un_addr.sun_path);
+	if ((ret == -1) && (errno != ENOENT)) {
+		perror("unlink failed");
+		exit(1);
+	}
+
+	ret = bind(sock, (struct sockaddr *)&un_addr, sizeof(un_addr));
+	if (ret == -1) {
+		perror("bind failed");
+		exit(1);
+	}
+
+	ret = listen(sock, 5);
+	if (ret == -1) {
+		perror("listen failed");
+		exit(1);
+	}
+
+	req = tfdd_send(ev, ev, sock);
+	if (req == NULL) {
+		fprintf(stderr, "tfdd_send failed\n");
+		exit(1);
+	}
+
+	write_ok(1);
+
+	if (!tevent_req_poll(req, ev)) {
+		perror("tevent_req_poll() failed");
+		exit(1);
+	}
+
+	ret = tfdd_recv(req);
+	TALLOC_FREE(req);
+	if (ret != 0) {
+		fprintf(stderr, "tfdd failed: %s\n", strerror(ret));
+		exit(1);
+	}
+
+	TALLOC_FREE(ev);
+
+	return 0;
+}
diff --git a/lib/tfd/wscript_build b/lib/tfd/wscript_build
new file mode 100644
index 0000000..b5aa4ff
--- /dev/null
+++ b/lib/tfd/wscript_build
@@ -0,0 +1,25 @@
+#!/usr/bin/env python
+
+bld.SAMBA_SUBSYSTEM('tfd',
+                    source='tfd.c',
+                    deps='msghdr replace pthread')
+bld.SAMBA_BINARY('tfdd',
+                 source='tfdd.c',
+                 deps='LIBASYNC_REQ msghdr sys_rw',
+                 install_path='${LIBEXECDIR}')
+bld.SAMBA_BINARY('fdsrc',
+                 source='fdsrc.c',
+                 deps='replace talloc POLL_FUNCS_TEVENT tfd',
+                 install=False)
+bld.SAMBA_BINARY('fddrn',
+                 source='fddrn.c',
+                 deps='replace talloc POLL_FUNCS_TEVENT tfd',
+                 install=False)
+bld.SAMBA_BINARY('socksrv',
+                 source='socksrv.c',
+                 deps='replace talloc POLL_FUNCS_TEVENT tfd',
+                 install=False)
+bld.SAMBA_BINARY('sockclnt',
+                 source='sockclnt.c',
+                 deps='replace talloc POLL_FUNCS_TEVENT tfd',
+                 install=False)
diff --git a/wscript_build b/wscript_build
index 3813cff..bf276ed 100644
--- a/wscript_build
+++ b/wscript_build
@@ -44,6 +44,7 @@ bld.RECURSE('lib/addns')
 bld.RECURSE('lib/ldb')
 bld.RECURSE('lib/param')
 bld.RECURSE('lib/poll_funcs')
+bld.RECURSE('lib/tfd')
 bld.RECURSE('dynconfig')
 bld.RECURSE('lib/util/charset')
 bld.RECURSE('python')
-- 
2.1.4



More information about the samba-technical mailing list