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