Mercurial
comparison third_party/libuv/src/unix/pipe.c @ 160:948de3f54cea
[ThirdParty] Added libuv
| author | June Park <parkjune1995@gmail.com> |
|---|---|
| date | Wed, 14 Jan 2026 19:39:52 -0800 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 159:05cf9467a1c3 | 160:948de3f54cea |
|---|---|
| 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 } |