1 /* Copyright Joyent, Inc. and other Node contributors. All rights reserved. 2 * 3 * Permission is hereby granted, free of charge, to any person obtaining a copy 4 * of this software and associated documentation files (the "Software"), to 5 * deal in the Software without restriction, including without limitation the 6 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 * sell copies of the Software, and to permit persons to whom the Software is 8 * furnished to do so, subject to the following conditions: 9 * 10 * The above copyright notice and this permission notice shall be included in 11 * all copies or substantial portions of the Software. 12 * 13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 * IN THE SOFTWARE. 20 */ 21 22 #include "uv.h" 23 #include "task.h" 24 25 26 #ifndef _WIN32 27 28 #include <fcntl.h> 29 #include <errno.h> 30 #include <stdio.h> 31 #include <stdlib.h> 32 #include <string.h> 33 #include <sys/socket.h> 34 #include <unistd.h> 35 36 37 /* NOTE: size should be divisible by 2 */ 38 static uv_pipe_t incoming[4]; 39 static unsigned int incoming_count; 40 static unsigned int close_called; 41 42 43 static void set_nonblocking(uv_os_sock_t sock) { 44 int r; 45 #ifdef _WIN32 46 unsigned long on = 1; 47 r = ioctlsocket(sock, FIONBIO, &on); 48 ASSERT(r == 0); 49 #else 50 int flags = fcntl(sock, F_GETFL, 0); 51 ASSERT(flags >= 0); 52 r = fcntl(sock, F_SETFL, flags | O_NONBLOCK); 53 ASSERT(r >= 0); 54 #endif 55 } 56 57 58 59 60 static void close_cb(uv_handle_t* handle) { 61 close_called++; 62 } 63 64 65 static void alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) { 66 static char base[1]; 67 68 buf->base = base; 69 buf->len = sizeof(base); 70 } 71 72 73 static void read_cb(uv_stream_t* handle, 74 ssize_t nread, 75 const uv_buf_t* buf) { 76 uv_pipe_t* p; 77 uv_pipe_t* inc; 78 uv_handle_type pending; 79 unsigned int i; 80 81 p = (uv_pipe_t*) handle; 82 ASSERT(nread >= 0); 83 84 while (uv_pipe_pending_count(p) != 0) { 85 pending = uv_pipe_pending_type(p); 86 ASSERT(pending == UV_NAMED_PIPE); 87 88 ASSERT(incoming_count < ARRAY_SIZE(incoming)); 89 inc = &incoming[incoming_count++]; 90 ASSERT(0 == uv_pipe_init(p->loop, inc, 0)); 91 ASSERT(0 == uv_accept(handle, (uv_stream_t*) inc)); 92 } 93 94 if (incoming_count != ARRAY_SIZE(incoming)) 95 return; 96 97 ASSERT(0 == uv_read_stop((uv_stream_t*) p)); 98 uv_close((uv_handle_t*) p, close_cb); 99 for (i = 0; i < ARRAY_SIZE(incoming); i++) 100 uv_close((uv_handle_t*) &incoming[i], close_cb); 101 } 102 103 104 TEST_IMPL(pipe_sendmsg) { 105 #if defined(NO_SEND_HANDLE_ON_PIPE) 106 RETURN_SKIP(NO_SEND_HANDLE_ON_PIPE); 107 #endif 108 uv_pipe_t p; 109 int r; 110 int fds[2]; 111 int send_fds[ARRAY_SIZE(incoming)]; 112 struct msghdr msg; 113 char scratch[64]; 114 struct cmsghdr *cmsg; 115 unsigned int i; 116 uv_buf_t buf; 117 118 ASSERT(0 == socketpair(AF_UNIX, SOCK_STREAM, 0, fds)); 119 for (i = 0; i < ARRAY_SIZE(send_fds); i += 2) 120 ASSERT(0 == socketpair(AF_UNIX, SOCK_STREAM, 0, send_fds + i)); 121 ASSERT(i == ARRAY_SIZE(send_fds)); 122 ASSERT(0 == uv_pipe_init(uv_default_loop(), &p, 1)); 123 ASSERT(0 == uv_pipe_open(&p, fds[1])); 124 125 buf = uv_buf_init("X", 1); 126 memset(&msg, 0, sizeof(msg)); 127 msg.msg_iov = (struct iovec*) &buf; 128 msg.msg_iovlen = 1; 129 msg.msg_flags = 0; 130 131 msg.msg_control = (void*) scratch; 132 msg.msg_controllen = CMSG_LEN(sizeof(send_fds)); 133 ASSERT(sizeof(scratch) >= msg.msg_controllen); 134 135 cmsg = CMSG_FIRSTHDR(&msg); 136 cmsg->cmsg_level = SOL_SOCKET; 137 cmsg->cmsg_type = SCM_RIGHTS; 138 cmsg->cmsg_len = msg.msg_controllen; 139 140 /* silence aliasing warning */ 141 { 142 void* pv = CMSG_DATA(cmsg); 143 int* pi = pv; 144 for (i = 0; i < ARRAY_SIZE(send_fds); i++) 145 pi[i] = send_fds[i]; 146 } 147 148 set_nonblocking(fds[1]); 149 ASSERT(0 == uv_read_start((uv_stream_t*) &p, alloc_cb, read_cb)); 150 151 do 152 r = sendmsg(fds[0], &msg, 0); 153 while (r == -1 && errno == EINTR); 154 ASSERT(r == 1); 155 156 uv_run(uv_default_loop(), UV_RUN_DEFAULT); 157 ASSERT(ARRAY_SIZE(incoming) == incoming_count); 158 ASSERT(ARRAY_SIZE(incoming) + 1 == close_called); 159 close(fds[0]); 160 161 MAKE_VALGRIND_HAPPY(); 162 return 0; 163 } 164 165 #else /* !_WIN32 */ 166 167 TEST_IMPL(pipe_sendmsg) { 168 MAKE_VALGRIND_HAPPY(); 169 return 0; 170 } 171 172 #endif /* _WIN32 */ 173