1 #include <sys/types.h>
2 #include <sys/stat.h>
3 #include <sys/wait.h>
4 
5 #include <err.h>
6 #include <fcntl.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <unistd.h>
10 
11 #define NETPERF_CMD	"netperf"
12 #define NETPERF_PATH	"/usr/local/bin/" NETPERF_CMD
13 
14 struct netperf_child {
15 	int		pipes[2];
16 };
17 
18 static void
19 usage(const char *cmd)
20 {
21 	fprintf(stderr, "%s -H host [-l len_s] [-i instances]\n", cmd);
22 	exit(1);
23 }
24 
25 int
26 main(int argc, char *argv[])
27 {
28 	struct netperf_child *instance;
29 	char len_str[32];
30 	char *args[32];
31 	const char *host;
32 	volatile int ninst;
33 	int len, ninst_done;
34 	int opt, i, null_fd;
35 	double result;
36 
37 	host = NULL;
38 	ninst = 2;
39 	len = 10;
40 
41 	while ((opt = getopt(argc, argv, "i:H:l:")) != -1) {
42 		switch (opt) {
43 		case 'i':
44 			ninst = strtoul(optarg, NULL, 10);
45 			break;
46 
47 		case 'H':
48 			host = optarg;
49 			break;
50 
51 		case 'l':
52 			len = strtoul(optarg, NULL, 10);
53 			break;
54 
55 		default:
56 			usage(argv[0]);
57 		}
58 	}
59 	if (ninst <= 0 || host == NULL || len <= 0)
60 		usage(argv[0]);
61 
62 	snprintf(len_str, sizeof(len_str), "%d", len);
63 
64 	i = 0;
65 	args[i++] = __DECONST(char *, NETPERF_CMD);
66 	args[i++] = __DECONST(char *, "-P0");
67 	args[i++] = __DECONST(char *, "-H");
68 	args[i++] = __DECONST(char *, host);
69 	args[i++] = __DECONST(char *, "-l");
70 	args[i++] = __DECONST(char *, len_str);
71 	args[i++] = __DECONST(char *, "-t");
72 	args[i++] = __DECONST(char *, "TCP_CC");
73 	args[i] = NULL;
74 
75 	instance = calloc(ninst, sizeof(struct netperf_child));
76 	if (instance == NULL)
77 		err(1, "calloc failed");
78 
79 	null_fd = open("/dev/null", O_RDWR);
80 	if (null_fd < 0)
81 		err(1, "open null failed");
82 
83 	for (i = 0; i < ninst; ++i) {
84 		if (pipe(instance[i].pipes) < 0)
85 			err(1, "pipe %dth failed", i);
86 	}
87 
88 	for (i = 0; i < ninst; ++i) {
89 		pid_t pid;
90 
91 		pid = vfork();
92 		if (pid == 0) {
93 			int ret;
94 
95 			dup2(instance[i].pipes[1], STDOUT_FILENO);
96 			dup2(null_fd, STDERR_FILENO);
97 			ret = execv(NETPERF_PATH, args);
98 			if (ret < 0) {
99 				warn("execv %d failed", i);
100 				_exit(1);
101 			}
102 			/* Never reached */
103 			abort();
104 		} else if (pid < 0) {
105 			err(1, "vfork %d failed", i);
106 		}
107 		close(instance[i].pipes[1]);
108 		instance[i].pipes[1] = -1;
109 	}
110 
111 	ninst_done = 0;
112 	while (ninst_done < ninst) {
113 		pid_t pid;
114 
115 		pid = waitpid(-1, NULL, 0);
116 		if (pid < 0)
117 			err(1, "waitpid failed");
118 		++ninst_done;
119 	}
120 
121 	result = 0.0;
122 	for (i = 0; i < ninst; ++i) {
123 		char line[128];
124 		FILE *fp;
125 
126 		fp = fdopen(instance[i].pipes[0], "r");
127 		if (fp == NULL)
128 			err(1, "fdopen %dth failed\n", i);
129 
130 		while (fgets(line, sizeof(line), fp) != NULL) {
131 			int n, arg1, arg2, arg3, arg4;
132 			double res, arg5;
133 
134 			n = sscanf(line, "%d%d%d%d%lf%lf",
135 			    &arg1, &arg2, &arg3, &arg4, &arg5, &res);
136 			if (n == 6) {
137 				result += res;
138 				break;
139 			}
140 		}
141 		fclose(fp);
142 	}
143 	printf("TCP_CC %.2f conns/s\n", result);
144 
145 	exit(0);
146 }
147