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>