blob: 4ae60dcea003e50cda00e4caa9d0c82324dfcc80 [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;
robbiew46faba62003-04-29 14:36:25 +000064socklen_t fromlen;
plars865695b2001-08-27 22:15:12 +000065
plarse12303f2003-01-28 17:20:24 +000066void setup(void);
67void setup0(void);
68void setup1(void);
69void setup2(void);
70void cleanup(void);
71void cleanup0(void);
72void cleanup1(void);
73pid_t start_server(struct sockaddr_in *);
plars865695b2001-08-27 22:15:12 +000074
75struct test_case_t { /* test case structure */
76 int domain; /* PF_INET, PF_UNIX, ... */
77 int type; /* SOCK_STREAM, SOCK_DGRAM ... */
78 int proto; /* protocol number (usually 0 = default) */
79 void *buf; /* recv data buffer */
robbiew46faba62003-04-29 14:36:25 +000080 size_t buflen; /* recv's 3rd argument */
plars865695b2001-08-27 22:15:12 +000081 unsigned flags; /* recv's 4th argument */
82 struct sockaddr *from; /* from address */
robbiew46faba62003-04-29 14:36:25 +000083 socklen_t *salen; /* from address value/result buffer length */
plars865695b2001-08-27 22:15:12 +000084 int retval; /* syscall return value */
85 int experrno; /* expected errno */
86 void (*setup)(void);
87 void (*cleanup)(void);
88 char *desc;
89} tdat[] = {
plarse12303f2003-01-28 17:20:24 +000090/* 1 */
plars865695b2001-08-27 22:15:12 +000091 { PF_INET, SOCK_STREAM, 0, buf, sizeof(buf), 0,
92 (struct sockaddr *)&from, &fromlen,
93 -1, EBADF, setup0, cleanup0, "bad file descriptor" },
plarse12303f2003-01-28 17:20:24 +000094/* 2 */
plars865695b2001-08-27 22:15:12 +000095 { 0, 0, 0, buf, sizeof(buf), 0, (struct sockaddr *)&from, &fromlen,
96 -1, ENOTSOCK, setup0, cleanup0, "invalid socket" },
plarse12303f2003-01-28 17:20:24 +000097/* 3 */
plars865695b2001-08-27 22:15:12 +000098 { PF_INET, SOCK_STREAM, 0, (void *)buf, sizeof(buf), 0,
99 (struct sockaddr *)-1, &fromlen,
robbiew11833d32001-09-13 16:28:55 +0000100 0, ENOTSOCK, setup1, cleanup1, "invalid socket buffer" },
plarse12303f2003-01-28 17:20:24 +0000101/* 4 */
robbiew46faba62003-04-29 14:36:25 +0000102 { PF_INET, SOCK_STREAM, 0, (void *)buf, sizeof(buf), -1,
plars865695b2001-08-27 22:15:12 +0000103 (struct sockaddr *)&from, &fromlen,
plarse12303f2003-01-28 17:20:24 +0000104 -1, EINVAL, setup2, cleanup1, "invalid socket length" },
105/* 5 */
plars865695b2001-08-27 22:15:12 +0000106 { PF_INET, SOCK_STREAM, 0, (void *)-1, sizeof(buf), 0,
107 (struct sockaddr *)&from, &fromlen,
plars421c8832001-12-13 14:37:20 +0000108 -1, EFAULT, setup1, cleanup1, "invalid recv buffer" },
plarse12303f2003-01-28 17:20:24 +0000109/* 6 */
plars865695b2001-08-27 22:15:12 +0000110 { PF_INET, SOCK_STREAM, 0, (void *)buf, sizeof(buf), -1,
111 (struct sockaddr *)&from, &fromlen,
112 -1, EINVAL, setup1, cleanup1, "invalid flags set" },
113};
114
115int TST_TOTAL=sizeof(tdat)/sizeof(tdat[0]); /* Total number of test cases. */
116
117int exp_enos[] = {EBADF, ENOTSOCK, EFAULT, EINVAL, 0};
118
119extern int Tst_count;
120
121int
122main(int argc, char *argv[])
123{
124 int lc; /* loop counter */
125 char *msg; /* message returned from parse_opts */
126
127 /* Parse standard options given to run the test. */
128 msg = parse_opts(argc, argv, (option_t *)NULL, NULL);
129 if (msg != (char *)NULL) {
130 tst_brkm(TBROK, tst_exit, "OPTION PARSING ERROR - %s", msg);
131 }
132
133 setup();
134
135 TEST_EXP_ENOS(exp_enos);
136
137 /* Check looping state if -i option given */
138 for (lc = 0; TEST_LOOPING(lc); ++lc) {
139 Tst_count = 0;
140 for (testno=0; testno < TST_TOTAL; ++testno) {
141 tdat[testno].setup();
142
143 TEST(recvfrom(s, tdat[testno].buf, tdat[testno].buflen,
144 tdat[testno].flags, tdat[testno].from,
145 tdat[testno].salen));
146 if (TEST_RETURN >= 0)
147 TEST_RETURN = 0; /* all nonzero equal here */
148 if (TEST_RETURN != tdat[testno].retval ||
149 (TEST_RETURN < 0 &&
150 TEST_ERRNO != tdat[testno].experrno)) {
151 tst_resm(TFAIL, "%s ; returned"
152 " %d (expected %d), errno %d (expected"
153 " %d)", tdat[testno].desc,
154 TEST_RETURN, tdat[testno].retval,
155 TEST_ERRNO, tdat[testno].experrno);
156 } else {
157 TEST_ERROR_LOG(TEST_ERRNO);
158 tst_resm(TPASS, "%s successful",
159 tdat[testno].desc);
160 }
161 tdat[testno].cleanup();
162 }
163 }
164 cleanup();
plarse12303f2003-01-28 17:20:24 +0000165 /*NOT REACHED*/
166 return 0;
plars865695b2001-08-27 22:15:12 +0000167} /* End main */
168
169pid_t pid;
170
171void
172setup(void)
173{
174 TEST_PAUSE; /* if -P option specified */
175
176 /* initialize sockaddr's */
177 sin1.sin_family = AF_INET;
178 sin1.sin_port = htons((getpid() % 32768) +11000);
179 sin1.sin_addr.s_addr = INADDR_ANY;
180 pid = start_server(&sin1);
181}
182
183void
184cleanup(void)
185{
186 (void) kill(pid, SIGKILL); /* kill server */
187 TEST_CLEANUP;
188 tst_exit();
189}
190
191
192void
193setup0(void)
194{
195 if (tdat[testno].experrno == EBADF)
196 s = 400; /* anything not an open file */
197 else
plarsb7ba4932002-05-06 21:56:16 +0000198 if((s = open("/dev/null", O_WRONLY)) == -1)
199 tst_brkm(TBROK, cleanup, "error opening /dev/null - "
200 "errno: %s", strerror(errno));
plars865695b2001-08-27 22:15:12 +0000201 fromlen = sizeof(from);
202}
203
204void
205cleanup0(void)
206{
207 s = -1;
208}
209
210void
211setup1(void)
212{
robbiewef952662003-03-27 15:10:06 +0000213 fd_set rdfds;
214 struct timeval timeout;
215 int n;
216
plars865695b2001-08-27 22:15:12 +0000217 s = socket(tdat[testno].domain, tdat[testno].type, tdat[testno].proto);
218 if (s < 0) {
219 tst_brkm(TBROK, cleanup, "socket setup failed: %s",
220 strerror(errno));
221 }
222 if (tdat[testno].type == SOCK_STREAM &&
plarse12303f2003-01-28 17:20:24 +0000223 connect(s, (struct sockaddr *)&sin1, sizeof(sin1)) < 0) {
plars865695b2001-08-27 22:15:12 +0000224 tst_brkm(TBROK, cleanup, "connect failed: ", strerror(errno));
225 }
robbiewef952662003-03-27 15:10:06 +0000226 /* Wait for something to be readable, else we won't detect EFAULT on recv */
227 FD_ZERO(&rdfds);
228 FD_SET(s, &rdfds);
229 timeout.tv_sec = 2;
230 timeout.tv_usec = 0;
231 n = select(s+1, &rdfds, 0, 0, &timeout);
232 if (n != 1 || !FD_ISSET(s, &rdfds))
233 tst_brkm(TBROK, cleanup, "client setup1 failed - no message ready in 2 sec");
plars865695b2001-08-27 22:15:12 +0000234 fromlen = sizeof(from);
235}
236
237void
238setup2(void)
239{
240 setup1();
241 fromlen = -1;
242}
243
244void
245cleanup1(void)
246{
247 (void) close(s);
248 s = -1;
249}
250
251pid_t
252start_server(struct sockaddr_in *sin0)
253{
254 struct sockaddr_in sin1 = *sin0, fsin;
255 fd_set afds, rfds;
256 pid_t pid;
257 int sfd, nfds, cc, fd;
plars865695b2001-08-27 22:15:12 +0000258
259 sfd = socket(PF_INET, SOCK_STREAM, 0);
260 if (sfd < 0) {
261 tst_brkm(TBROK, cleanup, "server socket failed: %s",
262 strerror(errno));
263 return -1;
264 }
plarse12303f2003-01-28 17:20:24 +0000265 if (bind(sfd, (struct sockaddr *)&sin1, sizeof(sin1)) < 0) {
plars865695b2001-08-27 22:15:12 +0000266 tst_brkm(TBROK, cleanup, "server bind failed: %s",
267 strerror(errno));
268 return -1;
269 }
270 if (listen(sfd, 10) < 0) {
271 tst_brkm(TBROK, cleanup, "server listen failed: %s",
272 strerror(errno));
273 return -1;
274 }
275 switch ((pid = fork())) {
276 case 0: /* child */
277 break;
278 case -1:
279 tst_brkm(TBROK, cleanup, "server fork failed: %s",
280 strerror(errno));
281 /* fall through */
282 default: /* parent */
283 (void) close(sfd);
284 return pid;
285 }
286
287 FD_ZERO(&afds);
288 FD_SET(sfd, &afds);
289
290 nfds = getdtablesize();
291
292 /* accept connections until killed */
293 while (1) {
robbiew46faba62003-04-29 14:36:25 +0000294 socklen_t fromlen;
plars865695b2001-08-27 22:15:12 +0000295
296 memcpy(&rfds, &afds, sizeof(rfds));
297
298 if (select(nfds, &rfds, (fd_set *)0, (fd_set *)0,
299 (struct timeval *)0) < 0)
300 if (errno != EINTR)
301 exit(1);
302 if (FD_ISSET(sfd, &rfds)) {
303 int newfd;
304
305 fromlen = sizeof(fsin);
plarse12303f2003-01-28 17:20:24 +0000306 newfd = accept(sfd, (struct sockaddr *)&fsin, &fromlen);
plars865695b2001-08-27 22:15:12 +0000307 if (newfd >= 0)
308 FD_SET(newfd, &afds);
309 /* send something back */
310 (void) write(newfd, "hoser\n", 6);
311 }
312 for (fd=0; fd<nfds; ++fd)
313 if (fd != sfd && FD_ISSET(fd, &rfds)) {
314 cc = read(fd, buf, sizeof(buf));
315 if (cc == 0 || (cc < 0 && errno != EINTR)) {
316 (void) close(fd);
317 FD_CLR(fd, &afds);
318 }
319 }
320 }
321}
322