complete upgrade
authorRyan Dahl <ry@tinyclouds.org>
Tue, 19 Jul 2011 09:50:33 +0000 (02:50 -0700)
committerRyan Dahl <ry@tinyclouds.org>
Tue, 19 Jul 2011 09:50:33 +0000 (02:50 -0700)
14 files changed:
deps/uv/src/win/async.c [new file with mode: 0644]
deps/uv/src/win/cares.c [new file with mode: 0644]
deps/uv/src/win/core.c [new file with mode: 0644]
deps/uv/src/win/error.c [new file with mode: 0644]
deps/uv/src/win/getaddrinfo.c [new file with mode: 0644]
deps/uv/src/win/handle.c [new file with mode: 0644]
deps/uv/src/win/internal.h [new file with mode: 0644]
deps/uv/src/win/loop-watcher.c [new file with mode: 0644]
deps/uv/src/win/pipe.c [new file with mode: 0644]
deps/uv/src/win/req.c [new file with mode: 0644]
deps/uv/src/win/stream.c [new file with mode: 0644]
deps/uv/src/win/tcp.c [new file with mode: 0644]
deps/uv/src/win/timer.c [new file with mode: 0644]
deps/uv/src/win/util.c [new file with mode: 0644]

diff --git a/deps/uv/src/win/async.c b/deps/uv/src/win/async.c
new file mode 100644 (file)
index 0000000..fb5ed90
--- /dev/null
@@ -0,0 +1,129 @@
+/* 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 "internal.h"
+
+
+/* Atomic set operation on char */
+#ifdef _MSC_VER /* MSVC */
+
+/* _InterlockedOr8 is supported by MSVC on x32 and x64. It is  slightly less */
+/* efficient than InterlockedExchange, but InterlockedExchange8 does not */
+/* exist, and interlocked operations on larger targets might require the */
+/* target to be aligned. */
+#pragma intrinsic(_InterlockedOr8)
+
+static char __declspec(inline) uv_atomic_exchange_set(char volatile* target) {
+  return _InterlockedOr8(target, 1);
+}
+
+#else /* GCC */
+
+/* Mingw-32 version, hopefully this works for 64-bit gcc as well. */
+static inline char uv_atomic_exchange_set(char volatile* target) {
+  const char one = 1;
+  char old_value;
+  __asm__ __volatile__ ("lock xchgb %0, %1\n\t"
+                        : "=r"(old_value), "=m"(*target)
+                        : "0"(one), "m"(*target)
+                        : "memory");
+  return old_value;
+}
+
+#endif
+
+
+void uv_async_endgame(uv_async_t* handle) {
+  if (handle->flags & UV_HANDLE_CLOSING &&
+      !handle->async_sent) {
+    assert(!(handle->flags & UV_HANDLE_CLOSED));
+    handle->flags |= UV_HANDLE_CLOSED;
+
+    if (handle->close_cb) {
+      handle->close_cb((uv_handle_t*)handle);
+    }
+
+    uv_unref();
+  }
+}
+
+
+int uv_async_init(uv_async_t* handle, uv_async_cb async_cb) {
+  uv_req_t* req;
+
+  uv_counters()->handle_init++;
+  uv_counters()->async_init++;
+
+  handle->type = UV_ASYNC;
+  handle->flags = 0;
+  handle->async_sent = 0;
+  handle->error = uv_ok_;
+  handle->async_cb = async_cb;
+
+  req = &handle->async_req;
+  uv_req_init(req);
+  req->type = UV_WAKEUP;
+  req->data = handle;
+
+  uv_ref();
+
+  return 0;
+}
+
+
+int uv_async_send(uv_async_t* handle) {
+  if (handle->type != UV_ASYNC) {
+    /* Can't set errno because that's not thread-safe. */
+    return -1;
+  }
+
+  /* The user should make sure never to call uv_async_send to a closing */
+  /* or closed handle. */
+  assert(!(handle->flags & UV_HANDLE_CLOSING));
+
+  if (!uv_atomic_exchange_set(&handle->async_sent)) {
+    if (!PostQueuedCompletionStatus(LOOP->iocp,
+                                    0,
+                                    0,
+                                    &handle->async_req.overlapped)) {
+      uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus");
+    }
+  }
+
+  return 0;
+}
+
+
+void uv_process_async_wakeup_req(uv_async_t* handle, uv_req_t* req) {
+  assert(handle->type == UV_ASYNC);
+  assert(req->type == UV_WAKEUP);
+
+  handle->async_sent = 0;
+  if (handle->async_cb) {
+    handle->async_cb((uv_async_t*) handle, 0);
+  }
+  if (handle->flags & UV_HANDLE_CLOSING) {
+    uv_want_endgame((uv_handle_t*)handle);
+  }
+}
diff --git a/deps/uv/src/win/cares.c b/deps/uv/src/win/cares.c
new file mode 100644 (file)
index 0000000..60e75ea
--- /dev/null
@@ -0,0 +1,304 @@
+/* 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"
+
+
+/*
+ * Subclass of uv_handle_t. Used for integration of c-ares.
+ */
+struct uv_ares_action_s {
+  UV_HANDLE_FIELDS
+  struct uv_req_s ares_req;
+  SOCKET sock;
+  int read;
+  int write;
+};
+
+
+/* memory used per ares_channel */
+typedef struct uv_ares_channel_s {
+  ares_channel channel;
+  int activesockets;
+  uv_timer_t pollingtimer;
+} uv_ares_channel_t;
+
+
+/* static data to hold single ares_channel */
+static uv_ares_channel_t uv_ares_data = { NULL, 0 };
+
+
+/* default timeout per socket request if ares does not specify value */
+/* use 20 sec */
+#define ARES_TIMEOUT_MS            20000
+
+
+/* thread pool callback when socket is signalled */
+static void CALLBACK uv_ares_socksignal_tp(void* parameter, BOOLEAN timerfired) {
+  WSANETWORKEVENTS network_events;
+  uv_ares_task_t* sockhandle;
+  uv_ares_action_t* selhandle;
+  uv_req_t* uv_ares_req;
+
+  assert(parameter != NULL);
+
+  if (parameter != NULL) {
+    sockhandle = (uv_ares_task_t*)parameter;
+
+    /* clear socket status for this event */
+    /* do not fail if error, thread may run after socket close */
+    /* The code assumes that c-ares will write all pending data in the callback,
+       unless the socket would block. We can clear the state here to avoid unecessary
+       signals. */
+    WSAEnumNetworkEvents(sockhandle->sock, sockhandle->h_event, &network_events);
+
+    /* setup new handle */
+    selhandle = (uv_ares_action_t*)malloc(sizeof(uv_ares_action_t));
+    if (selhandle == NULL) {
+      uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
+    }
+    selhandle->type = UV_ARES_EVENT;
+    selhandle->close_cb = NULL;
+    selhandle->data = sockhandle->data;
+    selhandle->sock = sockhandle->sock;
+    selhandle->read = (network_events.lNetworkEvents & (FD_READ | FD_CONNECT)) ? 1 : 0;
+    selhandle->write = (network_events.lNetworkEvents & (FD_WRITE | FD_CONNECT)) ? 1 : 0;
+
+    uv_ares_req = &selhandle->ares_req;
+    uv_req_init(uv_ares_req);
+    uv_ares_req->type = UV_ARES_EVENT_REQ;
+    uv_ares_req->data = selhandle;
+
+    /* post ares needs to called */
+    if (!PostQueuedCompletionStatus(LOOP->iocp,
+                                    0,
+                                    0,
+                                    &uv_ares_req->overlapped)) {
+      uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus");
+    }
+  }
+}
+
+
+/* periodically call ares to check for timeouts */
+static void uv_ares_poll(uv_timer_t* handle, int status) {
+  if (uv_ares_data.channel != NULL && uv_ares_data.activesockets > 0) {
+    ares_process_fd(uv_ares_data.channel, ARES_SOCKET_BAD, ARES_SOCKET_BAD);
+  }
+}
+
+
+/* callback from ares when socket operation is started */
+static void uv_ares_sockstate_cb(void *data, ares_socket_t sock, int read, int write) {
+  /* look to see if we have a handle for this socket in our list */
+  uv_ares_task_t* uv_handle_ares = uv_find_ares_handle(sock);
+  uv_ares_channel_t* uv_ares_data_ptr = (uv_ares_channel_t*)data;
+
+  int timeoutms = 0;
+
+  if (read == 0 && write == 0) {
+    /* if read and write are 0, cleanup existing data */
+    /* The code assumes that c-ares does a callback with read = 0 and write = 0
+       when the socket is closed. After we recieve this we stop monitoring the socket. */
+    if (uv_handle_ares != NULL) {
+      uv_req_t* uv_ares_req;
+
+      uv_handle_ares->h_close_event = CreateEvent(NULL, FALSE, FALSE, NULL);
+      /* remove Wait */
+      if (uv_handle_ares->h_wait) {
+        UnregisterWaitEx(uv_handle_ares->h_wait, uv_handle_ares->h_close_event);
+        uv_handle_ares->h_wait = NULL;
+      }
+
+      /* detach socket from the event */
+      WSAEventSelect(sock, NULL, 0);
+      if (uv_handle_ares->h_event != WSA_INVALID_EVENT) {
+        WSACloseEvent(uv_handle_ares->h_event);
+        uv_handle_ares->h_event = WSA_INVALID_EVENT;
+      }
+      /* remove handle from list */
+      uv_remove_ares_handle(uv_handle_ares);
+
+      /* Post request to cleanup the Task */
+      uv_ares_req = &uv_handle_ares->ares_req;
+      uv_req_init(uv_ares_req);
+      uv_ares_req->type = UV_ARES_CLEANUP_REQ;
+      uv_ares_req->data = uv_handle_ares;
+
+      /* post ares done with socket - finish cleanup when all threads done. */
+      if (!PostQueuedCompletionStatus(LOOP->iocp,
+                                      0,
+                                      0,
+                                      &uv_ares_req->overlapped)) {
+        uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus");
+      }
+    } else {
+      assert(0);
+      uv_fatal_error(ERROR_INVALID_DATA, "ares_SockStateCB");
+    }
+  } else {
+    if (uv_handle_ares == NULL) {
+      /* setup new handle */
+      /* The code assumes that c-ares will call us when it has an open socket.
+        We need to call into c-ares when there is something to read,
+        or when it becomes writable. */
+      uv_handle_ares = (uv_ares_task_t*)malloc(sizeof(uv_ares_task_t));
+      if (uv_handle_ares == NULL) {
+        uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
+      }
+      uv_handle_ares->type = UV_ARES_TASK;
+      uv_handle_ares->close_cb = NULL;
+      uv_handle_ares->data = uv_ares_data_ptr;
+      uv_handle_ares->sock = sock;
+      uv_handle_ares->h_wait = NULL;
+      uv_handle_ares->flags = 0;
+
+      /* create an event to wait on socket signal */
+      uv_handle_ares->h_event = WSACreateEvent();
+      if (uv_handle_ares->h_event == WSA_INVALID_EVENT) {
+        uv_fatal_error(WSAGetLastError(), "WSACreateEvent");
+      }
+
+      /* tie event to socket */
+      if (SOCKET_ERROR == WSAEventSelect(sock, uv_handle_ares->h_event, FD_READ | FD_WRITE | FD_CONNECT)) {
+        uv_fatal_error(WSAGetLastError(), "WSAEventSelect");
+      }
+
+      /* add handle to list */
+      uv_add_ares_handle(uv_handle_ares);
+      uv_ref();
+
+      /*
+       * we have a single polling timer for all ares sockets.
+       * This is preferred to using ares_timeout. See ares_timeout.c warning.
+       * if timer is not running start it, and keep socket count
+       */
+      if (uv_ares_data_ptr->activesockets == 0) {
+        uv_timer_init(&uv_ares_data_ptr->pollingtimer);
+        uv_timer_start(&uv_ares_data_ptr->pollingtimer, uv_ares_poll, 1000L, 1000L);
+      }
+      uv_ares_data_ptr->activesockets++;
+
+      /* specify thread pool function to call when event is signaled */
+      if (RegisterWaitForSingleObject(&uv_handle_ares->h_wait,
+                                  uv_handle_ares->h_event,
+                                  uv_ares_socksignal_tp,
+                                  (void*)uv_handle_ares,
+                                  INFINITE,
+                                  WT_EXECUTEINWAITTHREAD) == 0) {
+        uv_fatal_error(GetLastError(), "RegisterWaitForSingleObject");
+      }
+    } else {
+      /* found existing handle.  */
+      assert(uv_handle_ares->type == UV_ARES_TASK);
+      assert(uv_handle_ares->data != NULL);
+      assert(uv_handle_ares->h_event != WSA_INVALID_EVENT);
+    }
+  }
+}
+
+
+/* called via uv_poll when ares completion port signaled */
+void uv_process_ares_event_req(uv_ares_action_t* handle, uv_req_t* req) {
+  uv_ares_channel_t* uv_ares_data_ptr = (uv_ares_channel_t*)handle->data;
+
+  ares_process_fd(uv_ares_data_ptr->channel,
+                    handle->read ? handle->sock : INVALID_SOCKET,
+                    handle->write ?  handle->sock : INVALID_SOCKET);
+
+  /* release handle for select here  */
+  free(handle);
+}
+
+
+/* called via uv_poll when ares is finished with socket */
+void uv_process_ares_cleanup_req(uv_ares_task_t* handle, uv_req_t* req) {
+  /* check for event complete without waiting */
+  unsigned int signaled = WaitForSingleObject(handle->h_close_event, 0);
+
+  if (signaled != WAIT_TIMEOUT) {
+    uv_ares_channel_t* uv_ares_data_ptr = (uv_ares_channel_t*)handle->data;
+
+    uv_unref();
+
+    /* close event handle and free uv handle memory */
+    CloseHandle(handle->h_close_event);
+    free(handle);
+
+    /* decrement active count. if it becomes 0 stop polling */
+    if (uv_ares_data_ptr->activesockets > 0) {
+      uv_ares_data_ptr->activesockets--;
+      if (uv_ares_data_ptr->activesockets == 0) {
+        uv_close((uv_handle_t*)&uv_ares_data_ptr->pollingtimer, NULL);
+      }
+    }
+  } else {
+    /* stil busy - repost and try again */
+    if (!PostQueuedCompletionStatus(LOOP->iocp,
+                                    0,
+                                    0,
+                                    &req->overlapped)) {
+      uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus");
+    }
+  }
+}
+
+
+/* set ares SOCK_STATE callback to our handler */
+int uv_ares_init_options(ares_channel *channelptr,
+                        struct ares_options *options,
+                        int optmask) {
+  int rc;
+
+  /* only allow single init at a time */
+  if (uv_ares_data.channel != NULL) {
+    return UV_EALREADY;
+  }
+
+  /* set our callback as an option */
+  options->sock_state_cb = uv_ares_sockstate_cb;
+  options->sock_state_cb_data = &uv_ares_data;
+  optmask |= ARES_OPT_SOCK_STATE_CB;
+
+  /* We do the call to ares_init_option for caller. */
+  rc = ares_init_options(channelptr, options, optmask);
+
+  /* if success, save channel */
+  if (rc == ARES_SUCCESS) {
+    uv_ares_data.channel = *channelptr;
+  }
+
+  return rc;
+}
+
+
+/* release memory */
+void uv_ares_destroy(ares_channel channel) {
+  /* only allow destroy if did init */
+  if (uv_ares_data.channel != NULL) {
+    ares_destroy(channel);
+    uv_ares_data.channel = NULL;
+  }
+}
diff --git a/deps/uv/src/win/core.c b/deps/uv/src/win/core.c
new file mode 100644 (file)
index 0000000..3200947
--- /dev/null
@@ -0,0 +1,154 @@
+/* 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 <errno.h>
+#include <limits.h>
+#include <malloc.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "uv.h"
+#include "../uv-common.h"
+#include "internal.h"
+
+
+/* The only event loop we support right now */
+uv_loop_t uv_main_loop_;
+
+
+static void uv_loop_init() {
+  /* Create an I/O completion port */
+  LOOP->iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1);
+  if (LOOP->iocp == NULL) {
+    uv_fatal_error(GetLastError(), "CreateIoCompletionPort");
+  }
+
+  LOOP->refs = 0;
+
+  uv_update_time();
+
+  LOOP->pending_reqs_tail = NULL;
+
+  LOOP->endgame_handles = NULL;
+
+  RB_INIT(&LOOP->timers);
+
+  LOOP->check_handles = NULL;
+  LOOP->prepare_handles = NULL;
+  LOOP->idle_handles = NULL;
+
+  LOOP->next_prepare_handle = NULL;
+  LOOP->next_check_handle = NULL;
+  LOOP->next_idle_handle = NULL;
+
+  LOOP->last_error = uv_ok_;
+
+  LOOP->err_str = NULL;
+}
+
+
+void uv_init() {
+  /* Initialize winsock */
+  uv_winsock_startup();
+
+  /* Initialize timers */
+  uv_timer_startup();
+
+  /* Intialize event loop */
+  uv_loop_init();
+}
+
+
+void uv_ref() {
+  LOOP->refs++;
+}
+
+
+void uv_unref() {
+  LOOP->refs--;
+}
+
+
+static void uv_poll() {
+  BOOL success;
+  DWORD bytes;
+  ULONG_PTR key;
+  OVERLAPPED* overlapped;
+  uv_req_t* req;
+
+  success = GetQueuedCompletionStatus(LOOP->iocp,
+                                      &bytes,
+                                      &key,
+                                      &overlapped,
+                                      uv_get_poll_timeout());
+
+  uv_update_time();
+
+  if (overlapped) {
+    /* 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) {
+    /* Serious error */
+    uv_fatal_error(GetLastError(), "GetQueuedCompletionStatus");
+  }
+}
+
+
+int uv_run() {
+  while (1) {
+    uv_update_time();
+    uv_process_timers();
+
+    /* Terrible: please fix me! */
+    while (LOOP->refs > 0 &&
+        (LOOP->idle_handles || LOOP->pending_reqs_tail || LOOP->endgame_handles)) {
+      /* Terrible: please fix me! */
+      while (LOOP->pending_reqs_tail || LOOP->endgame_handles) {
+        uv_process_endgames();
+        uv_process_reqs();
+      }
+
+      /* Call idle callbacks */
+      uv_idle_invoke();
+    }
+
+    if (LOOP->refs <= 0) {
+      break;
+    }
+
+    uv_prepare_invoke();
+
+    uv_poll();
+
+    uv_check_invoke();
+  }
+
+  assert(LOOP->refs == 0);
+  return 0;
+}
diff --git a/deps/uv/src/win/error.c b/deps/uv/src/win/error.c
new file mode 100644 (file)
index 0000000..d7cf986
--- /dev/null
@@ -0,0 +1,133 @@
+/* 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 <errno.h>
+#include <malloc.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "uv.h"
+#include "../uv-common.h"
+#include "internal.h"
+
+
+const uv_err_t uv_ok_ = { UV_OK, ERROR_SUCCESS };
+
+
+/*
+ * Display an error message and abort the event loop.
+ */
+void uv_fatal_error(const int errorno, const char* syscall) {
+  char* buf = NULL;
+  const char* errmsg;
+
+  FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
+      FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorno,
+      MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&buf, 0, NULL);
+
+  if (buf) {
+    errmsg = buf;
+  } else {
+    errmsg = "Unknown error";
+  }
+
+  /* FormatMessage messages include a newline character already, */
+  /* so don't add another. */
+  if (syscall) {
+    fprintf(stderr, "%s: (%d) %s", syscall, errorno, errmsg);
+  } else {
+    fprintf(stderr, "(%d) %s", errorno, errmsg);
+  }
+
+  if (buf) {
+    LocalFree(buf);
+  }
+
+  *((char*)NULL) = 0xff; /* Force debug break */
+  abort();
+}
+
+
+uv_err_t uv_last_error() {
+  return LOOP->last_error;
+}
+
+
+char* uv_strerror(uv_err_t err) {
+  if (LOOP->err_str != NULL) {
+    LocalFree(LOOP->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)&LOOP->err_str, 0, NULL);
+
+  if (LOOP->err_str) {
+    return LOOP->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;
+    case ERROR_NOACCESS:                    return UV_EACCESS;
+    case WSAEACCES:                         return UV_EACCESS;
+    case ERROR_ADDRESS_ALREADY_ASSOCIATED:  return UV_EADDRINUSE;
+    case WSAEADDRINUSE:                     return UV_EADDRINUSE;
+    case WSAEADDRNOTAVAIL:                  return UV_EADDRNOTAVAIL;
+    case WSAEWOULDBLOCK:                    return UV_EAGAIN;
+    case WSAEALREADY:                       return UV_EALREADY;
+    case ERROR_CONNECTION_REFUSED:          return UV_ECONNREFUSED;
+    case WSAECONNREFUSED:                   return UV_ECONNREFUSED;
+    case WSAEFAULT:                         return UV_EFAULT;
+    case ERROR_INVALID_DATA:                return UV_EINVAL;
+    case WSAEINVAL:                         return UV_EINVAL;
+    case ERROR_TOO_MANY_OPEN_FILES:         return UV_EMFILE;
+    case WSAEMFILE:                         return UV_EMFILE;
+    case ERROR_OUTOFMEMORY:                 return UV_ENOMEM;
+    case ERROR_INSUFFICIENT_BUFFER:         return UV_EINVAL;
+    case ERROR_INVALID_FLAGS:               return UV_EBADF;
+    case ERROR_INVALID_PARAMETER:           return UV_EINVAL;
+    case ERROR_NO_UNICODE_TRANSLATION:      return UV_ECHARSET;
+    case ERROR_BROKEN_PIPE:                 return UV_EOF;
+    case ERROR_PIPE_BUSY:                   return UV_EBUSY;
+    case ERROR_SEM_TIMEOUT:                 return UV_ETIMEDOUT;
+    default:                                return UV_UNKNOWN;
+  }
+}
+
+
+uv_err_t uv_new_sys_error(int sys_errno) {
+  uv_err_t e;
+  e.code = uv_translate_sys_error(sys_errno);
+  e.sys_errno_ = sys_errno;
+  return e;
+}
+
+
+void uv_set_sys_error(int sys_errno) {
+  LOOP->last_error.code = uv_translate_sys_error(sys_errno);
+  LOOP->last_error.sys_errno_ = sys_errno;
+}
diff --git a/deps/uv/src/win/getaddrinfo.c b/deps/uv/src/win/getaddrinfo.c
new file mode 100644 (file)
index 0000000..7793fc4
--- /dev/null
@@ -0,0 +1,341 @@
+/* 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 <malloc.h>
+
+#include "uv.h"
+#include "internal.h"
+
+
+/*
+ * MinGW is missing this
+ */
+#ifndef _MSC_VER
+  typedef struct addrinfoW {
+    int ai_flags;
+    int ai_family;
+    int ai_socktype;
+    int ai_protocol;
+    size_t ai_addrlen;
+    wchar_t* ai_canonname;
+    struct sockaddr* ai_addr;
+    struct addrinfoW* ai_next;
+  } ADDRINFOW, *PADDRINFOW;
+
+  DECLSPEC_IMPORT int WSAAPI GetAddrInfoW(const wchar_t* node,
+                                          const wchar_t* service,
+                                          const ADDRINFOW* hints,
+                                          PADDRINFOW* result);
+
+  DECLSPEC_IMPORT void WSAAPI FreeAddrInfoW(PADDRINFOW pAddrInfo);
+#endif
+
+
+/* adjust size value to be multiple of 4. Use to keep pointer aligned */
+/* Do we need different versions of this for different architectures? */
+#define ALIGNED_SIZE(X)     ((((X) + 3) >> 2) << 2)
+
+
+/*
+ * getaddrinfo error code mapping
+ * Falls back to uv_translate_sys_error if no match
+ */
+static uv_err_code uv_translate_eai_error(int eai_errno) {
+  switch (eai_errno) {
+    case ERROR_SUCCESS:                   return UV_OK;
+    case EAI_BADFLAGS:                    return UV_EBADF;
+    case EAI_FAIL:                        return UV_EFAULT;
+    case EAI_FAMILY:                      return UV_EAIFAMNOSUPPORT;
+    case EAI_MEMORY:                      return UV_ENOMEM;
+    case EAI_NONAME:                      return UV_EAINONAME;
+    case EAI_AGAIN:                       return UV_EAGAIN;
+    case EAI_SERVICE:                     return UV_EAISERVICE;
+    case EAI_SOCKTYPE:                    return UV_EAISOCKTYPE;
+    default:                              return uv_translate_sys_error(eai_errno);
+  }
+}
+
+
+/* getaddrinfo worker thread implementation */
+static DWORD WINAPI getaddrinfo_thread_proc(void* parameter) {
+  uv_getaddrinfo_t* handle = (uv_getaddrinfo_t*)parameter;
+  int ret;
+
+  assert(handle != NULL);
+
+  if (handle != NULL) {
+    /* call OS function on this thread */
+    ret = GetAddrInfoW(handle->node, handle->service, handle->hints, &handle->res);
+    handle->retcode = ret;
+
+    /* post getaddrinfo completed */
+    if (!PostQueuedCompletionStatus(LOOP->iocp,
+                                  0,
+                                  0,
+                                  &handle->getadddrinfo_req.overlapped)) {
+      uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus");
+    }
+  }
+
+  return 0;
+}
+
+
+/*
+ * Called from uv_run when complete. Call user specified callback
+ * then free returned addrinfo
+ * Returned addrinfo strings are converted from UTF-16 to UTF-8.
+ *
+ * To minimize allocation we calculate total size required,
+ * and copy all structs and referenced strings into the one block.
+ * Each size calculation is adjusted to avoid unaligned pointers.
+ */
+void uv_process_getaddrinfo_req(uv_getaddrinfo_t* handle, uv_req_t* req) {
+  int addrinfo_len = 0;
+  int name_len = 0;
+  size_t addrinfo_struct_len = ALIGNED_SIZE(sizeof(struct addrinfo));
+  struct addrinfoW* addrinfow_ptr;
+  struct addrinfo* addrinfo_ptr;
+  char* alloc_ptr = NULL;
+  char* cur_ptr = NULL;
+  uv_err_code uv_ret;
+
+  /* release input parameter memory */
+  if (handle->alloc != NULL) {
+    free(handle->alloc);
+    handle->alloc = NULL;
+  }
+
+  uv_ret = uv_translate_eai_error(handle->retcode);
+  if (handle->retcode == 0) {
+    /* convert addrinfoW to addrinfo */
+    /* first calculate required length */
+    addrinfow_ptr = handle->res;
+    while (addrinfow_ptr != NULL) {
+      addrinfo_len += addrinfo_struct_len + ALIGNED_SIZE(addrinfow_ptr->ai_addrlen);
+      if (addrinfow_ptr->ai_canonname != NULL) {
+        name_len = uv_utf16_to_utf8(addrinfow_ptr->ai_canonname, -1, NULL, 0);
+        if (name_len == 0) {
+          uv_ret = uv_translate_sys_error(GetLastError());
+          goto complete;
+        }
+        addrinfo_len += ALIGNED_SIZE(name_len);
+      }
+      addrinfow_ptr = addrinfow_ptr->ai_next;
+    }
+
+    /* allocate memory for addrinfo results */
+    alloc_ptr = (char*)malloc(addrinfo_len);
+
+    /* do conversions */
+    if (alloc_ptr != NULL) {
+      cur_ptr = alloc_ptr;
+      addrinfow_ptr = handle->res;
+
+      while (addrinfow_ptr != NULL) {
+        /* copy addrinfo struct data */
+        assert(cur_ptr + addrinfo_struct_len <= alloc_ptr + addrinfo_len);
+        addrinfo_ptr = (struct addrinfo*)cur_ptr;
+        addrinfo_ptr->ai_family = addrinfow_ptr->ai_family;
+        addrinfo_ptr->ai_socktype = addrinfow_ptr->ai_socktype;
+        addrinfo_ptr->ai_protocol = addrinfow_ptr->ai_protocol;
+        addrinfo_ptr->ai_flags = addrinfow_ptr->ai_flags;
+        addrinfo_ptr->ai_addrlen = addrinfow_ptr->ai_addrlen;
+        addrinfo_ptr->ai_canonname = NULL;
+        addrinfo_ptr->ai_addr = NULL;
+        addrinfo_ptr->ai_next = NULL;
+
+        cur_ptr += addrinfo_struct_len;
+
+        /* copy sockaddr */
+        if (addrinfo_ptr->ai_addrlen > 0) {
+          assert(cur_ptr + addrinfo_ptr->ai_addrlen <= alloc_ptr + addrinfo_len);
+          memcpy(cur_ptr, addrinfow_ptr->ai_addr, addrinfo_ptr->ai_addrlen);
+          addrinfo_ptr->ai_addr = (struct sockaddr*)cur_ptr;
+          cur_ptr += ALIGNED_SIZE(addrinfo_ptr->ai_addrlen);
+        }
+
+        /* convert canonical name to UTF-8 */
+        if (addrinfow_ptr->ai_canonname != NULL) {
+          name_len = uv_utf16_to_utf8(addrinfow_ptr->ai_canonname, -1, NULL, 0);
+          assert(name_len > 0);
+          assert(cur_ptr + name_len <= alloc_ptr + addrinfo_len);
+          name_len = uv_utf16_to_utf8(addrinfow_ptr->ai_canonname, -1, cur_ptr, name_len);
+          assert(name_len > 0);
+          addrinfo_ptr->ai_canonname = cur_ptr;
+          cur_ptr += ALIGNED_SIZE(name_len);
+        }
+        assert(cur_ptr <= alloc_ptr + addrinfo_len);
+
+        /* set next ptr */
+        addrinfow_ptr = addrinfow_ptr->ai_next;
+        if (addrinfow_ptr != NULL) {
+          addrinfo_ptr->ai_next = (struct addrinfo*)cur_ptr;
+        }
+      }
+    } else {
+      uv_ret = UV_ENOMEM;
+    }
+
+  }
+
+  /* return memory to system */
+  if (handle->res != NULL) {
+    FreeAddrInfoW(handle->res);
+    handle->res = NULL;
+  }
+
+complete:
+  /* finally do callback with converted result */
+  handle->getaddrinfo_cb(handle, uv_ret, (struct addrinfo*)alloc_ptr);
+
+  /* release copied result memory */
+  if (alloc_ptr != NULL) {
+    free(alloc_ptr);
+  }
+
+  uv_unref();
+}
+
+
+/*
+ * Entry point for getaddrinfo
+ * we convert the UTF-8 strings to UNICODE
+ * and save the UNICODE string pointers in the handle
+ * We also copy hints so that caller does not need to keep memory until the callback.
+ * return UV_OK if a callback will be made
+ * return error code if validation fails
+ *
+ * To minimize allocation we calculate total size required,
+ * and copy all structs and referenced strings into the one block.
+ * Each size calculation is adjusted to avoid unaligned pointers.
+ */
+int uv_getaddrinfo(uv_getaddrinfo_t* handle,
+                   uv_getaddrinfo_cb getaddrinfo_cb,
+                   const char* node,
+                   const char* service,
+                   const struct addrinfo* hints) {
+  int nodesize = 0;
+  int servicesize = 0;
+  int hintssize = 0;
+  char* alloc_ptr = NULL;
+
+  if (handle == NULL || getaddrinfo_cb == NULL ||
+     (node == NULL && service == NULL)) {
+    uv_set_sys_error(WSAEINVAL);
+    goto error;
+  }
+
+  handle->getaddrinfo_cb = getaddrinfo_cb;
+  handle->res = NULL;
+  handle->type = UV_GETADDRINFO;
+
+  /* calculate required memory size for all input values */
+  if (node != NULL) {
+    nodesize = ALIGNED_SIZE(uv_utf8_to_utf16(node, NULL, 0) * sizeof(wchar_t));
+    if (nodesize == 0) {
+      uv_set_sys_error(GetLastError());
+      goto error;
+    }
+  }
+
+  if (service != NULL) {
+    servicesize = ALIGNED_SIZE(uv_utf8_to_utf16(service, NULL, 0) * sizeof(wchar_t));
+    if (servicesize == 0) {
+      uv_set_sys_error(GetLastError());
+      goto error;
+    }
+  }
+  if (hints != NULL) {
+    hintssize = ALIGNED_SIZE(sizeof(struct addrinfoW));
+  }
+
+  /* allocate memory for inputs, and partition it as needed */
+  alloc_ptr = (char*)malloc(nodesize + servicesize + hintssize);
+  if (!alloc_ptr) {
+    uv_set_sys_error(WSAENOBUFS);
+    goto error;
+  }
+
+  /* save alloc_ptr now so we can free if error */
+  handle->alloc = (void*)alloc_ptr;
+
+  /* convert node string to UTF16 into allocated memory and save pointer in handle */
+  if (node != NULL) {
+    handle->node = (wchar_t*)alloc_ptr;
+    if (uv_utf8_to_utf16(node, (wchar_t*)alloc_ptr, nodesize / sizeof(wchar_t)) == 0) {
+      uv_set_sys_error(GetLastError());
+      goto error;
+    }
+    alloc_ptr += nodesize;
+  } else {
+    handle->node = NULL;
+  }
+
+  /* convert service string to UTF16 into allocated memory and save pointer in handle */
+  if (service != NULL) {
+    handle->service = (wchar_t*)alloc_ptr;
+    if (uv_utf8_to_utf16(service, (wchar_t*)alloc_ptr, servicesize / sizeof(wchar_t)) == 0) {
+      uv_set_sys_error(GetLastError());
+      goto error;
+    }
+    alloc_ptr += servicesize;
+  } else {
+    handle->service = NULL;
+  }
+
+  /* copy hints to allocated memory and save pointer in handle */
+  if (hints != NULL) {
+    handle->hints = (struct addrinfoW*)alloc_ptr;
+    handle->hints->ai_family = hints->ai_family;
+    handle->hints->ai_socktype = hints->ai_socktype;
+    handle->hints->ai_protocol = hints->ai_protocol;
+    handle->hints->ai_flags = hints->ai_flags;
+    handle->hints->ai_addrlen = 0;
+    handle->hints->ai_canonname = NULL;
+    handle->hints->ai_addr = NULL;
+    handle->hints->ai_next = NULL;
+  } else {
+    handle->hints = NULL;
+  }
+
+  /* init request for Post handling */
+  uv_req_init(&handle->getadddrinfo_req);
+  handle->getadddrinfo_req.data = handle;
+  handle->getadddrinfo_req.type = UV_GETADDRINFO_REQ;
+
+  /* Ask thread to run. Treat this as a long operation */
+  if (QueueUserWorkItem(&getaddrinfo_thread_proc, handle, WT_EXECUTELONGFUNCTION) == 0) {
+    uv_set_sys_error(GetLastError());
+    goto error;
+  }
+
+  uv_ref();
+
+  return 0;
+
+error:
+  if (handle != NULL && handle->alloc != NULL) {
+    free(handle->alloc);
+  }
+  return -1;
+}
diff --git a/deps/uv/src/win/handle.c b/deps/uv/src/win/handle.c
new file mode 100644 (file)
index 0000000..91dfba8
--- /dev/null
@@ -0,0 +1,167 @@
+/* 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 "internal.h"
+
+
+int uv_is_active(uv_handle_t* handle) {
+  switch (handle->type) {
+    case UV_TIMER:
+    case UV_IDLE:
+    case UV_PREPARE:
+    case UV_CHECK:
+      return (handle->flags & UV_HANDLE_ACTIVE) ? 1 : 0;
+
+    default:
+      return 1;
+  }
+}
+
+
+/* TODO: integrate this with uv_close. */
+static int uv_close_error(uv_handle_t* handle, uv_err_t e) {
+  uv_tcp_t* tcp;
+  uv_pipe_t* pipe;
+
+  if (handle->flags & UV_HANDLE_CLOSING) {
+    return 0;
+  }
+
+  handle->error = e;
+  handle->flags |= UV_HANDLE_CLOSING;
+
+  /* Handle-specific close actions */
+  switch (handle->type) {
+    case UV_TCP:
+      tcp = (uv_tcp_t*)handle;
+      /* If we don't shutdown before calling closesocket, windows will */
+      /* silently discard the kernel send buffer and reset the connection. */
+      if (!(tcp->flags & UV_HANDLE_SHUT)) {
+        shutdown(tcp->socket, SD_SEND);
+        tcp->flags |= UV_HANDLE_SHUT;
+      }
+      tcp->flags &= ~(UV_HANDLE_READING | UV_HANDLE_LISTENING);
+      closesocket(tcp->socket);
+      if (tcp->reqs_pending == 0) {
+        uv_want_endgame(handle);
+      }
+      return 0;
+
+    case UV_NAMED_PIPE:
+      pipe = (uv_pipe_t*)handle;
+      pipe->flags &= ~(UV_HANDLE_READING | UV_HANDLE_LISTENING);
+      close_pipe(pipe, NULL, NULL);
+      if (pipe->reqs_pending == 0) {
+        uv_want_endgame(handle);
+      }
+      return 0;
+
+    case UV_TIMER:
+      uv_timer_stop((uv_timer_t*)handle);
+      uv_want_endgame(handle);
+      return 0;
+
+    case UV_PREPARE:
+      uv_prepare_stop((uv_prepare_t*)handle);
+      uv_want_endgame(handle);
+      return 0;
+
+    case UV_CHECK:
+      uv_check_stop((uv_check_t*)handle);
+      uv_want_endgame(handle);
+      return 0;
+
+    case UV_IDLE:
+      uv_idle_stop((uv_idle_t*)handle);
+      uv_want_endgame(handle);
+      return 0;
+
+    case UV_ASYNC:
+      if (!((uv_async_t*)handle)->async_sent) {
+        uv_want_endgame(handle);
+      }
+      return 0;
+
+    default:
+      /* Not supported */
+      assert(0);
+      return -1;
+  }
+}
+
+
+int uv_close(uv_handle_t* handle, uv_close_cb close_cb) {
+  handle->close_cb = close_cb;
+  return 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;
+
+    handle->endgame_next = LOOP->endgame_handles;
+    LOOP->endgame_handles = handle;
+  }
+}
+
+
+void uv_process_endgames() {
+  uv_handle_t* handle;
+
+  while (LOOP->endgame_handles) {
+    handle = LOOP->endgame_handles;
+    LOOP->endgame_handles = handle->endgame_next;
+
+    handle->flags &= ~UV_HANDLE_ENDGAME_QUEUED;
+
+    switch (handle->type) {
+      case UV_TCP:
+        uv_tcp_endgame((uv_tcp_t*)handle);
+        break;
+
+      case UV_NAMED_PIPE:
+        uv_pipe_endgame((uv_pipe_t*)handle);
+        break;
+
+      case UV_TIMER:
+        uv_timer_endgame((uv_timer_t*)handle);
+        break;
+
+      case UV_PREPARE:
+      case UV_CHECK:
+      case UV_IDLE:
+        uv_loop_watcher_endgame(handle);
+        break;
+
+      case UV_ASYNC:
+        uv_async_endgame((uv_async_t*)handle);
+        break;
+
+      default:
+        assert(0);
+        break;
+    }
+  }
+}
diff --git a/deps/uv/src/win/internal.h b/deps/uv/src/win/internal.h
new file mode 100644 (file)
index 0000000..7c42a77
--- /dev/null
@@ -0,0 +1,223 @@
+/* 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.
+ */
+
+#ifndef UV_WIN_INTERNAL_H_
+#define UV_WIN_INTERNAL_H_
+
+#include "uv.h"
+#include "../uv-common.h"
+#include "tree.h"
+
+
+/*
+ * Timers
+ */
+
+RB_HEAD(uv_timer_tree_s, uv_timer_s);
+
+void uv_timer_startup();
+
+void uv_timer_endgame(uv_timer_t* handle);
+
+DWORD uv_get_poll_timeout();
+void uv_process_timers();
+
+
+/*
+ * Core
+ */
+
+/* Loop state struct. We don't support multiplicity right now, but this */
+/* should help when we get to that. */
+typedef struct uv_loop_s {
+  /* The loop's I/O completion port */
+  HANDLE iocp;
+  /* Reference count that keeps the event loop alive */
+  int refs;
+  /* The current time according to the event loop. in msecs. */
+  int64_t time;
+  /* Tail of a single-linked circular queue of pending reqs. If the queue */
+  /* is empty, tail_ is NULL. If there is only one item, */
+  /* tail_->next_req == tail_ */
+  uv_req_t* pending_reqs_tail;
+  /* Head of a single-linked list of closed handles */
+  uv_handle_t* endgame_handles;
+  /* The head of the timers tree */
+  struct uv_timer_tree_s timers;
+    /* Lists of active loop (prepare / check / idle) watchers */
+  uv_prepare_t* prepare_handles;
+  uv_check_t* check_handles;
+  uv_idle_t* idle_handles;
+  /* This pointer will refer to the prepare/check/idle handle whose */
+  /* callback is scheduled to be called next. This is needed to allow */
+  /* safe removal from one of the lists above while that list being */
+  /* iterated over. */
+  uv_prepare_t* next_prepare_handle;
+  uv_check_t* next_check_handle;
+  uv_idle_t* next_idle_handle;
+  /* Last error code */
+  uv_err_t last_error;
+  /* Error string most recently returned by uv_strerror() */
+  char* err_str;
+} uv_loop_t;
+
+extern uv_loop_t uv_main_loop_;
+
+#define LOOP (&uv_main_loop_)
+
+
+/*
+ * Handles
+ */
+
+/* Private uv_handle flags */
+#define UV_HANDLE_CLOSING          0x0001
+#define UV_HANDLE_CLOSED           0x0002
+#define UV_HANDLE_BOUND            0x0004
+#define UV_HANDLE_LISTENING        0x0008
+#define UV_HANDLE_CONNECTION       0x0010
+#define UV_HANDLE_CONNECTED        0x0020
+#define UV_HANDLE_READING          0x0040
+#define UV_HANDLE_ACTIVE           0x0040
+#define UV_HANDLE_EOF              0x0080
+#define UV_HANDLE_SHUTTING         0x0100
+#define UV_HANDLE_SHUT             0x0200
+#define UV_HANDLE_ENDGAME_QUEUED   0x0400
+#define UV_HANDLE_BIND_ERROR       0x1000
+#define UV_HANDLE_IPV6             0x2000
+#define UV_HANDLE_PIPESERVER       0x4000
+#define UV_HANDLE_READ_PENDING     0x8000
+
+void uv_want_endgame(uv_handle_t* handle);
+void uv_process_endgames();
+
+#define DECREASE_PENDING_REQ_COUNT(handle)    \
+  do {                                        \
+    handle->reqs_pending--;                   \
+                                              \
+    if (handle->flags & UV_HANDLE_CLOSING &&  \
+        handle->reqs_pending == 0) {          \
+      uv_want_endgame((uv_handle_t*)handle);  \
+    }                                         \
+  } while (0)
+
+
+/*
+ * Requests
+ */
+void uv_req_init(uv_req_t* req);
+
+uv_req_t* uv_overlapped_to_req(OVERLAPPED* overlapped);
+
+void uv_insert_pending_req(uv_req_t* req);
+void uv_process_reqs();
+
+
+/*
+ * Streams
+ */
+void uv_stream_init(uv_stream_t* handle);
+void uv_connection_init(uv_stream_t* handle);
+
+size_t uv_count_bufs(uv_buf_t bufs[], int count);
+
+
+/*
+ * TCP
+ */
+void uv_winsock_startup();
+
+void uv_tcp_endgame(uv_tcp_t* handle);
+
+int uv_tcp_accept(uv_tcp_t* server, uv_tcp_t* client);
+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);
+
+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);
+void uv_process_tcp_accept_req(uv_tcp_t* handle, uv_req_t* req);
+void uv_process_tcp_connect_req(uv_tcp_t* handle, uv_connect_t* req);
+
+
+/*
+ * Pipes
+ */
+void close_pipe(uv_pipe_t* handle, int* status, uv_err_t* err);
+void uv_pipe_endgame(uv_pipe_t* handle);
+
+int uv_pipe_accept(uv_pipe_t* server, uv_pipe_t* client);
+int uv_pipe_read_start(uv_pipe_t* handle, uv_alloc_cb alloc_cb,
+    uv_read_cb read_cb);
+int uv_pipe_write(uv_write_t* req, uv_pipe_t* handle, uv_buf_t bufs[],
+    int bufcnt, uv_write_cb cb);
+
+void uv_process_pipe_read_req(uv_pipe_t* handle, uv_req_t* req);
+void uv_process_pipe_write_req(uv_pipe_t* handle, uv_write_t* req);
+void uv_process_pipe_accept_req(uv_pipe_t* handle, uv_req_t* raw_req);
+void uv_process_pipe_connect_req(uv_pipe_t* handle, uv_connect_t* req);
+
+/*
+ * Loop watchers
+ */
+void uv_loop_watcher_endgame(uv_handle_t* handle);
+
+void uv_prepare_invoke();
+void uv_check_invoke();
+void uv_idle_invoke();
+
+
+/*
+ * Async watcher
+ */
+void uv_async_endgame(uv_async_t* handle);
+
+void uv_process_async_wakeup_req(uv_async_t* handle, uv_req_t* req);
+
+
+/*
+ * C-ares integration
+ */
+typedef struct uv_ares_action_s uv_ares_action_t;
+
+void uv_process_ares_event_req(uv_ares_action_t* handle, uv_req_t* req);
+void uv_process_ares_cleanup_req(uv_ares_task_t* handle, uv_req_t* req);
+
+/*
+ * Getaddrinfo
+ */
+void uv_process_getaddrinfo_req(uv_getaddrinfo_t* handle, uv_req_t* req);
+
+
+/*
+ * Error handling
+ */
+extern const uv_err_t uv_ok_;
+
+void uv_fatal_error(const int errorno, const char* syscall);
+
+uv_err_code uv_translate_sys_error(int sys_errno);
+uv_err_t uv_new_sys_error(int sys_errno);
+void uv_set_sys_error(int sys_errno);
+
+
+#endif /* UV_WIN_INTERNAL_H_ */
diff --git a/deps/uv/src/win/loop-watcher.c b/deps/uv/src/win/loop-watcher.c
new file mode 100644 (file)
index 0000000..3038218
--- /dev/null
@@ -0,0 +1,128 @@
+/* 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"
+
+
+void uv_loop_watcher_endgame(uv_handle_t* handle) {
+  if (handle->flags & UV_HANDLE_CLOSING) {
+    assert(!(handle->flags & UV_HANDLE_CLOSED));
+    handle->flags |= UV_HANDLE_CLOSED;
+
+    if (handle->close_cb) {
+      handle->close_cb(handle);
+    }
+
+    uv_unref();
+  }
+}
+
+
+#define UV_LOOP_WATCHER_DEFINE(name, NAME)                                    \
+  int uv_##name##_init(uv_##name##_t* handle) {                               \
+    handle->type = UV_##NAME;                                                 \
+    handle->flags = 0;                                                        \
+    handle->error = uv_ok_;                                                   \
+                                                                              \
+    uv_ref();                                                                 \
+                                                                              \
+    uv_counters()->handle_init++;                                             \
+    uv_counters()->prepare_init++;                                            \
+                                                                              \
+    return 0;                                                                 \
+  }                                                                           \
+                                                                              \
+                                                                              \
+  int uv_##name##_start(uv_##name##_t* handle, uv_##name##_cb cb) {           \
+    uv_##name##_t* old_head;                                                  \
+                                                                              \
+    assert(handle->type == UV_##NAME);                                        \
+                                                                              \
+    if (handle->flags & UV_HANDLE_ACTIVE)                                     \
+      return 0;                                                               \
+                                                                              \
+    old_head = LOOP->name##_handles;                                          \
+                                                                              \
+    handle->name##_next = old_head;                                           \
+    handle->name##_prev = NULL;                                               \
+                                                                              \
+    if (old_head) {                                                           \
+      old_head->name##_prev = handle;                                         \
+    }                                                                         \
+                                                                              \
+    LOOP->name##_handles = handle;                                            \
+                                                                              \
+    handle->name##_cb = cb;                                                   \
+    handle->flags |= UV_HANDLE_ACTIVE;                                        \
+                                                                              \
+    return 0;                                                                 \
+  }                                                                           \
+                                                                              \
+                                                                              \
+  int uv_##name##_stop(uv_##name##_t* handle) {                               \
+    assert(handle->type == UV_##NAME);                                        \
+                                                                              \
+    if (!(handle->flags & UV_HANDLE_ACTIVE))                                  \
+      return 0;                                                               \
+                                                                              \
+    /* Update loop head if needed */                                          \
+    if (LOOP->name##_handles == handle) {                                     \
+      LOOP->name##_handles = handle->name##_next;                             \
+    }                                                                         \
+                                                                              \
+    /* Update the iterator-next pointer of needed */                          \
+    if (LOOP->next_##name##_handle == handle) {                               \
+      LOOP->next_##name##_handle = handle->name##_next;                       \
+    }                                                                         \
+                                                                              \
+    if (handle->name##_prev) {                                                \
+      handle->name##_prev->name##_next = handle->name##_next;                 \
+    }                                                                         \
+    if (handle->name##_next) {                                                \
+      handle->name##_next->name##_prev = handle->name##_prev;                 \
+    }                                                                         \
+                                                                              \
+    handle->flags &= ~UV_HANDLE_ACTIVE;                                       \
+                                                                              \
+    return 0;                                                                 \
+  }                                                                           \
+                                                                              \
+                                                                              \
+  void uv_##name##_invoke() {                                                 \
+    uv_##name##_t* handle;                                                    \
+                                                                              \
+    LOOP->next_##name##_handle = LOOP->name##_handles;                        \
+                                                                              \
+    while (LOOP->next_##name##_handle != NULL) {                              \
+      handle = LOOP->next_##name##_handle;                                    \
+      LOOP->next_##name##_handle = handle->name##_next;                       \
+                                                                              \
+      handle->name##_cb(handle, 0);                                           \
+    }                                                                         \
+  }
+
+UV_LOOP_WATCHER_DEFINE(prepare, PREPARE)
+UV_LOOP_WATCHER_DEFINE(check, CHECK)
+UV_LOOP_WATCHER_DEFINE(idle, IDLE)
diff --git a/deps/uv/src/win/pipe.c b/deps/uv/src/win/pipe.c
new file mode 100644 (file)
index 0000000..f253d82
--- /dev/null
@@ -0,0 +1,648 @@
+/* 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 <string.h>
+
+#include "uv.h"
+#include "../uv-common.h"
+#include "internal.h"
+
+
+/* A zero-size buffer for use by uv_pipe_read */
+static char uv_zero_[] = "";
+
+
+int uv_pipe_init(uv_pipe_t* handle) {
+  uv_stream_init((uv_stream_t*)handle);
+
+  handle->type = UV_NAMED_PIPE;
+  handle->reqs_pending = 0;
+  handle->pending_accepts = NULL;
+  handle->name = NULL;
+
+  uv_counters()->pipe_init++;
+
+  return 0;
+}
+
+
+static int uv_set_pipe_handle(uv_pipe_t* handle, HANDLE pipeHandle) {
+  DWORD mode = PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT;
+
+  if (!SetNamedPipeHandleState(pipeHandle, &mode, NULL, NULL)) {
+    return -1;
+  }
+
+  if (CreateIoCompletionPort(pipeHandle,
+                             LOOP->iocp,
+                             (ULONG_PTR)handle,
+                             0) == NULL) {
+    return -1;
+  }
+
+  return 0;
+}
+
+
+void uv_pipe_endgame(uv_pipe_t* handle) {
+  uv_err_t err;
+  int status;
+
+  if (handle->flags & UV_HANDLE_SHUTTING &&
+      !(handle->flags & UV_HANDLE_SHUT) &&
+      handle->write_reqs_pending == 0) {
+    close_pipe(handle, &status, &err);
+
+    if (handle->shutdown_req->cb) {
+      if (status == -1) {
+        LOOP->last_error = err;
+      }
+      handle->shutdown_req->cb(handle->shutdown_req, status);
+    }
+    handle->reqs_pending--;
+  }
+
+  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();
+  }
+}
+
+
+/* Creates a pipe server. */
+/* TODO: make this work with UTF8 name */
+int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
+  int i;
+  uv_pipe_accept_t* req;
+
+  if (!name) {
+    uv_set_sys_error(WSAEINVAL);
+    return -1;
+  }
+
+  /* Make our own copy of the pipe name */
+  handle->name = strdup(name);
+  if (!handle->name) {
+    uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
+  }
+
+  for (i = 0; i < COUNTOF(handle->accept_reqs); i++) {
+    req = &handle->accept_reqs[i];
+    uv_req_init((uv_req_t*) req);
+    req->type = UV_ACCEPT;
+    req->data = handle;
+    req->pipeHandle = INVALID_HANDLE_VALUE;
+    req->next_pending = NULL;
+  }
+
+  handle->flags |= UV_HANDLE_PIPESERVER;
+  return 0;
+}
+
+
+static DWORD WINAPI pipe_connect_thread_proc(void* parameter) {
+  HANDLE pipeHandle = INVALID_HANDLE_VALUE;
+  int errno;
+  uv_pipe_t* handle;
+  uv_connect_t* req;
+
+  req = (uv_connect_t*)parameter;
+  assert(req);
+  handle = (uv_pipe_t*)req->handle;
+  assert(handle);
+
+  /* We're here because CreateFile on a pipe returned ERROR_PIPE_BUSY.  We wait for the pipe to become available with WaitNamedPipe. */
+  while (WaitNamedPipe(handle->name, 30000)) {
+    /* The pipe is now available, try to connect. */
+    pipeHandle = CreateFile(handle->name,
+                            GENERIC_READ | GENERIC_WRITE,
+                            0,
+                            NULL,
+                            OPEN_EXISTING,
+                            FILE_FLAG_OVERLAPPED,
+                            NULL);
+
+    if (pipeHandle != INVALID_HANDLE_VALUE) {
+      break;
+    }
+  }
+
+  if (pipeHandle != INVALID_HANDLE_VALUE && !uv_set_pipe_handle(handle, pipeHandle)) {
+    handle->handle = pipeHandle;
+    req->error = uv_ok_;
+  } else {
+    req->error = uv_new_sys_error(GetLastError());
+  }
+
+  memset(&req->overlapped, 0, sizeof(req->overlapped));
+
+  /* Post completed */
+  if (!PostQueuedCompletionStatus(LOOP->iocp,
+                                0,
+                                0,
+                                &req->overlapped)) {
+    uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus");
+  }
+
+  return 0;
+}
+
+
+/* TODO: make this work with UTF8 name */
+int uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle,
+    const char* name, uv_connect_cb cb) {
+  int errno;
+  HANDLE pipeHandle;
+
+  handle->handle = INVALID_HANDLE_VALUE;
+
+  uv_req_init((uv_req_t*) req);
+  req->type = UV_CONNECT;
+  req->handle = (uv_stream_t*) handle;
+  req->cb = cb;
+
+  pipeHandle = CreateFile(name,
+                          GENERIC_READ | GENERIC_WRITE,
+                          0,
+                          NULL,
+                          OPEN_EXISTING,
+                          FILE_FLAG_OVERLAPPED,
+                          NULL);
+
+  if (pipeHandle == INVALID_HANDLE_VALUE) {
+    if (GetLastError() == ERROR_PIPE_BUSY) {
+      /* Wait for the server to make a pipe instance available. */
+      handle->name = strdup(name);
+      if (!handle->name) {
+        uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
+      }
+
+      if (!QueueUserWorkItem(&pipe_connect_thread_proc, req, WT_EXECUTELONGFUNCTION)) {
+        errno = GetLastError();
+        goto error;
+      }
+
+      return 0;
+    }
+
+    errno = GetLastError();
+    goto error;
+  }
+
+  if (uv_set_pipe_handle((uv_pipe_t*)req->handle, pipeHandle)) {
+    errno = GetLastError();
+    goto error;
+  }
+
+  handle->handle = pipeHandle;
+
+  req->error = uv_ok_;
+  uv_insert_pending_req((uv_req_t*) req);
+  handle->reqs_pending++;
+  return 0;
+
+error:
+  if (pipeHandle != INVALID_HANDLE_VALUE) {
+    CloseHandle(pipeHandle);
+  }
+  uv_set_sys_error(errno);
+  return -1;
+}
+
+
+/* Cleans up uv_pipe_t (server or connection) and all resources associated with it */
+void close_pipe(uv_pipe_t* handle, int* status, uv_err_t* err) {
+  int i;
+  HANDLE pipeHandle;
+
+  if (handle->name) {
+    free(handle->name);
+    handle->name;
+  }
+
+  if (handle->flags & UV_HANDLE_PIPESERVER) {
+    for (i = 0; i < COUNTOF(handle->accept_reqs); i++) {
+      pipeHandle = handle->accept_reqs[i].pipeHandle;
+      if (pipeHandle != INVALID_HANDLE_VALUE) {
+        CloseHandle(pipeHandle);
+      }
+    }
+
+  } else if (handle->handle != INVALID_HANDLE_VALUE) {
+    CloseHandle(handle->handle);
+  }
+
+  handle->flags |= UV_HANDLE_SHUT;
+}
+
+
+static void uv_pipe_queue_accept(uv_pipe_t* handle, uv_pipe_accept_t* req) {
+  HANDLE pipeHandle;
+
+  assert(handle->flags & UV_HANDLE_LISTENING);
+  assert(req->pipeHandle == INVALID_HANDLE_VALUE);
+
+  pipeHandle = CreateNamedPipe(handle->name,
+                               PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
+                               PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
+                               PIPE_UNLIMITED_INSTANCES,
+                               65536,
+                               65536,
+                               0,
+                               NULL);
+
+  if (pipeHandle == INVALID_HANDLE_VALUE) {
+    req->error = uv_new_sys_error(GetLastError());
+    uv_insert_pending_req((uv_req_t*) req);
+    handle->reqs_pending++;
+    return;
+  }
+
+  if (CreateIoCompletionPort(pipeHandle,
+                                LOOP->iocp,
+                                (ULONG_PTR)handle,
+                                0) == NULL) {
+    req->error = uv_new_sys_error(GetLastError());
+    uv_insert_pending_req((uv_req_t*) req);
+    handle->reqs_pending++;
+    return;
+  }
+
+  /* Prepare the overlapped structure. */
+  memset(&(req->overlapped), 0, sizeof(req->overlapped));
+
+  if (!ConnectNamedPipe(pipeHandle, &req->overlapped) && GetLastError() != ERROR_IO_PENDING) {
+    if (GetLastError() == ERROR_PIPE_CONNECTED) {
+      req->pipeHandle = pipeHandle;
+      req->error = uv_ok_;
+    } else {
+      /* Make this req pending reporting an error. */
+      req->error = uv_new_sys_error(GetLastError());
+    }
+    uv_insert_pending_req((uv_req_t*) req);
+    handle->reqs_pending++;
+    return;
+  }
+
+  req->pipeHandle = pipeHandle;
+  handle->reqs_pending++;
+}
+
+
+int uv_pipe_accept(uv_pipe_t* server, uv_pipe_t* client) {
+  /* Find a connection instance that has been connected, but not yet accepted. */
+  uv_pipe_accept_t* req = server->pending_accepts;
+
+  if (!req) {
+    /* No valid connections found, so we error out. */
+    uv_set_sys_error(WSAEWOULDBLOCK);
+    return -1;
+  }
+
+  /* Initialize the client handle and copy the pipeHandle to the client */
+  uv_pipe_init(client);
+  uv_connection_init((uv_stream_t*) client);
+  client->handle = req->pipeHandle;
+
+  /* Prepare the req to pick up a new connection */
+  server->pending_accepts = req->next_pending;
+  req->next_pending = NULL;
+  req->pipeHandle = INVALID_HANDLE_VALUE;
+
+  if (!(server->flags & UV_HANDLE_CLOSING)) {
+    uv_pipe_queue_accept(server, req);
+  }
+
+  return 0;
+}
+
+
+/* Starts listening for connections for the given pipe. */
+int uv_pipe_listen(uv_pipe_t* handle, uv_connection_cb cb) {
+  int i, errno;
+
+  if (handle->flags & UV_HANDLE_LISTENING ||
+      handle->flags & UV_HANDLE_READING) {
+    uv_set_sys_error(UV_EALREADY);
+    return -1;
+  }
+
+  if (!(handle->flags & UV_HANDLE_PIPESERVER)) {
+    uv_set_sys_error(UV_ENOTSUP);
+    return -1;
+  }
+
+  handle->flags |= UV_HANDLE_LISTENING;
+  handle->connection_cb = cb;
+
+  for (i = 0; i < COUNTOF(handle->accept_reqs); i++) {
+    uv_pipe_queue_accept(handle, &handle->accept_reqs[i]);
+  }
+
+  return 0;
+}
+
+
+static void uv_pipe_queue_read(uv_pipe_t* handle) {
+  uv_req_t* req;
+  int result;
+
+  assert(handle->flags & UV_HANDLE_READING);
+  assert(!(handle->flags & UV_HANDLE_READ_PENDING));
+
+  assert(handle->handle != INVALID_HANDLE_VALUE);
+
+  req = &handle->read_req;
+  memset(&req->overlapped, 0, sizeof(req->overlapped));
+
+  /* Do 0-read */
+  result = ReadFile(handle->handle,
+                    &uv_zero_,
+                    0,
+                    NULL,
+                    &req->overlapped);
+
+  if (!result && GetLastError() != ERROR_IO_PENDING) {
+    /* Make this req pending reporting an error. */
+    req->error = uv_new_sys_error(WSAGetLastError());
+    uv_insert_pending_req(req);
+    handle->reqs_pending++;
+    return;
+  }
+
+  handle->flags |= UV_HANDLE_READ_PENDING;
+  handle->reqs_pending++;
+}
+
+
+int uv_pipe_read_start(uv_pipe_t* handle, uv_alloc_cb alloc_cb, uv_read_cb read_cb) {
+  if (!(handle->flags & UV_HANDLE_CONNECTION)) {
+    uv_set_sys_error(UV_EINVAL);
+    return -1;
+  }
+
+  if (handle->flags & UV_HANDLE_READING) {
+    uv_set_sys_error(UV_EALREADY);
+    return -1;
+  }
+
+  if (handle->flags & UV_HANDLE_EOF) {
+    uv_set_sys_error(UV_EOF);
+    return -1;
+  }
+
+  handle->flags |= UV_HANDLE_READING;
+  handle->read_cb = read_cb;
+  handle->alloc_cb = alloc_cb;
+
+  /* If reading was stopped and then started again, there could stell be a */
+  /* read request pending. */
+  if (!(handle->flags & UV_HANDLE_READ_PENDING))
+    uv_pipe_queue_read(handle);
+
+  return 0;
+}
+
+
+int uv_pipe_write(uv_write_t* req, uv_pipe_t* handle, uv_buf_t bufs[], int bufcnt,
+    uv_write_cb cb) {
+  int result;
+
+  if (bufcnt != 1) {
+    uv_set_sys_error(UV_ENOTSUP);
+    return -1;
+  }
+
+  assert(handle->handle != INVALID_HANDLE_VALUE);
+
+  if (!(handle->flags & UV_HANDLE_CONNECTION)) {
+    uv_set_sys_error(UV_EINVAL);
+    return -1;
+  }
+
+  if (handle->flags & UV_HANDLE_SHUTTING) {
+    uv_set_sys_error(UV_EOF);
+    return -1;
+  }
+
+  uv_req_init((uv_req_t*) req);
+  req->type = UV_WRITE;
+  req->handle = (uv_stream_t*) handle;
+  req->cb = cb;
+  memset(&req->overlapped, 0, sizeof(req->overlapped));
+
+  result = WriteFile(handle->handle,
+                     bufs[0].base,
+                     bufs[0].len,
+                     NULL,
+                     &req->overlapped);
+
+  if (!result && GetLastError() != WSA_IO_PENDING) {
+    uv_set_sys_error(GetLastError());
+    return -1;
+  }
+
+  if (result) {
+    /* Request completed immediately. */
+    req->queued_bytes = 0;
+  } else {
+    /* Request queued by the kernel. */
+    req->queued_bytes = uv_count_bufs(bufs, bufcnt);
+    handle->write_queue_size += req->queued_bytes;
+  }
+
+  handle->reqs_pending++;
+  handle->write_reqs_pending++;
+
+  return 0;
+}
+
+
+void uv_process_pipe_read_req(uv_pipe_t* handle, uv_req_t* req) {
+  DWORD bytes, err, mode;
+  uv_buf_t buf;
+
+  assert(handle->type == UV_NAMED_PIPE);
+
+  handle->flags &= ~UV_HANDLE_READ_PENDING;
+
+  if (req->error.code != UV_OK) {
+    /* 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;
+      buf.base = 0;
+      buf.len = 0;
+      handle->read_cb((uv_stream_t*)handle, -1, buf);
+    }
+  } else {
+    /*
+      * Temporarily switch to non-blocking mode.
+      * This is so that ReadFile doesn't block if the read buffer is empty.
+      */
+    mode = PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_NOWAIT;
+    if (!SetNamedPipeHandleState(handle->handle, &mode, NULL, NULL)) {
+      /* We can't continue processing this read. */
+      handle->flags &= ~UV_HANDLE_READING;
+      uv_set_sys_error(GetLastError());
+      buf.base = 0;
+      buf.len = 0;
+      handle->read_cb((uv_stream_t*)handle, -1, buf);
+    }
+
+    /* Do non-blocking reads until the buffer is empty */
+    while (handle->flags & UV_HANDLE_READING) {
+      buf = handle->alloc_cb((uv_stream_t*)handle, 65536);
+      assert(buf.len > 0);
+
+      if (ReadFile(handle->handle,
+                   buf.base,
+                   buf.len,
+                   &bytes,
+                   NULL)) {
+        if (bytes > 0) {
+          /* Successful read */
+          handle->read_cb((uv_stream_t*)handle, bytes, buf);
+          /* Read again only if bytes == buf.len */
+          if (bytes < buf.len) {
+            break;
+          }
+        } else {
+          /* Connection closed */
+          handle->flags &= ~UV_HANDLE_READING;
+          handle->flags |= UV_HANDLE_EOF;
+          LOOP->last_error.code = UV_EOF;
+          LOOP->last_error.sys_errno_ = ERROR_SUCCESS;
+          handle->read_cb((uv_stream_t*)handle, -1, buf);
+          break;
+        }
+      } else {
+        err = GetLastError();
+        if (err == ERROR_NO_DATA) {
+          /* Read buffer was completely empty, report a 0-byte read. */
+          uv_set_sys_error(WSAEWOULDBLOCK);
+          handle->read_cb((uv_stream_t*)handle, 0, buf);
+        } else {
+          /* Ouch! serious error. */
+          uv_set_sys_error(err);
+          handle->read_cb((uv_stream_t*)handle, -1, buf);
+        }
+        break;
+      }
+    }
+
+    /* TODO: if the read callback stops reading we can't start reading again
+        because the pipe will still be in nowait mode. */
+    if ((handle->flags & UV_HANDLE_READING) &&
+        !(handle->flags & UV_HANDLE_READ_PENDING)) {
+      /* Switch back to blocking mode so that we can use IOCP for 0-reads */
+      mode = PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT;
+      if (SetNamedPipeHandleState(handle->handle, &mode, NULL, NULL)) {
+        /* Post another 0-read */
+        uv_pipe_queue_read(handle);
+      } else {
+        /* Report and continue. */
+        /* We can't continue processing this read. */
+        handle->flags &= ~UV_HANDLE_READING;
+        uv_set_sys_error(GetLastError());
+        buf.base = 0;
+        buf.len = 0;
+        handle->read_cb((uv_stream_t*)handle, -1, buf);
+      }
+    }
+  }
+
+  DECREASE_PENDING_REQ_COUNT(handle);
+}
+
+
+void uv_process_pipe_write_req(uv_pipe_t* handle, uv_write_t* req) {
+  assert(handle->type == UV_NAMED_PIPE);
+
+  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);
+  }
+
+  handle->write_reqs_pending--;
+  if (handle->write_reqs_pending == 0 &&
+      handle->flags & UV_HANDLE_SHUTTING) {
+    uv_want_endgame((uv_handle_t*)handle);
+  }
+
+  DECREASE_PENDING_REQ_COUNT(handle);
+}
+
+
+void uv_process_pipe_accept_req(uv_pipe_t* handle, uv_req_t* raw_req) {
+  uv_pipe_accept_t* req = (uv_pipe_accept_t*) raw_req;
+
+  assert(handle->type == UV_NAMED_PIPE);
+
+  if (req->error.code == UV_OK) {
+    assert(req->pipeHandle != INVALID_HANDLE_VALUE);
+
+    req->next_pending = handle->pending_accepts;
+    handle->pending_accepts = req;
+
+    if (handle->connection_cb) {
+      handle->connection_cb((uv_handle_t*)handle, 0);
+    }
+  } else {
+    if (req->pipeHandle != INVALID_HANDLE_VALUE) {
+      CloseHandle(req->pipeHandle);
+      req->pipeHandle = INVALID_HANDLE_VALUE;
+    }
+    if (!(handle->flags & UV_HANDLE_CLOSING)) {
+      uv_pipe_queue_accept(handle, req);
+    }
+  }
+
+  DECREASE_PENDING_REQ_COUNT(handle);
+}
+
+
+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) {
+      uv_connection_init((uv_stream_t*)handle);
+      ((uv_connect_cb)req->cb)(req, 0);
+    } else {
+      LOOP->last_error = req->error;
+      ((uv_connect_cb)req->cb)(req, -1);
+    }
+  }
+
+  DECREASE_PENDING_REQ_COUNT(handle);
+}
diff --git a/deps/uv/src/win/req.c b/deps/uv/src/win/req.c
new file mode 100644 (file)
index 0000000..627d7ec
--- /dev/null
@@ -0,0 +1,133 @@
+/* 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"
+
+
+void uv_req_init(uv_req_t* req) {
+  uv_counters()->req_init++;
+  req->type = UV_UNKNOWN_REQ;
+  req->error = uv_ok_;
+}
+
+
+uv_req_t* uv_overlapped_to_req(OVERLAPPED* overlapped) {
+  return CONTAINING_RECORD(overlapped, uv_req_t, overlapped);
+}
+
+
+void uv_insert_pending_req(uv_req_t* req) {
+  req->next_req = NULL;
+  if (LOOP->pending_reqs_tail) {
+    req->next_req = LOOP->pending_reqs_tail->next_req;
+    LOOP->pending_reqs_tail->next_req = req;
+    LOOP->pending_reqs_tail = req;
+  } else {
+    req->next_req = req;
+    LOOP->pending_reqs_tail = req;
+  }
+}
+
+
+static uv_req_t* uv_remove_pending_req() {
+  uv_req_t* req;
+
+  if (LOOP->pending_reqs_tail) {
+    req = LOOP->pending_reqs_tail->next_req;
+
+    if (req == LOOP->pending_reqs_tail) {
+      LOOP->pending_reqs_tail = NULL;
+    } else {
+      LOOP->pending_reqs_tail->next_req = req->next_req;
+    }
+
+    return req;
+
+  } else {
+    /* queue empty */
+    return NULL;
+  }
+}
+
+
+#define DELEGATE_STREAM_REQ(req, method, handle_at)                           \
+  do {                                                                        \
+    switch (((uv_handle_t*) (req)->handle_at)->type) {                        \
+      case UV_TCP:                                                            \
+        uv_process_tcp_##method##_req((uv_tcp_t*) ((req)->handle_at), req);   \
+        break;                                                                \
+                                                                              \
+      case UV_NAMED_PIPE:                                                     \
+        uv_process_pipe_##method##_req((uv_pipe_t*) ((req)->handle_at), req); \
+        break;                                                                \
+                                                                              \
+      default:                                                                \
+        assert(0);                                                            \
+    }                                                                         \
+  } while (0)
+
+
+void uv_process_reqs() {
+  uv_req_t* req;
+
+  while (req = uv_remove_pending_req()) {
+    switch (req->type) {
+      case UV_READ:
+        DELEGATE_STREAM_REQ(req, read, data);
+        break;
+
+      case UV_WRITE:
+        DELEGATE_STREAM_REQ((uv_write_t*) req, write, handle);
+        break;
+
+      case UV_ACCEPT:
+        DELEGATE_STREAM_REQ(req, accept, data);
+        break;
+
+      case UV_CONNECT:
+        DELEGATE_STREAM_REQ((uv_connect_t*) req, connect, handle);
+        break;
+
+      case UV_WAKEUP:
+        uv_process_async_wakeup_req((uv_async_t*) req->data, req);
+        break;
+
+      case UV_ARES_EVENT_REQ:
+        uv_process_ares_event_req((uv_ares_action_t*) req->data, req);
+        break;
+
+      case UV_ARES_CLEANUP_REQ:
+        uv_process_ares_cleanup_req((uv_ares_task_t*) req->data, req);
+        break;
+
+      case UV_GETADDRINFO_REQ:
+        uv_process_getaddrinfo_req((uv_getaddrinfo_t*) req->data, req);
+        break;
+
+      default:
+        assert(0);
+    }
+  }
+}
diff --git a/deps/uv/src/win/stream.c b/deps/uv/src/win/stream.c
new file mode 100644 (file)
index 0000000..acd67a0
--- /dev/null
@@ -0,0 +1,130 @@
+/* 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"
+
+
+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++;
+
+  uv_ref();
+}
+
+
+void uv_connection_init(uv_stream_t* handle) {
+  handle->flags |= UV_HANDLE_CONNECTION;
+  handle->write_reqs_pending = 0;
+
+  uv_req_init((uv_req_t*) &(handle->read_req));
+  handle->read_req.type = UV_READ;
+  handle->read_req.data = handle;
+}
+
+
+int uv_accept(uv_handle_t* server, uv_stream_t* client) {
+  assert(client->type == server->type);
+
+  if (server->type == UV_TCP) {
+    return uv_tcp_accept((uv_tcp_t*)server, (uv_tcp_t*)client);
+  } else if (server->type == UV_NAMED_PIPE) {
+    return uv_pipe_accept((uv_pipe_t*)server, (uv_pipe_t*)client);
+  }
+
+  return -1;
+}
+
+
+int uv_read_start(uv_stream_t* handle, uv_alloc_cb alloc_cb, uv_read_cb read_cb) {
+  if (handle->type == UV_TCP) {
+    return uv_tcp_read_start((uv_tcp_t*)handle, alloc_cb, read_cb);
+  } else if (handle->type == UV_NAMED_PIPE) {
+    return uv_pipe_read_start((uv_pipe_t*)handle, alloc_cb, read_cb);
+  }
+
+  return -1;
+}
+
+
+int uv_read_stop(uv_stream_t* handle) {
+  handle->flags &= ~UV_HANDLE_READING;
+
+  return 0;
+}
+
+
+int uv_write(uv_write_t* req, uv_stream_t* handle, uv_buf_t bufs[], int bufcnt,
+    uv_write_cb cb) {
+  if (handle->type == UV_TCP) {
+    return uv_tcp_write(req, (uv_tcp_t*) handle, bufs, bufcnt, cb);
+  } else if (handle->type == UV_NAMED_PIPE) {
+    return uv_pipe_write(req, (uv_pipe_t*) handle, bufs, bufcnt, cb);
+  }
+
+  uv_set_sys_error(WSAEINVAL);
+  return -1;
+}
+
+
+int uv_shutdown(uv_shutdown_t* req, uv_stream_t* handle, uv_shutdown_cb cb) {
+  if (!(handle->flags & UV_HANDLE_CONNECTION)) {
+    uv_set_sys_error(WSAEINVAL);
+    return -1;
+  }
+
+  if (handle->flags & UV_HANDLE_SHUTTING) {
+    uv_set_sys_error(WSAESHUTDOWN);
+    return -1;
+  }
+
+  uv_req_init((uv_req_t*) req);
+  req->type = UV_SHUTDOWN;
+  req->handle = handle;
+  req->cb = cb;
+
+  handle->flags |= UV_HANDLE_SHUTTING;
+  handle->shutdown_req = req;
+  handle->reqs_pending++;
+
+  uv_want_endgame((uv_handle_t*)handle);
+
+  return 0;
+}
+
+
+size_t uv_count_bufs(uv_buf_t bufs[], int count) {
+  size_t bytes = 0;
+  int i;
+
+  for (i = 0; i < count; i++) {
+    bytes += (size_t)bufs[i].len;
+  }
+
+  return bytes;
+}
diff --git a/deps/uv/src/win/tcp.c b/deps/uv/src/win/tcp.c
new file mode 100644 (file)
index 0000000..ace5353
--- /dev/null
@@ -0,0 +1,895 @@
+/* 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"
+
+/*
+ * Guids and typedefs for winsock extension functions
+ * Mingw32 doesn't have these :-(
+ */
+#ifndef WSAID_ACCEPTEX
+# define WSAID_ACCEPTEX                                        \
+         {0xb5367df1, 0xcbac, 0x11cf,                          \
+         {0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}}
+
+# define WSAID_CONNECTEX                                       \
+         {0x25a207b9, 0xddf3, 0x4660,                          \
+         {0x8e, 0xe9, 0x76, 0xe5, 0x8c, 0x74, 0x06, 0x3e}}
+
+# define WSAID_GETACCEPTEXSOCKADDRS                            \
+         {0xb5367df2, 0xcbac, 0x11cf,                          \
+         {0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}}
+
+# define WSAID_DISCONNECTEX                                    \
+         {0x7fda2e11, 0x8630, 0x436f,                          \
+         {0xa0, 0x31, 0xf5, 0x36, 0xa6, 0xee, 0xc1, 0x57}}
+
+# define WSAID_TRANSMITFILE                                    \
+         {0xb5367df0, 0xcbac, 0x11cf,                          \
+         {0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}}
+
+  typedef BOOL PASCAL (*LPFN_ACCEPTEX)
+                      (SOCKET sListenSocket,
+                       SOCKET sAcceptSocket,
+                       PVOID lpOutputBuffer,
+                       DWORD dwReceiveDataLength,
+                       DWORD dwLocalAddressLength,
+                       DWORD dwRemoteAddressLength,
+                       LPDWORD lpdwBytesReceived,
+                       LPOVERLAPPED lpOverlapped);
+
+  typedef BOOL PASCAL (*LPFN_CONNECTEX)
+                      (SOCKET s,
+                       const struct sockaddr* name,
+                       int namelen,
+                       PVOID lpSendBuffer,
+                       DWORD dwSendDataLength,
+                       LPDWORD lpdwBytesSent,
+                       LPOVERLAPPED lpOverlapped);
+
+  typedef void PASCAL (*LPFN_GETACCEPTEXSOCKADDRS)
+                      (PVOID lpOutputBuffer,
+                       DWORD dwReceiveDataLength,
+                       DWORD dwLocalAddressLength,
+                       DWORD dwRemoteAddressLength,
+                       LPSOCKADDR* LocalSockaddr,
+                       LPINT LocalSockaddrLength,
+                       LPSOCKADDR* RemoteSockaddr,
+                       LPINT RemoteSockaddrLength);
+
+  typedef BOOL PASCAL (*LPFN_DISCONNECTEX)
+                      (SOCKET hSocket,
+                       LPOVERLAPPED lpOverlapped,
+                       DWORD dwFlags,
+                       DWORD reserved);
+
+  typedef BOOL PASCAL (*LPFN_TRANSMITFILE)
+                      (SOCKET hSocket,
+                       HANDLE hFile,
+                       DWORD nNumberOfBytesToWrite,
+                       DWORD nNumberOfBytesPerSend,
+                       LPOVERLAPPED lpOverlapped,
+                       LPTRANSMIT_FILE_BUFFERS lpTransmitBuffers,
+                       DWORD dwFlags);
+#endif
+
+/*
+ * MinGW is missing this too
+ */
+#ifndef SO_UPDATE_CONNECT_CONTEXT
+# define SO_UPDATE_CONNECT_CONTEXT   0x7010
+#endif
+
+
+/* Pointers to winsock extension functions to be retrieved dynamically */
+static LPFN_CONNECTEX               pConnectEx;
+static LPFN_ACCEPTEX                pAcceptEx;
+static LPFN_GETACCEPTEXSOCKADDRS    pGetAcceptExSockAddrs;
+static LPFN_DISCONNECTEX            pDisconnectEx;
+static LPFN_TRANSMITFILE            pTransmitFile;
+
+/* IPv6 version of these extension functions */
+static LPFN_CONNECTEX               pConnectEx6;
+static LPFN_ACCEPTEX                pAcceptEx6;
+static LPFN_GETACCEPTEXSOCKADDRS    pGetAcceptExSockAddrs6;
+static LPFN_DISCONNECTEX            pDisconnectEx6;
+static LPFN_TRANSMITFILE            pTransmitFile6;
+
+/* Ip address used to bind to any port at any interface */
+static struct sockaddr_in uv_addr_ip4_any_;
+static struct sockaddr_in6 uv_addr_ip6_any_;
+
+/* A zero-size buffer for use by uv_tcp_read */
+static char uv_zero_[] = "";
+
+/* mark if IPv6 sockets are supported */
+static BOOL uv_allow_ipv6 = FALSE;
+
+
+/*
+ * Retrieves the pointer to a winsock extension function.
+ */
+static BOOL uv_get_extension_function(SOCKET socket, GUID guid,
+    void **target) {
+  DWORD result, bytes;
+
+  result = WSAIoctl(socket,
+                    SIO_GET_EXTENSION_FUNCTION_POINTER,
+                    &guid,
+                    sizeof(guid),
+                    (void*)target,
+                    sizeof(*target),
+                    &bytes,
+                    NULL,
+                    NULL);
+
+  if (result == SOCKET_ERROR) {
+    *target = NULL;
+    return FALSE;
+  } else {
+    return TRUE;
+  }
+}
+
+
+/*
+ * Setup tcp subsystem
+ */
+void uv_winsock_startup() {
+  const GUID wsaid_connectex            = WSAID_CONNECTEX;
+  const GUID wsaid_acceptex             = WSAID_ACCEPTEX;
+  const GUID wsaid_getacceptexsockaddrs = WSAID_GETACCEPTEXSOCKADDRS;
+  const GUID wsaid_disconnectex         = WSAID_DISCONNECTEX;
+  const GUID wsaid_transmitfile         = WSAID_TRANSMITFILE;
+
+  WSADATA wsa_data;
+  int errorno;
+  SOCKET dummy;
+  SOCKET dummy6;
+
+  /* Initialize winsock */
+  errorno = WSAStartup(MAKEWORD(2, 2), &wsa_data);
+  if (errorno != 0) {
+    uv_fatal_error(errorno, "WSAStartup");
+  }
+
+  /* Set implicit binding address used by connectEx */
+  uv_addr_ip4_any_ = uv_ip4_addr("0.0.0.0", 0);
+  uv_addr_ip6_any_ = uv_ip6_addr("::1", 0);
+
+  /* Retrieve the needed winsock extension function pointers. */
+  dummy = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
+  if (dummy == INVALID_SOCKET) {
+    uv_fatal_error(WSAGetLastError(), "socket");
+  }
+
+  if (!uv_get_extension_function(dummy,
+                            wsaid_connectex,
+                            (void**)&pConnectEx) ||
+      !uv_get_extension_function(dummy,
+                            wsaid_acceptex,
+                            (void**)&pAcceptEx) ||
+      !uv_get_extension_function(dummy,
+                            wsaid_getacceptexsockaddrs,
+                            (void**)&pGetAcceptExSockAddrs) ||
+      !uv_get_extension_function(dummy,
+                            wsaid_disconnectex,
+                            (void**)&pDisconnectEx) ||
+      !uv_get_extension_function(dummy,
+                            wsaid_transmitfile,
+                            (void**)&pTransmitFile)) {
+    uv_fatal_error(WSAGetLastError(),
+                   "WSAIoctl(SIO_GET_EXTENSION_FUNCTION_POINTER)");
+  }
+
+  if (closesocket(dummy) == SOCKET_ERROR) {
+    uv_fatal_error(WSAGetLastError(), "closesocket");
+  }
+
+  /* optional IPv6 versions of winsock extension functions */
+  dummy6 = socket(AF_INET6, SOCK_STREAM, IPPROTO_IP);
+  if (dummy6 != INVALID_SOCKET) {
+    uv_allow_ipv6 = TRUE;
+
+    if (!uv_get_extension_function(dummy6,
+                              wsaid_connectex,
+                              (void**)&pConnectEx6) ||
+        !uv_get_extension_function(dummy6,
+                              wsaid_acceptex,
+                              (void**)&pAcceptEx6) ||
+        !uv_get_extension_function(dummy6,
+                              wsaid_getacceptexsockaddrs,
+                              (void**)&pGetAcceptExSockAddrs6) ||
+        !uv_get_extension_function(dummy6,
+                              wsaid_disconnectex,
+                              (void**)&pDisconnectEx6) ||
+        !uv_get_extension_function(dummy6,
+                              wsaid_transmitfile,
+                              (void**)&pTransmitFile6)) {
+      uv_allow_ipv6 = FALSE;
+    }
+
+    if (closesocket(dummy6) == SOCKET_ERROR) {
+      uv_fatal_error(WSAGetLastError(), "closesocket");
+    }
+  }
+}
+
+
+static int uv_tcp_set_socket(uv_tcp_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;
+  }
+
+  handle->socket = socket;
+
+  return 0;
+}
+
+
+int uv_tcp_init(uv_tcp_t* handle) {
+  uv_stream_init((uv_stream_t*)handle);
+
+  handle->socket = INVALID_SOCKET;
+  handle->type = UV_TCP;
+  handle->reqs_pending = 0;
+  handle->accept_socket = INVALID_SOCKET;
+
+  uv_counters()->tcp_init++;
+
+  return 0;
+}
+
+
+void uv_tcp_endgame(uv_tcp_t* handle) {
+  uv_err_t err;
+  int status;
+
+  if (handle->flags & UV_HANDLE_SHUTTING &&
+      !(handle->flags & UV_HANDLE_SHUT) &&
+      handle->write_reqs_pending == 0) {
+
+    if (shutdown(handle->socket, SD_SEND) != SOCKET_ERROR) {
+      status = 0;
+      handle->flags |= UV_HANDLE_SHUT;
+    } else {
+      status = -1;
+      err = uv_new_sys_error(WSAGetLastError());
+    }
+    if (handle->shutdown_req->cb) {
+      if (status == -1) {
+        LOOP->last_error = err;
+      }
+      handle->shutdown_req->cb(handle->shutdown_req, status);
+    }
+    handle->reqs_pending--;
+  }
+
+  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_tcp_t* handle, int domain, struct sockaddr* addr, int addrsize) {
+  DWORD err;
+  int r;
+  SOCKET sock;
+
+  if (handle->socket == INVALID_SOCKET) {
+    sock = socket(domain, SOCK_STREAM, 0);
+    if (sock == INVALID_SOCKET) {
+      uv_set_sys_error(WSAGetLastError());
+      return -1;
+    }
+
+    if (uv_tcp_set_socket(handle, sock) == -1) {
+      closesocket(sock);
+      return -1;
+    }
+  }
+
+  r = bind(handle->socket, addr, addrsize);
+
+  if (r == SOCKET_ERROR) {
+    err = WSAGetLastError();
+    if (err == WSAEADDRINUSE) {
+      /* Some errors are not to be reported until connect() or listen() */
+      handle->error = uv_new_sys_error(err);
+      handle->flags |= UV_HANDLE_BIND_ERROR;
+    } else {
+      uv_set_sys_error(err);
+      return -1;
+    }
+  }
+
+  handle->flags |= UV_HANDLE_BOUND;
+
+  return 0;
+}
+
+
+int uv_tcp_bind(uv_tcp_t* handle, struct sockaddr_in addr) {
+  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));
+}
+
+
+int uv_tcp_bind6(uv_tcp_t* handle, struct sockaddr_in6 addr) {
+  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));
+  } else {
+    uv_new_sys_error(UV_EAFNOSUPPORT);
+    return -1;
+  }
+}
+
+
+static void uv_tcp_queue_accept(uv_tcp_t* handle) {
+  uv_req_t* req;
+  BOOL success;
+  DWORD bytes;
+  SOCKET accept_socket;
+  short family;
+  LPFN_ACCEPTEX pAcceptExFamily;
+
+  assert(handle->flags & UV_HANDLE_LISTENING);
+  assert(handle->accept_socket == INVALID_SOCKET);
+
+  /* Prepare the uv_req structure. */
+  req = &handle->accept_req;
+
+  /* choose family and extension function */
+  if ((handle->flags & UV_HANDLE_IPV6) != 0) {
+    family = AF_INET6;
+    pAcceptExFamily = pAcceptEx6;
+  } else {
+    family = AF_INET;
+    pAcceptExFamily = pAcceptEx;
+  }
+
+  /* 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());
+    uv_insert_pending_req(req);
+    handle->reqs_pending++;
+    return;
+  }
+
+  /* Prepare the overlapped structure. */
+  memset(&(req->overlapped), 0, sizeof(req->overlapped));
+
+  success = pAcceptExFamily(handle->socket,
+                          accept_socket,
+                          (void*)&handle->accept_buffer,
+                          0,
+                          sizeof(struct sockaddr_storage),
+                          sizeof(struct sockaddr_storage),
+                          &bytes,
+                          &req->overlapped);
+
+  if (!success && WSAGetLastError() != ERROR_IO_PENDING) {
+    /* Make this req pending reporting an error. */
+    req->error = uv_new_sys_error(WSAGetLastError());
+    uv_insert_pending_req(req);
+    handle->reqs_pending++;
+    /* Destroy the preallocated client socket. */
+    closesocket(accept_socket);
+    return;
+  }
+
+  handle->accept_socket = accept_socket;
+
+  handle->reqs_pending++;
+}
+
+
+static void uv_tcp_queue_read(uv_tcp_t* handle) {
+  uv_req_t* req;
+  uv_buf_t buf;
+  int result;
+  DWORD bytes, flags;
+
+  assert(handle->flags & UV_HANDLE_READING);
+  assert(!(handle->flags & UV_HANDLE_READ_PENDING));
+
+  req = &handle->read_req;
+  memset(&req->overlapped, 0, sizeof(req->overlapped));
+
+  buf.base = (char*) &uv_zero_;
+  buf.len = 0;
+
+  flags = 0;
+  result = WSARecv(handle->socket,
+                   (WSABUF*)&buf,
+                   1,
+                   &bytes,
+                   &flags,
+                   &req->overlapped,
+                   NULL);
+  if (result != 0 && WSAGetLastError() != ERROR_IO_PENDING) {
+    /* Make this req pending reporting an error. */
+    req->error = uv_new_sys_error(WSAGetLastError());
+    uv_insert_pending_req(req);
+    handle->reqs_pending++;
+    return;
+  }
+
+  handle->flags |= UV_HANDLE_READ_PENDING;
+  handle->reqs_pending++;
+}
+
+
+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;
+    return -1;
+  }
+
+  if (handle->flags & UV_HANDLE_LISTENING ||
+      handle->flags & UV_HANDLE_READING) {
+    /* Already listening. */
+    uv_set_sys_error(WSAEALREADY);
+    return -1;
+  }
+
+  if (!(handle->flags & UV_HANDLE_BOUND) &&
+      uv_tcp_bind(handle, uv_addr_ip4_any_) < 0)
+    return -1;
+
+  if (listen(handle->socket, backlog) == SOCKET_ERROR) {
+    uv_set_sys_error(WSAGetLastError());
+    return -1;
+  }
+
+  handle->flags |= UV_HANDLE_LISTENING;
+  handle->connection_cb = cb;
+
+  uv_req_init(&(handle->accept_req));
+  handle->accept_req.type = UV_ACCEPT;
+  handle->accept_req.data = handle;
+  uv_tcp_queue_accept(handle);
+
+  return 0;
+}
+
+
+int uv_tcp_accept(uv_tcp_t* server, uv_tcp_t* client) {
+  int rv = 0;
+
+  if (server->accept_socket == INVALID_SOCKET) {
+    uv_set_sys_error(WSAENOTCONN);
+    return -1;
+  }
+
+  if (uv_tcp_set_socket(client, server->accept_socket) == -1) {
+    closesocket(server->accept_socket);
+    rv = -1;
+  } else {
+    uv_connection_init((uv_stream_t*)client);
+  }
+
+  server->accept_socket = INVALID_SOCKET;
+
+  if (!(server->flags & UV_HANDLE_CLOSING)) {
+    uv_tcp_queue_accept(server);
+  }
+
+  return rv;
+}
+
+
+int uv_tcp_read_start(uv_tcp_t* handle, uv_alloc_cb alloc_cb, uv_read_cb read_cb) {
+  if (!(handle->flags & UV_HANDLE_CONNECTION)) {
+    uv_set_sys_error(WSAEINVAL);
+    return -1;
+  }
+
+  if (handle->flags & UV_HANDLE_READING) {
+    uv_set_sys_error(WSAEALREADY);
+    return -1;
+  }
+
+  if (handle->flags & UV_HANDLE_EOF) {
+    uv_set_sys_error(WSAESHUTDOWN);
+    return -1;
+  }
+
+  handle->flags |= UV_HANDLE_READING;
+  handle->read_cb = read_cb;
+  handle->alloc_cb = alloc_cb;
+
+  /* If reading was stopped and then started again, there could stell be a */
+  /* read request pending. */
+  if (!(handle->flags & UV_HANDLE_READ_PENDING))
+    uv_tcp_queue_read(handle);
+
+  return 0;
+}
+
+
+int uv_tcp_connect(uv_connect_t* req, uv_tcp_t* handle,
+    struct sockaddr_in address, uv_connect_cb cb) {
+  int addrsize = sizeof(struct sockaddr_in);
+  BOOL success;
+  DWORD bytes;
+
+  if (handle->flags & UV_HANDLE_BIND_ERROR) {
+    LOOP->last_error = handle->error;
+    return -1;
+  }
+
+  if (address.sin_family != AF_INET) {
+    uv_set_sys_error(WSAEFAULT);
+    return -1;
+  }
+
+  if (!(handle->flags & UV_HANDLE_BOUND) &&
+      uv_tcp_bind(handle, uv_addr_ip4_any_) < 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 = pConnectEx(handle->socket,
+                       (struct sockaddr*) &address,
+                       addrsize,
+                       NULL,
+                       0,
+                       &bytes,
+                       &req->overlapped);
+
+  if (!success && WSAGetLastError() != ERROR_IO_PENDING) {
+    uv_set_sys_error(WSAGetLastError());
+    return -1;
+  }
+
+  handle->reqs_pending++;
+
+  return 0;
+}
+
+
+int uv_tcp_connect6(uv_connect_t* req, uv_tcp_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(UV_EAFNOSUPPORT);
+    return -1;
+  }
+
+  if (handle->flags & UV_HANDLE_BIND_ERROR) {
+    LOOP->last_error = handle->error;
+    return -1;
+  }
+
+  if (address.sin6_family != AF_INET6) {
+    uv_set_sys_error(WSAEFAULT);
+    return -1;
+  }
+
+  if (!(handle->flags & UV_HANDLE_BOUND) &&
+      uv_tcp_bind6(handle, uv_addr_ip6_any_) < 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 (!success && WSAGetLastError() != ERROR_IO_PENDING) {
+    uv_set_sys_error(WSAGetLastError());
+    return -1;
+  }
+
+  handle->reqs_pending++;
+
+  return 0;
+}
+
+
+int uv_getsockname(uv_tcp_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;
+}
+
+
+int uv_tcp_write(uv_write_t* req, uv_tcp_t* handle, uv_buf_t bufs[], int bufcnt,
+    uv_write_cb cb) {
+  int result;
+  DWORD bytes, err;
+
+  if (!(handle->flags & UV_HANDLE_CONNECTION)) {
+    uv_set_sys_error(WSAEINVAL);
+    return -1;
+  }
+
+  if (handle->flags & UV_HANDLE_SHUTTING) {
+    uv_set_sys_error(WSAESHUTDOWN);
+    return -1;
+  }
+
+  uv_req_init((uv_req_t*) req);
+  req->type = UV_WRITE;
+  req->handle = (uv_stream_t*) handle;
+  req->cb = cb;
+  memset(&req->overlapped, 0, sizeof(req->overlapped));
+
+  result = WSASend(handle->socket,
+                   (WSABUF*)bufs,
+                   bufcnt,
+                   &bytes,
+                   0,
+                   &req->overlapped,
+                   NULL);
+  if (result != 0) {
+    err = WSAGetLastError();
+    if (err != WSA_IO_PENDING) {
+      /* Send failed due to an error. */
+      uv_set_sys_error(WSAGetLastError());
+      return -1;
+    }
+  }
+
+  if (result == 0) {
+    /* Request completed immediately. */
+    req->queued_bytes = 0;
+  } else {
+    /* Request queued by the kernel. */
+    req->queued_bytes = uv_count_bufs(bufs, bufcnt);
+    handle->write_queue_size += req->queued_bytes;
+  }
+
+  handle->reqs_pending++;
+  handle->write_reqs_pending++;
+
+  return 0;
+}
+
+
+void uv_process_tcp_read_req(uv_tcp_t* handle, uv_req_t* req) {
+  DWORD bytes, flags, err;
+  uv_buf_t buf;
+
+  assert(handle->type == UV_TCP);
+
+  handle->flags &= ~UV_HANDLE_READ_PENDING;
+
+  if (req->error.code != UV_OK) {
+    /* An error occurred doing the 0-read. */
+    if ((handle->flags & UV_HANDLE_READING)) {
+      handle->flags &= ~UV_HANDLE_READING;
+      LOOP->last_error = req->error;
+      buf.base = 0;
+      buf.len = 0;
+      handle->read_cb((uv_stream_t*)handle, -1, buf);
+    }
+  } else {
+    /* Do nonblocking reads until the buffer is empty */
+    while (handle->flags & UV_HANDLE_READING) {
+      buf = handle->alloc_cb((uv_stream_t*)handle, 65536);
+      assert(buf.len > 0);
+      flags = 0;
+      if (WSARecv(handle->socket,
+                  (WSABUF*)&buf,
+                  1,
+                  &bytes,
+                  &flags,
+                  NULL,
+                  NULL) != SOCKET_ERROR) {
+        if (bytes > 0) {
+          /* Successful read */
+          handle->read_cb((uv_stream_t*)handle, bytes, buf);
+          /* Read again only if bytes == buf.len */
+          if (bytes < buf.len) {
+            break;
+          }
+        } else {
+          /* Connection closed */
+          handle->flags &= ~UV_HANDLE_READING;
+          handle->flags |= UV_HANDLE_EOF;
+          LOOP->last_error.code = UV_EOF;
+          LOOP->last_error.sys_errno_ = ERROR_SUCCESS;
+          handle->read_cb((uv_stream_t*)handle, -1, buf);
+          break;
+        }
+      } else {
+        err = WSAGetLastError();
+        if (err == WSAEWOULDBLOCK) {
+          /* Read buffer was completely empty, report a 0-byte read. */
+          uv_set_sys_error(WSAEWOULDBLOCK);
+          handle->read_cb((uv_stream_t*)handle, 0, buf);
+        } else {
+          /* Ouch! serious error. */
+          uv_set_sys_error(err);
+          handle->read_cb((uv_stream_t*)handle, -1, buf);
+        }
+        break;
+      }
+    }
+
+    /* Post another 0-read if still reading and not closing. */
+    if ((handle->flags & UV_HANDLE_READING) &&
+        !(handle->flags & UV_HANDLE_READ_PENDING)) {
+      uv_tcp_queue_read(handle);
+    }
+  }
+
+  DECREASE_PENDING_REQ_COUNT(handle);
+}
+
+
+void uv_process_tcp_write_req(uv_tcp_t* handle, uv_write_t* req) {
+  assert(handle->type == UV_TCP);
+
+  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);
+  }
+
+  handle->write_reqs_pending--;
+  if (handle->flags & UV_HANDLE_SHUTTING &&
+      handle->write_reqs_pending == 0) {
+    uv_want_endgame((uv_handle_t*)handle);
+  }
+
+  DECREASE_PENDING_REQ_COUNT(handle);
+}
+
+
+void uv_process_tcp_accept_req(uv_tcp_t* handle, uv_req_t* req) {
+  assert(handle->type == UV_TCP);
+
+  /* If handle->accepted_socket is not a valid socket, then */
+  /* uv_queue_accept must have failed. This is a serious error. We stop */
+  /* accepting connections and report this error to the connection */
+  /* callback. */
+  if (handle->accept_socket == INVALID_SOCKET) {
+    if (handle->flags & UV_HANDLE_LISTENING) {
+      handle->flags &= ~UV_HANDLE_LISTENING;
+      if (handle->connection_cb) {
+        LOOP->last_error = req->error;
+        handle->connection_cb((uv_handle_t*)handle, -1);
+      }
+    }
+  } else if (req->error.code == UV_OK &&
+      setsockopt(handle->accept_socket,
+                  SOL_SOCKET,
+                  SO_UPDATE_ACCEPT_CONTEXT,
+                  (char*)&handle->socket,
+                  sizeof(handle->socket)) == 0) {
+    /* Accept and SO_UPDATE_ACCEPT_CONTEXT were successful. */
+    if (handle->connection_cb) {
+      handle->connection_cb((uv_handle_t*)handle, 0);
+    }
+  } else {
+    /* Error related to accepted socket is ignored because the server */
+    /* socket may still be healthy. If the server socket is broken
+    /* uv_queue_accept will detect it. */
+    closesocket(handle->accept_socket);
+    if (handle->flags & UV_HANDLE_LISTENING) {
+      uv_tcp_queue_accept(handle);
+    }
+  }
+
+  DECREASE_PENDING_REQ_COUNT(handle);
+}
+
+
+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 (setsockopt(handle->socket,
+                      SOL_SOCKET,
+                      SO_UPDATE_CONNECT_CONTEXT,
+                      NULL,
+                      0) == 0) {
+        uv_connection_init((uv_stream_t*)handle);
+        ((uv_connect_cb)req->cb)(req, 0);
+      } else {
+        uv_set_sys_error(WSAGetLastError());
+        ((uv_connect_cb)req->cb)(req, -1);
+      }
+    } else {
+      LOOP->last_error = req->error;
+      ((uv_connect_cb)req->cb)(req, -1);
+    }
+  }
+
+  DECREASE_PENDING_REQ_COUNT(handle);
+}
diff --git a/deps/uv/src/win/timer.c b/deps/uv/src/win/timer.c
new file mode 100644 (file)
index 0000000..6f74a2c
--- /dev/null
@@ -0,0 +1,232 @@
+/* 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 <limits.h>
+
+#include "uv.h"
+#include "internal.h"
+#include "tree.h"
+
+
+/* The resolution of the high-resolution clock. */
+static int64_t uv_ticks_per_msec_ = 0;
+
+
+
+void uv_update_time() {
+  LARGE_INTEGER counter;
+
+  if (!QueryPerformanceCounter(&counter))
+    uv_fatal_error(GetLastError(), "QueryPerformanceCounter");
+
+  LOOP->time = counter.QuadPart / uv_ticks_per_msec_;
+}
+
+
+int64_t uv_now() {
+  return LOOP->time;
+}
+
+
+uint64_t uv_hrtime(void) {
+  assert(0 && "implement me");
+  return 0;
+}
+
+
+void uv_timer_startup() {
+  LARGE_INTEGER timer_frequency;
+
+  /* Initialize the event loop time */
+  if (!QueryPerformanceFrequency(&timer_frequency))
+    uv_fatal_error(GetLastError(), "QueryPerformanceFrequency");
+  uv_ticks_per_msec_ = timer_frequency.QuadPart / 1000;
+}
+
+
+static int uv_timer_compare(uv_timer_t* a, uv_timer_t* b) {
+  if (a->due < b->due)
+    return -1;
+  if (a->due > b->due)
+    return 1;
+  if ((intptr_t)a < (intptr_t)b)
+    return -1;
+  if ((intptr_t)a > (intptr_t)b)
+    return 1;
+  return 0;
+}
+
+
+RB_GENERATE_STATIC(uv_timer_tree_s, uv_timer_s, tree_entry, uv_timer_compare);
+
+
+int uv_timer_init(uv_timer_t* handle) {
+  uv_counters()->handle_init++;
+  uv_counters()->timer_init++;
+
+  handle->type = UV_TIMER;
+  handle->flags = 0;
+  handle->error = uv_ok_;
+  handle->timer_cb = NULL;
+  handle->repeat = 0;
+
+  uv_ref();
+
+  return 0;
+}
+
+
+void uv_timer_endgame(uv_timer_t* handle) {
+  if (handle->flags & UV_HANDLE_CLOSING) {
+    assert(!(handle->flags & UV_HANDLE_CLOSED));
+    handle->flags |= UV_HANDLE_CLOSED;
+
+    if (handle->close_cb) {
+      handle->close_cb((uv_handle_t*)handle);
+    }
+
+    uv_unref();
+  }
+}
+
+
+int uv_timer_start(uv_timer_t* handle, uv_timer_cb timer_cb, int64_t timeout, int64_t repeat) {
+  if (handle->flags & UV_HANDLE_ACTIVE) {
+    RB_REMOVE(uv_timer_tree_s, &LOOP->timers, handle);
+  }
+
+  handle->timer_cb = timer_cb;
+  handle->due = LOOP->time + timeout;
+  handle->repeat = repeat;
+  handle->flags |= UV_HANDLE_ACTIVE;
+
+  if (RB_INSERT(uv_timer_tree_s, &LOOP->timers, handle) != NULL) {
+    uv_fatal_error(ERROR_INVALID_DATA, "RB_INSERT");
+  }
+
+  return 0;
+}
+
+
+int uv_timer_stop(uv_timer_t* handle) {
+  if (!(handle->flags & UV_HANDLE_ACTIVE))
+    return 0;
+
+  RB_REMOVE(uv_timer_tree_s, &LOOP->timers, handle);
+
+  handle->flags &= ~UV_HANDLE_ACTIVE;
+
+  return 0;
+}
+
+
+int uv_timer_again(uv_timer_t* handle) {
+  /* If timer_cb is NULL that means that the timer was never started. */
+  if (!handle->timer_cb) {
+    uv_set_sys_error(ERROR_INVALID_DATA);
+    return -1;
+  }
+
+  if (handle->flags & UV_HANDLE_ACTIVE) {
+    RB_REMOVE(uv_timer_tree_s, &LOOP->timers, handle);
+    handle->flags &= ~UV_HANDLE_ACTIVE;
+  }
+
+  if (handle->repeat) {
+    handle->due = LOOP->time + handle->repeat;
+
+    if (RB_INSERT(uv_timer_tree_s, &LOOP->timers, handle) != NULL) {
+      uv_fatal_error(ERROR_INVALID_DATA, "RB_INSERT");
+    }
+
+    handle->flags |= UV_HANDLE_ACTIVE;
+  }
+
+  return 0;
+}
+
+
+void uv_timer_set_repeat(uv_timer_t* handle, int64_t repeat) {
+  assert(handle->type == UV_TIMER);
+  handle->repeat = repeat;
+}
+
+
+int64_t uv_timer_get_repeat(uv_timer_t* handle) {
+  assert(handle->type == UV_TIMER);
+  return handle->repeat;
+}
+
+
+DWORD uv_get_poll_timeout() {
+  uv_timer_t* timer;
+  int64_t delta;
+
+  /* Check if there are any running timers */
+  timer = RB_MIN(uv_timer_tree_s, &LOOP->timers);
+  if (timer) {
+    uv_update_time();
+
+    delta = timer->due - LOOP->time;
+    if (delta >= UINT_MAX) {
+      /* Can't have a timeout greater than UINT_MAX, and a timeout value of */
+      /* UINT_MAX means infinite, so that's no good either. */
+      return UINT_MAX - 1;
+    } else if (delta < 0) {
+      /* Negative timeout values are not allowed */
+      return 0;
+    } else {
+      return (DWORD)delta;
+    }
+  } else {
+    /* No timers */
+    return INFINITE;
+  }
+}
+
+
+void uv_process_timers() {
+  uv_timer_t* timer;
+
+  /* Call timer callbacks */
+  for (timer = RB_MIN(uv_timer_tree_s, &LOOP->timers);
+       timer != NULL && timer->due <= LOOP->time;
+       timer = RB_MIN(uv_timer_tree_s, &LOOP->timers)) {
+    RB_REMOVE(uv_timer_tree_s, &LOOP->timers, timer);
+
+    if (timer->repeat != 0) {
+      /* If it is a repeating timer, reschedule with repeat timeout. */
+      timer->due += timer->repeat;
+      if (timer->due < LOOP->time) {
+        timer->due = LOOP->time;
+      }
+      if (RB_INSERT(uv_timer_tree_s, &LOOP->timers, timer) != NULL) {
+        uv_fatal_error(ERROR_INVALID_DATA, "RB_INSERT");
+      }
+    } else {
+      /* If non-repeating, mark the timer as inactive. */
+      timer->flags &= ~UV_HANDLE_ACTIVE;
+    }
+
+    timer->timer_cb((uv_timer_t*) timer, 0);
+  }
+}
diff --git a/deps/uv/src/win/util.c b/deps/uv/src/win/util.c
new file mode 100644 (file)
index 0000000..3299e7a
--- /dev/null
@@ -0,0 +1,82 @@
+/* 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 <malloc.h>
+#include <string.h>
+
+#include "uv.h"
+#include "internal.h"
+
+
+int uv_utf16_to_utf8(wchar_t* utf16Buffer, size_t utf16Size, char* utf8Buffer, size_t utf8Size) {
+  return WideCharToMultiByte(CP_UTF8, 0, utf16Buffer, utf16Size, utf8Buffer, utf8Size, NULL, NULL);
+}
+
+
+int uv_utf8_to_utf16(const char* utf8Buffer, wchar_t* utf16Buffer, size_t utf16Size) {
+  return MultiByteToWideChar(CP_UTF8, 0, utf8Buffer, -1, utf16Buffer, utf16Size);
+}
+
+
+int uv_exepath(char* buffer, size_t* size) {
+  int retVal;
+  size_t utf16Size;
+  wchar_t* utf16Buffer;
+
+  if (!buffer || !size) {
+    return -1;
+  }
+
+  utf16Buffer = (wchar_t*)malloc(sizeof(wchar_t) * *size);
+  if (!utf16Buffer) {
+    retVal = -1;
+    goto done;
+  }
+
+  /* Get the path as UTF-16 */
+  utf16Size = GetModuleFileNameW(NULL, utf16Buffer, *size - 1);
+  if (utf16Size <= 0) {
+    uv_set_sys_error(GetLastError());
+    retVal = -1;
+    goto done;
+  }
+
+  utf16Buffer[utf16Size] = L'\0';
+
+  /* Convert to UTF-8 */
+  *size = uv_utf16_to_utf8(utf16Buffer, utf16Size, buffer, *size);
+  if (!*size) {
+    uv_set_sys_error(GetLastError());
+    retVal = -1;
+    goto done;
+  }
+
+  buffer[*size] = '\0';
+  retVal = 0;
+
+done:
+  if (utf16Buffer) {
+    free(utf16Buffer);
+  }
+
+  return retVal;
+}