blob: 7a9f110bc695645eb209b2e6992f31f6e5c2e63c [file] [log] [blame]
plars865695b2001-08-27 22:15:12 +00001/*
2 *
3 * Copyright (c) International Business Machines Corp., 2001
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
13 * the GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20/*
21 * Test Name: recvfrom01
22 *
23 * Test Description:
24 * Verify that recvfrom() returns the proper errno for various failure cases
25 *
26 * Usage: <for command-line>
27 * recvfrom01 [-c n] [-e] [-i n] [-I x] [-P x] [-t]
28 * where, -c n : Run n copies concurrently.
29 * -e : Turn on errno logging.
30 * -i n : Execute test n times.
31 * -I x : Execute test for x seconds.
32 * -P x : Pause for x seconds between iterations.
33 * -t : Turn on syscall timing.
34 *
35 * HISTORY
36 * 07/2001 Ported by Wayne Boyer
37 *
38 * RESTRICTIONS:
39 * None.
40 *
41 */
42
43#include <stdio.h>
44#include <unistd.h>
45#include <errno.h>
plarsb7ba4932002-05-06 21:56:16 +000046#include <fcntl.h>
plars865695b2001-08-27 22:15:12 +000047
48#include <sys/types.h>
49#include <sys/socket.h>
50#include <sys/signal.h>
51#include <sys/un.h>
52
53#include <netinet/in.h>
54
55#include "test.h"
56#include "usctest.h"
57
58char *TCID="recvfrom01"; /* Test program identifier. */
59int testno;
60
61char buf[1024];
62int s; /* socket descriptor */
63struct sockaddr_in sin1, from;
robbiewd34d5812005-07-11 22:28:09 +000064static int sfd; /* shared between do_child and start_server */
robbiew46faba62003-04-29 14:36:25 +000065socklen_t fromlen;
plars865695b2001-08-27 22:15:12 +000066
robbiewd34d5812005-07-11 22:28:09 +000067void do_child(void);
plarse12303f2003-01-28 17:20:24 +000068void setup(void);
69void setup0(void);
70void setup1(void);
71void setup2(void);
72void cleanup(void);
73void cleanup0(void);
74void cleanup1(void);
75pid_t start_server(struct sockaddr_in *);
plars865695b2001-08-27 22:15:12 +000076
77struct test_case_t { /* test case structure */
78 int domain; /* PF_INET, PF_UNIX, ... */
79 int type; /* SOCK_STREAM, SOCK_DGRAM ... */
80 int proto; /* protocol number (usually 0 = default) */
81 void *buf; /* recv data buffer */
robbiew46faba62003-04-29 14:36:25 +000082 size_t buflen; /* recv's 3rd argument */
plars865695b2001-08-27 22:15:12 +000083 unsigned flags; /* recv's 4th argument */
84 struct sockaddr *from; /* from address */
robbiew46faba62003-04-29 14:36:25 +000085 socklen_t *salen; /* from address value/result buffer length */
plars865695b2001-08-27 22:15:12 +000086 int retval; /* syscall return value */
87 int experrno; /* expected errno */
88 void (*setup)(void);
89 void (*cleanup)(void);
90 char *desc;
91} tdat[] = {
plarse12303f2003-01-28 17:20:24 +000092/* 1 */
plars865695b2001-08-27 22:15:12 +000093 { PF_INET, SOCK_STREAM, 0, buf, sizeof(buf), 0,
94 (struct sockaddr *)&from, &fromlen,
95 -1, EBADF, setup0, cleanup0, "bad file descriptor" },
plarse12303f2003-01-28 17:20:24 +000096/* 2 */
plars865695b2001-08-27 22:15:12 +000097 { 0, 0, 0, buf, sizeof(buf), 0, (struct sockaddr *)&from, &fromlen,
98 -1, ENOTSOCK, setup0, cleanup0, "invalid socket" },
plarse12303f2003-01-28 17:20:24 +000099/* 3 */
plars865695b2001-08-27 22:15:12 +0000100 { PF_INET, SOCK_STREAM, 0, (void *)buf, sizeof(buf), 0,
101 (struct sockaddr *)-1, &fromlen,
robbiew11833d32001-09-13 16:28:55 +0000102 0, ENOTSOCK, setup1, cleanup1, "invalid socket buffer" },
plarse12303f2003-01-28 17:20:24 +0000103/* 4 */
robbiew46faba62003-04-29 14:36:25 +0000104 { PF_INET, SOCK_STREAM, 0, (void *)buf, sizeof(buf), -1,
plars865695b2001-08-27 22:15:12 +0000105 (struct sockaddr *)&from, &fromlen,
plarse12303f2003-01-28 17:20:24 +0000106 -1, EINVAL, setup2, cleanup1, "invalid socket length" },
107/* 5 */
plars865695b2001-08-27 22:15:12 +0000108 { PF_INET, SOCK_STREAM, 0, (void *)-1, sizeof(buf), 0,
109 (struct sockaddr *)&from, &fromlen,
plars421c8832001-12-13 14:37:20 +0000110 -1, EFAULT, setup1, cleanup1, "invalid recv buffer" },
plarse12303f2003-01-28 17:20:24 +0000111/* 6 */
plars865695b2001-08-27 22:15:12 +0000112 { PF_INET, SOCK_STREAM, 0, (void *)buf, sizeof(buf), -1,
113 (struct sockaddr *)&from, &fromlen,
114 -1, EINVAL, setup1, cleanup1, "invalid flags set" },
115};
116
117int TST_TOTAL=sizeof(tdat)/sizeof(tdat[0]); /* Total number of test cases. */
118
119int exp_enos[] = {EBADF, ENOTSOCK, EFAULT, EINVAL, 0};
120
121extern int Tst_count;
122
robbiewd34d5812005-07-11 22:28:09 +0000123#ifdef UCLINUX
124static char *argv0;
125#endif
126
plars865695b2001-08-27 22:15:12 +0000127int
128main(int argc, char *argv[])
129{
130 int lc; /* loop counter */
131 char *msg; /* message returned from parse_opts */
132
133 /* Parse standard options given to run the test. */
134 msg = parse_opts(argc, argv, (option_t *)NULL, NULL);
135 if (msg != (char *)NULL) {
136 tst_brkm(TBROK, tst_exit, "OPTION PARSING ERROR - %s", msg);
137 }
138
robbiewd34d5812005-07-11 22:28:09 +0000139#ifdef UCLINUX
140 argv0 = argv[0];
141 maybe_run_child(&do_child, "d", &sfd);
142#endif
143
plars865695b2001-08-27 22:15:12 +0000144 setup();
145
146 TEST_EXP_ENOS(exp_enos);
147
148 /* Check looping state if -i option given */
149 for (lc = 0; TEST_LOOPING(lc); ++lc) {
150 Tst_count = 0;
151 for (testno=0; testno < TST_TOTAL; ++testno) {
152 tdat[testno].setup();
153
154 TEST(recvfrom(s, tdat[testno].buf, tdat[testno].buflen,
155 tdat[testno].flags, tdat[testno].from,
156 tdat[testno].salen));
157 if (TEST_RETURN >= 0)
158 TEST_RETURN = 0; /* all nonzero equal here */
159 if (TEST_RETURN != tdat[testno].retval ||
160 (TEST_RETURN < 0 &&
161 TEST_ERRNO != tdat[testno].experrno)) {
162 tst_resm(TFAIL, "%s ; returned"
163 " %d (expected %d), errno %d (expected"
164 " %d)", tdat[testno].desc,
165 TEST_RETURN, tdat[testno].retval,
166 TEST_ERRNO, tdat[testno].experrno);
167 } else {
168 TEST_ERROR_LOG(TEST_ERRNO);
169 tst_resm(TPASS, "%s successful",
170 tdat[testno].desc);
171 }
172 tdat[testno].cleanup();
173 }
174 }
175 cleanup();
plarse12303f2003-01-28 17:20:24 +0000176 /*NOT REACHED*/
177 return 0;
plars865695b2001-08-27 22:15:12 +0000178} /* End main */
179
180pid_t pid;
181
182void
183setup(void)
184{
185 TEST_PAUSE; /* if -P option specified */
186
187 /* initialize sockaddr's */
188 sin1.sin_family = AF_INET;
189 sin1.sin_port = htons((getpid() % 32768) +11000);
190 sin1.sin_addr.s_addr = INADDR_ANY;
191 pid = start_server(&sin1);
192}
193
194void
195cleanup(void)
196{
197 (void) kill(pid, SIGKILL); /* kill server */
198 TEST_CLEANUP;
199 tst_exit();
200}
201
202
203void
204setup0(void)
205{
206 if (tdat[testno].experrno == EBADF)
207 s = 400; /* anything not an open file */
208 else
plarsb7ba4932002-05-06 21:56:16 +0000209 if((s = open("/dev/null", O_WRONLY)) == -1)
210 tst_brkm(TBROK, cleanup, "error opening /dev/null - "
211 "errno: %s", strerror(errno));
plars865695b2001-08-27 22:15:12 +0000212 fromlen = sizeof(from);
213}
214
215void
216cleanup0(void)
217{
218 s = -1;
219}
220
221void
222setup1(void)
223{
robbiewef952662003-03-27 15:10:06 +0000224 fd_set rdfds;
225 struct timeval timeout;
226 int n;
227
plars865695b2001-08-27 22:15:12 +0000228 s = socket(tdat[testno].domain, tdat[testno].type, tdat[testno].proto);
229 if (s < 0) {
230 tst_brkm(TBROK, cleanup, "socket setup failed: %s",
231 strerror(errno));
232 }
233 if (tdat[testno].type == SOCK_STREAM &&
plarse12303f2003-01-28 17:20:24 +0000234 connect(s, (struct sockaddr *)&sin1, sizeof(sin1)) < 0) {
plars865695b2001-08-27 22:15:12 +0000235 tst_brkm(TBROK, cleanup, "connect failed: ", strerror(errno));
236 }
robbiewef952662003-03-27 15:10:06 +0000237 /* Wait for something to be readable, else we won't detect EFAULT on recv */
238 FD_ZERO(&rdfds);
239 FD_SET(s, &rdfds);
240 timeout.tv_sec = 2;
241 timeout.tv_usec = 0;
242 n = select(s+1, &rdfds, 0, 0, &timeout);
243 if (n != 1 || !FD_ISSET(s, &rdfds))
244 tst_brkm(TBROK, cleanup, "client setup1 failed - no message ready in 2 sec");
plars865695b2001-08-27 22:15:12 +0000245 fromlen = sizeof(from);
246}
247
248void
249setup2(void)
250{
251 setup1();
252 fromlen = -1;
253}
254
255void
256cleanup1(void)
257{
258 (void) close(s);
259 s = -1;
260}
261
262pid_t
263start_server(struct sockaddr_in *sin0)
264{
robbiewd34d5812005-07-11 22:28:09 +0000265 struct sockaddr_in sin1 = *sin0;
plars865695b2001-08-27 22:15:12 +0000266 pid_t pid;
plars865695b2001-08-27 22:15:12 +0000267
268 sfd = socket(PF_INET, SOCK_STREAM, 0);
269 if (sfd < 0) {
270 tst_brkm(TBROK, cleanup, "server socket failed: %s",
271 strerror(errno));
272 return -1;
273 }
plarse12303f2003-01-28 17:20:24 +0000274 if (bind(sfd, (struct sockaddr *)&sin1, sizeof(sin1)) < 0) {
plars865695b2001-08-27 22:15:12 +0000275 tst_brkm(TBROK, cleanup, "server bind failed: %s",
276 strerror(errno));
277 return -1;
278 }
279 if (listen(sfd, 10) < 0) {
280 tst_brkm(TBROK, cleanup, "server listen failed: %s",
281 strerror(errno));
282 return -1;
283 }
vapierfed9da32006-02-19 09:25:08 +0000284 switch ((pid = FORK_OR_VFORK())) {
plars865695b2001-08-27 22:15:12 +0000285 case 0: /* child */
robbiewd34d5812005-07-11 22:28:09 +0000286#ifdef UCLINUX
287 if (self_exec(argv0, "d", sfd) < 0) {
288 tst_brkm(TBROK, cleanup, "server self_exec failed");
289 }
290#else
291 do_child();
292#endif
plars865695b2001-08-27 22:15:12 +0000293 break;
294 case -1:
295 tst_brkm(TBROK, cleanup, "server fork failed: %s",
296 strerror(errno));
297 /* fall through */
298 default: /* parent */
299 (void) close(sfd);
300 return pid;
301 }
302
robbiewd34d5812005-07-11 22:28:09 +0000303 /*NOTREACHED*/
304 exit(1);
305}
306
307void
308do_child()
309{
310 struct sockaddr_in fsin;
311 fd_set afds, rfds;
312 int nfds, cc, fd;
313
plars865695b2001-08-27 22:15:12 +0000314 FD_ZERO(&afds);
315 FD_SET(sfd, &afds);
316
317 nfds = getdtablesize();
318
319 /* accept connections until killed */
320 while (1) {
robbiew46faba62003-04-29 14:36:25 +0000321 socklen_t fromlen;
plars865695b2001-08-27 22:15:12 +0000322
323 memcpy(&rfds, &afds, sizeof(rfds));
324
325 if (select(nfds, &rfds, (fd_set *)0, (fd_set *)0,
326 (struct timeval *)0) < 0)
327 if (errno != EINTR)
328 exit(1);
329 if (FD_ISSET(sfd, &rfds)) {
330 int newfd;
331
332 fromlen = sizeof(fsin);
plarse12303f2003-01-28 17:20:24 +0000333 newfd = accept(sfd, (struct sockaddr *)&fsin, &fromlen);
plars865695b2001-08-27 22:15:12 +0000334 if (newfd >= 0)
335 FD_SET(newfd, &afds);
336 /* send something back */
337 (void) write(newfd, "hoser\n", 6);
338 }
339 for (fd=0; fd<nfds; ++fd)
340 if (fd != sfd && FD_ISSET(fd, &rfds)) {
341 cc = read(fd, buf, sizeof(buf));
342 if (cc == 0 || (cc < 0 && errno != EINTR)) {
343 (void) close(fd);
344 FD_CLR(fd, &afds);
345 }
346 }
347 }
348}
349