1 #include <sys/types.h>
2 #include <sys/mman.h>
3 #include <sys/socket.h>
4 #include <sys/sysctl.h>
5 #include <sys/time.h>
6 #include <sys/wait.h>
7 
8 #include <arpa/inet.h>
9 #include <netinet/in.h>
10 
11 #include <err.h>
12 #include <signal.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <unistd.h>
17 
18 static void	mainloop(const struct sockaddr_in *, long, u_long *);
19 
20 static int	global_stopped;
21 
22 static void
23 usage(const char *cmd)
24 {
25 	fprintf(stderr, "%s -4 inet4 -p port "
26 	    "[-i n_instance] [-l duration]\n", cmd);
27 	exit(1);
28 }
29 
30 int
31 main(int argc, char *argv[])
32 {
33 	struct sockaddr_in in;
34 	int opt, ninst, i;
35 	long dur;
36 	u_long *result, sum;
37 	size_t prm_len;
38 
39 	prm_len = sizeof(ninst);
40 	if (sysctlbyname("hw.ncpu", &ninst, &prm_len, NULL, 0) != 0)
41 		err(2, "sysctl hw.ncpu failed");
42 
43 	memset(&in, 0, sizeof(in));
44 	in.sin_family = AF_INET;
45 
46 	dur = 10;
47 
48 	while ((opt = getopt(argc, argv, "4:p:i:l:")) != -1) {
49 		switch (opt) {
50 		case '4':
51 			if (inet_pton(AF_INET, optarg, &in.sin_addr) <= 0) {
52 				fprintf(stderr, "invalid inet address %s\n",
53 				    optarg);
54 				usage(argv[0]);
55 			}
56 			break;
57 
58 		case 'p':
59 			in.sin_port = htons(atoi(optarg));
60 			break;
61 
62 		case 'i':
63 			ninst = atoi(optarg);
64 			break;
65 
66 		case 'l':
67 			dur = strtol(optarg, NULL, 10);
68 			break;
69 
70 		default:
71 			usage(argv[0]);
72 		}
73 	}
74 
75 	if (ninst < 1 || dur < 1 ||
76 	    in.sin_port == 0 || in.sin_addr.s_addr == INADDR_ANY)
77 		usage(argv[0]);
78 
79 	result = mmap(NULL, ninst * sizeof(u_long), PROT_READ | PROT_WRITE,
80 	    MAP_ANON | MAP_SHARED, -1, 0);
81 	if (result == MAP_FAILED)
82 		err(1, "mmap failed");
83 	memset(result, 0, ninst * sizeof(u_long));
84 
85 	for (i = 0; i < ninst; ++i) {
86 		pid_t pid;
87 
88 		pid = fork();
89 		if (pid == 0) {
90 			mainloop(&in, dur, &result[i]);
91 			exit(0);
92 		} else if (pid < 0) {
93 			err(1, "fork failed");
94 		}
95 	}
96 
97 	for (i = 0; i < ninst; ++i) {
98 		pid_t pid;
99 
100 		pid = waitpid(-1, NULL, 0);
101 		if (pid < 0)
102 			err(1, "waitpid failed");
103 	}
104 
105 	sum = 0;
106 	for (i = 0; i < ninst; ++i)
107 		sum += result[i];
108 	printf("%.2f\n", (double)sum / (double)dur);
109 
110 	exit(0);
111 }
112 
113 static void
114 signal_handler(int signum __unused)
115 {
116 	global_stopped = 1;
117 }
118 
119 static void
120 mainloop(const struct sockaddr_in *in, long dur, u_long *res)
121 {
122 	struct itimerval it;
123 	u_long count = 0;
124 
125 	if (signal(SIGALRM, signal_handler) == SIG_ERR)
126 		err(1, "signal failed");
127 
128 	it.it_interval.tv_sec = 0;
129 	it.it_interval.tv_usec = 0;
130 	it.it_value.tv_sec = dur;
131 	it.it_value.tv_usec = 0;
132 
133 	if (setitimer(ITIMER_REAL, &it, NULL) < 0)
134 		err(1, "setitimer failed");
135 
136 	while (!global_stopped) {
137 		int s;
138 
139 		s = socket(AF_INET, SOCK_STREAM, 0);
140 		if (s < 0)
141 			continue;
142 
143 		if (connect(s,
144 		    (const struct sockaddr *)in, sizeof(*in)) == 0)
145 			++count;
146 		close(s);
147 	}
148 	*res = count;
149 }
150