blob: c74eeec36cc3fc33d69b3cb3a07ad938ad9798b2 [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
Wanlong Gao4548c6c2012-10-19 18:03:36 +080017 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
plars865695b2001-08-27 22:15:12 +000018 */
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"
plars865695b2001-08-27 22:15:12 +000056
Cyril Hrubisfdce7d52013-04-04 18:35:48 +020057char *TCID = "recvfrom01";
plars865695b2001-08-27 22:15:12 +000058int testno;
59
subrata_modak56207ce2009-03-23 13:35:39 +000060char buf[1024];
61int s; /* socket descriptor */
plars865695b2001-08-27 22:15:12 +000062struct sockaddr_in sin1, from;
subrata_modak56207ce2009-03-23 13:35:39 +000063static int sfd; /* shared between do_child and start_server */
64socklen_t fromlen;
plars865695b2001-08-27 22:15:12 +000065
robbiewd34d5812005-07-11 22:28:09 +000066void do_child(void);
plarse12303f2003-01-28 17:20:24 +000067void setup(void);
68void setup0(void);
69void setup1(void);
70void setup2(void);
71void cleanup(void);
72void cleanup0(void);
73void cleanup1(void);
74pid_t start_server(struct sockaddr_in *);
plars865695b2001-08-27 22:15:12 +000075
76struct test_case_t { /* test case structure */
subrata_modak56207ce2009-03-23 13:35:39 +000077 int domain; /* PF_INET, PF_UNIX, ... */
78 int type; /* SOCK_STREAM, SOCK_DGRAM ... */
79 int proto; /* protocol number (usually 0 = default) */
80 void *buf; /* recv data buffer */
81 size_t buflen; /* recv's 3rd argument */
82 unsigned flags; /* recv's 4th argument */
plars865695b2001-08-27 22:15:12 +000083 struct sockaddr *from; /* from address */
robbiew46faba62003-04-29 14:36:25 +000084 socklen_t *salen; /* from address value/result buffer length */
subrata_modak56207ce2009-03-23 13:35:39 +000085 int retval; /* syscall return value */
86 int experrno; /* expected errno */
87 void (*setup) (void);
88 void (*cleanup) (void);
plars865695b2001-08-27 22:15:12 +000089 char *desc;
90} tdat[] = {
plarse12303f2003-01-28 17:20:24 +000091/* 1 */
subrata_modak56207ce2009-03-23 13:35:39 +000092 {
93 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 */
subrata_modak56207ce2009-03-23 13:35:39 +000097 {
98 0, 0, 0, buf, sizeof(buf), 0, (struct sockaddr *)&from,
99 &fromlen, -1, ENOTSOCK, setup0, cleanup0, "invalid socket"},
plarse12303f2003-01-28 17:20:24 +0000100/* 3 */
subrata_modak56207ce2009-03-23 13:35:39 +0000101 {
102 PF_INET, SOCK_STREAM, 0, (void *)buf, sizeof(buf), 0,
103 (struct sockaddr *)-1, &fromlen,
104 0, ENOTSOCK, setup1, cleanup1, "invalid socket buffer"},
plarse12303f2003-01-28 17:20:24 +0000105/* 4 */
subrata_modak56207ce2009-03-23 13:35:39 +0000106 {
Chuck Ebbert20a99d72014-09-25 06:58:38 -0500107 PF_INET, SOCK_STREAM, 0, (void *)buf, sizeof(buf), 0,
subrata_modak56207ce2009-03-23 13:35:39 +0000108 (struct sockaddr *)&from, &fromlen,
Chuck Ebbert20a99d72014-09-25 06:58:38 -0500109 -1, EINVAL, setup2, cleanup1, "invalid socket addr length"},
plarse12303f2003-01-28 17:20:24 +0000110/* 5 */
subrata_modak56207ce2009-03-23 13:35:39 +0000111 {
112 PF_INET, SOCK_STREAM, 0, (void *)-1, sizeof(buf), 0,
113 (struct sockaddr *)&from, &fromlen,
114 -1, EFAULT, setup1, cleanup1, "invalid recv buffer"},
plarse12303f2003-01-28 17:20:24 +0000115/* 6 */
subrata_modak56207ce2009-03-23 13:35:39 +0000116 {
Chuck Ebbert1153a842014-10-01 17:10:32 -0500117 PF_INET, SOCK_STREAM, 0, (void *)buf, sizeof(buf), MSG_OOB,
subrata_modak56207ce2009-03-23 13:35:39 +0000118 (struct sockaddr *)&from, &fromlen,
Chuck Ebbert1153a842014-10-01 17:10:32 -0500119 -1, EINVAL, setup1, cleanup1, "invalid MSG_OOB flag set"},
120/* 7 */
121 {
122 PF_INET, SOCK_STREAM, 0, (void *)buf, sizeof(buf), MSG_ERRQUEUE,
123 (struct sockaddr *)&from, &fromlen,
124 -1, EAGAIN, setup1, cleanup1, "invalid MSG_ERRQUEUE flag set"},};
plars865695b2001-08-27 22:15:12 +0000125
Cyril Hrubisfdce7d52013-04-04 18:35:48 +0200126int TST_TOTAL = sizeof(tdat) / sizeof(tdat[0]);
plars865695b2001-08-27 22:15:12 +0000127
robbiewd34d5812005-07-11 22:28:09 +0000128#ifdef UCLINUX
129static char *argv0;
130#endif
131
subrata_modak56207ce2009-03-23 13:35:39 +0000132int main(int argc, char *argv[])
plars865695b2001-08-27 22:15:12 +0000133{
Cyril Hrubis89af32a2012-10-24 16:39:11 +0200134 int lc;
Cyril Hrubis0b9589f2014-05-27 17:40:33 +0200135 const char *msg;
plars865695b2001-08-27 22:15:12 +0000136
Garrett Coopera9e49f12010-12-16 10:54:03 -0800137 if ((msg = parse_opts(argc, argv, NULL, NULL)) != NULL)
Garrett Cooper60fa8012010-11-22 13:50:58 -0800138 tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg);
Garrett Coopera9e49f12010-12-16 10:54:03 -0800139
robbiewd34d5812005-07-11 22:28:09 +0000140#ifdef UCLINUX
141 argv0 = argv[0];
142 maybe_run_child(&do_child, "d", &sfd);
143#endif
144
plars865695b2001-08-27 22:15:12 +0000145 setup();
146
plars865695b2001-08-27 22:15:12 +0000147 for (lc = 0; TEST_LOOPING(lc); ++lc) {
Caspar Zhangd59a6592013-03-07 14:59:12 +0800148 tst_count = 0;
subrata_modak56207ce2009-03-23 13:35:39 +0000149 for (testno = 0; testno < TST_TOTAL; ++testno) {
Jan Stanceke5fd5122015-01-10 11:08:03 +0100150 if ((tst_kvercmp(3, 17, 0) < 0)
151 && (tdat[testno].flags & MSG_ERRQUEUE)
152 && (tdat[testno].type & SOCK_STREAM)) {
153 tst_resm(TCONF, "skip MSG_ERRQUEUE test, "
154 "it's supported from 3.17");
155 continue;
156 }
plars865695b2001-08-27 22:15:12 +0000157
Jan Stanceke5fd5122015-01-10 11:08:03 +0100158 tdat[testno].setup();
plars865695b2001-08-27 22:15:12 +0000159 TEST(recvfrom(s, tdat[testno].buf, tdat[testno].buflen,
subrata_modak56207ce2009-03-23 13:35:39 +0000160 tdat[testno].flags, tdat[testno].from,
161 tdat[testno].salen));
plars865695b2001-08-27 22:15:12 +0000162 if (TEST_RETURN >= 0)
subrata_modak56207ce2009-03-23 13:35:39 +0000163 TEST_RETURN = 0; /* all nonzero equal here */
plars865695b2001-08-27 22:15:12 +0000164 if (TEST_RETURN != tdat[testno].retval ||
165 (TEST_RETURN < 0 &&
166 TEST_ERRNO != tdat[testno].experrno)) {
167 tst_resm(TFAIL, "%s ; returned"
vapier8447d112009-08-28 13:40:32 +0000168 " %ld (expected %d), errno %d (expected"
subrata_modak56207ce2009-03-23 13:35:39 +0000169 " %d)", tdat[testno].desc,
170 TEST_RETURN, tdat[testno].retval,
171 TEST_ERRNO, tdat[testno].experrno);
plars865695b2001-08-27 22:15:12 +0000172 } else {
plars865695b2001-08-27 22:15:12 +0000173 tst_resm(TPASS, "%s successful",
subrata_modak56207ce2009-03-23 13:35:39 +0000174 tdat[testno].desc);
plars865695b2001-08-27 22:15:12 +0000175 }
176 tdat[testno].cleanup();
177 }
178 }
179 cleanup();
Garrett Cooper2c282152010-12-16 00:55:50 -0800180
181 tst_exit();
182}
plars865695b2001-08-27 22:15:12 +0000183
184pid_t pid;
185
subrata_modak56207ce2009-03-23 13:35:39 +0000186void setup(void)
plars865695b2001-08-27 22:15:12 +0000187{
Cyril Hrubisfdce7d52013-04-04 18:35:48 +0200188 TEST_PAUSE;
plars865695b2001-08-27 22:15:12 +0000189
plars865695b2001-08-27 22:15:12 +0000190 pid = start_server(&sin1);
191}
192
subrata_modak56207ce2009-03-23 13:35:39 +0000193void cleanup(void)
plars865695b2001-08-27 22:15:12 +0000194{
Cyril Hrubis605fa332015-02-04 13:11:20 +0100195 (void)kill(pid, SIGKILL);
Garrett Cooper2c282152010-12-16 00:55:50 -0800196
plars865695b2001-08-27 22:15:12 +0000197}
198
subrata_modak56207ce2009-03-23 13:35:39 +0000199void setup0(void)
plars865695b2001-08-27 22:15:12 +0000200{
201 if (tdat[testno].experrno == EBADF)
202 s = 400; /* anything not an open file */
subrata_modak56207ce2009-03-23 13:35:39 +0000203 else if ((s = open("/dev/null", O_WRONLY)) == -1)
Wanlong Gao354ebb42012-12-07 10:10:04 +0800204 tst_brkm(TBROK | TERRNO, cleanup, "open(/dev/null) failed");
plars865695b2001-08-27 22:15:12 +0000205 fromlen = sizeof(from);
206}
207
subrata_modak56207ce2009-03-23 13:35:39 +0000208void cleanup0(void)
plars865695b2001-08-27 22:15:12 +0000209{
210 s = -1;
211}
212
subrata_modak56207ce2009-03-23 13:35:39 +0000213void setup1(void)
plars865695b2001-08-27 22:15:12 +0000214{
subrata_modak56207ce2009-03-23 13:35:39 +0000215 fd_set rdfds;
216 struct timeval timeout;
217 int n;
subrata_modak4bb656a2009-02-26 12:02:09 +0000218
plars865695b2001-08-27 22:15:12 +0000219 s = socket(tdat[testno].domain, tdat[testno].type, tdat[testno].proto);
vapier8447d112009-08-28 13:40:32 +0000220 if (s < 0)
Wanlong Gao354ebb42012-12-07 10:10:04 +0800221 tst_brkm(TBROK | TERRNO, cleanup, "socket() failed");
plars865695b2001-08-27 22:15:12 +0000222 if (tdat[testno].type == SOCK_STREAM &&
plarse12303f2003-01-28 17:20:24 +0000223 connect(s, (struct sockaddr *)&sin1, sizeof(sin1)) < 0) {
Wanlong Gao354ebb42012-12-07 10:10:04 +0800224 tst_brkm(TBROK | TERRNO, cleanup, "connect failed");
plars865695b2001-08-27 22:15:12 +0000225 }
subrata_modak56207ce2009-03-23 13:35:39 +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,
234 "client setup1 failed - no message ready in 2 sec");
plars865695b2001-08-27 22:15:12 +0000235 fromlen = sizeof(from);
236}
237
subrata_modak56207ce2009-03-23 13:35:39 +0000238void setup2(void)
plars865695b2001-08-27 22:15:12 +0000239{
240 setup1();
241 fromlen = -1;
242}
243
subrata_modak56207ce2009-03-23 13:35:39 +0000244void cleanup1(void)
plars865695b2001-08-27 22:15:12 +0000245{
subrata_modak56207ce2009-03-23 13:35:39 +0000246 (void)close(s);
plars865695b2001-08-27 22:15:12 +0000247 s = -1;
248}
249
subrata_modak56207ce2009-03-23 13:35:39 +0000250pid_t start_server(struct sockaddr_in *sin0)
plars865695b2001-08-27 22:15:12 +0000251{
subrata_modak56207ce2009-03-23 13:35:39 +0000252 pid_t pid;
Jan Stancek6e4e77a2014-03-07 11:39:56 +0100253 socklen_t slen = sizeof(*sin0);
254
255 sin0->sin_family = AF_INET;
256 sin0->sin_port = 0; /* pick random free port */
257 sin0->sin_addr.s_addr = INADDR_ANY;
plars865695b2001-08-27 22:15:12 +0000258
259 sfd = socket(PF_INET, SOCK_STREAM, 0);
260 if (sfd < 0) {
Wanlong Gao354ebb42012-12-07 10:10:04 +0800261 tst_brkm(TBROK | TERRNO, cleanup, "server socket failed");
plars865695b2001-08-27 22:15:12 +0000262 return -1;
263 }
Jan Stancek6e4e77a2014-03-07 11:39:56 +0100264 if (bind(sfd, (struct sockaddr *)sin0, sizeof(*sin0)) < 0) {
Wanlong Gao354ebb42012-12-07 10:10:04 +0800265 tst_brkm(TBROK | TERRNO, cleanup, "server bind failed");
plars865695b2001-08-27 22:15:12 +0000266 return -1;
267 }
268 if (listen(sfd, 10) < 0) {
Wanlong Gao354ebb42012-12-07 10:10:04 +0800269 tst_brkm(TBROK | TERRNO, cleanup, "server listen failed");
plars865695b2001-08-27 22:15:12 +0000270 return -1;
271 }
Jan Stancek6e4e77a2014-03-07 11:39:56 +0100272 if (getsockname(sfd, (struct sockaddr *)sin0, &slen) == -1)
273 tst_brkm(TBROK | TERRNO, cleanup, "getsockname failed");
274
vapierfed9da32006-02-19 09:25:08 +0000275 switch ((pid = FORK_OR_VFORK())) {
subrata_modak56207ce2009-03-23 13:35:39 +0000276 case 0: /* child */
robbiewd34d5812005-07-11 22:28:09 +0000277#ifdef UCLINUX
278 if (self_exec(argv0, "d", sfd) < 0) {
279 tst_brkm(TBROK, cleanup, "server self_exec failed");
280 }
281#else
282 do_child();
283#endif
plars865695b2001-08-27 22:15:12 +0000284 break;
285 case -1:
Wanlong Gao354ebb42012-12-07 10:10:04 +0800286 tst_brkm(TBROK | TERRNO, cleanup, "server fork failed");
plars865695b2001-08-27 22:15:12 +0000287 /* fall through */
subrata_modak56207ce2009-03-23 13:35:39 +0000288 default: /* parent */
289 (void)close(sfd);
plars865695b2001-08-27 22:15:12 +0000290 return pid;
291 }
292
Wanlong Gao354ebb42012-12-07 10:10:04 +0800293 exit(1);
robbiewd34d5812005-07-11 22:28:09 +0000294}
295
Mike Frysingerc57fba52014-04-09 18:56:30 -0400296void do_child(void)
robbiewd34d5812005-07-11 22:28:09 +0000297{
298 struct sockaddr_in fsin;
subrata_modak56207ce2009-03-23 13:35:39 +0000299 fd_set afds, rfds;
robbiewd34d5812005-07-11 22:28:09 +0000300 int nfds, cc, fd;
301
plars865695b2001-08-27 22:15:12 +0000302 FD_ZERO(&afds);
303 FD_SET(sfd, &afds);
304
Cyril Hrubis7855d092014-10-09 16:13:05 +0200305 nfds = sfd + 1;
plars865695b2001-08-27 22:15:12 +0000306
307 /* accept connections until killed */
308 while (1) {
robbiew46faba62003-04-29 14:36:25 +0000309 socklen_t fromlen;
plars865695b2001-08-27 22:15:12 +0000310
311 memcpy(&rfds, &afds, sizeof(rfds));
312
Cyril Hrubis4e2bab82014-09-24 16:34:35 +0200313 if (select(nfds, &rfds, NULL, NULL,
314 NULL) < 0)
plars865695b2001-08-27 22:15:12 +0000315 if (errno != EINTR)
316 exit(1);
317 if (FD_ISSET(sfd, &rfds)) {
318 int newfd;
319
320 fromlen = sizeof(fsin);
plarse12303f2003-01-28 17:20:24 +0000321 newfd = accept(sfd, (struct sockaddr *)&fsin, &fromlen);
Cyril Hrubis7855d092014-10-09 16:13:05 +0200322 if (newfd >= 0) {
plars865695b2001-08-27 22:15:12 +0000323 FD_SET(newfd, &afds);
Cyril Hrubis7855d092014-10-09 16:13:05 +0200324 nfds = MAX(nfds, newfd + 1);
325 /* send something back */
326 (void)write(newfd, "hoser\n", 6);
327 }
plars865695b2001-08-27 22:15:12 +0000328 }
subrata_modak56207ce2009-03-23 13:35:39 +0000329 for (fd = 0; fd < nfds; ++fd)
plars865695b2001-08-27 22:15:12 +0000330 if (fd != sfd && FD_ISSET(fd, &rfds)) {
331 cc = read(fd, buf, sizeof(buf));
332 if (cc == 0 || (cc < 0 && errno != EINTR)) {
subrata_modak56207ce2009-03-23 13:35:39 +0000333 (void)close(fd);
plars865695b2001-08-27 22:15:12 +0000334 FD_CLR(fd, &afds);
335 }
336 }
337 }
Chris Dearmanec6edca2012-10-17 19:54:01 -0700338}