From 3ad85270ffa4c4b0eff1a0655e0a838f7173a7ac Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 21 May 2015 11:37:06 +0200 Subject: [PATCH 01/29] 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 Reviewed-by: Volker Lendecke Reviewed-by: Jeremy Allison (cherry picked from commit 3a8b7b0518b33b016d2dbb8dd23d35ef1c6aaa5c) --- 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 fe39dfd..39f5a03 100644 --- a/lib/tsocket/tsocket_bsd.c +++ b/lib/tsocket/tsocket_bsd.c @@ -1409,6 +1409,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 caeb9f9d7ad1d6dd349397dc35f11f351c9e4569 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 21 May 2015 11:39:38 +0200 Subject: [PATCH 02/29] 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 Reviewed-by: Volker Lendecke Reviewed-by: Jeremy Allison (cherry picked from commit 36b97d0bb9fe004f3d8a500f3af83dff34f86d7b) --- 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 39f5a03..067d658 100644 --- a/lib/tsocket/tsocket_bsd.c +++ b/lib/tsocket/tsocket_bsd.c @@ -1462,6 +1462,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 dd2fb426e81c428095a4d6bb7ca762d186c252ab Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 28 May 2015 14:25:27 +0200 Subject: [PATCH 03/29] 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 Reviewed-by: Volker Lendecke Reviewed-by: Jeremy Allison (cherry picked from commit dd037b0be4ed2df7239cb61bd3d4bb868bb09126) --- 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 bc8fa23dda57dd7b6256d0f20299023c6c58aa73 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 21 May 2015 03:45:36 +0200 Subject: [PATCH 04/29] 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 Reviewed-by: Volker Lendecke Reviewed-by: Jeremy Allison (similar to commit 0c108f55d9c3cca0bde1c15c66dccabbc40e6133) --- source3/wscript_build | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/source3/wscript_build b/source3/wscript_build index 8c09dd0..2e6aab8 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. @@ -259,9 +259,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 ccan-hash') + deps='ndr LIBTSOCKET samba-security NDR_SECURITY samba-util util_tdb ccan-hash') if bld.CONFIG_GET("CTDB_CFLAGS") and bld.CONFIG_GET("CTDB_INCLUDE"): SAMBA_CLUSTER_SUPPORT_SOURCES=''' -- 1.9.1 From 79406d114009dcc735b71f5205167ff31b4f26aa Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 28 May 2015 13:31:17 +0200 Subject: [PATCH 05/29] 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 Reviewed-by: Volker Lendecke (cherry picked from commit 9d3444ad887bb3a118eaecd141c79dfd6de53f41) --- 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; inum_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 e46a0b7e9d36f7bd621cd028db59f4ef8cb9a1e6 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 5 Jun 2015 14:19:00 +0200 Subject: [PATCH 06/29] 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 Reviewed-by: Volker Lendecke (cherry picked from commit 257bc586c22f9a7f34b913823d5c89592d433454) --- 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 914d9a20b844e0c99b450c9d74e10328eae129c0 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 21 May 2015 12:17:24 +0200 Subject: [PATCH 07/29] 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 Reviewed-by: Volker Lendecke (cherry picked from commit 0d161e42d9aeb155eae2b04eccec497b21de8029) --- 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 7beffb6be91a6691edc54f7e3fb790ce1cad8559 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 21 May 2015 03:00:17 +0200 Subject: [PATCH 08/29] 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 Reviewed-by: Volker Lendecke (cherry picked from commit 992be06f165c3d05e85d16baf514dba49f55d1ec) --- 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 403750d..054b8af 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 c7752801f7a8d3068307d735375e395ab4ae8bb7 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 21 May 2015 03:01:05 +0200 Subject: [PATCH 09/29] 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 Reviewed-by: Volker Lendecke (cherry picked from commit 04f89d4255ed95631aa8f0ada4bcf5f888e126d4) --- 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 054b8af..1256e5f 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 9da2e0fd74d7aed4a2b5a1c565d82fafbb000b76 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 21 May 2015 03:01:30 +0200 Subject: [PATCH 10/29] 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 Reviewed-by: Volker Lendecke (cherry picked from commit 058d84747e75a5f97a02e31bac9c8d0d147174bc) --- 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 1256e5f..dc04b6a 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 d65b2608c7da4c39f51ab6a596aa0fb6f69c3dc4 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 21 May 2015 02:20:00 +0200 Subject: [PATCH 11/29] 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 Reviewed-by: Volker Lendecke (cherry picked from commit 9ccf8e6d36618498c4952bb1d4b74152f75ab793) --- 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 2c01bb7..41dcd7f 100644 --- a/source3/libsmb/unexpected.c +++ b/source3/libsmb/unexpected.c @@ -40,6 +40,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; @@ -70,7 +71,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; @@ -95,9 +95,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; } @@ -111,6 +114,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 3752a46f6eb79e48f792b1aeca28b630b7af312d Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 21 May 2015 01:53:44 +0200 Subject: [PATCH 12/29] 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 Reviewed-by: Volker Lendecke (cherry picked from commit 3ecf4ec6574de9bdd5a2d55529ed81b17c74d452) --- 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 41dcd7f..4a05ee2 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" @@ -54,8 +55,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; }; @@ -127,6 +132,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, @@ -141,6 +147,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); @@ -157,7 +164,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); @@ -169,11 +182,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; } @@ -211,10 +224,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; @@ -226,11 +238,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", @@ -261,32 +272,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( @@ -295,7 +325,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 " @@ -408,12 +438,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); @@ -427,29 +457,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 2e6aab8..27f3783 100755 --- a/source3/wscript_build +++ b/source3/wscript_build @@ -719,7 +719,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 2e5130d4426246a11e3de248a6ad43d334704253 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 21 May 2015 02:18:26 +0200 Subject: [PATCH 13/29] 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 Reviewed-by: Volker Lendecke (cherry picked from commit ecb4d041de89441941a112ab3a724887e568117e) --- 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 4a05ee2..79df11a 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" static const char *nmbd_socket_dir(void) @@ -470,12 +469,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]; @@ -483,7 +481,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); @@ -496,7 +493,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); @@ -517,25 +517,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); } @@ -543,15 +541,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( @@ -561,10 +550,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; } @@ -579,8 +569,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; } @@ -596,7 +586,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)); @@ -606,8 +596,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; } @@ -624,7 +615,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", @@ -649,9 +640,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; } @@ -675,9 +668,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); } @@ -709,7 +702,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; @@ -728,6 +721,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; } @@ -738,8 +732,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 b5663f6517937a4c75fbea2fc311e8345708ec20 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 21 May 2015 04:43:27 +0200 Subject: [PATCH 14/29] 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 Reviewed-by: Volker Lendecke (cherry picked from commit a3282911f6ceb76b2ada567e569a55af8c7ef160) --- 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 654ca1d..6f056be 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 e98054dc1b9d079274888fa7d402a72f289d6b21 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 21 May 2015 12:25:38 +0200 Subject: [PATCH 15/29] 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 Reviewed-by: Volker Lendecke (cherry picked from commit ccd038e1523a69197a9aaeca00305b0958f09ff0) --- 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 74b2cb7..531d779 100644 --- a/lib/async_req/async_sock.c +++ b/lib/async_req/async_sock.c @@ -32,184 +32,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 #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 edc6a5f7f4919f827a1abd80838520fe634b7485 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 5 Jun 2015 13:58:19 +0200 Subject: [PATCH 16/29] 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 Reviewed-by: Volker Lendecke (cherry picked from commit be8c2ff10353df00f05cd378c251a33a9e08563a) --- 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 531d779..13c58ff 100644 --- a/lib/async_req/async_sock.c +++ b/lib/async_req/async_sock.c @@ -69,13 +69,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; } @@ -115,7 +114,7 @@ struct tevent_req *async_connect_send( } if (state->result == 0) { - tevent_req_done(result); + tevent_req_done(req); goto done; } @@ -136,18 +135,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 202a9706c217b1f7156cbb1d719f8b062c3f405b Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 21 May 2015 22:28:14 +0200 Subject: [PATCH 17/29] 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 Reviewed-by: Volker Lendecke (cherry picked from commit d5a4b30f894f0d4d4fa728ebd2c435254bf3b142) --- 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 13c58ff..2080ac9 100644 --- a/lib/async_req/async_sock.c +++ b/lib/async_req/async_sock.c @@ -34,8 +34,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; @@ -45,6 +45,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); @@ -71,7 +73,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) { @@ -84,20 +85,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); @@ -115,7 +118,7 @@ struct tevent_req *async_connect_send( if (state->result == 0) { tevent_req_done(req); - goto done; + return tevent_req_post(req, ev); } /** @@ -130,23 +133,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; + } } /** @@ -179,8 +190,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; } @@ -188,31 +197,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 78177f7ffad6e69bd28a88f19951d22764d4a976 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 21 May 2015 22:28:14 +0200 Subject: [PATCH 18/29] 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 Reviewed-by: Volker Lendecke (cherry picked from commit 0c1109695639a177d3d739b343e7588a6ecf0949) --- 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 2080ac9..3f659ae 100644 --- a/lib/async_req/async_sock.c +++ b/lib/async_req/async_sock.c @@ -216,6 +216,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; @@ -223,6 +224,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); @@ -245,40 +248,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; } } @@ -372,11 +381,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 82a05237e239b04199fed861904726627655ad27 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 21 May 2015 22:28:14 +0200 Subject: [PATCH 19/29] 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 Reviewed-by: Volker Lendecke (cherry picked from commit 4f05f68abc1d756bb114260e80d3532f3f959fec) --- 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 3f659ae..cf21246 100644 --- a/lib/async_req/async_sock.c +++ b/lib/async_req/async_sock.c @@ -412,12 +412,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; @@ -431,13 +431,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 2127939f1ad86ca2c2ff0cf6eee748b1889f93f4 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 21 May 2015 22:28:14 +0200 Subject: [PATCH 20/29] 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 Reviewed-by: Volker Lendecke (cherry picked from commit 9a116b28bab20507760f50f25214635a60ea6c43) --- 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 cf21246..372aaa0 100644 --- a/lib/async_req/async_sock.c +++ b/lib/async_req/async_sock.c @@ -426,19 +426,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 dd4822e47a6348198382f2f804170056e336e304 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 21 May 2015 22:28:14 +0200 Subject: [PATCH 21/29] 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 Reviewed-by: Volker Lendecke (cherry picked from commit a2a7cbc66c4713493e6ade45d0cdde25f64c9007) --- 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 372aaa0..8e04a08 100644 --- a/lib/async_req/async_sock.c +++ b/lib/async_req/async_sock.c @@ -394,12 +394,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); @@ -414,7 +417,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) { @@ -425,19 +427,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) @@ -515,9 +529,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 62d79c1004ece38b529edd26c535f7382869a0b9 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 21 May 2015 22:28:14 +0200 Subject: [PATCH 22/29] 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 Reviewed-by: Volker Lendecke (cherry picked from commit 64640cc99c7b8543ee8d35ca243c57c048cdb490) --- 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 8e04a08..2f3225d 100644 --- a/lib/async_req/async_sock.c +++ b/lib/async_req/async_sock.c @@ -538,10 +538,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, @@ -558,36 +559,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 1bd4c0275a22725c09ed2754683919fe57d4329a Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 21 May 2015 22:29:55 +0200 Subject: [PATCH 23/29] 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 Reviewed-by: Volker Lendecke (cherry picked from commit 26c4b3fc9db507557b2539dd7d1f9e593c3fa35a) --- 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 7579281f8fd26d446ab32835eed0920f489ebc5c Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 28 May 2015 13:09:11 +0200 Subject: [PATCH 24/29] 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 Reviewed-by: Volker Lendecke (cherry picked from commit 46e1aa22b12eacc3567f7897716ae07837545c23) --- 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 742caf1..3e4491d 100644 --- a/libcli/smb/smbXcli_base.c +++ b/libcli/smb/smbXcli_base.c @@ -971,15 +971,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; @@ -1062,6 +1058,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 f35ead72ec52059e6c7acc2f21c817c81b284fc1 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 28 May 2015 13:22:19 +0200 Subject: [PATCH 25/29] 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 Reviewed-by: Volker Lendecke (cherry picked from commit 8f42df235dc825a103631fdf0e37e1c1d03cf420) --- 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 3e4491d..29bec3a 100644 --- a/libcli/smb/smbXcli_base.c +++ b/libcli/smb/smbXcli_base.c @@ -39,8 +39,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; @@ -309,18 +308,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); @@ -401,9 +395,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; } @@ -414,7 +405,7 @@ bool smbXcli_conn_is_connected(struct smbXcli_conn *conn) return false; } - if (conn->read_fd == -1) { + if (conn->sock_fd == -1) { return false; } @@ -441,7 +432,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) @@ -527,7 +518,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); @@ -960,7 +951,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; } @@ -971,13 +962,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) { @@ -1059,11 +1048,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); } } @@ -1529,7 +1515,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; } @@ -3071,7 +3057,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 f7ede3ed153d0367205181024d14f03105cf904e Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 29 May 2015 15:29:31 +0200 Subject: [PATCH 26/29] 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 Reviewed-by: Volker Lendecke (cherry picked from commit 59338434274799db1ac60b082a6453bd924c5f4c) --- 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 29bec3a..9765dac 100644 --- a/libcli/smb/smbXcli_base.c +++ b/libcli/smb/smbXcli_base.c @@ -47,6 +47,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; @@ -493,8 +494,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, @@ -515,6 +519,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); @@ -524,9 +533,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( @@ -536,9 +575,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; @@ -980,6 +1022,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 b943b82a3034db00b8e41907d67b0099720fceb4 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 29 May 2015 15:48:26 +0200 Subject: [PATCH 27/29] 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 Reviewed-by: Volker Lendecke (cherry picked from commit f3982eb2c7f1d17a013dacfd430a3752e6ef4ae4) --- 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 9765dac..61edd28 100644 --- a/libcli/smb/smbXcli_base.c +++ b/libcli/smb/smbXcli_base.c @@ -640,14 +640,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; } @@ -1565,6 +1560,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, @@ -1632,9 +1631,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; } @@ -1643,11 +1642,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 f02751f9f82ecc57edd4669252d5f2042564ae7d Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 29 May 2015 16:14:40 +0200 Subject: [PATCH 28/29] 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 Reviewed-by: Volker Lendecke (cherry picked from commit 006042ac126261e87089fb9835c28789e8aeae1b) --- 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 61edd28..c27b317 100644 --- a/libcli/smb/smbXcli_base.c +++ b/libcli/smb/smbXcli_base.c @@ -206,6 +206,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]; @@ -812,6 +814,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 @@ -870,6 +874,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: /* @@ -1572,6 +1578,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; } @@ -1628,6 +1636,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) { @@ -3109,6 +3119,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; } @@ -3170,6 +3182,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 df4f2d06bba5b2636db2cdab6a39c98caf891265 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 5 Jun 2015 10:30:39 +0200 Subject: [PATCH 29/29] 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 Reviewed-by: Volker Lendecke (cherry picked from commit 53ff3e4f31f3debd98f9293171c023a0a406858d) --- 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