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 16static struct { 17 unsigned int timeout; 18 unsigned int port; 19} opts = { 20 .timeout = RUNTIME, 21 .port = PORT, 22}; 23 24static void handler(int sig) 25{ 26 _exit(sig == SIGALRM ? 0 : 1); 27} 28 29static 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 40static 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 51static 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 72static 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 89static 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 106static 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 122int 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