#endif
/* Expand this list if necessary. */
+#define UV_ERRNO_MAP(XX) \
+ XX( -1, UNKNOWN, "unknown error") \
+ XX( 0, OK, "success") \
+ XX( 1, EOF, "end of file") \
+ XX( 2, EADDRINFO, "getaddrinfo error") \
+ XX( 3, EACCES, "permission denied") \
+ XX( 4, EAGAIN, "no more processes") \
+ XX( 5, EADDRINUSE, "address already in use") \
+ XX( 6, EADDRNOTAVAIL, "") \
+ XX( 7, EAFNOSUPPORT, "") \
+ XX( 8, EALREADY, "") \
+ XX( 9, EBADF, "bad file descriptor") \
+ XX( 10, EBUSY, "mount device busy") \
+ XX( 11, ECONNABORTED, "software caused connection abort") \
+ XX( 12, ECONNREFUSED, "connection refused") \
+ XX( 13, ECONNRESET, "connection reset by peer") \
+ XX( 14, EDESTADDRREQ, "destination address required") \
+ XX( 15, EFAULT, "bad address in system call argument") \
+ XX( 16, EHOSTUNREACH, "host is unreachable") \
+ XX( 17, EINTR, "interrupted system call") \
+ XX( 18, EINVAL, "invalid argument") \
+ XX( 19, EISCONN, "socket is already connected") \
+ XX( 20, EMFILE, "too many open files") \
+ XX( 21, EMSGSIZE, "message too long") \
+ XX( 22, ENETDOWN, "network is down") \
+ XX( 23, ENETUNREACH, "network is unreachable") \
+ XX( 24, ENFILE, "file table overflow") \
+ XX( 25, ENOBUFS, "no buffer space available") \
+ XX( 26, ENOMEM, "not enough memory") \
+ XX( 27, ENOTDIR, "not a directory") \
+ XX( 28, EISDIR, "illegal operation on a directory") \
+ XX( 29, ENONET, "machine is not on the network") \
+ XX( 31, ENOTCONN, "socket is not connected") \
+ XX( 32, ENOTSOCK, "socket operation on non-socket") \
+ XX( 33, ENOTSUP, "operation not supported on socket") \
+ XX( 34, ENOENT, "no such file or directory") \
+ XX( 35, ENOSYS, "function not implemented") \
+ XX( 36, EPIPE, "broken pipe") \
+ XX( 37, EPROTO, "protocol error") \
+ XX( 38, EPROTONOSUPPORT, "protocol not suppored") \
+ XX( 39, EPROTOTYPE, "protocol wrong type for socket") \
+ XX( 40, ETIMEDOUT, "connection timed out") \
+ XX( 41, ECHARSET, "") \
+ XX( 42, EAIFAMNOSUPPORT, "") \
+ XX( 43, EAINONAME, "") \
+ XX( 44, EAISERVICE, "") \
+ XX( 45, EAISOCKTYPE, "") \
+ XX( 46, ESHUTDOWN, "") \
+ XX( 47, EEXIST, "file already exists") \
+ XX( 48, ESRCH, "no such process")
+
+
+#define UV_ERRNO_GEN(val, name, s) UV_##name = val,
typedef enum {
- UV_UNKNOWN = -1,
- UV_OK = 0,
- UV_EOF,
- UV_EADDRINFO,
- UV_EACCES,
- UV_EAGAIN,
- UV_EADDRINUSE,
- UV_EADDRNOTAVAIL,
- UV_EAFNOSUPPORT,
- UV_EALREADY,
- UV_EBADF,
- UV_EBUSY,
- UV_ECONNABORTED,
- UV_ECONNREFUSED,
- UV_ECONNRESET,
- UV_EDESTADDRREQ,
- UV_EFAULT,
- UV_EHOSTUNREACH,
- UV_EINTR,
- UV_EINVAL,
- UV_EISCONN,
- UV_EMFILE,
- UV_EMSGSIZE,
- UV_ENETDOWN,
- UV_ENETUNREACH,
- UV_ENFILE,
- UV_ENOBUFS,
- UV_ENOMEM,
- UV_ENOTDIR,
- UV_EISDIR,
- UV_ENONET,
- UV_ENOPROTOOPT,
- UV_ENOTCONN,
- UV_ENOTSOCK,
- UV_ENOTSUP,
- UV_ENOENT,
- UV_ENOSYS,
- UV_EPIPE,
- UV_EPROTO,
- UV_EPROTONOSUPPORT,
- UV_EPROTOTYPE,
- UV_ETIMEDOUT,
- UV_ECHARSET,
- UV_EAIFAMNOSUPPORT,
- UV_EAINONAME,
- UV_EAISERVICE,
- UV_EAISOCKTYPE,
- UV_ESHUTDOWN,
- UV_EEXIST,
- UV_ESRCH
+ UV_ERRNO_MAP(UV_ERRNO_GEN)
+ UV_MAX_ERRORS
} uv_err_code;
+#undef UV_ERRNO_GEN
typedef enum {
UV_UNKNOWN_HANDLE = 0,
static int uv_getaddrinfo_done(eio_req* req) {
uv_getaddrinfo_t* handle = req->data;
struct addrinfo *res = handle->res;
+#if __sun
+ size_t hostlen = strlen(handle->hostname);
+#endif
+
handle->res = NULL;
uv_unref(handle->loop);
} else if (handle->retcode == EAI_NONAME) {
#endif
uv__set_sys_error(handle->loop, ENOENT); /* FIXME compatibility hack */
+#if __sun
+ } else if (handle->retcode == EAI_MEMORY && hostlen >= MAXHOSTNAMELEN) {
+ uv__set_sys_error(handle->loop, ENOENT);
+#endif
} else {
handle->loop->last_err.code = UV_EADDRINFO;
handle->loop->last_err.sys_errno_ = handle->retcode;
/* Open a socket in non-blocking close-on-exec mode, atomically if possible. */
int uv__socket(int domain, int type, int protocol) {
-#if defined(SOCK_NONBLOCK) && defined(SOCK_CLOEXEC)
- return socket(domain, type | SOCK_NONBLOCK | SOCK_CLOEXEC, protocol);
-#else
int sockfd;
- if ((sockfd = socket(domain, type, protocol)) == -1) {
- return -1;
- }
+#if defined(SOCK_NONBLOCK) && defined(SOCK_CLOEXEC)
+ sockfd = socket(domain, type | SOCK_NONBLOCK | SOCK_CLOEXEC, protocol);
- if (uv__nonblock(sockfd, 1) == -1 || uv__cloexec(sockfd, 1) == -1) {
+ if (sockfd != -1)
+ goto out;
+
+ if (errno != EINVAL)
+ goto out;
+#endif
+
+ sockfd = socket(domain, type, protocol);
+
+ if (sockfd == -1)
+ goto out;
+
+ if (uv__nonblock(sockfd, 1) || uv__cloexec(sockfd, 1)) {
uv__close(sockfd);
- return -1;
+ sockfd = -1;
}
+out:
return sockfd;
-#endif
}
assert(sockfd >= 0);
- do {
-#if defined(HAVE_ACCEPT4)
+ while (1) {
+#if HAVE_ACCEPT4
peerfd = accept4(sockfd, saddr, &slen, SOCK_NONBLOCK | SOCK_CLOEXEC);
-#else
- if ((peerfd = accept(sockfd, saddr, &slen)) != -1) {
- if (uv__cloexec(peerfd, 1) == -1 || uv__nonblock(peerfd, 1) == -1) {
- uv__close(peerfd);
- return -1;
- }
- }
+
+ if (peerfd != -1)
+ break;
+
+ if (errno == EINTR)
+ continue;
+
+ if (errno != ENOSYS)
+ break;
#endif
+
+ if ((peerfd = accept(sockfd, saddr, &slen)) == -1) {
+ if (errno == EINTR)
+ continue;
+ else
+ break;
+ }
+
+ if (uv__cloexec(peerfd, 1) || uv__nonblock(peerfd, 1)) {
+ uv__close(peerfd);
+ peerfd = -1;
+ }
+
+ break;
}
- while (peerfd == -1 && errno == EINTR);
return peerfd;
}
}
-static int uv__translate_lib_error(int code) {
- switch (code) {
- case UV_ENOSYS: return ENOSYS;
- case UV_ENOTSOCK: return ENOTSOCK;
- case UV_ENOENT: return ENOENT;
- case UV_EACCES: return EACCES;
- case UV_EAFNOSUPPORT: return EAFNOSUPPORT;
- case UV_EBADF: return EBADF;
- case UV_EPIPE: return EPIPE;
- case UV_EAGAIN: return EAGAIN;
- case UV_ECONNRESET: return ECONNRESET;
- case UV_EFAULT: return EFAULT;
- case UV_EMFILE: return EMFILE;
- case UV_EMSGSIZE: return EMSGSIZE;
- case UV_EINVAL: return EINVAL;
- case UV_ECONNREFUSED: return ECONNREFUSED;
- case UV_EADDRINUSE: return EADDRINUSE;
- case UV_EADDRNOTAVAIL: return EADDRNOTAVAIL;
- case UV_ENOTDIR: return ENOTDIR;
- case UV_EISDIR: return EISDIR;
- case UV_ENOTCONN: return ENOTCONN;
- case UV_EEXIST: return EEXIST;
- case UV_EHOSTUNREACH: return EHOSTUNREACH;
- case UV_ESRCH: return ESRCH;
- default: return -1;
- }
-
- assert(0 && "unreachable");
- return -1;
-}
-
-
uv_err_code uv_translate_sys_error(int sys_errno) {
switch (sys_errno) {
case 0: return UV_OK;
assert(0 && "unreachable");
return -1;
}
-
-
-/* TODO Pull in error messages so we don't have to
- * a) rely on what the system provides us
- * b) reverse-map the error codes
- */
-const char* uv_strerror(uv_err_t err) {
- int errorno;
-
- if (err.sys_errno_)
- errorno = err.sys_errno_;
- else
- errorno = uv__translate_lib_error(err.code);
-
- if (err.code == UV_EADDRINFO)
- return gai_strerror(errorno);
-
- if (errorno == -1)
- return "Unknown error";
- else
- return strerror(errorno);
-}
int uv_exepath(char* buffer, size_t* size) {
- uint32_t usize;
- int result;
- char* path;
- char* fullpath;
int mib[4];
size_t cb;
}
+#define UV__F_IPC (1 << 0)
+#define UV__F_NONBLOCK (1 << 1)
+
+static int uv__make_socketpair(int fds[2], int flags) {
+#ifdef SOCK_NONBLOCK
+ int fl;
+
+ fl = SOCK_CLOEXEC;
+
+ if (flags & UV__F_NONBLOCK)
+ fl |= SOCK_NONBLOCK;
+
+ if (socketpair(AF_UNIX, SOCK_STREAM|fl, 0, fds) == 0)
+ return 0;
+
+ if (errno != EINVAL)
+ return -1;
+
+ /* errno == EINVAL so maybe the kernel headers lied about
+ * the availability of SOCK_NONBLOCK. This can happen if people
+ * build libuv against newer kernel headers than the kernel
+ * they actually run the software on.
+ */
+#endif
+
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds))
+ return -1;
+
+ uv__cloexec(fds[0], 1);
+ uv__cloexec(fds[1], 1);
+
+ if (flags & UV__F_NONBLOCK) {
+ uv__nonblock(fds[0], 1);
+ uv__nonblock(fds[1], 1);
+ }
+
+ return 0;
+}
+
+
+static int uv__make_pipe(int fds[2], int flags) {
+#if HAVE_PIPE2
+ int fl;
+
+ fl = O_CLOEXEC;
+
+ if (flags & UV__F_NONBLOCK)
+ fl |= O_NONBLOCK;
+
+ if (pipe2(fds, fl) == 0)
+ return 0;
+
+ if (errno != ENOSYS)
+ return -1;
+
+ /* errno == ENOSYS so maybe the kernel headers lied about
+ * the availability of pipe2(). This can happen if people
+ * build libuv against newer kernel headers than the kernel
+ * they actually run the software on.
+ */
+#endif
+
+ if (pipe(fds))
+ return -1;
+
+ uv__cloexec(fds[0], 1);
+ uv__cloexec(fds[1], 1);
+
+ if (flags & UV__F_NONBLOCK) {
+ uv__nonblock(fds[0], 1);
+ uv__nonblock(fds[1], 1);
+ }
+
+ return 0;
+}
+
+
/*
* Used for initializing stdio streams like options.stdin_stream. Returns
* zero on success.
*/
-static int uv__process_init_pipe(uv_pipe_t* handle, int fds[2]) {
+static int uv__process_init_pipe(uv_pipe_t* handle, int fds[2], int flags) {
if (handle->type != UV_NAMED_PIPE) {
errno = EINVAL;
return -1;
}
- if (handle->ipc) {
- if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) {
- return -1;
- }
- } else {
- if (pipe(fds) < 0) {
- return -1;
- }
- }
-
- uv__cloexec(fds[0], 1);
- uv__cloexec(fds[1], 1);
-
- return 0;
+ if (handle->ipc)
+ return uv__make_socketpair(fds, flags);
+ else
+ return uv__make_pipe(fds, flags);
}
process->exit_cb = options.exit_cb;
if (options.stdin_stream &&
- uv__process_init_pipe(options.stdin_stream, stdin_pipe)) {
+ uv__process_init_pipe(options.stdin_stream, stdin_pipe, 0)) {
goto error;
}
if (options.stdout_stream &&
- uv__process_init_pipe(options.stdout_stream, stdout_pipe)) {
+ uv__process_init_pipe(options.stdout_stream, stdout_pipe, 0)) {
goto error;
}
if (options.stderr_stream &&
- uv__process_init_pipe(options.stderr_stream, stderr_pipe)) {
+ uv__process_init_pipe(options.stderr_stream, stderr_pipe, 0)) {
goto error;
}
* the parent polls the read end until it sees POLLHUP.
*/
#if SPAWN_WAIT_EXEC
-# ifdef HAVE_PIPE2
- if (pipe2(signal_pipe, O_CLOEXEC | O_NONBLOCK) < 0) {
+ if (uv__make_pipe(signal_pipe, UV__F_NONBLOCK))
goto error;
- }
-# else
- if (socketpair(AF_UNIX, SOCK_STREAM, 0, signal_pipe) < 0) {
- goto error;
- }
- uv__cloexec(signal_pipe[0], 1);
- uv__cloexec(signal_pipe[1], 1);
- uv__nonblock(signal_pipe[0], 1);
- uv__nonblock(signal_pipe[1], 1);
-# endif
#endif
pid = fork();
const uv_err_t uv_ok_ = { UV_OK, 0 };
-
+#define UV_ERR_NAME_GEN(val, name, s) case UV_##name : return #name;
const char* uv_err_name(uv_err_t err) {
switch (err.code) {
- case UV_UNKNOWN: return "UNKNOWN";
- case UV_OK: return "OK";
- case UV_EOF: return "EOF";
- case UV_EADDRINFO: return "EADDRINFO";
- case UV_EACCES: return "EACCES";
- case UV_EAGAIN: return "EAGAIN";
- case UV_EADDRINUSE: return "EADDRINUSE";
- case UV_EADDRNOTAVAIL: return "EADDRNOTAVAIL";
- case UV_EAFNOSUPPORT: return "EAFNOSUPPORT";
- case UV_EALREADY: return "EALREADY";
- case UV_EBADF: return "EBADF";
- case UV_EBUSY: return "EBUSY";
- case UV_ECONNABORTED: return "ECONNABORTED";
- case UV_ECONNREFUSED: return "ECONNREFUSED";
- case UV_ECONNRESET: return "ECONNRESET";
- case UV_EDESTADDRREQ: return "EDESTADDRREQ";
- case UV_EFAULT: return "EFAULT";
- case UV_EHOSTUNREACH: return "EHOSTUNREACH";
- case UV_EINTR: return "EINTR";
- case UV_EINVAL: return "EINVAL";
- case UV_EISCONN: return "EISCONN";
- case UV_EMFILE: return "EMFILE";
- case UV_EMSGSIZE: return "EMSGSIZE";
- case UV_ENETDOWN: return "ENETDOWN";
- case UV_ENETUNREACH: return "ENETUNREACH";
- case UV_ENFILE: return "ENFILE";
- case UV_ENOBUFS: return "ENOBUFS";
- case UV_ENOMEM: return "ENOMEM";
- case UV_ENOTDIR: return "ENOTDIR";
- case UV_ENONET: return "ENONET";
- case UV_ENOPROTOOPT: return "ENOPROTOOPT";
- case UV_ENOTCONN: return "ENOTCONN";
- case UV_ENOTSOCK: return "ENOTSOCK";
- case UV_ENOTSUP: return "ENOTSUP";
- case UV_ENOENT: return "ENOENT";
- case UV_ENOSYS: return "ENOSYS";
- case UV_EPIPE: return "EPIPE";
- case UV_EPROTO: return "EPROTO";
- case UV_EPROTONOSUPPORT: return "EPROTONOSUPPORT";
- case UV_EPROTOTYPE: return "EPROTOTYPE";
- case UV_ETIMEDOUT: return "ETIMEDOUT";
- case UV_ECHARSET: return "ECHARSET";
- case UV_EAIFAMNOSUPPORT: return "EAIFAMNOSUPPORT";
- case UV_EAINONAME: return "EAINONAME";
- case UV_EAISERVICE: return "EAISERVICE";
- case UV_EAISOCKTYPE: return "EAISOCKTYPE";
- case UV_ESHUTDOWN: return "ESHUTDOWN";
- case UV_EEXIST: return "EEXIST";
- case UV_ESRCH: return "ESRCH";
+ UV_ERRNO_MAP(UV_ERR_NAME_GEN)
default:
assert(0);
return NULL;
}
}
+#undef UV_ERR_NAME_GEN
+
+
+#define UV_STRERROR_GEN(val, name, s) case UV_##name : return s;
+const char* uv_strerror(uv_err_t err) {
+ switch (err.code) {
+ UV_ERRNO_MAP(UV_STRERROR_GEN)
+ default:
+ return "Unknown system error";
+ }
+}
+#undef UV_STRERROR_GEN
void uv__set_error(uv_loop_t* loop, uv_err_code code, int sys_error) {
}
-/* TODO: thread safety */
-static char* last_err_str_ = NULL;
-
-const char* uv_strerror(uv_err_t err) {
- if (last_err_str_ != NULL) {
- LocalFree(last_err_str_);
- }
-
- FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
- FORMAT_MESSAGE_IGNORE_INSERTS, NULL, err.sys_errno_,
- MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR) &last_err_str_, 0,
- NULL);
-
- if (last_err_str_) {
- return last_err_str_;
- } else {
- return "Unknown error";
- }
-}
-
-
uv_err_code uv_translate_sys_error(int sys_errno) {
switch (sys_errno) {
case ERROR_SUCCESS: return UV_OK;
HANDLE dir;
WIN32_FIND_DATAW ent = {0};
size_t len = wcslen(path);
- size_t buf_size = 4096;
+ size_t buf_char_len = 4096;
wchar_t* path2;
const wchar_t* fmt = !len ? L"./*"
: (path[len - 1] == L'/' || path[len - 1] == L'\\') ? L"%s*"
len = wcslen(name);
if (!buf) {
- buf = (wchar_t*)malloc(buf_size * sizeof(wchar_t));
+ buf = (wchar_t*)malloc(buf_char_len * sizeof(wchar_t));
if (!buf) {
uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
}
ptr = buf;
}
- while ((ptr - buf) + len + 1 > buf_size) {
- buf_size *= 2;
+ while ((ptr - buf) + len + 1 > buf_char_len) {
+ buf_char_len *= 2;
path2 = buf;
- buf = (wchar_t*)realloc(buf, buf_size * sizeof(wchar_t));
+ buf = (wchar_t*)realloc(buf, buf_char_len * sizeof(wchar_t));
if (!buf) {
uv_fatal_error(ERROR_OUTOFMEMORY, "realloc");
}
if (buf) {
/* Convert result to UTF8. */
- size = uv_utf16_to_utf8(buf, buf_size / sizeof(wchar_t), NULL, 0);
+ size = uv_utf16_to_utf8(buf, buf_char_len, NULL, 0);
if (!size) {
SET_REQ_RESULT_WIN32_ERROR(req, GetLastError());
return;
uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
}
- size = uv_utf16_to_utf8(buf, buf_size / sizeof(wchar_t), (char*)req->ptr, size);
+ size = uv_utf16_to_utf8(buf, buf_char_len, (char*)req->ptr, size);
if (!size) {
free(buf);
free(req->ptr);
err = GET_REQ_SOCK_ERROR(req);
if (err == WSAECONNABORTED) {
- /* Treat WSAECONNABORTED as connection closed. */
- handle->flags |= UV_HANDLE_EOF;
- uv__set_error(loop, UV_EOF, ERROR_SUCCESS);
+ /*
+ * Turn WSAECONNABORTED into UV_ECONNRESET to be consistent with Unix.
+ */
+ uv__set_error(loop, UV_ECONNRESET, err);
} else {
uv__set_sys_error(loop, err);
}
handle->read_cb((uv_stream_t*)handle, 0, buf);
} else {
if (err == WSAECONNABORTED) {
- /* Treat WSAECONNABORTED as connection closed. */
- handle->flags |= UV_HANDLE_EOF;
- uv__set_error(loop, UV_EOF, ERROR_SUCCESS);
+ /*
+ * Turn WSAECONNABORTED into UV_ECONNRESET to be consistent with Unix.
+ */
+ uv__set_error(loop, UV_ECONNRESET, err);
} else {
/* Ouch! serious error. */
uv__set_sys_error(loop, err);
static int write_cb_called;
static int read_cb_called;
-static int read_eof_cb_called;
-
static void connection_cb(uv_stream_t* server, int status) {
int r;
static void read_cb(uv_stream_t* stream, ssize_t nread, uv_buf_t buf) {
if (nread == -1) {
fprintf(stderr, "read_cb error: %s\n", uv_err_name(uv_last_error(stream->loop)));
- ASSERT(uv_last_error(stream->loop).code == UV_EOF);
+ ASSERT(uv_last_error(stream->loop).code == UV_ECONNRESET ||
+ uv_last_error(stream->loop).code == UV_EOF);
uv_close((uv_handle_t*)&tcp_server, NULL);
uv_close((uv_handle_t*)&tcp_peer, NULL);
-
- read_eof_cb_called++;
}
read_cb_called++;
ASSERT(write_cb_called > 0);
ASSERT(read_cb_called > 0);
- ASSERT(read_eof_cb_called > 0);
return 0;
}