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 
39 static uv_pipe_t pipe_client;
40 static uv_pipe_t pipe_server;
41 static uv_connect_t connect_req;
42 
43 static int pipe_close_cb_called = 0;
44 static int pipe_client_connect_cb_called = 0;
45 
46 
pipe_close_cb(uv_handle_t * handle)47 static 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 
pipe_client_connect_cb(uv_connect_t * req,int status)54 static 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 
pipe_server_connection_cb(uv_stream_t * handle,int status)81 static 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 
TEST_IMPL(pipe_getsockname)89 TEST_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(loop != NULL);
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 
TEST_IMPL(pipe_getsockname_abstract)164 TEST_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_LOCAL, 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 
TEST_IMPL(pipe_getsockname_blocking)211 TEST_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, NULL, NULL);
229   ASSERT(r == 0);
230   Sleep(100);
231   r = uv_read_stop((uv_stream_t*)&pipe_client);
232   ASSERT(r == 0);
233 
234   len1 = sizeof buf1;
235   r = uv_pipe_getsockname(&pipe_client, buf1, &len1);
236   ASSERT(r == 0);
237   ASSERT(len1 == 0);  /* It's an annonymous pipe. */
238 
239   r = uv_read_start((uv_stream_t*)&pipe_client, NULL, NULL);
240   ASSERT(r == 0);
241   Sleep(100);
242 
243   len2 = sizeof buf2;
244   r = uv_pipe_getsockname(&pipe_client, buf2, &len2);
245   ASSERT(r == 0);
246   ASSERT(len2 == 0);  /* It's an annonymous pipe. */
247 
248   r = uv_read_stop((uv_stream_t*)&pipe_client);
249   ASSERT(r == 0);
250 
251   ASSERT(len1 == len2);
252   ASSERT(memcmp(buf1, buf2, len1) == 0);
253 
254   pipe_close_cb_called = 0;
255   uv_close((uv_handle_t*)&pipe_client, pipe_close_cb);
256 
257   uv_run(uv_default_loop(), UV_RUN_DEFAULT);
258 
259   ASSERT(pipe_close_cb_called == 1);
260 
261   CloseHandle(writeh);
262 #endif
263 
264   MAKE_VALGRIND_HAPPY();
265   return 0;
266 }
267