Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 3 Apr 2024 18:46:38 +0100
From:      Sad Clouds <cryintothebluesky@gmail.com>
To:        Michael Tuexen <michael.tuexen@lurchi.franken.de>
Cc:        "freebsd-net@freebsd.org" <freebsd-net@FreeBSD.org>
Subject:   Re: TCP socket handling errors
Message-ID:  <20240403184638.aaf842926a7665d1f7fc8b14@gmail.com>
In-Reply-To: <0BA9AF99-A50F-472F-8139-1BA9EA067F91@lurchi.franken.de>
References:  <20240403131434.c3bfa64c726505d842408c80@gmail.com> <20240403144445.9a5662aa66975430c73f9e6d@gmail.com> <0BA9AF99-A50F-472F-8139-1BA9EA067F91@lurchi.franken.de>

next in thread | previous in thread | raw e-mail | index | archive | help
This is a multi-part message in MIME format.

--Multipart=_Wed__3_Apr_2024_18_46_38_+0100_SbkNPf9x/jE9zv/H
Content-Type: text/plain; charset=US-ASCII
Content-Transfer-Encoding: 7bit

On Wed, 3 Apr 2024 17:28:52 +0200
Michael Tuexen <michael.tuexen@lurchi.franken.de> wrote:

> > On 3. Apr 2024, at 15:44, Sad Clouds <cryintothebluesky@gmail.com> wrote:
> > 
> > I found a bug that is still open from May 2010 and describes the same
> > behaviour that I see with my application:
> > 
> > https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=146845
> > 
> > If this hasn't been fixed over the last 14 years, then I guess I will
> > add some code to simply ignore ECONNRESET on close(2) for FreeBSD and
> > MacOS. This seems the be the general advice from other people who hit
> > this issue.
> I'll bring this up on the bi-weekly FreeBSD transport call.
> 
> Best regards
> Michael
> > 
> 

Hello, I've attached a test program, this easily reproduces the issue
on Raspberry Pi 4 within a few seconds of running it.

Server output:
$ ./econnreset server
Server: accept()
Server: shutdown()
Server: close()
...
Server: accept()
Server: shutdown()
Server: close()
close() failed, error=Connection reset by peer


Client output (aborts when server exists due to close() failure):
$ while true; do ./econnreset client || break; done
Client: connect()
Client: shutdown()
Client: close()
...
Client: connect()
Assertion failed: (int_val == 0), function client, file econnreset.c,
line 156. Abort trap (core dumped)

--Multipart=_Wed__3_Apr_2024_18_46_38_+0100_SbkNPf9x/jE9zv/H
Content-Type: text/x-csrc;
 name="econnreset.c"
Content-Disposition: attachment;
 filename="econnreset.c"
Content-Transfer-Encoding: 7bit

/*
* cc -D_POSIX_C_SOURCE=200809L -D__BSD_VISIBLE -D__XSI_VISIBLE \
* -O2 -std=c11 -Wpedantic -Wall -o econnreset econnreset.c
*/

#include <arpa/inet.h>
#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <unistd.h>

#define ADDR "127.0.0.1"
#define PORT 9999
#define SIZE (10 * 1024U * 1024U)

#define CLI_ID    "client"
#define CLI_ID_LEN 6

#define SRV_ID     "server"
#define SRV_ID_LEN 6

static void server()
{
	int int_val, sockfd, connfd;
	struct sockaddr_storage socket_addr = {0};
	socklen_t               socket_addr_size;

	uint8_t snd_buf[1024], rcv_buf[1024];
	size_t  snd_size, rcv_size, io_size;
	ssize_t ssize_val;

	/* Socket family */
	((struct sockaddr_in *)&socket_addr)->sin_family = AF_INET;
	/* Socket address */
	int_val = inet_pton(AF_INET, ADDR, &(((struct sockaddr_in *)&socket_addr)->sin_addr));
	assert(int_val == 1);
	/* Socket port */
	((struct sockaddr_in *)&socket_addr)->sin_port = htons(PORT);
	/* Socket size */
	socket_addr_size = sizeof(struct sockaddr_in);

	sockfd = socket(socket_addr.ss_family, SOCK_STREAM, 0);
	assert(sockfd >= 0);

	int_val = bind(sockfd, (const struct sockaddr *)&socket_addr, socket_addr_size);
	assert(int_val == 0);

	int_val = listen(sockfd, 128);
	assert(int_val == 0);

	while (1)
	{
		printf("Server: accept()\n");
		connfd = accept(sockfd, NULL, NULL);
		assert(connfd >= 0);

		/* Size of data to send/receive */
		snd_size = rcv_size = SIZE;

		/* Data copy loop */
		while (snd_size != 0 && rcv_size != 0)
		{
			/* Send data */
			io_size = (sizeof(snd_buf) <= snd_size) ? sizeof(snd_buf) : snd_size;
			ssize_val = send(connfd, snd_buf, io_size, MSG_NOSIGNAL);
			if (ssize_val < 0)
			{
				fprintf(stderr, "send() failed, error=%s\n", strerror(errno));
				goto cleanup;
			}
			snd_size -= (size_t)ssize_val;

			/* Receive data */
			io_size = (sizeof(rcv_buf) <= rcv_size) ? sizeof(rcv_buf) : rcv_size;
			ssize_val = recv(connfd, rcv_buf, io_size, MSG_NOSIGNAL | MSG_WAITALL);
			if (ssize_val < 0)
			{
				fprintf(stderr, "recv() failed, error=%s\n", strerror(errno));
				goto cleanup;
			}
			rcv_size -= (size_t)ssize_val;
		}

		/* Send server ID string to client */
		ssize_val = send(connfd, SRV_ID, SRV_ID_LEN, MSG_NOSIGNAL);
		if (ssize_val <= 0)
		{
			fprintf(stderr, "send() failed, error=%s\n", strerror(errno));
			goto cleanup;
		}

		/* No more sending, do TCP half close */
		printf("Server: shutdown()\n");
		int_val = shutdown(connfd, SHUT_WR);
		if (int_val != 0)
		{
			fprintf(stderr, "shutdown() failed, error=%s\n", strerror(errno));
			goto cleanup;
		}

		/* Receive client ID string and verify it */
		ssize_val = recv(connfd, rcv_buf, CLI_ID_LEN, MSG_NOSIGNAL | MSG_WAITALL);
		if (ssize_val < 0)
		{
			fprintf(stderr, "recv() failed, error=%s\n", strerror(errno));
			goto cleanup;
		}
		assert(ssize_val == CLI_ID_LEN);
		assert(strncmp((char *)rcv_buf, CLI_ID, CLI_ID_LEN) == 0);

		cleanup:
		printf("Server: close()\n");
		int_val = close(connfd);
		if (int_val != 0)
		{
			/* We hit https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=146845 */
			fprintf(stderr, "close() failed, error=%s\n", strerror(errno));
			exit(EXIT_FAILURE);
		}
	}
}

static void client()
{
	int int_val, connfd;
	struct sockaddr_storage socket_addr = {0};
	socklen_t               socket_addr_size;

	uint8_t snd_buf[1024], rcv_buf[1024];
	size_t  snd_size, rcv_size, io_size;
	ssize_t ssize_val;

	/* Socket family */
	((struct sockaddr_in *)&socket_addr)->sin_family = AF_INET;
	/* Socket address */
	int_val = inet_pton(AF_INET, ADDR, &(((struct sockaddr_in *)&socket_addr)->sin_addr));
	assert(int_val == 1);
	/* Socket port */
	((struct sockaddr_in *)&socket_addr)->sin_port = htons(PORT);
	/* Socket size */
	socket_addr_size = sizeof(struct sockaddr_in);

	connfd = socket(socket_addr.ss_family, SOCK_STREAM, 0);
	assert(connfd >= 0);

	printf("Client: connect()\n");
	int_val = connect(connfd, (const struct sockaddr *)&socket_addr, socket_addr_size);
	assert(int_val == 0);

	/* Size of data to send/receive */
	snd_size = rcv_size = SIZE;

	/* Data copy loop */
	while (snd_size != 0 && rcv_size != 0)
	{
		/* Send data */
		io_size = (sizeof(snd_buf) <= snd_size) ? sizeof(snd_buf) : snd_size;
		ssize_val = send(connfd, snd_buf, io_size, MSG_NOSIGNAL);
		assert(ssize_val >= 0);
		snd_size -= (size_t)ssize_val;

		/* Receive data */
		io_size = (sizeof(rcv_buf) <= rcv_size) ? sizeof(rcv_buf) : rcv_size;
		ssize_val = recv(connfd, rcv_buf, io_size, MSG_NOSIGNAL | MSG_WAITALL);
		assert(ssize_val >= 0);
		rcv_size -= (size_t)ssize_val;
	}

	/* Send client ID string to server */
	ssize_val = send(connfd, CLI_ID, CLI_ID_LEN, MSG_NOSIGNAL);
	assert(ssize_val >= 0);

	/* No more sending, do TCP half close */
	printf("Client: shutdown()\n");
	int_val = shutdown(connfd, SHUT_WR);
	assert(int_val == 0);

	/* Receive server ID string and verify it */
	ssize_val = recv(connfd, rcv_buf, SRV_ID_LEN, MSG_NOSIGNAL | MSG_WAITALL);
	assert(ssize_val == SRV_ID_LEN);
	assert(strncmp((char *)rcv_buf, SRV_ID, SRV_ID_LEN) == 0);

	printf("Client: close()\n");
	int_val = close(connfd);
	if (int_val != 0)
	{
		/* We hit https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=146845 */
		fprintf(stderr, "close() failed, error=%s\n", strerror(errno));
		exit(EXIT_FAILURE);
	}
}

int main(int argc, char *argv[])
{
	if (argc != 2)
	{
		printf("Usage: econnreset client | server\n");
		exit(EXIT_FAILURE);
	}

	if (strcmp(argv[1], "client") == 0)
	{
		client();
	}
	else if (strcmp(argv[1], "server") == 0)
	{
		server();
	}
	else
	{
		printf("Usage: econnreset client | server\n");
		exit(EXIT_FAILURE);
	}

	exit(EXIT_SUCCESS);
}

--Multipart=_Wed__3_Apr_2024_18_46_38_+0100_SbkNPf9x/jE9zv/H--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20240403184638.aaf842926a7665d1f7fc8b14>