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