int uv__stream_open(uv_stream_t* stream, int fd, int flags) { assert(fd >= 0); stream->flags |= flags; if (stream->type == UV_TCP) { if ((stream->flags & UV_TCP_NODELAY) && uv__tcp_nodelay(fd, 1)) return uv__set_sys_error(stream->loop, errno); /* TODO Use delay the user passed in. */ if ((stream->flags & UV_TCP_KEEPALIVE) && uv__tcp_keepalive(fd, 1, 60)) return uv__set_sys_error(stream->loop, errno); } #if defined(__APPLE__) { uv__stream_select_t* s; int r; r = uv__stream_try_select(stream, fd); if (r == -1) return r; s = stream->select; if (s != NULL) fd = s->fake_fd; } #endif /* defined(__APPLE__) */ stream->io_watcher.fd = fd; return 0; }
int uv_pipe_open(uv_pipe_t* handle, uv_os_fd_t fd) { int flags; int mode; int err; flags = 0; if (uv__fd_exists(handle->loop, fd)) return UV_EEXIST; do mode = fcntl(fd, F_GETFL); while (mode == -1 && errno == EINTR); if (mode == -1) return UV__ERR(errno); /* according to docs, must be EBADF */ err = uv__nonblock(fd, 1); if (err) return err; #if defined(__APPLE__) err = uv__stream_try_select((uv_stream_t*) handle, &fd); if (err) return err; #endif /* defined(__APPLE__) */ mode &= O_ACCMODE; if (mode != O_WRONLY) flags |= UV_HANDLE_READABLE; if (mode != O_RDONLY) flags |= UV_HANDLE_WRITABLE; return uv__stream_open((uv_stream_t*)handle, fd, flags); }
int uv__stream_open(uv_stream_t* stream, int fd, int flags) { socklen_t yes; assert(fd >= 0); stream->fd = fd; stream->flags |= flags; if (stream->type == UV_TCP) { /* Reuse the port address if applicable. */ yes = 1; if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes) == -1) { uv__set_sys_error(stream->loop, errno); return -1; } if ((stream->flags & UV_TCP_NODELAY) && uv__tcp_nodelay((uv_tcp_t*)stream, 1)) { return -1; } /* TODO Use delay the user passed in. */ if ((stream->flags & UV_TCP_KEEPALIVE) && uv__tcp_keepalive((uv_tcp_t*)stream, 1, 60)) { return -1; } } #if defined(__APPLE__) if (uv__stream_try_select(stream, fd) == 0) { /* Use fake fd */ fd = ((uv__stream_select_t*) stream->select)->fak
int uv_pipe_open(uv_pipe_t* handle, uv_file fd) { #if defined(__APPLE__) if (uv__stream_try_select((uv_stream_t*) handle, &fd)) return -1; #endif /* defined(__APPLE__) */ return uv__stream_open((uv_stream_t*)handle, fd, UV_STREAM_READABLE | UV_STREAM_WRITABLE); }
int uv_pipe_open(uv_pipe_t* handle, uv_os_fd_t fd) { int err; err = uv__nonblock(fd, 1); if (err) return err; #if defined(__APPLE__) err = uv__stream_try_select((uv_stream_t*) handle, &fd); if (err) return err; #endif /* defined(__APPLE__) */ return uv__stream_open((uv_stream_t*)handle, fd, UV_STREAM_READABLE | UV_STREAM_WRITABLE); }
int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) { uv__stream_init(loop, (uv_stream_t*)tty, UV_TTY); #if defined(__APPLE__) if (uv__stream_try_select((uv_stream_t*) tty, &fd)) return -1; #endif /* defined(__APPLE__) */ if (readable) { uv__nonblock(fd, 1); uv__stream_open((uv_stream_t*)tty, fd, UV_STREAM_READABLE); } else { /* Note: writable tty we set to blocking mode. */ uv__stream_open((uv_stream_t*)tty, fd, UV_STREAM_WRITABLE); tty->flags |= UV_STREAM_BLOCKING; } tty->mode = 0; return 0; }
int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) { int flags; int newfd; int r; flags = 0; newfd = -1; uv__stream_init(loop, (uv_stream_t*) tty, UV_TTY); /* Reopen the file descriptor when it refers to a tty. This lets us put the * tty in non-blocking mode without affecting other processes that share it * with us. * * Example: `node | cat` - if we put our fd 0 in non-blocking mode, it also * affects fd 1 of `cat` because both file descriptors refer to the same * struct file in the kernel. When we reopen our fd 0, it points to a * different struct file, hence changing its properties doesn't affect * other processes. */ if (isatty(fd)) { r = uv__open_cloexec("/dev/tty", O_RDWR); if (r < 0) { /* fallback to using blocking writes */ if (!readable) flags |= UV_STREAM_BLOCKING; goto skip; } newfd = r; r = uv__dup2_cloexec(newfd, fd); if (r < 0 && r != -EINVAL) { /* EINVAL means newfd == fd which could conceivably happen if another * thread called close(fd) between our calls to isatty() and open(). * That's a rather unlikely event but let's handle it anyway. */ uv__close(newfd); return r; } fd = newfd; } skip: #if defined(__APPLE__) r = uv__stream_try_select((uv_stream_t*) tty, &fd); if (r) { if (newfd != -1) uv__close(newfd); return r; } #endif if (readable) flags |= UV_STREAM_READABLE; else flags |= UV_STREAM_WRITABLE; if (!(flags & UV_STREAM_BLOCKING)) uv__nonblock(fd, 1); uv__stream_open((uv_stream_t*) tty, fd, flags); tty->mode = UV_TTY_MODE_NORMAL; return 0; }
int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) { uv_handle_type type; int flags; int newfd; int r; int saved_flags; char path[256]; /* File descriptors that refer to files cannot be monitored with epoll. * That restriction also applies to character devices like /dev/random * (but obviously not /dev/tty.) */ type = uv_guess_handle(fd); if (type == UV_FILE || type == UV_UNKNOWN_HANDLE) return UV_EINVAL; flags = 0; newfd = -1; /* Reopen the file descriptor when it refers to a tty. This lets us put the * tty in non-blocking mode without affecting other processes that share it * with us. * * Example: `node | cat` - if we put our fd 0 in non-blocking mode, it also * affects fd 1 of `cat` because both file descriptors refer to the same * struct file in the kernel. When we reopen our fd 0, it points to a * different struct file, hence changing its properties doesn't affect * other processes. */ if (type == UV_TTY) { /* Reopening a pty in master mode won't work either because the reopened * pty will be in slave mode (*BSD) or reopening will allocate a new * master/slave pair (Linux). Therefore check if the fd points to a * slave device. */ if (uv__tty_is_slave(fd) && ttyname_r(fd, path, sizeof(path)) == 0) r = uv__open_cloexec(path, O_RDWR); else r = -1; if (r < 0) { /* fallback to using blocking writes */ if (!readable) flags |= UV_HANDLE_BLOCKING_WRITES; goto skip; } newfd = r; r = uv__dup2_cloexec(newfd, fd); if (r < 0 && r != UV_EINVAL) { /* EINVAL means newfd == fd which could conceivably happen if another * thread called close(fd) between our calls to isatty() and open(). * That's a rather unlikely event but let's handle it anyway. */ uv__close(newfd); return r; } fd = newfd; } #if defined(__APPLE__) /* Save the fd flags in case we need to restore them due to an error. */ do saved_flags = fcntl(fd, F_GETFL); while (saved_flags == -1 && errno == EINTR); if (saved_flags == -1) { if (newfd != -1) uv__close(newfd); return UV__ERR(errno); } #endif /* Pacify the compiler. */ (void) &saved_flags; skip: uv__stream_init(loop, (uv_stream_t*) tty, UV_TTY); /* If anything fails beyond this point we need to remove the handle from * the handle queue, since it was added by uv__handle_init in uv_stream_init. */ if (!(flags & UV_HANDLE_BLOCKING_WRITES)) uv__nonblock(fd, 1); #if defined(__APPLE__) r = uv__stream_try_select((uv_stream_t*) tty, &fd); if (r) { int rc = r; if (newfd != -1) uv__close(newfd); QUEUE_REMOVE(&tty->handle_queue); do r = fcntl(fd, F_SETFL, saved_flags); while (r == -1 && errno == EINTR); return rc; } #endif if (readable) flags |= UV_HANDLE_READABLE; else flags |= UV_HANDLE_WRITABLE; uv__stream_open((uv_stream_t*) tty, fd, flags); tty->mode = UV_TTY_MODE_NORMAL; return 0; }