1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 2f08c3bdfSopenharmony_ci/* 3f08c3bdfSopenharmony_ci * Copyright (c) 2001 Wayne Boyer International Business Machines 4f08c3bdfSopenharmony_ci * Copyright (c) Linux Test Project, 2002-2022 5f08c3bdfSopenharmony_ci * Copyright (c) 2023 Wei Gao <wegao@suse.com> 6f08c3bdfSopenharmony_ci */ 7f08c3bdfSopenharmony_ci 8f08c3bdfSopenharmony_ci/*\ 9f08c3bdfSopenharmony_ci * [Description] 10f08c3bdfSopenharmony_ci * 11f08c3bdfSopenharmony_ci * Verify that recvmsg() returns the proper errno for various failure cases. 12f08c3bdfSopenharmony_ci */ 13f08c3bdfSopenharmony_ci 14f08c3bdfSopenharmony_ci#include <stdio.h> 15f08c3bdfSopenharmony_ci#include <stdlib.h> 16f08c3bdfSopenharmony_ci#include <sys/wait.h> 17f08c3bdfSopenharmony_ci#include "tst_test.h" 18f08c3bdfSopenharmony_ci 19f08c3bdfSopenharmony_ci#define MSG "from recvmsg01 server" 20f08c3bdfSopenharmony_ci#define BUF_SIZE 1024 21f08c3bdfSopenharmony_ci#define CONTROL_LEN (128 * 1024) 22f08c3bdfSopenharmony_ci 23f08c3bdfSopenharmony_cistatic char recv_buf[BUF_SIZE], cbuf[BUF_SIZE]; 24f08c3bdfSopenharmony_cistatic int sock; 25f08c3bdfSopenharmony_cistatic struct sockaddr_in sin1, from; 26f08c3bdfSopenharmony_cistatic struct sockaddr_un sun1; 27f08c3bdfSopenharmony_cistatic struct msghdr msgdat; 28f08c3bdfSopenharmony_cistatic struct cmsghdr *control; 29f08c3bdfSopenharmony_cistatic int controllen; 30f08c3bdfSopenharmony_cistatic struct iovec iov[1]; 31f08c3bdfSopenharmony_cistatic int sfd; /* shared between do_child and start_server */ 32f08c3bdfSopenharmony_cistatic int ufd; /* shared between do_child and start_server */ 33f08c3bdfSopenharmony_cistatic pid_t pid; 34f08c3bdfSopenharmony_cistatic char tmpsunpath[BUF_SIZE]; 35f08c3bdfSopenharmony_ci 36f08c3bdfSopenharmony_cistatic void setup_all(void); 37f08c3bdfSopenharmony_cistatic void setup_invalid_sock(int); 38f08c3bdfSopenharmony_cistatic void setup_valid_sock(int); 39f08c3bdfSopenharmony_cistatic void setup_valid_msg_control(int); 40f08c3bdfSopenharmony_cistatic void setup_large_msg_control(int); 41f08c3bdfSopenharmony_cistatic void cleanup_all(void); 42f08c3bdfSopenharmony_cistatic void cleanup_invalid_sock(int); 43f08c3bdfSopenharmony_cistatic void cleanup_close_sock(int); 44f08c3bdfSopenharmony_cistatic void cleanup_reset_all(int); 45f08c3bdfSopenharmony_cistatic void do_child(void); 46f08c3bdfSopenharmony_cistatic pid_t start_server(struct sockaddr_in *, struct sockaddr_un *); 47f08c3bdfSopenharmony_ci 48f08c3bdfSopenharmony_cistatic struct tcase { 49f08c3bdfSopenharmony_ci int domain; 50f08c3bdfSopenharmony_ci int type; 51f08c3bdfSopenharmony_ci int protocol; 52f08c3bdfSopenharmony_ci struct iovec *iov; 53f08c3bdfSopenharmony_ci int iovcnt; 54f08c3bdfSopenharmony_ci void *recv_buf; 55f08c3bdfSopenharmony_ci int buflen; 56f08c3bdfSopenharmony_ci struct msghdr *msg; 57f08c3bdfSopenharmony_ci unsigned int flags; 58f08c3bdfSopenharmony_ci struct sockaddr *from; 59f08c3bdfSopenharmony_ci int fromlen; 60f08c3bdfSopenharmony_ci int exp_errno; 61f08c3bdfSopenharmony_ci void (*setup)(int n); 62f08c3bdfSopenharmony_ci void (*cleanup)(int n); 63f08c3bdfSopenharmony_ci char *desc; 64f08c3bdfSopenharmony_ci} tcases[] = { 65f08c3bdfSopenharmony_ci { 66f08c3bdfSopenharmony_ci .domain = PF_INET, 67f08c3bdfSopenharmony_ci .type = SOCK_STREAM, 68f08c3bdfSopenharmony_ci .iov = iov, 69f08c3bdfSopenharmony_ci .iovcnt = 1, 70f08c3bdfSopenharmony_ci .recv_buf = recv_buf, 71f08c3bdfSopenharmony_ci .buflen = sizeof(recv_buf), 72f08c3bdfSopenharmony_ci .msg = &msgdat, 73f08c3bdfSopenharmony_ci .from = (struct sockaddr *)&from, 74f08c3bdfSopenharmony_ci .fromlen = sizeof(from), 75f08c3bdfSopenharmony_ci .exp_errno = EBADF, 76f08c3bdfSopenharmony_ci .setup = setup_invalid_sock, 77f08c3bdfSopenharmony_ci .cleanup = cleanup_invalid_sock, 78f08c3bdfSopenharmony_ci .desc = "bad file descriptor", 79f08c3bdfSopenharmony_ci }, 80f08c3bdfSopenharmony_ci { 81f08c3bdfSopenharmony_ci .domain = PF_INET, 82f08c3bdfSopenharmony_ci .type = SOCK_STREAM, 83f08c3bdfSopenharmony_ci .iov = iov, 84f08c3bdfSopenharmony_ci .iovcnt = 1, 85f08c3bdfSopenharmony_ci .recv_buf = (void *)recv_buf, 86f08c3bdfSopenharmony_ci .buflen = sizeof(recv_buf), 87f08c3bdfSopenharmony_ci .msg = &msgdat, 88f08c3bdfSopenharmony_ci .from = (struct sockaddr *)&from, 89f08c3bdfSopenharmony_ci .fromlen = sizeof(from), 90f08c3bdfSopenharmony_ci .exp_errno = ENOTSOCK, 91f08c3bdfSopenharmony_ci .setup = setup_invalid_sock, 92f08c3bdfSopenharmony_ci .cleanup = cleanup_invalid_sock, 93f08c3bdfSopenharmony_ci .desc = "invalid socket", 94f08c3bdfSopenharmony_ci }, 95f08c3bdfSopenharmony_ci { 96f08c3bdfSopenharmony_ci .domain = PF_INET, 97f08c3bdfSopenharmony_ci .type = SOCK_STREAM, 98f08c3bdfSopenharmony_ci .iov = iov, 99f08c3bdfSopenharmony_ci .iovcnt = 1, 100f08c3bdfSopenharmony_ci .recv_buf = (void *)recv_buf, 101f08c3bdfSopenharmony_ci .buflen = sizeof(recv_buf), 102f08c3bdfSopenharmony_ci .msg = &msgdat, 103f08c3bdfSopenharmony_ci .flags = -1, 104f08c3bdfSopenharmony_ci .from = (struct sockaddr *)&from, 105f08c3bdfSopenharmony_ci .fromlen = -1, 106f08c3bdfSopenharmony_ci .exp_errno = EINVAL, 107f08c3bdfSopenharmony_ci .setup = setup_valid_sock, 108f08c3bdfSopenharmony_ci .cleanup = cleanup_close_sock, 109f08c3bdfSopenharmony_ci .desc = "invalid socket length", 110f08c3bdfSopenharmony_ci }, 111f08c3bdfSopenharmony_ci { 112f08c3bdfSopenharmony_ci .domain = PF_INET, 113f08c3bdfSopenharmony_ci .type = SOCK_STREAM, 114f08c3bdfSopenharmony_ci .iov = iov, 115f08c3bdfSopenharmony_ci .iovcnt = 1, 116f08c3bdfSopenharmony_ci .recv_buf = (void *)-1, 117f08c3bdfSopenharmony_ci .buflen = sizeof(recv_buf), 118f08c3bdfSopenharmony_ci .msg = &msgdat, 119f08c3bdfSopenharmony_ci .from = (struct sockaddr *)&from, 120f08c3bdfSopenharmony_ci .fromlen = sizeof(from), 121f08c3bdfSopenharmony_ci .exp_errno = EFAULT, 122f08c3bdfSopenharmony_ci .setup = setup_valid_sock, 123f08c3bdfSopenharmony_ci .cleanup = cleanup_close_sock, 124f08c3bdfSopenharmony_ci .desc = "invalid recv buffer", 125f08c3bdfSopenharmony_ci }, 126f08c3bdfSopenharmony_ci { 127f08c3bdfSopenharmony_ci .domain = PF_INET, 128f08c3bdfSopenharmony_ci .type = SOCK_STREAM, 129f08c3bdfSopenharmony_ci .iovcnt = 1, 130f08c3bdfSopenharmony_ci .recv_buf = recv_buf, 131f08c3bdfSopenharmony_ci .buflen = sizeof(recv_buf), 132f08c3bdfSopenharmony_ci .msg = &msgdat, 133f08c3bdfSopenharmony_ci .from = (struct sockaddr *)&from, 134f08c3bdfSopenharmony_ci .fromlen = sizeof(from), 135f08c3bdfSopenharmony_ci .exp_errno = EFAULT, 136f08c3bdfSopenharmony_ci .setup = setup_valid_sock, 137f08c3bdfSopenharmony_ci .cleanup = cleanup_close_sock, 138f08c3bdfSopenharmony_ci .desc = "invalid iovec buffer", 139f08c3bdfSopenharmony_ci }, 140f08c3bdfSopenharmony_ci { 141f08c3bdfSopenharmony_ci .domain = PF_INET, 142f08c3bdfSopenharmony_ci .type = SOCK_STREAM, 143f08c3bdfSopenharmony_ci .iov = iov, 144f08c3bdfSopenharmony_ci .iovcnt = -1, 145f08c3bdfSopenharmony_ci .recv_buf = recv_buf, 146f08c3bdfSopenharmony_ci .buflen = sizeof(recv_buf), 147f08c3bdfSopenharmony_ci .msg = &msgdat, 148f08c3bdfSopenharmony_ci .from = (struct sockaddr *)&from, 149f08c3bdfSopenharmony_ci .fromlen = sizeof(from), 150f08c3bdfSopenharmony_ci .exp_errno = EMSGSIZE, 151f08c3bdfSopenharmony_ci .setup = setup_valid_sock, 152f08c3bdfSopenharmony_ci .cleanup = cleanup_close_sock, 153f08c3bdfSopenharmony_ci .desc = "invalid iovec count", 154f08c3bdfSopenharmony_ci }, 155f08c3bdfSopenharmony_ci { 156f08c3bdfSopenharmony_ci .domain = PF_INET, 157f08c3bdfSopenharmony_ci .type = SOCK_STREAM, 158f08c3bdfSopenharmony_ci .iov = iov, 159f08c3bdfSopenharmony_ci .iovcnt = 1, 160f08c3bdfSopenharmony_ci .recv_buf = recv_buf, 161f08c3bdfSopenharmony_ci .buflen = sizeof(recv_buf), 162f08c3bdfSopenharmony_ci .msg = &msgdat, 163f08c3bdfSopenharmony_ci .from = (struct sockaddr *)&from, 164f08c3bdfSopenharmony_ci .fromlen = sizeof(from), 165f08c3bdfSopenharmony_ci .setup = setup_valid_msg_control, 166f08c3bdfSopenharmony_ci .cleanup = cleanup_reset_all, 167f08c3bdfSopenharmony_ci .desc = "permission reception", 168f08c3bdfSopenharmony_ci }, 169f08c3bdfSopenharmony_ci { 170f08c3bdfSopenharmony_ci .domain = PF_INET, 171f08c3bdfSopenharmony_ci .type = SOCK_STREAM, 172f08c3bdfSopenharmony_ci .iov = iov, 173f08c3bdfSopenharmony_ci .iovcnt = 1, 174f08c3bdfSopenharmony_ci .recv_buf = recv_buf, 175f08c3bdfSopenharmony_ci .buflen = sizeof(recv_buf), 176f08c3bdfSopenharmony_ci .msg = &msgdat, 177f08c3bdfSopenharmony_ci .flags = MSG_OOB, 178f08c3bdfSopenharmony_ci .from = (struct sockaddr *)&from, 179f08c3bdfSopenharmony_ci .fromlen = sizeof(from), 180f08c3bdfSopenharmony_ci .exp_errno = EINVAL, 181f08c3bdfSopenharmony_ci .setup = setup_valid_sock, 182f08c3bdfSopenharmony_ci .cleanup = cleanup_close_sock, 183f08c3bdfSopenharmony_ci .desc = "invalid MSG_OOB flag set", 184f08c3bdfSopenharmony_ci }, 185f08c3bdfSopenharmony_ci { 186f08c3bdfSopenharmony_ci .domain = PF_INET, 187f08c3bdfSopenharmony_ci .type = SOCK_STREAM, 188f08c3bdfSopenharmony_ci .iov = iov, 189f08c3bdfSopenharmony_ci .iovcnt = 1, 190f08c3bdfSopenharmony_ci .recv_buf = recv_buf, 191f08c3bdfSopenharmony_ci .buflen = sizeof(recv_buf), 192f08c3bdfSopenharmony_ci .msg = &msgdat, 193f08c3bdfSopenharmony_ci .flags = MSG_ERRQUEUE, 194f08c3bdfSopenharmony_ci .from = (struct sockaddr *)&from, 195f08c3bdfSopenharmony_ci .fromlen = sizeof(from), 196f08c3bdfSopenharmony_ci .exp_errno = EAGAIN, 197f08c3bdfSopenharmony_ci .setup = setup_valid_sock, 198f08c3bdfSopenharmony_ci .cleanup = cleanup_close_sock, 199f08c3bdfSopenharmony_ci .desc = "invalid MSG_ERRQUEUE flag set", 200f08c3bdfSopenharmony_ci }, 201f08c3bdfSopenharmony_ci { 202f08c3bdfSopenharmony_ci .domain = PF_INET, 203f08c3bdfSopenharmony_ci .type = SOCK_STREAM, 204f08c3bdfSopenharmony_ci .iov = iov, 205f08c3bdfSopenharmony_ci .iovcnt = 1, 206f08c3bdfSopenharmony_ci .recv_buf = recv_buf, 207f08c3bdfSopenharmony_ci .buflen = sizeof(recv_buf), 208f08c3bdfSopenharmony_ci .msg = &msgdat, 209f08c3bdfSopenharmony_ci .from = (struct sockaddr *)&from, 210f08c3bdfSopenharmony_ci .fromlen = sizeof(from), 211f08c3bdfSopenharmony_ci .setup = setup_large_msg_control, 212f08c3bdfSopenharmony_ci .cleanup = cleanup_reset_all, 213f08c3bdfSopenharmony_ci .desc = "large cmesg length", 214f08c3bdfSopenharmony_ci }, 215f08c3bdfSopenharmony_ci 216f08c3bdfSopenharmony_ci}; 217f08c3bdfSopenharmony_ci 218f08c3bdfSopenharmony_cistatic void run(unsigned int n) 219f08c3bdfSopenharmony_ci{ 220f08c3bdfSopenharmony_ci struct tcase *tc = &tcases[n]; 221f08c3bdfSopenharmony_ci int ret = tc->exp_errno ? -1 : 0; 222f08c3bdfSopenharmony_ci 223f08c3bdfSopenharmony_ci if ((tst_kvercmp(3, 17, 0) < 0) 224f08c3bdfSopenharmony_ci && (tc->flags & MSG_ERRQUEUE) 225f08c3bdfSopenharmony_ci && (tc->type & SOCK_STREAM)) { 226f08c3bdfSopenharmony_ci tst_res(TCONF, "MSG_ERRQUEUE requires kernel >= 3.17"); 227f08c3bdfSopenharmony_ci return; 228f08c3bdfSopenharmony_ci } 229f08c3bdfSopenharmony_ci 230f08c3bdfSopenharmony_ci setup_all(); 231f08c3bdfSopenharmony_ci tc->setup(n); 232f08c3bdfSopenharmony_ci 233f08c3bdfSopenharmony_ci iov[0].iov_base = tc->recv_buf; 234f08c3bdfSopenharmony_ci iov[0].iov_len = tc->buflen; 235f08c3bdfSopenharmony_ci msgdat.msg_name = tc->from; 236f08c3bdfSopenharmony_ci msgdat.msg_namelen = tc->fromlen; 237f08c3bdfSopenharmony_ci msgdat.msg_iov = tc->iov; 238f08c3bdfSopenharmony_ci msgdat.msg_iovlen = tc->iovcnt; 239f08c3bdfSopenharmony_ci msgdat.msg_control = control; 240f08c3bdfSopenharmony_ci msgdat.msg_controllen = controllen; 241f08c3bdfSopenharmony_ci msgdat.msg_flags = 0; 242f08c3bdfSopenharmony_ci 243f08c3bdfSopenharmony_ci TEST(recvmsg(sock, tc->msg, tc->flags)); 244f08c3bdfSopenharmony_ci if (TST_RET >= 0) 245f08c3bdfSopenharmony_ci TST_RET = 0; 246f08c3bdfSopenharmony_ci 247f08c3bdfSopenharmony_ci if (TST_RET != ret) { 248f08c3bdfSopenharmony_ci tst_res(TFAIL | TTERRNO, "%s: expected %d, returned %ld", 249f08c3bdfSopenharmony_ci tc->desc, ret, TST_RET); 250f08c3bdfSopenharmony_ci } else if (TST_ERR != tc->exp_errno) { 251f08c3bdfSopenharmony_ci tst_res(TFAIL | TTERRNO, 252f08c3bdfSopenharmony_ci "%s: expected %s", 253f08c3bdfSopenharmony_ci tc->desc, tst_strerrno(tc->exp_errno)); 254f08c3bdfSopenharmony_ci } else { 255f08c3bdfSopenharmony_ci tst_res(TPASS, "%s passed", tc->desc); 256f08c3bdfSopenharmony_ci } 257f08c3bdfSopenharmony_ci 258f08c3bdfSopenharmony_ci tc->cleanup(n); 259f08c3bdfSopenharmony_ci cleanup_all(); 260f08c3bdfSopenharmony_ci} 261f08c3bdfSopenharmony_ci 262f08c3bdfSopenharmony_ci 263f08c3bdfSopenharmony_cistatic void setup_all(void) 264f08c3bdfSopenharmony_ci{ 265f08c3bdfSopenharmony_ci int tfd; 266f08c3bdfSopenharmony_ci 267f08c3bdfSopenharmony_ci sun1.sun_family = AF_UNIX; 268f08c3bdfSopenharmony_ci 269f08c3bdfSopenharmony_ci (void)strcpy(tmpsunpath, "udsockXXXXXX"); 270f08c3bdfSopenharmony_ci tfd = mkstemp(tmpsunpath); 271f08c3bdfSopenharmony_ci SAFE_CLOSE(tfd); 272f08c3bdfSopenharmony_ci SAFE_UNLINK(tmpsunpath); 273f08c3bdfSopenharmony_ci (void)strcpy(sun1.sun_path, tmpsunpath); 274f08c3bdfSopenharmony_ci SAFE_SIGNAL(SIGPIPE, SIG_IGN); 275f08c3bdfSopenharmony_ci pid = start_server(&sin1, &sun1); 276f08c3bdfSopenharmony_ci} 277f08c3bdfSopenharmony_ci 278f08c3bdfSopenharmony_cistatic void cleanup_all(void) 279f08c3bdfSopenharmony_ci{ 280f08c3bdfSopenharmony_ci if (pid > 0) { 281f08c3bdfSopenharmony_ci (void)kill(pid, SIGKILL); /* kill server */ 282f08c3bdfSopenharmony_ci wait(NULL); 283f08c3bdfSopenharmony_ci } 284f08c3bdfSopenharmony_ci 285f08c3bdfSopenharmony_ci if (tmpsunpath[0] != '\0') 286f08c3bdfSopenharmony_ci (void)SAFE_UNLINK(tmpsunpath); 287f08c3bdfSopenharmony_ci} 288f08c3bdfSopenharmony_ci 289f08c3bdfSopenharmony_cistatic void setup_invalid_sock(int n) 290f08c3bdfSopenharmony_ci{ 291f08c3bdfSopenharmony_ci if (tcases[n].exp_errno == EBADF) 292f08c3bdfSopenharmony_ci sock = 400; /* anything not an open file */ 293f08c3bdfSopenharmony_ci else 294f08c3bdfSopenharmony_ci sock = SAFE_OPEN("/dev/null", O_WRONLY); 295f08c3bdfSopenharmony_ci} 296f08c3bdfSopenharmony_ci 297f08c3bdfSopenharmony_cistatic void cleanup_invalid_sock(int n) 298f08c3bdfSopenharmony_ci{ 299f08c3bdfSopenharmony_ci if (tcases[n].exp_errno == EBADF) 300f08c3bdfSopenharmony_ci sock = -1; 301f08c3bdfSopenharmony_ci else 302f08c3bdfSopenharmony_ci SAFE_CLOSE(sock); 303f08c3bdfSopenharmony_ci} 304f08c3bdfSopenharmony_ci 305f08c3bdfSopenharmony_cistatic void setup_valid_sock(int n) 306f08c3bdfSopenharmony_ci{ 307f08c3bdfSopenharmony_ci fd_set rdfds; 308f08c3bdfSopenharmony_ci struct timeval timeout; 309f08c3bdfSopenharmony_ci 310f08c3bdfSopenharmony_ci sock = SAFE_SOCKET(tcases[n].domain, tcases[n].type, tcases[n].protocol); 311f08c3bdfSopenharmony_ci 312f08c3bdfSopenharmony_ci if (tcases[n].type == SOCK_STREAM) { 313f08c3bdfSopenharmony_ci if (tcases[n].domain == PF_INET) { 314f08c3bdfSopenharmony_ci SAFE_CONNECT(sock, (struct sockaddr *)&sin1, sizeof(sin1)); 315f08c3bdfSopenharmony_ci /* Wait for something to be readable, else we won't detect EFAULT on recv */ 316f08c3bdfSopenharmony_ci FD_ZERO(&rdfds); 317f08c3bdfSopenharmony_ci FD_SET(sock, &rdfds); 318f08c3bdfSopenharmony_ci timeout.tv_sec = 2; 319f08c3bdfSopenharmony_ci timeout.tv_usec = 0; 320f08c3bdfSopenharmony_ci n = select(sock + 1, &rdfds, 0, 0, &timeout); 321f08c3bdfSopenharmony_ci 322f08c3bdfSopenharmony_ci if (n != 1 || !FD_ISSET(sock, &rdfds)) 323f08c3bdfSopenharmony_ci tst_brk(TBROK, "no message ready in %d sec", (int)timeout.tv_sec); 324f08c3bdfSopenharmony_ci 325f08c3bdfSopenharmony_ci } else if (tcases[n].domain == PF_UNIX) { 326f08c3bdfSopenharmony_ci SAFE_CONNECT(sock, (struct sockaddr *)&sun1, sizeof(sun1)); 327f08c3bdfSopenharmony_ci } 328f08c3bdfSopenharmony_ci } 329f08c3bdfSopenharmony_ci} 330f08c3bdfSopenharmony_ci 331f08c3bdfSopenharmony_cistatic void setup_valid_msg_control(int n) 332f08c3bdfSopenharmony_ci{ 333f08c3bdfSopenharmony_ci setup_valid_sock(n); 334f08c3bdfSopenharmony_ci SAFE_SEND(1, sock, "R", 1, 0); 335f08c3bdfSopenharmony_ci control = (struct cmsghdr *)cbuf; 336f08c3bdfSopenharmony_ci controllen = control->cmsg_len = sizeof(cbuf); 337f08c3bdfSopenharmony_ci} 338f08c3bdfSopenharmony_ci 339f08c3bdfSopenharmony_cistatic void setup_large_msg_control(int n) 340f08c3bdfSopenharmony_ci{ 341f08c3bdfSopenharmony_ci setup_valid_msg_control(n); 342f08c3bdfSopenharmony_ci controllen = CONTROL_LEN; 343f08c3bdfSopenharmony_ci} 344f08c3bdfSopenharmony_ci 345f08c3bdfSopenharmony_cistatic void cleanup_close_sock(int n LTP_ATTRIBUTE_UNUSED) 346f08c3bdfSopenharmony_ci{ 347f08c3bdfSopenharmony_ci SAFE_CLOSE(sock); 348f08c3bdfSopenharmony_ci} 349f08c3bdfSopenharmony_ci 350f08c3bdfSopenharmony_cistatic void cleanup_reset_all(int n LTP_ATTRIBUTE_UNUSED) 351f08c3bdfSopenharmony_ci{ 352f08c3bdfSopenharmony_ci SAFE_CLOSE(sock); 353f08c3bdfSopenharmony_ci 354f08c3bdfSopenharmony_ci control = 0; 355f08c3bdfSopenharmony_ci controllen = 0; 356f08c3bdfSopenharmony_ci} 357f08c3bdfSopenharmony_ci 358f08c3bdfSopenharmony_cipid_t start_server(struct sockaddr_in *ssin, struct sockaddr_un *ssun) 359f08c3bdfSopenharmony_ci{ 360f08c3bdfSopenharmony_ci pid_t pid; 361f08c3bdfSopenharmony_ci socklen_t slen = sizeof(*ssin); 362f08c3bdfSopenharmony_ci 363f08c3bdfSopenharmony_ci ssin->sin_family = AF_INET; 364f08c3bdfSopenharmony_ci ssin->sin_port = 0; /* pick random free port */ 365f08c3bdfSopenharmony_ci ssin->sin_addr.s_addr = INADDR_ANY; 366f08c3bdfSopenharmony_ci 367f08c3bdfSopenharmony_ci /* set up inet socket */ 368f08c3bdfSopenharmony_ci sfd = SAFE_SOCKET(PF_INET, SOCK_STREAM, 0); 369f08c3bdfSopenharmony_ci SAFE_BIND(sfd, (struct sockaddr *)ssin, sizeof(*ssin)); 370f08c3bdfSopenharmony_ci SAFE_LISTEN(sfd, 10); 371f08c3bdfSopenharmony_ci SAFE_GETSOCKNAME(sfd, (struct sockaddr *)ssin, &slen); 372f08c3bdfSopenharmony_ci 373f08c3bdfSopenharmony_ci /* set up UNIX-domain socket */ 374f08c3bdfSopenharmony_ci ufd = SAFE_SOCKET(PF_UNIX, SOCK_STREAM, 0); 375f08c3bdfSopenharmony_ci SAFE_BIND(ufd, (struct sockaddr *)ssun, sizeof(*ssun)); 376f08c3bdfSopenharmony_ci SAFE_LISTEN(ufd, 10); 377f08c3bdfSopenharmony_ci 378f08c3bdfSopenharmony_ci pid = SAFE_FORK(); 379f08c3bdfSopenharmony_ci if (!pid) { 380f08c3bdfSopenharmony_ci do_child(); 381f08c3bdfSopenharmony_ci exit(1); 382f08c3bdfSopenharmony_ci } 383f08c3bdfSopenharmony_ci 384f08c3bdfSopenharmony_ci SAFE_CLOSE(sfd); 385f08c3bdfSopenharmony_ci SAFE_CLOSE(ufd); 386f08c3bdfSopenharmony_ci 387f08c3bdfSopenharmony_ci return pid; 388f08c3bdfSopenharmony_ci} 389f08c3bdfSopenharmony_ci 390f08c3bdfSopenharmony_ci/* for permission test */ 391f08c3bdfSopenharmony_cistatic void sender(int fd) 392f08c3bdfSopenharmony_ci{ 393f08c3bdfSopenharmony_ci struct msghdr mh = {}; 394f08c3bdfSopenharmony_ci struct cmsghdr *control; 395f08c3bdfSopenharmony_ci char tmpfn[BUF_SIZE] = ""; 396f08c3bdfSopenharmony_ci char snd_cbuf[BUF_SIZE] = ""; 397f08c3bdfSopenharmony_ci int tfd; 398f08c3bdfSopenharmony_ci 399f08c3bdfSopenharmony_ci (void)strcpy(tmpfn, "smtXXXXXX"); 400f08c3bdfSopenharmony_ci tfd = mkstemp(tmpfn); 401f08c3bdfSopenharmony_ci if (tfd < 0) 402f08c3bdfSopenharmony_ci return; 403f08c3bdfSopenharmony_ci 404f08c3bdfSopenharmony_ci /* set up cmsghdr */ 405f08c3bdfSopenharmony_ci control = (struct cmsghdr *)snd_cbuf; 406f08c3bdfSopenharmony_ci control->cmsg_len = sizeof(struct cmsghdr) + 4; 407f08c3bdfSopenharmony_ci control->cmsg_level = SOL_SOCKET; 408f08c3bdfSopenharmony_ci control->cmsg_type = SCM_RIGHTS; 409f08c3bdfSopenharmony_ci *(int *)CMSG_DATA(control) = tfd; 410f08c3bdfSopenharmony_ci 411f08c3bdfSopenharmony_ci /* set up msghdr */ 412f08c3bdfSopenharmony_ci iov[0].iov_base = MSG; 413f08c3bdfSopenharmony_ci iov[0].iov_len = sizeof(MSG); 414f08c3bdfSopenharmony_ci mh.msg_iov = iov; 415f08c3bdfSopenharmony_ci mh.msg_iovlen = 1; 416f08c3bdfSopenharmony_ci mh.msg_flags = 0; 417f08c3bdfSopenharmony_ci mh.msg_control = control; 418f08c3bdfSopenharmony_ci mh.msg_controllen = control->cmsg_len; 419f08c3bdfSopenharmony_ci 420f08c3bdfSopenharmony_ci /* do it */ 421f08c3bdfSopenharmony_ci SAFE_SENDMSG(sizeof(MSG), fd, &mh, 0); 422f08c3bdfSopenharmony_ci SAFE_CLOSE(tfd); 423f08c3bdfSopenharmony_ci (void)SAFE_UNLINK(tmpfn); 424f08c3bdfSopenharmony_ci} 425f08c3bdfSopenharmony_ci 426f08c3bdfSopenharmony_cistatic void do_child(void) 427f08c3bdfSopenharmony_ci{ 428f08c3bdfSopenharmony_ci struct sockaddr_in fsin; 429f08c3bdfSopenharmony_ci struct sockaddr_un fsun; 430f08c3bdfSopenharmony_ci fd_set afds, rfds; 431f08c3bdfSopenharmony_ci int nfds, fd; 432f08c3bdfSopenharmony_ci 433f08c3bdfSopenharmony_ci FD_ZERO(&afds); 434f08c3bdfSopenharmony_ci FD_SET(sfd, &afds); 435f08c3bdfSopenharmony_ci FD_SET(ufd, &afds); 436f08c3bdfSopenharmony_ci 437f08c3bdfSopenharmony_ci nfds = MAX(sfd + 1, ufd + 1); 438f08c3bdfSopenharmony_ci 439f08c3bdfSopenharmony_ci /* accept connections until killed */ 440f08c3bdfSopenharmony_ci while (1) { 441f08c3bdfSopenharmony_ci socklen_t fromlen; 442f08c3bdfSopenharmony_ci 443f08c3bdfSopenharmony_ci memcpy(&rfds, &afds, sizeof(rfds)); 444f08c3bdfSopenharmony_ci 445f08c3bdfSopenharmony_ci if (select(nfds, &rfds, NULL, NULL, 446f08c3bdfSopenharmony_ci NULL) < 0) { 447f08c3bdfSopenharmony_ci if (errno != EINTR) { 448f08c3bdfSopenharmony_ci perror("server select"); 449f08c3bdfSopenharmony_ci exit(1); 450f08c3bdfSopenharmony_ci } 451f08c3bdfSopenharmony_ci continue; 452f08c3bdfSopenharmony_ci } 453f08c3bdfSopenharmony_ci if (FD_ISSET(sfd, &rfds)) { 454f08c3bdfSopenharmony_ci int newfd; 455f08c3bdfSopenharmony_ci 456f08c3bdfSopenharmony_ci fromlen = sizeof(fsin); 457f08c3bdfSopenharmony_ci newfd = SAFE_ACCEPT(sfd, (struct sockaddr *)&fsin, &fromlen); 458f08c3bdfSopenharmony_ci if (newfd >= 0) { 459f08c3bdfSopenharmony_ci FD_SET(newfd, &afds); 460f08c3bdfSopenharmony_ci nfds = MAX(nfds, newfd + 1); 461f08c3bdfSopenharmony_ci /* send something back */ 462f08c3bdfSopenharmony_ci SAFE_SEND(1, newfd, "hi", 2, 0); 463f08c3bdfSopenharmony_ci } 464f08c3bdfSopenharmony_ci } 465f08c3bdfSopenharmony_ci if (FD_ISSET(ufd, &rfds)) { 466f08c3bdfSopenharmony_ci int newfd; 467f08c3bdfSopenharmony_ci 468f08c3bdfSopenharmony_ci fromlen = sizeof(fsun); 469f08c3bdfSopenharmony_ci newfd = SAFE_ACCEPT(ufd, (struct sockaddr *)&fsun, &fromlen); 470f08c3bdfSopenharmony_ci if (newfd >= 0) { 471f08c3bdfSopenharmony_ci FD_SET(newfd, &afds); 472f08c3bdfSopenharmony_ci nfds = MAX(nfds, newfd + 1); 473f08c3bdfSopenharmony_ci } 474f08c3bdfSopenharmony_ci } 475f08c3bdfSopenharmony_ci for (fd = 0; fd < nfds; ++fd) 476f08c3bdfSopenharmony_ci if (fd != sfd && fd != ufd && FD_ISSET(fd, &rfds)) { 477f08c3bdfSopenharmony_ci char rbuf[BUF_SIZE]; 478f08c3bdfSopenharmony_ci 479f08c3bdfSopenharmony_ci TEST(read(fd, rbuf, sizeof(rbuf))); 480f08c3bdfSopenharmony_ci if (TST_RET > 0 && rbuf[0] == 'R') 481f08c3bdfSopenharmony_ci sender(fd); 482f08c3bdfSopenharmony_ci if (TST_RET == 0 || (TST_RET < 0 && TST_ERR != EINTR)) { 483f08c3bdfSopenharmony_ci close(fd); 484f08c3bdfSopenharmony_ci FD_CLR(fd, &afds); 485f08c3bdfSopenharmony_ci } 486f08c3bdfSopenharmony_ci } 487f08c3bdfSopenharmony_ci } 488f08c3bdfSopenharmony_ci} 489f08c3bdfSopenharmony_ci 490f08c3bdfSopenharmony_cistatic struct tst_test test = { 491f08c3bdfSopenharmony_ci .test = run, 492f08c3bdfSopenharmony_ci .tcnt = ARRAY_SIZE(tcases), 493f08c3bdfSopenharmony_ci .forks_child = 1, 494f08c3bdfSopenharmony_ci .needs_tmpdir = 1, 495f08c3bdfSopenharmony_ci}; 496