blob: 86a0e2329a3fbeadd6e497b9eab2711c5301c342 [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: connect01
22 *
23 * Test Description:
24 * Verify that connect() returns the proper errno for various failure cases
25 *
26 * Usage: <for command-line>
27 * connect01 [-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>
plarsa9de6132002-03-26 19:36:37 +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 = "connect01";
plars865695b2001-08-27 22:15:12 +000058int testno;
59
subrata_modak56207ce2009-03-23 13:35:39 +000060int s, s2; /* socket descriptor */
plars865695b2001-08-27 22:15:12 +000061struct sockaddr_in sin1, sin2, sin3, sin4;
subrata_modak56207ce2009-03-23 13:35:39 +000062static int sfd; /* shared between start_server and do_child */
plars865695b2001-08-27 22:15:12 +000063
64void setup(void), setup0(void), setup1(void), setup2(void),
subrata_modak56207ce2009-03-23 13:35:39 +000065cleanup(void), cleanup0(void), cleanup1(void), do_child(void);
plars865695b2001-08-27 22:15:12 +000066
subrata_modak56207ce2009-03-23 13:35:39 +000067static pid_t start_server(struct sockaddr_in *);
robbiew2c945242002-11-11 19:01:25 +000068
plars865695b2001-08-27 22:15:12 +000069struct test_case_t { /* test case structure */
subrata_modak56207ce2009-03-23 13:35:39 +000070 int domain; /* PF_INET, PF_UNIX, ... */
71 int type; /* SOCK_STREAM, SOCK_DGRAM ... */
72 int proto; /* protocol number (usually 0 = default) */
plars865695b2001-08-27 22:15:12 +000073 struct sockaddr *sockaddr; /* socket address buffer */
subrata_modak56207ce2009-03-23 13:35:39 +000074 int salen; /* connect's 3rd argument */
75 int retval; /* syscall return value */
76 int experrno; /* expected errno */
77 void (*setup) (void);
78 void (*cleanup) (void);
plars865695b2001-08-27 22:15:12 +000079 char *desc;
80} tdat[] = {
subrata_modak56207ce2009-03-23 13:35:39 +000081 {
82 PF_INET, SOCK_STREAM, 0, (struct sockaddr *)&sin1,
83 sizeof(struct sockaddr_in), -1, EBADF, setup0,
84 cleanup0, "bad file descriptor"},
vapier7ec19d92006-02-27 04:38:56 +000085#ifndef UCLINUX
subrata_modak56207ce2009-03-23 13:35:39 +000086 /* Skip since uClinux does not implement memory protection */
87 {
88 PF_INET, SOCK_STREAM, 0, (struct sockaddr *)-1,
89 sizeof(struct sockaddr_in), -1, EFAULT, setup1,
90 cleanup1, "invalid socket buffer"},
vapier7ec19d92006-02-27 04:38:56 +000091#endif
subrata_modak56207ce2009-03-23 13:35:39 +000092 {
93 PF_INET, SOCK_STREAM, 0, (struct sockaddr *)&sin1,
94 3, -1, EINVAL, setup1, cleanup1, "invalid salen"}, {
95 0, 0, 0, (struct sockaddr *)&sin1,
96 sizeof(sin1), -1, ENOTSOCK, setup0, cleanup0,
97 "invalid socket"}
98 , {
99 PF_INET, SOCK_STREAM, 0, (struct sockaddr *)&sin1,
100 sizeof(sin1), -1, EISCONN, setup2, cleanup1,
101 "already connected"}
102 , {
103 PF_INET, SOCK_STREAM, 0, (struct sockaddr *)&sin2,
104 sizeof(sin2), -1, ECONNREFUSED, setup1, cleanup1,
105 "connection refused"}
106 , {
107 PF_INET, SOCK_STREAM, 0, (struct sockaddr *)&sin4,
108 sizeof(sin4), -1, EAFNOSUPPORT, setup1, cleanup1,
109 "invalid address family"}
110,};
111
Cyril Hrubisfdce7d52013-04-04 18:35:48 +0200112int TST_TOTAL = sizeof(tdat) / sizeof(tdat[0]);
subrata_modak56207ce2009-03-23 13:35:39 +0000113
robbiewd34d5812005-07-11 22:28:09 +0000114#ifdef UCLINUX
115static char *argv0;
116#endif
117
subrata_modak56207ce2009-03-23 13:35:39 +0000118int main(int argc, char *argv[])
plars865695b2001-08-27 22:15:12 +0000119{
Cyril Hrubis89af32a2012-10-24 16:39:11 +0200120 int lc;
Cyril Hrubis0b9589f2014-05-27 17:40:33 +0200121 const char *msg;
plars865695b2001-08-27 22:15:12 +0000122
Garrett Cooper45e285d2010-11-22 12:19:25 -0800123 msg = parse_opts(argc, argv, NULL, NULL);
124 if (msg != NULL) {
plars865695b2001-08-27 22:15:12 +0000125 tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg);
plars865695b2001-08-27 22:15:12 +0000126 }
robbiewd34d5812005-07-11 22:28:09 +0000127#ifdef UCLINUX
128 argv0 = argv[0];
129 maybe_run_child(&do_child, "d", &sfd);
130#endif
131
plars865695b2001-08-27 22:15:12 +0000132 setup();
133
plars865695b2001-08-27 22:15:12 +0000134 for (lc = 0; TEST_LOOPING(lc); ++lc) {
Caspar Zhangd59a6592013-03-07 14:59:12 +0800135 tst_count = 0;
subrata_modak56207ce2009-03-23 13:35:39 +0000136 for (testno = 0; testno < TST_TOTAL; ++testno) {
plars865695b2001-08-27 22:15:12 +0000137 tdat[testno].setup();
138
subrata_modak56207ce2009-03-23 13:35:39 +0000139 TEST(connect
140 (s, tdat[testno].sockaddr, tdat[testno].salen));
plars865695b2001-08-27 22:15:12 +0000141
142 if (TEST_RETURN != tdat[testno].retval ||
143 (TEST_RETURN < 0 &&
144 TEST_ERRNO != tdat[testno].experrno)) {
145 tst_resm(TFAIL, "%s ; returned"
vapier0874e6f2009-08-28 12:07:53 +0000146 " %ld (expected %d), errno %d (expected"
subrata_modak56207ce2009-03-23 13:35:39 +0000147 " %d)", tdat[testno].desc,
148 TEST_RETURN, tdat[testno].retval,
149 TEST_ERRNO, tdat[testno].experrno);
plars865695b2001-08-27 22:15:12 +0000150 } else {
151 tst_resm(TPASS, "%s successful",
subrata_modak56207ce2009-03-23 13:35:39 +0000152 tdat[testno].desc);
plars865695b2001-08-27 22:15:12 +0000153 }
154 tdat[testno].cleanup();
155 }
156 }
157 cleanup();
robbiew2c945242002-11-11 19:01:25 +0000158
Garrett Cooper2c282152010-12-16 00:55:50 -0800159 tst_exit();
Wanlong Gao354ebb42012-12-07 10:10:04 +0800160}
plars865695b2001-08-27 22:15:12 +0000161
162pid_t pid;
163
subrata_modak56207ce2009-03-23 13:35:39 +0000164void setup(void)
plars865695b2001-08-27 22:15:12 +0000165{
subrata_modak56207ce2009-03-23 13:35:39 +0000166 TEST_PAUSE; /* if -p option specified */
plars865695b2001-08-27 22:15:12 +0000167
plars865695b2001-08-27 22:15:12 +0000168 pid = start_server(&sin1);
169
170 sin2.sin_family = AF_INET;
subrata_modak56207ce2009-03-23 13:35:39 +0000171 /* this port must be unused! */
Jan Stancek6e4e77a2014-03-07 11:39:56 +0100172 sin2.sin_port = tst_get_unused_port(NULL, AF_INET, SOCK_STREAM);
plars865695b2001-08-27 22:15:12 +0000173 sin2.sin_addr.s_addr = INADDR_ANY;
174
175 sin3.sin_family = AF_INET;
176 sin3.sin_port = 0;
subrata_modak56207ce2009-03-23 13:35:39 +0000177 /* assumes no route to this network! */
plars865695b2001-08-27 22:15:12 +0000178 sin3.sin_addr.s_addr = htonl(0x0AFFFEFD);
179
180 sin4.sin_family = 47; /* bogus address family */
181 sin4.sin_port = 0;
182 sin4.sin_addr.s_addr = htonl(0x0AFFFEFD);
183
184}
185
subrata_modak56207ce2009-03-23 13:35:39 +0000186void cleanup(void)
plars865695b2001-08-27 22:15:12 +0000187{
Cyril Hrubis605fa332015-02-04 13:11:20 +0100188 (void)kill(pid, SIGKILL);
Garrett Cooper2c282152010-12-16 00:55:50 -0800189
plars865695b2001-08-27 22:15:12 +0000190}
191
subrata_modak56207ce2009-03-23 13:35:39 +0000192void setup0(void)
plars865695b2001-08-27 22:15:12 +0000193{
194 if (tdat[testno].experrno == EBADF)
195 s = 400; /* anything not an open file */
subrata_modak56207ce2009-03-23 13:35:39 +0000196 else if ((s = open("/dev/null", O_WRONLY)) == -1)
Wanlong Gao354ebb42012-12-07 10:10:04 +0800197 tst_brkm(TBROK | TERRNO, cleanup, "open(/dev/null) failed");
plarsa9de6132002-03-26 19:36:37 +0000198
plars865695b2001-08-27 22:15:12 +0000199}
200
subrata_modak56207ce2009-03-23 13:35:39 +0000201void cleanup0(void)
plars865695b2001-08-27 22:15:12 +0000202{
Jan Stancekb3e86e42014-03-06 12:10:07 +0100203 close(s);
plars865695b2001-08-27 22:15:12 +0000204 s = -1;
205}
206
subrata_modak56207ce2009-03-23 13:35:39 +0000207void setup1(void)
plars865695b2001-08-27 22:15:12 +0000208{
209 s = socket(tdat[testno].domain, tdat[testno].type, tdat[testno].proto);
vapier0874e6f2009-08-28 12:07:53 +0000210 if (s < 0)
Wanlong Gao354ebb42012-12-07 10:10:04 +0800211 tst_brkm(TBROK | TERRNO, cleanup, "socket() failed");
plars865695b2001-08-27 22:15:12 +0000212}
213
subrata_modak56207ce2009-03-23 13:35:39 +0000214void cleanup1(void)
plars865695b2001-08-27 22:15:12 +0000215{
subrata_modak56207ce2009-03-23 13:35:39 +0000216 (void)close(s);
plars865695b2001-08-27 22:15:12 +0000217 s = -1;
218}
219
subrata_modak56207ce2009-03-23 13:35:39 +0000220void setup2(void)
plars865695b2001-08-27 22:15:12 +0000221{
subrata_modak56207ce2009-03-23 13:35:39 +0000222 setup1(); /* get a socket in s */
vapier0874e6f2009-08-28 12:07:53 +0000223 if (connect(s, (const struct sockaddr *)&sin1, sizeof(sin1)) < 0)
Wanlong Gao354ebb42012-12-07 10:10:04 +0800224 tst_brkm(TBROK | TERRNO, cleanup,
225 "socket setup failed connect test %d", testno);
plars865695b2001-08-27 22:15:12 +0000226}
227
subrata_modak56207ce2009-03-23 13:35:39 +0000228pid_t start_server(struct sockaddr_in *sin0)
plars865695b2001-08-27 22:15:12 +0000229{
subrata_modak56207ce2009-03-23 13:35:39 +0000230 pid_t pid;
Jan Stancek6e4e77a2014-03-07 11:39:56 +0100231 socklen_t slen = sizeof(*sin0);
232
233 sin0->sin_family = AF_INET;
234 sin0->sin_port = 0; /* pick random free port */
235 sin0->sin_addr.s_addr = INADDR_ANY;
plars865695b2001-08-27 22:15:12 +0000236
237 sfd = socket(PF_INET, SOCK_STREAM, 0);
238 if (sfd < 0) {
Wanlong Gao354ebb42012-12-07 10:10:04 +0800239 tst_brkm(TBROK | TERRNO, cleanup, "server socket failed");
plars865695b2001-08-27 22:15:12 +0000240 return -1;
241 }
Jan Stancek6e4e77a2014-03-07 11:39:56 +0100242 if (bind(sfd, (struct sockaddr *)sin0, sizeof(*sin0)) < 0) {
Wanlong Gao354ebb42012-12-07 10:10:04 +0800243 tst_brkm(TBROK | TERRNO, cleanup, "server bind failed");
plars865695b2001-08-27 22:15:12 +0000244 return -1;
245 }
246 if (listen(sfd, 10) < 0) {
Wanlong Gao354ebb42012-12-07 10:10:04 +0800247 tst_brkm(TBROK | TERRNO, cleanup, "server listen failed");
plars865695b2001-08-27 22:15:12 +0000248 return -1;
249 }
Jan Stancek6e4e77a2014-03-07 11:39:56 +0100250 if (getsockname(sfd, (struct sockaddr *)sin0, &slen) == -1)
251 tst_brkm(TBROK | TERRNO, cleanup, "getsockname failed");
252
robbiewd34d5812005-07-11 22:28:09 +0000253 switch ((pid = FORK_OR_VFORK())) {
subrata_modak56207ce2009-03-23 13:35:39 +0000254 case 0: /* child */
robbiewd34d5812005-07-11 22:28:09 +0000255#ifdef UCLINUX
256 self_exec(argv0, "d", sfd);
257#else
258 do_child();
259#endif
plars865695b2001-08-27 22:15:12 +0000260 break;
261 case -1:
Wanlong Gao354ebb42012-12-07 10:10:04 +0800262 tst_brkm(TBROK | TERRNO, cleanup, "server fork failed");
plars865695b2001-08-27 22:15:12 +0000263 /* fall through */
subrata_modak56207ce2009-03-23 13:35:39 +0000264 default: /* parent */
265 (void)close(sfd);
plars865695b2001-08-27 22:15:12 +0000266 return pid;
267 }
268
robbiewd34d5812005-07-11 22:28:09 +0000269 return -1;
270}
271
Jan Stancekb3e86e42014-03-06 12:10:07 +0100272void do_child(void)
robbiewd34d5812005-07-11 22:28:09 +0000273{
274 struct sockaddr_in fsin;
subrata_modak56207ce2009-03-23 13:35:39 +0000275 fd_set afds, rfds;
276 int nfds, cc, fd;
277 char c;
robbiewd34d5812005-07-11 22:28:09 +0000278
plars865695b2001-08-27 22:15:12 +0000279 FD_ZERO(&afds);
280 FD_SET(sfd, &afds);
281
Cyril Hrubis7855d092014-10-09 16:13:05 +0200282 nfds = sfd + 1;
plars865695b2001-08-27 22:15:12 +0000283
284 /* accept connections until killed */
285 while (1) {
subrata_modak56207ce2009-03-23 13:35:39 +0000286 socklen_t fromlen;
plars865695b2001-08-27 22:15:12 +0000287
288 memcpy(&rfds, &afds, sizeof(rfds));
289
Cyril Hrubis4e2bab82014-09-24 16:34:35 +0200290 if (select(nfds, &rfds, NULL, NULL,
291 NULL) < 0)
plars865695b2001-08-27 22:15:12 +0000292 if (errno != EINTR)
293 exit(1);
294 if (FD_ISSET(sfd, &rfds)) {
295 int newfd;
296
297 fromlen = sizeof(fsin);
subrata_modak56207ce2009-03-23 13:35:39 +0000298 newfd = accept(sfd, (struct sockaddr *)&fsin, &fromlen);
Cyril Hrubis7855d092014-10-09 16:13:05 +0200299 if (newfd >= 0) {
plars865695b2001-08-27 22:15:12 +0000300 FD_SET(newfd, &afds);
Cyril Hrubis7855d092014-10-09 16:13:05 +0200301 nfds = MAX(nfds, newfd + 1);
302 }
plars865695b2001-08-27 22:15:12 +0000303 }
subrata_modak56207ce2009-03-23 13:35:39 +0000304 for (fd = 0; fd < nfds; ++fd)
plars865695b2001-08-27 22:15:12 +0000305 if (fd != sfd && FD_ISSET(fd, &rfds)) {
subrata_modak56207ce2009-03-23 13:35:39 +0000306 if ((cc = read(fd, &c, 1)) == 0) {
307 (void)close(fd);
plars865695b2001-08-27 22:15:12 +0000308 FD_CLR(fd, &afds);
309 }
310 }
311 }
Chris Dearmanec6edca2012-10-17 19:54:01 -0700312}