[SCM] Samba Shared Repository - branch v4-16-test updated

Jule Anger janger at samba.org
Mon Oct 31 15:32:01 UTC 2022


The branch, v4-16-test has been updated
       via  618395a7eaf s3: libsmbclient: Fix smbc_stat() to return ENOENT on a non-existent file.
       via  efa48817d3c s4: torture: libsmbclient: Add a torture test to ensure smbc_stat() returns ENOENT on a non-existent file.
       via  f7a84cffe9d s4:ldap_server: let ldapsrv_call_writev_start use conn_idle_time to limit the time
       via  bc16a8abe3f lib/tsocket: avoid endless cpu-spinning in tstream_bsd_fde_handler()
       via  aeb7dd2ca89 lib/tsocket: remember the first error as tstream_bsd->error
       via  d8d5146d167 lib/tsocket: check for errors indicated by poll() before getsockopt(fd, SOL_SOCKET, SO_ERROR)
       via  119bf609985 lib/tsocket: split out tsocket_bsd_error() from tsocket_bsd_pending()
       via  c805ccba339 lib/tsocket: Add tests for loop on EAGAIN
      from  c2095819c31 VERSION: Bump version up to Samba 4.16.7...

https://git.samba.org/?p=samba.git;a=shortlog;h=v4-16-test


- Log -----------------------------------------------------------------
commit 618395a7eafbb6224047610659c2d343318a1d33
Author: Jeremy Allison <jra at samba.org>
Date:   Mon Oct 17 13:24:27 2022 -0700

    s3: libsmbclient: Fix smbc_stat() to return ENOENT on a non-existent file.
    
    Remove knownfail.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15195
    
    Signed-off-by: Jeremy Allison <jra at samba.org>
    Reviewed-by: Pavel Filipenský <pfilipensky at samba.org>
    
    (backported from commit fd0c01da1c744ae6fd9d8675616d8b6d3531e469)
    
    jra at samba.org: Older SMBC_getatr returns bool not NTSTATUS.
    
    Autobuild-User(v4-16-test): Jule Anger <janger at samba.org>
    Autobuild-Date(v4-16-test): Mon Oct 31 15:31:53 UTC 2022 on sn-devel-184

commit efa48817d3c6fd3c64051bdf29648dff1702cf5d
Author: Jeremy Allison <jra at samba.org>
Date:   Mon Oct 17 13:14:41 2022 -0700

    s4: torture: libsmbclient: Add a torture test to ensure smbc_stat() returns ENOENT on a non-existent file.
    
    Add knownfail.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15195
    
    Signed-off-by: Jeremy Allison <jra at samba.org>
    Reviewed-by: Pavel Filipenský <pfilipensky at samba.org>
    (cherry picked from commit 9eda432836bfff3d3d4a365a08a5ecb54f0f2e34)

commit f7a84cffe9d9c61df7a7c5dd94e9caf3d18d9b3c
Author: Stefan Metzmacher <metze at samba.org>
Date:   Thu Oct 13 10:17:25 2022 +0200

    s4:ldap_server: let ldapsrv_call_writev_start use conn_idle_time to limit the time
    
    If the client is not able to receive the results within connections idle
    time, then we should treat it as dead. It's value is 15 minutes (900 s)
    by default.
    
    In order to limit that further an admin can use 'socket options'
    and set TCP_KEEPCNT, TCP_KEEPIDLE, TCP_KEEPINTVL and/or TCP_USER_TIMEOUT
    to useful values.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15202
    
    Signed-off-by: Stefan Metzmacher <metze at samba.org>
    Reviewed-by: Ralph Boehme <slow at samba.org>
    
    Autobuild-User(master): Stefan Metzmacher <metze at samba.org>
    Autobuild-Date(master): Wed Oct 19 17:13:39 UTC 2022 on sn-devel-184
    
    (cherry picked from commit eb2f3526032803f34c88ef1619a832a741f71910)

commit bc16a8abe3f1446a0da7e672cdba469fcc8ef96a
Author: Stefan Metzmacher <metze at samba.org>
Date:   Wed Oct 12 17:26:16 2022 +0200

    lib/tsocket: avoid endless cpu-spinning in tstream_bsd_fde_handler()
    
    There were some reports that strace output an LDAP server socket is in
    CLOSE_WAIT state, returning EAGAIN for writev over and over (after a call to
    epoll() each time).
    
    In the tstream_bsd code the problem happens when we have a pending
    writev_send, while there's no readv_send pending. In that case
    we still ask for TEVENT_FD_READ in order to notice connection errors
    early, so we try to call writev even if the socket doesn't report TEVENT_FD_WRITE.
    And there are situations where we do that over and over again.
    
    It happens like this with a Linux kernel:
    
        tcp_fin() has this:
            struct tcp_sock *tp = tcp_sk(sk);
    
            inet_csk_schedule_ack(sk);
    
            sk->sk_shutdown |= RCV_SHUTDOWN;
            sock_set_flag(sk, SOCK_DONE);
    
            switch (sk->sk_state) {
            case TCP_SYN_RECV:
            case TCP_ESTABLISHED:
                    /* Move to CLOSE_WAIT */
                    tcp_set_state(sk, TCP_CLOSE_WAIT);
                    inet_csk_enter_pingpong_mode(sk);
                    break;
    
    It means RCV_SHUTDOWN gets set as well as TCP_CLOSE_WAIT, but
    sk->sk_err is not changed to indicate an error.
    
        tcp_sendmsg_locked has this:
        ...
            err = -EPIPE;
            if (sk->sk_err || (sk->sk_shutdown & SEND_SHUTDOWN))
                    goto do_error;
    
            while (msg_data_left(msg)) {
                    int copy = 0;
    
                    skb = tcp_write_queue_tail(sk);
                    if (skb)
                            copy = size_goal - skb->len;
    
                    if (copy <= 0 || !tcp_skb_can_collapse_to(skb)) {
                            bool first_skb;
    
        new_segment:
                            if (!sk_stream_memory_free(sk))
                                    goto wait_for_space;
    
        ...
    
        wait_for_space:
                    set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
                    if (copied)
                            tcp_push(sk, flags & ~MSG_MORE, mss_now,
                                     TCP_NAGLE_PUSH, size_goal);
    
                    err = sk_stream_wait_memory(sk, &timeo);
                    if (err != 0)
                            goto do_error;
    
    It means if (sk->sk_err || (sk->sk_shutdown & SEND_SHUTDOWN)) doesn't
    hit as we only have RCV_SHUTDOWN and sk_stream_wait_memory returns
    -EAGAIN.
    
        tcp_poll has this:
    
            if (sk->sk_shutdown & RCV_SHUTDOWN)
                    mask |= EPOLLIN | EPOLLRDNORM | EPOLLRDHUP;
    
    So we'll get EPOLLIN | EPOLLRDNORM | EPOLLRDHUP triggering
    TEVENT_FD_READ and writev/sendmsg keeps getting EAGAIN.
    
    So we need to always clear TEVENT_FD_READ if we don't
    have readable handler in order to avoid burning cpu.
    But we turn it on again after a timeout of 1 second
    in order to monitor the error state of the connection.
    
    And now that our tsocket_bsd_error() helper checks for POLLRDHUP,
    we can check if the socket is in an error state before calling the
    writable handler when TEVENT_FD_READ was reported.
    Only on error we'll call the writable handler, which will pick
    the error without calling writev().
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15202
    
    Signed-off-by: Stefan Metzmacher <metze at samba.org>
    Reviewed-by: Ralph Boehme <slow at samba.org>
    (cherry picked from commit e232ba946f00aac39d67197d9939bc923814479c)

commit aeb7dd2ca89e7a010baaf3a5da17eaa466ace06e
Author: Stefan Metzmacher <metze at samba.org>
Date:   Thu Oct 13 16:23:03 2022 +0200

    lib/tsocket: remember the first error as tstream_bsd->error
    
    If we found that the connection is broken, there's no point
    in trying to use it anymore, so just return the first error we detected.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15202
    
    Signed-off-by: Stefan Metzmacher <metze at samba.org>
    Reviewed-by: Ralph Boehme <slow at samba.org>
    (cherry picked from commit 4c7e2b9b60de5d02bb3f69effe7eddbf466a6155)

commit d8d5146d1679383747ad0533759f97020b78221e
Author: Stefan Metzmacher <metze at samba.org>
Date:   Thu Oct 13 14:46:14 2022 +0200

    lib/tsocket: check for errors indicated by poll() before getsockopt(fd, SOL_SOCKET, SO_ERROR)
    
    This also returns an error if we got TCP_FIN from the peer,
    which is only reported by an explicit POLLRDHUP check.
    
    Also on FreeBSD getsockopt(fd, SOL_SOCKET, SO_ERROR) fetches
    and resets the error, so a 2nd call no longer returns an error.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15202
    
    Signed-off-by: Stefan Metzmacher <metze at samba.org>
    Reviewed-by: Ralph Boehme <slow at samba.org>
    (cherry picked from commit 29a65da63d730ecead1e7d4a81a76dd1c8c179ea)

commit 119bf609985a873346891c5ca55e69178d712eb0
Author: Stefan Metzmacher <metze at samba.org>
Date:   Thu Oct 13 10:39:59 2022 +0200

    lib/tsocket: split out tsocket_bsd_error() from tsocket_bsd_pending()
    
    This will be used on its own soon.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15202
    
    Signed-off-by: Stefan Metzmacher <metze at samba.org>
    Reviewed-by: Ralph Boehme <slow at samba.org>
    (cherry picked from commit 9950efd83e1a4b5e711f1d36fefa8a5d5e8b2410)

commit c805ccba33985ca07da63b4be3affafb495e13a1
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Mon Oct 17 16:08:42 2022 +1300

    lib/tsocket: Add tests for loop on EAGAIN
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15202
    
    Pair-Programmed-With: Stefan Metzmacher <metze at samba.org>
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Signed-off-by: Stefan Metzmacher <metze at samba.org>
    (cherry picked from commit f0fb8b9508346aed50528216fd959a9b1a941409)

-----------------------------------------------------------------------

Summary of changes:
 lib/tsocket/tests/socketpair_tcp.c                 |  89 ++++
 .../tsocket/tests/socketpair_tcp.h                 |  30 +-
 lib/tsocket/tests/test_tstream.c                   | 517 +++++++++++++++++++++
 lib/tsocket/tsocket_bsd.c                          | 274 ++++++++++-
 lib/tsocket/wscript_build                          |   6 +
 selftest/tests.py                                  |   3 +
 source3/libsmb/libsmb_file.c                       |  39 +-
 source4/ldap_server/ldap_server.c                  |   5 +
 source4/torture/libsmbclient/libsmbclient.c        |  63 +++
 9 files changed, 976 insertions(+), 50 deletions(-)
 create mode 100644 lib/tsocket/tests/socketpair_tcp.c
 copy source3/lib/namearray.c => lib/tsocket/tests/socketpair_tcp.h (61%)
 create mode 100644 lib/tsocket/tests/test_tstream.c


Changeset truncated at 500 lines:

diff --git a/lib/tsocket/tests/socketpair_tcp.c b/lib/tsocket/tests/socketpair_tcp.c
new file mode 100644
index 00000000000..251b8bc0212
--- /dev/null
+++ b/lib/tsocket/tests/socketpair_tcp.c
@@ -0,0 +1,89 @@
+/*
+   Unix SMB/CIFS implementation.
+   Samba utility functions
+   Copyright (C) Andrew Tridgell 1992-1998
+   Copyright (C) Tim Potter      2000-2001
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "system/network.h"
+#include "socketpair_tcp.h"
+
+/*******************************************************************
+this is like socketpair but uses tcp. It is used by the Samba
+regression test code
+The function guarantees that nobody else can attach to the socket,
+or if they do that this function fails and the socket gets closed
+returns 0 on success, -1 on failure
+the resulting file descriptors are symmetrical
+ ******************************************************************/
+int socketpair_tcp(int fd[2])
+{
+	int listener;
+	struct sockaddr_in sock;
+	struct sockaddr_in sock2;
+	socklen_t socklen = sizeof(sock);
+	int connect_done = 0;
+
+	fd[0] = fd[1] = listener = -1;
+
+	memset(&sock, 0, sizeof(sock));
+
+	if ((listener = socket(PF_INET, SOCK_STREAM, 0)) == -1) goto failed;
+
+	memset(&sock2, 0, sizeof(sock2));
+#ifdef HAVE_SOCK_SIN_LEN
+	sock2.sin_len = sizeof(sock2);
+#endif
+	sock2.sin_family = PF_INET;
+
+	if (bind(listener, (struct sockaddr *)&sock2, sizeof(sock2)) != 0) goto failed;
+
+	if (listen(listener, 1) != 0) goto failed;
+
+	if (getsockname(listener, (struct sockaddr *)&sock, &socklen) != 0) goto failed;
+
+	if ((fd[1] = socket(PF_INET, SOCK_STREAM, 0)) == -1) goto failed;
+
+	set_blocking(fd[1], 0);
+
+	sock.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+
+	if (connect(fd[1], (struct sockaddr *)&sock, socklen) == -1) {
+		if (errno != EINPROGRESS) goto failed;
+	} else {
+		connect_done = 1;
+	}
+
+	if ((fd[0] = accept(listener, (struct sockaddr *)&sock, &socklen)) == -1) goto failed;
+
+	if (connect_done == 0) {
+		if (connect(fd[1], (struct sockaddr *)&sock, socklen) != 0
+		    && errno != EISCONN) goto failed;
+	}
+	close(listener);
+
+	set_blocking(fd[1], 1);
+
+	/* all OK! */
+	return 0;
+
+ failed:
+	if (fd[0] != -1) close(fd[0]);
+	if (fd[1] != -1) close(fd[1]);
+	if (listener != -1) close(listener);
+	return -1;
+}
diff --git a/source3/lib/namearray.c b/lib/tsocket/tests/socketpair_tcp.h
similarity index 61%
copy from source3/lib/namearray.c
copy to lib/tsocket/tests/socketpair_tcp.h
index e5c3bd983b5..dbee4efec70 100644
--- a/source3/lib/namearray.c
+++ b/lib/tsocket/tests/socketpair_tcp.h
@@ -2,10 +2,7 @@
    Unix SMB/CIFS implementation.
    Samba utility functions
    Copyright (C) Andrew Tridgell 1992-1998
-   Copyright (C) Jeremy Allison 2001-2007
-   Copyright (C) Simo Sorce 2001
-   Copyright (C) Jim McDonough <jmcd at us.ibm.com> 2003
-   Copyright (C) James Peach 2006
+   Copyright (C) Tim Potter      2000-2001
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -21,19 +18,12 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
-#include "includes.h"
-/****************************************************************************
- Routine to free a namearray.
-****************************************************************************/
-
-void free_namearray(name_compare_entry *name_array)
-{
-	int i;
-
-	if(name_array == NULL)
-		return;
-
-	for(i=0; name_array[i].name!=NULL; i++)
-		SAFE_FREE(name_array[i].name);
-	SAFE_FREE(name_array);
-}
+/*******************************************************************
+this is like socketpair but uses tcp. It is used by the Samba
+regression test code
+The function guarantees that nobody else can attach to the socket,
+or if they do that this function fails and the socket gets closed
+returns 0 on success, -1 on failure
+the resulting file descriptors are symmetrical
+ ******************************************************************/
+int socketpair_tcp(int fd[2]);
diff --git a/lib/tsocket/tests/test_tstream.c b/lib/tsocket/tests/test_tstream.c
new file mode 100644
index 00000000000..a920e671cda
--- /dev/null
+++ b/lib/tsocket/tests/test_tstream.c
@@ -0,0 +1,517 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Copyright (C) 2022      Andrew Bartlett <abartlet at samba.org>
+ * Copyright (C) 2021      Andreas Schneider <asn at samba.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <setjmp.h>
+#include <cmocka.h>
+#include "includes.h"
+#include "system/network.h"
+#include "socketpair_tcp.h"
+#include "tsocket.h"
+
+enum socket_pair_selector {
+	SOCKET_SERVER = 0,
+	SOCKET_CLIENT = 1,
+};
+
+struct socket_pair {
+	struct tevent_context *ev;
+	int socket_server;
+	int socket_client;
+
+	/* for tstream tests */
+	int rc;
+	int sys_errno;
+	int expected_errno;
+	struct timeval endtime;
+	size_t max_loops;
+	size_t num_loops;
+};
+
+/* If this is too large, we get EPIPE rather than EAGAIN */
+static const uint8_t TEST_STRING[128] = { 0 };
+
+static int sigpipe_setup(void **state)
+{
+	BlockSignals(true, SIGPIPE);
+	return 0;
+}
+
+static int setup_socketpair_tcp_context(void **state)
+{
+	int fd[2];
+	struct socket_pair *sp = talloc_zero(NULL, struct socket_pair);
+	assert_non_null(sp);
+
+	/* Set up a socketpair over TCP to test with */
+	assert_return_code(socketpair_tcp(fd), errno);
+
+	sp->socket_server = fd[SOCKET_SERVER];
+	sp->socket_client = fd[SOCKET_CLIENT];
+
+	sp->ev = tevent_context_init(sp);
+	assert_non_null(sp->ev);
+
+	*state = sp;
+	return 0;
+}
+
+static int setup_socketpair_context(void **state)
+{
+	int fd[2];
+	struct socket_pair *sp = talloc_zero(NULL, struct socket_pair);
+	assert_non_null(sp);
+
+	/* Set up a socketpair over TCP to test with */
+	assert_return_code(socketpair(AF_UNIX, SOCK_STREAM, 0, fd), errno);
+
+	sp->socket_server = fd[SOCKET_SERVER];
+	sp->socket_client = fd[SOCKET_CLIENT];
+
+	sp->ev = tevent_context_init(sp);
+	assert_non_null(sp->ev);
+
+	*state = sp;
+	return 0;
+}
+
+static int teardown_socketpair_context(void **state)
+{
+	struct socket_pair *sp = *state;
+	struct socket_pair sp_save = *sp;
+
+	TALLOC_FREE(sp);
+
+	/*
+	 * Close these after the TALLOC_FREE() to allow clean shutdown
+	 * of epoll() in tstream
+	 */
+	if (sp_save.socket_client != -1) {
+		close(sp_save.socket_client);
+	}
+	if (sp_save.socket_server != -1) {
+		close(sp_save.socket_server);
+	}
+	return 0;
+}
+
+
+/* Test socket behaviour */
+static void test_simple_socketpair(void **state) {
+
+	struct socket_pair *sp = *state;
+
+	char buf[sizeof(TEST_STRING)];
+
+	assert_int_equal(write(sp->socket_server, TEST_STRING, sizeof(TEST_STRING)),
+			 sizeof(TEST_STRING));
+	assert_int_equal(read(sp->socket_client, buf, sizeof(buf)),
+			 sizeof(buf));
+
+
+}
+
+/* Test socket behaviour */
+static void test_read_client_after_close_server_socket(void **state) {
+
+	struct socket_pair *sp = *state;
+	int rc;
+	char buf[sizeof(TEST_STRING)];
+
+	rc = write(sp->socket_server, TEST_STRING, sizeof(TEST_STRING));
+	assert_return_code(rc, errno);
+	assert_int_equal(rc, sizeof(TEST_STRING));
+
+	assert_return_code(close(sp->socket_server), 0);
+
+	rc = read(sp->socket_client, buf, sizeof(buf));
+
+	assert_return_code(rc, errno);
+	assert_int_equal(rc, sizeof(buf));
+}
+
+static void test_write_server_after_close_client_socket(void **state) {
+
+	struct socket_pair *sp = *state;
+	int rc;
+
+	assert_return_code(close(sp->socket_client), 0);
+	sp->socket_client = -1;
+
+	rc = write(sp->socket_server, TEST_STRING, sizeof(TEST_STRING));
+	assert_return_code(rc, errno);
+	assert_int_equal(rc, sizeof(TEST_STRING));
+}
+
+static void test_fill_socket(int sock)
+{
+	size_t num_busy = 0;
+	int rc;
+
+	while (true) {
+		rc = write(sock, TEST_STRING, sizeof(TEST_STRING));
+		if (rc == -1 && errno == EAGAIN) {
+			/*
+			 * This makes sure we write until we get a whole second
+			 * only with EAGAIN every 50 ms (20 times)
+			 *
+			 * Otherwise the tests are not reliable...
+			 */
+			num_busy++;
+			if (num_busy > 20) {
+				break;
+			}
+			smb_msleep(50);
+			continue;
+		}
+		/* try again next time */
+		num_busy = 0;
+	}
+
+	assert_int_equal(rc, -1);
+	assert_int_equal(errno, EAGAIN);
+}
+
+static void test_big_write_server(void **state) {
+
+	struct socket_pair *sp = *state;
+	int rc;
+
+	rc = write(sp->socket_server, TEST_STRING, sizeof(TEST_STRING));
+	assert_return_code(rc, errno);
+	assert_int_equal(rc, sizeof(TEST_STRING));
+
+	rc = set_blocking(sp->socket_server, 0);
+	assert_return_code(rc, errno);
+
+	test_fill_socket(sp->socket_server);
+}
+
+static void test_big_write_server_close_write(void **state) {
+
+	struct socket_pair *sp = *state;
+	int rc;
+
+	rc = write(sp->socket_server, TEST_STRING, sizeof(TEST_STRING));
+	assert_return_code(rc, errno);
+	assert_int_equal(rc, sizeof(TEST_STRING));
+
+	rc = set_blocking(sp->socket_server, 0);
+	assert_return_code(rc, errno);
+
+	test_fill_socket(sp->socket_server);
+
+	assert_return_code(close(sp->socket_client), 0);
+	sp->socket_client = -1;
+
+	rc = write(sp->socket_server, TEST_STRING, sizeof(TEST_STRING));
+	assert_int_equal(errno, ECONNRESET);
+
+}
+
+static void test_big_write_server_shutdown_wr_write(void **state) {
+
+	struct socket_pair *sp = *state;
+	int rc;
+
+	rc = write(sp->socket_server, TEST_STRING, sizeof(TEST_STRING));
+	assert_return_code(rc, errno);
+	assert_int_equal(rc, sizeof(TEST_STRING));
+
+	rc = set_blocking(sp->socket_server, 0);
+	assert_return_code(rc, errno);
+
+	test_fill_socket(sp->socket_server);
+
+	assert_return_code(shutdown(sp->socket_client, SHUT_WR), 0);
+	sp->socket_client = -1;
+
+	rc = write(sp->socket_server, TEST_STRING, sizeof(TEST_STRING));
+	assert_int_equal(rc, -1);
+	assert_int_equal(errno, EAGAIN);
+}
+
+static void test_big_write_server_shutdown_rd_write(void **state) {
+
+	struct socket_pair *sp = *state;
+	int rc;
+
+	rc = write(sp->socket_server, TEST_STRING, sizeof(TEST_STRING));
+	assert_return_code(rc, errno);
+	assert_int_equal(rc, sizeof(TEST_STRING));
+
+	rc = set_blocking(sp->socket_server, 0);
+	assert_return_code(rc, errno);
+
+	test_fill_socket(sp->socket_server);
+
+	assert_return_code(shutdown(sp->socket_client, SHUT_RD), 0);
+	sp->socket_client = -1;
+
+	rc = write(sp->socket_server, TEST_STRING, sizeof(TEST_STRING));
+	assert_int_equal(rc, -1);
+	assert_int_equal(errno, EAGAIN);
+}
+
+static void test_call_writev_done(struct tevent_req *subreq)
+{
+	struct socket_pair *sp =
+		tevent_req_callback_data(subreq,
+		struct socket_pair);
+	int rc;
+
+	rc = tstream_writev_recv(subreq, &sp->sys_errno);
+	TALLOC_FREE(subreq);
+
+	sp->rc = rc;
+}
+
+static void test_tstream_server_spin_client_shutdown(struct socket_pair *sp)
+{
+	int rc;
+
+	rc = shutdown(sp->socket_client, SHUT_WR);
+	assert_return_code(rc, errno);
+	/*
+	 * It should only take a few additional loop to realise that this socket is
+	 * in CLOSE_WAIT
+	 */
+	sp->max_loops = sp->num_loops + 2;
+	sp->expected_errno = ECONNRESET;
+}
+
+static void test_tstream_server_spin_client_write(struct socket_pair *sp)
+{
+	int rc;
+	int timeout = 5000;
+
+	sp->endtime = timeval_current_ofs_msec(timeout);
+
+	rc = write(sp->socket_client, TEST_STRING, sizeof(TEST_STRING));
+	assert_return_code(rc, errno);
+	sp->expected_errno = ETIMEDOUT;
+}
+
+static void test_tstream_server_spin_client_tcp_user_timeout(struct socket_pair *sp)
+{
+	int rc;
+	int timeout = 5000;
+
+	rc = setsockopt(sp->socket_server, IPPROTO_TCP, TCP_USER_TIMEOUT, &timeout, sizeof(timeout));
+	assert_return_code(rc, errno);
+
+	rc = write(sp->socket_client, TEST_STRING, sizeof(TEST_STRING));
+	assert_return_code(rc, errno);
+	sp->expected_errno = ETIMEDOUT;
+	sp->max_loops = 15;
+}
+
+static void test_tstream_server_spin_client_both_timer(struct tevent_context *ev,
+						       struct tevent_timer *te,
+						       struct timeval current_time,
+						       void *private_data)
+{
+	struct socket_pair *sp =
+		talloc_get_type_abort(private_data,
+		struct socket_pair);
+
+	test_tstream_server_spin_client_shutdown(sp);
+}
+
+static void test_tstream_server_spin_client_both(struct socket_pair *sp)
+{
+	struct tevent_timer *te = NULL;
+	struct timeval endtime;
+
+	test_tstream_server_spin_client_write(sp);
+
+	endtime = timeval_current_ofs_msec(2500);
+
+	te = tevent_add_timer(sp->ev,
+			      sp,
+			      endtime,


-- 
Samba Shared Repository



More information about the samba-cvs mailing list