summaryrefslogtreecommitdiff
path: root/deps/uv/src/unix
diff options
context:
space:
mode:
Diffstat (limited to 'deps/uv/src/unix')
-rw-r--r--deps/uv/src/unix/aix.c187
-rw-r--r--deps/uv/src/unix/core.c30
-rw-r--r--deps/uv/src/unix/freebsd.c35
-rw-r--r--deps/uv/src/unix/fs.c137
-rw-r--r--deps/uv/src/unix/internal.h1
-rw-r--r--deps/uv/src/unix/kqueue.c12
-rw-r--r--deps/uv/src/unix/loop.c34
-rw-r--r--deps/uv/src/unix/pthread-fixes.c1
-rw-r--r--deps/uv/src/unix/stream.c36
-rw-r--r--deps/uv/src/unix/tcp.c51
-rw-r--r--deps/uv/src/unix/tty.c9
-rw-r--r--deps/uv/src/unix/udp.c42
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,