Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wait for all buffered data to be sent before closing TCP Streams #994

Open
davidBar-On opened this issue May 11, 2020 · 0 comments
Open
Labels
bug:test-data Bugs related to the amount of data sent during a test

Comments

@davidBar-On
Copy link
Contributor

davidBar-On commented May 11, 2020

Context

  • Version of iperf3:
    iperf 3.7+ (cJSON 1.5.2)

  • Hardware:
    Dell PC DESKTOP-L81E90U

  • Operating system (and distribution, if any):
    Ubunto Linux 18.04 LTS VM under Windows 10

  • Other relevant information (for example, non-default compilers,
    libraries, cross-compiling, etc.):

Enhancement Request

The suggested code changes are below. Unfortunately, I don't have the infrastructure that can allow to test the effectiveness of these changes. I did check with basic scenarios that the changes do not cause problems (at least in Ubunto VM under Windows 10). This is also why I am not sending a pull request.

The approach is to set SO_LINGER timeout for each stream (I set 10 seconds) and to call shotdown() for each stream before closing it. This should be enough to make sure that the sender sent all the data. However, it may not be enough to ensure that the receiver received all the data. That may also depend on the shutdown() implementation in each operating system.

Following are the enhancements I did. The code I added is marked between the /* DBO >>> …*/ and the /* <<< DBO */ comments.

iperf_client_api.c


iperf_create_streams(…) {
    ….
   for (i = 0; i < test->num_streams; ++i) {

        test->bind_port = orig_bind_port;
	if (orig_bind_port)
	    test->bind_port += i;
        if ((s = test->protocol->connect(test)) < 0)
            return -1;

    /* DBO >>> Set socket Linger value */
        int saved_errno;
        struct linger ling;
	ling.l_onoff = 1; 
        ling.l_linger = 10;
	if (setsockopt(s, SOL_SOCKET, SO_LINGER, &ling, sizeof(ling))) {
	    saved_errno = errno;
	    close(s);
	    errno = saved_errno;
            i_errno = IESETLINGER;
            return -1;
	}
    /* <<< DBO */
    ….
}

……..

iperf_run_client(…) {
    ……

		/* Yes, done!  Send TEST_END. */
		test->done = 1;
		cpu_util(test->cpu_util);
		test->stats_callback(test);
		if (iperf_set_send_state(test, TEST_END) != 0)
		    return -1;

		/* >>> DBO - When Sender - Make sure all sockets are flushed and received by other end (that sends FIN) */
		SLIST_FOREACH(sp, &test->streams, streams) {
			if (sp->sender) {
				printf("*** CLNT BEFORE SHUTDOWN\n");
				shutdown(sp->socket, SHUT_WR);
				printf("*** CNLT AFTER SHUTDOWN\n");
			}
		}

		/* When Receiver - Make sure all sockets are received */
		int all_blocks_received = 0;
		int r;
		while (all_blocks_received == 0) {
			all_blocks_received = 1;
			SLIST_FOREACH(sp, &test->streams, streams) {
				if (!sp->sender) {
					r = sp->rcv(sp);
					printf("*** RECEIVED LAST BLOCK SIZE %i\n", r);
					if (r > 0)
					all_blocks_received = 0;
				}
			}
		}
		/* <<<< DBO */
    ……..

}

iperf_server_api.c


iperf_handle_message_server(struct iperf_test *test)
{
    ….
  switch(test->state) {
        case TEST_START:
            break;
        case TEST_END:
	    /* >>> DBO - When Sender - Make sure all sockets are flushed and received by other end (that sends FIN) */
		SLIST_FOREACH(sp, &test->streams, streams) {
		    if (sp->sender) {
			printf("*** SRV BEFORE SHUTDOWN\n");
			setnonblocking(sp->socket, 0);
			shutdown(sp->socket, SHUT_WR);
			setnonblocking(sp->socket, 1);
			printf("*** SRV AFTER SHUTDOWN\n");
		    }
		}

		/* When Receiver - Make sure all sockets are received */
		int all_blocks_received = 0;
		int r;
		while (all_blocks_received == 0) {
		    all_blocks_received = 1;
		    SLIST_FOREACH(sp, &test->streams, streams) {
			if (!sp->sender) {
			    r = sp->rcv(sp);
			    printf("*** RECEIVED LAST BLOCK SIZE %i\n", r);
			    if (r > 0)
				all_blocks_received = 0;
			}
		    }
		}
	    /* <<< DBO */

            test->done = 1;
            ………..

……..

iperf_run_server(struct iperf_test *test)
{
      …….
            if (test->state == CREATE_STREAMS) {
                if (FD_ISSET(test->prot_listener, &read_set)) {
    
                    if ((s = test->protocol->accept(test)) < 0) {
			cleanup_server(test);
                        return -1;
		    }

		    /* DBO >>> Set socket Linger value */
		    int saved_errno;
		    struct linger ling;
		    ling.l_onoff = 1; 
		    ling.l_linger = 10;
		    if (setsockopt(s, SOL_SOCKET, SO_LINGER, &ling, sizeof(ling))) {
			saved_errno = errno;
			close(s);
			errno = saved_errno;
			i_errno = IESETLINGER;
			return -1;
		    }
		    /* <<< DBO */
    …….

iperf_ api.c


iperf_send(struct iperf_test *test, fd_set *write_setP)
{
    register int multisend, r, streams_active;
    register struct iperf_stream *sp;
    struct iperf_time now;

    /* >>> DBO - Don't send if test ended */
    if (test->state == TEST_END)
        return 0;
    /* >>> DBO */

    ……….
@bmah888 bmah888 added the bug:test-data Bugs related to the amount of data sent during a test label Jul 13, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug:test-data Bugs related to the amount of data sent during a test
Projects
None yet
Development

No branches or pull requests

2 participants