Path: blob/main/tools/regression/netinet/tcpsockclosebeforeaccept/tcpsockclosebeforeaccept.c
39534 views
/*-1* Copyright (c) 2006 Robert N. M. Watson2* All rights reserved.3*4* Redistribution and use in source and binary forms, with or without5* modification, are permitted provided that the following conditions6* are met:7* 1. Redistributions of source code must retain the above copyright8* notice, this list of conditions and the following disclaimer.9* 2. Redistributions in binary form must reproduce the above copyright10* notice, this list of conditions and the following disclaimer in the11* documentation and/or other materials provided with the distribution.12*13* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND14* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE15* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE16* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE17* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL18* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS19* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)20* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT21* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY22* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF23* SUCH DAMAGE.24*/2526/*27* TCP regression test which opens a loopback TCP session, and closes it28* before the remote endpoint (server) can accept it. Run the test twice,29* once using an explicit close() from the client, a second using a tcp drop.30*/3132#include <sys/types.h>33#include <sys/socket.h>34#include <sys/sysctl.h>3536#include <netinet/in.h>3738#include <err.h>39#include <errno.h>40#include <signal.h>41#include <stdio.h>42#include <stdlib.h>43#include <string.h>44#include <unistd.h>4546#define TCP_PORT 90054748static int49tcp_drop(struct sockaddr_in *sin_local, struct sockaddr_in *sin_remote)50{51struct sockaddr_storage addrs[2];5253/*54* Sysctl accepts an array of two sockaddr's, the first being the55* 'foreign' sockaddr, the second being the 'local' sockaddr.56*/5758bcopy(sin_remote, &addrs[0], sizeof(*sin_remote));59bcopy(sin_local, &addrs[1], sizeof(*sin_local));6061return (sysctlbyname("net.inet.tcp.drop", NULL, 0, addrs,62sizeof(addrs)));63}646566static void67tcp_server(pid_t partner)68{69int error, listen_fd, accept_fd;70struct sockaddr_in sin;7172listen_fd = socket(PF_INET, SOCK_STREAM, 0);73if (listen_fd < 0) {74error = errno;75(void)kill(partner, SIGKILL);76errno = error;77err(-1, "tcp_server: socket");78}7980bzero(&sin, sizeof(sin));81sin.sin_family = AF_INET;82sin.sin_len = sizeof(sin);83sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);84sin.sin_port = htons(TCP_PORT);8586if (bind(listen_fd, (struct sockaddr *)&sin, sizeof(sin)) < 0) {87error = errno;88(void)kill(partner, SIGKILL);89errno = error;90err(-1, "tcp_server: bind");91}9293if (listen(listen_fd, -1) < 0) {94error = errno;95(void)kill(partner, SIGKILL);96errno = error;97err(-1, "tcp_server: listen");98}99100sleep(10);101102accept_fd = accept(listen_fd, NULL, NULL);103if (accept_fd < 0) {104error = errno;105(void)kill(partner, SIGKILL);106errno = error;107err(-1, "tcp_server: accept");108}109close(accept_fd);110close(listen_fd);111}112113static void114tcp_client(pid_t partner, int dropflag)115{116struct sockaddr_in sin, sin_local;117int error, sock;118socklen_t slen;119120sleep(1);121122sock = socket(PF_INET, SOCK_STREAM, 0);123if (sock < 0) {124error = errno;125(void)kill(partner, SIGKILL);126errno = error;127err(-1, "socket");128}129130bzero(&sin, sizeof(sin));131sin.sin_family = AF_INET;132sin.sin_len = sizeof(sin);133sin.sin_addr.s_addr = ntohl(INADDR_LOOPBACK);134sin.sin_port = htons(TCP_PORT);135136if (connect(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) {137error = errno;138(void)kill(partner, SIGKILL);139errno = error;140err(-1, "connect");141}142143slen = sizeof(sin_local);144if (getsockname(sock, (struct sockaddr *)&sin_local, &slen) < 0) {145error = errno;146(void)kill(partner, SIGKILL);147errno = error;148err(-1, "getsockname");149}150151if (dropflag) {152if (tcp_drop(&sin_local, &sin) < 0) {153error = errno;154(void)kill(partner, SIGKILL);155errno = error;156err(-1, "tcp_drop");157}158sleep(2);159}160close(sock);161}162163int164main(int argc, char *argv[])165{166pid_t child_pid, parent_pid;167168if (signal(SIGCHLD, SIG_IGN) == SIG_ERR)169err(-1, "signal");170171parent_pid = getpid();172child_pid = fork();173if (child_pid < 0)174err(-1, "fork");175if (child_pid == 0) {176child_pid = getpid();177tcp_server(parent_pid);178return (0);179} else180tcp_client(child_pid, 0);181(void)kill(child_pid, SIGTERM);182183sleep(5);184185parent_pid = getpid();186child_pid = fork();187if (child_pid < 0)188err(-1, "fork");189if (child_pid == 0) {190child_pid = getpid();191tcp_server(parent_pid);192return (0);193} else194tcp_client(child_pid, 1);195(void)kill(child_pid, SIGTERM);196197return (0);198}199200201