Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

uv: upgrade to 80e5491

  • Loading branch information...
commit 28998a8cfe92043b27ff573b54258e21123616a4 1 parent 7003d6e
@bnoordhuis bnoordhuis authored
Showing with 6,505 additions and 109 deletions.
  1. +6 −4 deps/uv/README
  2. +20 −0 deps/uv/include/uv-unix.h
  3. +17 −4 deps/uv/include/uv-win.h
  4. +157 −3 deps/uv/include/uv.h
  5. +547 −10 deps/uv/src/uv-unix.c
  6. +0 −1  deps/uv/src/win/async.c
  7. +0 −8 deps/uv/src/win/core.c
  8. +1 −0  deps/uv/src/win/error.c
  9. +31 −9 deps/uv/src/win/handle.c
  10. +40 −1 deps/uv/src/win/internal.h
  11. +0 −1  deps/uv/src/win/loop-watcher.c
  12. +20 −23 deps/uv/src/win/pipe.c
  13. +0 −1  deps/uv/src/win/process.c
  14. +10 −1 deps/uv/src/win/req.c
  15. +0 −1  deps/uv/src/win/stream.c
  16. +22 −19 deps/uv/src/win/tcp.c
  17. +0 −1  deps/uv/src/win/timer.c
  18. +576 −0 deps/uv/src/win/udp.c
  19. +4,040 −2 deps/uv/src/win/winapi.h
  20. +115 −0 deps/uv/src/win/winsock.c
  21. +6 −2 deps/uv/src/win/winsock.h
  22. +21 −0 deps/uv/test/benchmark-list.h
  23. +1 −1  deps/uv/test/benchmark-ping-pongs.c
  24. +2 −2 deps/uv/test/benchmark-pound.c
  25. +2 −2 deps/uv/test/benchmark-pump.c
  26. +1 −1  deps/uv/test/benchmark-spawn.c
  27. +247 −0 deps/uv/test/benchmark-udp-packet-storm.c
  28. +1 −1  deps/uv/test/dns-server.c
  29. +1 −1  deps/uv/test/echo-server.c
  30. +1 −1  deps/uv/test/test-callback-stack.c
  31. +1 −1  deps/uv/test/test-delayed-accept.c
  32. +4 −4 deps/uv/test/test-getsockname.c
  33. +9 −0 deps/uv/test/test-list.h
  34. +1 −1  deps/uv/test/test-ping-pong.c
  35. +1 −1  deps/uv/test/test-shutdown-eof.c
  36. +1 −1  deps/uv/test/test-spawn.c
  37. +1 −1  deps/uv/test/test-tcp-writealot.c
  38. +88 −0 deps/uv/test/test-udp-dgram-too-big.c
  39. +141 −0 deps/uv/test/test-udp-ipv6-only.c
  40. +158 −0 deps/uv/test/test-udp-ipv6.c
  41. +210 −0 deps/uv/test/test-udp-send-and-recv.c
  42. +5 −0 deps/uv/uv.gyp
View
10 deps/uv/README
@@ -24,13 +24,15 @@ checkout GYP into the project tree manually:
svn co http://gyp.googlecode.com/svn/trunk build/gyp
-And then run
+Unix users run
- ./build/gyp_uv -f make
+ ./gyp_uv -f make
+ make
-or
+Macintosh users run
- ./build/gyp_uv -f xcode
+ ./gyp_uv -f xcode
+ xcodebuild -project uv.xcodeproj -configuration Release -target All
= Supported Platforms
View
20 deps/uv/include/uv-unix.h
@@ -55,6 +55,16 @@ typedef struct {
#define UV_CONNECT_PRIVATE_FIELDS \
ngx_queue_t queue;
+#define UV_UDP_SEND_PRIVATE_FIELDS \
+ ngx_queue_t queue; \
+ struct sockaddr_storage addr; \
+ socklen_t addrlen; \
+ uv_buf_t* bufs; \
+ int bufcnt; \
+ ssize_t status; \
+ uv_udp_send_cb send_cb; \
+ uv_buf_t bufsml[UV_REQ_BUFSML_SIZE]; \
+
#define UV_PRIVATE_REQ_TYPES /* empty */
@@ -83,6 +93,16 @@ typedef struct {
#define UV_TCP_PRIVATE_FIELDS
+/* UV_UDP */
+#define UV_UDP_PRIVATE_FIELDS \
+ uv_alloc_cb alloc_cb; \
+ uv_udp_recv_cb recv_cb; \
+ ev_io read_watcher; \
+ ev_io write_watcher; \
+ ngx_queue_t write_queue; \
+ ngx_queue_t write_completed_queue; \
+
+
/* UV_NAMED_PIPE */
#define UV_PIPE_PRIVATE_TYPEDEF
#define UV_PIPE_PRIVATE_FIELDS \
View
21 deps/uv/include/uv-win.h
@@ -48,7 +48,8 @@ typedef struct uv_buf_t {
UV_ARES_CLEANUP_REQ, \
UV_GETADDRINFO_REQ, \
UV_PROCESS_EXIT, \
- UV_PROCESS_CLOSE
+ UV_PROCESS_CLOSE, \
+ UV_UDP_RECV
#define UV_REQ_PRIVATE_FIELDS \
union { \
@@ -58,7 +59,6 @@ typedef struct uv_buf_t {
size_t queued_bytes; \
}; \
}; \
- uv_err_t error; \
struct uv_req_s* next_req;
#define UV_WRITE_PRIVATE_FIELDS \
@@ -70,6 +70,9 @@ typedef struct uv_buf_t {
#define UV_SHUTDOWN_PRIVATE_FIELDS \
/* empty */
+#define UV_UDP_SEND_PRIVATE_FIELDS \
+ /* empty */
+
#define UV_PRIVATE_REQ_TYPES \
typedef struct uv_pipe_accept_s { \
UV_REQ_FIELDS \
@@ -109,11 +112,22 @@ typedef struct uv_buf_t {
#define UV_TCP_PRIVATE_FIELDS \
SOCKET socket; \
+ uv_err_t bind_error; \
union { \
struct { uv_tcp_server_fields }; \
struct { uv_tcp_connection_fields }; \
};
+#define UV_UDP_PRIVATE_FIELDS \
+ SOCKET socket; \
+ unsigned int reqs_pending; \
+ uv_req_t recv_req; \
+ uv_buf_t recv_buffer; \
+ struct sockaddr_storage recv_from; \
+ int recv_from_len; \
+ uv_udp_recv_cb recv_cb; \
+ uv_alloc_cb alloc_cb;
+
#define uv_pipe_server_fields \
uv_pipe_accept_t accept_reqs[4]; \
uv_pipe_accept_t* pending_accepts;
@@ -157,8 +171,7 @@ typedef struct uv_buf_t {
#define UV_HANDLE_PRIVATE_FIELDS \
uv_handle_t* endgame_next; \
- unsigned int flags; \
- uv_err_t error;
+ unsigned int flags;
#define UV_ARES_TASK_PRIVATE_FIELDS \
struct uv_req_s ares_req; \
View
160 deps/uv/include/uv.h
@@ -45,6 +45,7 @@ typedef struct uv_err_s uv_err_t;
typedef struct uv_handle_s uv_handle_t;
typedef struct uv_stream_s uv_stream_t;
typedef struct uv_tcp_s uv_tcp_t;
+typedef struct uv_udp_s uv_udp_t;
typedef struct uv_pipe_s uv_pipe_t;
typedef struct uv_timer_s uv_timer_t;
typedef struct uv_prepare_s uv_prepare_t;
@@ -58,6 +59,7 @@ typedef struct uv_req_s uv_req_t;
typedef struct uv_shutdown_s uv_shutdown_t;
typedef struct uv_write_s uv_write_t;
typedef struct uv_connect_s uv_connect_t;
+typedef struct uv_udp_send_s uv_udp_send_t;
#if defined(__unix__) || defined(__POSIX__) || defined(__APPLE__)
# include "uv-unix.h"
@@ -106,8 +108,8 @@ int64_t uv_now();
* In the case of uv_read_cb the uv_buf_t returned should be freed by the
* user.
*/
-typedef uv_buf_t (*uv_alloc_cb)(uv_stream_t* tcp, size_t suggested_size);
-typedef void (*uv_read_cb)(uv_stream_t* tcp, ssize_t nread, uv_buf_t buf);
+typedef uv_buf_t (*uv_alloc_cb)(uv_handle_t* handle, size_t suggested_size);
+typedef void (*uv_read_cb)(uv_stream_t* stream, ssize_t nread, uv_buf_t buf);
typedef void (*uv_write_cb)(uv_write_t* req, int status);
typedef void (*uv_connect_cb)(uv_connect_t* req, int status);
typedef void (*uv_shutdown_cb)(uv_shutdown_t* req, int status);
@@ -146,6 +148,7 @@ typedef enum {
UV_EINVAL,
UV_EISCONN,
UV_EMFILE,
+ UV_EMSGSIZE,
UV_ENETDOWN,
UV_ENETUNREACH,
UV_ENFILE,
@@ -172,6 +175,7 @@ typedef enum {
typedef enum {
UV_UNKNOWN_HANDLE = 0,
UV_TCP,
+ UV_UDP,
UV_NAMED_PIPE,
UV_TTY,
UV_FILE,
@@ -194,6 +198,7 @@ typedef enum {
UV_WRITE,
UV_SHUTDOWN,
UV_WAKEUP,
+ UV_UDP_SEND,
UV_REQ_TYPE_PRIVATE
} uv_req_type;
@@ -415,7 +420,155 @@ struct uv_connect_s {
};
-int uv_getsockname(uv_tcp_t* handle, struct sockaddr* name, int* namelen);
+int uv_getsockname(uv_handle_t* handle, struct sockaddr* name, int* namelen);
+
+
+/*
+ * UDP support.
+ */
+
+enum uv_udp_flags {
+ /* Disables dual stack mode. Used with uv_udp_bind6(). */
+ UV_UDP_IPV6ONLY = 1,
+ /*
+ * Indicates message was truncated because read buffer was too small. The
+ * remainder was discarded by the OS. Used in uv_udp_recv_cb.
+ */
+ UV_UDP_PARTIAL = 2
+};
+
+/*
+ * Called after a uv_udp_send() or uv_udp_send6(). status 0 indicates
+ * success otherwise error.
+ */
+typedef void (*uv_udp_send_cb)(uv_udp_send_t* req, int status);
+
+/*
+ * Callback that is invoked when a new UDP datagram is received.
+ *
+ * handle UDP handle.
+ * nread Number of bytes that have been received.
+ * 0 if there is no more data to read. You may
+ * discard or repurpose the read buffer.
+ * -1 if a transmission error was detected.
+ * buf uv_buf_t with the received data.
+ * addr struct sockaddr_in or struct sockaddr_in6.
+ * Valid for the duration of the callback only.
+ * flags One or more OR'ed UV_UDP_* constants.
+ * Right now only UV_UDP_PARTIAL is used.
+ */
+typedef void (*uv_udp_recv_cb)(uv_udp_t* handle, ssize_t nread, uv_buf_t buf,
+ struct sockaddr* addr, unsigned flags);
+
+/* uv_udp_t is a subclass of uv_handle_t */
+struct uv_udp_s {
+ UV_HANDLE_FIELDS
+ UV_UDP_PRIVATE_FIELDS
+};
+
+/* uv_udp_send_t is a subclass of uv_req_t */
+struct uv_udp_send_s {
+ UV_REQ_FIELDS
+ uv_udp_t* handle;
+ uv_udp_send_cb cb;
+ UV_UDP_SEND_PRIVATE_FIELDS
+};
+
+/*
+ * Initialize a new UDP handle. The actual socket is created lazily.
+ * Returns 0 on success.
+ */
+int uv_udp_init(uv_udp_t* handle);
+
+/*
+ * Bind to a IPv4 address and port.
+ *
+ * Arguments:
+ * handle UDP handle. Should have been initialized with `uv_udp_init`.
+ * addr struct sockaddr_in with the address and port to bind to.
+ * flags Unused.
+ *
+ * Returns:
+ * 0 on success, -1 on error.
+ */
+int uv_udp_bind(uv_udp_t* handle, struct sockaddr_in addr, unsigned flags);
+
+/*
+ * Bind to a IPv6 address and port.
+ *
+ * Arguments:
+ * handle UDP handle. Should have been initialized with `uv_udp_init`.
+ * addr struct sockaddr_in with the address and port to bind to.
+ * flags Should be 0 or UV_UDP_IPV6ONLY.
+ *
+ * Returns:
+ * 0 on success, -1 on error.
+ */
+int uv_udp_bind6(uv_udp_t* handle, struct sockaddr_in6 addr, unsigned flags);
+
+/*
+ * Send data. If the socket has not previously been bound with `uv_udp_bind`
+ * or `uv_udp_bind6`, it is bound to 0.0.0.0 (the "all interfaces" address)
+ * and a random port number.
+ *
+ * Arguments:
+ * req UDP request handle. Need not be initialized.
+ * handle UDP handle. Should have been initialized with `uv_udp_init`.
+ * bufs List of buffers to send.
+ * bufcnt Number of buffers in `bufs`.
+ * addr Address of the remote peer. See `uv_ip4_addr`.
+ * send_cb Callback to invoke when the data has been sent out.
+ *
+ * Returns:
+ * 0 on success, -1 on error.
+ */
+int uv_udp_send(uv_udp_send_t* req, uv_udp_t* handle, uv_buf_t bufs[],
+ int bufcnt, struct sockaddr_in addr, uv_udp_send_cb send_cb);
+
+/*
+ * Send data. If the socket has not previously been bound with `uv_udp_bind6`,
+ * it is bound to ::0 (the "all interfaces" address) and a random port number.
+ *
+ * Arguments:
+ * req UDP request handle. Need not be initialized.
+ * handle UDP handle. Should have been initialized with `uv_udp_init`.
+ * bufs List of buffers to send.
+ * bufcnt Number of buffers in `bufs`.
+ * addr Address of the remote peer. See `uv_ip6_addr`.
+ * send_cb Callback to invoke when the data has been sent out.
+ *
+ * Returns:
+ * 0 on success, -1 on error.
+ */
+int uv_udp_send6(uv_udp_send_t* req, uv_udp_t* handle, uv_buf_t bufs[],
+ int bufcnt, struct sockaddr_in6 addr, uv_udp_send_cb send_cb);
+
+/*
+ * Send data. If the socket has not previously been bound with `uv_udp_bind`
+ * or `uv_udp_bind6`, it is bound to 0.0.0.0 (the "all interfaces" address)
+ * and a random port number.
+ *
+ * Arguments:
+ * handle UDP handle. Should have been initialized with `uv_udp_init`.
+ * alloc_cb Callback to invoke when temporary storage is needed.
+ * recv_cb Callback to invoke with received data.
+ *
+ * Returns:
+ * 0 on success, -1 on error.
+ */
+int uv_udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb,
+ uv_udp_recv_cb recv_cb);
+
+/*
+ * Stop listening for incoming datagrams.
+ *
+ * Arguments:
+ * handle UDP handle. Should have been initialized with `uv_udp_init`.
+ *
+ * Returns:
+ * 0 on success, -1 on error.
+ */
+int uv_udp_recv_stop(uv_udp_t* handle);
/*
@@ -699,6 +852,7 @@ typedef struct {
uint64_t handle_init;
uint64_t stream_init;
uint64_t tcp_init;
+ uint64_t udp_init;
uint64_t pipe_init;
uint64_t prepare_init;
uint64_t check_init;
View
557 deps/uv/src/uv-unix.c
@@ -103,6 +103,28 @@ static void uv__stream_connect(uv_stream_t*);
static void uv__stream_io(EV_P_ ev_io* watcher, int revents);
static void uv__pipe_accept(EV_P_ ev_io* watcher, int revents);
+static void uv__udp_watcher_start(uv_udp_t* handle, ev_io* w);
+static void uv__udp_watcher_stop(uv_udp_t* handle, ev_io* w);
+static void uv__udp_run_completed(uv_udp_t* handle);
+static void uv__udp_run_pending(uv_udp_t* handle);
+static void uv__udp_destroy(uv_udp_t* handle);
+static void uv__udp_recvmsg(uv_udp_t* handle);
+static void uv__udp_sendmsg(uv_udp_t* handle);
+static void uv__udp_io(EV_P_ ev_io* w, int events);
+static int uv__udp_bind(uv_udp_t* handle,
+ int domain,
+ struct sockaddr* addr,
+ socklen_t len,
+ unsigned flags);
+static int uv__udp_maybe_deferred_bind(uv_udp_t* handle, int domain);
+static int uv__udp_send(uv_udp_send_t* req,
+ uv_udp_t* handle,
+ uv_buf_t bufs[],
+ int bufcnt,
+ struct sockaddr* addr,
+ socklen_t addrlen,
+ uv_udp_send_cb send_cb);
+
#ifndef __GNUC__
#define __attribute__(a)
#endif
@@ -173,6 +195,7 @@ static uv_err_code uv_translate_sys_error(int sys_errno) {
case ECONNRESET: return UV_ECONNRESET;
case EFAULT: return UV_EFAULT;
case EMFILE: return UV_EMFILE;
+ case EMSGSIZE: return UV_EMSGSIZE;
case EINVAL: return UV_EINVAL;
case ECONNREFUSED: return UV_ECONNREFUSED;
case EADDRINUSE: return UV_EADDRINUSE;
@@ -201,6 +224,7 @@ static uv_err_t uv_err_new(uv_handle_t* handle, int sys_error) {
void uv_close(uv_handle_t* handle, uv_close_cb close_cb) {
+ uv_udp_t* udp;
uv_async_t* async;
uv_timer_t* timer;
uv_stream_t* stream;
@@ -226,6 +250,17 @@ void uv_close(uv_handle_t* handle, uv_close_cb close_cb) {
uv__close(stream->accepted_fd);
stream->accepted_fd = -1;
}
+
+ assert(!ev_is_active(&stream->read_watcher));
+ assert(!ev_is_active(&stream->write_watcher));
+ break;
+
+ case UV_UDP:
+ udp = (uv_udp_t*)handle;
+ uv__udp_watcher_stop(udp, &udp->read_watcher);
+ uv__udp_watcher_stop(udp, &udp->write_watcher);
+ uv__close(udp->fd);
+ udp->fd = -1;
break;
case UV_PREPARE:
@@ -302,6 +337,489 @@ static void uv__handle_init(uv_handle_t* handle, uv_handle_type type) {
}
+static void uv__udp_watcher_start(uv_udp_t* handle, ev_io* w) {
+ int flags;
+
+ assert(w == &handle->read_watcher
+ || w == &handle->write_watcher);
+
+ flags = (w == &handle->read_watcher ? EV_READ : EV_WRITE);
+
+ w->data = handle;
+ ev_set_cb(w, uv__udp_io);
+ ev_io_set(w, handle->fd, flags);
+ ev_io_start(EV_DEFAULT_UC_ w);
+}
+
+
+static void uv__udp_watcher_stop(uv_udp_t* handle, ev_io* w) {
+ int flags;
+
+ assert(w == &handle->read_watcher
+ || w == &handle->write_watcher);
+
+ flags = (w == &handle->read_watcher ? EV_READ : EV_WRITE);
+
+ ev_io_stop(EV_DEFAULT_UC_ w);
+ ev_io_set(w, -1, flags);
+ ev_set_cb(w, NULL);
+ w->data = (void*)0xDEADBABE;
+}
+
+
+static void uv__udp_destroy(uv_udp_t* handle) {
+ uv_udp_send_t* req;
+ ngx_queue_t* q;
+
+ uv__udp_run_completed(handle);
+
+ while (!ngx_queue_empty(&handle->write_queue)) {
+ q = ngx_queue_head(&handle->write_queue);
+ ngx_queue_remove(q);
+
+ req = ngx_queue_data(q, uv_udp_send_t, queue);
+ if (req->send_cb) {
+ /* FIXME proper error code like UV_EABORTED */
+ uv_err_new_artificial((uv_handle_t*)handle, UV_EINTR);
+ req->send_cb(req, -1);
+ }
+ }
+
+ /* Now tear down the handle. */
+ handle->flags = 0;
+ handle->recv_cb = NULL;
+ handle->alloc_cb = NULL;
+ /* but _do not_ touch close_cb */
+
+ if (handle->fd != -1) {
+ uv__close(handle->fd);
+ handle->fd = -1;
+ }
+
+ uv__udp_watcher_stop(handle, &handle->read_watcher);
+ uv__udp_watcher_stop(handle, &handle->write_watcher);
+}
+
+
+static void uv__udp_run_pending(uv_udp_t* handle) {
+ uv_udp_send_t* req;
+ ngx_queue_t* q;
+ struct msghdr h;
+ ssize_t size;
+
+ while (!ngx_queue_empty(&handle->write_queue)) {
+ q = ngx_queue_head(&handle->write_queue);
+ assert(q != NULL);
+
+ req = ngx_queue_data(q, uv_udp_send_t, queue);
+ assert(req != NULL);
+
+ memset(&h, 0, sizeof h);
+ h.msg_name = &req->addr;
+ h.msg_namelen = req->addrlen;
+ h.msg_iov = (struct iovec*)req->bufs;
+ h.msg_iovlen = req->bufcnt;
+
+ do {
+ size = sendmsg(handle->fd, &h, 0);
+ }
+ while (size == -1 && errno == EINTR);
+
+ /* TODO try to write once or twice more in the
+ * hope that the socket becomes readable again?
+ */
+ if (size == -1 && (errno == EAGAIN || errno == EWOULDBLOCK))
+ break;
+
+ req->status = (size == -1 ? -errno : size);
+
+#ifndef NDEBUG
+ /* Sanity check. */
+ if (size != -1) {
+ ssize_t nbytes;
+ int i;
+
+ for (nbytes = i = 0; i < req->bufcnt; i++)
+ nbytes += req->bufs[i].len;
+
+ assert(size == nbytes);
+ }
+#endif
+
+ /* Sending a datagram is an atomic operation: either all data
+ * is written or nothing is (and EMSGSIZE is raised). That is
+ * why we don't handle partial writes. Just pop the request
+ * off the write queue and onto the completed queue, done.
+ */
+ ngx_queue_remove(&req->queue);
+ ngx_queue_insert_tail(&handle->write_completed_queue, &req->queue);
+ }
+}
+
+
+static void uv__udp_run_completed(uv_udp_t* handle) {
+ uv_udp_send_t* req;
+ ngx_queue_t* q;
+
+ while (!ngx_queue_empty(&handle->write_completed_queue)) {
+ q = ngx_queue_head(&handle->write_completed_queue);
+ assert(q != NULL);
+
+ ngx_queue_remove(q);
+
+ req = ngx_queue_data(q, uv_udp_send_t, queue);
+ assert(req != NULL);
+
+ if (req->bufs != req->bufsml)
+ free(req->bufs);
+
+ if (req->send_cb == NULL)
+ continue;
+
+ /* req->status >= 0 == bytes written
+ * req->status < 0 == errno
+ */
+ if (req->status >= 0) {
+ req->send_cb(req, 0);
+ }
+ else {
+ uv_err_new((uv_handle_t*)handle, -req->status);
+ req->send_cb(req, -1);
+ }
+ }
+}
+
+
+static void uv__udp_recvmsg(uv_udp_t* handle) {
+ struct sockaddr_storage peer;
+ struct msghdr h;
+ ssize_t nread;
+ uv_buf_t buf;
+ int flags;
+
+ assert(handle->recv_cb != NULL);
+ assert(handle->alloc_cb != NULL);
+
+ do {
+ /* FIXME: hoist alloc_cb out the loop but for now follow uv__read() */
+ buf = handle->alloc_cb((uv_handle_t*)handle, 64 * 1024);
+ assert(buf.len > 0);
+ assert(buf.base != NULL);
+
+ memset(&h, 0, sizeof h);
+ h.msg_name = &peer;
+ h.msg_namelen = sizeof peer;
+ h.msg_iov = (struct iovec*)&buf;
+ h.msg_iovlen = 1;
+
+ do {
+ nread = recvmsg(handle->fd, &h, 0);
+ }
+ while (nread == -1 && errno == EINTR);
+
+ if (nread == -1) {
+ if (errno == EAGAIN || errno == EWOULDBLOCK) {
+ uv_err_new((uv_handle_t*)handle, EAGAIN);
+ handle->recv_cb(handle, 0, buf, NULL, 0);
+ }
+ else {
+ uv_err_new((uv_handle_t*)handle, errno);
+ handle->recv_cb(handle, -1, buf, NULL, 0);
+ }
+ }
+ else {
+ flags = 0;
+
+ if (h.msg_flags & MSG_TRUNC)
+ flags |= UV_UDP_PARTIAL;
+
+ handle->recv_cb(handle,
+ nread,
+ buf,
+ (struct sockaddr*)&peer,
+ flags);
+ }
+ }
+ /* recv_cb callback may decide to pause or close the handle */
+ while (nread != -1
+ && handle->fd != -1
+ && handle->recv_cb != NULL);
+}
+
+
+static void uv__udp_sendmsg(uv_udp_t* handle) {
+ assert(!ngx_queue_empty(&handle->write_queue)
+ || !ngx_queue_empty(&handle->write_completed_queue));
+
+ /* Write out pending data first. */
+ uv__udp_run_pending(handle);
+
+ /* Drain 'request completed' queue. */
+ uv__udp_run_completed(handle);
+
+ if (!ngx_queue_empty(&handle->write_completed_queue)) {
+ /* Schedule completion callbacks. */
+ ev_feed_event(EV_DEFAULT_ &handle->write_watcher, EV_WRITE);
+ }
+ else if (ngx_queue_empty(&handle->write_queue)) {
+ /* Pending queue and completion queue empty, stop watcher. */
+ uv__udp_watcher_stop(handle, &handle->write_watcher);
+ }
+}
+
+
+static void uv__udp_io(EV_P_ ev_io* w, int events) {
+ uv_udp_t* handle;
+
+ handle = w->data;
+ assert(handle != NULL);
+ assert(handle->type == UV_UDP);
+ assert(handle->fd >= 0);
+ assert(!(events & ~(EV_READ|EV_WRITE)));
+
+ if (events & EV_READ)
+ uv__udp_recvmsg(handle);
+
+ if (events & EV_WRITE)
+ uv__udp_sendmsg(handle);
+}
+
+
+static int uv__udp_bind(uv_udp_t* handle,
+ int domain,
+ struct sockaddr* addr,
+ socklen_t len,
+ unsigned flags) {
+ int saved_errno;
+ int status;
+ int yes;
+ int fd;
+
+ saved_errno = errno;
+ status = -1;
+
+ /* Check for bad flags. */
+ if (flags & ~UV_UDP_IPV6ONLY) {
+ uv_err_new((uv_handle_t*)handle, EINVAL);
+ goto out;
+ }
+
+ /* Cannot set IPv6-only mode on non-IPv6 socket. */
+ if ((flags & UV_UDP_IPV6ONLY) && domain != AF_INET6) {
+ uv_err_new((uv_handle_t*)handle, EINVAL);
+ goto out;
+ }
+
+ /* Check for already active socket. */
+ if (handle->fd != -1) {
+ uv_err_new_artificial((uv_handle_t*)handle, UV_EALREADY);
+ goto out;
+ }
+
+ if ((fd = uv__socket(domain, SOCK_DGRAM, 0)) == -1) {
+ uv_err_new((uv_handle_t*)handle, errno);
+ goto out;
+ }
+
+ if (flags & UV_UDP_IPV6ONLY) {
+#ifdef IPV6_V6ONLY
+ yes = 1;
+ if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof yes) == -1) {
+ uv_err_new((uv_handle_t*)handle, errno);
+ goto out;
+ }
+#else
+ uv_err_new((uv_handle_t*)handle, ENOTSUP);
+ goto out;
+#endif
+ }
+
+ if (bind(fd, addr, len) == -1) {
+ uv_err_new((uv_handle_t*)handle, errno);
+ goto out;
+ }
+
+ handle->fd = fd;
+ status = 0;
+
+out:
+ if (status)
+ uv__close(fd);
+
+ errno = saved_errno;
+ return status;
+}
+
+
+static int uv__udp_maybe_deferred_bind(uv_udp_t* handle, int domain) {
+ struct sockaddr_storage taddr;
+ socklen_t addrlen;
+
+ assert(domain == AF_INET || domain == AF_INET6);
+
+ if (handle->fd != -1)
+ return 0;
+
+ switch (domain) {
+ case AF_INET:
+ {
+ struct sockaddr_in* addr = (void*)&taddr;
+ memset(addr, 0, sizeof *addr);
+ addr->sin_family = AF_INET;
+ addr->sin_addr.s_addr = INADDR_ANY;
+ addrlen = sizeof *addr;
+ break;
+ }
+ case AF_INET6:
+ {
+ struct sockaddr_in6* addr = (void*)&taddr;
+ memset(addr, 0, sizeof *addr);
+ addr->sin6_family = AF_INET6;
+ addr->sin6_addr = in6addr_any;
+ addrlen = sizeof *addr;
+ break;
+ }
+ default:
+ assert(0 && "unsupported address family");
+ abort();
+ }
+
+ return uv__udp_bind(handle, domain, (struct sockaddr*)&taddr, addrlen, 0);
+}
+
+
+static int uv__udp_send(uv_udp_send_t* req,
+ uv_udp_t* handle,
+ uv_buf_t bufs[],
+ int bufcnt,
+ struct sockaddr* addr,
+ socklen_t addrlen,
+ uv_udp_send_cb send_cb) {
+ if (uv__udp_maybe_deferred_bind(handle, addr->sa_family))
+ return -1;
+
+ /* Don't use uv__req_init(), it zeroes the data field. */
+ uv_counters()->req_init++;
+
+ memcpy(&req->addr, addr, addrlen);
+ req->addrlen = addrlen;
+ req->send_cb = send_cb;
+ req->handle = handle;
+ req->bufcnt = bufcnt;
+ req->type = UV_UDP_SEND;
+
+ if (bufcnt <= UV_REQ_BUFSML_SIZE) {
+ req->bufs = req->bufsml;
+ }
+ else if ((req->bufs = malloc(bufcnt * sizeof(bufs[0]))) == NULL) {
+ uv_err_new((uv_handle_t*)handle, ENOMEM);
+ return -1;
+ }
+ memcpy(req->bufs, bufs, bufcnt * sizeof(bufs[0]));
+
+ ngx_queue_insert_tail(&handle->write_queue, &req->queue);
+ uv__udp_watcher_start(handle, &handle->write_watcher);
+
+ return 0;
+}
+
+
+int uv_udp_init(uv_udp_t* handle) {
+ memset(handle, 0, sizeof *handle);
+
+ uv__handle_init((uv_handle_t*)handle, UV_UDP);
+ uv_counters()->udp_init++;
+
+ handle->fd = -1;
+ ngx_queue_init(&handle->write_queue);
+ ngx_queue_init(&handle->write_completed_queue);
+
+ return 0;
+}
+
+
+int uv_udp_bind(uv_udp_t* handle, struct sockaddr_in addr, unsigned flags) {
+ return uv__udp_bind(handle,
+ AF_INET,
+ (struct sockaddr*)&addr,
+ sizeof addr,
+ flags);
+}
+
+
+int uv_udp_bind6(uv_udp_t* handle, struct sockaddr_in6 addr, unsigned flags) {
+ return uv__udp_bind(handle,
+ AF_INET6,
+ (struct sockaddr*)&addr,
+ sizeof addr,
+ flags);
+}
+
+
+int uv_udp_send(uv_udp_send_t* req,
+ uv_udp_t* handle,
+ uv_buf_t bufs[],
+ int bufcnt,
+ struct sockaddr_in addr,
+ uv_udp_send_cb send_cb) {
+ return uv__udp_send(req,
+ handle,
+ bufs,
+ bufcnt,
+ (struct sockaddr*)&addr,
+ sizeof addr,
+ send_cb);
+}
+
+
+int uv_udp_send6(uv_udp_send_t* req,
+ uv_udp_t* handle,
+ uv_buf_t bufs[],
+ int bufcnt,
+ struct sockaddr_in6 addr,
+ uv_udp_send_cb send_cb) {
+ return uv__udp_send(req,
+ handle,
+ bufs,
+ bufcnt,
+ (struct sockaddr*)&addr,
+ sizeof addr,
+ send_cb);
+}
+
+
+int uv_udp_recv_start(uv_udp_t* handle,
+ uv_alloc_cb alloc_cb,
+ uv_udp_recv_cb recv_cb) {
+ if (alloc_cb == NULL || recv_cb == NULL) {
+ uv_err_new_artificial((uv_handle_t*)handle, UV_EINVAL);
+ return -1;
+ }
+
+ if (ev_is_active(&handle->read_watcher)) {
+ uv_err_new_artificial((uv_handle_t*)handle, UV_EALREADY);
+ return -1;
+ }
+
+ if (uv__udp_maybe_deferred_bind(handle, AF_INET))
+ return -1;
+
+ handle->alloc_cb = alloc_cb;
+ handle->recv_cb = recv_cb;
+ uv__udp_watcher_start(handle, &handle->read_watcher);
+
+ return 0;
+}
+
+
+int uv_udp_recv_stop(uv_udp_t* handle) {
+ uv__udp_watcher_stop(handle, &handle->read_watcher);
+ handle->alloc_cb = NULL;
+ handle->recv_cb = NULL;
+ return 0;
+}
+
+
int uv_tcp_init(uv_tcp_t* tcp) {
uv__handle_init((uv_handle_t*)tcp, UV_TCP);
uv_counters()->tcp_init++;
@@ -329,8 +847,10 @@ int uv_tcp_init(uv_tcp_t* tcp) {
}
-static int uv__bind(uv_tcp_t* tcp, int domain, struct sockaddr* addr,
- int addrsize) {
+static int uv__tcp_bind(uv_tcp_t* tcp,
+ int domain,
+ struct sockaddr* addr,
+ int addrsize) {
int saved_errno;
int status;
@@ -376,8 +896,10 @@ int uv_tcp_bind(uv_tcp_t* tcp, struct sockaddr_in addr) {
return -1;
}
- return uv__bind(tcp, AF_INET, (struct sockaddr*)&addr,
- sizeof(struct sockaddr_in));
+ return uv__tcp_bind(tcp,
+ AF_INET,
+ (struct sockaddr*)&addr,
+ sizeof(struct sockaddr_in));
}
@@ -387,8 +909,10 @@ int uv_tcp_bind6(uv_tcp_t* tcp, struct sockaddr_in6 addr) {
return -1;
}
- return uv__bind(tcp, AF_INET6, (struct sockaddr*)&addr,
- sizeof(struct sockaddr_in6));
+ return uv__tcp_bind(tcp,
+ AF_INET6,
+ (struct sockaddr*)&addr,
+ sizeof(struct sockaddr_in6));
}
@@ -587,6 +1111,13 @@ void uv__finish_close(uv_handle_t* handle) {
assert(!ev_is_active(&((uv_stream_t*)handle)->write_watcher));
break;
+ case UV_UDP:
+ assert(!ev_is_active(&((uv_udp_t*)handle)->read_watcher));
+ assert(!ev_is_active(&((uv_udp_t*)handle)->write_watcher));
+ assert(((uv_udp_t*)handle)->fd == -1);
+ uv__udp_destroy((uv_udp_t*)handle);
+ break;
+
case UV_PROCESS:
assert(!ev_is_active(&((uv_process_t*)handle)->child_watcher));
break;
@@ -820,21 +1351,22 @@ static void uv__read(uv_stream_t* stream) {
*/
while (stream->read_cb && ((uv_handle_t*)stream)->flags & UV_READING) {
assert(stream->alloc_cb);
- buf = stream->alloc_cb(stream, 64 * 1024);
+ 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 == -1 && errno == EINTR);
+ while (nread < 0 && errno == EINTR);
if (nread < 0) {
/* Error */
if (errno == EAGAIN) {
/* Wait for the next one. */
- if (((uv_handle_t*)stream)->flags & UV_READING) {
+ if (stream->flags & UV_READING) {
ev_io_start(EV_DEFAULT_UC_ &stream->read_watcher);
}
uv_err_new((uv_handle_t*)stream, EAGAIN);
@@ -1112,7 +1644,7 @@ int uv_tcp_connect6(uv_connect_t* req,
}
-int uv_getsockname(uv_tcp_t* handle, struct sockaddr* name, int* namelen) {
+int uv_getsockname(uv_handle_t* handle, struct sockaddr* name, int* namelen) {
socklen_t socklen;
int saved_errno;
@@ -1251,6 +1783,11 @@ int64_t uv_now() {
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((uv_handle_t*)stream, EINVAL);
+ return -1;
+ }
+
/* The UV_READING flag is irrelevant of the state of the tcp - it just
* expresses the desired state of the user.
*/
View
1  deps/uv/src/win/async.c
@@ -78,7 +78,6 @@ int uv_async_init(uv_async_t* handle, uv_async_cb async_cb) {
handle->type = UV_ASYNC;
handle->flags = 0;
handle->async_sent = 0;
- handle->error = uv_ok_;
handle->async_cb = async_cb;
req = &handle->async_req;
View
8 deps/uv/src/win/core.c
@@ -111,10 +111,6 @@ static void uv_poll(int block) {
/* Package was dequeued */
req = uv_overlapped_to_req(overlapped);
- if (!success) {
- req->error = uv_new_sys_error(GetLastError());
- }
-
uv_insert_pending_req(req);
} else if (GetLastError() != WAIT_TIMEOUT) {
@@ -150,10 +146,6 @@ static void uv_poll_ex(int block) {
for (i = 0; i < count; i++) {
/* Package was dequeued */
req = uv_overlapped_to_req(overlappeds[i].lpOverlapped);
- if (overlappeds[i].lpOverlapped->Internal != STATUS_SUCCESS) {
- req->error = uv_new_sys_error(pRtlNtStatusToDosError(
- overlappeds[i].lpOverlapped->Internal));
- }
uv_insert_pending_req(req);
}
} else if (GetLastError() != WAIT_TIMEOUT) {
View
1  deps/uv/src/win/error.c
@@ -109,6 +109,7 @@ uv_err_code uv_translate_sys_error(int sys_errno) {
case WSAEINVAL: return UV_EINVAL;
case ERROR_TOO_MANY_OPEN_FILES: return UV_EMFILE;
case WSAEMFILE: return UV_EMFILE;
+ case WSAEMSGSIZE: return UV_EMSGSIZE;
case ERROR_NETWORK_UNREACHABLE: return UV_ENETUNREACH;
case WSAENETUNREACH: return UV_ENETUNREACH;
case ERROR_OUTOFMEMORY: return UV_ENOMEM;
View
40 deps/uv/src/win/handle.c
@@ -39,18 +39,33 @@ int uv_is_active(uv_handle_t* handle) {
}
-/* TODO: integrate this with uv_close. */
-static void uv_close_error(uv_handle_t* handle, uv_err_t e) {
+int uv_getsockname(uv_handle_t* handle, struct sockaddr* name, int* namelen) {
+ switch (handle->type) {
+ case UV_TCP:
+ return uv_tcp_getsockname((uv_tcp_t*) handle, name, namelen);
+
+ case UV_UDP:
+ return uv_tcp_getsockname((uv_tcp_t*) handle, name, namelen);
+
+ default:
+ uv_set_sys_error(WSAENOTSOCK);
+ return -1;
+ }
+}
+
+
+void uv_close(uv_handle_t* handle, uv_close_cb cb) {
uv_tcp_t* tcp;
uv_pipe_t* pipe;
+ uv_udp_t* udp;
uv_process_t* process;
if (handle->flags & UV_HANDLE_CLOSING) {
return;
}
- handle->error = e;
handle->flags |= UV_HANDLE_CLOSING;
+ handle->close_cb = cb;
/* Handle-specific close actions */
switch (handle->type) {
@@ -78,6 +93,15 @@ static void uv_close_error(uv_handle_t* handle, uv_err_t e) {
}
return;
+ case UV_UDP:
+ udp = (uv_udp_t*) handle;
+ uv_udp_recv_stop(udp);
+ closesocket(udp->socket);
+ if (udp->reqs_pending == 0) {
+ uv_want_endgame(handle);
+ }
+ return;
+
case UV_TIMER:
uv_timer_stop((uv_timer_t*)handle);
uv_want_endgame(handle);
@@ -116,12 +140,6 @@ static void uv_close_error(uv_handle_t* handle, uv_err_t e) {
}
-void uv_close(uv_handle_t* handle, uv_close_cb close_cb) {
- handle->close_cb = close_cb;
- uv_close_error(handle, uv_ok_);
-}
-
-
void uv_want_endgame(uv_handle_t* handle) {
if (!(handle->flags & UV_HANDLE_ENDGAME_QUEUED)) {
handle->flags |= UV_HANDLE_ENDGAME_QUEUED;
@@ -150,6 +168,10 @@ void uv_process_endgames() {
uv_pipe_endgame((uv_pipe_t*)handle);
break;
+ case UV_UDP:
+ uv_udp_endgame((uv_udp_t*) handle);
+ break;
+
case UV_TIMER:
uv_timer_endgame((uv_timer_t*)handle);
break;
View
41 deps/uv/src/win/internal.h
@@ -142,7 +142,6 @@ void uv_insert_pending_req(uv_req_t* req);
void uv_process_reqs();
#define POST_COMPLETION_FOR_REQ(req) \
- memset(&((req)->overlapped), 0, sizeof((req)->overlapped)); \
if (!PostQueuedCompletionStatus(LOOP->iocp, \
0, \
0, \
@@ -169,6 +168,7 @@ int uv_tcp_read_start(uv_tcp_t* handle, uv_alloc_cb alloc_cb,
uv_read_cb read_cb);
int uv_tcp_write(uv_write_t* req, uv_tcp_t* handle, uv_buf_t bufs[],
int bufcnt, uv_write_cb cb);
+int uv_tcp_getsockname(uv_tcp_t* handle, struct sockaddr* name, int* namelen);
void uv_process_tcp_read_req(uv_tcp_t* handle, uv_req_t* req);
void uv_process_tcp_write_req(uv_tcp_t* handle, uv_write_t* req);
@@ -179,6 +179,17 @@ void uv_tcp_endgame(uv_tcp_t* handle);
/*
+ * UDP
+ */
+int uv_udp_getsockname(uv_udp_t* handle, struct sockaddr* name, int* namelen);
+
+void uv_process_udp_recv_req(uv_udp_t* handle, uv_req_t* req);
+void uv_process_udp_send_req(uv_udp_t* handle, uv_udp_send_t* req);
+
+void uv_udp_endgame(uv_udp_t* handle);
+
+
+/*
* Pipes
*/
int uv_pipe_init_with_handle(uv_pipe_t* handle, HANDLE pipeHandle);
@@ -252,12 +263,40 @@ uv_err_t uv_new_sys_error(int sys_errno);
void uv_set_sys_error(int sys_errno);
void uv_set_error(uv_err_code code, int sys_errno);
+#define SET_REQ_STATUS(req, status) \
+ (req)->overlapped.Internal = (ULONG_PTR) (status)
+
+#define SET_REQ_ERROR(req, error) \
+ SET_REQ_STATUS((req), NTSTATUS_FROM_WIN32((error)))
+
+#define SET_REQ_SUCCESS(req) \
+ SET_REQ_STATUS((req), STATUS_SUCCESS)
+
+#define GET_REQ_STATUS(req) \
+ ((req)->overlapped.Internal)
+
+#define REQ_SUCCESS(req) \
+ (NT_SUCCESS(GET_REQ_STATUS((req))))
+
+#define GET_REQ_ERROR(req) \
+ (pRtlNtStatusToDosError(GET_REQ_STATUS((req))))
+
+#define GET_REQ_SOCK_ERROR(req) \
+ (uv_ntstatus_to_winsock_error(GET_REQ_STATUS((req))))
+
+#define GET_REQ_UV_ERROR(req) \
+ (uv_new_sys_error(GET_REQ_ERROR((req))))
+
+#define GET_REQ_UV_SOCK_ERROR(req) \
+ (uv_new_sys_error(GET_REQ_SOCK_ERROR((req))))
+
/*
* Initialization for the windows and winsock api
*/
void uv_winapi_init();
void uv_winsock_init();
+int uv_ntstatus_to_winsock_error(NTSTATUS status);
#endif /* UV_WIN_INTERNAL_H_ */
View
1  deps/uv/src/win/loop-watcher.c
@@ -44,7 +44,6 @@ void uv_loop_watcher_endgame(uv_handle_t* handle) {
int uv_##name##_init(uv_##name##_t* handle) { \
handle->type = UV_##NAME; \
handle->flags = 0; \
- handle->error = uv_ok_; \
\
uv_ref(); \
\
View
43 deps/uv/src/win/pipe.c
@@ -300,8 +300,6 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
errno = GetLastError();
if (errno == ERROR_ACCESS_DENIED) {
uv_set_error(UV_EADDRINUSE, errno);
- handle->error = LOOP->last_error;
- handle->flags |= UV_HANDLE_BIND_ERROR;
} else if (errno == ERROR_PATH_NOT_FOUND || errno == ERROR_INVALID_NAME) {
uv_set_error(UV_EACCESS, errno);
} else {
@@ -366,9 +364,9 @@ static DWORD WINAPI pipe_connect_thread_proc(void* parameter) {
if (pipeHandle != INVALID_HANDLE_VALUE && !uv_set_pipe_handle(handle, pipeHandle)) {
handle->handle = pipeHandle;
- req->error = uv_ok_;
+ SET_REQ_SUCCESS(req);
} else {
- req->error = uv_new_sys_error(GetLastError());
+ SET_REQ_ERROR(req, GetLastError());
}
/* Post completed */
@@ -434,7 +432,7 @@ int uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle,
handle->handle = pipeHandle;
- req->error = uv_ok_;
+ SET_REQ_SUCCESS(req);
uv_insert_pending_req((uv_req_t*) req);
handle->reqs_pending++;
return 0;
@@ -497,7 +495,7 @@ static void uv_pipe_queue_accept(uv_pipe_t* handle, uv_pipe_accept_t* req, BOOL
NULL);
if (req->pipeHandle == INVALID_HANDLE_VALUE) {
- req->error = uv_new_sys_error(GetLastError());
+ SET_REQ_ERROR(req, GetLastError());
uv_insert_pending_req((uv_req_t*) req);
handle->reqs_pending++;
return;
@@ -506,7 +504,7 @@ static void uv_pipe_queue_accept(uv_pipe_t* handle, uv_pipe_accept_t* req, BOOL
if (uv_set_pipe_handle(handle, req->pipeHandle)) {
CloseHandle(req->pipeHandle);
req->pipeHandle = INVALID_HANDLE_VALUE;
- req->error = uv_new_sys_error(GetLastError());
+ SET_REQ_ERROR(req, GetLastError());
uv_insert_pending_req((uv_req_t*) req);
handle->reqs_pending++;
return;
@@ -520,12 +518,12 @@ static void uv_pipe_queue_accept(uv_pipe_t* handle, uv_pipe_accept_t* req, BOOL
if (!ConnectNamedPipe(req->pipeHandle, &req->overlapped) && GetLastError() != ERROR_IO_PENDING) {
if (GetLastError() == ERROR_PIPE_CONNECTED) {
- req->error = uv_ok_;
+ SET_REQ_SUCCESS(req);
} else {
CloseHandle(req->pipeHandle);
req->pipeHandle = INVALID_HANDLE_VALUE;
/* Make this req pending reporting an error. */
- req->error = uv_new_sys_error(GetLastError());
+ SET_REQ_ERROR(req, GetLastError());
}
uv_insert_pending_req((uv_req_t*) req);
handle->reqs_pending++;
@@ -570,11 +568,6 @@ int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) {
uv_pipe_accept_t* req;
HANDLE pipeHandle;
- if (handle->flags & UV_HANDLE_BIND_ERROR) {
- uv_set_error(UV_EINVAL, 0);
- return -1;
- }
-
if (!(handle->flags & UV_HANDLE_BOUND) &&
!(handle->flags & UV_HANDLE_GIVEN_OS_HANDLE)) {
uv_set_error(UV_EINVAL, 0);
@@ -647,7 +640,7 @@ static void uv_pipe_queue_read(uv_pipe_t* handle) {
if (!result && GetLastError() != ERROR_IO_PENDING) {
/* Make this req pending reporting an error. */
- req->error = uv_new_sys_error(WSAGetLastError());
+ SET_REQ_ERROR(req, WSAGetLastError());
uv_insert_pending_req(req);
handle->reqs_pending++;
return;
@@ -749,12 +742,12 @@ void uv_process_pipe_read_req(uv_pipe_t* handle, uv_req_t* req) {
handle->flags &= ~UV_HANDLE_READ_PENDING;
- if (req->error.code != UV_OK) {
+ if (!REQ_SUCCESS(req)) {
/* An error occurred doing the 0-read. */
if (handle->flags & UV_HANDLE_READING) {
/* Stop reading and report error. */
handle->flags &= ~UV_HANDLE_READING;
- LOOP->last_error = req->error;
+ LOOP->last_error = GET_REQ_UV_ERROR(req);
buf.base = 0;
buf.len = 0;
handle->read_cb((uv_stream_t*)handle, -1, buf);
@@ -780,7 +773,7 @@ void uv_process_pipe_read_req(uv_pipe_t* handle, uv_req_t* req) {
break;
}
- buf = handle->alloc_cb((uv_stream_t*)handle, avail);
+ buf = handle->alloc_cb((uv_handle_t*) handle, avail);
assert(buf.len > 0);
if (ReadFile(handle->handle,
@@ -819,8 +812,12 @@ void uv_process_pipe_write_req(uv_pipe_t* handle, uv_write_t* req) {
handle->write_queue_size -= req->queued_bytes;
if (req->cb) {
- LOOP->last_error = req->error;
- ((uv_write_cb)req->cb)(req, LOOP->last_error.code == UV_OK ? 0 : -1);
+ if (!REQ_SUCCESS(req)) {
+ LOOP->last_error = GET_REQ_UV_ERROR(req);
+ ((uv_write_cb)req->cb)(req, -1);
+ } else {
+ ((uv_write_cb)req->cb)(req, 0);
+ }
}
handle->write_reqs_pending--;
@@ -838,7 +835,7 @@ void uv_process_pipe_accept_req(uv_pipe_t* handle, uv_req_t* raw_req) {
assert(handle->type == UV_NAMED_PIPE);
- if (req->error.code == UV_OK) {
+ if (REQ_SUCCESS(req)) {
assert(req->pipeHandle != INVALID_HANDLE_VALUE);
req->next_pending = handle->pending_accepts;
handle->pending_accepts = req;
@@ -865,11 +862,11 @@ void uv_process_pipe_connect_req(uv_pipe_t* handle, uv_connect_t* req) {
assert(handle->type == UV_NAMED_PIPE);
if (req->cb) {
- if (req->error.code == UV_OK) {
+ if (REQ_SUCCESS(req)) {
uv_connection_init((uv_stream_t*)handle);
((uv_connect_cb)req->cb)(req, 0);
} else {
- LOOP->last_error = req->error;
+ LOOP->last_error = GET_REQ_UV_ERROR(req);
((uv_connect_cb)req->cb)(req, -1);
}
}
View
1  deps/uv/src/win/process.c
@@ -54,7 +54,6 @@ typedef struct env_var {
static void uv_process_init(uv_process_t* handle) {
handle->type = UV_PROCESS;
handle->flags = 0;
- handle->error = uv_ok_;
handle->exit_cb = NULL;
handle->pid = 0;
handle->exit_signal = 0;
View
11 deps/uv/src/win/req.c
@@ -29,7 +29,7 @@
void uv_req_init(uv_req_t* req) {
uv_counters()->req_init++;
req->type = UV_UNKNOWN_REQ;
- req->error = uv_ok_;
+ SET_REQ_SUCCESS(req);
}
@@ -117,6 +117,15 @@ void uv_process_reqs() {
(uv_pipe_t*) ((uv_shutdown_t*) req)->handle, (uv_shutdown_t*) req);
break;
+ case UV_UDP_RECV:
+ uv_process_udp_recv_req((uv_udp_t*) req->data, req);
+ break;
+
+ case UV_UDP_SEND:
+ uv_process_udp_send_req(((uv_udp_send_t*) req)->handle,
+ (uv_udp_send_t*) req);
+ break;
+
case UV_WAKEUP:
uv_process_async_wakeup_req((uv_async_t*) req->data, req);
break;
View
1  deps/uv/src/win/stream.c
@@ -29,7 +29,6 @@
void uv_stream_init(uv_stream_t* handle) {
handle->write_queue_size = 0;
handle->flags = 0;
- handle->error = uv_ok_;
uv_counters()->handle_init++;
uv_counters()->stream_init++;
View
41 deps/uv/src/win/tcp.c
@@ -28,10 +28,13 @@
/*
* Threshold of active tcp streams for which to preallocate tcp read buffers.
+ * (Due to node slab allocator performing poorly under this pattern,
+ * the optimization is temporarily disabled (threshold=0). This will be
+ * revisited once node allocator is improved.)
*/
-const unsigned int uv_active_tcp_streams_threshold = 50;
+const unsigned int uv_active_tcp_streams_threshold = 0;
-/*
+/*
* Number of simultaneous pending AcceptEx calls.
*/
const unsigned int uv_simultaneous_server_accepts = 32;
@@ -171,7 +174,7 @@ static int uv__bind(uv_tcp_t* handle, int domain, struct sockaddr* addr, int add
err = WSAGetLastError();
if (err == WSAEADDRINUSE) {
/* Some errors are not to be reported until connect() or listen() */
- handle->error = uv_new_sys_error(err);
+ handle->bind_error = uv_new_sys_error(err);
handle->flags |= UV_HANDLE_BIND_ERROR;
} else {
uv_set_sys_error(err);
@@ -232,7 +235,7 @@ static void uv_tcp_queue_accept(uv_tcp_t* handle, uv_tcp_accept_t* req) {
/* Open a socket for the accepted connection. */
accept_socket = socket(family, SOCK_STREAM, 0);
if (accept_socket == INVALID_SOCKET) {
- req->error = uv_new_sys_error(WSAGetLastError());
+ SET_REQ_ERROR(req, WSAGetLastError());
uv_insert_pending_req((uv_req_t*)req);
handle->reqs_pending++;
return;
@@ -261,7 +264,7 @@ static void uv_tcp_queue_accept(uv_tcp_t* handle, uv_tcp_accept_t* req) {
handle->reqs_pending++;
} else {
/* Make this req pending reporting an error. */
- req->error = uv_new_sys_error(WSAGetLastError());
+ SET_REQ_ERROR(req, WSAGetLastError());
uv_insert_pending_req((uv_req_t*)req);
handle->reqs_pending++;
/* Destroy the preallocated client socket. */
@@ -288,7 +291,7 @@ static void uv_tcp_queue_read(uv_tcp_t* handle) {
*/
if (active_tcp_streams < uv_active_tcp_streams_threshold) {
handle->flags &= ~UV_HANDLE_ZERO_READ;
- handle->read_buffer = handle->alloc_cb((uv_stream_t*)handle, 65536);
+ handle->read_buffer = handle->alloc_cb((uv_handle_t*) handle, 65536);
assert(handle->read_buffer.len > 0);
buf = handle->read_buffer;
} else {
@@ -318,7 +321,7 @@ static void uv_tcp_queue_read(uv_tcp_t* handle) {
handle->reqs_pending++;
} else {
/* Make this req pending reporting an error. */
- req->error = uv_new_sys_error(WSAGetLastError());
+ SET_REQ_ERROR(req, WSAGetLastError());
uv_insert_pending_req(req);
handle->reqs_pending++;
}
@@ -332,7 +335,7 @@ int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) {
assert(backlog > 0);
if (handle->flags & UV_HANDLE_BIND_ERROR) {
- LOOP->last_error = handle->error;
+ LOOP->last_error = handle->bind_error;
return -1;
}
@@ -449,7 +452,7 @@ int uv_tcp_connect(uv_connect_t* req, uv_tcp_t* handle,
DWORD bytes;
if (handle->flags & UV_HANDLE_BIND_ERROR) {
- LOOP->last_error = handle->error;
+ LOOP->last_error = handle->bind_error;
return -1;
}
@@ -504,7 +507,7 @@ int uv_tcp_connect6(uv_connect_t* req, uv_tcp_t* handle,
}
if (handle->flags & UV_HANDLE_BIND_ERROR) {
- LOOP->last_error = handle->error;
+ LOOP->last_error = handle->bind_error;
return -1;
}
@@ -545,7 +548,7 @@ int uv_tcp_connect6(uv_connect_t* req, uv_tcp_t* handle,
}
-int uv_getsockname(uv_tcp_t* handle, struct sockaddr* name, int* namelen) {
+int uv_tcp_getsockname(uv_tcp_t* handle, struct sockaddr* name, int* namelen) {
int result;
if (handle->flags & UV_HANDLE_SHUTTING) {
@@ -622,11 +625,11 @@ void uv_process_tcp_read_req(uv_tcp_t* handle, uv_req_t* req) {
handle->flags &= ~UV_HANDLE_READ_PENDING;
- if (req->error.code != UV_OK) {
+ if (!REQ_SUCCESS(req)) {
/* An error occurred doing the read. */
if ((handle->flags & UV_HANDLE_READING)) {
handle->flags &= ~UV_HANDLE_READING;
- LOOP->last_error = req->error;
+ LOOP->last_error = GET_REQ_UV_SOCK_ERROR(req);
buf = (handle->flags & UV_HANDLE_ZERO_READ) ?
uv_buf_init(NULL, 0) : handle->read_buffer;
handle->read_cb((uv_stream_t*)handle, -1, buf);
@@ -656,7 +659,7 @@ void uv_process_tcp_read_req(uv_tcp_t* handle, uv_req_t* req) {
/* Do nonblocking reads until the buffer is empty */
while (handle->flags & UV_HANDLE_READING) {
- buf = handle->alloc_cb((uv_stream_t*)handle, 65536);
+ buf = handle->alloc_cb((uv_handle_t*) handle, 65536);
assert(buf.len > 0);
flags = 0;
if (WSARecv(handle->socket,
@@ -715,7 +718,7 @@ void uv_process_tcp_write_req(uv_tcp_t* handle, uv_write_t* req) {
handle->write_queue_size -= req->queued_bytes;
if (req->cb) {
- LOOP->last_error = req->error;
+ LOOP->last_error = GET_REQ_UV_SOCK_ERROR(req);
((uv_write_cb)req->cb)(req, LOOP->last_error.code == UV_OK ? 0 : -1);
}
@@ -742,11 +745,11 @@ void uv_process_tcp_accept_req(uv_tcp_t* handle, uv_req_t* raw_req) {
if (handle->flags & UV_HANDLE_LISTENING) {
handle->flags &= ~UV_HANDLE_LISTENING;
if (handle->connection_cb) {
- LOOP->last_error = req->error;
+ LOOP->last_error = GET_REQ_UV_SOCK_ERROR(req);
handle->connection_cb((uv_stream_t*)handle, -1);
}
}
- } else if (req->error.code == UV_OK &&
+ } else if (REQ_SUCCESS(req) &&
setsockopt(req->accept_socket,
SOL_SOCKET,
SO_UPDATE_ACCEPT_CONTEXT,
@@ -778,7 +781,7 @@ void uv_process_tcp_connect_req(uv_tcp_t* handle, uv_connect_t* req) {
assert(handle->type == UV_TCP);
if (req->cb) {
- if (req->error.code == UV_OK) {
+ if (REQ_SUCCESS(req)) {
if (setsockopt(handle->socket,
SOL_SOCKET,
SO_UPDATE_CONNECT_CONTEXT,
@@ -792,7 +795,7 @@ void uv_process_tcp_connect_req(uv_tcp_t* handle, uv_connect_t* req) {
((uv_connect_cb)req->cb)(req, -1);
}
} else {
- LOOP->last_error = req->error;
+ LOOP->last_error = GET_REQ_UV_SOCK_ERROR(req);
((uv_connect_cb)req->cb)(req, -1);
}
}
View
1  deps/uv/src/win/timer.c
@@ -117,7 +117,6 @@ int uv_timer_init(uv_timer_t* handle) {
handle->type = UV_TIMER;
handle->flags = 0;
- handle->error = uv_ok_;
handle->timer_cb = NULL;
handle->repeat = 0;
View
576 deps/uv/src/win/udp.c
@@ -0,0 +1,576 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+
+#include "uv.h"
+#include "../uv-common.h"
+#include "internal.h"
+#include <stdio.h>
+
+#if 0
+/*
+ * Threshold of active udp streams for which to preallocate udp read buffers.
+ */
+const unsigned int uv_active_udp_streams_threshold = 0;
+
+/* A zero-size buffer for use by uv_udp_read */
+static char uv_zero_[] = "";
+#endif
+
+/* Counter to keep track of active udp streams */
+static unsigned int active_udp_streams = 0;
+
+
+static int uv_udp_set_socket(uv_udp_t* handle, SOCKET socket) {
+ DWORD yes = 1;
+
+ assert(handle->socket == INVALID_SOCKET);
+
+ /* Set the socket to nonblocking mode */
+ if (ioctlsocket(socket, FIONBIO, &yes) == SOCKET_ERROR) {
+ uv_set_sys_error(WSAGetLastError());
+ return -1;
+ }
+
+ /* Make the socket non-inheritable */
+ if (!SetHandleInformation((HANDLE)socket, HANDLE_FLAG_INHERIT, 0)) {
+ uv_set_sys_error(GetLastError());
+ return -1;
+ }
+
+ /* Associate it with the I/O completion port. */
+ /* Use uv_handle_t pointer as completion key. */
+ if (CreateIoCompletionPort((HANDLE)socket,
+ LOOP->iocp,
+ (ULONG_PTR)socket,
+ 0) == NULL) {
+ uv_set_sys_error(GetLastError());
+ return -1;
+ }
+
+ if (pSetFileCompletionNotificationModes) {
+ if (!pSetFileCompletionNotificationModes((HANDLE)socket, FILE_SKIP_SET_EVENT_ON_HANDLE |
+ FILE_SKIP_COMPLETION_PORT_ON_SUCCESS)) {
+ uv_set_sys_error(GetLastError());
+ return -1;
+ }
+
+ handle->flags |= UV_HANDLE_SYNC_BYPASS_IOCP;
+ }
+
+ handle->socket = socket;
+
+ return 0;
+}
+
+
+int uv_udp_init(uv_udp_t* handle) {
+ handle->type = UV_UDP;
+ handle->socket = INVALID_SOCKET;
+ handle->reqs_pending = 0;
+ handle->flags = 0;
+
+ uv_req_init((uv_req_t*) &(handle->recv_req));
+ handle->recv_req.type = UV_UDP_RECV;
+ handle->recv_req.data = handle;
+
+ uv_ref();
+
+ uv_counters()->handle_init++;
+ uv_counters()->udp_init++;
+
+ return 0;
+}
+
+
+void uv_udp_endgame(uv_udp_t* handle) {
+ if (handle->flags & UV_HANDLE_CLOSING &&
+ handle->reqs_pending == 0) {
+ assert(!(handle->flags & UV_HANDLE_CLOSED));
+ handle->flags |= UV_HANDLE_CLOSED;
+
+ if (handle->close_cb) {
+ handle->close_cb((uv_handle_t*)handle);
+ }
+
+ uv_unref();
+ }
+}
+
+
+static int uv__bind(uv_udp_t* handle, int domain, struct sockaddr* addr,
+ int addrsize, unsigned int flags) {
+ DWORD err;
+ int r;
+ SOCKET sock;
+
+ if ((flags & UV_UDP_IPV6ONLY) && domain != AF_INET6) {
+ /* UV_UDP_IPV6ONLY is supported only for IPV6 sockets */
+ uv_set_sys_error(UV_EINVAL);
+ }
+
+ if (handle->socket == INVALID_SOCKET) {
+ sock = socket(domain, SOCK_DGRAM, 0);
+ if (sock == INVALID_SOCKET) {
+ uv_set_sys_error(WSAGetLastError());
+ return -1;
+ }
+
+ if (uv_udp_set_socket(handle, sock) == -1) {
+ closesocket(sock);
+ return -1;
+ }
+ }
+
+ if (domain == AF_INET6 && !(flags & UV_UDP_IPV6ONLY)) {
+ DWORD off = 0;
+ /* On windows IPV6ONLY is on by default. */
+ /* If the user doesn't specify it libuv turns it off. */
+
+ /* TODO: how to handle errors? This may fail if there is no ipv4 stack */
+ /* available, or when run on XP/2003 which have no support for dualstack */
+ /* sockets. For now we're silently ignoring the error. */
+ setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (const char*) &off, sizeof off);
+ }
+
+ r = bind(handle->socket, addr, addrsize);
+
+ if (r == SOCKET_ERROR) {
+ err = WSAGetLastError();
+ uv_set_sys_error(WSAGetLastError());
+ return -1;
+ }
+
+ handle->flags |= UV_HANDLE_BOUND;
+
+ return 0;
+}
+
+
+int uv_udp_bind(uv_udp_t* handle, struct sockaddr_in addr, unsigned int flags) {
+ if (addr.sin_family != AF_INET) {
+ uv_set_sys_error(WSAEFAULT);
+ return -1;
+ }
+
+ return uv__bind(handle,
+ AF_INET,
+ (struct sockaddr*) &addr,
+ sizeof(struct sockaddr_in),
+ flags);
+}
+
+
+int uv_udp_bind6(uv_udp_t* handle, struct sockaddr_in6 addr, unsigned int flags) {
+ if (addr.sin6_family != AF_INET6) {
+ uv_set_sys_error(WSAEFAULT);
+ return -1;
+ }
+
+ if (uv_allow_ipv6) {
+ handle->flags |= UV_HANDLE_IPV6;
+ return uv__bind(handle,
+ AF_INET6,
+ (struct sockaddr*) &addr,
+ sizeof(struct sockaddr_in6),
+ flags);
+ } else {
+ uv_new_sys_error(WSAEAFNOSUPPORT);
+ return -1;
+ }
+}
+
+
+int uv_udp_getsockname(uv_udp_t* handle, struct sockaddr* name, int* namelen) {
+ int result;
+
+ if (handle->flags & UV_HANDLE_SHUTTING) {
+ uv_set_sys_error(WSAESHUTDOWN);
+ return -1;
+ }
+
+ result = getsockname(handle->socket, name, namelen);
+ if (result != 0) {
+ uv_set_sys_error(WSAGetLastError());
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static void uv_udp_queue_recv(uv_udp_t* handle) {
+ uv_req_t* req;
+ uv_buf_t buf;
+ DWORD bytes, flags;
+ int result;
+
+ assert(handle->flags & UV_HANDLE_READING);
+ assert(!(handle->flags & UV_HANDLE_READ_PENDING));
+
+ req = &handle->recv_req;
+ memset(&req->overlapped, 0, sizeof(req->overlapped));
+
+ /*
+ * Preallocate a read buffer if the number of active streams is below
+ * the threshold.
+ */
+#if 0
+ if (active_udp_streams < uv_active_udp_streams_threshold) {
+ handle->flags &= ~UV_HANDLE_ZERO_READ;
+#endif
+ handle->recv_buffer = handle->alloc_cb((uv_handle_t*) handle, 65536);
+ assert(handle->recv_buffer.len > 0);
+
+ buf = handle->recv_buffer;
+ memset(&handle->recv_from, 0, sizeof handle->recv_from);
+ handle->recv_from_len = sizeof handle->recv_from;
+ flags = 0;
+
+ result = WSARecvFrom(handle->socket,
+ (WSABUF*) &buf,
+ 1,
+ &bytes,
+ &flags,
+ (struct sockaddr*) &handle->recv_from,
+ &handle->recv_from_len,
+ &req->overlapped,
+ NULL);
+
+ if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) {
+ /* Process the req without IOCP. */
+ handle->flags |= UV_HANDLE_READ_PENDING;
+ req->overlapped.InternalHigh = bytes;
+ handle->reqs_pending++;
+ uv_insert_pending_req(req);
+ } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) {
+ /* The req will be processed with IOCP. */
+ handle->flags |= UV_HANDLE_READ_PENDING;
+ handle->reqs_pending++;
+ } else {
+ /* Make this req pending reporting an error. */
+ SET_REQ_ERROR(req, WSAGetLastError());
+ uv_insert_pending_req(req);
+ handle->reqs_pending++;
+ }
+#if 0
+ } else {
+ handle->flags |= UV_HANDLE_ZERO_READ;
+
+ buf.base = (char*) uv_zero_;
+ buf.len = 0;
+ flags = MSG_PARTIAL;
+
+ result = WSARecv(handle->socket,
+ (WSABUF*) &buf,
+ 1,
+ &bytes,
+ &flags,
+ &req->overlapped,
+ NULL);
+
+ if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) {
+ /* Process the req without IOCP. */
+ handle->flags |= UV_HANDLE_READ_PENDING;
+ req->overlapped.InternalHigh = bytes;
+ handle->reqs_pending++;
+ uv_insert_pending_req(req);
+ } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) {
+ /* The req will be processed with IOCP. */
+ handle->flags |= UV_HANDLE_READ_PENDING;
+ handle->reqs_pending++;
+ } else {
+ /* Make this req pending reporting an error. */
+ SET_REQ_ERROR(req, WSAGetLastError());
+ uv_insert_pending_req(req);
+ handle->reqs_pending++;
+ }
+ }
+#endif
+}
+
+
+int uv_udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb, uv_udp_recv_cb recv_cb) {
+ if (handle->flags & UV_HANDLE_READING) {
+ uv_set_sys_error(WSAEALREADY);
+ return -1;
+ }
+
+ if (!(handle->flags & UV_HANDLE_BOUND) &&
+ uv_udp_bind(handle, uv_addr_ip4_any_, 0) < 0) {
+ return -1;
+ }
+
+ handle->flags |= UV_HANDLE_READING;
+ active_udp_streams++;
+
+ handle->recv_cb = recv_cb;
+ handle->alloc_cb = alloc_cb;
+
+ /* If reading was stopped and then started again, there could stell be a */
+ /* recv request pending. */
+ if (!(handle->flags & UV_HANDLE_READ_PENDING))
+ uv_udp_queue_recv(handle);
+
+ return 0;
+}
+
+
+int uv_udp_recv_stop(uv_udp_t* handle) {
+ if (handle->flags & UV_HANDLE_READING) {
+ handle->flags &= ~UV_HANDLE_READING;
+ active_udp_streams--;
+ }
+
+ return 0;
+}
+
+
+int uv_udp_connect6(uv_connect_t* req, uv_udp_t* handle,
+ struct sockaddr_in6 address, uv_connect_cb cb) {
+ int addrsize = sizeof(struct sockaddr_in6);
+ BOOL success;
+ DWORD bytes;
+
+ if (!uv_allow_ipv6) {
+ uv_new_sys_error(WSAEAFNOSUPPORT);
+ return -1;
+ }
+
+ if (address.sin6_family != AF_INET6) {
+ uv_set_sys_error(WSAEFAULT);
+ return -1;
+ }
+
+ if (!(handle->flags & UV_HANDLE_BOUND) &&
+ uv_udp_bind6(handle, uv_addr_ip6_any_, 0) < 0)
+ return -1;
+
+ uv_req_init((uv_req_t*) req);
+ req->type = UV_CONNECT;
+ req->handle = (uv_stream_t*) handle;
+ req->cb = cb;
+ memset(&req->overlapped, 0, sizeof(req->overlapped));
+
+ success = pConnectEx6(handle->socket,
+ (struct sockaddr*) &address,
+ addrsize,
+ NULL,
+ 0,
+ &bytes,
+ &req->overlapped);
+
+ if (UV_SUCCEEDED_WITHOUT_IOCP(success)) {
+ handle->reqs_pending++;
+ uv_insert_pending_req((uv_req_t*)req);
+ } else if (UV_SUCCEEDED_WITH_IOCP(success)) {
+ handle->reqs_pending++;
+ } else {
+ uv_set_sys_error(WSAGetLastError());
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int uv__udp_send(uv_udp_send_t* req, uv_udp_t* handle, uv_buf_t bufs[],
+ int bufcnt, struct sockaddr* addr, int addr_len, uv_udp_send_cb cb) {
+ DWORD result, bytes;
+
+ uv_req_init((uv_req_t*) req);
+ req->type = UV_UDP_SEND;
+ req->handle = handle;
+ req->cb = cb;
+ memset(&req->overlapped, 0, sizeof(req->overlapped));
+
+ result = WSASendTo(handle->socket,
+ (WSABUF*)bufs,
+ bufcnt,
+ &bytes,
+ 0,
+ addr,
+ addr_len,
+ &req->overlapped,
+ NULL);
+
+ if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) {
+ /* Request completed immediately. */
+ req->queued_bytes = 0;
+ handle->reqs_pending++;
+ uv_insert_pending_req((uv_req_t*)req);
+ } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) {
+ /* Request queued by the kernel. */
+ req->queued_bytes = uv_count_bufs(bufs, bufcnt);
+ handle->reqs_pending++;
+ } else {
+ /* Send failed due to an error. */
+ uv_set_sys_error(WSAGetLastError());
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int uv_udp_send(uv_udp_send_t* req, uv_udp_t* handle, uv_buf_t bufs[],
+ int bufcnt, struct sockaddr_in addr, uv_udp_send_cb cb) {
+
+ if (!(handle->flags & UV_HANDLE_BOUND) &&
+ uv_udp_bind(handle, uv_addr_ip4_any_, 0) < 0) {
+ return -1;
+ }
+
+ return uv__udp_send(req,
+ handle,
+ bufs,
+ bufcnt,
+ (struct sockaddr*) &addr,
+ sizeof addr,
+ cb);
+}
+
+
+int uv_udp_send6(uv_udp_send_t* req, uv_udp_t* handle, uv_buf_t bufs[],
+ int bufcnt, struct sockaddr_in6 addr, uv_udp_send_cb cb) {
+
+ if (!(handle->flags & UV_HANDLE_BOUND) &&
+ uv_udp_bind6(handle, uv_addr_ip6_any_, 0) < 0) {
+ return -1;
+ }
+
+ return uv__udp_send(req,
+ handle,
+ bufs,
+ bufcnt,
+ (struct sockaddr*) &addr,
+ sizeof addr,
+ cb);
+}
+
+
+void uv_process_udp_recv_req(uv_udp_t* handle, uv_req_t* req) {
+ uv_buf_t buf;
+ int partial;
+
+ assert(handle->type == UV_UDP);
+
+ handle->flags &= ~UV_HANDLE_READ_PENDING;
+
+ if (!REQ_SUCCESS(req) &&
+ GET_REQ_STATUS(req) != STATUS_RECEIVE_EXPEDITED) {
+ /* An error occurred doing the read. */
+ if ((handle->flags & UV_HANDLE_READING)) {
+ LOOP->last_error = GET_REQ_UV_SOCK_ERROR(req);
+ uv_udp_recv_stop(handle);
+#if 0
+ buf = (handle->flags & UV_HANDLE_ZERO_READ) ?
+ uv_buf_init(NULL, 0) : handle->recv_buffer;
+#else
+ buf = handle->recv_buffer;
+#endif
+ handle->recv_cb(handle, -1, buf, NULL, 0);
+ }
+ goto done;
+ }
+
+#if 0
+ if (!(handle->flags & UV_HANDLE_ZERO_READ)) {
+#endif
+ /* Successful read */
+ partial = (GET_REQ_STATUS(req) == STATUS_RECEIVE_EXPEDITED);
+ handle->recv_cb(handle,
+ req->overlapped.InternalHigh,
+ handle->recv_buffer,
+ (struct sockaddr*) &handle->recv_from,
+ partial ? UV_UDP_PARTIAL : 0);
+#if 0
+ } else {
+ DWORD bytes, err, flags;
+ struct sockaddr_storage from;
+ int from_len;
+
+ /* Do a nonblocking receive */
+ /* TODO: try to read multiple datagrams at once. FIONREAD maybe? */
+ buf = handle->alloc_cb((uv_handle_t*) handle, 65536);
+ assert(buf.len > 0);
+
+ memset(&from, 0, sizeof from);
+ from_len = sizeof from;
+ flags = MSG_PARTIAL;
+
+ if (WSARecvFrom(handle->socket,
+ (WSABUF*)&buf,
+ 1,
+ &bytes,
+ &flags,
+ (struct sockaddr*) &from,
+ &from_len,
+ NULL,
+ NULL) != SOCKET_ERROR) {
+
+ /* Message received */
+ handle->recv_cb(handle,
+ bytes,
+ buf,
+ (struct sockaddr*) &from,
+ (flags & MSG_PARTIAL) ? UV_UDP_PARTIAL : 0);
+ } else {
+ err = WSAGetLastError();
+ if (err == WSAEWOULDBLOCK) {
+ uv_set_sys_error(WSAEWOULDBLOCK);
+ handle->recv_cb(handle, 0, buf, NULL, 0);
+ } else {
+ /* Ouch! serious error. */
+ uv_set_sys_error(err);
+ handle->recv_cb(handle, -1, buf, NULL, 0);
+ }
+ }
+ }
+#endif
+
+done:
+ /* Post another read if still reading and not closing. */
+ if ((handle->flags & UV_HANDLE_READING) &&
+ !(handle->flags & UV_HANDLE_READ_PENDING)) {
+ uv_udp_queue_recv(handle);
+ }
+
+ DECREASE_PENDING_REQ_COUNT(handle);
+}
+
+
+void uv_process_udp_send_req(uv_udp_t* handle, uv_udp_send_t* req) {
+ assert(handle->type == UV_UDP);
+
+ if (req->cb) {
+ if (REQ_SUCCESS(req)) {
+ req->cb(req, 0);
+ } else {
+ LOOP->last_error = GET_REQ_UV_SOCK_ERROR(req);
+ req->cb(req, -1);
+ }
+ }
+
+ DECREASE_PENDING_REQ_COUNT(handle);
+}
+
View
4,042 deps/uv/src/win/winapi.h
4,040 additions, 2 deletions not shown
View
115 deps/uv/src/win/winsock.c
@@ -153,3 +153,118 @@ void uv_winsock_init() {
}
}
}
+
+
+int uv_ntstatus_to_winsock_error(NTSTATUS status) {
+ switch (status) {
+ case STATUS_SUCCESS:
+ return ERROR_SUCCESS;
+
+ case STATUS_PENDING:
+ return ERROR_IO_PENDING;
+
+ case STATUS_INVALID_HANDLE:
+ case STATUS_OBJECT_TYPE_MISMATCH:
+ return WSAENOTSOCK;
+
+ case STATUS_INSUFFICIENT_RESOURCES:
+ case STATUS_PAGEFILE_QUOTA:
+ case STATUS_COMMITMENT_LIMIT:
+ case STATUS_WORKING_SET_QUOTA:
+ case STATUS_NO_MEMORY:
+ case STATUS_CONFLICTING_ADDRESSES:
+ case STATUS_QUOTA_EXCEEDED:
+ case STATUS_TOO_MANY_PAGING_FILES:
+ case STATUS_REMOTE_RESOURCES:
+ case STATUS_TOO_MANY_ADDRESSES:
+ return WSAENOBUFS;
+
+ case STATUS_SHARING_VIOLATION:
+ case STATUS_ADDRESS_ALREADY_EXISTS:
+ return WSAEADDRINUSE;
+
+ case STATUS_LINK_TIMEOUT:
+ case STATUS_IO_TIMEOUT:
+ case STATUS_TIMEOUT:
+ return WSAETIMEDOUT;
+
+ case STATUS_GRACEFUL_DISCONNECT:
+ return WSAEDISCON;
+
+ case STATUS_REMOTE_DISCONNECT:
+ case STATUS_CONNECTION_RESET:
+ case STATUS_LINK_FAILED:
+ case STATUS_CONNECTION_DISCONNECTED:
+ case STATUS_PORT_UNREACHABLE:
+ return WSAECONNRESET;
+
+ case STATUS_LOCAL_DISCONNECT:
+ case STATUS_TRANSACTION_ABORTED:
+ case STATUS_CONNECTION_ABORTED:
+ return WSAECONNABORTED;
+
+ case STATUS_BAD_NETWORK_PATH:
+ case STATUS_NETWORK_UNREACHABLE:
+ case STATUS_PROTOCOL_UNREACHABLE:
+ return WSAENETUNREACH;
+
+ case STATUS_HOST_UNREACHABLE:
+ return WSAEHOSTUNREACH;
+
+ case STATUS_CANCELLED:
+ case STATUS_REQUEST_ABORTED:
+ return WSAEINTR;
+
+ case STATUS_BUFFER_OVERFLOW:
+ case STATUS_INVALID_BUFFER_SIZE:
+ return WSAEMSGSIZE;
+
+ case STATUS_BUFFER_TOO_SMALL:
+ case STATUS_ACCESS_VIOLATION:
+ return WSAEFAULT;
+
+ case STATUS_DEVICE_NOT_READY:
+ case STATUS_REQUEST_NOT_ACCEPTED:
+ return WSAEWOULDBLOCK;
+
+ case STATUS_INVALID_NETWORK_RESPONSE:
+ case STATUS_NETWORK_BUSY:
+ case STATUS_NO_SUCH_DEVICE:
+ case STATUS_NO_SUCH_FILE:
+ case STATUS_OBJECT_PATH_NOT_FOUND:
+ case STATUS_OBJECT_NAME_NOT_FOUND:
+ case STATUS_UNEXPECTED_NETWORK_ERROR:
+ return WSAENETDOWN;
+
+ case STATUS_INVALID_CONNECTION:
+ return WSAENOTCONN;
+
+ case STATUS_REMOTE_NOT_LISTENING:
+ case STATUS_CONNECTION_REFUSED:
+ return WSAECONNREFUSED;
+
+ case STATUS_PIPE_DISCONNECTED:
+ return WSAESHUTDOWN;
+
+ case STATUS_INVALID_ADDRESS:
+ case STATUS_INVALID_ADDRESS_COMPONENT:
+ return WSAEADDRNOTAVAIL;
+
+ case STATUS_NOT_SUPPORTED:
+ case STATUS_NOT_IMPLEMENTED:
+ return WSAEOPNOTSUPP;
+
+ case STATUS_ACCESS_DENIED:
+ return WSAEACCES;
+
+ default:
+ if (status & ((FACILITY_NTWIN32 << 16) | ERROR_SEVERITY_ERROR)) {
+ /* It's a windows error that has been previously mapped to an */
+ /* ntstatus code. */
+ return (DWORD) (status & 0xffff);
+ } else {
+ /* The default fallback for unmappable ntstatus codes. */
+ return WSAEINVAL;
+ }
+ }
+}
View
8 deps/uv/src/win/winsock.h
@@ -99,10 +99,14 @@
#endif
/*
- * MinGW is missing this too
+ * MinGW is missing these too
*/
#ifndef SO_UPDATE_CONNECT_CONTEXT
-# define SO_UPDATE_CONNECT_CONTEXT 0x7010
+# define SO_UPDATE_CONNECT_CONTEXT 0x7010
+#endif
+
+#ifndef IPV6_V6ONLY
+ #define IPV6_V6ONLY 27
#endif
View
21 deps/uv/test/benchmark-list.h
@@ -29,6 +29,16 @@ BENCHMARK_DECLARE (tcp_pump100_client)
BENCHMARK_DECLARE (tcp_pump1_client)
BENCHMARK_DECLARE (pipe_pump100_client)
BENCHMARK_DECLARE (pipe_pump1_client)
+BENCHMARK_DECLARE (udp_packet_storm_1v1)
+BENCHMARK_DECLARE (udp_packet_storm_1v10)
+BENCHMARK_DECLARE (udp_packet_storm_1v100)
+BENCHMARK_DECLARE (udp_packet_storm_1v1000)
+BENCHMARK_DECLARE (udp_packet_storm_10v10)
+BENCHMARK_DECLARE (udp_packet_storm_10v100)
+BENCHMARK_DECLARE (udp_packet_storm_10v1000)
+BENCHMARK_DECLARE (udp_packet_storm_100v100)
+BENCHMARK_DECLARE (udp_packet_storm_100v1000)
+BENCHMARK_DECLARE (udp_packet_storm_1000v1000)
BENCHMARK_DECLARE (gethostbyname)
BENCHMARK_DECLARE (getaddrinfo)
BENCHMARK_DECLARE (spawn)
@@ -68,6 +78,17 @@ TASK_LIST_START
BENCHMARK_ENTRY (pipe_pound_1000)
BENCHMARK_HELPER (pipe_pound_1000, pipe_echo_server)
+ BENCHMARK_ENTRY (udp_packet_storm_1v1)
+ BENCHMARK_ENTRY (udp_packet_storm_1v10)
+ BENCHMARK_ENTRY (udp_packet_storm_1v100)
+ BENCHMARK_ENTRY (udp_packet_storm_1v1000)
+ BENCHMARK_ENTRY (udp_packet_storm_10v10)
+ BENCHMARK_ENTRY (udp_packet_storm_10v100)
+ BENCHMARK_ENTRY (udp_packet_storm_10v1000)
+ BENCHMARK_ENTRY (udp_packet_storm_100v100)
+ BENCHMARK_ENTRY (udp_packet_storm_100v1000)
+ BENCHMARK_ENTRY (udp_packet_storm_1000v1000)
+
BENCHMARK_ENTRY (gethostbyname)
BENCHMARK_HELPER (gethostbyname, dns_server)
View
2  deps/uv/test/benchmark-ping-pongs.c
@@ -52,7 +52,7 @@ static int completed_pingers = 0;
static int64_t start_time;
-static uv_buf_t buf_alloc(uv_stream_t* tcp, size_t size) {
+static uv_buf_t buf_alloc(uv_handle_t* tcp, size_t size) {
buf_t* ab;
ab = buf_freelist;
View
4 deps/uv/test/benchmark-pound.c
@@ -72,13 +72,13 @@ static uint64_t start; /* in ms */
static int closed_streams;
static int conns_failed;
-static uv_buf_t alloc_cb(uv_stream_t* stream, size_t suggested_size);
+static uv_buf_t alloc_cb(uv_handle_t* handle, size_t suggested_size);
static void connect_cb(uv_connect_t* conn_req, int status);
static void read_cb(uv_stream_t* stream, ssize_t nread, uv_buf_t buf);
static void close_cb(uv_handle_t* handle);
-static uv_buf_t alloc_cb(uv_stream_t* stream, size_t suggested_size) {
+static uv_buf_t alloc_cb(uv_handle_t* handle, size_t suggested_size) {
static char slab[65536];
uv_buf_t buf;
buf.base = slab;
View
4 deps/uv/test/benchmark-pump.c
@@ -41,7 +41,7 @@ static void maybe_connect_some();
static uv_req_t* req_alloc();
static void req_free(uv_req_t* uv_req);
-static uv_buf_t buf_alloc(uv_stream_t*, size_t size);
+static uv_buf_t buf_alloc(uv_handle_t*, size_t size);
static void buf_free(uv_buf_t uv_buf_t);
@@ -337,7 +337,7 @@ typedef struct buf_list_s {
static buf_list_t* buf_freelist = NULL;
-static uv_buf_t buf_alloc(uv_stream_t* stream, size_t size) {
+static uv_buf_t buf_alloc(uv_handle_t* handle, size_t size) {
buf_list_t* buf;
buf = buf_freelist;
View
2  deps/uv/test/benchmark-spawn.c
@@ -69,7 +69,7 @@ static void exit_cb(uv_process_t* process, int exit_status, int term_signal) {
}
-uv_buf_t on_alloc(uv_stream_t* tcp, size_t suggested_size) {
+uv_buf_t on_alloc(uv_handle_t* handle, size_t suggested_size) {
uv_buf_t buf;
buf.base = output + output_used;
buf.len = OUTPUT_SIZE - output_used;
View
247 deps/uv/test/benchmark-udp-packet-storm.c
@@ -0,0 +1,247 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "task.h"
+#include "uv.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define EXPECTED "RANG TANG DING DONG I AM THE JAPANESE SANDMAN" /* "Take eight!" */
+
+#define TEST_DURATION 5000 /* ms */
+
+#define MAX_SENDERS 1000
+#define MAX_RECEIVERS 1000
+
+#define BASE_PORT 12345
+
+#define ARRAY_SIZE(a) (sizeof((a)) / sizeof((a)[0]))
+
+static int n_senders_;
+static int n_receivers_;
+static uv_udp_t senders[MAX_SENDERS];
+static uv_udp_t receivers[MAX_RECEIVERS];
+static uv_buf_t bufs[5];
+
+static int send_cb_called;
+static int recv_cb_called;
+static int close_cb_called;