First fixes for https://bugzilla.samba.org/show_bug.cgi?id=11141 (11316)

Stefan (metze) Metzmacher metze at samba.org
Mon Jun 8 02:45:36 MDT 2015


Hi,

here're fixes which should fix the generic problem which can happen
in a lot of other places too.

I choose to use the tdgram/tstream abstraction in non performance critical
places, as it has the prevention of this bug builtin.
In other places I kept the low-level read_packet_send/recv and
writev_send/recv
calls and added the protection by hand.

I've create a new bug report here:
https://bugzilla.samba.org/show_bug.cgi?id=11316

Please review carefully and push.

Thanks!
metze

> here're the first patches for
> https://bugzilla.samba.org/show_bug.cgi?id=11141.
> 
> From the bugreport:
> 
>> What happens is the following:
>>
>> - The related winbindd_cli_state has a wb_req_read_send()
>>   or wb_resp_write_send() pending. That means there's
>>   tevent_fd registered with the kernel via epoll_ctl(...ADD)
>> - A new winbindd child is fork'ed and winbindd_reinit_after_fork()
>>   -> close_conns_after_fork() starts to run, but didn't
>>   reach the related winbindd_cli_state yet.
>> - The parent calls remove_client() on the related winbindd_cli_state
>>   maybe via remove_timed_out_clients().
>> - remove_client() calls close() before TALLOC_FREE(state)
>>   the close() doesn't remove the fd from the parents epoll
>>   set yet, as the socket fd is still open in the child.
>>   TALLOC_FREE(state) triggers tevent_req_received() on the pending
>>   wb_req_read or wb_req_write, which then triggers
>>   epoll_event_fd_destructor() -> epoll_update_event() -> epoll_del_event().
>>   The results in epoll_ctl(DEL) returning EBADF because the fd is already
>>   closed in the parent.
>> - As the socket fd was still open in the child, epoll_wait returns
>>   on event in the parent epoll queue, but the pointer in events.data.ptr
>>   is not valid anymore.
>>
>> So we need to make sure the close() comes after epoll_ctl(DEL)
>>
>> As a safe-guard epoll_del_event() should also call epoll_panic()
>> if it gets EBADF, this would result in a fallback to the poll backend
>> instead of crashing later.
> 
> We may need to fix other places with similar problems,
> we need to basically audit all direct and indirect callers
> of writev_send() and read_packet_send(), we need to free the related
> subrequests before calling close() on the socket.
> 
> But the winbind timeout cleanup together with forking new winbindd
> childs seems to be the most common case to trigger crashes.
> 
> It would be cool to have this in 4.2.2 :-)
> 
> 4.0 doesn't use the epoll backend, but 4.1.next should also get the fixes.
> 
> Please review and push.
> Thanks!
> metze
> 
-------------- next part --------------
From 13677f688213d6fc62ae36aeb748680403c46aff Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Sat, 30 May 2015 01:42:08 +0200
Subject: [PATCH 01/31] tevent/testsuite: make sure we cleanup tevent_fd
 structures in the correct order

First we need to remove the tevent_fd structures without
tevent_fd_set_auto_close(). Closing the fd needs to be the last
thing...

BUG: https://bugzilla.samba.org/show_bug.cgi?id=11316

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 lib/tevent/testsuite.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lib/tevent/testsuite.c b/lib/tevent/testsuite.c
index e9d1ef4..c63c878 100644
--- a/lib/tevent/testsuite.c
+++ b/lib/tevent/testsuite.c
@@ -177,10 +177,10 @@ static bool test_event_context(struct torture_context *test,
 		}
 	}
 
-	talloc_free(fde_read);
-	talloc_free(fde_write);
 	talloc_free(fde_read_1);
 	talloc_free(fde_write_1);
+	talloc_free(fde_read);
+	talloc_free(fde_write);
 
 	while (alarm_count < fde_count+1) {
 		if (tevent_loop_once(ev_ctx) == -1) {
-- 
1.9.1


From f277e49d97cb2f3020d6c697d846a80b05220dc4 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 28 May 2015 09:32:26 +0200
Subject: [PATCH 02/31] tevent.h: propose tstream_ versions of
 read_packet_send/recv and writev_send/recv

The functions operating on the raw file descriptor are for advanced callers,
which take extra care and avoid the problems of
https://bugzilla.samba.org/show_bug.cgi?id=11141.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=11316

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 lib/tevent/tevent.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lib/tevent/tevent.h b/lib/tevent/tevent.h
index 6861ffb..b6c39d1 100644
--- a/lib/tevent/tevent.h
+++ b/lib/tevent/tevent.h
@@ -616,8 +616,8 @@ void tevent_get_trace_callback(struct tevent_context *ev,
  * file descriptor (tevent_add_fd) and timer (tevent_add_timed) events
  * are considered too low-level to be used in larger computations. To
  * read and write from and to sockets, Samba provides two calls on top
- * of tevent_add_fd: read_packet_send/recv and writev_send/recv. These
- * requests are much easier to compose than the low-level event
+ * of tevent_add_fd: tstream_read_packet_send/recv and tstream_writev_send/recv.
+ * These requests are much easier to compose than the low-level event
  * handlers called from tevent_add_fd.
  *
  * A lot of the simplicity tevent_req has brought to the notoriously
-- 
1.9.1


From 0e325acb151a083fdb029e85d3ea646ae4755da7 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 21 May 2015 11:37:06 +0200
Subject: [PATCH 03/31] lib/tsocket: add tdgram_bsd_existing_socket() helper
 function

This is similar to tstream_bsd_existing_socket().
Both help to migrate strange code path to using the tstream or tdgram
abstractions.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=11316

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 lib/tsocket/tsocket.h     | 42 ++++++++++++++++++++++++++++++++++++++++++
 lib/tsocket/tsocket_bsd.c | 24 ++++++++++++++++++++++++
 2 files changed, 66 insertions(+)

diff --git a/lib/tsocket/tsocket.h b/lib/tsocket/tsocket.h
index 6b0eef6..296c7c5 100644
--- a/lib/tsocket/tsocket.h
+++ b/lib/tsocket/tsocket.h
@@ -627,6 +627,48 @@ int _tsocket_address_unix_from_path(TALLOC_CTX *mem_ctx,
 char *tsocket_address_unix_path(const struct tsocket_address *addr,
 				TALLOC_CTX *mem_ctx);
 
+#ifdef DOXYGEN
+/**
+ * @brief Wrap an existing file descriptors into the tdgram abstraction.
+ *
+ * You can use this function to wrap an existing file descriptors into the
+ * tdgram abstraction. After that you're not able to use this file descriptor
+ * for anything else. The file descriptor will be closed when the stream gets
+ * freed. If you still want to use the fd you have have to create a duplicate.
+ *
+ * @param[in]  mem_ctx  The talloc memory context to use.
+ *
+ * @param[in]  fd       The non blocking fd to use!
+ *
+ * @param[out] dgram    A pointer to store an allocated tdgram_context.
+ *
+ * @return              0 on success, -1 on error.
+ *
+ * Example:
+ * @code
+ *   fd2 = dup(fd);
+ *   rc = tdgram_bsd_existing_socket(mem_ctx, fd2, &tdgram);
+ *   if (rc < 0) {
+ *     return;
+ *   }
+ * @endcode
+ *
+ * @warning This is an internal function. You should read the code to fully
+ *          understand it if you plan to use it.
+ */
+int tdgram_bsd_existing_socket(TALLOC_CTX *mem_ctx,
+			       int fd,
+			       struct tdgram_context **dgram);
+#else
+int _tdgram_bsd_existing_socket(TALLOC_CTX *mem_ctx,
+				int fd,
+				struct tdgram_context **_dgram,
+				const char *location);
+#define tdgram_bsd_existing_socket(mem_ctx, fd, dgram) \
+	_tdgram_bsd_existing_socket(mem_ctx, fd, dgram, \
+				    __location__)
+#endif
+
 /**
  * @brief Request a syscall optimization for tdgram_recvfrom_send()
  *
diff --git a/lib/tsocket/tsocket_bsd.c b/lib/tsocket/tsocket_bsd.c
index 5d8f80c..9ddbc06 100644
--- a/lib/tsocket/tsocket_bsd.c
+++ b/lib/tsocket/tsocket_bsd.c
@@ -1388,6 +1388,30 @@ static int tdgram_bsd_dgram_socket(const struct tsocket_address *local,
 	return 0;
 }
 
+int _tdgram_bsd_existing_socket(TALLOC_CTX *mem_ctx,
+				int fd,
+				struct tdgram_context **_dgram,
+				const char *location)
+{
+	struct tdgram_context *dgram;
+	struct tdgram_bsd *bsds;
+
+	dgram = tdgram_context_create(mem_ctx,
+				      &tdgram_bsd_ops,
+				      &bsds,
+				      struct tdgram_bsd,
+				      location);
+	if (!dgram) {
+		return -1;
+	}
+	ZERO_STRUCTP(bsds);
+	bsds->fd = fd;
+	talloc_set_destructor(bsds, tdgram_bsd_destructor);
+
+	*_dgram = dgram;
+	return 0;
+}
+
 int _tdgram_inet_udp_socket(const struct tsocket_address *local,
 			    const struct tsocket_address *remote,
 			    TALLOC_CTX *mem_ctx,
-- 
1.9.1


From ec6b6590b4707955522a8a2c64141060af2d7895 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 21 May 2015 11:39:38 +0200
Subject: [PATCH 04/31] lib/tsocket: add tdgram_inet_udp_broadcast_socket()

This is similar to tdgram_inet_udp_socket(), but it allows
the use of ipv4 broadcast traffic.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=11316

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 lib/tsocket/tsocket.h     | 29 +++++++++++++++++++++++++++++
 lib/tsocket/tsocket_bsd.c | 30 ++++++++++++++++++++++++++++++
 2 files changed, 59 insertions(+)

diff --git a/lib/tsocket/tsocket.h b/lib/tsocket/tsocket.h
index 296c7c5..f52b746 100644
--- a/lib/tsocket/tsocket.h
+++ b/lib/tsocket/tsocket.h
@@ -705,6 +705,8 @@ bool tdgram_bsd_optimize_recvfrom(struct tdgram_context *dgram,
  *                      communication. The function will allocate the memory.
  *
  * @return              0 on success, -1 on error with errno set.
+ *
+ * @see tdgram_inet_udp_broadcast_socket()
  */
 int tdgram_inet_udp_socket(const struct tsocket_address *local,
 			    const struct tsocket_address *remote,
@@ -722,6 +724,33 @@ int _tdgram_inet_udp_socket(const struct tsocket_address *local,
 
 #ifdef DOXYGEN
 /**
+ * @brief Create a tdgram_context for a ipv4 UDP broadcast (and unicast) communication.
+ *
+ * @param[in]  local    An 'inet' (ipv4 only) tsocket_address for the local endpoint.
+ *
+ * @param[in]  mem_ctx  The talloc memory context to use.
+ *
+ * @param[in]  dgram    The tdgram_context pointer to setup the udp
+ *                      communication. The function will allocate the memory.
+ *
+ * @return              0 on success, -1 on error with errno set.
+ *
+ * @see tdgram_inet_udp_socket()
+ */
+int tdgram_inet_udp_broadcast_socket(const struct tsocket_address *local,
+				     TALLOC_CTX *mem_ctx,
+				     struct tdgram_context **dgram);
+#else
+int _tdgram_inet_udp_broadcast_socket(const struct tsocket_address *local,
+				      TALLOC_CTX *mem_ctx,
+				      struct tdgram_context **dgram,
+				      const char *location);
+#define tdgram_inet_udp_broadcast_socket(local, mem_ctx, dgram) \
+	_tdgram_inet_udp_broadcast_socket(local, mem_ctx, dgram, __location__)
+#endif
+
+#ifdef DOXYGEN
+/**
  * @brief Create a tdgram_context for unix domain datagram communication.
  *
  * @param[in]  local    An 'unix' tsocket_address for the local endpoint.
diff --git a/lib/tsocket/tsocket_bsd.c b/lib/tsocket/tsocket_bsd.c
index 9ddbc06..f1ece75 100644
--- a/lib/tsocket/tsocket_bsd.c
+++ b/lib/tsocket/tsocket_bsd.c
@@ -1441,6 +1441,36 @@ int _tdgram_inet_udp_socket(const struct tsocket_address *local,
 	return ret;
 }
 
+int _tdgram_inet_udp_broadcast_socket(const struct tsocket_address *local,
+				      TALLOC_CTX *mem_ctx,
+				      struct tdgram_context **dgram,
+				      const char *location)
+{
+	struct tsocket_address_bsd *lbsda =
+		talloc_get_type_abort(local->private_data,
+		struct tsocket_address_bsd);
+	int ret;
+
+	switch (lbsda->u.sa.sa_family) {
+	case AF_INET:
+		break;
+#ifdef HAVE_IPV6
+	case AF_INET6:
+		/* only ipv4 */
+		errno = EINVAL;
+		return -1;
+#endif
+	default:
+		errno = EINVAL;
+		return -1;
+	}
+
+	ret = tdgram_bsd_dgram_socket(local, NULL, true,
+				      mem_ctx, dgram, location);
+
+	return ret;
+}
+
 int _tdgram_unix_socket(const struct tsocket_address *local,
 			const struct tsocket_address *remote,
 			TALLOC_CTX *mem_ctx,
-- 
1.9.1


From 896160e80e637061add205a492c5b81d7eef227c Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 28 May 2015 14:25:27 +0200
Subject: [PATCH 05/31] s4:libcli/raw: make sure
 smbcli_transport_connect_send/recv correctly cleanup on error

We need to make sure that we remove any pending writev_send or read_smb_send
request before closing the socket fd. As a side effect we always close the
socket fd if we don't return success for any any reason.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=11316

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source4/libcli/raw/clisocket.c | 59 ++++++++++++++++++++++++++++++------------
 1 file changed, 42 insertions(+), 17 deletions(-)

diff --git a/source4/libcli/raw/clisocket.c b/source4/libcli/raw/clisocket.c
index dd3ea39..1959a93 100644
--- a/source4/libcli/raw/clisocket.c
+++ b/source4/libcli/raw/clisocket.c
@@ -36,11 +36,14 @@
 struct smbcli_transport_connect_state {
 	struct tevent_context *ev;
 	struct socket_context *sock;
+	struct tevent_req *io_req;
 	uint8_t *request;
 	struct iovec iov;
 	uint8_t *response;
 };
 
+static void smbcli_transport_connect_cleanup(struct tevent_req *req,
+					     enum tevent_req_state req_state);
 static void smbcli_transport_connect_writev_done(struct tevent_req *subreq);
 static void smbcli_transport_connect_read_smb_done(struct tevent_req *subreq);
 
@@ -72,6 +75,8 @@ static struct tevent_req *smbcli_transport_connect_send(TALLOC_CTX *mem_ctx,
 		return tevent_req_post(req, ev);
 	}
 
+	tevent_req_set_cleanup_fn(req, smbcli_transport_connect_cleanup);
+
 	status = nbt_name_to_blob(state, &calling_blob, calling);
 	if (tevent_req_nterror(req, status)) {
 		return tevent_req_post(req, ev);
@@ -115,6 +120,7 @@ static struct tevent_req *smbcli_transport_connect_send(TALLOC_CTX *mem_ctx,
 	tevent_req_set_callback(subreq,
 				smbcli_transport_connect_writev_done,
 				req);
+	state->io_req = subreq;
 
 	if (timeout_msec > 0) {
 		struct timeval endtime;
@@ -128,6 +134,36 @@ static struct tevent_req *smbcli_transport_connect_send(TALLOC_CTX *mem_ctx,
 	return req;
 }
 
+static void smbcli_transport_connect_cleanup(struct tevent_req *req,
+					     enum tevent_req_state req_state)
+{
+	struct smbcli_transport_connect_state *state =
+		tevent_req_data(req,
+		struct smbcli_transport_connect_state);
+
+	TALLOC_FREE(state->io_req);
+
+	if (state->sock == NULL) {
+		return;
+	}
+
+	if (state->sock->fd == -1) {
+		return;
+	}
+
+	if (req_state == TEVENT_REQ_DONE) {
+		/*
+		 * we keep the socket open for the caller to use
+		 */
+		state->sock = NULL;
+		return;
+	}
+
+	close(state->sock->fd);
+	state->sock->fd = -1;
+	state->sock = NULL;
+}
+
 static void smbcli_transport_connect_writev_done(struct tevent_req *subreq)
 {
 	struct tevent_req *req =
@@ -139,14 +175,12 @@ static void smbcli_transport_connect_writev_done(struct tevent_req *subreq)
 	ssize_t ret;
 	int err;
 
+	state->io_req = NULL;
+
 	ret = writev_recv(subreq, &err);
 	TALLOC_FREE(subreq);
 	if (ret == -1) {
 		NTSTATUS status = map_nt_error_from_unix_common(err);
-
-		close(state->sock->fd);
-		state->sock->fd = -1;
-
 		tevent_req_nterror(req, status);
 		return;
 	}
@@ -159,6 +193,7 @@ static void smbcli_transport_connect_writev_done(struct tevent_req *subreq)
 	tevent_req_set_callback(subreq,
 				smbcli_transport_connect_read_smb_done,
 				req);
+	state->io_req = subreq;
 }
 
 static void smbcli_transport_connect_read_smb_done(struct tevent_req *subreq)
@@ -174,22 +209,18 @@ static void smbcli_transport_connect_read_smb_done(struct tevent_req *subreq)
 	NTSTATUS status;
 	uint8_t error;
 
+	state->io_req = NULL;
+
 	ret = read_smb_recv(subreq, state,
 			    &state->response, &err);
+	TALLOC_FREE(subreq);
 	if (ret == -1) {
 		status = map_nt_error_from_unix_common(err);
-
-		close(state->sock->fd);
-		state->sock->fd = -1;
-
 		tevent_req_nterror(req, status);
 		return;
 	}
 
 	if (ret < 4) {
-		close(state->sock->fd);
-		state->sock->fd = -1;
-
 		tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
 		return;
 	}
@@ -201,9 +232,6 @@ static void smbcli_transport_connect_read_smb_done(struct tevent_req *subreq)
 
 	case NBSSnegative:
 		if (ret < 5) {
-			close(state->sock->fd);
-			state->sock->fd = -1;
-
 			tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
 			return;
 		}
@@ -236,9 +264,6 @@ static void smbcli_transport_connect_read_smb_done(struct tevent_req *subreq)
 		break;
 	}
 
-	close(state->sock->fd);
-	state->sock->fd = -1;
-
 	tevent_req_nterror(req, status);
 }
 
-- 
1.9.1


From 3682336aff45e6b4fb305c381d2f2bd52140f0b3 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 21 May 2015 03:45:36 +0200
Subject: [PATCH 06/31] s3:wscript: move lib/util_tsock.c from 'TLDAP' to
 'samba3util'

tstream_read_packet_send/recv() is a generic helper function...

BUG: https://bugzilla.samba.org/show_bug.cgi?id=11316

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source3/wscript_build | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/source3/wscript_build b/source3/wscript_build
index d9b85b8..331153a 100755
--- a/source3/wscript_build
+++ b/source3/wscript_build
@@ -96,8 +96,8 @@ bld.SAMBA3_SUBSYSTEM('GROUPDB',
 bld.SAMBA3_SUBSYSTEM('TLDAP',
                     source='''lib/tldap.c
                     lib/tldap_util.c
-                    lib/util_tsock.c''',
-                    deps='asn1util LIBTSOCKET')
+                    ''',
+                    deps='asn1util LIBTSOCKET samba3util')
 
 # libpdb.so should not expose internal symbols that are only usable
 # to the statically linked modules that are merged into libpdb.
@@ -261,9 +261,10 @@ bld.SAMBA3_SUBSYSTEM('samba3util',
                    lib/util_file.c
                    lib/util.c
                    lib/util_sock.c
+                   lib/util_tsock.c
                    lib/util_transfer_file.c
                    lib/sock_exec.c''',
-                   deps='ndr samba-security NDR_SECURITY samba-util util_tdb sys_rw iov_buf')
+                   deps='ndr LIBTSOCKET samba-security NDR_SECURITY samba-util util_tdb sys_rw iov_buf')
 
 if bld.CONFIG_GET("CTDB_CFLAGS") and bld.CONFIG_GET("CTDB_INCLUDE"):
     SAMBA_CLUSTER_SUPPORT_SOURCES='''
-- 
1.9.1


From 4bb03035afd8ad13bd08ce0e9b21f870cc8d0fc6 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 28 May 2015 13:31:17 +0200
Subject: [PATCH 07/31] s3:lib/background: make sure we destroy a pending
 read_packet_send() before closing the pipe fd

BUG: https://bugzilla.samba.org/show_bug.cgi?id=11316

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source3/lib/background.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/source3/lib/background.c b/source3/lib/background.c
index 869f2ef..4ea1282 100644
--- a/source3/lib/background.c
+++ b/source3/lib/background.c
@@ -34,6 +34,7 @@ struct background_job_state {
 
 	struct tevent_req *wakeup_req;
 	int pipe_fd;
+	struct tevent_req *pipe_req;
 };
 
 static int background_job_state_destructor(struct background_job_state *s);
@@ -103,14 +104,18 @@ struct tevent_req *background_job_send(TALLOC_CTX *mem_ctx,
 static int background_job_state_destructor(struct background_job_state *state)
 {
 	size_t i;
+
+	TALLOC_FREE(state->pipe_req);
 	if (state->pipe_fd != -1) {
 		close(state->pipe_fd);
 		state->pipe_fd = -1;
 	}
+
 	for (i=0; i<state->num_trigger_msgs; i++) {
 		messaging_deregister(state->msg, state->trigger_msgs[i],
 				     state);
 	}
+
 	return 0;
 }
 
@@ -207,6 +212,7 @@ static void background_job_waited(struct tevent_req *subreq)
 		return;
 	}
 	tevent_req_set_callback(subreq, background_job_done, req);
+	state->pipe_req = subreq;
 }
 
 static void background_job_done(struct tevent_req *subreq)
@@ -220,6 +226,8 @@ static void background_job_done(struct tevent_req *subreq)
 	int err;
 	int wait_secs;
 
+	state->pipe_req = NULL;
+
 	ret = read_packet_recv(subreq, talloc_tos(), &buf, &err);
 	TALLOC_FREE(subreq);
 	if (ret == -1) {
-- 
1.9.1


From 5272ae1ad7ed5caf67b768c809c65f1bcddbd8a6 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Fri, 5 Jun 2015 14:19:00 +0200
Subject: [PATCH 08/31] s3:lib/addrchange: look at the correct nl_pid in
 addrchange_done()

state->fromaddr is the address we got from recvfrom_send/recv.

state->addr is completely untouched after tevent_req_create().

BUG: https://bugzilla.samba.org/show_bug.cgi?id=11316

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source3/lib/addrchange.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/source3/lib/addrchange.c b/source3/lib/addrchange.c
index a5d2041..b85a81f 100644
--- a/source3/lib/addrchange.c
+++ b/source3/lib/addrchange.c
@@ -126,7 +126,7 @@ static void addrchange_done(struct tevent_req *subreq)
 		subreq, struct tevent_req);
 	struct addrchange_state *state = tevent_req_data(
 		req, struct addrchange_state);
-	struct sockaddr_nl *addr;
+	struct sockaddr_nl *fromaddr;
 	struct nlmsghdr *h;
 	struct ifaddrmsg *ifa;
 	struct rtattr *rta;
@@ -148,10 +148,10 @@ static void addrchange_done(struct tevent_req *subreq)
 		goto retry;
 	}
 
-	addr = (struct sockaddr_nl *)(void *)&state->addr;
-	if (addr->nl_pid != 0) {
+	fromaddr = (struct sockaddr_nl *)(void *)&state->fromaddr;
+	if (fromaddr->nl_pid != 0) {
 		DEBUG(10, ("Got msg from pid %d, not from the kernel\n",
-			   (int)addr->nl_pid));
+			   (int)fromaddr->nl_pid));
 		goto retry;
 	}
 
-- 
1.9.1


From 831250f8cf03e45ca244bdcea2fd18feb9d04a8f Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 21 May 2015 12:17:24 +0200
Subject: [PATCH 09/31] s3:lib/addrchange: make use of tdgram_* in
 addrchange_*()

This makes the cleanup handling easier to get right,
as we need to make sure any tevent_fd is removed before
closing a socket fd.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=11316

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source3/lib/addrchange.c | 91 +++++++++++++++++++++++++++++-------------------
 1 file changed, 55 insertions(+), 36 deletions(-)

diff --git a/source3/lib/addrchange.c b/source3/lib/addrchange.c
index b85a81f..9a628f7 100644
--- a/source3/lib/addrchange.c
+++ b/source3/lib/addrchange.c
@@ -25,33 +25,44 @@
 #include "asm/types.h"
 #include "linux/netlink.h"
 #include "linux/rtnetlink.h"
-#include "lib/async_req/async_sock.h"
+#include "lib/tsocket/tsocket.h"
 
 struct addrchange_context {
-	int sock;
+	struct tdgram_context *sock;
 };
 
-static int addrchange_context_destructor(struct addrchange_context *c);
-
 NTSTATUS addrchange_context_create(TALLOC_CTX *mem_ctx,
 				   struct addrchange_context **pctx)
 {
 	struct addrchange_context *ctx;
 	struct sockaddr_nl addr;
 	NTSTATUS status;
+	int sock = -1;
 	int res;
+	bool ok;
 
 	ctx = talloc(mem_ctx, struct addrchange_context);
 	if (ctx == NULL) {
 		return NT_STATUS_NO_MEMORY;
 	}
 
-	ctx->sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
-	if (ctx->sock == -1) {
+	sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+	if (sock == -1) {
+		status = map_nt_error_from_unix(errno);
+		goto fail;
+	}
+
+	ok = smb_set_close_on_exec(sock);
+	if (!ok) {
+		status = map_nt_error_from_unix(errno);
+		goto fail;
+	}
+
+	res = set_blocking(sock, false);
+	if (res == -1) {
 		status = map_nt_error_from_unix(errno);
 		goto fail;
 	}
-	talloc_set_destructor(ctx, addrchange_context_destructor);
 
 	/*
 	 * We're interested in address changes
@@ -60,7 +71,13 @@ NTSTATUS addrchange_context_create(TALLOC_CTX *mem_ctx,
 	addr.nl_family = AF_NETLINK;
 	addr.nl_groups = RTMGRP_IPV6_IFADDR | RTMGRP_IPV4_IFADDR;
 
-	res = bind(ctx->sock, (struct sockaddr *)(void *)&addr, sizeof(addr));
+	res = bind(sock, (struct sockaddr *)(void *)&addr, sizeof(addr));
+	if (res == -1) {
+		status = map_nt_error_from_unix(errno);
+		goto fail;
+	}
+
+	res = tdgram_bsd_existing_socket(ctx, sock, &ctx->sock);
 	if (res == -1) {
 		status = map_nt_error_from_unix(errno);
 		goto fail;
@@ -69,25 +86,18 @@ NTSTATUS addrchange_context_create(TALLOC_CTX *mem_ctx,
 	*pctx = ctx;
 	return NT_STATUS_OK;
 fail:
+	if (sock != -1) {
+		close(sock);
+	}
 	TALLOC_FREE(ctx);
 	return status;
 }
 
-static int addrchange_context_destructor(struct addrchange_context *c)
-{
-	if (c->sock != -1) {
-		close(c->sock);
-		c->sock = -1;
-	}
-	return 0;
-}
-
 struct addrchange_state {
 	struct tevent_context *ev;
 	struct addrchange_context *ctx;
-	uint8_t buf[8192];
-	struct sockaddr_storage fromaddr;
-	socklen_t fromaddr_len;
+	uint8_t *buf;
+	struct tsocket_address *fromaddr;
 
 	enum addrchange_type type;
 	struct sockaddr_storage addr;
@@ -109,10 +119,7 @@ struct tevent_req *addrchange_send(TALLOC_CTX *mem_ctx,
 	state->ev = ev;
 	state->ctx = ctx;
 
-	state->fromaddr_len = sizeof(state->fromaddr);
-	subreq = recvfrom_send(state, state->ev, state->ctx->sock,
-			       state->buf, sizeof(state->buf), 0,
-			       &state->fromaddr, &state->fromaddr_len);
+	subreq = tdgram_recvfrom_send(state, state->ev, state->ctx->sock);
 	if (tevent_req_nomem(subreq, req)) {
 		return tevent_req_post(req, state->ev);
 	}
@@ -126,7 +133,11 @@ static void addrchange_done(struct tevent_req *subreq)
 		subreq, struct tevent_req);
 	struct addrchange_state *state = tevent_req_data(
 		req, struct addrchange_state);
-	struct sockaddr_nl *fromaddr;
+	union {
+		struct sockaddr sa;
+		struct sockaddr_nl nl;
+		struct sockaddr_storage ss;
+	} fromaddr;
 	struct nlmsghdr *h;
 	struct ifaddrmsg *ifa;
 	struct rtattr *rta;
@@ -135,23 +146,29 @@ static void addrchange_done(struct tevent_req *subreq)
 	int err;
 	bool found;
 
-	received = recvfrom_recv(subreq, &err);
+	received = tdgram_recvfrom_recv(subreq, &err, state,
+					&state->buf,
+					&state->fromaddr);
 	TALLOC_FREE(subreq);
 	if (received == -1) {
-		DEBUG(10, ("recvfrom returned %s\n", strerror(errno)));
+		DEBUG(10, ("tdgram_recvfrom_recv returned %s\n", strerror(err)));
 		tevent_req_nterror(req, map_nt_error_from_unix(err));
 		return;
 	}
-	if ((state->fromaddr_len != sizeof(struct sockaddr_nl))
-	    || (state->fromaddr.ss_family != AF_NETLINK)) {
+	len = tsocket_address_bsd_sockaddr(state->fromaddr,
+					   &fromaddr.sa,
+					   sizeof(fromaddr));
+
+	if ((len != sizeof(fromaddr.nl) ||
+	    fromaddr.sa.sa_family != AF_NETLINK))
+	{
 		DEBUG(10, ("Got message from wrong addr\n"));
 		goto retry;
 	}
 
-	fromaddr = (struct sockaddr_nl *)(void *)&state->fromaddr;
-	if (fromaddr->nl_pid != 0) {
+	if (fromaddr.nl.nl_pid != 0) {
 		DEBUG(10, ("Got msg from pid %d, not from the kernel\n",
-			   (int)fromaddr->nl_pid));
+			   (int)fromaddr.nl.nl_pid));
 		goto retry;
 	}
 
@@ -246,10 +263,10 @@ static void addrchange_done(struct tevent_req *subreq)
 	return;
 
 retry:
-	state->fromaddr_len = sizeof(state->fromaddr);
-	subreq = recvfrom_send(state, state->ev, state->ctx->sock,
-			       state->buf, sizeof(state->buf), 0,
-			       &state->fromaddr, &state->fromaddr_len);
+	TALLOC_FREE(state->buf);
+	TALLOC_FREE(state->fromaddr);
+
+	subreq = tdgram_recvfrom_send(state, state->ev, state->ctx->sock);
 	if (tevent_req_nomem(subreq, req)) {
 		return;
 	}
@@ -264,11 +281,13 @@ NTSTATUS addrchange_recv(struct tevent_req *req, enum addrchange_type *type,
 	NTSTATUS status;
 
 	if (tevent_req_is_nterror(req, &status)) {
+		tevent_req_received(req);
 		return status;
 	}
 
 	*type = state->type;
 	*addr = state->addr;
+	tevent_req_received(req);
 	return NT_STATUS_OK;
 }
 
-- 
1.9.1


From 3fdcc62a63751d7a7bfec469b03f59aa307ede57 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 21 May 2015 03:00:17 +0200
Subject: [PATCH 10/31] s3:libsmb: remove the cli_session_request as early as
 possible via a nb_connect_cleanup() hook

cli_session_request_send() is likely to use tevent_fd objects on the given
socket fd, so we need to destroy the request before closing the socket fd.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=11316

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source3/libsmb/smbsock_connect.c | 36 ++++++++++++++++++++++++++++++------
 1 file changed, 30 insertions(+), 6 deletions(-)

diff --git a/source3/libsmb/smbsock_connect.c b/source3/libsmb/smbsock_connect.c
index 92abc38..ceaa9b2 100644
--- a/source3/libsmb/smbsock_connect.c
+++ b/source3/libsmb/smbsock_connect.c
@@ -157,12 +157,13 @@ struct nb_connect_state {
 	const struct sockaddr_storage *addr;
 	const char *called_name;
 	int sock;
-
+	struct tevent_req *session_subreq;
 	struct nmb_name called;
 	struct nmb_name calling;
 };
 
-static int nb_connect_state_destructor(struct nb_connect_state *state);
+static void nb_connect_cleanup(struct tevent_req *req,
+			       enum tevent_req_state req_state);
 static void nb_connect_connected(struct tevent_req *subreq);
 static void nb_connect_done(struct tevent_req *subreq);
 
@@ -189,7 +190,7 @@ static struct tevent_req *nb_connect_send(TALLOC_CTX *mem_ctx,
 	make_nmb_name(&state->called, called_name, called_type);
 	make_nmb_name(&state->calling, calling_name, calling_type);
 
-	talloc_set_destructor(state, nb_connect_state_destructor);
+	tevent_req_set_cleanup_fn(req, nb_connect_cleanup);
 
 	subreq = open_socket_out_send(state, ev, addr, NBT_SMB_PORT, 5000);
 	if (tevent_req_nomem(subreq, req)) {
@@ -199,12 +200,31 @@ static struct tevent_req *nb_connect_send(TALLOC_CTX *mem_ctx,
 	return req;
 }
 
-static int nb_connect_state_destructor(struct nb_connect_state *state)
+static void nb_connect_cleanup(struct tevent_req *req,
+			       enum tevent_req_state req_state)
 {
+	struct nb_connect_state *state = tevent_req_data(
+		req, struct nb_connect_state);
+
+	/*
+	 * we need to free a pending request before closing the
+	 * socket, see bug #11141
+	 */
+	TALLOC_FREE(state->session_subreq);
+
+	if (req_state == TEVENT_REQ_DONE) {
+		/*
+		 * we keep the socket open for the caller to use
+		 */
+		return;
+	}
+
 	if (state->sock != -1) {
 		close(state->sock);
+		state->sock = -1;
 	}
-	return 0;
+
+	return;
 }
 
 static void nb_connect_connected(struct tevent_req *subreq)
@@ -227,6 +247,7 @@ static void nb_connect_connected(struct tevent_req *subreq)
 		return;
 	}
 	tevent_req_set_callback(subreq, nb_connect_done, req);
+	state->session_subreq = subreq;
 }
 
 static void nb_connect_done(struct tevent_req *subreq)
@@ -239,6 +260,8 @@ static void nb_connect_done(struct tevent_req *subreq)
 	int err;
 	uint8_t resp;
 
+	state->session_subreq = NULL;
+
 	ret = cli_session_request_recv(subreq, &err, &resp);
 	TALLOC_FREE(subreq);
 	if (!ret) {
@@ -286,7 +309,6 @@ static void nb_connect_done(struct tevent_req *subreq)
 
 	tevent_req_done(req);
 	return;
-
 }
 
 static NTSTATUS nb_connect_recv(struct tevent_req *req, int *sock)
@@ -296,10 +318,12 @@ static NTSTATUS nb_connect_recv(struct tevent_req *req, int *sock)
 	NTSTATUS status;
 
 	if (tevent_req_is_nterror(req, &status)) {
+		tevent_req_received(req);
 		return status;
 	}
 	*sock = state->sock;
 	state->sock = -1;
+	tevent_req_received(req);
 	return NT_STATUS_OK;
 }
 
-- 
1.9.1


From 72ce6eac8497d60fe5ea892f1b785f00439b6ad7 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 21 May 2015 03:01:05 +0200
Subject: [PATCH 11/31] s3:libsmb: remove subreqs as early as possible via a
 smbsock_connect_cleanup() hook

open_socket_out_send() or nb_connect_send() likely use socket fds and
tevent_fd objects. We should clean them up as early as possible.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=11316

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source3/libsmb/smbsock_connect.c | 32 ++++++++++++++++++++++++++------
 1 file changed, 26 insertions(+), 6 deletions(-)

diff --git a/source3/libsmb/smbsock_connect.c b/source3/libsmb/smbsock_connect.c
index ceaa9b2..365e9f1 100644
--- a/source3/libsmb/smbsock_connect.c
+++ b/source3/libsmb/smbsock_connect.c
@@ -340,8 +340,8 @@ struct smbsock_connect_state {
 	uint16_t port;
 };
 
-static int smbsock_connect_state_destructor(
-	struct smbsock_connect_state *state);
+static void smbsock_connect_cleanup(struct tevent_req *req,
+				    enum tevent_req_state req_state);
 static void smbsock_connect_connected(struct tevent_req *subreq);
 static void smbsock_connect_do_139(struct tevent_req *subreq);
 
@@ -373,7 +373,7 @@ struct tevent_req *smbsock_connect_send(TALLOC_CTX *mem_ctx,
 	state->calling_type =
 		(calling_type != -1) ? calling_type : 0x00;
 
-	talloc_set_destructor(state, smbsock_connect_state_destructor);
+	tevent_req_set_cleanup_fn(req, smbsock_connect_cleanup);
 
 	if (port == NBT_SMB_PORT) {
 		state->req_139 = nb_connect_send(state, state->ev, state->addr,
@@ -424,14 +424,32 @@ struct tevent_req *smbsock_connect_send(TALLOC_CTX *mem_ctx,
 	return req;
 }
 
-static int smbsock_connect_state_destructor(
-	struct smbsock_connect_state *state)
+static void smbsock_connect_cleanup(struct tevent_req *req,
+				    enum tevent_req_state req_state)
 {
+	struct smbsock_connect_state *state = tevent_req_data(
+		req, struct smbsock_connect_state);
+
+	/*
+	 * we need to free a pending request before closing the
+	 * socket, see bug #11141
+	 */
+	TALLOC_FREE(state->req_445);
+	TALLOC_FREE(state->req_139);
+
+	if (req_state == TEVENT_REQ_DONE) {
+		/*
+		 * we keep the socket open for the caller to use
+		 */
+		return;
+	}
+
 	if (state->sock != -1) {
 		close(state->sock);
 		state->sock = -1;
 	}
-	return 0;
+
+	return;
 }
 
 static void smbsock_connect_do_139(struct tevent_req *subreq)
@@ -515,6 +533,7 @@ NTSTATUS smbsock_connect_recv(struct tevent_req *req, int *sock,
 	NTSTATUS status;
 
 	if (tevent_req_is_nterror(req, &status)) {
+		tevent_req_received(req);
 		return status;
 	}
 	*sock = state->sock;
@@ -522,6 +541,7 @@ NTSTATUS smbsock_connect_recv(struct tevent_req *req, int *sock,
 	if (ret_port != NULL) {
 		*ret_port = state->port;
 	}
+	tevent_req_received(req);
 	return NT_STATUS_OK;
 }
 
-- 
1.9.1


From a46efd076fa5d1a34be286f1caab681c8af7497f Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 21 May 2015 03:01:30 +0200
Subject: [PATCH 12/31] s3:libsmb: remove pending requests as early as possible
 via a smbsock_any_connect_cleanup() hook

Once we got an error or a valid connection we should destroy all other
connection attempts as early as possible.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=11316

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source3/libsmb/smbsock_connect.c | 33 +++++++++++++++++++++++++++++++--
 1 file changed, 31 insertions(+), 2 deletions(-)

diff --git a/source3/libsmb/smbsock_connect.c b/source3/libsmb/smbsock_connect.c
index 365e9f1..9f915e1 100644
--- a/source3/libsmb/smbsock_connect.c
+++ b/source3/libsmb/smbsock_connect.c
@@ -598,6 +598,8 @@ struct smbsock_any_connect_state {
 	size_t chosen_index;
 };
 
+static void smbsock_any_connect_cleanup(struct tevent_req *req,
+					enum tevent_req_state req_state);
 static bool smbsock_any_connect_send_next(
 	struct tevent_req *req,	struct smbsock_any_connect_state *state);
 static void smbsock_any_connect_trynext(struct tevent_req *subreq);
@@ -628,6 +630,9 @@ struct tevent_req *smbsock_any_connect_send(TALLOC_CTX *mem_ctx,
 	state->calling_names = calling_names;
 	state->calling_types = calling_types;
 	state->port = port;
+	state->fd = -1;
+
+	tevent_req_set_cleanup_fn(req, smbsock_any_connect_cleanup);
 
 	if (num_addrs == 0) {
 		tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
@@ -653,6 +658,27 @@ struct tevent_req *smbsock_any_connect_send(TALLOC_CTX *mem_ctx,
 	return req;
 }
 
+static void smbsock_any_connect_cleanup(struct tevent_req *req,
+					enum tevent_req_state req_state)
+{
+	struct smbsock_any_connect_state *state = tevent_req_data(
+		req, struct smbsock_any_connect_state);
+
+	TALLOC_FREE(state->requests);
+
+	if (req_state == TEVENT_REQ_DONE) {
+		/*
+		 * Keep the socket open for the caller.
+		 */
+		return;
+	}
+
+	if (state->fd != -1) {
+		close(state->fd);
+		state->fd = -1;
+	}
+}
+
 static void smbsock_any_connect_trynext(struct tevent_req *subreq)
 {
 	struct tevent_req *req = tevent_req_callback_data(
@@ -742,9 +768,9 @@ static void smbsock_any_connect_connected(struct tevent_req *subreq)
 
 	if (NT_STATUS_IS_OK(status)) {
 		/*
-		 * This will kill all the other requests
+		 * tevent_req_done() will kill all the other requests
+		 * via smbsock_any_connect_cleanup().
 		 */
-		TALLOC_FREE(state->requests);
 		state->fd = fd;
 		state->chosen_port = chosen_port;
 		state->chosen_index = chosen_index;
@@ -776,15 +802,18 @@ NTSTATUS smbsock_any_connect_recv(struct tevent_req *req, int *pfd,
 	NTSTATUS status;
 
 	if (tevent_req_is_nterror(req, &status)) {
+		tevent_req_received(req);
 		return status;
 	}
 	*pfd = state->fd;
+	state->fd = -1;
 	if (chosen_index != NULL) {
 		*chosen_index = state->chosen_index;
 	}
 	if (chosen_port != NULL) {
 		*chosen_port = state->chosen_port;
 	}
+	tevent_req_received(req);
 	return NT_STATUS_OK;
 }
 
-- 
1.9.1


From cf3e3abe59f86cbeb865903031c9191f056ef0c7 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 21 May 2015 02:20:00 +0200
Subject: [PATCH 13/31] s3:libsmb: let nb_packet_server_destructor() explicitly
 destroy the tevent_fd

The need to destroy the tevent_fd before closing the socket fd.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=11316

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source3/libsmb/unexpected.c | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/source3/libsmb/unexpected.c b/source3/libsmb/unexpected.c
index ee1c360..40c09c3 100644
--- a/source3/libsmb/unexpected.c
+++ b/source3/libsmb/unexpected.c
@@ -41,6 +41,7 @@ struct nb_packet_client;
 struct nb_packet_server {
 	struct tevent_context *ev;
 	int listen_sock;
+	struct tevent_fd *listen_fde;
 	int max_clients;
 	int num_clients;
 	struct nb_packet_client *clients;
@@ -71,7 +72,6 @@ NTSTATUS nb_packet_server_create(TALLOC_CTX *mem_ctx,
 				 struct nb_packet_server **presult)
 {
 	struct nb_packet_server *result;
-	struct tevent_fd *fde;
 	NTSTATUS status;
 	int rc;
 
@@ -96,9 +96,12 @@ NTSTATUS nb_packet_server_create(TALLOC_CTX *mem_ctx,
 	}
 	talloc_set_destructor(result, nb_packet_server_destructor);
 
-	fde = tevent_add_fd(ev, result, result->listen_sock, TEVENT_FD_READ,
-			    nb_packet_server_listener, result);
-	if (fde == NULL) {
+	result->listen_fde = tevent_add_fd(ev, result,
+					   result->listen_sock,
+					   TEVENT_FD_READ,
+					   nb_packet_server_listener,
+					   result);
+	if (result->listen_fde == NULL) {
 		status = NT_STATUS_NO_MEMORY;
 		goto fail;
 	}
@@ -112,6 +115,8 @@ fail:
 
 static int nb_packet_server_destructor(struct nb_packet_server *s)
 {
+	TALLOC_FREE(s->listen_fde);
+
 	if (s->listen_sock != -1) {
 		close(s->listen_sock);
 		s->listen_sock = -1;
-- 
1.9.1


From bdd4eaf4d85644209913775b638724f49366736a Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 21 May 2015 01:53:44 +0200
Subject: [PATCH 14/31] s3:libsmb: convert nb_packet_client to tstream_*
 functions

By using the tstream abstraction we don't need to take care
error handling regarding dangling tevent_fd structures.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=11316

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source3/libsmb/unexpected.c | 118 +++++++++++++++++++++++++-------------------
 source3/wscript_build       |   2 +-
 2 files changed, 68 insertions(+), 52 deletions(-)

diff --git a/source3/libsmb/unexpected.c b/source3/libsmb/unexpected.c
index 40c09c3..5d49469 100644
--- a/source3/libsmb/unexpected.c
+++ b/source3/libsmb/unexpected.c
@@ -20,6 +20,7 @@
 
 #include "includes.h"
 #include "../lib/util/tevent_ntstatus.h"
+#include "lib/tsocket/tsocket.h"
 #include "lib/async_req/async_sock.h"
 #include "libsmb/nmblib.h"
 #include "lib/sys_rw.h"
@@ -55,8 +56,12 @@ struct nb_packet_client {
 	int trn_id;
 	char *mailslot_name;
 
-	int sock;
-	struct tevent_req *read_req;
+	struct {
+		uint8_t byte;
+		struct iovec iov[1];
+	} ack;
+
+	struct tstream_context *sock;
 	struct tevent_queue *out_queue;
 };
 
@@ -128,6 +133,7 @@ static int nb_packet_client_destructor(struct nb_packet_client *c);
 static ssize_t nb_packet_client_more(uint8_t *buf, size_t buflen,
 				     void *private_data);
 static void nb_packet_got_query(struct tevent_req *req);
+static void nb_packet_client_ack_done(struct tevent_req *req);
 static void nb_packet_client_read_done(struct tevent_req *req);
 
 static void nb_packet_server_listener(struct tevent_context *ev,
@@ -142,6 +148,7 @@ static void nb_packet_server_listener(struct tevent_context *ev,
 	struct sockaddr_un sunaddr;
 	socklen_t len;
 	int sock;
+	int ret;
 
 	len = sizeof(sunaddr);
 
@@ -158,7 +165,13 @@ static void nb_packet_server_listener(struct tevent_context *ev,
 		close(sock);
 		return;
 	}
-	client->sock = sock;
+	ret = tstream_bsd_existing_socket(client, sock, &client->sock);
+	if (ret != 0) {
+		DEBUG(10, ("tstream_bsd_existing_socket failed\n"));
+		close(sock);
+		return;
+	}
+
 	client->server = server;
 	talloc_set_destructor(client, nb_packet_client_destructor);
 
@@ -170,11 +183,11 @@ static void nb_packet_server_listener(struct tevent_context *ev,
 		return;
 	}
 
-	req = read_packet_send(client, ev, client->sock,
-			       sizeof(struct nb_packet_query),
-			       nb_packet_client_more, NULL);
+	req = tstream_read_packet_send(client, ev, client->sock,
+				       sizeof(struct nb_packet_query),
+				       nb_packet_client_more, NULL);
 	if (req == NULL) {
-		DEBUG(10, ("read_packet_send failed\n"));
+		DEBUG(10, ("tstream_read_packet_send failed\n"));
 		TALLOC_FREE(client);
 		return;
 	}
@@ -212,10 +225,9 @@ static ssize_t nb_packet_client_more(uint8_t *buf, size_t buflen,
 
 static int nb_packet_client_destructor(struct nb_packet_client *c)
 {
-	if (c->sock != -1) {
-		close(c->sock);
-		c->sock = -1;
-	}
+	tevent_queue_stop(c->out_queue);
+	TALLOC_FREE(c->sock);
+
 	DLIST_REMOVE(c->server->clients, c);
 	c->server->num_clients -= 1;
 	return 0;
@@ -227,11 +239,10 @@ static void nb_packet_got_query(struct tevent_req *req)
 		req, struct nb_packet_client);
 	struct nb_packet_query q;
 	uint8_t *buf;
-	ssize_t nread, nwritten;
+	ssize_t nread;
 	int err;
-	char c;
 
-	nread = read_packet_recv(req, talloc_tos(), &buf, &err);
+	nread = tstream_read_packet_recv(req, talloc_tos(), &buf, &err);
 	TALLOC_FREE(req);
 	if (nread < (ssize_t)sizeof(struct nb_packet_query)) {
 		DEBUG(10, ("read_packet_recv returned %d (%s)\n",
@@ -262,32 +273,51 @@ static void nb_packet_got_query(struct tevent_req *req)
 		}
 	}
 
-	/*
-	 * Yes, this is a blocking write of 1 byte into a unix
-	 * domain socket that has never been written to. Highly
-	 * unlikely that this actually blocks.
-	 */
-	c = 0;
-	nwritten = sys_write(client->sock, &c, sizeof(c));
-	if (nwritten != sizeof(c)) {
-		DEBUG(10, ("Could not write success indicator to client: %s\n",
-			   strerror(errno)));
+	client->ack.byte = 0;
+	client->ack.iov[0].iov_base = &client->ack.byte;
+	client->ack.iov[0].iov_len = 1;
+	req = tstream_writev_queue_send(client, client->server->ev,
+					client->sock,
+					client->out_queue,
+					client->ack.iov, 1);
+	if (req == NULL) {
+		DEBUG(10, ("tstream_writev_queue_send failed\n"));
 		TALLOC_FREE(client);
 		return;
 	}
+	tevent_req_set_callback(req, nb_packet_client_ack_done, client);
 
-	client->read_req = read_packet_send(client, client->server->ev,
-					    client->sock, 1, NULL, NULL);
-	if (client->read_req == NULL) {
+	req = tstream_read_packet_send(client, client->server->ev,
+				       client->sock, 1, NULL, NULL);
+	if (req == NULL) {
 		DEBUG(10, ("Could not activate reader for client exit "
 			   "detection\n"));
 		TALLOC_FREE(client);
 		return;
 	}
-	tevent_req_set_callback(client->read_req, nb_packet_client_read_done,
+	tevent_req_set_callback(req, nb_packet_client_read_done,
 				client);
 }
 
+static void nb_packet_client_ack_done(struct tevent_req *req)
+{
+	struct nb_packet_client *client = tevent_req_callback_data(
+		req, struct nb_packet_client);
+	ssize_t nwritten;
+	int err;
+
+	nwritten = tstream_writev_queue_recv(req, &err);
+
+	TALLOC_FREE(req);
+
+	if (nwritten == -1) {
+		DEBUG(10, ("tstream_writev_queue_recv failed: %s\n",
+			   strerror(err)));
+		TALLOC_FREE(client);
+		return;
+	}
+}
+
 static void nb_packet_client_read_done(struct tevent_req *req)
 {
 	struct nb_packet_client *client = tevent_req_callback_data(
@@ -296,7 +326,7 @@ static void nb_packet_client_read_done(struct tevent_req *req)
 	uint8_t *buf;
 	int err;
 
-	nread = read_packet_recv(req, talloc_tos(), &buf, &err);
+	nread = tstream_read_packet_recv(req, talloc_tos(), &buf, &err);
 	TALLOC_FREE(req);
 	if (nread == 1) {
 		DEBUG(10, ("Protocol error, received data on write-only "
@@ -409,12 +439,12 @@ static void nb_packet_client_send(struct nb_packet_client *client,
 	state->iov[1].iov_base = state->buf;
 	state->iov[1].iov_len = state->hdr.len;
 
-	TALLOC_FREE(client->read_req);
-
-	req = writev_send(client, client->server->ev, client->out_queue,
-			  client->sock, true, state->iov, 2);
+	req = tstream_writev_queue_send(state, client->server->ev,
+					client->sock,
+					client->out_queue,
+					state->iov, 2);
 	if (req == NULL) {
-		DEBUG(10, ("writev_send failed\n"));
+		DEBUG(10, ("tstream_writev_queue_send failed\n"));
 		return;
 	}
 	tevent_req_set_callback(req, nb_packet_client_send_done, state);
@@ -428,29 +458,15 @@ static void nb_packet_client_send_done(struct tevent_req *req)
 	ssize_t nwritten;
 	int err;
 
-	nwritten = writev_recv(req, &err);
+	nwritten = tstream_writev_queue_recv(req, &err);
 
 	TALLOC_FREE(req);
 	TALLOC_FREE(state);
 
 	if (nwritten == -1) {
-		DEBUG(10, ("writev failed: %s\n", strerror(err)));
+		DEBUG(10, ("tstream_writev_queue failed: %s\n", strerror(err)));
 		TALLOC_FREE(client);
-	}
-
-	if (tevent_queue_length(client->out_queue) == 0) {
-		client->read_req = read_packet_send(client, client->server->ev,
-						    client->sock, 1,
-						    NULL, NULL);
-		if (client->read_req == NULL) {
-			DEBUG(10, ("Could not activate reader for client exit "
-				   "detection\n"));
-			TALLOC_FREE(client);
-			return;
-		}
-		tevent_req_set_callback(client->read_req,
-					nb_packet_client_read_done,
-					client);
+		return;
 	}
 }
 
diff --git a/source3/wscript_build b/source3/wscript_build
index 331153a..231f1c0 100755
--- a/source3/wscript_build
+++ b/source3/wscript_build
@@ -736,7 +736,7 @@ bld.SAMBA3_SUBSYSTEM('LIBNMB',
                      libsmb/namequery.c
                      libsmb/conncache.c
                      libads/sitename_cache.c''',
-                     deps='addns lmhosts resolv')
+                     deps='LIBTSOCKET samba3util addns lmhosts resolv')
 
 bld.SAMBA3_SUBSYSTEM('SERVICES',
                     source='''services/svc_spoolss.c
-- 
1.9.1


From af3e8e4124c44b67ecdee0ce20e63d0b2e9230fc Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 21 May 2015 02:18:26 +0200
Subject: [PATCH 15/31] s3:libsmb: convert nb_packet_reader to tstream_*
 functions

By using the tstream abstraction we don't need to take care
error handling regarding dangling tevent_fd structures.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=11316

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source3/libsmb/unexpected.c | 72 +++++++++++++++++++++------------------------
 1 file changed, 34 insertions(+), 38 deletions(-)

diff --git a/source3/libsmb/unexpected.c b/source3/libsmb/unexpected.c
index 5d49469..013d798 100644
--- a/source3/libsmb/unexpected.c
+++ b/source3/libsmb/unexpected.c
@@ -21,7 +21,6 @@
 #include "includes.h"
 #include "../lib/util/tevent_ntstatus.h"
 #include "lib/tsocket/tsocket.h"
-#include "lib/async_req/async_sock.h"
 #include "libsmb/nmblib.h"
 #include "lib/sys_rw.h"
 
@@ -471,12 +470,11 @@ static void nb_packet_client_send_done(struct tevent_req *req)
 }
 
 struct nb_packet_reader {
-	int sock;
+	struct tstream_context *sock;
 };
 
 struct nb_packet_reader_state {
 	struct tevent_context *ev;
-	struct sockaddr_un addr;
 	struct nb_packet_query query;
 	const char *mailslot_name;
 	struct iovec iov[2];
@@ -484,7 +482,6 @@ struct nb_packet_reader_state {
 	struct nb_packet_reader *reader;
 };
 
-static int nb_packet_reader_destructor(struct nb_packet_reader *r);
 static void nb_packet_reader_connected(struct tevent_req *subreq);
 static void nb_packet_reader_sent_query(struct tevent_req *subreq);
 static void nb_packet_reader_got_ack(struct tevent_req *subreq);
@@ -497,7 +494,10 @@ struct tevent_req *nb_packet_reader_send(TALLOC_CTX *mem_ctx,
 {
 	struct tevent_req *req, *subreq;
 	struct nb_packet_reader_state *state;
-	char *path;
+	struct tsocket_address *laddr;
+	char *rpath;
+	struct tsocket_address *raddr;
+	int ret;
 
 	req = tevent_req_create(mem_ctx, &state,
 				struct nb_packet_reader_state);
@@ -518,25 +518,23 @@ struct tevent_req *nb_packet_reader_send(TALLOC_CTX *mem_ctx,
 		return tevent_req_post(req, ev);
 	}
 
-	path = talloc_asprintf(talloc_tos(), "%s/%s", nmbd_socket_dir(),
+	ret = tsocket_address_unix_from_path(state, "", &laddr);
+	if (ret != 0) {
+		tevent_req_nterror(req, map_nt_error_from_unix(errno));
+		return tevent_req_post(req, ev);
+	}
+	rpath = talloc_asprintf(state, "%s/%s", nmbd_socket_dir(),
 			       "unexpected");
-	if (tevent_req_nomem(path, req)) {
+	if (tevent_req_nomem(rpath, req)) {
 		return tevent_req_post(req, ev);
 	}
-	state->addr.sun_family = AF_UNIX;
-	strlcpy(state->addr.sun_path, path, sizeof(state->addr.sun_path));
-	TALLOC_FREE(path);
-
-	state->reader->sock = socket(AF_UNIX, SOCK_STREAM, 0);
-	if (state->reader->sock == -1) {
+	ret = tsocket_address_unix_from_path(state, rpath, &raddr);
+	if (ret != 0) {
 		tevent_req_nterror(req, map_nt_error_from_unix(errno));
 		return tevent_req_post(req, ev);
 	}
-	talloc_set_destructor(state->reader, nb_packet_reader_destructor);
 
-	subreq = async_connect_send(state, ev, state->reader->sock,
-				    (struct sockaddr *)(void *)&state->addr,
-				    sizeof(state->addr), NULL, NULL, NULL);
+	subreq = tstream_unix_connect_send(state, ev, laddr, raddr);
 	if (tevent_req_nomem(subreq, req)) {
 		return tevent_req_post(req, ev);
 	}
@@ -544,15 +542,6 @@ struct tevent_req *nb_packet_reader_send(TALLOC_CTX *mem_ctx,
 	return req;
 }
 
-static int nb_packet_reader_destructor(struct nb_packet_reader *r)
-{
-	if (r->sock != -1) {
-		close(r->sock);
-		r->sock = -1;
-	}
-	return 0;
-}
-
 static void nb_packet_reader_connected(struct tevent_req *subreq)
 {
 	struct tevent_req *req = tevent_req_callback_data(
@@ -562,10 +551,11 @@ static void nb_packet_reader_connected(struct tevent_req *subreq)
 	int res, err;
 	int num_iovecs = 1;
 
-	res = async_connect_recv(subreq, &err);
+	res = tstream_unix_connect_recv(subreq, &err, state->reader,
+					&state->reader->sock);
 	TALLOC_FREE(subreq);
 	if (res == -1) {
-		DEBUG(10, ("async_connect failed: %s\n", strerror(err)));
+		DEBUG(10, ("tstream_unix_connect failed: %s\n", strerror(err)));
 		tevent_req_nterror(req, map_nt_error_from_unix(err));
 		return;
 	}
@@ -580,8 +570,8 @@ static void nb_packet_reader_connected(struct tevent_req *subreq)
 		state->iov[1].iov_len = state->query.mailslot_namelen;
 	}
 
-	subreq = writev_send(state, state->ev, NULL, state->reader->sock,
-			     true, state->iov, num_iovecs);
+	subreq = tstream_writev_send(state, state->ev, state->reader->sock,
+				     state->iov, num_iovecs);
 	if (tevent_req_nomem(subreq, req)) {
 		return;
 	}
@@ -597,7 +587,7 @@ static void nb_packet_reader_sent_query(struct tevent_req *subreq)
 	ssize_t written;
 	int err;
 
-	written = writev_recv(subreq, &err);
+	written = tstream_writev_recv(subreq, &err);
 	TALLOC_FREE(subreq);
 	if (written == -1) {
 		tevent_req_nterror(req, map_nt_error_from_unix(err));
@@ -607,8 +597,9 @@ static void nb_packet_reader_sent_query(struct tevent_req *subreq)
 		tevent_req_nterror(req, NT_STATUS_UNEXPECTED_IO_ERROR);
 		return;
 	}
-	subreq = read_packet_send(state, state->ev, state->reader->sock,
-				  sizeof(state->c), NULL, NULL);
+	subreq = tstream_read_packet_send(state, state->ev,
+					  state->reader->sock,
+					  sizeof(state->c), NULL, NULL);
 	if (tevent_req_nomem(subreq, req)) {
 		return;
 	}
@@ -625,7 +616,7 @@ static void nb_packet_reader_got_ack(struct tevent_req *subreq)
 	int err;
 	uint8_t *buf;
 
-	nread = read_packet_recv(subreq, state, &buf, &err);
+	nread = tstream_read_packet_recv(subreq, state, &buf, &err);
 	TALLOC_FREE(subreq);
 	if (nread == -1) {
 		DEBUG(10, ("read_packet_recv returned %s\n",
@@ -650,9 +641,11 @@ NTSTATUS nb_packet_reader_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
 	NTSTATUS status;
 
 	if (tevent_req_is_nterror(req, &status)) {
+		tevent_req_received(req);
 		return status;
 	}
 	*preader = talloc_move(mem_ctx, &state->reader);
+	tevent_req_received(req);
 	return NT_STATUS_OK;
 }
 
@@ -676,9 +669,9 @@ struct tevent_req *nb_packet_read_send(TALLOC_CTX *mem_ctx,
 	if (req == NULL) {
 		return NULL;
 	}
-	subreq = read_packet_send(state, ev, reader->sock,
-				  sizeof(struct nb_packet_client_header),
-				  nb_packet_read_more, state);
+	subreq = tstream_read_packet_send(state, ev, reader->sock,
+					  sizeof(struct nb_packet_client_header),
+					  nb_packet_read_more, state);
 	if (tevent_req_nomem(subreq, req)) {
 		return tevent_req_post(req, ev);
 	}
@@ -710,7 +703,7 @@ static void nb_packet_read_done(struct tevent_req *subreq)
 	ssize_t nread;
 	int err;
 
-	nread = read_packet_recv(subreq, state, &state->buf, &err);
+	nread = tstream_read_packet_recv(subreq, state, &state->buf, &err);
 	if (nread == -1) {
 		tevent_req_nterror(req, map_nt_error_from_unix(err));
 		return;
@@ -729,6 +722,7 @@ NTSTATUS nb_packet_read_recv(struct tevent_req *req,
 	NTSTATUS status;
 
 	if (tevent_req_is_nterror(req, &status)) {
+		tevent_req_received(req);
 		return status;
 	}
 
@@ -739,8 +733,10 @@ NTSTATUS nb_packet_read_recv(struct tevent_req *req,
 		state->buflen - sizeof(struct nb_packet_client_header),
 		state->hdr.type, state->hdr.ip, state->hdr.port);
 	if (packet == NULL) {
+		tevent_req_received(req);
 		return NT_STATUS_INVALID_NETWORK_RESPONSE;
 	}
 	*ppacket = packet;
+	tevent_req_received(req);
 	return NT_STATUS_OK;
 }
-- 
1.9.1


From 551ababe90b6db3b368af901c43e7b71fae753c1 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 21 May 2015 04:43:27 +0200
Subject: [PATCH 16/31] s3:libsmb: convert nb_trans_send/recv internals to
 tdgram

This simplifies/fixes the cleanup, because we need to remove any
tevent_fd object before closing the socket fd.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=11316

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source3/libsmb/namequery.c | 102 +++++++++++++++++++++++++++++----------------
 1 file changed, 66 insertions(+), 36 deletions(-)

diff --git a/source3/libsmb/namequery.c b/source3/libsmb/namequery.c
index d44b043..e900934 100644
--- a/source3/libsmb/namequery.c
+++ b/source3/libsmb/namequery.c
@@ -24,6 +24,7 @@
 #include "../lib/addns/dnsquery.h"
 #include "../libcli/netlogon/netlogon.h"
 #include "lib/async_req/async_sock.h"
+#include "lib/tsocket/tsocket.h"
 #include "libsmb/nmblib.h"
 #include "../libcli/nbt/libnbt.h"
 
@@ -294,11 +295,10 @@ struct sock_packet_read_state {
 	struct nb_packet_reader *reader;
 	struct tevent_req *reader_req;
 
-	int sock;
+	struct tdgram_context *sock;
 	struct tevent_req *socket_req;
-	uint8_t buf[1024];
-	struct sockaddr_storage addr;
-	socklen_t addr_len;
+	uint8_t *buf;
+	struct tsocket_address *addr;
 
 	bool (*validator)(struct packet_struct *p,
 			  void *private_data);
@@ -314,7 +314,7 @@ static void sock_packet_read_got_socket(struct tevent_req *subreq);
 static struct tevent_req *sock_packet_read_send(
 	TALLOC_CTX *mem_ctx,
 	struct tevent_context *ev,
-	int sock, /* dgram socket */
+	struct tdgram_context *sock,
 	struct nb_packet_reader *reader,
 	enum packet_type type,
 	int trn_id,
@@ -347,10 +347,7 @@ static struct tevent_req *sock_packet_read_send(
 			state->reader_req, sock_packet_read_got_packet, req);
 	}
 
-	state->addr_len = sizeof(state->addr);
-	state->socket_req = recvfrom_send(state, ev, sock,
-					  state->buf, sizeof(state->buf), 0,
-					  &state->addr, &state->addr_len);
+	state->socket_req = tdgram_recvfrom_send(state, ev, state->sock);
 	if (tevent_req_nomem(state->socket_req, req)) {
 		return tevent_req_post(req, ev);
 	}
@@ -422,11 +419,17 @@ static void sock_packet_read_got_socket(struct tevent_req *subreq)
 		subreq, struct tevent_req);
 	struct sock_packet_read_state *state = tevent_req_data(
 		req, struct sock_packet_read_state);
-	struct sockaddr_in *in_addr;
+	union {
+		struct sockaddr sa;
+		struct sockaddr_in sin;
+	} addr;
+	ssize_t ret;
 	ssize_t received;
 	int err;
+	bool ok;
 
-	received = recvfrom_recv(subreq, &err);
+	received = tdgram_recvfrom_recv(subreq, &err, state,
+					&state->buf, &state->addr);
 
 	TALLOC_FREE(state->socket_req);
 
@@ -443,13 +446,20 @@ static void sock_packet_read_got_socket(struct tevent_req *subreq)
 		tevent_req_nterror(req, map_nt_error_from_unix(err));
 		return;
 	}
-	if (state->addr.ss_family != AF_INET) {
+	ok = tsocket_address_is_inet(state->addr, "ipv4");
+	if (!ok) {
 		goto retry;
 	}
-	in_addr = (struct sockaddr_in *)(void *)&state->addr;
+	ret = tsocket_address_bsd_sockaddr(state->addr,
+					   &addr.sa,
+					   sizeof(addr.sin));
+	if (ret == -1) {
+		tevent_req_nterror(req, map_nt_error_from_unix(errno));
+		return;
+	}
 
 	state->packet = parse_packet((char *)state->buf, received, state->type,
-				     in_addr->sin_addr, in_addr->sin_port);
+				     addr.sin.sin_addr, addr.sin.sin_port);
 	if (state->packet == NULL) {
 		DEBUG(10, ("parse_packet failed\n"));
 		goto retry;
@@ -475,9 +485,10 @@ retry:
 		free_packet(state->packet);
 		state->packet = NULL;
 	}
-	state->socket_req = recvfrom_send(state, state->ev, state->sock,
-					  state->buf, sizeof(state->buf), 0,
-					  &state->addr, &state->addr_len);
+	TALLOC_FREE(state->buf);
+	TALLOC_FREE(state->addr);
+
+	state->socket_req = tdgram_recvfrom_send(state, state->ev, state->sock);
 	if (tevent_req_nomem(state->socket_req, req)) {
 		return;
 	}
@@ -502,10 +513,11 @@ static NTSTATUS sock_packet_read_recv(struct tevent_req *req,
 
 struct nb_trans_state {
 	struct tevent_context *ev;
-	int sock;
+	struct tdgram_context *sock;
 	struct nb_packet_reader *reader;
 
-	const struct sockaddr_storage *dst_addr;
+	struct tsocket_address *src_addr;
+	struct tsocket_address *dst_addr;
 	uint8_t *buf;
 	size_t buflen;
 	enum packet_type type;
@@ -527,8 +539,8 @@ static void nb_trans_send_next(struct tevent_req *subreq);
 static struct tevent_req *nb_trans_send(
 	TALLOC_CTX *mem_ctx,
 	struct tevent_context *ev,
-	const struct sockaddr_storage *my_addr,
-	const struct sockaddr_storage *dst_addr,
+	const struct sockaddr_storage *_my_addr,
+	const struct sockaddr_storage *_dst_addr,
 	bool bcast,
 	uint8_t *buf, size_t buflen,
 	enum packet_type type, int trn_id,
@@ -536,8 +548,15 @@ static struct tevent_req *nb_trans_send(
 			  void *private_data),
 	void *private_data)
 {
+	const struct sockaddr *my_addr =
+		discard_const_p(const struct sockaddr, _my_addr);
+	size_t my_addr_len = sizeof(*_my_addr);
+	const struct sockaddr *dst_addr =
+		discard_const_p(const struct sockaddr, _dst_addr);
+	size_t dst_addr_len = sizeof(*_dst_addr);
 	struct tevent_req *req, *subreq;
 	struct nb_trans_state *state;
+	int ret;
 
 	req = tevent_req_create(mem_ctx, &state, struct nb_trans_state);
 	if (req == NULL) {
@@ -545,7 +564,6 @@ static struct tevent_req *nb_trans_send(
 	}
 	talloc_set_destructor(state, nb_trans_state_destructor);
 	state->ev = ev;
-	state->dst_addr = dst_addr;
 	state->buf = buf;
 	state->buflen = buflen;
 	state->type = type;
@@ -553,15 +571,27 @@ static struct tevent_req *nb_trans_send(
 	state->validator = validator;
 	state->private_data = private_data;
 
-	state->sock = open_socket_in(SOCK_DGRAM, 0, 3, my_addr, True);
-	if (state->sock == -1) {
+	ret = tsocket_address_bsd_from_sockaddr(state,
+						my_addr, my_addr_len,
+						&state->src_addr);
+	if (ret == -1) {
 		tevent_req_nterror(req, map_nt_error_from_unix(errno));
-		DEBUG(10, ("open_socket_in failed: %s\n", strerror(errno)));
 		return tevent_req_post(req, ev);
 	}
 
-	if (bcast) {
-		set_socket_options(state->sock,"SO_BROADCAST");
+	ret = tsocket_address_bsd_from_sockaddr(state,
+						dst_addr, dst_addr_len,
+						&state->dst_addr);
+	if (ret == -1) {
+		tevent_req_nterror(req, map_nt_error_from_unix(errno));
+		return tevent_req_post(req, ev);
+	}
+
+	ret = tdgram_inet_udp_broadcast_socket(state->src_addr, state,
+					       &state->sock);
+	if (ret == -1) {
+		tevent_req_nterror(req, map_nt_error_from_unix(errno));
+		return tevent_req_post(req, ev);
 	}
 
 	subreq = nb_packet_reader_send(state, ev, type, state->trn_id, NULL);
@@ -574,10 +604,6 @@ static struct tevent_req *nb_trans_send(
 
 static int nb_trans_state_destructor(struct nb_trans_state *s)
 {
-	if (s->sock != -1) {
-		close(s->sock);
-		s->sock = -1;
-	}
 	if (s->packet != NULL) {
 		free_packet(s->packet);
 		s->packet = NULL;
@@ -610,8 +636,10 @@ static void nb_trans_got_reader(struct tevent_req *subreq)
 	}
 	tevent_req_set_callback(subreq, nb_trans_done, req);
 
-	subreq = sendto_send(state, state->ev, state->sock,
-			     state->buf, state->buflen, 0, state->dst_addr);
+	subreq = tdgram_sendto_send(state, state->ev,
+				    state->sock,
+				    state->buf, state->buflen,
+				    state->dst_addr);
 	if (tevent_req_nomem(subreq, req)) {
 		return;
 	}
@@ -627,7 +655,7 @@ static void nb_trans_sent(struct tevent_req *subreq)
 	ssize_t sent;
 	int err;
 
-	sent = sendto_recv(subreq, &err);
+	sent = tdgram_sendto_recv(subreq, &err);
 	TALLOC_FREE(subreq);
 	if (sent == -1) {
 		DEBUG(10, ("sendto failed: %s\n", strerror(err)));
@@ -656,8 +684,10 @@ static void nb_trans_send_next(struct tevent_req *subreq)
 		tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
 		return;
 	}
-	subreq = sendto_send(state, state->ev, state->sock,
-			     state->buf, state->buflen, 0, state->dst_addr);
+	subreq = tdgram_sendto_send(state, state->ev,
+				    state->sock,
+				    state->buf, state->buflen,
+				    state->dst_addr);
 	if (tevent_req_nomem(subreq, req)) {
 		return;
 	}
-- 
1.9.1


From 6b11ab7db19130330b761448884d1bd7ad7fb432 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 21 May 2015 12:25:38 +0200
Subject: [PATCH 17/31] lib/async_req: remove unused sendto_{send,recv} and
 recvfrom_{send,recv}

BUG: https://bugzilla.samba.org/show_bug.cgi?id=11316

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 lib/async_req/async_sock.c | 178 ---------------------------------------------
 lib/async_req/async_sock.h |  12 ---
 2 files changed, 190 deletions(-)

diff --git a/lib/async_req/async_sock.c b/lib/async_req/async_sock.c
index ee91b8f..dfc81b8 100644
--- a/lib/async_req/async_sock.c
+++ b/lib/async_req/async_sock.c
@@ -33,184 +33,6 @@
 #include "lib/util/tevent_unix.h"
 #include "lib/util/samba_util.h"
 
-#ifndef TALLOC_FREE
-#define TALLOC_FREE(ctx) do { talloc_free(ctx); ctx=NULL; } while(0)
-#endif
-
-struct sendto_state {
-	int fd;
-	const void *buf;
-	size_t len;
-	int flags;
-	const struct sockaddr_storage *addr;
-	socklen_t addr_len;
-	ssize_t sent;
-};
-
-static void sendto_handler(struct tevent_context *ev,
-			       struct tevent_fd *fde,
-			       uint16_t flags, void *private_data);
-
-struct tevent_req *sendto_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
-			       int fd, const void *buf, size_t len, int flags,
-			       const struct sockaddr_storage *addr)
-{
-	struct tevent_req *result;
-	struct sendto_state *state;
-	struct tevent_fd *fde;
-
-	result = tevent_req_create(mem_ctx, &state, struct sendto_state);
-	if (result == NULL) {
-		return result;
-	}
-	state->fd = fd;
-	state->buf = buf;
-	state->len = len;
-	state->flags = flags;
-	state->addr = addr;
-
-	switch (addr->ss_family) {
-	case AF_INET:
-		state->addr_len = sizeof(struct sockaddr_in);
-		break;
-#if defined(HAVE_IPV6)
-	case AF_INET6:
-		state->addr_len = sizeof(struct sockaddr_in6);
-		break;
-#endif
-	case AF_UNIX:
-		state->addr_len = sizeof(struct sockaddr_un);
-		break;
-	default:
-		state->addr_len = sizeof(struct sockaddr_storage);
-		break;
-	}
-
-	fde = tevent_add_fd(ev, state, fd, TEVENT_FD_WRITE, sendto_handler,
-			    result);
-	if (fde == NULL) {
-		TALLOC_FREE(result);
-		return NULL;
-	}
-	return result;
-}
-
-static void sendto_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 sendto_state *state =
-		tevent_req_data(req, struct sendto_state);
-
-	state->sent = sendto(state->fd, state->buf, state->len, state->flags,
-			     (const struct sockaddr *)state->addr,
-			     state->addr_len);
-	if ((state->sent == -1) && (errno == EINTR)) {
-		/* retry */
-		return;
-	}
-	if (state->sent == -1) {
-		tevent_req_error(req, errno);
-		return;
-	}
-	tevent_req_done(req);
-}
-
-ssize_t sendto_recv(struct tevent_req *req, int *perrno)
-{
-	struct sendto_state *state =
-		tevent_req_data(req, struct sendto_state);
-
-	if (tevent_req_is_unix_error(req, perrno)) {
-		return -1;
-	}
-	return state->sent;
-}
-
-struct recvfrom_state {
-	int fd;
-	void *buf;
-	size_t len;
-	int flags;
-	struct sockaddr_storage *addr;
-	socklen_t *addr_len;
-	ssize_t received;
-};
-
-static void recvfrom_handler(struct tevent_context *ev,
-			       struct tevent_fd *fde,
-			       uint16_t flags, void *private_data);
-
-struct tevent_req *recvfrom_send(TALLOC_CTX *mem_ctx,
-				 struct tevent_context *ev,
-				 int fd, void *buf, size_t len, int flags,
-				 struct sockaddr_storage *addr,
-				 socklen_t *addr_len)
-{
-	struct tevent_req *result;
-	struct recvfrom_state *state;
-	struct tevent_fd *fde;
-
-	result = tevent_req_create(mem_ctx, &state, struct recvfrom_state);
-	if (result == NULL) {
-		return result;
-	}
-	state->fd = fd;
-	state->buf = buf;
-	state->len = len;
-	state->flags = flags;
-	state->addr = addr;
-	state->addr_len = addr_len;
-
-	fde = tevent_add_fd(ev, state, fd, TEVENT_FD_READ, recvfrom_handler,
-			    result);
-	if (fde == NULL) {
-		TALLOC_FREE(result);
-		return NULL;
-	}
-	return result;
-}
-
-static void recvfrom_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 recvfrom_state *state =
-		tevent_req_data(req, struct recvfrom_state);
-
-	state->received = recvfrom(state->fd, state->buf, state->len,
-				   state->flags, (struct sockaddr *)state->addr,
-				   state->addr_len);
-	if ((state->received == -1) && (errno == EINTR)) {
-		/* retry */
-		return;
-	}
-	if (state->received == 0) {
-		tevent_req_error(req, EPIPE);
-		return;
-	}
-	if (state->received == -1) {
-		tevent_req_error(req, errno);
-		return;
-	}
-	tevent_req_done(req);
-}
-
-ssize_t recvfrom_recv(struct tevent_req *req, int *perrno)
-{
-	struct recvfrom_state *state =
-		tevent_req_data(req, struct recvfrom_state);
-
-	if (tevent_req_is_unix_error(req, perrno)) {
-		return -1;
-	}
-	return state->received;
-}
-
 struct async_connect_state {
 	int fd;
 	int result;
diff --git a/lib/async_req/async_sock.h b/lib/async_req/async_sock.h
index 494b92e..1b76fab 100644
--- a/lib/async_req/async_sock.h
+++ b/lib/async_req/async_sock.h
@@ -28,18 +28,6 @@
 #include <tevent.h>
 #include "system/network.h"
 
-struct tevent_req *sendto_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
-			       int fd, const void *buf, size_t len, int flags,
-			       const struct sockaddr_storage *addr);
-ssize_t sendto_recv(struct tevent_req *req, int *perrno);
-
-struct tevent_req *recvfrom_send(TALLOC_CTX *mem_ctx,
-				 struct tevent_context *ev,
-				 int fd, void *buf, size_t len, int flags,
-				 struct sockaddr_storage *addr,
-				 socklen_t *addr_len);
-ssize_t recvfrom_recv(struct tevent_req *req, int *perrno);
-
 struct tevent_req *async_connect_send(
 	TALLOC_CTX *mem_ctx, struct tevent_context *ev, int fd,
 	const struct sockaddr *address, socklen_t address_len,
-- 
1.9.1


From 9f74170f0f95abbdc90b2182134b63e9f56f8753 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Fri, 5 Jun 2015 13:58:19 +0200
Subject: [PATCH 18/31] lib/async_req: s/result/req/ in async_connect_send()

BUG: https://bugzilla.samba.org/show_bug.cgi?id=11316

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 lib/async_req/async_sock.c | 17 ++++++++---------
 1 file changed, 8 insertions(+), 9 deletions(-)

diff --git a/lib/async_req/async_sock.c b/lib/async_req/async_sock.c
index dfc81b8..fec306d 100644
--- a/lib/async_req/async_sock.c
+++ b/lib/async_req/async_sock.c
@@ -70,13 +70,12 @@ struct tevent_req *async_connect_send(
 	void (*after_connect)(void *private_data),
 	void *private_data)
 {
-	struct tevent_req *result;
+	struct tevent_req *req;
 	struct async_connect_state *state;
 	struct tevent_fd *fde;
 
-	result = tevent_req_create(
-		mem_ctx, &state, struct async_connect_state);
-	if (result == NULL) {
+	req = tevent_req_create(mem_ctx, &state, struct async_connect_state);
+	if (req == NULL) {
 		return NULL;
 	}
 
@@ -116,7 +115,7 @@ struct tevent_req *async_connect_send(
 	}
 
 	if (state->result == 0) {
-		tevent_req_done(result);
+		tevent_req_done(req);
 		goto done;
 	}
 
@@ -137,18 +136,18 @@ struct tevent_req *async_connect_send(
 	}
 
 	fde = tevent_add_fd(ev, state, fd, TEVENT_FD_READ | TEVENT_FD_WRITE,
-			   async_connect_connected, result);
+			   async_connect_connected, req);
 	if (fde == NULL) {
 		state->sys_errno = ENOMEM;
 		goto post_errno;
 	}
-	return result;
+	return req;
 
  post_errno:
-	tevent_req_error(result, state->sys_errno);
+	tevent_req_error(req, state->sys_errno);
  done:
 	fcntl(fd, F_SETFL, state->old_sockflags);
-	return tevent_req_post(result, ev);
+	return tevent_req_post(req, ev);
 }
 
 /**
-- 
1.9.1


From e9502ec9b4532a9c4e6cb4bdc7b47d6db3419e12 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 21 May 2015 22:28:14 +0200
Subject: [PATCH 19/31] lib/async_req: simplify async_connect_* using a
 _cleanup() hook

This makes sure we remove the tevent_fd as soon as possible
and always reset the old_sockflags.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=11316

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 lib/async_req/async_sock.c | 68 ++++++++++++++++++++++------------------------
 1 file changed, 33 insertions(+), 35 deletions(-)

diff --git a/lib/async_req/async_sock.c b/lib/async_req/async_sock.c
index fec306d..afa1456 100644
--- a/lib/async_req/async_sock.c
+++ b/lib/async_req/async_sock.c
@@ -35,8 +35,8 @@
 
 struct async_connect_state {
 	int fd;
+	struct tevent_fd *fde;
 	int result;
-	int sys_errno;
 	long old_sockflags;
 	socklen_t address_len;
 	struct sockaddr_storage address;
@@ -46,6 +46,8 @@ struct async_connect_state {
 	void *private_data;
 };
 
+static void async_connect_cleanup(struct tevent_req *req,
+				  enum tevent_req_state req_state);
 static void async_connect_connected(struct tevent_context *ev,
 				    struct tevent_fd *fde, uint16_t flags,
 				    void *priv);
@@ -72,7 +74,6 @@ struct tevent_req *async_connect_send(
 {
 	struct tevent_req *req;
 	struct async_connect_state *state;
-	struct tevent_fd *fde;
 
 	req = tevent_req_create(mem_ctx, &state, struct async_connect_state);
 	if (req == NULL) {
@@ -85,20 +86,22 @@ struct tevent_req *async_connect_send(
 	 */
 
 	state->fd = fd;
-	state->sys_errno = 0;
 	state->before_connect = before_connect;
 	state->after_connect = after_connect;
 	state->private_data = private_data;
 
 	state->old_sockflags = fcntl(fd, F_GETFL, 0);
 	if (state->old_sockflags == -1) {
-		goto post_errno;
+		tevent_req_error(req, errno);
+		return tevent_req_post(req, ev);
 	}
 
+	tevent_req_set_cleanup_fn(req, async_connect_cleanup);
+
 	state->address_len = address_len;
 	if (address_len > sizeof(state->address)) {
-		errno = EINVAL;
-		goto post_errno;
+		tevent_req_error(req, EINVAL);
+		return tevent_req_post(req, ev);
 	}
 	memcpy(&state->address, address, address_len);
 
@@ -116,7 +119,7 @@ struct tevent_req *async_connect_send(
 
 	if (state->result == 0) {
 		tevent_req_done(req);
-		goto done;
+		return tevent_req_post(req, ev);
 	}
 
 	/**
@@ -131,23 +134,31 @@ struct tevent_req *async_connect_send(
 	      errno == EISCONN ||
 #endif
 	      errno == EAGAIN || errno == EINTR)) {
-		state->sys_errno = errno;
-		goto post_errno;
+		tevent_req_error(req, errno);
+		return tevent_req_post(req, ev);
 	}
 
-	fde = tevent_add_fd(ev, state, fd, TEVENT_FD_READ | TEVENT_FD_WRITE,
-			   async_connect_connected, req);
-	if (fde == NULL) {
-		state->sys_errno = ENOMEM;
-		goto post_errno;
+	state->fde = tevent_add_fd(ev, state, fd,
+				   TEVENT_FD_READ | TEVENT_FD_WRITE,
+				   async_connect_connected, req);
+	if (state->fde == NULL) {
+		tevent_req_error(req, ENOMEM);
+		return tevent_req_post(req, ev);
 	}
 	return req;
+}
 
- post_errno:
-	tevent_req_error(req, state->sys_errno);
- done:
-	fcntl(fd, F_SETFL, state->old_sockflags);
-	return tevent_req_post(req, ev);
+static void async_connect_cleanup(struct tevent_req *req,
+				  enum tevent_req_state req_state)
+{
+	struct async_connect_state *state =
+		tevent_req_data(req, struct async_connect_state);
+
+	TALLOC_FREE(state->fde);
+	if (state->fd != -1) {
+		fcntl(state->fd, F_SETFL, state->old_sockflags);
+		state->fd = -1;
+	}
 }
 
 /**
@@ -180,8 +191,6 @@ static void async_connect_connected(struct tevent_context *ev,
 	}
 
 	if (ret == 0) {
-		state->sys_errno = 0;
-		TALLOC_FREE(fde);
 		tevent_req_done(req);
 		return;
 	}
@@ -189,31 +198,20 @@ static void async_connect_connected(struct tevent_context *ev,
 		/* Try again later, leave the fde around */
 		return;
 	}
-	state->sys_errno = errno;
-	TALLOC_FREE(fde);
 	tevent_req_error(req, errno);
 	return;
 }
 
 int async_connect_recv(struct tevent_req *req, int *perrno)
 {
-	struct async_connect_state *state =
-		tevent_req_data(req, struct async_connect_state);
-	int err;
-
-	fcntl(state->fd, F_SETFL, state->old_sockflags);
+	int err = tevent_req_simple_recv_unix(req);
 
-	if (tevent_req_is_unix_error(req, &err)) {
+	if (err != 0) {
 		*perrno = err;
 		return -1;
 	}
 
-	if (state->sys_errno == 0) {
-		return 0;
-	}
-
-	*perrno = state->sys_errno;
-	return -1;
+	return 0;
 }
 
 struct writev_state {
-- 
1.9.1


From 91dc4293802e64bd0584a8bb1e18cd9403e60122 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 21 May 2015 22:28:14 +0200
Subject: [PATCH 20/31] lib/async_req: remove the tevent_fd as early as
 possible via a writev_cleanup() hook

BUG: https://bugzilla.samba.org/show_bug.cgi?id=11316

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 lib/async_req/async_sock.c | 41 +++++++++++++++++++++++++++--------------
 1 file changed, 27 insertions(+), 14 deletions(-)

diff --git a/lib/async_req/async_sock.c b/lib/async_req/async_sock.c
index afa1456..8cccd15 100644
--- a/lib/async_req/async_sock.c
+++ b/lib/async_req/async_sock.c
@@ -217,6 +217,7 @@ int async_connect_recv(struct tevent_req *req, int *perrno)
 struct writev_state {
 	struct tevent_context *ev;
 	int fd;
+	struct tevent_fd *fde;
 	struct iovec *iov;
 	int count;
 	size_t total_size;
@@ -224,6 +225,8 @@ struct writev_state {
 	bool err_on_readability;
 };
 
+static void writev_cleanup(struct tevent_req *req,
+			   enum tevent_req_state req_state);
 static void writev_trigger(struct tevent_req *req, void *private_data);
 static void writev_handler(struct tevent_context *ev, struct tevent_fd *fde,
 			   uint16_t flags, void *private_data);
@@ -246,40 +249,46 @@ struct tevent_req *writev_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
 	state->count = count;
 	state->iov = (struct iovec *)talloc_memdup(
 		state, iov, sizeof(struct iovec) * count);
-	if (state->iov == NULL) {
-		goto fail;
+	if (tevent_req_nomem(state->iov, req)) {
+		return tevent_req_post(req, ev);
 	}
 	state->flags = TEVENT_FD_WRITE|TEVENT_FD_READ;
 	state->err_on_readability = err_on_readability;
 
+	tevent_req_set_cleanup_fn(req, writev_cleanup);
+
 	if (queue == NULL) {
-		struct tevent_fd *fde;
-		fde = tevent_add_fd(state->ev, state, state->fd,
+		state->fde = tevent_add_fd(state->ev, state, state->fd,
 				    state->flags, writev_handler, req);
-		if (tevent_req_nomem(fde, req)) {
+		if (tevent_req_nomem(state->fde, req)) {
 			return tevent_req_post(req, ev);
 		}
 		return req;
 	}
 
 	if (!tevent_queue_add(queue, ev, req, writev_trigger, NULL)) {
-		goto fail;
+		tevent_req_nomem(NULL, req);
+		return tevent_req_post(req, ev);
 	}
 	return req;
- fail:
-	TALLOC_FREE(req);
-	return NULL;
+}
+
+static void writev_cleanup(struct tevent_req *req,
+			   enum tevent_req_state req_state)
+{
+	struct writev_state *state = tevent_req_data(req, struct writev_state);
+
+	TALLOC_FREE(state->fde);
 }
 
 static void writev_trigger(struct tevent_req *req, void *private_data)
 {
 	struct writev_state *state = tevent_req_data(req, struct writev_state);
-	struct tevent_fd *fde;
 
-	fde = tevent_add_fd(state->ev, state, state->fd, state->flags,
+	state->fde = tevent_add_fd(state->ev, state, state->fd, state->flags,
 			    writev_handler, req);
-	if (fde == NULL) {
-		tevent_req_error(req, ENOMEM);
+	if (tevent_req_nomem(state->fde, req)) {
+		return;
 	}
 }
 
@@ -356,11 +365,15 @@ ssize_t writev_recv(struct tevent_req *req, int *perrno)
 {
 	struct writev_state *state =
 		tevent_req_data(req, struct writev_state);
+	ssize_t ret;
 
 	if (tevent_req_is_unix_error(req, perrno)) {
+		tevent_req_received(req);
 		return -1;
 	}
-	return state->total_size;
+	ret = state->total_size;
+	tevent_req_received(req);
+	return ret;
 }
 
 struct read_packet_state {
-- 
1.9.1


From ebf3fbf9410aeabf56d8b6a74d35e8b54d680609 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 21 May 2015 22:28:14 +0200
Subject: [PATCH 21/31] lib/async_req: s/result/req/ in read_packet_send()

BUG: https://bugzilla.samba.org/show_bug.cgi?id=11316

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 lib/async_req/async_sock.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/lib/async_req/async_sock.c b/lib/async_req/async_sock.c
index 8cccd15..ebcedb5 100644
--- a/lib/async_req/async_sock.c
+++ b/lib/async_req/async_sock.c
@@ -396,12 +396,12 @@ struct tevent_req *read_packet_send(TALLOC_CTX *mem_ctx,
 						    void *private_data),
 				    void *private_data)
 {
-	struct tevent_req *result;
+	struct tevent_req *req;
 	struct read_packet_state *state;
 	struct tevent_fd *fde;
 
-	result = tevent_req_create(mem_ctx, &state, struct read_packet_state);
-	if (result == NULL) {
+	req = tevent_req_create(mem_ctx, &state, struct read_packet_state);
+	if (req == NULL) {
 		return NULL;
 	}
 	state->fd = fd;
@@ -415,13 +415,13 @@ struct tevent_req *read_packet_send(TALLOC_CTX *mem_ctx,
 	}
 
 	fde = tevent_add_fd(ev, state, fd, TEVENT_FD_READ, read_packet_handler,
-			    result);
+			    req);
 	if (fde == NULL) {
 		goto fail;
 	}
-	return result;
+	return req;
  fail:
-	TALLOC_FREE(result);
+	TALLOC_FREE(req);
 	return NULL;
 }
 
-- 
1.9.1


From e9b5376a93ef455fc99c22f3618dfc2ccf20d041 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 21 May 2015 22:28:14 +0200
Subject: [PATCH 22/31] lib/async_req: use tevent_req_nomem/tevent_req_post in
 read_packet_send()

BUG: https://bugzilla.samba.org/show_bug.cgi?id=11316

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 lib/async_req/async_sock.c | 11 ++++-------
 1 file changed, 4 insertions(+), 7 deletions(-)

diff --git a/lib/async_req/async_sock.c b/lib/async_req/async_sock.c
index ebcedb5..19278f6 100644
--- a/lib/async_req/async_sock.c
+++ b/lib/async_req/async_sock.c
@@ -410,19 +410,16 @@ struct tevent_req *read_packet_send(TALLOC_CTX *mem_ctx,
 	state->private_data = private_data;
 
 	state->buf = talloc_array(state, uint8_t, initial);
-	if (state->buf == NULL) {
-		goto fail;
+	if (tevent_req_nomem(state->buf, req)) {
+		return tevent_req_post(req, ev);
 	}
 
 	fde = tevent_add_fd(ev, state, fd, TEVENT_FD_READ, read_packet_handler,
 			    req);
-	if (fde == NULL) {
-		goto fail;
+	if (tevent_req_nomem(fde, req)) {
+		return tevent_req_post(req, ev);
 	}
 	return req;
- fail:
-	TALLOC_FREE(req);
-	return NULL;
 }
 
 static void read_packet_handler(struct tevent_context *ev,
-- 
1.9.1


From 9d17c0f8d8f3a6719c2c42c720887133bf4323ab Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 21 May 2015 22:28:14 +0200
Subject: [PATCH 23/31] lib/async_req: remove the tevent_fd as early as
 possible via a read_packet_cleanup() hook

BUG: https://bugzilla.samba.org/show_bug.cgi?id=11316

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 lib/async_req/async_sock.c | 24 ++++++++++++++++++++----
 1 file changed, 20 insertions(+), 4 deletions(-)

diff --git a/lib/async_req/async_sock.c b/lib/async_req/async_sock.c
index 19278f6..adb8f87 100644
--- a/lib/async_req/async_sock.c
+++ b/lib/async_req/async_sock.c
@@ -378,12 +378,15 @@ ssize_t writev_recv(struct tevent_req *req, int *perrno)
 
 struct read_packet_state {
 	int fd;
+	struct tevent_fd *fde;
 	uint8_t *buf;
 	size_t nread;
 	ssize_t (*more)(uint8_t *buf, size_t buflen, void *private_data);
 	void *private_data;
 };
 
+static void read_packet_cleanup(struct tevent_req *req,
+				 enum tevent_req_state req_state);
 static void read_packet_handler(struct tevent_context *ev,
 				struct tevent_fd *fde,
 				uint16_t flags, void *private_data);
@@ -398,7 +401,6 @@ struct tevent_req *read_packet_send(TALLOC_CTX *mem_ctx,
 {
 	struct tevent_req *req;
 	struct read_packet_state *state;
-	struct tevent_fd *fde;
 
 	req = tevent_req_create(mem_ctx, &state, struct read_packet_state);
 	if (req == NULL) {
@@ -409,19 +411,31 @@ struct tevent_req *read_packet_send(TALLOC_CTX *mem_ctx,
 	state->more = more;
 	state->private_data = private_data;
 
+	tevent_req_set_cleanup_fn(req, read_packet_cleanup);
+
 	state->buf = talloc_array(state, uint8_t, initial);
 	if (tevent_req_nomem(state->buf, req)) {
 		return tevent_req_post(req, ev);
 	}
 
-	fde = tevent_add_fd(ev, state, fd, TEVENT_FD_READ, read_packet_handler,
-			    req);
-	if (tevent_req_nomem(fde, req)) {
+	state->fde = tevent_add_fd(ev, state, fd,
+				   TEVENT_FD_READ, read_packet_handler,
+				   req);
+	if (tevent_req_nomem(state->fde, req)) {
 		return tevent_req_post(req, ev);
 	}
 	return req;
 }
 
+static void read_packet_cleanup(struct tevent_req *req,
+			   enum tevent_req_state req_state)
+{
+	struct read_packet_state *state =
+		tevent_req_data(req, struct read_packet_state);
+
+	TALLOC_FREE(state->fde);
+}
+
 static void read_packet_handler(struct tevent_context *ev,
 				struct tevent_fd *fde,
 				uint16_t flags, void *private_data)
@@ -499,9 +513,11 @@ ssize_t read_packet_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
 		tevent_req_data(req, struct read_packet_state);
 
 	if (tevent_req_is_unix_error(req, perrno)) {
+		tevent_req_received(req);
 		return -1;
 	}
 	*pbuf = talloc_move(mem_ctx, &state->buf);
+	tevent_req_received(req);
 	return talloc_get_size(*pbuf);
 }
 
-- 
1.9.1


From 6dce891e888a2412aa9c95cfa1b8454b164ba54e Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 21 May 2015 22:28:14 +0200
Subject: [PATCH 24/31] lib/async_req: remove the tevent_fd as early as
 possible via a wait_for_read_cleanup() hook

BUG: https://bugzilla.samba.org/show_bug.cgi?id=11316

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 lib/async_req/async_sock.c | 30 +++++++++++++++++++++---------
 1 file changed, 21 insertions(+), 9 deletions(-)

diff --git a/lib/async_req/async_sock.c b/lib/async_req/async_sock.c
index adb8f87..03bda58 100644
--- a/lib/async_req/async_sock.c
+++ b/lib/async_req/async_sock.c
@@ -522,10 +522,11 @@ ssize_t read_packet_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
 }
 
 struct wait_for_read_state {
-	struct tevent_req *req;
 	struct tevent_fd *fde;
 };
 
+static void wait_for_read_cleanup(struct tevent_req *req,
+				  enum tevent_req_state req_state);
 static void wait_for_read_done(struct tevent_context *ev,
 			       struct tevent_fd *fde,
 			       uint16_t flags,
@@ -542,36 +543,47 @@ struct tevent_req *wait_for_read_send(TALLOC_CTX *mem_ctx,
 	if (req == NULL) {
 		return NULL;
 	}
-	state->req = req;
+
+	tevent_req_set_cleanup_fn(req, wait_for_read_cleanup);
+
 	state->fde = tevent_add_fd(ev, state, fd, TEVENT_FD_READ,
-				   wait_for_read_done, state);
+				   wait_for_read_done, req);
 	if (tevent_req_nomem(state->fde, req)) {
 		return tevent_req_post(req, ev);
 	}
 	return req;
 }
 
+static void wait_for_read_cleanup(struct tevent_req *req,
+				  enum tevent_req_state req_state)
+{
+	struct wait_for_read_state *state =
+		tevent_req_data(req, struct wait_for_read_state);
+
+	TALLOC_FREE(state->fde);
+}
+
 static void wait_for_read_done(struct tevent_context *ev,
 			       struct tevent_fd *fde,
 			       uint16_t flags,
 			       void *private_data)
 {
-	struct wait_for_read_state *state = talloc_get_type_abort(
-		private_data, struct wait_for_read_state);
+	struct tevent_req *req = talloc_get_type_abort(
+		private_data, struct tevent_req);
 
 	if (flags & TEVENT_FD_READ) {
-		TALLOC_FREE(state->fde);
-		tevent_req_done(state->req);
+		tevent_req_done(req);
 	}
 }
 
 bool wait_for_read_recv(struct tevent_req *req, int *perr)
 {
-	int err;
+	int err = tevent_req_simple_recv_unix(req);
 
-	if (tevent_req_is_unix_error(req, &err)) {
+	if (err != 0) {
 		*perr = err;
 		return false;
 	}
+
 	return true;
 }
-- 
1.9.1


From 865fb90d8b70f9d0abc12a29615d71e0f9c69741 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 21 May 2015 22:29:55 +0200
Subject: [PATCH 25/31] libcli/smb: use tevent_req_received(req) in
 read_smb_recv()

BUG: https://bugzilla.samba.org/show_bug.cgi?id=11316

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 libcli/smb/read_smb.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/libcli/smb/read_smb.c b/libcli/smb/read_smb.c
index 26816c3..a40f702 100644
--- a/libcli/smb/read_smb.c
+++ b/libcli/smb/read_smb.c
@@ -105,8 +105,10 @@ ssize_t read_smb_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
 		req, struct read_smb_state);
 
 	if (tevent_req_is_unix_error(req, perrno)) {
+		tevent_req_received(req);
 		return -1;
 	}
 	*pbuf = talloc_move(mem_ctx, &state->buf);
+	tevent_req_received(req);
 	return talloc_get_size(*pbuf);
 }
-- 
1.9.1


From 6e8e29722cae27f4710ebd42b84c38bf717ad5e9 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 28 May 2015 13:09:11 +0200
Subject: [PATCH 26/31] libcli/smb: close the socket fd at the end of
 smbXcli_conn_disconnect()

We need to cancel all pending requests before closing the socket fds,
otherwise we cause problem with the interaction with the epoll event backend.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=11316

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 libcli/smb/smbXcli_base.c | 15 +++++++++------
 1 file changed, 9 insertions(+), 6 deletions(-)

diff --git a/libcli/smb/smbXcli_base.c b/libcli/smb/smbXcli_base.c
index c2ba83a..b38792e 100644
--- a/libcli/smb/smbXcli_base.c
+++ b/libcli/smb/smbXcli_base.c
@@ -997,15 +997,11 @@ static bool smbXcli_conn_receive_next(struct smbXcli_conn *conn)
 void smbXcli_conn_disconnect(struct smbXcli_conn *conn, NTSTATUS status)
 {
 	struct smbXcli_session *session;
+	int read_fd = conn->read_fd;
+	int write_fd = conn->write_fd;
 
 	tevent_queue_stop(conn->outgoing);
 
-	if (conn->read_fd != -1) {
-		close(conn->read_fd);
-	}
-	if (conn->write_fd != -1) {
-		close(conn->write_fd);
-	}
 	conn->read_fd = -1;
 	conn->write_fd = -1;
 
@@ -1088,6 +1084,13 @@ void smbXcli_conn_disconnect(struct smbXcli_conn *conn, NTSTATUS status)
 		}
 		TALLOC_FREE(chain);
 	}
+
+	if (read_fd != -1) {
+		close(read_fd);
+	}
+	if (write_fd != -1) {
+		close(write_fd);
+	}
 }
 
 /*
-- 
1.9.1


From 8d61f1a9483e49de2cababdecdcf3b2e74fc1562 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 28 May 2015 13:22:19 +0200
Subject: [PATCH 27/31] libcli/smb: remove unused split of read_fd and write_fd

The tevent epoll backend supports separate read and write tevent_fd structure
on a single fd, so there's no need for a dup() anymore.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=11316

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 libcli/smb/smbXcli_base.c | 38 ++++++++++++--------------------------
 1 file changed, 12 insertions(+), 26 deletions(-)

diff --git a/libcli/smb/smbXcli_base.c b/libcli/smb/smbXcli_base.c
index b38792e..63bcee9 100644
--- a/libcli/smb/smbXcli_base.c
+++ b/libcli/smb/smbXcli_base.c
@@ -44,8 +44,7 @@ struct smbXcli_session;
 struct smbXcli_tcon;
 
 struct smbXcli_conn {
-	int read_fd;
-	int write_fd;
+	int sock_fd;
 	struct sockaddr_storage local_ss;
 	struct sockaddr_storage remote_ss;
 	const char *remote_name;
@@ -328,18 +327,13 @@ struct smbXcli_conn *smbXcli_conn_create(TALLOC_CTX *mem_ctx,
 		return NULL;
 	}
 
-	conn->read_fd = fd;
-	conn->write_fd = dup(fd);
-	if (conn->write_fd == -1) {
-		goto error;
-	}
+	conn->sock_fd = fd;
 
 	conn->remote_name = talloc_strdup(conn, remote_name);
 	if (conn->remote_name == NULL) {
 		goto error;
 	}
 
-
 	ss = (void *)&conn->local_ss;
 	sa = (struct sockaddr *)ss;
 	sa_length = sizeof(conn->local_ss);
@@ -428,9 +422,6 @@ struct smbXcli_conn *smbXcli_conn_create(TALLOC_CTX *mem_ctx,
 	return conn;
 
  error:
-	if (conn->write_fd != -1) {
-		close(conn->write_fd);
-	}
 	TALLOC_FREE(conn);
 	return NULL;
 }
@@ -441,7 +432,7 @@ bool smbXcli_conn_is_connected(struct smbXcli_conn *conn)
 		return false;
 	}
 
-	if (conn->read_fd == -1) {
+	if (conn->sock_fd == -1) {
 		return false;
 	}
 
@@ -468,7 +459,7 @@ bool smbXcli_conn_use_unicode(struct smbXcli_conn *conn)
 
 void smbXcli_conn_set_sockopt(struct smbXcli_conn *conn, const char *options)
 {
-	set_socket_options(conn->read_fd, options);
+	set_socket_options(conn->sock_fd, options);
 }
 
 const struct sockaddr_storage *smbXcli_conn_local_sockaddr(struct smbXcli_conn *conn)
@@ -554,7 +545,7 @@ struct tevent_req *smbXcli_conn_samba_suicide_send(TALLOC_CTX *mem_ctx,
 	state->iov.iov_base = state->buf;
 	state->iov.iov_len = sizeof(state->buf);
 
-	subreq = writev_send(state, ev, conn->outgoing, conn->write_fd,
+	subreq = writev_send(state, ev, conn->outgoing, conn->sock_fd,
 			     false, &state->iov, 1);
 	if (tevent_req_nomem(subreq, req)) {
 		return tevent_req_post(req, ev);
@@ -986,7 +977,7 @@ static bool smbXcli_conn_receive_next(struct smbXcli_conn *conn)
 	 */
 	conn->read_smb_req = read_smb_send(conn->pending,
 					   state->ev,
-					   conn->read_fd);
+					   conn->sock_fd);
 	if (conn->read_smb_req == NULL) {
 		return false;
 	}
@@ -997,13 +988,11 @@ static bool smbXcli_conn_receive_next(struct smbXcli_conn *conn)
 void smbXcli_conn_disconnect(struct smbXcli_conn *conn, NTSTATUS status)
 {
 	struct smbXcli_session *session;
-	int read_fd = conn->read_fd;
-	int write_fd = conn->write_fd;
+	int sock_fd = conn->sock_fd;
 
 	tevent_queue_stop(conn->outgoing);
 
-	conn->read_fd = -1;
-	conn->write_fd = -1;
+	conn->sock_fd = -1;
 
 	session = conn->sessions;
 	if (talloc_array_length(conn->pending) == 0) {
@@ -1085,11 +1074,8 @@ void smbXcli_conn_disconnect(struct smbXcli_conn *conn, NTSTATUS status)
 		TALLOC_FREE(chain);
 	}
 
-	if (read_fd != -1) {
-		close(read_fd);
-	}
-	if (write_fd != -1) {
-		close(write_fd);
+	if (sock_fd != -1) {
+		close(sock_fd);
 	}
 }
 
@@ -1571,7 +1557,7 @@ static NTSTATUS smb1cli_req_writev_submit(struct tevent_req *req,
 	tevent_req_set_cancel_fn(req, smbXcli_req_cancel);
 
 	subreq = writev_send(state, state->ev, state->conn->outgoing,
-			     state->conn->write_fd, false, iov, iov_count);
+			     state->conn->sock_fd, false, iov, iov_count);
 	if (subreq == NULL) {
 		return NT_STATUS_NO_MEMORY;
 	}
@@ -3166,7 +3152,7 @@ skip_credits:
 	}
 
 	subreq = writev_send(state, state->ev, state->conn->outgoing,
-			     state->conn->write_fd, false, iov, num_iov);
+			     state->conn->sock_fd, false, iov, num_iov);
 	if (subreq == NULL) {
 		return NT_STATUS_NO_MEMORY;
 	}
-- 
1.9.1


From 5e784cef1cfed960da770207ea24389be8fd3b4b Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Fri, 29 May 2015 15:29:31 +0200
Subject: [PATCH 28/31] libcli/smb: make sure the writev_send of
 smbXcli_conn_samba_suicide() is removed before closing the socket

BUG: https://bugzilla.samba.org/show_bug.cgi?id=11316

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 libcli/smb/smbXcli_base.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 53 insertions(+)

diff --git a/libcli/smb/smbXcli_base.c b/libcli/smb/smbXcli_base.c
index 63bcee9..43642e7 100644
--- a/libcli/smb/smbXcli_base.c
+++ b/libcli/smb/smbXcli_base.c
@@ -52,6 +52,7 @@ struct smbXcli_conn {
 	struct tevent_queue *outgoing;
 	struct tevent_req **pending;
 	struct tevent_req *read_smb_req;
+	struct tevent_req *suicide_req;
 
 	enum protocol_types min_protocol;
 	enum protocol_types max_protocol;
@@ -520,8 +521,11 @@ struct smbXcli_conn_samba_suicide_state {
 	struct smbXcli_conn *conn;
 	struct iovec iov;
 	uint8_t buf[9];
+	struct tevent_req *write_req;
 };
 
+static void smbXcli_conn_samba_suicide_cleanup(struct tevent_req *req,
+					       enum tevent_req_state req_state);
 static void smbXcli_conn_samba_suicide_done(struct tevent_req *subreq);
 
 struct tevent_req *smbXcli_conn_samba_suicide_send(TALLOC_CTX *mem_ctx,
@@ -542,6 +546,11 @@ struct tevent_req *smbXcli_conn_samba_suicide_send(TALLOC_CTX *mem_ctx,
 	SCVAL(state->buf, 8, exitcode);
 	_smb_setlen_nbt(state->buf, sizeof(state->buf)-4);
 
+	if (conn->suicide_req != NULL) {
+		tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+		return tevent_req_post(req, ev);
+	}
+
 	state->iov.iov_base = state->buf;
 	state->iov.iov_len = sizeof(state->buf);
 
@@ -551,9 +560,39 @@ struct tevent_req *smbXcli_conn_samba_suicide_send(TALLOC_CTX *mem_ctx,
 		return tevent_req_post(req, ev);
 	}
 	tevent_req_set_callback(subreq, smbXcli_conn_samba_suicide_done, req);
+	state->write_req = subreq;
+
+	tevent_req_set_cleanup_fn(req, smbXcli_conn_samba_suicide_cleanup);
+
+	/*
+	 * We need to use tevent_req_defer_callback()
+	 * in order to allow smbXcli_conn_disconnect()
+	 * to do a safe cleanup.
+	 */
+	tevent_req_defer_callback(req, ev);
+	conn->suicide_req = req;
+
 	return req;
 }
 
+static void smbXcli_conn_samba_suicide_cleanup(struct tevent_req *req,
+					       enum tevent_req_state req_state)
+{
+	struct smbXcli_conn_samba_suicide_state *state = tevent_req_data(
+		req, struct smbXcli_conn_samba_suicide_state);
+
+	TALLOC_FREE(state->write_req);
+
+	if (state->conn == NULL) {
+		return;
+	}
+
+	if (state->conn->suicide_req == req) {
+		state->conn->suicide_req = NULL;
+	}
+	state->conn = NULL;
+}
+
 static void smbXcli_conn_samba_suicide_done(struct tevent_req *subreq)
 {
 	struct tevent_req *req = tevent_req_callback_data(
@@ -563,9 +602,12 @@ static void smbXcli_conn_samba_suicide_done(struct tevent_req *subreq)
 	ssize_t nwritten;
 	int err;
 
+	state->write_req = NULL;
+
 	nwritten = writev_recv(subreq, &err);
 	TALLOC_FREE(subreq);
 	if (nwritten == -1) {
+		/* here, we need to notify all pending requests */
 		NTSTATUS status = map_nt_error_from_unix_common(err);
 		smbXcli_conn_disconnect(state->conn, status);
 		return;
@@ -1006,6 +1048,17 @@ void smbXcli_conn_disconnect(struct smbXcli_conn *conn, NTSTATUS status)
 		smb2cli_session_increment_channel_sequence(session);
 	}
 
+	if (conn->suicide_req != NULL) {
+		/*
+		 * smbXcli_conn_samba_suicide_send()
+		 * used tevent_req_defer_callback() already.
+		 */
+		if (!NT_STATUS_IS_OK(status)) {
+			tevent_req_nterror(conn->suicide_req, status);
+		}
+		conn->suicide_req = NULL;
+	}
+
 	/*
 	 * Cancel all pending requests. We do not do a for-loop walking
 	 * conn->pending because that array changes in
-- 
1.9.1


From d783801290fa732b1ff474981649a74251a6cb6b Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Fri, 29 May 2015 15:48:26 +0200
Subject: [PATCH 29/31] libcli/smb: add smb1 requests to the pending array
 before writev_send()

This way we have a change to destroy the pending writev_send request before
closing the socket in smbXcli_conn_disconnect().

BUG: https://bugzilla.samba.org/show_bug.cgi?id=11316

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 libcli/smb/smbXcli_base.c | 18 ++++++------------
 1 file changed, 6 insertions(+), 12 deletions(-)

diff --git a/libcli/smb/smbXcli_base.c b/libcli/smb/smbXcli_base.c
index 43642e7..04f8c96 100644
--- a/libcli/smb/smbXcli_base.c
+++ b/libcli/smb/smbXcli_base.c
@@ -666,14 +666,9 @@ uint32_t smb1cli_conn_max_xmit(struct smbXcli_conn *conn)
 
 bool smb1cli_conn_req_possible(struct smbXcli_conn *conn)
 {
-	size_t pending;
+	size_t pending = talloc_array_length(conn->pending);
 	uint16_t possible = conn->smb1.server.max_mux;
 
-	pending = tevent_queue_length(conn->outgoing);
-	if (pending >= possible) {
-		return false;
-	}
-	pending += talloc_array_length(conn->pending);
 	if (pending >= possible) {
 		return false;
 	}
@@ -1607,6 +1602,10 @@ static NTSTATUS smb1cli_req_writev_submit(struct tevent_req *req,
 		state->conn->dispatch_incoming = smb1cli_conn_dispatch_incoming;
 	}
 
+	if (!smbXcli_req_set_pending(req)) {
+		return NT_STATUS_NO_MEMORY;
+	}
+
 	tevent_req_set_cancel_fn(req, smbXcli_req_cancel);
 
 	subreq = writev_send(state, state->ev, state->conn->outgoing,
@@ -1674,9 +1673,9 @@ static void smb1cli_req_writev_done(struct tevent_req *subreq)
 	nwritten = writev_recv(subreq, &err);
 	TALLOC_FREE(subreq);
 	if (nwritten == -1) {
+		/* here, we need to notify all pending requests */
 		NTSTATUS status = map_nt_error_from_unix_common(err);
 		smbXcli_conn_disconnect(state->conn, status);
-		tevent_req_nterror(req, status);
 		return;
 	}
 
@@ -1685,11 +1684,6 @@ static void smb1cli_req_writev_done(struct tevent_req *subreq)
 		tevent_req_done(req);
 		return;
 	}
-
-	if (!smbXcli_req_set_pending(req)) {
-		tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
-		return;
-	}
 }
 
 static void smbXcli_conn_received(struct tevent_req *subreq)
-- 
1.9.1


From 097adaa9d920229949ec259d3009f3c878ea31b5 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Fri, 29 May 2015 16:14:40 +0200
Subject: [PATCH 30/31] libcli/smb: make sure we remove the writev_send()
 request when a request is destroyed

This way smbXcli_conn_disconnect() removes all tevent_fd structures attached to
the sock_fd before closing it.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=11316

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 libcli/smb/smbXcli_base.c | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/libcli/smb/smbXcli_base.c b/libcli/smb/smbXcli_base.c
index 04f8c96..c8ae5b0 100644
--- a/libcli/smb/smbXcli_base.c
+++ b/libcli/smb/smbXcli_base.c
@@ -222,6 +222,8 @@ struct smbXcli_req_state {
 
 	uint8_t *inbuf;
 
+	struct tevent_req *write_req;
+
 	struct {
 		/* Space for the header including the wct */
 		uint8_t hdr[HDR_VWV];
@@ -838,6 +840,8 @@ void smbXcli_req_unset_pending(struct tevent_req *req)
 	size_t num_pending = talloc_array_length(conn->pending);
 	size_t i;
 
+	TALLOC_FREE(state->write_req);
+
 	if (state->smb1.mid != 0) {
 		/*
 		 * This is a [nt]trans[2] request which waits
@@ -896,6 +900,8 @@ static void smbXcli_req_cleanup(struct tevent_req *req,
 		tevent_req_data(req,
 		struct smbXcli_req_state);
 
+	TALLOC_FREE(state->write_req);
+
 	switch (req_state) {
 	case TEVENT_REQ_RECEIVED:
 		/*
@@ -1614,6 +1620,8 @@ static NTSTATUS smb1cli_req_writev_submit(struct tevent_req *req,
 		return NT_STATUS_NO_MEMORY;
 	}
 	tevent_req_set_callback(subreq, smb1cli_req_writev_done, req);
+	state->write_req = subreq;
+
 	return NT_STATUS_OK;
 }
 
@@ -1670,6 +1678,8 @@ static void smb1cli_req_writev_done(struct tevent_req *subreq)
 	ssize_t nwritten;
 	int err;
 
+	state->write_req = NULL;
+
 	nwritten = writev_recv(subreq, &err);
 	TALLOC_FREE(subreq);
 	if (nwritten == -1) {
@@ -3204,6 +3214,8 @@ skip_credits:
 		return NT_STATUS_NO_MEMORY;
 	}
 	tevent_req_set_callback(subreq, smb2cli_req_writev_done, reqs[0]);
+	state->write_req = subreq;
+
 	return NT_STATUS_OK;
 }
 
@@ -3265,6 +3277,8 @@ static void smb2cli_req_writev_done(struct tevent_req *subreq)
 	ssize_t nwritten;
 	int err;
 
+	state->write_req = NULL;
+
 	nwritten = writev_recv(subreq, &err);
 	TALLOC_FREE(subreq);
 	if (nwritten == -1) {
-- 
1.9.1


From f1aeb436c57a90a21a8c4b6067a547d230f9c7fe Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Fri, 5 Jun 2015 10:30:39 +0200
Subject: [PATCH 31/31] ctdb-ib: make sure the tevent_fd is removed before the
 fd is closed

BUG: https://bugzilla.samba.org/show_bug.cgi?id=11316

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 ctdb/ib/ibwrapper.c | 21 ++++++++++-----------
 1 file changed, 10 insertions(+), 11 deletions(-)

diff --git a/ctdb/ib/ibwrapper.c b/ctdb/ib/ibwrapper.c
index 3daab3e..51d39da 100644
--- a/ctdb/ib/ibwrapper.c
+++ b/ctdb/ib/ibwrapper.c
@@ -134,16 +134,16 @@ static int ibw_ctx_priv_destruct(struct ibw_ctx_priv *pctx)
 {
 	DEBUG(DEBUG_DEBUG, ("ibw_ctx_priv_destruct(%p)\n", pctx));
 
+	/*
+	 * tevent_fd must be removed before the fd is closed
+	 */
+	TALLOC_FREE(pctx->cm_channel_event);
+
 	/* destroy cm */
 	if (pctx->cm_channel) {
 		rdma_destroy_event_channel(pctx->cm_channel);
 		pctx->cm_channel = NULL;
 	}
-	if (pctx->cm_channel_event) {
-		/* TODO: do we have to do this here? */
-		talloc_free(pctx->cm_channel_event);
-		pctx->cm_channel_event = NULL;
-	}
 	if (pctx->cm_id) {
 		rdma_destroy_id(pctx->cm_id);
 		pctx->cm_id = NULL;
@@ -166,6 +166,11 @@ static int ibw_conn_priv_destruct(struct ibw_conn_priv *pconn)
 	/* pconn->wr_index is freed by talloc */
 	/* pconn->wr_index[i] are freed by talloc */
 
+	/*
+	 * tevent_fd must be removed before the fd is closed
+	 */
+	TALLOC_FREE(pconn->verbs_channel_event);
+
 	/* destroy verbs */
 	if (pconn->cm_id!=NULL && pconn->cm_id->qp!=NULL) {
 		rdma_destroy_qp(pconn->cm_id);
@@ -182,12 +187,6 @@ static int ibw_conn_priv_destruct(struct ibw_conn_priv *pconn)
 		pconn->verbs_channel = NULL;
 	}
 
-	/* must be freed here because its order is important */
-	if (pconn->verbs_channel_event) {
-		talloc_free(pconn->verbs_channel_event);
-		pconn->verbs_channel_event = NULL;
-	}
-
 	/* free memory regions */
 	ibw_free_mr(&pconn->buf_send, &pconn->mr_send);
 	ibw_free_mr(&pconn->buf_recv, &pconn->mr_recv);
-- 
1.9.1
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 198 bytes
Desc: OpenPGP digital signature
URL: <http://lists.samba.org/pipermail/samba-technical/attachments/20150608/5ace9d05/attachment-0001.pgp>


More information about the samba-technical mailing list