1f08c3bdfSopenharmony_ci/*
2f08c3bdfSopenharmony_ci *
3f08c3bdfSopenharmony_ci *   Copyright (c) International Business Machines  Corp., 2001
4f08c3bdfSopenharmony_ci *
5f08c3bdfSopenharmony_ci *   This program is free software;  you can redistribute it and/or modify
6f08c3bdfSopenharmony_ci *   it under the terms of the GNU General Public License as published by
7f08c3bdfSopenharmony_ci *   the Free Software Foundation; either version 2 of the License, or
8f08c3bdfSopenharmony_ci *   (at your option) any later version.
9f08c3bdfSopenharmony_ci *
10f08c3bdfSopenharmony_ci *   This program is distributed in the hope that it will be useful,
11f08c3bdfSopenharmony_ci *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
12f08c3bdfSopenharmony_ci *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
13f08c3bdfSopenharmony_ci *   the GNU General Public License for more details.
14f08c3bdfSopenharmony_ci *
15f08c3bdfSopenharmony_ci *   You should have received a copy of the GNU General Public License
16f08c3bdfSopenharmony_ci *   along with this program;  if not, write to the Free Software
17f08c3bdfSopenharmony_ci *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18f08c3bdfSopenharmony_ci */
19f08c3bdfSopenharmony_ci
20f08c3bdfSopenharmony_ci/*
21f08c3bdfSopenharmony_ci * Test Name: connect01
22f08c3bdfSopenharmony_ci *
23f08c3bdfSopenharmony_ci * Test Description:
24f08c3bdfSopenharmony_ci *  Verify that connect() returns the proper errno for various failure cases
25f08c3bdfSopenharmony_ci *
26f08c3bdfSopenharmony_ci * Usage:  <for command-line>
27f08c3bdfSopenharmony_ci *  connect01 [-c n] [-e] [-i n] [-I x] [-P x] [-t]
28f08c3bdfSopenharmony_ci *     where,  -c n : Run n copies concurrently.
29f08c3bdfSopenharmony_ci *             -e   : Turn on errno logging.
30f08c3bdfSopenharmony_ci *	       -i n : Execute test n times.
31f08c3bdfSopenharmony_ci *	       -I x : Execute test for x seconds.
32f08c3bdfSopenharmony_ci *	       -P x : Pause for x seconds between iterations.
33f08c3bdfSopenharmony_ci *	       -t   : Turn on syscall timing.
34f08c3bdfSopenharmony_ci *
35f08c3bdfSopenharmony_ci * HISTORY
36f08c3bdfSopenharmony_ci *	07/2001 Ported by Wayne Boyer
37f08c3bdfSopenharmony_ci *
38f08c3bdfSopenharmony_ci * RESTRICTIONS:
39f08c3bdfSopenharmony_ci *  None.
40f08c3bdfSopenharmony_ci *
41f08c3bdfSopenharmony_ci */
42f08c3bdfSopenharmony_ci
43f08c3bdfSopenharmony_ci#include <stdio.h>
44f08c3bdfSopenharmony_ci#include <unistd.h>
45f08c3bdfSopenharmony_ci#include <errno.h>
46f08c3bdfSopenharmony_ci#include <fcntl.h>
47f08c3bdfSopenharmony_ci
48f08c3bdfSopenharmony_ci#include <sys/types.h>
49f08c3bdfSopenharmony_ci#include <sys/socket.h>
50f08c3bdfSopenharmony_ci#include <sys/signal.h>
51f08c3bdfSopenharmony_ci#include <sys/un.h>
52f08c3bdfSopenharmony_ci
53f08c3bdfSopenharmony_ci#include <netinet/in.h>
54f08c3bdfSopenharmony_ci
55f08c3bdfSopenharmony_ci#include "test.h"
56f08c3bdfSopenharmony_ci#include "safe_macros.h"
57f08c3bdfSopenharmony_ci
58f08c3bdfSopenharmony_cichar *TCID = "connect01";
59f08c3bdfSopenharmony_ciint testno;
60f08c3bdfSopenharmony_ci
61f08c3bdfSopenharmony_ciint s, s2;			/* socket descriptor */
62f08c3bdfSopenharmony_cistruct sockaddr_in sin1, sin2, sin3, sin4;
63f08c3bdfSopenharmony_cistatic int sfd;			/* shared between start_server and do_child */
64f08c3bdfSopenharmony_ci
65f08c3bdfSopenharmony_civoid setup(void), setup0(void), setup1(void), setup2(void),
66f08c3bdfSopenharmony_cicleanup(void), cleanup0(void), cleanup1(void), do_child(void);
67f08c3bdfSopenharmony_ci
68f08c3bdfSopenharmony_cistatic pid_t start_server(struct sockaddr_in *);
69f08c3bdfSopenharmony_ci
70f08c3bdfSopenharmony_cistruct test_case_t {		/* test case structure */
71f08c3bdfSopenharmony_ci	int domain;		/* PF_INET, PF_UNIX, ... */
72f08c3bdfSopenharmony_ci	int type;		/* SOCK_STREAM, SOCK_DGRAM ... */
73f08c3bdfSopenharmony_ci	int proto;		/* protocol number (usually 0 = default) */
74f08c3bdfSopenharmony_ci	struct sockaddr *sockaddr;	/* socket address buffer */
75f08c3bdfSopenharmony_ci	int salen;		/* connect's 3rd argument */
76f08c3bdfSopenharmony_ci	int retval;		/* syscall return value */
77f08c3bdfSopenharmony_ci	int experrno;		/* expected errno */
78f08c3bdfSopenharmony_ci	void (*setup) (void);
79f08c3bdfSopenharmony_ci	void (*cleanup) (void);
80f08c3bdfSopenharmony_ci	char *desc;
81f08c3bdfSopenharmony_ci} tdat[] = {
82f08c3bdfSopenharmony_ci	{
83f08c3bdfSopenharmony_ci	PF_INET, SOCK_STREAM, 0, (struct sockaddr *)&sin1,
84f08c3bdfSopenharmony_ci		    sizeof(struct sockaddr_in), -1, EBADF, setup0,
85f08c3bdfSopenharmony_ci		    cleanup0, "bad file descriptor"},
86f08c3bdfSopenharmony_ci#ifndef UCLINUX
87f08c3bdfSopenharmony_ci	    /* Skip since uClinux does not implement memory protection */
88f08c3bdfSopenharmony_ci	{
89f08c3bdfSopenharmony_ci	PF_INET, SOCK_STREAM, 0, (struct sockaddr *)-1,
90f08c3bdfSopenharmony_ci		    sizeof(struct sockaddr_in), -1, EFAULT, setup1,
91f08c3bdfSopenharmony_ci		    cleanup1, "invalid socket buffer"},
92f08c3bdfSopenharmony_ci#endif
93f08c3bdfSopenharmony_ci	{
94f08c3bdfSopenharmony_ci	PF_INET, SOCK_STREAM, 0, (struct sockaddr *)&sin1,
95f08c3bdfSopenharmony_ci		    3, -1, EINVAL, setup1, cleanup1, "invalid salen"}, {
96f08c3bdfSopenharmony_ci	0, 0, 0, (struct sockaddr *)&sin1,
97f08c3bdfSopenharmony_ci		    sizeof(sin1), -1, ENOTSOCK, setup0, cleanup0,
98f08c3bdfSopenharmony_ci		    "invalid socket"}
99f08c3bdfSopenharmony_ci	, {
100f08c3bdfSopenharmony_ci	PF_INET, SOCK_STREAM, 0, (struct sockaddr *)&sin1,
101f08c3bdfSopenharmony_ci		    sizeof(sin1), -1, EISCONN, setup2, cleanup1,
102f08c3bdfSopenharmony_ci		    "already connected"}
103f08c3bdfSopenharmony_ci	, {
104f08c3bdfSopenharmony_ci	PF_INET, SOCK_STREAM, 0, (struct sockaddr *)&sin2,
105f08c3bdfSopenharmony_ci		    sizeof(sin2), -1, ECONNREFUSED, setup1, cleanup1,
106f08c3bdfSopenharmony_ci		    "connection refused"}
107f08c3bdfSopenharmony_ci	, {
108f08c3bdfSopenharmony_ci	PF_INET, SOCK_STREAM, 0, (struct sockaddr *)&sin4,
109f08c3bdfSopenharmony_ci		    sizeof(sin4), -1, EAFNOSUPPORT, setup1, cleanup1,
110f08c3bdfSopenharmony_ci		    "invalid address family"}
111f08c3bdfSopenharmony_ci,};
112f08c3bdfSopenharmony_ci
113f08c3bdfSopenharmony_ciint TST_TOTAL = sizeof(tdat) / sizeof(tdat[0]);
114f08c3bdfSopenharmony_ci
115f08c3bdfSopenharmony_ci#ifdef UCLINUX
116f08c3bdfSopenharmony_cistatic char *argv0;
117f08c3bdfSopenharmony_ci#endif
118f08c3bdfSopenharmony_ci
119f08c3bdfSopenharmony_ci/**
120f08c3bdfSopenharmony_ci * bionic's connect() implementation calls netdClientInitConnect() before
121f08c3bdfSopenharmony_ci * sending the request to the kernel.  We need to bypass this, or the test will
122f08c3bdfSopenharmony_ci * segfault during the addr = (struct sockaddr *)-1 testcase. We had cases where
123f08c3bdfSopenharmony_ci * tests started to segfault on glibc upgrade or in special conditions where
124f08c3bdfSopenharmony_ci * libc had to convert structure layouts between 32bit/64bit userspace/kernel =>
125f08c3bdfSopenharmony_ci * safer to call the raw syscall regardless of the libc implementation.
126f08c3bdfSopenharmony_ci */
127f08c3bdfSopenharmony_ci#include "lapi/syscalls.h"
128f08c3bdfSopenharmony_ci
129f08c3bdfSopenharmony_cistatic int sys_connect(int sockfd, const struct sockaddr *addr,
130f08c3bdfSopenharmony_ci		socklen_t addrlen)
131f08c3bdfSopenharmony_ci{
132f08c3bdfSopenharmony_ci	return tst_syscall(__NR_connect, sockfd, addr, addrlen);
133f08c3bdfSopenharmony_ci}
134f08c3bdfSopenharmony_ci
135f08c3bdfSopenharmony_ci#define connect(sockfd, addr, addrlen) sys_connect(sockfd, addr, addrlen)
136f08c3bdfSopenharmony_ci
137f08c3bdfSopenharmony_ciint main(int argc, char *argv[])
138f08c3bdfSopenharmony_ci{
139f08c3bdfSopenharmony_ci	int lc;
140f08c3bdfSopenharmony_ci
141f08c3bdfSopenharmony_ci	tst_parse_opts(argc, argv, NULL, NULL);
142f08c3bdfSopenharmony_ci#ifdef UCLINUX
143f08c3bdfSopenharmony_ci	argv0 = argv[0];
144f08c3bdfSopenharmony_ci	maybe_run_child(&do_child, "d", &sfd);
145f08c3bdfSopenharmony_ci#endif
146f08c3bdfSopenharmony_ci
147f08c3bdfSopenharmony_ci	setup();
148f08c3bdfSopenharmony_ci
149f08c3bdfSopenharmony_ci	for (lc = 0; TEST_LOOPING(lc); ++lc) {
150f08c3bdfSopenharmony_ci		tst_count = 0;
151f08c3bdfSopenharmony_ci		for (testno = 0; testno < TST_TOTAL; ++testno) {
152f08c3bdfSopenharmony_ci			tdat[testno].setup();
153f08c3bdfSopenharmony_ci
154f08c3bdfSopenharmony_ci			TEST(connect
155f08c3bdfSopenharmony_ci			     (s, tdat[testno].sockaddr, tdat[testno].salen));
156f08c3bdfSopenharmony_ci
157f08c3bdfSopenharmony_ci			if (TEST_RETURN != tdat[testno].retval ||
158f08c3bdfSopenharmony_ci			    (TEST_RETURN < 0 &&
159f08c3bdfSopenharmony_ci			     TEST_ERRNO != tdat[testno].experrno)) {
160f08c3bdfSopenharmony_ci				tst_resm(TFAIL, "%s ; returned"
161f08c3bdfSopenharmony_ci					 " %ld (expected %d), errno %d (expected"
162f08c3bdfSopenharmony_ci					 " %d)", tdat[testno].desc,
163f08c3bdfSopenharmony_ci					 TEST_RETURN, tdat[testno].retval,
164f08c3bdfSopenharmony_ci					 TEST_ERRNO, tdat[testno].experrno);
165f08c3bdfSopenharmony_ci			} else {
166f08c3bdfSopenharmony_ci				tst_resm(TPASS, "%s successful",
167f08c3bdfSopenharmony_ci					 tdat[testno].desc);
168f08c3bdfSopenharmony_ci			}
169f08c3bdfSopenharmony_ci			tdat[testno].cleanup();
170f08c3bdfSopenharmony_ci		}
171f08c3bdfSopenharmony_ci	}
172f08c3bdfSopenharmony_ci	cleanup();
173f08c3bdfSopenharmony_ci
174f08c3bdfSopenharmony_ci	tst_exit();
175f08c3bdfSopenharmony_ci}
176f08c3bdfSopenharmony_ci
177f08c3bdfSopenharmony_cipid_t pid;
178f08c3bdfSopenharmony_ci
179f08c3bdfSopenharmony_civoid setup(void)
180f08c3bdfSopenharmony_ci{
181f08c3bdfSopenharmony_ci	TEST_PAUSE;		/* if -p option specified */
182f08c3bdfSopenharmony_ci
183f08c3bdfSopenharmony_ci	pid = start_server(&sin1);
184f08c3bdfSopenharmony_ci
185f08c3bdfSopenharmony_ci	sin2.sin_family = AF_INET;
186f08c3bdfSopenharmony_ci	/* this port must be unused! */
187f08c3bdfSopenharmony_ci	sin2.sin_port = TST_GET_UNUSED_PORT(NULL, AF_INET, SOCK_STREAM);
188f08c3bdfSopenharmony_ci	sin2.sin_addr.s_addr = INADDR_ANY;
189f08c3bdfSopenharmony_ci
190f08c3bdfSopenharmony_ci	sin3.sin_family = AF_INET;
191f08c3bdfSopenharmony_ci	sin3.sin_port = 0;
192f08c3bdfSopenharmony_ci	/* assumes no route to this network! */
193f08c3bdfSopenharmony_ci	sin3.sin_addr.s_addr = htonl(0x0AFFFEFD);
194f08c3bdfSopenharmony_ci
195f08c3bdfSopenharmony_ci	sin4.sin_family = 47;	/* bogus address family */
196f08c3bdfSopenharmony_ci	sin4.sin_port = 0;
197f08c3bdfSopenharmony_ci	sin4.sin_addr.s_addr = htonl(0x0AFFFEFD);
198f08c3bdfSopenharmony_ci
199f08c3bdfSopenharmony_ci}
200f08c3bdfSopenharmony_ci
201f08c3bdfSopenharmony_civoid cleanup(void)
202f08c3bdfSopenharmony_ci{
203f08c3bdfSopenharmony_ci	(void)kill(pid, SIGKILL);
204f08c3bdfSopenharmony_ci
205f08c3bdfSopenharmony_ci}
206f08c3bdfSopenharmony_ci
207f08c3bdfSopenharmony_civoid setup0(void)
208f08c3bdfSopenharmony_ci{
209f08c3bdfSopenharmony_ci	if (tdat[testno].experrno == EBADF)
210f08c3bdfSopenharmony_ci		s = 400;	/* anything not an open file */
211f08c3bdfSopenharmony_ci	else if ((s = open("/dev/null", O_WRONLY)) == -1)
212f08c3bdfSopenharmony_ci		tst_brkm(TBROK | TERRNO, cleanup, "open(/dev/null) failed");
213f08c3bdfSopenharmony_ci
214f08c3bdfSopenharmony_ci}
215f08c3bdfSopenharmony_ci
216f08c3bdfSopenharmony_civoid cleanup0(void)
217f08c3bdfSopenharmony_ci{
218f08c3bdfSopenharmony_ci	close(s);
219f08c3bdfSopenharmony_ci	s = -1;
220f08c3bdfSopenharmony_ci}
221f08c3bdfSopenharmony_ci
222f08c3bdfSopenharmony_civoid setup1(void)
223f08c3bdfSopenharmony_ci{
224f08c3bdfSopenharmony_ci	s = SAFE_SOCKET(cleanup, tdat[testno].domain, tdat[testno].type,
225f08c3bdfSopenharmony_ci		        tdat[testno].proto);
226f08c3bdfSopenharmony_ci}
227f08c3bdfSopenharmony_ci
228f08c3bdfSopenharmony_civoid cleanup1(void)
229f08c3bdfSopenharmony_ci{
230f08c3bdfSopenharmony_ci	(void)close(s);
231f08c3bdfSopenharmony_ci	s = -1;
232f08c3bdfSopenharmony_ci}
233f08c3bdfSopenharmony_ci
234f08c3bdfSopenharmony_civoid setup2(void)
235f08c3bdfSopenharmony_ci{
236f08c3bdfSopenharmony_ci	setup1();		/* get a socket in s */
237f08c3bdfSopenharmony_ci	SAFE_CONNECT(cleanup, s, (const struct sockaddr *)&sin1, sizeof(sin1));
238f08c3bdfSopenharmony_ci}
239f08c3bdfSopenharmony_ci
240f08c3bdfSopenharmony_cipid_t start_server(struct sockaddr_in *sin0)
241f08c3bdfSopenharmony_ci{
242f08c3bdfSopenharmony_ci	pid_t pid;
243f08c3bdfSopenharmony_ci	socklen_t slen = sizeof(*sin0);
244f08c3bdfSopenharmony_ci
245f08c3bdfSopenharmony_ci	sin0->sin_family = AF_INET;
246f08c3bdfSopenharmony_ci	sin0->sin_port = 0; /* pick random free port */
247f08c3bdfSopenharmony_ci	sin0->sin_addr.s_addr = INADDR_ANY;
248f08c3bdfSopenharmony_ci
249f08c3bdfSopenharmony_ci	sfd = socket(PF_INET, SOCK_STREAM, 0);
250f08c3bdfSopenharmony_ci	if (sfd < 0) {
251f08c3bdfSopenharmony_ci		tst_brkm(TBROK | TERRNO, cleanup, "server socket failed");
252f08c3bdfSopenharmony_ci		return -1;
253f08c3bdfSopenharmony_ci	}
254f08c3bdfSopenharmony_ci	if (bind(sfd, (struct sockaddr *)sin0, sizeof(*sin0)) < 0) {
255f08c3bdfSopenharmony_ci		tst_brkm(TBROK | TERRNO, cleanup, "server bind failed");
256f08c3bdfSopenharmony_ci		return -1;
257f08c3bdfSopenharmony_ci	}
258f08c3bdfSopenharmony_ci	if (listen(sfd, 10) < 0) {
259f08c3bdfSopenharmony_ci		tst_brkm(TBROK | TERRNO, cleanup, "server listen failed");
260f08c3bdfSopenharmony_ci		return -1;
261f08c3bdfSopenharmony_ci	}
262f08c3bdfSopenharmony_ci	SAFE_GETSOCKNAME(cleanup, sfd, (struct sockaddr *)sin0, &slen);
263f08c3bdfSopenharmony_ci
264f08c3bdfSopenharmony_ci	switch ((pid = FORK_OR_VFORK())) {
265f08c3bdfSopenharmony_ci	case 0:		/* child */
266f08c3bdfSopenharmony_ci#ifdef UCLINUX
267f08c3bdfSopenharmony_ci		self_exec(argv0, "d", sfd);
268f08c3bdfSopenharmony_ci#else
269f08c3bdfSopenharmony_ci		do_child();
270f08c3bdfSopenharmony_ci#endif
271f08c3bdfSopenharmony_ci		break;
272f08c3bdfSopenharmony_ci	case -1:
273f08c3bdfSopenharmony_ci		tst_brkm(TBROK | TERRNO, cleanup, "server fork failed");
274f08c3bdfSopenharmony_ci		/* fall through */
275f08c3bdfSopenharmony_ci	default:		/* parent */
276f08c3bdfSopenharmony_ci		(void)close(sfd);
277f08c3bdfSopenharmony_ci		return pid;
278f08c3bdfSopenharmony_ci	}
279f08c3bdfSopenharmony_ci
280f08c3bdfSopenharmony_ci	return -1;
281f08c3bdfSopenharmony_ci}
282f08c3bdfSopenharmony_ci
283f08c3bdfSopenharmony_civoid do_child(void)
284f08c3bdfSopenharmony_ci{
285f08c3bdfSopenharmony_ci	struct sockaddr_in fsin;
286f08c3bdfSopenharmony_ci	fd_set afds, rfds;
287f08c3bdfSopenharmony_ci	int nfds, cc, fd;
288f08c3bdfSopenharmony_ci	char c;
289f08c3bdfSopenharmony_ci
290f08c3bdfSopenharmony_ci	FD_ZERO(&afds);
291f08c3bdfSopenharmony_ci	FD_SET(sfd, &afds);
292f08c3bdfSopenharmony_ci
293f08c3bdfSopenharmony_ci	nfds = sfd + 1;
294f08c3bdfSopenharmony_ci
295f08c3bdfSopenharmony_ci	/* accept connections until killed */
296f08c3bdfSopenharmony_ci	while (1) {
297f08c3bdfSopenharmony_ci		socklen_t fromlen;
298f08c3bdfSopenharmony_ci
299f08c3bdfSopenharmony_ci		memcpy(&rfds, &afds, sizeof(rfds));
300f08c3bdfSopenharmony_ci
301f08c3bdfSopenharmony_ci		if (select(nfds, &rfds, NULL, NULL,
302f08c3bdfSopenharmony_ci			   NULL) < 0)
303f08c3bdfSopenharmony_ci			if (errno != EINTR)
304f08c3bdfSopenharmony_ci				exit(1);
305f08c3bdfSopenharmony_ci		if (FD_ISSET(sfd, &rfds)) {
306f08c3bdfSopenharmony_ci			int newfd;
307f08c3bdfSopenharmony_ci
308f08c3bdfSopenharmony_ci			fromlen = sizeof(fsin);
309f08c3bdfSopenharmony_ci			newfd = accept(sfd, (struct sockaddr *)&fsin, &fromlen);
310f08c3bdfSopenharmony_ci			if (newfd >= 0) {
311f08c3bdfSopenharmony_ci				FD_SET(newfd, &afds);
312f08c3bdfSopenharmony_ci				nfds = MAX(nfds, newfd + 1);
313f08c3bdfSopenharmony_ci			}
314f08c3bdfSopenharmony_ci		}
315f08c3bdfSopenharmony_ci		for (fd = 0; fd < nfds; ++fd)
316f08c3bdfSopenharmony_ci			if (fd != sfd && FD_ISSET(fd, &rfds)) {
317f08c3bdfSopenharmony_ci				if ((cc = read(fd, &c, 1)) == 0) {
318f08c3bdfSopenharmony_ci					(void)close(fd);
319f08c3bdfSopenharmony_ci					FD_CLR(fd, &afds);
320f08c3bdfSopenharmony_ci				}
321f08c3bdfSopenharmony_ci			}
322f08c3bdfSopenharmony_ci	}
323f08c3bdfSopenharmony_ci}
324