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