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
set_nonblocking(uv_os_sock_t sock)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
close_cb(uv_handle_t * handle)60 static void close_cb(uv_handle_t* handle) {
61 close_called++;
62 }
63
64
alloc_cb(uv_handle_t * handle,size_t size,uv_buf_t * buf)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
read_cb(uv_stream_t * handle,ssize_t nread,const uv_buf_t * buf)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
TEST_IMPL(pipe_sendmsg)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
TEST_IMPL(pipe_sendmsg)167 TEST_IMPL(pipe_sendmsg) {
168 MAKE_VALGRIND_HAPPY();
169 return 0;
170 }
171
172 #endif /* _WIN32 */
173