• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 @! # TEST TYPE(S): Concurrency, Load stress
3 @! # TESTCASE DESCRIPTION:
4 @! # 	Purpose: to send packets from the file to echo protocol on remote
5 @! #		 machine and read the echoing packets back and compare them
6 @! # 	Design: Connect to echo protocol on the remote machine
7 @! #		read from the file and send the file to remote machine
8 @! #		read the echoing  packets and store them in a file
9 @! #		repeat until file exhausted.
10 @! #		compare result
11 @! #
12 @! # SPEC. EXEC. REQS: May require multiple of this test to run
13 @! #		       to target machines from multiple machine in order
14 @! #		       to create stress condition
15 @! # 			echoes <REMOTE HOST> <echofile> <number of processes>
16 */
17 #include <unistd.h>
18 #include <sys/types.h>
19 #include <sys/socket.h>
20 #include <sys/stat.h>
21 #include <sys/wait.h>
22 #include <errno.h>
23 #include <libgen.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <netdb.h>
28 #include <netinet/in.h>
29 #include <fcntl.h>
30 #include "test.h"
31 #include "netdefs.h"
32 
33 #if INET6
34 char *TCID = "echoes6";
35 #else
36 char *TCID = "echoes";
37 #endif
38 
39 int TST_TOTAL = 1;
40 
41 void echofile(struct servent *, struct addrinfo *, char *, char *);
42 int checkfile(char *, char *);
43 void cleanup(int);
44 
main(int argc,char * argv[],char * env[])45 int main(int argc, char *argv[], char *env[])
46 {
47 
48 	unsigned int finish, i, j, k;
49 	int gai, wait_stat;
50 	pid_t pid;
51 	struct addrinfo hints, *hp;
52 	struct servent *sp;
53 	struct {
54 		char resultfile[FILENAME_MAX + 1];
55 		pid_t pid;
56 	} echo_struc[200];
57 
58 	memset(&hints, 0, sizeof(hints));
59 	hints.ai_family = PFI;
60 	hints.ai_socktype = SOCK_STREAM;
61 
62 	if (argc != 4)
63 		tst_brkm(TBROK, NULL, "usage: remote-addr file num-procs");
64 
65 	if ((sp = getservbyname("echo", "tcp")) == NULL)
66 		tst_brkm(TBROK | TERRNO, NULL, "getservbyname failed");
67 
68 	if ((gai = getaddrinfo(argv[1], NULL, &hints, &hp)) != 0)
69 		tst_brkm(TBROK, NULL, "unknown subject address %s: %s\n",
70 			 argv[1], gai_strerror(gai));
71 
72 	if (!hp || !hp->ai_addr || hp->ai_addr->sa_family != AFI)
73 		tst_brkm(TBROK, NULL, "getaddrinfo failed");
74 
75 	i = (unsigned int)strtol(argv[3], NULL, 10);
76 	j = 0;
77 	while (i-- > 0) {
78 		switch (pid = fork()) {
79 		case 0:
80 			snprintf(echo_struc[j].resultfile,
81 				 FILENAME_MAX, "%s%u", argv[2], j);
82 			echofile(sp, hp, echo_struc[j].resultfile, argv[2]);
83 			break;
84 		case -1:
85 			tst_resm(TBROK | TERRNO, "fork failed");
86 			break;
87 		default:
88 			echo_struc[j].pid = pid;
89 			j++;
90 			break;
91 		}
92 	}
93 	finish = (unsigned int)strtol(argv[3], NULL, 10);
94 	i = finish;
95 	/* Consume all operating threads until we're done... */
96 	while (finish != 0) {
97 
98 		if ((pid = wait(&wait_stat)) == -1)
99 			tst_resm(TFAIL | TERRNO, "wait failed");
100 		if (wait_stat == 0) {
101 			for (j = 0; j < i; j++) {
102 				if (echo_struc[j].pid == pid) {
103 					finish--;
104 					j = i;
105 				}
106 			}
107 		} else {
108 
109 			tst_resm(TFAIL, "wait(2) status was non-zero");
110 
111 			if (WIFEXITED(wait_stat)) {
112 				tst_resm(TINFO, "exit status: %d",
113 					 WEXITSTATUS(wait_stat));
114 			} else if (WIFSIGNALED(wait_stat)) {
115 				tst_resm(TINFO, "signaled: %d",
116 					 WTERMSIG(wait_stat));
117 			}
118 
119 			for (k = 0; k < i; k++) {
120 				if (kill(echo_struc[k].pid, 0) == 0) {
121 					kill(echo_struc[k].pid, 9);
122 				}
123 			}
124 			break;
125 		}
126 
127 	}
128 
129 	tst_exit();
130 }
131 
132 /* XXX (garrcoop): This shouldn't use libltp as it's a forked process. */
133 void
echofile(struct servent * sp,struct addrinfo * ai,char * resultfile,char * srcfile)134 echofile(struct servent *sp, struct addrinfo *ai, char *resultfile,
135 	 char *srcfile)
136 {
137 	int n;
138 	int port;
139 	char wr_buffer[BUFSIZ];
140 	char rd_buffer[BUFSIZ];
141 	sai_t sa;
142 #ifdef DEBUG
143 	sa_t address;
144 	socklen_t addrlen;
145 #endif
146 	int s;
147 	int finish;
148 	int fdw, fdr;
149 	int nread, nwrite;
150 	int count;
151 	pid_t pid;
152 
153 #ifdef 	DEBUG
154 	printf("Creating socket .....\n");
155 #endif
156 
157 	pid = getpid();
158 	if ((s = socket(AFI, SOCK_STREAM, 0)) < 0) {
159 		tst_resm(TBROK, "Failed to create listener socket (pid=%d)",
160 			 pid);
161 		cleanup(s);
162 		tst_exit();
163 	}
164 	port = sp->s_port;
165 
166 	/*
167 	 * TODO: Old code did something of the form:
168 	 *
169 	 * struct hostent *hp;
170 	 *
171 	 * hp = gethostbyname(argv[1]);
172 	 *
173 	 * ...
174 	 *
175 	 * struct       in_addr hostaddr;
176 	 *
177 	 * memcpy(&hostaddr,hp->h_addr_list[0],sizeof(struct in_addr));
178 	 *
179 	 * This is all fine and dandy, but gethostbyname has been deprecated
180 	 * for some time, and doesn't work too well with IPV6 (from what I've
181 	 * read), so I have to push it over to getaddrinfo. getaddrinfo isn't
182 	 * a 1:1 mapping though, so I have to do some work to shoehorn the old
183 	 * code to fit the new code.
184 	 *
185 	 * Some notes (from a test app)...
186 	 *
187 	 * (gdb) set args 127.0.0.1
188 	 * (gdb) list
189 	 * 33              for (int i = 1; i < argc; i++) {
190 	 * 34
191 	 * 35                      gai = getaddrinfo(argv[i], NULL, &hints, &ai);
192 	 * 36                      hp = gethostbyname(argv[i]);
193 	 * 37
194 	 * 38                      if (gai != 0) {
195 	 * 39                              printf("Error: %s\n", gai_strerror(gai));
196 	 * 40                              error = 2;
197 	 * 41                      } else {
198 	 * 42                              printf("Host IP: 0x%x\n", ai->ai_addr);
199 	 * (gdb) p *hp
200 	 * $16 = {h_name = 0x1a60198 "127.0.0.1", h_aliases = 0x1a60190, h_addrtype = 2,
201 	 *   h_length = 4, h_addr_list = 0x1a60180}
202 	 * (gdb) p *hp->h_addr_list
203 	 * $14 = 0x1a60170 "\177"
204 	 * (gdb) p *ai
205 	 * $15 = {ai_flags = 0, ai_family = 2, ai_socktype = 1, ai_protocol = 6,
206 	 *   ai_addrlen = 16, ai_addr = 0x1a600b0, ai_canonname = 0x0,
207 	 *     ai_next = 0x1a600d0}
208 	 *
209 	 * If one continues down this path, SIGPIPE will get tossed at the first
210 	 * write(2), as opposed to Connection refused (the old code). So I'm not
211 	 * passing in the correct info to connect(2).
212 	 *
213 	 * That and using -DDEBUG with the getpeername(3) call below always fails
214 	 * (that alone should be a sufficient to note that my sockaddr* data is
215 	 * skewed).
216 	 *
217 	 * For now let's just mark it broken.
218 	 *
219 	 */
220 	//tst_resm(TBROK, "FIX ME GARRETT!");
221 	//tst_exit();
222 
223 	memset((char *)&sa, 0, sizeof(sa));
224 	memcpy(&sa, ai->ai_addr, ai->ai_addrlen);
225 
226 #if INET6
227 	sa.sin6_port = port;
228 #else
229 	sa.sin_port = port;
230 #endif
231 
232 	if (connect(s, (sa_t *) & sa, sizeof(sa)) == -1) {
233 		tst_resm(TBROK | TERRNO,
234 			 "failed to create connector socket (pid=%d)", pid);
235 		cleanup(s);
236 		tst_exit();
237 	}
238 #ifdef DEBUG
239 	addrlen = sizeof(struct sockaddr);
240 	/* printf("addrlen=%d\n", addrlen); */
241 	/* printf("ai->ai_addr=%s\n", inet_ntoa(ai->ai_addr)); */
242 	if (getsockname(s, &address, &addrlen) == -1) {
243 		tst_resm(TBROK | TERRNO, "getsockname call failed (pid=%d)",
244 			 pid);
245 		cleanup(s);
246 		tst_exit();
247 	}
248 
249 	printf("local port is: %d\n", port);
250 
251 	if (getpeername(s, &address, &addrlen) == -1) {
252 		tst_resm(TBROK | TERRNO, "getpeername call failed (pid=%d)",
253 			 pid);
254 		cleanup(s);
255 		tst_exit();
256 	}
257 
258 	tst_resm(TINFO, "The remote port is: %d\n", port);
259 #endif
260 	if ((fdr = open(srcfile, O_RDONLY)) < 0) {
261 		tst_resm(TBROK | TERRNO,
262 			 "failed to open input file (pid=%d)", pid);
263 		cleanup(s);
264 		tst_exit();
265 	}
266 
267 	if ((fdw = creat(resultfile, 0644)) < 0) {
268 		tst_resm(TBROK | TERRNO,
269 			 "failed to create a temporary file (pid=%d)", pid);
270 		cleanup(s);
271 		tst_exit();
272 	}
273 #if DEBUG
274 	tst_resm(TINFO, "creat(resultfile,...) done.");
275 #endif
276 	finish = FALSE;
277 	count = 0;
278 	while (finish == FALSE) {
279 
280 		if ((nwrite = read(fdr, wr_buffer, BUFSIZ)) == -1) {
281 			tst_resm(TFAIL | TERRNO,
282 				 "failed to read from file (pid=%d)", pid);
283 			cleanup(s);
284 		}
285 #if DEBUG
286 		tst_resm(TINFO, "Read %d bytes from file", nwrite);
287 #endif
288 		if (nwrite == 0)
289 			finish = TRUE;
290 		else {
291 			count++;
292 			if ((n = write(s, wr_buffer, nwrite)) != nwrite) {
293 				tst_resm(TFAIL | TERRNO,
294 					 "failed to write to socket (pid=%d)",
295 					 pid);
296 				cleanup(s);
297 			}
298 #ifdef 	DEBUG
299 			tst_resm(TINFO, "Writing %d bytes to remote socket",
300 				 count);
301 #endif
302 			while (nwrite != 0) {
303 
304 				nread = read(s, rd_buffer, BUFSIZ);
305 				if (nread == -1) {
306 					printf("read size: %d\n", n);
307 					tst_resm(TFAIL | TERRNO,
308 						 "failed to read from socket [2nd "
309 						 "time] (pid=%d)", pid);
310 					cleanup(s);
311 				}
312 #ifdef 	DEBUG
313 				printf("Reading ....... %d\n", count);
314 #endif
315 				n = write(fdw, rd_buffer, nread);
316 				if (n != nread) {
317 					tst_resm(TFAIL | TERRNO,
318 						 "ERROR during write to result "
319 						 "file (pid=%d); read amount: %d",
320 						 pid, n);
321 					cleanup(s);
322 				}
323 
324 				nwrite -= nread;
325 
326 			}
327 
328 		}		/* end of else */
329 
330 	}			/* end of while */
331 
332 	if ((n = close(s)) == -1) {
333 		tst_brkm(TBROK | TERRNO, NULL,
334 			 "failed to cleanly close socket (pid=%d)", pid);
335 	}
336 	if ((n = close(fdr)) == -1) {
337 		tst_brkm(TBROK | TERRNO, NULL,
338 			 "failed to cleanly close input file (pid=%d)", pid);
339 	}
340 	if ((n = close(fdw)) == -1) {
341 		tst_brkm(TBROK | TERRNO, NULL,
342 			 "failed to cleanly close temp file (pid=%d)", pid);
343 	}
344 	if (checkfile(srcfile, resultfile) != TRUE) {
345 		tst_brkm(TFAIL, NULL,
346 			 "Input file and output file are not equal (pid=%d)",
347 			 pid);
348 	}
349 	tst_resm(TINFO, "Finish .... (pid=%d)", pid);
350 	tst_exit();
351 }
352 
checkfile(char * file1,char * file2)353 int checkfile(char *file1, char *file2)
354 {
355 	off_t n;
356 	struct stat buffer;
357 	stat(file1, &buffer);
358 	n = buffer.st_size;
359 #ifdef 	DEBUG
360 	printf("%s size=%lu\n", file1, n);
361 #endif
362 	stat(file2, &buffer);
363 #ifdef 	DEBUG
364 	printf("%s size=%lu\n", file2, buffer.st_size);
365 #endif
366 	if (n != buffer.st_size)
367 		return FALSE;
368 	else
369 		return TRUE;
370 }
371 
cleanup(int s)372 void cleanup(int s)
373 {
374 	close(s);
375 }
376