1 // SPDX-License-Identifier: GPL-2.0 2 3 #include <stdio.h> 4 #include <stdlib.h> 5 #include <fcntl.h> 6 #include <string.h> 7 #include <unistd.h> 8 #include <signal.h> 9 10 #include <arpa/inet.h> 11 #include <sys/socket.h> 12 13 #define PORT 12345 14 #define RUNTIME 10 15 16 static struct { 17 unsigned int timeout; 18 unsigned int port; 19 } opts = { 20 .timeout = RUNTIME, 21 .port = PORT, 22 }; 23 24 static void handler(int sig) 25 { 26 _exit(sig == SIGALRM ? 0 : 1); 27 } 28 29 static void set_timeout(void) 30 { 31 struct sigaction action = { 32 .sa_handler = handler, 33 }; 34 35 sigaction(SIGALRM, &action, NULL); 36 37 alarm(opts.timeout); 38 } 39 40 static void do_connect(const struct sockaddr_in *dst) 41 { 42 int s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 43 44 if (s >= 0) 45 fcntl(s, F_SETFL, O_NONBLOCK); 46 47 connect(s, (struct sockaddr *)dst, sizeof(*dst)); 48 close(s); 49 } 50 51 static void do_accept(const struct sockaddr_in *src) 52 { 53 int c, one = 1, s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 54 55 if (s < 0) 56 return; 57 58 setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)); 59 setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one)); 60 61 bind(s, (struct sockaddr *)src, sizeof(*src)); 62 63 listen(s, 16); 64 65 c = accept(s, NULL, NULL); 66 if (c >= 0) 67 close(c); 68 69 close(s); 70 } 71 72 static int accept_loop(void) 73 { 74 struct sockaddr_in src = { 75 .sin_family = AF_INET, 76 .sin_port = htons(opts.port), 77 }; 78 79 inet_pton(AF_INET, "127.0.0.1", &src.sin_addr); 80 81 set_timeout(); 82 83 for (;;) 84 do_accept(&src); 85 86 return 1; 87 } 88 89 static int connect_loop(void) 90 { 91 struct sockaddr_in dst = { 92 .sin_family = AF_INET, 93 .sin_port = htons(opts.port), 94 }; 95 96 inet_pton(AF_INET, "127.0.0.1", &dst.sin_addr); 97 98 set_timeout(); 99 100 for (;;) 101 do_connect(&dst); 102 103 return 1; 104 } 105 106 static void parse_opts(int argc, char **argv) 107 { 108 int c; 109 110 while ((c = getopt(argc, argv, "t:p:")) != -1) { 111 switch (c) { 112 case 't': 113 opts.timeout = atoi(optarg); 114 break; 115 case 'p': 116 opts.port = atoi(optarg); 117 break; 118 } 119 } 120 } 121 122 int main(int argc, char *argv[]) 123 { 124 pid_t p; 125 126 parse_opts(argc, argv); 127 128 p = fork(); 129 if (p < 0) 130 return 111; 131 132 if (p > 0) 133 return accept_loop(); 134 135 return connect_loop(); 136 } 137