|
160
|
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 "internal.h"
|
|
|
24
|
|
|
25 #include <assert.h>
|
|
|
26 #include <errno.h>
|
|
|
27 #include <string.h>
|
|
|
28 #include <sys/un.h>
|
|
|
29 #include <unistd.h>
|
|
|
30 #include <stdlib.h>
|
|
|
31
|
|
|
32
|
|
|
33 /* Does the file path contain embedded nul bytes? */
|
|
|
34 static int includes_invalid_nul(const char *s, size_t n) {
|
|
|
35 if (n == 0)
|
|
|
36 return 0;
|
|
|
37 #ifdef __linux__
|
|
|
38 /* Accept abstract socket namespace paths, throughout which nul bytes have
|
|
|
39 * no special significance ("\0foo\0bar").
|
|
|
40 */
|
|
|
41 if (s[0] == '\0')
|
|
|
42 return 0;
|
|
|
43 #endif
|
|
|
44 return NULL != memchr(s, '\0', n);
|
|
|
45 }
|
|
|
46
|
|
|
47
|
|
|
48 int uv_pipe_init(uv_loop_t* loop, uv_pipe_t* handle, int ipc) {
|
|
|
49 uv__stream_init(loop, (uv_stream_t*)handle, UV_NAMED_PIPE);
|
|
|
50 handle->shutdown_req = NULL;
|
|
|
51 handle->connect_req = NULL;
|
|
|
52 handle->pipe_fname = NULL;
|
|
|
53 handle->ipc = ipc;
|
|
|
54 return 0;
|
|
|
55 }
|
|
|
56
|
|
|
57
|
|
|
58 int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
|
|
|
59 return uv_pipe_bind2(handle, name, strlen(name), 0);
|
|
|
60 }
|
|
|
61
|
|
|
62
|
|
|
63 int uv_pipe_bind2(uv_pipe_t* handle,
|
|
|
64 const char* name,
|
|
|
65 size_t namelen,
|
|
|
66 unsigned int flags) {
|
|
|
67 struct sockaddr_un saddr;
|
|
|
68 char* pipe_fname;
|
|
|
69 int sockfd;
|
|
|
70 int err;
|
|
|
71 socklen_t addrlen;
|
|
|
72
|
|
|
73 pipe_fname = NULL;
|
|
|
74
|
|
|
75 if (flags & ~UV_PIPE_NO_TRUNCATE)
|
|
|
76 return UV_EINVAL;
|
|
|
77
|
|
|
78 if (name == NULL)
|
|
|
79 return UV_EINVAL;
|
|
|
80
|
|
|
81 /* namelen==0 on Linux means autobind the listen socket in the abstract
|
|
|
82 * socket namespace, see `man 7 unix` for details.
|
|
|
83 */
|
|
|
84 #if !defined(__linux__)
|
|
|
85 if (namelen == 0)
|
|
|
86 return UV_EINVAL;
|
|
|
87 #endif
|
|
|
88
|
|
|
89 if (includes_invalid_nul(name, namelen))
|
|
|
90 return UV_EINVAL;
|
|
|
91
|
|
|
92 if (flags & UV_PIPE_NO_TRUNCATE)
|
|
|
93 if (namelen > sizeof(saddr.sun_path))
|
|
|
94 return UV_EINVAL;
|
|
|
95
|
|
|
96 /* Truncate long paths. Documented behavior. */
|
|
|
97 if (namelen > sizeof(saddr.sun_path))
|
|
|
98 namelen = sizeof(saddr.sun_path);
|
|
|
99
|
|
|
100 /* Already bound? */
|
|
|
101 if (uv__stream_fd(handle) >= 0)
|
|
|
102 return UV_EINVAL;
|
|
|
103
|
|
|
104 if (uv__is_closing(handle))
|
|
|
105 return UV_EINVAL;
|
|
|
106
|
|
|
107 /* Make a copy of the file path unless it is an abstract socket.
|
|
|
108 * We unlink the file later but abstract sockets disappear
|
|
|
109 * automatically since they're not real file system entities.
|
|
|
110 */
|
|
|
111 if (*name == '\0') {
|
|
|
112 addrlen = offsetof(struct sockaddr_un, sun_path) + namelen;
|
|
|
113 } else {
|
|
|
114 pipe_fname = uv__malloc(namelen + 1);
|
|
|
115 if (pipe_fname == NULL)
|
|
|
116 return UV_ENOMEM;
|
|
|
117 memcpy(pipe_fname, name, namelen);
|
|
|
118 pipe_fname[namelen] = '\0';
|
|
|
119 addrlen = sizeof saddr;
|
|
|
120 }
|
|
|
121
|
|
|
122 err = uv__socket(AF_UNIX, SOCK_STREAM, 0);
|
|
|
123 if (err < 0)
|
|
|
124 goto err_socket;
|
|
|
125 sockfd = err;
|
|
|
126
|
|
|
127 memset(&saddr, 0, sizeof saddr);
|
|
|
128 memcpy(&saddr.sun_path, name, namelen);
|
|
|
129 saddr.sun_family = AF_UNIX;
|
|
|
130
|
|
|
131 if (bind(sockfd, (struct sockaddr*)&saddr, addrlen)) {
|
|
|
132 err = UV__ERR(errno);
|
|
|
133 /* Convert ENOENT to EACCES for compatibility with Windows. */
|
|
|
134 if (err == UV_ENOENT)
|
|
|
135 err = UV_EACCES;
|
|
|
136
|
|
|
137 uv__close(sockfd);
|
|
|
138 goto err_socket;
|
|
|
139 }
|
|
|
140
|
|
|
141 /* Success. */
|
|
|
142 handle->flags |= UV_HANDLE_BOUND;
|
|
|
143 handle->pipe_fname = pipe_fname; /* NULL or a copy of |name| */
|
|
|
144 handle->io_watcher.fd = sockfd;
|
|
|
145 return 0;
|
|
|
146
|
|
|
147 err_socket:
|
|
|
148 uv__free(pipe_fname);
|
|
|
149 return err;
|
|
|
150 }
|
|
|
151
|
|
|
152
|
|
|
153 int uv__pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) {
|
|
|
154 if (uv__stream_fd(handle) == -1)
|
|
|
155 return UV_EINVAL;
|
|
|
156
|
|
|
157 if (handle->ipc)
|
|
|
158 return UV_EINVAL;
|
|
|
159
|
|
|
160 #if defined(__MVS__) || defined(__PASE__)
|
|
|
161 /* On zOS, backlog=0 has undefined behaviour */
|
|
|
162 /* On IBMi PASE, backlog=0 leads to "Connection refused" error */
|
|
|
163 if (backlog == 0)
|
|
|
164 backlog = 1;
|
|
|
165 else if (backlog < 0)
|
|
|
166 backlog = SOMAXCONN;
|
|
|
167 #endif
|
|
|
168
|
|
|
169 if (listen(uv__stream_fd(handle), backlog))
|
|
|
170 return UV__ERR(errno);
|
|
|
171
|
|
|
172 handle->connection_cb = cb;
|
|
|
173 handle->io_watcher.cb = uv__server_io;
|
|
|
174 uv__io_start(handle->loop, &handle->io_watcher, POLLIN);
|
|
|
175 return 0;
|
|
|
176 }
|
|
|
177
|
|
|
178
|
|
|
179 void uv__pipe_close(uv_pipe_t* handle) {
|
|
|
180 if (handle->pipe_fname) {
|
|
|
181 /*
|
|
|
182 * Unlink the file system entity before closing the file descriptor.
|
|
|
183 * Doing it the other way around introduces a race where our process
|
|
|
184 * unlinks a socket with the same name that's just been created by
|
|
|
185 * another thread or process.
|
|
|
186 */
|
|
|
187 unlink(handle->pipe_fname);
|
|
|
188 uv__free((void*)handle->pipe_fname);
|
|
|
189 handle->pipe_fname = NULL;
|
|
|
190 }
|
|
|
191
|
|
|
192 uv__stream_close((uv_stream_t*)handle);
|
|
|
193 }
|
|
|
194
|
|
|
195
|
|
|
196 int uv_pipe_open(uv_pipe_t* handle, uv_file fd) {
|
|
|
197 int flags;
|
|
|
198 int mode;
|
|
|
199 int err;
|
|
|
200 flags = 0;
|
|
|
201
|
|
|
202 if (uv__fd_exists(handle->loop, fd))
|
|
|
203 return UV_EEXIST;
|
|
|
204
|
|
|
205 do
|
|
|
206 mode = fcntl(fd, F_GETFL);
|
|
|
207 while (mode == -1 && errno == EINTR);
|
|
|
208
|
|
|
209 if (mode == -1)
|
|
|
210 return UV__ERR(errno); /* according to docs, must be EBADF */
|
|
|
211
|
|
|
212 err = uv__nonblock(fd, 1);
|
|
|
213 if (err)
|
|
|
214 return err;
|
|
|
215
|
|
|
216 #if defined(__APPLE__)
|
|
|
217 err = uv__stream_try_select((uv_stream_t*) handle, &fd);
|
|
|
218 if (err)
|
|
|
219 return err;
|
|
|
220 #endif /* defined(__APPLE__) */
|
|
|
221
|
|
|
222 mode &= O_ACCMODE;
|
|
|
223 if (mode != O_WRONLY)
|
|
|
224 flags |= UV_HANDLE_READABLE;
|
|
|
225 if (mode != O_RDONLY)
|
|
|
226 flags |= UV_HANDLE_WRITABLE;
|
|
|
227
|
|
|
228 return uv__stream_open((uv_stream_t*)handle, fd, flags);
|
|
|
229 }
|
|
|
230
|
|
|
231
|
|
|
232 void uv_pipe_connect(uv_connect_t* req,
|
|
|
233 uv_pipe_t* handle,
|
|
|
234 const char* name,
|
|
|
235 uv_connect_cb cb) {
|
|
|
236 int err;
|
|
|
237
|
|
|
238 err = uv_pipe_connect2(req, handle, name, strlen(name), 0, cb);
|
|
|
239
|
|
|
240 if (err) {
|
|
|
241 handle->delayed_error = err;
|
|
|
242 handle->connect_req = req;
|
|
|
243
|
|
|
244 uv__req_init(handle->loop, req, UV_CONNECT);
|
|
|
245 req->handle = (uv_stream_t*) handle;
|
|
|
246 req->cb = cb;
|
|
|
247 uv__queue_init(&req->queue);
|
|
|
248
|
|
|
249 /* Force callback to run on next tick in case of error. */
|
|
|
250 uv__io_feed(handle->loop, &handle->io_watcher);
|
|
|
251 }
|
|
|
252 }
|
|
|
253
|
|
|
254
|
|
|
255 int uv_pipe_connect2(uv_connect_t* req,
|
|
|
256 uv_pipe_t* handle,
|
|
|
257 const char* name,
|
|
|
258 size_t namelen,
|
|
|
259 unsigned int flags,
|
|
|
260 uv_connect_cb cb) {
|
|
|
261 struct sockaddr_un saddr;
|
|
|
262 int new_sock;
|
|
|
263 int err;
|
|
|
264 int r;
|
|
|
265 socklen_t addrlen;
|
|
|
266
|
|
|
267 if (flags & ~UV_PIPE_NO_TRUNCATE)
|
|
|
268 return UV_EINVAL;
|
|
|
269
|
|
|
270 if (name == NULL)
|
|
|
271 return UV_EINVAL;
|
|
|
272
|
|
|
273 if (namelen == 0)
|
|
|
274 return UV_EINVAL;
|
|
|
275
|
|
|
276 if (includes_invalid_nul(name, namelen))
|
|
|
277 return UV_EINVAL;
|
|
|
278
|
|
|
279 if (flags & UV_PIPE_NO_TRUNCATE)
|
|
|
280 if (namelen > sizeof(saddr.sun_path))
|
|
|
281 return UV_EINVAL;
|
|
|
282
|
|
|
283 /* Truncate long paths. Documented behavior. */
|
|
|
284 if (namelen > sizeof(saddr.sun_path))
|
|
|
285 namelen = sizeof(saddr.sun_path);
|
|
|
286
|
|
|
287 new_sock = (uv__stream_fd(handle) == -1);
|
|
|
288
|
|
|
289 if (new_sock) {
|
|
|
290 err = uv__socket(AF_UNIX, SOCK_STREAM, 0);
|
|
|
291 if (err < 0)
|
|
|
292 goto out;
|
|
|
293 handle->io_watcher.fd = err;
|
|
|
294 }
|
|
|
295
|
|
|
296 memset(&saddr, 0, sizeof saddr);
|
|
|
297 memcpy(&saddr.sun_path, name, namelen);
|
|
|
298 saddr.sun_family = AF_UNIX;
|
|
|
299
|
|
|
300 if (*name == '\0')
|
|
|
301 addrlen = offsetof(struct sockaddr_un, sun_path) + namelen;
|
|
|
302 else
|
|
|
303 addrlen = sizeof saddr;
|
|
|
304
|
|
|
305 do {
|
|
|
306 r = connect(uv__stream_fd(handle), (struct sockaddr*)&saddr, addrlen);
|
|
|
307 }
|
|
|
308 while (r == -1 && errno == EINTR);
|
|
|
309
|
|
|
310 if (r == -1 && errno != EINPROGRESS) {
|
|
|
311 err = UV__ERR(errno);
|
|
|
312 #if defined(__CYGWIN__) || defined(__MSYS__)
|
|
|
313 /* EBADF is supposed to mean that the socket fd is bad, but
|
|
|
314 Cygwin reports EBADF instead of ENOTSOCK when the file is
|
|
|
315 not a socket. We do not expect to see a bad fd here
|
|
|
316 (e.g. due to new_sock), so translate the error. */
|
|
|
317 if (err == UV_EBADF)
|
|
|
318 err = UV_ENOTSOCK;
|
|
|
319 #endif
|
|
|
320 goto out;
|
|
|
321 }
|
|
|
322
|
|
|
323 err = 0;
|
|
|
324 if (new_sock) {
|
|
|
325 err = uv__stream_open((uv_stream_t*)handle,
|
|
|
326 uv__stream_fd(handle),
|
|
|
327 UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
|
|
|
328 }
|
|
|
329
|
|
|
330 if (err == 0)
|
|
|
331 uv__io_start(handle->loop, &handle->io_watcher, POLLOUT);
|
|
|
332
|
|
|
333 out:
|
|
|
334 handle->delayed_error = err;
|
|
|
335 handle->connect_req = req;
|
|
|
336
|
|
|
337 uv__req_init(handle->loop, req, UV_CONNECT);
|
|
|
338 req->handle = (uv_stream_t*) handle;
|
|
|
339 req->cb = cb;
|
|
|
340 uv__queue_init(&req->queue);
|
|
|
341
|
|
|
342 /* Force callback to run on next tick in case of error. */
|
|
|
343 if (err)
|
|
|
344 uv__io_feed(handle->loop, &handle->io_watcher);
|
|
|
345
|
|
|
346 return 0;
|
|
|
347 }
|
|
|
348
|
|
|
349
|
|
|
350 static int uv__pipe_getsockpeername(const uv_pipe_t* handle,
|
|
|
351 uv__peersockfunc func,
|
|
|
352 char* buffer,
|
|
|
353 size_t* size) {
|
|
|
354 #if defined(__linux__)
|
|
|
355 static const int is_linux = 1;
|
|
|
356 #else
|
|
|
357 static const int is_linux = 0;
|
|
|
358 #endif
|
|
|
359 struct sockaddr_un sa;
|
|
|
360 socklen_t addrlen;
|
|
|
361 size_t slop;
|
|
|
362 char* p;
|
|
|
363 int err;
|
|
|
364
|
|
|
365 if (buffer == NULL || size == NULL || *size == 0)
|
|
|
366 return UV_EINVAL;
|
|
|
367
|
|
|
368 addrlen = sizeof(sa);
|
|
|
369 memset(&sa, 0, addrlen);
|
|
|
370 err = uv__getsockpeername((const uv_handle_t*) handle,
|
|
|
371 func,
|
|
|
372 (struct sockaddr*) &sa,
|
|
|
373 (int*) &addrlen);
|
|
|
374 if (err < 0) {
|
|
|
375 *size = 0;
|
|
|
376 return err;
|
|
|
377 }
|
|
|
378
|
|
|
379 slop = 1;
|
|
|
380 if (is_linux && sa.sun_path[0] == '\0') {
|
|
|
381 /* Linux abstract namespace. Not zero-terminated. */
|
|
|
382 slop = 0;
|
|
|
383 addrlen -= offsetof(struct sockaddr_un, sun_path);
|
|
|
384 } else {
|
|
|
385 p = memchr(sa.sun_path, '\0', sizeof(sa.sun_path));
|
|
|
386 if (p == NULL)
|
|
|
387 p = ARRAY_END(sa.sun_path);
|
|
|
388 addrlen = p - sa.sun_path;
|
|
|
389 }
|
|
|
390
|
|
|
391 if ((size_t)addrlen + slop > *size) {
|
|
|
392 *size = addrlen + slop;
|
|
|
393 return UV_ENOBUFS;
|
|
|
394 }
|
|
|
395
|
|
|
396 memcpy(buffer, sa.sun_path, addrlen);
|
|
|
397 *size = addrlen;
|
|
|
398
|
|
|
399 /* only null-terminate if it's not an abstract socket */
|
|
|
400 if (buffer[0] != '\0')
|
|
|
401 buffer[addrlen] = '\0';
|
|
|
402
|
|
|
403 return 0;
|
|
|
404 }
|
|
|
405
|
|
|
406
|
|
|
407 int uv_pipe_getsockname(const uv_pipe_t* handle, char* buffer, size_t* size) {
|
|
|
408 return uv__pipe_getsockpeername(handle, getsockname, buffer, size);
|
|
|
409 }
|
|
|
410
|
|
|
411
|
|
|
412 int uv_pipe_getpeername(const uv_pipe_t* handle, char* buffer, size_t* size) {
|
|
|
413 return uv__pipe_getsockpeername(handle, getpeername, buffer, size);
|
|
|
414 }
|
|
|
415
|
|
|
416
|
|
|
417 void uv_pipe_pending_instances(uv_pipe_t* handle, int count) {
|
|
|
418 }
|
|
|
419
|
|
|
420
|
|
|
421 int uv_pipe_pending_count(uv_pipe_t* handle) {
|
|
|
422 uv__stream_queued_fds_t* queued_fds;
|
|
|
423
|
|
|
424 if (!handle->ipc)
|
|
|
425 return 0;
|
|
|
426
|
|
|
427 if (handle->accepted_fd == -1)
|
|
|
428 return 0;
|
|
|
429
|
|
|
430 if (handle->queued_fds == NULL)
|
|
|
431 return 1;
|
|
|
432
|
|
|
433 queued_fds = handle->queued_fds;
|
|
|
434 return queued_fds->offset + 1;
|
|
|
435 }
|
|
|
436
|
|
|
437
|
|
|
438 uv_handle_type uv_pipe_pending_type(uv_pipe_t* handle) {
|
|
|
439 if (!handle->ipc)
|
|
|
440 return UV_UNKNOWN_HANDLE;
|
|
|
441
|
|
|
442 if (handle->accepted_fd == -1)
|
|
|
443 return UV_UNKNOWN_HANDLE;
|
|
|
444 else
|
|
|
445 return uv_guess_handle(handle->accepted_fd);
|
|
|
446 }
|
|
|
447
|
|
|
448
|
|
|
449 int uv_pipe_chmod(uv_pipe_t* handle, int mode) {
|
|
|
450 char name_buffer[1 + UV__PATH_MAX];
|
|
|
451 int desired_mode;
|
|
|
452 size_t name_len;
|
|
|
453 const char* name;
|
|
|
454 int fd;
|
|
|
455 int r;
|
|
|
456
|
|
|
457 if (handle == NULL)
|
|
|
458 return UV_EBADF;
|
|
|
459
|
|
|
460 fd = uv__stream_fd(handle);
|
|
|
461 if (fd == -1)
|
|
|
462 return UV_EBADF;
|
|
|
463
|
|
|
464 if (mode != UV_READABLE &&
|
|
|
465 mode != UV_WRITABLE &&
|
|
|
466 mode != (UV_WRITABLE | UV_READABLE))
|
|
|
467 return UV_EINVAL;
|
|
|
468
|
|
|
469 desired_mode = 0;
|
|
|
470 if (mode & UV_READABLE)
|
|
|
471 desired_mode |= S_IRUSR | S_IRGRP | S_IROTH;
|
|
|
472 if (mode & UV_WRITABLE)
|
|
|
473 desired_mode |= S_IWUSR | S_IWGRP | S_IWOTH;
|
|
|
474
|
|
|
475 /* fchmod on macOS and (Free|Net|Open)BSD does not support UNIX sockets. */
|
|
|
476 if (fchmod(fd, desired_mode))
|
|
|
477 if (errno != EINVAL && errno != EOPNOTSUPP)
|
|
|
478 return UV__ERR(errno);
|
|
|
479
|
|
|
480 /* Fall back to chmod. */
|
|
|
481 name_len = sizeof(name_buffer);
|
|
|
482 r = uv_pipe_getsockname(handle, name_buffer, &name_len);
|
|
|
483 if (r != 0)
|
|
|
484 return r;
|
|
|
485 name = name_buffer;
|
|
|
486
|
|
|
487 /* On some platforms, getsockname returns an empty string, and we try with pipe_fname. */
|
|
|
488 if (name_len == 0 && handle->pipe_fname != NULL)
|
|
|
489 name = handle->pipe_fname;
|
|
|
490
|
|
|
491 if (chmod(name, desired_mode))
|
|
|
492 return UV__ERR(errno);
|
|
|
493
|
|
|
494 return 0;
|
|
|
495 }
|
|
|
496
|
|
|
497
|
|
|
498 int uv_pipe(uv_os_fd_t fds[2], int read_flags, int write_flags) {
|
|
|
499 uv_os_fd_t temp[2];
|
|
|
500 int err;
|
|
|
501 #if defined(__linux__) || \
|
|
|
502 defined(__FreeBSD__) || \
|
|
|
503 defined(__OpenBSD__) || \
|
|
|
504 defined(__DragonFly__) || \
|
|
|
505 defined(__NetBSD__) || \
|
|
|
506 defined(__illumos__) || \
|
|
|
507 (defined(UV__SOLARIS_11_4) && UV__SOLARIS_11_4)
|
|
|
508 int flags = O_CLOEXEC;
|
|
|
509
|
|
|
510 if ((read_flags & UV_NONBLOCK_PIPE) && (write_flags & UV_NONBLOCK_PIPE))
|
|
|
511 flags |= UV_FS_O_NONBLOCK;
|
|
|
512
|
|
|
513 if (pipe2(temp, flags))
|
|
|
514 return UV__ERR(errno);
|
|
|
515
|
|
|
516 if (flags & UV_FS_O_NONBLOCK) {
|
|
|
517 fds[0] = temp[0];
|
|
|
518 fds[1] = temp[1];
|
|
|
519 return 0;
|
|
|
520 }
|
|
|
521 #else
|
|
|
522 if (pipe(temp))
|
|
|
523 return UV__ERR(errno);
|
|
|
524
|
|
|
525 if ((err = uv__cloexec(temp[0], 1)))
|
|
|
526 goto fail;
|
|
|
527
|
|
|
528 if ((err = uv__cloexec(temp[1], 1)))
|
|
|
529 goto fail;
|
|
|
530 #endif
|
|
|
531
|
|
|
532 if (read_flags & UV_NONBLOCK_PIPE)
|
|
|
533 if ((err = uv__nonblock(temp[0], 1)))
|
|
|
534 goto fail;
|
|
|
535
|
|
|
536 if (write_flags & UV_NONBLOCK_PIPE)
|
|
|
537 if ((err = uv__nonblock(temp[1], 1)))
|
|
|
538 goto fail;
|
|
|
539
|
|
|
540 fds[0] = temp[0];
|
|
|
541 fds[1] = temp[1];
|
|
|
542 return 0;
|
|
|
543
|
|
|
544 fail:
|
|
|
545 uv__close(temp[0]);
|
|
|
546 uv__close(temp[1]);
|
|
|
547 return err;
|
|
|
548 }
|
|
|
549
|
|
|
550
|
|
|
551 int uv__make_pipe(int fds[2], int flags) {
|
|
|
552 return uv_pipe(fds,
|
|
|
553 flags & UV_NONBLOCK_PIPE,
|
|
|
554 flags & UV_NONBLOCK_PIPE);
|
|
|
555 }
|