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#if defined(__linux__)
29  #include <sys/socket.h>
30  #include <sys/un.h>
31#endif
32
33#ifndef _WIN32
34# include <unistd.h>  /* close */
35#else
36# include <fcntl.h>
37#endif
38
39static uv_pipe_t pipe_client;
40static uv_pipe_t pipe_server;
41static uv_connect_t connect_req;
42
43static int pipe_close_cb_called = 0;
44static int pipe_client_connect_cb_called = 0;
45
46
47static void pipe_close_cb(uv_handle_t* handle) {
48  ASSERT(handle == (uv_handle_t*) &pipe_client ||
49         handle == (uv_handle_t*) &pipe_server);
50  pipe_close_cb_called++;
51}
52
53
54static void pipe_client_connect_cb(uv_connect_t* req, int status) {
55  char buf[1024];
56  size_t len;
57  int r;
58
59  ASSERT(req == &connect_req);
60  ASSERT(status == 0);
61
62  len = sizeof buf;
63  r = uv_pipe_getpeername(&pipe_client, buf, &len);
64  ASSERT(r == 0);
65
66  ASSERT(buf[len - 1] != 0);
67  ASSERT(memcmp(buf, TEST_PIPENAME, len) == 0);
68
69  len = sizeof buf;
70  r = uv_pipe_getsockname(&pipe_client, buf, &len);
71  ASSERT(r == 0 && len == 0);
72
73  pipe_client_connect_cb_called++;
74
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(status == 0);
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 buf[1024];
95  size_t len;
96  int r;
97
98  loop = uv_default_loop();
99  ASSERT_NOT_NULL(loop);
100
101  r = uv_pipe_init(loop, &pipe_server, 0);
102  ASSERT(r == 0);
103
104  len = sizeof buf;
105  r = uv_pipe_getsockname(&pipe_server, buf, &len);
106  ASSERT(r == UV_EBADF);
107
108  len = sizeof buf;
109  r = uv_pipe_getpeername(&pipe_server, buf, &len);
110  ASSERT(r == UV_EBADF);
111
112  r = uv_pipe_bind(&pipe_server, TEST_PIPENAME);
113  ASSERT(r == 0);
114
115  len = sizeof buf;
116  r = uv_pipe_getsockname(&pipe_server, buf, &len);
117  ASSERT(r == 0);
118
119  ASSERT(buf[len - 1] != 0);
120  ASSERT(buf[len] == '\0');
121  ASSERT(memcmp(buf, TEST_PIPENAME, len) == 0);
122
123  len = sizeof buf;
124  r = uv_pipe_getpeername(&pipe_server, buf, &len);
125  ASSERT(r == UV_ENOTCONN);
126
127  r = uv_listen((uv_stream_t*) &pipe_server, 0, pipe_server_connection_cb);
128  ASSERT(r == 0);
129
130  r = uv_pipe_init(loop, &pipe_client, 0);
131  ASSERT(r == 0);
132
133  len = sizeof buf;
134  r = uv_pipe_getsockname(&pipe_client, buf, &len);
135  ASSERT(r == UV_EBADF);
136
137  len = sizeof buf;
138  r = uv_pipe_getpeername(&pipe_client, buf, &len);
139  ASSERT(r == UV_EBADF);
140
141  uv_pipe_connect(&connect_req, &pipe_client, TEST_PIPENAME, pipe_client_connect_cb);
142
143  len = sizeof buf;
144  r = uv_pipe_getsockname(&pipe_client, buf, &len);
145  ASSERT(r == 0 && len == 0);
146
147  len = sizeof buf;
148  r = uv_pipe_getpeername(&pipe_client, buf, &len);
149  ASSERT(r == 0);
150
151  ASSERT(buf[len - 1] != 0);
152  ASSERT(memcmp(buf, TEST_PIPENAME, len) == 0);
153
154  r = uv_run(loop, UV_RUN_DEFAULT);
155  ASSERT(r == 0);
156  ASSERT(pipe_client_connect_cb_called == 1);
157  ASSERT(pipe_close_cb_called == 2);
158
159  MAKE_VALGRIND_HAPPY();
160  return 0;
161}
162
163
164TEST_IMPL(pipe_getsockname_abstract) {
165#if defined(__linux__)
166  char buf[1024];
167  size_t len;
168  int r;
169  int sock;
170  struct sockaddr_un sun;
171  socklen_t sun_len;
172  char abstract_pipe[] = "\0test-pipe";
173
174  sock = socket(AF_UNIX, SOCK_STREAM, 0);
175  ASSERT(sock != -1);
176
177  sun_len = sizeof sun;
178  memset(&sun, 0, sun_len);
179  sun.sun_family = AF_UNIX;
180  memcpy(sun.sun_path, abstract_pipe, sizeof abstract_pipe);
181
182  r = bind(sock, (struct sockaddr*)&sun, sun_len);
183  ASSERT(r == 0);
184
185  r = uv_pipe_init(uv_default_loop(), &pipe_server, 0);
186  ASSERT(r == 0);
187  r = uv_pipe_open(&pipe_server, sock);
188  ASSERT(r == 0);
189
190  len = sizeof buf;
191  r = uv_pipe_getsockname(&pipe_server, buf, &len);
192  ASSERT(r == 0);
193
194  ASSERT(memcmp(buf, abstract_pipe, sizeof abstract_pipe) == 0);
195
196  uv_close((uv_handle_t*)&pipe_server, pipe_close_cb);
197
198  uv_run(uv_default_loop(), UV_RUN_DEFAULT);
199
200  close(sock);
201
202  ASSERT(pipe_close_cb_called == 1);
203  MAKE_VALGRIND_HAPPY();
204  return 0;
205#else
206  MAKE_VALGRIND_HAPPY();
207  return 0;
208#endif
209}
210
211TEST_IMPL(pipe_getsockname_blocking) {
212#ifdef _WIN32
213  HANDLE readh, writeh;
214  int readfd;
215  char buf1[1024], buf2[1024];
216  size_t len1, len2;
217  int r;
218
219  r = CreatePipe(&readh, &writeh, NULL, 65536);
220  ASSERT(r != 0);
221
222  r = uv_pipe_init(uv_default_loop(), &pipe_client, 0);
223  ASSERT(r == 0);
224  readfd = _open_osfhandle((intptr_t)readh, _O_RDONLY);
225  ASSERT(r != -1);
226  r = uv_pipe_open(&pipe_client, readfd);
227  ASSERT(r == 0);
228  r = uv_read_start((uv_stream_t*) &pipe_client,
229                    (uv_alloc_cb) abort,
230                    (uv_read_cb) abort);
231  ASSERT(r == 0);
232  Sleep(100);
233  r = uv_read_stop((uv_stream_t*)&pipe_client);
234  ASSERT(r == 0);
235
236  len1 = sizeof buf1;
237  r = uv_pipe_getsockname(&pipe_client, buf1, &len1);
238  ASSERT(r == 0);
239  ASSERT(len1 == 0);  /* It's an annonymous pipe. */
240
241  r = uv_read_start((uv_stream_t*)&pipe_client,
242                    (uv_alloc_cb) abort,
243                    (uv_read_cb) abort);
244  ASSERT(r == 0);
245  Sleep(100);
246
247  len2 = sizeof buf2;
248  r = uv_pipe_getsockname(&pipe_client, buf2, &len2);
249  ASSERT(r == 0);
250  ASSERT(len2 == 0);  /* It's an annonymous pipe. */
251
252  r = uv_read_stop((uv_stream_t*)&pipe_client);
253  ASSERT(r == 0);
254
255  ASSERT(len1 == len2);
256  ASSERT(memcmp(buf1, buf2, len1) == 0);
257
258  pipe_close_cb_called = 0;
259  uv_close((uv_handle_t*)&pipe_client, pipe_close_cb);
260
261  uv_run(uv_default_loop(), UV_RUN_DEFAULT);
262
263  ASSERT(pipe_close_cb_called == 1);
264
265  CloseHandle(writeh);
266#endif
267
268  MAKE_VALGRIND_HAPPY();
269  return 0;
270}
271