1 /* $OpenBSD: mcontrol-stream.c,v 1.1 2018/12/19 21:21:59 bluhm Exp $ */ 2 /* 3 * Copyright (c) 2018 Alexander Bluhm <bluhm@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/socket.h> 19 #include <sys/wait.h> 20 21 #include <err.h> 22 #include <fcntl.h> 23 #include <string.h> 24 #include <unistd.h> 25 26 int 27 main(int argc, char *argv[]) 28 { 29 pid_t pid; 30 int fd, s[2], status; 31 char str[] = "foo"; 32 struct msghdr msg; 33 struct cmsghdr *cmsg; 34 union { 35 struct cmsghdr hdr; 36 unsigned char buf[CMSG_SPACE(sizeof(int))]; 37 } cmsgbuf; 38 struct iovec io_vector[1]; 39 40 if ((fd = open("/dev/null", O_RDONLY)) == -1) 41 err(1, "open"); 42 if (socketpair(AF_UNIX, SOCK_STREAM, 0, s) == -1) 43 err(1, "socketpair"); 44 45 if ((pid = fork()) == -1) 46 err(1, "fork"); 47 if (pid == 0) { 48 char buf[16]; 49 ssize_t n; 50 51 /* 52 * The first recv(2) will block until the second control 53 * message causes a short read. 54 */ 55 if ((n = recv(s[1], buf, sizeof(buf), MSG_WAITALL)) == -1) 56 err(1, "recv 1"); 57 if ((size_t)n != strlen(str)) 58 errx(1, "recv 1: len %zd", n); 59 if ((n = recv(s[1], buf, sizeof(buf), 0)) == -1) 60 err(1, "recv 2"); 61 if ((size_t)n != strlen(str)) 62 errx(1, "recv 2: len %zd", n); 63 _exit(0); 64 } 65 66 io_vector[0].iov_base = str; 67 io_vector[0].iov_len = strlen(str); 68 69 memset(&msg, 0, sizeof(msg)); 70 msg.msg_control = &cmsgbuf.buf; 71 msg.msg_controllen = sizeof(cmsgbuf.buf); 72 msg.msg_iov = io_vector; 73 msg.msg_iovlen = 1; 74 75 cmsg = CMSG_FIRSTHDR(&msg); 76 cmsg->cmsg_len = CMSG_LEN(sizeof(int)); 77 cmsg->cmsg_level = SOL_SOCKET; 78 cmsg->cmsg_type = SCM_RIGHTS; 79 *(int *)CMSG_DATA(cmsg) = fd; 80 81 if (sendmsg(s[0], &msg, 0) == -1) 82 err(1, "sendmsg 1"); 83 84 /* Wait until child is blocking in recv(2) MSG_WAITALL syscall. */ 85 sleep(2); 86 87 /* This will insert a control mbuf while soreceive() is sleeping. */ 88 if (sendmsg(s[0], &msg, 0) == -1) 89 err(1, "sendmsg 2"); 90 91 if (close(s[0]) == -1) 92 err(1, "close"); 93 94 if (waitpid(pid, &status, 0) == -1) 95 err(1, "waitpid"); 96 if (status != 0) 97 errx(1, "child: %d", status); 98 99 return 0; 100 } 101