int uv_fs_fstat(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) { uv_fs_req_init(loop, req, UV_FS_FSTAT, NULL, cb); if (cb) { /* async */ uv_ref(loop); req->eio = eio_fstat(file, EIO_PRI_DEFAULT, uv__fs_after, req); if (!req->eio) { uv_err_new(loop, ENOMEM); return -1; } } else { /* sync */ req->result = fstat(file, &req->statbuf); if (req->result < 0) { uv_err_new(loop, errno); return -1; } req->ptr = &req->statbuf; } return 0; }
int uv_tcp_connect6(uv_connect_t* req, uv_tcp_t* handle, struct sockaddr_in6 address, uv_connect_cb cb) { int saved_errno; int status; saved_errno = errno; status = -1; if (handle->type != UV_TCP) { uv_err_new(handle->loop, EINVAL); goto out; } if (address.sin6_family != AF_INET6) { uv_err_new(handle->loop, EINVAL); goto out; } status = uv__connect(req, (uv_stream_t*)handle, (struct sockaddr*)&address, sizeof address, cb); out: errno = saved_errno; return status; }
int uv_fs_write(uv_loop_t* loop, uv_fs_t* req, uv_file file, void* buf, size_t length, off_t offset, uv_fs_cb cb) { uv_fs_req_init(loop, req, UV_FS_WRITE, NULL, cb); if (cb) { /* async */ uv_ref(loop); req->eio = eio_write(file, buf, length, offset, EIO_PRI_DEFAULT, uv__fs_after, req); if (!req->eio) { uv_err_new(loop, ENOMEM); return -1; } } else { /* sync */ req->result = offset < 0 ? write(file, buf, length) : pwrite(file, buf, length, offset); if (req->result < 0) { uv_err_new(loop, errno); return -1; } } return 0; }
int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb) { int r; assert(tcp->fd >= 0); if (tcp->delayed_error) { uv_err_new((uv_handle_t*)tcp, tcp->delayed_error); return -1; } r = listen(tcp->fd, backlog); if (r < 0) { uv_err_new((uv_handle_t*)tcp, errno); return -1; } tcp->connection_cb = cb; /* Start listening for connections. */ ev_io_set(&tcp->read_watcher, tcp->fd, EV_READ); ev_set_cb(&tcp->read_watcher, uv__server_io); ev_io_start(EV_DEFAULT_ &tcp->read_watcher); return 0; }
int uv_fs_open(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags, int mode, uv_fs_cb cb) { uv_fs_req_init(loop, req, UV_FS_OPEN, path, cb); if (cb) { /* async */ uv_ref(loop); req->eio = eio_open(path, flags, mode, EIO_PRI_DEFAULT, uv__fs_after, req); if (!req->eio) { uv_err_new(loop, ENOMEM); return -1; } } else { /* sync */ req->result = open(path, flags, mode); if (req->result < 0) { uv_err_new(loop, errno); return -1; } uv__cloexec(req->result, 1); } return 0; }
static void uv__drain(uv_tcp_t* tcp) { uv_shutdown_t* req; assert(!uv_write_queue_head(tcp)); assert(tcp->write_queue_size == 0); ev_io_stop(EV_DEFAULT_ &tcp->write_watcher); /* Shutdown? */ if (uv_flag_is_set((uv_handle_t*)tcp, UV_SHUTTING) && !uv_flag_is_set((uv_handle_t*)tcp, UV_CLOSING) && !uv_flag_is_set((uv_handle_t*)tcp, UV_SHUT)) { assert(tcp->shutdown_req); req = tcp->shutdown_req; if (shutdown(tcp->fd, SHUT_WR)) { /* Error. Report it. User should call uv_close(). */ uv_err_new((uv_handle_t*)tcp, errno); if (req->cb) { req->cb(req, -1); } } else { uv_err_new((uv_handle_t*)tcp, 0); uv_flag_set((uv_handle_t*)tcp, UV_SHUT); if (req->cb) { req->cb(req, 0); } } } }
static void uv__drain(uv_handle_t* handle) { assert(!uv_write_queue_head(handle)); assert(handle->write_queue_size == 0); ev_io_stop(EV_DEFAULT_ &handle->write_watcher); /* Shutdown? */ if (uv_flag_is_set(handle, UV_SHUTTING) && !uv_flag_is_set(handle, UV_CLOSING) && !uv_flag_is_set(handle, UV_SHUT)) { assert(handle->shutdown_req); uv_req_t* req = handle->shutdown_req; uv_shutdown_cb cb = req->cb; if (shutdown(handle->fd, SHUT_WR)) { /* Error. Nothing we can do, close the handle. */ uv_err_new(handle, errno); uv_close(handle); if (cb) cb(req, -1); } else { uv_err_new(handle, 0); uv_flag_set(handle, UV_SHUT); if (cb) cb(req, 0); } } }
int uv_tcp_getpeername(uv_tcp_t* handle, struct sockaddr* name, int* namelen) { socklen_t socklen; int saved_errno; int rv = 0; /* Don't clobber errno. */ saved_errno = errno; if (handle->delayed_error) { uv_err_new(handle->loop, handle->delayed_error); rv = -1; goto out; } if (handle->fd < 0) { uv_err_new(handle->loop, EINVAL); rv = -1; goto out; } /* sizeof(socklen_t) != sizeof(int) on some systems. */ socklen = (socklen_t)*namelen; if (getpeername(handle->fd, name, &socklen) == -1) { uv_err_new(handle->loop, errno); rv = -1; } else { *namelen = (int)socklen; } out: errno = saved_errno; return rv; }
static void uv__drain(uv_stream_t* stream) { uv_shutdown_t* req; assert(!uv_write_queue_head(stream)); assert(stream->write_queue_size == 0); ev_io_stop(stream->loop->ev, &stream->write_watcher); /* Shutdown? */ if ((stream->flags & UV_SHUTTING) && !(stream->flags & UV_CLOSING) && !(stream->flags & UV_SHUT)) { assert(stream->shutdown_req); req = stream->shutdown_req; if (shutdown(stream->fd, SHUT_WR)) { /* Error. Report it. User should call uv_close(). */ uv_err_new(stream->loop, errno); if (req->cb) { req->cb(req, -1); } } else { uv_err_new(stream->loop, 0); ((uv_handle_t*) stream)->flags |= UV_SHUT; if (req->cb) { req->cb(req, 0); } } } }
int uv_fs_readdir(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags, uv_fs_cb cb) { int r; struct dirent* entry; size_t size = 0; size_t d_namlen = 0; uv_fs_req_init(loop, req, UV_FS_READDIR, path, cb); if (cb) { /* async */ uv_ref(loop); req->eio = eio_readdir(path, flags, EIO_PRI_DEFAULT, uv__fs_after, req); if (!req->eio) { uv_err_new(loop, ENOMEM); return -1; } } else { /* sync */ DIR* dir = opendir(path); if (!dir) { uv_err_new(loop, errno); req->result = -1; return -1; } /* req->result stores number of entries */ req->result = 0; while ((entry = readdir(dir))) { d_namlen = strlen(entry->d_name); /* Skip . and .. */ if ((d_namlen == 1 && entry->d_name[0] == '.') || (d_namlen == 2 && entry->d_name[0] == '.' && entry->d_name[1] == '.')) { continue; } req->ptr = realloc(req->ptr, size + d_namlen + 1); /* TODO check ENOMEM */ memcpy((char*)req->ptr + size, entry->d_name, d_namlen); size += d_namlen; ((char*)req->ptr)[size] = '\0'; size++; req->result++; } r = closedir(dir); if (r) { uv_err_new(loop, errno); req->result = -1; return -1; } } return 0; }
int uv_fs_readlink(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) { ssize_t size; int status; char* buf; status = -1; uv_fs_req_init(loop, req, UV_FS_READLINK, path, cb); if (cb) { if ((req->eio = eio_readlink(path, EIO_PRI_DEFAULT, uv__fs_after, req))) { uv_ref(loop); return 0; } else { uv_err_new(loop, ENOMEM); return -1; } } else { /* pathconf(_PC_PATH_MAX) may return -1 to signify that path * lengths have no upper limit or aren't suitable for malloc'ing. */ if ((size = pathconf(path, _PC_PATH_MAX)) == -1) { #if defined(PATH_MAX) size = PATH_MAX; #else size = 4096; #endif } if ((buf = malloc(size + 1)) == NULL) { uv_err_new(loop, ENOMEM); return -1; } if ((size = readlink(path, buf, size)) == -1) { req->errorno = errno; req->result = -1; free(buf); } else { /* Cannot conceivably fail since it shrinks the buffer. */ buf = realloc(buf, size + 1); buf[size] = '\0'; req->result = 0; req->ptr = buf; } return 0; } assert(0 && "unreachable"); }
static void uv__read(uv_stream_t* stream) { uv_buf_t buf; ssize_t nread; struct ev_loop* ev = stream->loop->ev; /* XXX: Maybe instead of having UV_READING we just test if * tcp->read_cb is NULL or not? */ while (stream->read_cb && ((uv_handle_t*)stream)->flags & UV_READING) { assert(stream->alloc_cb); buf = stream->alloc_cb((uv_handle_t*)stream, 64 * 1024); assert(buf.len > 0); assert(buf.base); assert(stream->fd >= 0); do { nread = read(stream->fd, buf.base, buf.len); } while (nread < 0 && errno == EINTR); if (nread < 0) { /* Error */ if (errno == EAGAIN) { /* Wait for the next one. */ if (stream->flags & UV_READING) { ev_io_start(ev, &stream->read_watcher); } uv_err_new(stream->loop, EAGAIN); stream->read_cb(stream, 0, buf); return; } else { /* Error. User should call uv_close(). */ uv_err_new(stream->loop, errno); stream->read_cb(stream, -1, buf); assert(!ev_is_active(&stream->read_watcher)); return; } } else if (nread == 0) { /* EOF */ uv_err_new_artificial(stream->loop, UV_EOF); ev_io_stop(ev, &stream->read_watcher); stream->read_cb(stream, -1, buf); return; } else { /* Successful read */ stream->read_cb(stream, nread, buf); } } }
void uv__read(uv_handle_t* handle) { /* XXX: Maybe instead of having UV_READING we just test if * handle->read_cb is NULL or not? */ while (handle->read_cb && uv_flag_is_set(handle, UV_READING)) { assert(alloc_cb); uv_buf_t buf = alloc_cb(handle, 64 * 1024); assert(buf.len > 0); assert(buf.base); struct iovec* iov = (struct iovec*) &buf; ssize_t nread = readv(handle->fd, iov, 1); if (nread < 0) { /* Error */ if (errno == EAGAIN) { /* Wait for the next one. */ if (uv_flag_is_set(handle, UV_READING)) { ev_io_start(EV_DEFAULT_UC_ &handle->read_watcher); } uv_err_new(handle, EAGAIN); handle->read_cb(handle, 0, buf); return; } else { uv_err_new(handle, errno); uv_close(handle); handle->read_cb(handle, -1, buf); assert(!ev_is_active(&handle->read_watcher)); return; } } else if (nread == 0) { /* EOF */ uv_err_new_artificial(handle, UV_EOF); ev_io_stop(EV_DEFAULT_UC_ &handle->read_watcher); handle->read_cb(handle, -1, buf); if (uv_flag_is_set(handle, UV_SHUT)) { uv_close(handle); } return; } else { /* Successful read */ handle->read_cb(handle, nread, buf); } } }
void uv__read(uv_tcp_t* tcp) { uv_buf_t buf; struct iovec* iov; ssize_t nread; /* XXX: Maybe instead of having UV_READING we just test if * tcp->read_cb is NULL or not? */ while (tcp->read_cb && uv_flag_is_set((uv_handle_t*)tcp, UV_READING)) { assert(tcp->alloc_cb); buf = tcp->alloc_cb((uv_stream_t*)tcp, 64 * 1024); assert(buf.len > 0); assert(buf.base); iov = (struct iovec*) &buf; nread = read(tcp->fd, buf.base, buf.len); if (nread < 0) { /* Error */ if (errno == EAGAIN) { /* Wait for the next one. */ if (uv_flag_is_set((uv_handle_t*)tcp, UV_READING)) { ev_io_start(EV_DEFAULT_UC_ &tcp->read_watcher); } uv_err_new((uv_handle_t*)tcp, EAGAIN); tcp->read_cb((uv_stream_t*)tcp, 0, buf); return; } else { /* Error. User should call uv_close(). */ uv_err_new((uv_handle_t*)tcp, errno); tcp->read_cb((uv_stream_t*)tcp, -1, buf); assert(!ev_is_active(&tcp->read_watcher)); return; } } else if (nread == 0) { /* EOF */ uv_err_new_artificial((uv_handle_t*)tcp, UV_EOF); ev_io_stop(EV_DEFAULT_UC_ &tcp->read_watcher); tcp->read_cb((uv_stream_t*)tcp, -1, buf); return; } else { /* Successful read */ tcp->read_cb((uv_stream_t*)tcp, nread, buf); } } }
int uv_bind(uv_handle_t* handle, struct sockaddr* addr) { int addrsize; int domain; int r; if (handle->fd <= 0) { int fd = socket(AF_INET, SOCK_STREAM, 0); if (fd < 0) { uv_err_new(handle, errno); return -1; } if (uv_tcp_open(handle, fd)) { close(fd); return -2; } } assert(handle->fd >= 0); if (addr->sa_family == AF_INET) { addrsize = sizeof(struct sockaddr_in); domain = AF_INET; } else if (addr->sa_family == AF_INET6) { addrsize = sizeof(struct sockaddr_in6); domain = AF_INET6; } else { uv_err_new(handle, EFAULT); return -1; } r = bind(handle->fd, addr, addrsize); handle->delayed_error = 0; if (r) { switch (errno) { case EADDRINUSE: handle->delayed_error = errno; return 0; default: uv_err_new(handle, errno); return -1; } } return 0; }
int uv_shutdown(uv_shutdown_t* req, uv_stream_t* stream, uv_shutdown_cb cb) { assert((stream->type == UV_TCP || stream->type == UV_NAMED_PIPE) && "uv_shutdown (unix) only supports uv_handle_t right now"); assert(stream->fd >= 0); if (!(stream->flags & UV_WRITABLE) || stream->flags & UV_SHUT || stream->flags & UV_CLOSED || stream->flags & UV_CLOSING) { uv_err_new(stream->loop, EINVAL); return -1; } /* Initialize request */ uv__req_init((uv_req_t*)req); req->handle = stream; req->cb = cb; stream->shutdown_req = req; req->type = UV_SHUTDOWN; ((uv_handle_t*)stream)->flags |= UV_SHUTTING; ev_io_start(stream->loop->ev, &stream->write_watcher); return 0; }
int uv__stream_open(uv_stream_t* stream, int fd, int flags) { socklen_t yes; assert(fd >= 0); stream->fd = fd; ((uv_handle_t*)stream)->flags |= flags; /* Reuse the port address if applicable. */ yes = 1; if (stream->type == UV_TCP && setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) { uv_err_new(stream->loop, errno); return -1; } /* Associate the fd with each ev_io watcher. */ ev_io_set(&stream->read_watcher, fd, EV_READ); ev_io_set(&stream->write_watcher, fd, EV_WRITE); /* These should have been set up by uv_tcp_init or uv_pipe_init. */ assert(stream->read_watcher.cb == uv__stream_io); assert(stream->write_watcher.cb == uv__stream_io); return 0; }
int uv_read_start(uv_stream_t* stream, uv_alloc_cb alloc_cb, uv_read_cb read_cb) { assert(stream->type == UV_TCP || stream->type == UV_NAMED_PIPE); if (stream->flags & UV_CLOSING) { uv_err_new(stream->loop, EINVAL); return -1; } /* The UV_READING flag is irrelevant of the state of the tcp - it just * expresses the desired state of the user. */ ((uv_handle_t*)stream)->flags |= UV_READING; /* TODO: try to do the read inline? */ /* TODO: keep track of tcp state. If we've gotten a EOF then we should * not start the IO watcher. */ assert(stream->fd >= 0); assert(alloc_cb); stream->read_cb = read_cb; stream->alloc_cb = alloc_cb; /* These should have been set by uv_tcp_init. */ assert(stream->read_watcher.cb == uv__stream_io); ev_io_start(stream->loop->ev, &stream->read_watcher); return 0; }
int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle, const char* filename, uv_fs_event_cb cb) { uv_err_new(loop, ENOSYS); return -1; }
/* TODO merge with uv__server_io()? */ void uv__pipe_accept(EV_P_ ev_io* watcher, int revents) { struct sockaddr_un sun; uv_pipe_t* pipe; int saved_errno; int sockfd; saved_errno = errno; pipe = watcher->data; assert(pipe->type == UV_NAMED_PIPE); assert(pipe->pipe_fname != NULL); sockfd = uv__accept(pipe->fd, (struct sockaddr *)&sun, sizeof sun); if (sockfd == -1) { if (errno == EAGAIN || errno == EWOULDBLOCK) { assert(0 && "EAGAIN on uv__accept(pipefd)"); } else { uv_err_new(pipe->loop, errno); } } else { pipe->accepted_fd = sockfd; pipe->connection_cb((uv_stream_t*)pipe, 0); if (pipe->accepted_fd == sockfd) { /* The user hasn't yet accepted called uv_accept() */ ev_io_stop(pipe->loop->ev, &pipe->read_watcher); } } errno = saved_errno; }
int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) { int saved_errno; int status; saved_errno = errno; status = -1; if (handle->fd == -1) { uv_err_new_artificial(handle->loop, UV_EINVAL); goto out; } assert(handle->fd >= 0); if ((status = listen(handle->fd, backlog)) == -1) { uv_err_new(handle->loop, errno); } else { handle->connection_cb = cb; ev_io_init(&handle->read_watcher, uv__pipe_accept, handle->fd, EV_READ); ev_io_start(handle->loop->ev, &handle->read_watcher); } out: errno = saved_errno; return status; }
int uv_tcp_bind6(uv_tcp_t* tcp, struct sockaddr_in6 addr) { if (addr.sin6_family != AF_INET6) { uv_err_new((uv_handle_t*)tcp, EFAULT); return -1; } return uv__bind(tcp, AF_INET6, (struct sockaddr*)&addr, sizeof(struct sockaddr_in6)); }
int uv_timer_again(uv_timer_t* timer) { if (!ev_is_active(&timer->timer_watcher)) { uv_err_new(timer->loop, EINVAL); return -1; } ev_timer_again(timer->loop->ev, &timer->timer_watcher); return 0; }
int uv_timer_again(uv_handle_t* handle) { if (!ev_is_active(&handle->timer_watcher)) { uv_err_new(handle, EINVAL); return -1; } ev_timer_again(EV_DEFAULT_UC_ &handle->timer_watcher); return 0; }
int uv_timer_again(uv_timer_t* timer) { if (!ev_is_active(&timer->timer_watcher)) { uv_err_new((uv_handle_t*)timer, EINVAL); return -1; } ev_timer_again(EV_DEFAULT_UC_ &timer->timer_watcher); return 0; }
int uv_fs_lstat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) { char* pathdup; int pathlen; uv_fs_req_init(loop, req, UV_FS_LSTAT, path, cb); /* TODO do this without duplicating the string. */ /* TODO security */ pathdup = strdup(path); pathlen = strlen(path); if (pathlen > 0 && path[pathlen - 1] == '\\') { /* TODO do not modify input string */ pathdup[pathlen - 1] = '\0'; } if (cb) { /* async */ uv_ref(loop); req->eio = eio_lstat(pathdup, EIO_PRI_DEFAULT, uv__fs_after, req); free(pathdup); if (!req->eio) { uv_err_new(loop, ENOMEM); return -1; } } else { /* sync */ req->result = lstat(pathdup, &req->statbuf); free(pathdup); if (req->result < 0) { uv_err_new(loop, errno); return -1; } req->ptr = &req->statbuf; } return 0; }
int uv_process_kill(uv_process_t* process, int signum) { int r = kill(process->pid, signum); if (r) { uv_err_new(process->loop, errno); return -1; } else { return 0; } }
int uv_bind(uv_tcp_t* tcp, struct sockaddr_in addr) { int addrsize = sizeof(struct sockaddr_in); int domain = AF_INET; int r; if (tcp->fd <= 0) { int fd = socket(AF_INET, SOCK_STREAM, 0); if (fd < 0) { uv_err_new((uv_handle_t*)tcp, errno); return -1; } if (uv_tcp_open(tcp, fd)) { close(fd); return -2; } } assert(tcp->fd >= 0); if (addr.sin_family != AF_INET) { uv_err_new((uv_handle_t*)tcp, EFAULT); return -1; } r = bind(tcp->fd, (struct sockaddr*) &addr, addrsize); tcp->delayed_error = 0; if (r) { switch (errno) { case EADDRINUSE: tcp->delayed_error = errno; return 0; default: uv_err_new((uv_handle_t*)tcp, errno); return -1; } } return 0; }
int uv_tcp_bind(uv_tcp_t* tcp, struct sockaddr_in addr) { if (addr.sin_family != AF_INET) { uv_err_new(tcp->loop, EFAULT); return -1; } return uv__tcp_bind(tcp, AF_INET, (struct sockaddr*)&addr, sizeof(struct sockaddr_in)); }
static int uv__tcp_bind(uv_tcp_t* tcp, int domain, struct sockaddr* addr, int addrsize) { int saved_errno; int status; saved_errno = errno; status = -1; if (tcp->fd < 0) { if ((tcp->fd = uv__socket(domain, SOCK_STREAM, 0)) == -1) { uv_err_new(tcp->loop, errno); goto out; } if (uv__stream_open((uv_stream_t*)tcp, tcp->fd, UV_READABLE | UV_WRITABLE)) { uv__close(tcp->fd); tcp->fd = -1; status = -2; goto out; } } assert(tcp->fd >= 0); tcp->delayed_error = 0; if (bind(tcp->fd, addr, addrsize) == -1) { if (errno == EADDRINUSE) { tcp->delayed_error = errno; } else { uv_err_new(tcp->loop, errno); goto out; } } status = 0; out: errno = saved_errno; return status; }