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: recv01 22f08c3bdfSopenharmony_ci * 23f08c3bdfSopenharmony_ci * Test Description: 24f08c3bdfSopenharmony_ci * Verify that recv() returns the proper errno for various failure cases 25f08c3bdfSopenharmony_ci * 26f08c3bdfSopenharmony_ci * Usage: <for command-line> 27f08c3bdfSopenharmony_ci * recv01 [-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 = "recv01"; 59f08c3bdfSopenharmony_ciint testno; 60f08c3bdfSopenharmony_ci 61f08c3bdfSopenharmony_cichar buf[1024]; 62f08c3bdfSopenharmony_ciint s; /* socket descriptor */ 63f08c3bdfSopenharmony_cistruct sockaddr_in sin1, sin2, sin3, sin4; 64f08c3bdfSopenharmony_cistatic int sfd; /* shared between do_child and start_server */ 65f08c3bdfSopenharmony_ci 66f08c3bdfSopenharmony_civoid do_child(void), setup(void), setup0(void), setup1(void), 67f08c3bdfSopenharmony_cicleanup(void), cleanup0(void), cleanup1(void); 68f08c3bdfSopenharmony_cipid_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 void *buf; /* recv data buffer */ 75f08c3bdfSopenharmony_ci int buflen; /* recv's 3rd argument */ 76f08c3bdfSopenharmony_ci unsigned flags; /* recv's 4th argument */ 77f08c3bdfSopenharmony_ci int retval; /* syscall return value */ 78f08c3bdfSopenharmony_ci int experrno; /* expected errno */ 79f08c3bdfSopenharmony_ci void (*setup) (void); 80f08c3bdfSopenharmony_ci void (*cleanup) (void); 81f08c3bdfSopenharmony_ci char *desc; 82f08c3bdfSopenharmony_ci} tdat[] = { 83f08c3bdfSopenharmony_ci { 84f08c3bdfSopenharmony_ci PF_INET, SOCK_STREAM, 0, buf, sizeof(buf), 0, 85f08c3bdfSopenharmony_ci -1, EBADF, setup0, cleanup0, "bad file descriptor"} 86f08c3bdfSopenharmony_ci , { 87f08c3bdfSopenharmony_ci 0, 0, 0, buf, sizeof(buf), 0, 88f08c3bdfSopenharmony_ci -1, ENOTSOCK, setup0, cleanup0, "invalid socket"} 89f08c3bdfSopenharmony_ci , 90f08c3bdfSopenharmony_ci#ifndef UCLINUX 91f08c3bdfSopenharmony_ci /* Skip since uClinux does not implement memory protection */ 92f08c3bdfSopenharmony_ci { 93f08c3bdfSopenharmony_ci PF_INET, SOCK_STREAM, 0, (void *)-1, sizeof(buf), 0, 94f08c3bdfSopenharmony_ci -1, EFAULT, setup1, cleanup1, "invalid recv buffer"} 95f08c3bdfSopenharmony_ci , 96f08c3bdfSopenharmony_ci#endif 97f08c3bdfSopenharmony_ci { 98f08c3bdfSopenharmony_ci PF_INET, SOCK_STREAM, 0, buf, sizeof(buf), MSG_OOB, 99f08c3bdfSopenharmony_ci -1, EINVAL, setup1, cleanup1, "invalid MSG_OOB flag set"} 100f08c3bdfSopenharmony_ci , 101f08c3bdfSopenharmony_ci { 102f08c3bdfSopenharmony_ci PF_INET, SOCK_STREAM, 0, buf, sizeof(buf), MSG_ERRQUEUE, 103f08c3bdfSopenharmony_ci -1, EAGAIN, setup1, cleanup1, "invalid MSG_ERRQUEUE flag set"} 104f08c3bdfSopenharmony_ci,}; 105f08c3bdfSopenharmony_ci 106f08c3bdfSopenharmony_ciint TST_TOTAL = sizeof(tdat) / sizeof(tdat[0]); 107f08c3bdfSopenharmony_ci 108f08c3bdfSopenharmony_ci#ifdef UCLINUX 109f08c3bdfSopenharmony_cistatic char *argv0; 110f08c3bdfSopenharmony_ci#endif 111f08c3bdfSopenharmony_ci 112f08c3bdfSopenharmony_ciint main(int argc, char *argv[]) 113f08c3bdfSopenharmony_ci{ 114f08c3bdfSopenharmony_ci int lc; 115f08c3bdfSopenharmony_ci 116f08c3bdfSopenharmony_ci tst_parse_opts(argc, argv, NULL, NULL); 117f08c3bdfSopenharmony_ci#ifdef UCLINUX 118f08c3bdfSopenharmony_ci argv0 = argv[0]; 119f08c3bdfSopenharmony_ci maybe_run_child(&do_child, "d", &sfd); 120f08c3bdfSopenharmony_ci#endif 121f08c3bdfSopenharmony_ci 122f08c3bdfSopenharmony_ci setup(); 123f08c3bdfSopenharmony_ci 124f08c3bdfSopenharmony_ci for (lc = 0; TEST_LOOPING(lc); ++lc) { 125f08c3bdfSopenharmony_ci tst_count = 0; 126f08c3bdfSopenharmony_ci for (testno = 0; testno < TST_TOTAL; ++testno) { 127f08c3bdfSopenharmony_ci if ((tst_kvercmp(3, 17, 0) < 0) 128f08c3bdfSopenharmony_ci && (tdat[testno].flags & MSG_ERRQUEUE) 129f08c3bdfSopenharmony_ci && (tdat[testno].type & SOCK_STREAM)) { 130f08c3bdfSopenharmony_ci tst_resm(TCONF, "skip MSG_ERRQUEUE test, " 131f08c3bdfSopenharmony_ci "it's supported from 3.17"); 132f08c3bdfSopenharmony_ci continue; 133f08c3bdfSopenharmony_ci } 134f08c3bdfSopenharmony_ci 135f08c3bdfSopenharmony_ci tdat[testno].setup(); 136f08c3bdfSopenharmony_ci TEST(recv(s, tdat[testno].buf, tdat[testno].buflen, 137f08c3bdfSopenharmony_ci tdat[testno].flags)); 138f08c3bdfSopenharmony_ci if (TEST_RETURN > 0) 139f08c3bdfSopenharmony_ci TEST_RETURN = 0; /* all nonzero equal here */ 140f08c3bdfSopenharmony_ci if (TEST_RETURN != tdat[testno].retval || 141f08c3bdfSopenharmony_ci (TEST_RETURN < 0 && 142f08c3bdfSopenharmony_ci TEST_ERRNO != tdat[testno].experrno)) { 143f08c3bdfSopenharmony_ci tst_resm(TFAIL, "%s ; returned" 144f08c3bdfSopenharmony_ci " %ld (expected %d), errno %d (expected" 145f08c3bdfSopenharmony_ci " %d)", tdat[testno].desc, 146f08c3bdfSopenharmony_ci TEST_RETURN, tdat[testno].retval, 147f08c3bdfSopenharmony_ci TEST_ERRNO, tdat[testno].experrno); 148f08c3bdfSopenharmony_ci } else { 149f08c3bdfSopenharmony_ci tst_resm(TPASS, "%s successful", 150f08c3bdfSopenharmony_ci tdat[testno].desc); 151f08c3bdfSopenharmony_ci } 152f08c3bdfSopenharmony_ci tdat[testno].cleanup(); 153f08c3bdfSopenharmony_ci } 154f08c3bdfSopenharmony_ci } 155f08c3bdfSopenharmony_ci cleanup(); 156f08c3bdfSopenharmony_ci 157f08c3bdfSopenharmony_ci tst_exit(); 158f08c3bdfSopenharmony_ci} 159f08c3bdfSopenharmony_ci 160f08c3bdfSopenharmony_cipid_t pid; 161f08c3bdfSopenharmony_ci 162f08c3bdfSopenharmony_civoid setup(void) 163f08c3bdfSopenharmony_ci{ 164f08c3bdfSopenharmony_ci TEST_PAUSE; 165f08c3bdfSopenharmony_ci 166f08c3bdfSopenharmony_ci pid = start_server(&sin1); 167f08c3bdfSopenharmony_ci 168f08c3bdfSopenharmony_ci (void)signal(SIGPIPE, SIG_IGN); 169f08c3bdfSopenharmony_ci} 170f08c3bdfSopenharmony_ci 171f08c3bdfSopenharmony_civoid cleanup(void) 172f08c3bdfSopenharmony_ci{ 173f08c3bdfSopenharmony_ci (void)kill(pid, SIGKILL); 174f08c3bdfSopenharmony_ci 175f08c3bdfSopenharmony_ci} 176f08c3bdfSopenharmony_ci 177f08c3bdfSopenharmony_civoid setup0(void) 178f08c3bdfSopenharmony_ci{ 179f08c3bdfSopenharmony_ci if (tdat[testno].experrno == EBADF) 180f08c3bdfSopenharmony_ci s = 400; /* anything not an open file */ 181f08c3bdfSopenharmony_ci else if ((s = open("/dev/null", O_WRONLY)) == -1) 182f08c3bdfSopenharmony_ci tst_brkm(TBROK | TERRNO, cleanup, "open(/dev/null)"); 183f08c3bdfSopenharmony_ci} 184f08c3bdfSopenharmony_ci 185f08c3bdfSopenharmony_civoid cleanup0(void) 186f08c3bdfSopenharmony_ci{ 187f08c3bdfSopenharmony_ci s = -1; 188f08c3bdfSopenharmony_ci} 189f08c3bdfSopenharmony_ci 190f08c3bdfSopenharmony_civoid setup1(void) 191f08c3bdfSopenharmony_ci{ 192f08c3bdfSopenharmony_ci fd_set rdfds; 193f08c3bdfSopenharmony_ci struct timeval timeout; 194f08c3bdfSopenharmony_ci int n; 195f08c3bdfSopenharmony_ci 196f08c3bdfSopenharmony_ci s = SAFE_SOCKET(cleanup, tdat[testno].domain, tdat[testno].type, 197f08c3bdfSopenharmony_ci tdat[testno].proto); 198f08c3bdfSopenharmony_ci if (tdat[testno].type == SOCK_STREAM && 199f08c3bdfSopenharmony_ci connect(s, (struct sockaddr *)&sin1, sizeof(sin1)) < 0) { 200f08c3bdfSopenharmony_ci tst_brkm(TBROK | TERRNO, cleanup, "connect failed"); 201f08c3bdfSopenharmony_ci } 202f08c3bdfSopenharmony_ci /* Wait for something to be readable, else we won't detect EFAULT on recv */ 203f08c3bdfSopenharmony_ci FD_ZERO(&rdfds); 204f08c3bdfSopenharmony_ci FD_SET(s, &rdfds); 205f08c3bdfSopenharmony_ci timeout.tv_sec = 2; 206f08c3bdfSopenharmony_ci timeout.tv_usec = 0; 207f08c3bdfSopenharmony_ci n = select(s + 1, &rdfds, 0, 0, &timeout); 208f08c3bdfSopenharmony_ci if (n != 1 || !FD_ISSET(s, &rdfds)) 209f08c3bdfSopenharmony_ci tst_brkm(TBROK, cleanup, 210f08c3bdfSopenharmony_ci "client setup1 failed - no message ready in 2 sec"); 211f08c3bdfSopenharmony_ci} 212f08c3bdfSopenharmony_ci 213f08c3bdfSopenharmony_civoid cleanup1(void) 214f08c3bdfSopenharmony_ci{ 215f08c3bdfSopenharmony_ci (void)close(s); 216f08c3bdfSopenharmony_ci s = -1; 217f08c3bdfSopenharmony_ci} 218f08c3bdfSopenharmony_ci 219f08c3bdfSopenharmony_cipid_t start_server(struct sockaddr_in *sin0) 220f08c3bdfSopenharmony_ci{ 221f08c3bdfSopenharmony_ci pid_t pid; 222f08c3bdfSopenharmony_ci socklen_t slen = sizeof(*sin0); 223f08c3bdfSopenharmony_ci 224f08c3bdfSopenharmony_ci sin0->sin_family = AF_INET; 225f08c3bdfSopenharmony_ci sin0->sin_port = 0; /* pick random free port */ 226f08c3bdfSopenharmony_ci sin0->sin_addr.s_addr = INADDR_ANY; 227f08c3bdfSopenharmony_ci 228f08c3bdfSopenharmony_ci sfd = socket(PF_INET, SOCK_STREAM, 0); 229f08c3bdfSopenharmony_ci if (sfd < 0) { 230f08c3bdfSopenharmony_ci tst_brkm(TBROK | TERRNO, cleanup, "server socket failed"); 231f08c3bdfSopenharmony_ci return -1; 232f08c3bdfSopenharmony_ci } 233f08c3bdfSopenharmony_ci if (bind(sfd, (struct sockaddr *)sin0, sizeof(*sin0)) < 0) { 234f08c3bdfSopenharmony_ci tst_brkm(TBROK | TERRNO, cleanup, "server bind failed"); 235f08c3bdfSopenharmony_ci return -1; 236f08c3bdfSopenharmony_ci } 237f08c3bdfSopenharmony_ci if (listen(sfd, 10) < 0) { 238f08c3bdfSopenharmony_ci tst_brkm(TBROK | TERRNO, cleanup, "server listen failed"); 239f08c3bdfSopenharmony_ci return -1; 240f08c3bdfSopenharmony_ci } 241f08c3bdfSopenharmony_ci SAFE_GETSOCKNAME(cleanup, sfd, (struct sockaddr *)sin0, &slen); 242f08c3bdfSopenharmony_ci 243f08c3bdfSopenharmony_ci switch ((pid = FORK_OR_VFORK())) { 244f08c3bdfSopenharmony_ci case 0: /* child */ 245f08c3bdfSopenharmony_ci#ifdef UCLINUX 246f08c3bdfSopenharmony_ci if (self_exec(argv0, "d", sfd) < 0) 247f08c3bdfSopenharmony_ci tst_brkm(TBROK | TERRNO, cleanup, 248f08c3bdfSopenharmony_ci "server self_exec failed"); 249f08c3bdfSopenharmony_ci#else 250f08c3bdfSopenharmony_ci do_child(); 251f08c3bdfSopenharmony_ci#endif 252f08c3bdfSopenharmony_ci break; 253f08c3bdfSopenharmony_ci case -1: 254f08c3bdfSopenharmony_ci tst_brkm(TBROK | TERRNO, cleanup, "server fork failed"); 255f08c3bdfSopenharmony_ci /* fall through */ 256f08c3bdfSopenharmony_ci default: /* parent */ 257f08c3bdfSopenharmony_ci (void)close(sfd); 258f08c3bdfSopenharmony_ci return pid; 259f08c3bdfSopenharmony_ci } 260f08c3bdfSopenharmony_ci 261f08c3bdfSopenharmony_ci exit(1); 262f08c3bdfSopenharmony_ci} 263f08c3bdfSopenharmony_ci 264f08c3bdfSopenharmony_civoid do_child(void) 265f08c3bdfSopenharmony_ci{ 266f08c3bdfSopenharmony_ci struct sockaddr_in fsin; 267f08c3bdfSopenharmony_ci fd_set afds, rfds; 268f08c3bdfSopenharmony_ci int nfds, cc, fd; 269f08c3bdfSopenharmony_ci 270f08c3bdfSopenharmony_ci FD_ZERO(&afds); 271f08c3bdfSopenharmony_ci FD_SET(sfd, &afds); 272f08c3bdfSopenharmony_ci 273f08c3bdfSopenharmony_ci nfds = sfd + 1; 274f08c3bdfSopenharmony_ci 275f08c3bdfSopenharmony_ci /* accept connections until killed */ 276f08c3bdfSopenharmony_ci while (1) { 277f08c3bdfSopenharmony_ci socklen_t fromlen; 278f08c3bdfSopenharmony_ci 279f08c3bdfSopenharmony_ci memcpy(&rfds, &afds, sizeof(rfds)); 280f08c3bdfSopenharmony_ci 281f08c3bdfSopenharmony_ci if (select(nfds, &rfds, NULL, NULL, 282f08c3bdfSopenharmony_ci NULL) < 0) 283f08c3bdfSopenharmony_ci if (errno != EINTR) 284f08c3bdfSopenharmony_ci exit(1); 285f08c3bdfSopenharmony_ci if (FD_ISSET(sfd, &rfds)) { 286f08c3bdfSopenharmony_ci int newfd; 287f08c3bdfSopenharmony_ci 288f08c3bdfSopenharmony_ci fromlen = sizeof(fsin); 289f08c3bdfSopenharmony_ci newfd = accept(sfd, (struct sockaddr *)&fsin, &fromlen); 290f08c3bdfSopenharmony_ci if (newfd >= 0) { 291f08c3bdfSopenharmony_ci FD_SET(newfd, &afds); 292f08c3bdfSopenharmony_ci nfds = MAX(nfds, newfd + 1); 293f08c3bdfSopenharmony_ci /* send something back */ 294f08c3bdfSopenharmony_ci (void)write(newfd, "hoser\n", 6); 295f08c3bdfSopenharmony_ci } 296f08c3bdfSopenharmony_ci } 297f08c3bdfSopenharmony_ci for (fd = 0; fd < nfds; ++fd) 298f08c3bdfSopenharmony_ci if (fd != sfd && FD_ISSET(fd, &rfds)) { 299f08c3bdfSopenharmony_ci cc = read(fd, buf, sizeof(buf)); 300f08c3bdfSopenharmony_ci if (cc == 0 || (cc < 0 && errno != EINTR)) { 301f08c3bdfSopenharmony_ci (void)close(fd); 302f08c3bdfSopenharmony_ci FD_CLR(fd, &afds); 303f08c3bdfSopenharmony_ci } 304f08c3bdfSopenharmony_ci } 305f08c3bdfSopenharmony_ci } 306f08c3bdfSopenharmony_ci} 307