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#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27
28#ifndef _WIN32
29# include <unistd.h>  /* close */
30#else
31# include <fcntl.h>
32#endif
33
34static uv_pipe_t pipe_client;
35static uv_pipe_t pipe_server;
36static uv_connect_t connect_req;
37
38static int pipe_close_cb_called = 0;
39static int pipe_client_connect_cb_called = 0;
40
41
42static void pipe_close_cb(uv_handle_t* handle) {
43  ASSERT_NE(handle == (uv_handle_t*) &pipe_client ||
44            handle == (uv_handle_t*) &pipe_server, 0);
45  pipe_close_cb_called++;
46}
47
48
49static void pipe_client_connect_cb(uv_connect_t* req, int status) {
50  char buf[1024];
51  size_t len;
52  int r;
53
54  ASSERT_PTR_EQ(req, &connect_req);
55  ASSERT_OK(status);
56
57  len = sizeof buf;
58  r = uv_pipe_getpeername(&pipe_client, buf, &len);
59  ASSERT_OK(r);
60
61  if (*buf == '\0') {  /* Linux abstract socket. */
62    const char expected[] = "\0" TEST_PIPENAME;
63    ASSERT_EQ(len, sizeof(expected) - 1);
64    ASSERT_MEM_EQ(buf, expected, len);
65  } else {
66    ASSERT_NE(0, buf[len - 1]);
67    ASSERT_MEM_EQ(buf, TEST_PIPENAME, len);
68  }
69
70  len = sizeof buf;
71  r = uv_pipe_getsockname(&pipe_client, buf, &len);
72  ASSERT(r == 0 && len == 0);
73
74  pipe_client_connect_cb_called++;
75
76  uv_close((uv_handle_t*) &pipe_client, pipe_close_cb);
77  uv_close((uv_handle_t*) &pipe_server, pipe_close_cb);
78}
79
80
81static void pipe_server_connection_cb(uv_stream_t* handle, int status) {
82  /* This function *may* be called, depending on whether accept or the
83   * connection callback is called first.
84   */
85  ASSERT_OK(status);
86}
87
88
89TEST_IMPL(pipe_getsockname) {
90#if defined(NO_SELF_CONNECT)
91  RETURN_SKIP(NO_SELF_CONNECT);
92#endif
93  uv_loop_t* loop;
94  char namebuf[256];
95  char buf[1024];
96  size_t namelen;
97  size_t len;
98  int r;
99
100  snprintf(namebuf, sizeof(namebuf), "%s-oob", TEST_PIPENAME);
101  namelen = sizeof(TEST_PIPENAME) - 1;
102
103  loop = uv_default_loop();
104  ASSERT_NOT_NULL(loop);
105
106  r = uv_pipe_init(loop, &pipe_server, 0);
107  ASSERT_OK(r);
108
109  r = uv_pipe_bind2(&pipe_server, "bad\0path", 8, 0);
110  ASSERT_EQ(r, UV_EINVAL);
111
112  len = sizeof buf;
113  r = uv_pipe_getsockname(&pipe_server, buf, &len);
114  ASSERT_EQ(r, UV_EBADF);
115
116  len = sizeof buf;
117  r = uv_pipe_getpeername(&pipe_server, buf, &len);
118  ASSERT_EQ(r, UV_EBADF);
119
120  r = uv_pipe_bind2(&pipe_server, namebuf, namelen, 0);
121  ASSERT_OK(r);
122
123#ifndef _WIN32
124  ASSERT_STR_EQ(pipe_server.pipe_fname, TEST_PIPENAME);
125#endif
126
127  len = sizeof buf;
128  r = uv_pipe_getsockname(&pipe_server, buf, &len);
129  ASSERT_OK(r);
130
131  ASSERT_NE(0, buf[len - 1]);
132  ASSERT_EQ(buf[len], '\0');
133  ASSERT_OK(memcmp(buf, TEST_PIPENAME, len));
134
135  len = sizeof buf;
136  r = uv_pipe_getpeername(&pipe_server, buf, &len);
137  ASSERT_EQ(r, UV_ENOTCONN);
138
139  r = uv_listen((uv_stream_t*) &pipe_server, 0, pipe_server_connection_cb);
140  ASSERT_OK(r);
141
142  r = uv_pipe_init(loop, &pipe_client, 0);
143  ASSERT_OK(r);
144
145  len = sizeof buf;
146  r = uv_pipe_getsockname(&pipe_client, buf, &len);
147  ASSERT_EQ(r, UV_EBADF);
148
149  len = sizeof buf;
150  r = uv_pipe_getpeername(&pipe_client, buf, &len);
151  ASSERT_EQ(r, UV_EBADF);
152
153  r = uv_pipe_connect2(&connect_req,
154                       &pipe_client,
155                       namebuf,
156                       namelen,
157                       0,
158                       pipe_client_connect_cb);
159  ASSERT_OK(r);
160
161  len = sizeof buf;
162  r = uv_pipe_getsockname(&pipe_client, buf, &len);
163  ASSERT(r == 0 && len == 0);
164
165  len = sizeof buf;
166  r = uv_pipe_getpeername(&pipe_client, buf, &len);
167  ASSERT_OK(r);
168
169  ASSERT_NE(0, buf[len - 1]);
170  ASSERT_OK(memcmp(buf, TEST_PIPENAME, len));
171
172  r = uv_run(loop, UV_RUN_DEFAULT);
173  ASSERT_OK(r);
174  ASSERT_EQ(1, pipe_client_connect_cb_called);
175  ASSERT_EQ(2, pipe_close_cb_called);
176
177  MAKE_VALGRIND_HAPPY(loop);
178  return 0;
179}
180
181
182TEST_IMPL(pipe_getsockname_abstract) {
183  /* TODO(bnoordhuis) Use unique name, susceptible to concurrent test runs. */
184  static const char name[] = "\0" TEST_PIPENAME;
185#if defined(__linux__)
186  char buf[256];
187  size_t buflen;
188
189  buflen = sizeof(buf);
190  memset(buf, 0, sizeof(buf));
191  ASSERT_OK(uv_pipe_init(uv_default_loop(), &pipe_server, 0));
192  ASSERT_OK(uv_pipe_bind2(&pipe_server, name, sizeof(name) - 1, 0));
193  ASSERT_OK(uv_pipe_getsockname(&pipe_server, buf, &buflen));
194  ASSERT_UINT64_EQ(sizeof(name) - 1, buflen);
195  ASSERT_MEM_EQ(name, buf, buflen);
196  ASSERT_OK(uv_listen((uv_stream_t*) &pipe_server,
197                      0,
198                      pipe_server_connection_cb));
199  ASSERT_OK(uv_pipe_init(uv_default_loop(), &pipe_client, 0));
200  ASSERT_OK(uv_pipe_connect2(&connect_req,
201                             &pipe_client,
202                             name,
203                             sizeof(name) - 1,
204                             0,
205                             pipe_client_connect_cb));
206  ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT));
207  ASSERT_EQ(1, pipe_client_connect_cb_called);
208  ASSERT_EQ(2, pipe_close_cb_called);
209  MAKE_VALGRIND_HAPPY(uv_default_loop());
210  return 0;
211#else
212  /* On other platforms it should simply fail with UV_EINVAL. */
213  ASSERT_OK(uv_pipe_init(uv_default_loop(), &pipe_server, 0));
214  ASSERT_EQ(UV_EINVAL, uv_pipe_bind2(&pipe_server, name, sizeof(name), 0));
215  ASSERT_OK(uv_pipe_init(uv_default_loop(), &pipe_client, 0));
216  uv_close((uv_handle_t*) &pipe_server, pipe_close_cb);
217  ASSERT_EQ(UV_EINVAL, uv_pipe_connect2(&connect_req,
218                                        &pipe_client,
219                                        name,
220                                        sizeof(name),
221                                        0,
222                                        (uv_connect_cb) abort));
223  uv_close((uv_handle_t*) &pipe_client, pipe_close_cb);
224  ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT));
225  ASSERT_EQ(2, pipe_close_cb_called);
226  MAKE_VALGRIND_HAPPY(uv_default_loop());
227  return 0;
228#endif
229}
230
231TEST_IMPL(pipe_getsockname_blocking) {
232#ifdef _WIN32
233  HANDLE readh, writeh;
234  int readfd;
235  char buf1[1024], buf2[1024];
236  size_t len1, len2;
237  int r;
238
239  r = CreatePipe(&readh, &writeh, NULL, 65536);
240  ASSERT(r);
241
242  r = uv_pipe_init(uv_default_loop(), &pipe_client, 0);
243  ASSERT_OK(r);
244  readfd = _open_osfhandle((intptr_t)readh, _O_RDONLY);
245  ASSERT_NE(r, -1);
246  r = uv_pipe_open(&pipe_client, readfd);
247  ASSERT_OK(r);
248  r = uv_read_start((uv_stream_t*) &pipe_client,
249                    (uv_alloc_cb) abort,
250                    (uv_read_cb) abort);
251  ASSERT_OK(r);
252  Sleep(100);
253  r = uv_read_stop((uv_stream_t*)&pipe_client);
254  ASSERT_OK(r);
255
256  len1 = sizeof buf1;
257  r = uv_pipe_getsockname(&pipe_client, buf1, &len1);
258  ASSERT_OK(r);
259  ASSERT_OK(len1);  /* It's an annonymous pipe. */
260
261  r = uv_read_start((uv_stream_t*)&pipe_client,
262                    (uv_alloc_cb) abort,
263                    (uv_read_cb) abort);
264  ASSERT_OK(r);
265  Sleep(100);
266
267  len2 = sizeof buf2;
268  r = uv_pipe_getsockname(&pipe_client, buf2, &len2);
269  ASSERT_OK(r);
270  ASSERT_OK(len2);  /* It's an annonymous pipe. */
271
272  r = uv_read_stop((uv_stream_t*)&pipe_client);
273  ASSERT_OK(r);
274
275  ASSERT_EQ(len1, len2);
276  ASSERT_OK(memcmp(buf1, buf2, len1));
277
278  pipe_close_cb_called = 0;
279  uv_close((uv_handle_t*)&pipe_client, pipe_close_cb);
280
281  uv_run(uv_default_loop(), UV_RUN_DEFAULT);
282
283  ASSERT_EQ(1, pipe_close_cb_called);
284
285  CloseHandle(writeh);
286#endif
287
288  MAKE_VALGRIND_HAPPY(uv_default_loop());
289  return 0;
290}
291