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