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