diff options
Diffstat (limited to 'deps/uv/src/unix')
-rw-r--r-- | deps/uv/src/unix/aix.c | 187 | ||||
-rw-r--r-- | deps/uv/src/unix/core.c | 30 | ||||
-rw-r--r-- | deps/uv/src/unix/freebsd.c | 35 | ||||
-rw-r--r-- | deps/uv/src/unix/fs.c | 137 | ||||
-rw-r--r-- | deps/uv/src/unix/internal.h | 1 | ||||
-rw-r--r-- | deps/uv/src/unix/kqueue.c | 12 | ||||
-rw-r--r-- | deps/uv/src/unix/loop.c | 34 | ||||
-rw-r--r-- | deps/uv/src/unix/pthread-fixes.c | 1 | ||||
-rw-r--r-- | deps/uv/src/unix/stream.c | 36 | ||||
-rw-r--r-- | deps/uv/src/unix/tcp.c | 51 | ||||
-rw-r--r-- | deps/uv/src/unix/tty.c | 9 | ||||
-rw-r--r-- | deps/uv/src/unix/udp.c | 42 |
12 files changed, 339 insertions, 236 deletions
diff --git a/deps/uv/src/unix/aix.c b/deps/uv/src/unix/aix.c index a2b0744a04..c90b7e5cb9 100644 --- a/deps/uv/src/unix/aix.c +++ b/deps/uv/src/unix/aix.c @@ -43,6 +43,7 @@ #include <sys/protosw.h> #include <libperfstat.h> +#include <procinfo.h> #include <sys/proc.h> #include <sys/procfs.h> @@ -288,182 +289,80 @@ uint64_t uv__hrtime(uv_clocktype_t type) { * and use it in conjunction with PATH environment variable to craft one. */ int uv_exepath(char* buffer, size_t* size) { - ssize_t res; - char cwd[PATH_MAX], cwdl[PATH_MAX]; - char symlink[PATH_MAX], temp_buffer[PATH_MAX]; - char pp[64]; - struct psinfo ps; - int fd; - char **argv; + int res; + char args[PATH_MAX]; + char abspath[PATH_MAX]; + size_t abspath_size; + struct procsinfo pi; if (buffer == NULL || size == NULL || *size == 0) return -EINVAL; - snprintf(pp, sizeof(pp), "/proc/%lu/psinfo", (unsigned long) getpid()); - - fd = open(pp, O_RDONLY); - if (fd < 0) - return fd; - - res = read(fd, &ps, sizeof(ps)); - uv__close(fd); - if (res < 0) - return res; - - if (ps.pr_argv == 0) - return -EINVAL; - - argv = (char **) *((char ***) (intptr_t) ps.pr_argv); - - if ((argv == NULL) || (argv[0] == NULL)) + pi.pi_pid = getpid(); + res = getargs(&pi, sizeof(pi), args, sizeof(args)); + if (res < 0) return -EINVAL; /* - * Three possibilities for argv[0]: + * Possibilities for args: * i) an absolute path such as: /home/user/myprojects/nodejs/node - * ii) a relative path such as: ./node or ./myprojects/nodejs/node + * ii) a relative path such as: ./node or ../myprojects/nodejs/node * iii) a bare filename such as "node", after exporting PATH variable * to its location. */ - /* case #1, absolute path. */ - if (argv[0][0] == '/') { - snprintf(symlink, PATH_MAX-1, "%s", argv[0]); - - /* This could or could not be a symlink. */ - res = readlink(symlink, temp_buffer, PATH_MAX-1); - - /* if readlink fails, it is a normal file just copy symlink to the - * output buffer. - */ - if (res < 0) { - assert(*size > strlen(symlink)); - strcpy(buffer, symlink); - - /* If it is a link, the resolved filename is again a relative path, - * make it absolute. - */ - } else { - assert(*size > (strlen(symlink) + 1 + strlen(temp_buffer))); - snprintf(buffer, *size-1, "%s/%s", dirname(symlink), temp_buffer); - } - *size = strlen(buffer); - return 0; - - /* case #2, relative path with usage of '.' */ - } else if (argv[0][0] == '.') { - char *relative = strchr(argv[0], '/'); - if (relative == NULL) - return -EINVAL; - - /* Get the current working directory to resolve the relative path. */ - snprintf(cwd, PATH_MAX-1, "/proc/%lu/cwd", (unsigned long) getpid()); - - /* This is always a symlink, resolve it. */ - res = readlink(cwd, cwdl, sizeof(cwdl) - 1); - if (res < 0) + /* Case i) and ii) absolute or relative paths */ + if (strchr(args, '/') != NULL) { + if (realpath(args, abspath) != abspath) return -errno; - snprintf(symlink, PATH_MAX-1, "%s%s", cwdl, relative + 1); - - res = readlink(symlink, temp_buffer, PATH_MAX-1); - if (res < 0) { - assert(*size > strlen(symlink)); - strcpy(buffer, symlink); - } else { - assert(*size > (strlen(symlink) + 1 + strlen(temp_buffer))); - snprintf(buffer, *size-1, "%s/%s", dirname(symlink), temp_buffer); - } - *size = strlen(buffer); - return 0; - - /* case #3, relative path without usage of '.', such as invocations in Node test suite. */ - } else if (strchr(argv[0], '/') != NULL) { - /* Get the current working directory to resolve the relative path. */ - snprintf(cwd, PATH_MAX-1, "/proc/%lu/cwd", (unsigned long) getpid()); + abspath_size = strlen(abspath); - /* This is always a symlink, resolve it. */ - res = readlink(cwd, cwdl, sizeof(cwdl) - 1); - if (res < 0) - return -errno; + *size -= 1; + if (*size > abspath_size) + *size = abspath_size; - snprintf(symlink, PATH_MAX-1, "%s%s", cwdl, argv[0]); + memcpy(buffer, abspath, *size); + buffer[*size] = '\0'; - res = readlink(symlink, temp_buffer, PATH_MAX-1); - if (res < 0) { - assert(*size > strlen(symlink)); - strcpy(buffer, symlink); - } else { - assert(*size > (strlen(symlink) + 1 + strlen(temp_buffer))); - snprintf(buffer, *size-1, "%s/%s", dirname(symlink), temp_buffer); - } - *size = strlen(buffer); return 0; - /* Usage of absolute filename with location exported in PATH */ } else { - char clonedpath[8192]; /* assume 8k buffer will fit PATH */ + /* Case iii). Search PATH environment variable */ + char trypath[PATH_MAX]; + char *clonedpath = NULL; char *token = NULL; - struct stat statstruct; - - /* Get the paths. */ char *path = getenv("PATH"); - if(sizeof(clonedpath) <= strlen(path)) + + if (path == NULL) return -EINVAL; - /* Get a local copy. */ - strcpy(clonedpath, path); + clonedpath = uv__strdup(path); + if (clonedpath == NULL) + return -ENOMEM; - /* Tokenize. */ token = strtok(clonedpath, ":"); + while (token != NULL) { + snprintf(trypath, sizeof(trypath) - 1, "%s/%s", token, args); + if (realpath(trypath, abspath) == abspath) { + /* Check the match is executable */ + if (access(abspath, X_OK) == 0) { + abspath_size = strlen(abspath); - /* Get current working directory. (may be required in the loop). */ - snprintf(cwd, PATH_MAX-1, "/proc/%lu/cwd", (unsigned long) getpid()); - res = readlink(cwd, cwdl, sizeof(cwdl) - 1); - if (res < 0) - return -errno; - /* Run through the tokens, append our executable file name with each, - * and see which one succeeds. Exit on first match. */ - while(token != NULL) { - if (token[0] == '.') { - /* Path contains a token relative to current directory. */ - char *relative = strchr(token, '/'); - if (relative != NULL) - /* A path which is not current directory. */ - snprintf(symlink, PATH_MAX-1, "%s%s/%s", cwdl, relative+1, ps.pr_fname); - else - snprintf(symlink, PATH_MAX-1, "%s%s", cwdl, ps.pr_fname); - if (stat(symlink, &statstruct) != -1) { - /* File exists. Resolve if it is a link. */ - res = readlink(symlink, temp_buffer, PATH_MAX-1); - if (res < 0) { - assert(*size > strlen(symlink)); - strcpy(buffer, symlink); - } else { - assert(*size > (strlen(symlink) + 1 + strlen(temp_buffer))); - snprintf(buffer, *size-1, "%s/%s", dirname(symlink), temp_buffer); - } - *size = strlen(buffer); - return 0; - } + *size -= 1; + if (*size > abspath_size) + *size = abspath_size; - /* Absolute path names. */ - } else { - snprintf(symlink, PATH_MAX-1, "%s/%s", token, ps.pr_fname); - if (stat(symlink, &statstruct) != -1) { - res = readlink(symlink, temp_buffer, PATH_MAX-1); - if (res < 0) { - assert(*size > strlen(symlink)); - strcpy(buffer, symlink); - } else { - assert(*size > (strlen(symlink) + 1 + strlen(temp_buffer))); - snprintf(buffer, *size-1, "%s/%s", dirname(symlink), temp_buffer); - } - *size = strlen(buffer); + memcpy(buffer, abspath, *size); + buffer[*size] = '\0'; + + uv__free(clonedpath); return 0; } } token = strtok(NULL, ":"); } + uv__free(clonedpath); + /* Out of tokens (path entries), and no match found */ return -EINVAL; } diff --git a/deps/uv/src/unix/core.c b/deps/uv/src/unix/core.c index 826b4113b2..e149357e07 100644 --- a/deps/uv/src/unix/core.c +++ b/deps/uv/src/unix/core.c @@ -35,7 +35,7 @@ #include <sys/un.h> #include <netinet/in.h> #include <arpa/inet.h> -#include <limits.h> /* INT_MAX, PATH_MAX */ +#include <limits.h> /* INT_MAX, PATH_MAX, IOV_MAX */ #include <sys/uio.h> /* writev */ #include <sys/resource.h> /* getrusage */ #include <pwd.h> @@ -55,13 +55,13 @@ # include <sys/ioctl.h> #endif -#ifdef __FreeBSD__ +#if defined(__FreeBSD__) || defined(__DragonFly__) # include <sys/sysctl.h> # include <sys/filio.h> # include <sys/ioctl.h> # include <sys/wait.h> # define UV__O_CLOEXEC O_CLOEXEC -# if __FreeBSD__ >= 10 +# if defined(__FreeBSD__) && __FreeBSD__ >= 10 # define uv__accept4 accept4 # define UV__SOCK_NONBLOCK SOCK_NONBLOCK # define UV__SOCK_CLOEXEC SOCK_CLOEXEC @@ -199,6 +199,19 @@ void uv__make_close_pending(uv_handle_t* handle) { handle->loop->closing_handles = handle; } +int uv__getiovmax(void) { +#if defined(IOV_MAX) + return IOV_MAX; +#elif defined(_SC_IOV_MAX) + static int iovmax = -1; + if (iovmax == -1) + iovmax = sysconf(_SC_IOV_MAX); + return iovmax; +#else + return 1024; +#endif +} + static void uv__finish_close(uv_handle_t* handle) { /* Note: while the handle is in the UV_CLOSING state now, it's still possible @@ -477,7 +490,7 @@ int uv__close(int fd) { #if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) || \ - defined(_AIX) + defined(_AIX) || defined(__DragonFly__) int uv__nonblock(int fd, int set) { int r; @@ -506,7 +519,8 @@ int uv__cloexec(int fd, int set) { return 0; } -#else /* !(defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__)) */ +#else /* !(defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) || \ + defined(_AIX) || defined(__DragonFly__)) */ int uv__nonblock(int fd, int set) { int flags; @@ -569,7 +583,8 @@ int uv__cloexec(int fd, int set) { return 0; } -#endif /* defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) */ +#endif /* defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) || \ + defined(_AIX) || defined(__DragonFly__) */ /* This function is not execve-safe, there is a race window @@ -907,7 +922,8 @@ int uv__open_cloexec(const char* path, int flags) { int err; int fd; -#if defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD__ >= 9) +#if defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD__ >= 9) || \ + defined(__DragonFly__) static int no_cloexec; if (!no_cloexec) { diff --git a/deps/uv/src/unix/freebsd.c b/deps/uv/src/unix/freebsd.c index 44976f7fe2..c838beb28e 100644 --- a/deps/uv/src/unix/freebsd.c +++ b/deps/uv/src/unix/freebsd.c @@ -74,6 +74,30 @@ uint64_t uv__hrtime(uv_clocktype_t type) { } +#ifdef __DragonFly__ +int uv_exepath(char* buffer, size_t* size) { + char abspath[PATH_MAX * 2 + 1]; + ssize_t abspath_size; + + if (buffer == NULL || size == NULL || *size == 0) + return -EINVAL; + + abspath_size = readlink("/proc/curproc/file", abspath, sizeof(abspath)); + if (abspath_size < 0) + return -errno; + + assert(abspath_size > 0); + *size -= 1; + + if (*size > abspath_size) + *size = abspath_size; + + memcpy(buffer, abspath, *size); + buffer[*size] = '\0'; + + return 0; +} +#else int uv_exepath(char* buffer, size_t* size) { char abspath[PATH_MAX * 2 + 1]; int mib[4]; @@ -82,19 +106,12 @@ int uv_exepath(char* buffer, size_t* size) { if (buffer == NULL || size == NULL || *size == 0) return -EINVAL; -#ifdef __DragonFly__ - mib[0] = CTL_KERN; - mib[1] = KERN_PROC; - mib[2] = KERN_PROC_ARGS; - mib[3] = getpid(); -#else mib[0] = CTL_KERN; mib[1] = KERN_PROC; mib[2] = KERN_PROC_PATHNAME; mib[3] = -1; -#endif - abspath_size = sizeof abspath;; + abspath_size = sizeof abspath; if (sysctl(mib, 4, abspath, &abspath_size, NULL, 0)) return -errno; @@ -110,7 +127,7 @@ int uv_exepath(char* buffer, size_t* size) { return 0; } - +#endif uint64_t uv_get_free_memory(void) { int freecount; diff --git a/deps/uv/src/unix/fs.c b/deps/uv/src/unix/fs.c index 9dab202dd7..52082e9347 100644 --- a/deps/uv/src/unix/fs.c +++ b/deps/uv/src/unix/fs.c @@ -58,52 +58,63 @@ # include <sys/sendfile.h> #endif -#define INIT(type) \ +#define INIT(subtype) \ do { \ - uv__req_init((loop), (req), UV_FS); \ - (req)->fs_type = UV_FS_ ## type; \ - (req)->result = 0; \ - (req)->ptr = NULL; \ - (req)->loop = loop; \ - (req)->path = NULL; \ - (req)->new_path = NULL; \ - (req)->cb = (cb); \ + req->type = UV_FS; \ + if (cb != NULL) \ + uv__req_init(loop, req, UV_FS); \ + req->fs_type = UV_FS_ ## subtype; \ + req->result = 0; \ + req->ptr = NULL; \ + req->loop = loop; \ + req->path = NULL; \ + req->new_path = NULL; \ + req->cb = cb; \ } \ while (0) #define PATH \ do { \ - (req)->path = uv__strdup(path); \ - if ((req)->path == NULL) \ - return -ENOMEM; \ + assert(path != NULL); \ + if (cb == NULL) { \ + req->path = path; \ + } else { \ + req->path = uv__strdup(path); \ + if (req->path == NULL) \ + return -ENOMEM; \ + } \ } \ while (0) #define PATH2 \ do { \ - size_t path_len; \ - size_t new_path_len; \ - path_len = strlen((path)) + 1; \ - new_path_len = strlen((new_path)) + 1; \ - (req)->path = uv__malloc(path_len + new_path_len); \ - if ((req)->path == NULL) \ - return -ENOMEM; \ - (req)->new_path = (req)->path + path_len; \ - memcpy((void*) (req)->path, (path), path_len); \ - memcpy((void*) (req)->new_path, (new_path), new_path_len); \ + if (cb == NULL) { \ + req->path = path; \ + req->new_path = new_path; \ + } else { \ + size_t path_len; \ + size_t new_path_len; \ + path_len = strlen(path) + 1; \ + new_path_len = strlen(new_path) + 1; \ + req->path = uv__malloc(path_len + new_path_len); \ + if (req->path == NULL) \ + return -ENOMEM; \ + req->new_path = req->path + path_len; \ + memcpy((void*) req->path, path, path_len); \ + memcpy((void*) req->new_path, new_path, new_path_len); \ + } \ } \ while (0) #define POST \ do { \ - if ((cb) != NULL) { \ - uv__work_submit((loop), &(req)->work_req, uv__fs_work, uv__fs_done); \ + if (cb != NULL) { \ + uv__work_submit(loop, &req->work_req, uv__fs_work, uv__fs_done); \ return 0; \ } \ else { \ - uv__fs_work(&(req)->work_req); \ - uv__fs_done(&(req)->work_req, 0); \ - return (req)->result; \ + uv__fs_work(&req->work_req); \ + return req->result; \ } \ } \ while (0) @@ -309,8 +320,6 @@ static ssize_t uv__fs_read(uv_fs_t* req) { } done: - if (req->bufs != req->bufsml) - uv__free(req->bufs); return result; } @@ -545,7 +554,7 @@ static ssize_t uv__fs_sendfile(uv_fs_t* req) { return -1; } -#elif defined(__FreeBSD__) || defined(__APPLE__) +#elif defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__) { off_t len; ssize_t r; @@ -555,7 +564,7 @@ static ssize_t uv__fs_sendfile(uv_fs_t* req) { * number of bytes have been sent, we don't consider it an error. */ -#if defined(__FreeBSD__) +#if defined(__FreeBSD__) || defined(__DragonFly__) len = 0; r = sendfile(in_fd, out_fd, req->off, req->bufsml[0].len, NULL, &len, 0); #else @@ -670,9 +679,6 @@ done: pthread_mutex_unlock(&lock); #endif - if (req->bufs != req->bufsml) - uv__free(req->bufs); - return r; } @@ -777,6 +783,47 @@ static int uv__fs_fstat(int fd, uv_stat_t *buf) { } +typedef ssize_t (*uv__fs_buf_iter_processor)(uv_fs_t* req); +static ssize_t uv__fs_buf_iter(uv_fs_t* req, uv__fs_buf_iter_processor process) { + unsigned int iovmax; + unsigned int nbufs; + uv_buf_t* bufs; + ssize_t total; + ssize_t result; + + iovmax = uv__getiovmax(); + nbufs = req->nbufs; + bufs = req->bufs; + total = 0; + + while (nbufs > 0) { + req->nbufs = nbufs; + if (req->nbufs > iovmax) + req->nbufs = iovmax; + + result = process(req); + if (result <= 0) { + if (total == 0) + total = result; + break; + } + + if (req->off >= 0) + req->off += result; + + req->bufs += req->nbufs; + nbufs -= req->nbufs; + total += result; + } + + if (bufs != req->bufsml) + uv__free(bufs); + req->bufs = NULL; + + return total; +} + + static void uv__fs_work(struct uv__work* w) { int retry_on_eintr; uv_fs_t* req; @@ -810,7 +857,7 @@ static void uv__fs_work(struct uv__work* w) { X(MKDIR, mkdir(req->path, req->mode)); X(MKDTEMP, uv__fs_mkdtemp(req)); X(OPEN, uv__fs_open(req)); - X(READ, uv__fs_read(req)); + X(READ, uv__fs_buf_iter(req, uv__fs_read)); X(SCANDIR, uv__fs_scandir(req)); X(READLINK, uv__fs_readlink(req)); X(RENAME, rename(req->path, req->new_path)); @@ -820,7 +867,7 @@ static void uv__fs_work(struct uv__work* w) { X(SYMLINK, symlink(req->path, req->new_path)); X(UNLINK, unlink(req->path)); X(UTIME, uv__fs_utime(req)); - X(WRITE, uv__fs_write(req)); + X(WRITE, uv__fs_buf_iter(req, uv__fs_write)); default: abort(); } #undef X @@ -850,8 +897,7 @@ static void uv__fs_done(struct uv__work* w, int status) { req->result = -ECANCELED; } - if (req->cb != NULL) - req->cb(req); + req->cb(req); } @@ -1035,6 +1081,9 @@ int uv_fs_read(uv_loop_t* loop, uv_fs_t* req, unsigned int nbufs, int64_t off, uv_fs_cb cb) { + if (bufs == NULL || nbufs == 0) + return -EINVAL; + INIT(READ); req->file = file; @@ -1157,6 +1206,9 @@ int uv_fs_write(uv_loop_t* loop, unsigned int nbufs, int64_t off, uv_fs_cb cb) { + if (bufs == NULL || nbufs == 0) + return -EINVAL; + INIT(WRITE); req->file = file; @@ -1176,7 +1228,14 @@ int uv_fs_write(uv_loop_t* loop, void uv_fs_req_cleanup(uv_fs_t* req) { - uv__free((void*)req->path); + /* Only necessary for asychronous requests, i.e., requests with a callback. + * Synchronous ones don't copy their arguments and have req->path and + * req->new_path pointing to user-owned memory. UV_FS_MKDTEMP is the + * exception to the rule, it always allocates memory. + */ + if (req->path != NULL && (req->cb != NULL || req->fs_type == UV_FS_MKDTEMP)) + uv__free((void*) req->path); /* Memory is shared with req->new_path. */ + req->path = NULL; req->new_path = NULL; diff --git a/deps/uv/src/unix/internal.h b/deps/uv/src/unix/internal.h index c31e54992d..741fa57d69 100644 --- a/deps/uv/src/unix/internal.h +++ b/deps/uv/src/unix/internal.h @@ -172,6 +172,7 @@ int uv__socket(int domain, int type, int protocol); int uv__dup(int fd); ssize_t uv__recvmsg(int fd, struct msghdr *msg, int flags); void uv__make_close_pending(uv_handle_t* handle); +int uv__getiovmax(void); void uv__io_init(uv__io_t* w, uv__io_cb cb, int fd); void uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events); diff --git a/deps/uv/src/unix/kqueue.c b/deps/uv/src/unix/kqueue.c index 424236a6ef..495f20d285 100644 --- a/deps/uv/src/unix/kqueue.c +++ b/deps/uv/src/unix/kqueue.c @@ -379,6 +379,10 @@ int uv_fs_event_start(uv_fs_event_t* handle, if (!(statbuf.st_mode & S_IFDIR)) goto fallback; + /* The fallback fd is no longer needed */ + uv__close(fd); + handle->event_watcher.fd = -1; + return uv__fsevents_init(handle); fallback: @@ -406,8 +410,12 @@ int uv_fs_event_stop(uv_fs_event_t* handle) { uv__free(handle->path); handle->path = NULL; - uv__close(handle->event_watcher.fd); - handle->event_watcher.fd = -1; + if (handle->event_watcher.fd != -1) { + /* When FSEvents is used, we don't use the event_watcher's fd under certain + * confitions. (see uv_fs_event_start) */ + uv__close(handle->event_watcher.fd); + handle->event_watcher.fd = -1; + } return 0; } diff --git a/deps/uv/src/unix/loop.c b/deps/uv/src/unix/loop.c index aa9146bf9a..92e96f09ed 100644 --- a/deps/uv/src/unix/loop.c +++ b/deps/uv/src/unix/loop.c @@ -63,24 +63,44 @@ int uv_loop_init(uv_loop_t* loop) { if (err) return err; - uv_signal_init(loop, &loop->child_watcher); + err = uv_signal_init(loop, &loop->child_watcher); + if (err) + goto fail_signal_init; + uv__handle_unref(&loop->child_watcher); loop->child_watcher.flags |= UV__HANDLE_INTERNAL; QUEUE_INIT(&loop->process_handles); - if (uv_rwlock_init(&loop->cloexec_lock)) - abort(); + err = uv_rwlock_init(&loop->cloexec_lock); + if (err) + goto fail_rwlock_init; - if (uv_mutex_init(&loop->wq_mutex)) - abort(); + err = uv_mutex_init(&loop->wq_mutex); + if (err) + goto fail_mutex_init; - if (uv_async_init(loop, &loop->wq_async, uv__work_done)) - abort(); + err = uv_async_init(loop, &loop->wq_async, uv__work_done); + if (err) + goto fail_async_init; uv__handle_unref(&loop->wq_async); loop->wq_async.flags |= UV__HANDLE_INTERNAL; return 0; + +fail_async_init: + uv_mutex_destroy(&loop->wq_mutex); + +fail_mutex_init: + uv_rwlock_destroy(&loop->cloexec_lock); + +fail_rwlock_init: + uv__signal_loop_cleanup(loop); + +fail_signal_init: + uv__platform_loop_delete(loop); + + return err; } diff --git a/deps/uv/src/unix/pthread-fixes.c b/deps/uv/src/unix/pthread-fixes.c index dc54f35d60..3a71eb5aae 100644 --- a/deps/uv/src/unix/pthread-fixes.c +++ b/deps/uv/src/unix/pthread-fixes.c @@ -35,6 +35,7 @@ * */ #include <errno.h> #include <pthread.h> +#include <signal.h> int uv__pthread_sigmask(int how, const sigset_t* set, sigset_t* oset) { static int workaround; diff --git a/deps/uv/src/unix/stream.c b/deps/uv/src/unix/stream.c index 7ad1658cf8..183b68cf71 100644 --- a/deps/uv/src/unix/stream.c +++ b/deps/uv/src/unix/stream.c @@ -391,6 +391,9 @@ int uv__stream_open(uv_stream_t* stream, int fd, int flags) { int enable; #endif + if (!(stream->io_watcher.fd == -1 || stream->io_watcher.fd == fd)) + return -EBUSY; + assert(fd >= 0); stream->flags |= flags; @@ -736,19 +739,6 @@ static int uv__handle_fd(uv_handle_t* handle) { } } -static int uv__getiovmax() { -#if defined(IOV_MAX) - return IOV_MAX; -#elif defined(_SC_IOV_MAX) - static int iovmax = -1; - if (iovmax == -1) - iovmax = sysconf(_SC_IOV_MAX); - return iovmax; -#else - return 1024; -#endif -} - static void uv__write(uv_stream_t* stream) { struct iovec* iov; QUEUE* q; @@ -819,7 +809,17 @@ start: do { n = sendmsg(uv__stream_fd(stream), &msg, 0); } +#if defined(__APPLE__) + /* + * Due to a possible kernel bug at least in OS X 10.10 "Yosemite", + * EPROTOTYPE can be returned while trying to write to a socket that is + * shutting down. If we retry the write, we should get the expected EPIPE + * instead. + */ + while (n == -1 && (errno == EINTR || errno == EPROTOTYPE)); +#else while (n == -1 && errno == EINTR); +#endif } else { do { if (iovcnt == 1) { @@ -828,7 +828,17 @@ start: n = writev(uv__stream_fd(stream), iov, iovcnt); } } +#if defined(__APPLE__) + /* + * Due to a possible kernel bug at least in OS X 10.10 "Yosemite", + * EPROTOTYPE can be returned while trying to write to a socket that is + * shutting down. If we retry the write, we should get the expected EPIPE + * instead. + */ + while (n == -1 && (errno == EINTR || errno == EPROTOTYPE)); +#else while (n == -1 && errno == EINTR); +#endif } if (n < 0) { diff --git a/deps/uv/src/unix/tcp.c b/deps/uv/src/unix/tcp.c index 4060e7bd70..6d213a4977 100644 --- a/deps/uv/src/unix/tcp.c +++ b/deps/uv/src/unix/tcp.c @@ -28,18 +28,14 @@ #include <errno.h> -int uv_tcp_init(uv_loop_t* loop, uv_tcp_t* tcp) { - uv__stream_init(loop, (uv_stream_t*)tcp, UV_TCP); - return 0; -} - - static int maybe_new_socket(uv_tcp_t* handle, int domain, int flags) { int sockfd; int err; - if (uv__stream_fd(handle) != -1) + if (domain == AF_UNSPEC || uv__stream_fd(handle) != -1) { + handle->flags |= flags; return 0; + } err = uv__socket(domain, SOCK_STREAM, 0); if (err < 0) @@ -56,6 +52,40 @@ static int maybe_new_socket(uv_tcp_t* handle, int domain, int flags) { } +int uv_tcp_init_ex(uv_loop_t* loop, uv_tcp_t* tcp, unsigned int flags) { + int domain; + + /* Use the lower 8 bits for the domain */ + domain = flags & 0xFF; + if (domain != AF_INET && domain != AF_INET6 && domain != AF_UNSPEC) + return -EINVAL; + + if (flags & ~0xFF) + return -EINVAL; + + uv__stream_init(loop, (uv_stream_t*)tcp, UV_TCP); + + /* 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 (domain != AF_UNSPEC) { + int err = maybe_new_socket(tcp, domain, 0); + if (err) { + QUEUE_REMOVE(&tcp->handle_queue); + return err; + } + } + + return 0; +} + + +int uv_tcp_init(uv_loop_t* loop, uv_tcp_t* tcp) { + return uv_tcp_init_ex(loop, tcp, AF_UNSPEC); +} + + int uv__tcp_bind(uv_tcp_t* tcp, const struct sockaddr* addr, unsigned int addrlen, @@ -91,8 +121,13 @@ int uv__tcp_bind(uv_tcp_t* tcp, #endif errno = 0; - if (bind(tcp->io_watcher.fd, addr, addrlen) && errno != EADDRINUSE) + if (bind(tcp->io_watcher.fd, addr, addrlen) && errno != EADDRINUSE) { + if (errno == EAFNOSUPPORT) + /* OSX, other BSDs and SunoS fail with EAFNOSUPPORT when binding a + * socket created with AF_INET to an AF_INET6 address or vice versa. */ + return -EINVAL; return -errno; + } tcp->delayed_error = -errno; if (addr->sa_family == AF_INET6) diff --git a/deps/uv/src/unix/tty.c b/deps/uv/src/unix/tty.c index 7783548a6e..54c9055a08 100644 --- a/deps/uv/src/unix/tty.c +++ b/deps/uv/src/unix/tty.c @@ -51,8 +51,6 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) { 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. @@ -89,11 +87,18 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) { } 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 defined(__APPLE__) r = uv__stream_try_select((uv_stream_t*) tty, &fd); if (r) { if (newfd != -1) uv__close(newfd); + QUEUE_REMOVE(&tty->handle_queue); return r; } #endif diff --git a/deps/uv/src/unix/udp.c b/deps/uv/src/unix/udp.c index f85ab1473a..66ecc4e341 100644 --- a/deps/uv/src/unix/udp.c +++ b/deps/uv/src/unix/udp.c @@ -321,6 +321,10 @@ int uv__udp_bind(uv_udp_t* handle, if (bind(fd, addr, addrlen)) { err = -errno; + if (errno == EAFNOSUPPORT) + /* OSX, other BSDs and SunoS fail with EAFNOSUPPORT when binding a + * socket created with AF_INET to an AF_INET6 address or vice versa. */ + err = -EINVAL; goto out; } @@ -551,25 +555,51 @@ static int uv__udp_set_membership6(uv_udp_t* handle, } -int uv_udp_init(uv_loop_t* loop, uv_udp_t* handle) { +int uv_udp_init_ex(uv_loop_t* loop, uv_udp_t* handle, unsigned int flags) { + int domain; + int err; + int fd; + + /* Use the lower 8 bits for the domain */ + domain = flags & 0xFF; + if (domain != AF_INET && domain != AF_INET6 && domain != AF_UNSPEC) + return -EINVAL; + + if (flags & ~0xFF) + return -EINVAL; + + if (domain != AF_UNSPEC) { + err = uv__socket(domain, SOCK_DGRAM, 0); + if (err < 0) + return err; + fd = err; + } else { + fd = -1; + } + uv__handle_init(loop, (uv_handle_t*)handle, UV_UDP); handle->alloc_cb = NULL; handle->recv_cb = NULL; handle->send_queue_size = 0; handle->send_queue_count = 0; - uv__io_init(&handle->io_watcher, uv__udp_io, -1); + uv__io_init(&handle->io_watcher, uv__udp_io, fd); QUEUE_INIT(&handle->write_queue); QUEUE_INIT(&handle->write_completed_queue); return 0; } +int uv_udp_init(uv_loop_t* loop, uv_udp_t* handle) { + return uv_udp_init_ex(loop, handle, AF_UNSPEC); +} + + int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock) { int err; /* Check for already active socket. */ if (handle->io_watcher.fd != -1) - return -EALREADY; /* FIXME(bnoordhuis) Should be -EBUSY. */ + return -EBUSY; err = uv__nonblock(sock, 1); if (err) @@ -638,6 +668,8 @@ static int uv__setsockopt_maybe_char(uv_udp_t* handle, int val) { #if defined(__sun) || defined(_AIX) char arg = val; +#elif defined(__OpenBSD__) + unsigned char arg = val; #else int arg = val; #endif @@ -672,13 +704,13 @@ int uv_udp_set_ttl(uv_udp_t* handle, int ttl) { * so hardcode the size of these options on this platform, * and use the general uv__setsockopt_maybe_char call on other platforms. */ -#if defined(__sun) || defined(_AIX) +#if defined(__sun) || defined(_AIX) || defined(__OpenBSD__) return uv__setsockopt(handle, IP_TTL, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl)); -#endif /* defined(__sun) || defined(_AIX) */ +#endif /* defined(__sun) || defined(_AIX) || defined (__OpenBSD__) */ return uv__setsockopt_maybe_char(handle, IP_TTL, |