deps: upgrade libuv to 3b8c0da
authorBen Noordhuis <info@bnoordhuis.nl>
Sat, 30 Jun 2012 01:27:54 +0000 (03:27 +0200)
committerBen Noordhuis <info@bnoordhuis.nl>
Sat, 30 Jun 2012 01:27:54 +0000 (03:27 +0200)
deps/uv/src/unix/internal.h
deps/uv/src/unix/stream.c
deps/uv/src/unix/tcp.c
deps/uv/test/test-gethostbyname.c
deps/uv/test/test-list.h
deps/uv/test/test-tcp-unexpected-read.c [new file with mode: 0644]
deps/uv/uv.gyp

index 23f16f7..382c272 100644 (file)
@@ -93,7 +93,8 @@ enum {
   UV_STREAM_WRITABLE  = 0x40,   /* The stream is writable */
   UV_STREAM_BLOCKING  = 0x80,   /* Synchronous writes. */
   UV_TCP_NODELAY      = 0x100,  /* Disable Nagle. */
-  UV_TCP_KEEPALIVE    = 0x200   /* Turn on keep-alive. */
+  UV_TCP_KEEPALIVE    = 0x200,  /* Turn on keep-alive. */
+  UV_TCP_CONNECTING   = 0x400   /* Not alway set. See uv_connect() in tcp.c */
 };
 
 inline static void uv__req_init(uv_loop_t* loop,
@@ -139,8 +140,6 @@ int uv__stream_open(uv_stream_t*, int fd, int flags);
 void uv__stream_destroy(uv_stream_t* stream);
 void uv__server_io(uv_loop_t* loop, uv__io_t* watcher, int events);
 int uv__accept(int sockfd);
-int uv__connect(uv_connect_t* req, uv_stream_t* stream, struct sockaddr* addr,
-    socklen_t addrlen, uv_connect_cb cb);
 
 /* tcp */
 int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb);
index 8c33ee0..bab6580 100644 (file)
@@ -784,12 +784,15 @@ static void uv__stream_connect(uv_stream_t* stream) {
   if (error == EINPROGRESS)
     return;
 
-  if (error == 0)
-    uv__io_start(stream->loop, &stream->read_watcher);
-
   stream->connect_req = NULL;
   uv__req_unregister(stream->loop, req);
 
+  /* Hack. See uv__connect() in tcp.c */
+  if (stream->flags & UV_TCP_CONNECTING) {
+    assert(stream->type == UV_TCP);
+    uv__handle_stop(stream);
+  }
+
   if (req->cb) {
     uv__set_sys_error(stream->loop, error);
     req->cb(req, error ? -1 : 0);
@@ -797,65 +800,6 @@ static void uv__stream_connect(uv_stream_t* stream) {
 }
 
 
-int uv__connect(uv_connect_t* req, uv_stream_t* stream, struct sockaddr* addr,
-    socklen_t addrlen, uv_connect_cb cb) {
-  int sockfd;
-  int r;
-
-  if (stream->type != UV_TCP)
-    return uv__set_sys_error(stream->loop, ENOTSOCK);
-
-  if (stream->connect_req)
-    return uv__set_sys_error(stream->loop, EALREADY);
-
-  if (stream->fd <= 0) {
-    sockfd = uv__socket(addr->sa_family, SOCK_STREAM, 0);
-
-    if (sockfd == -1)
-      return uv__set_sys_error(stream->loop, errno);
-
-    if (uv__stream_open(stream,
-                        sockfd,
-                        UV_STREAM_READABLE | UV_STREAM_WRITABLE)) {
-      close(sockfd);
-      return -1;
-    }
-  }
-
-  stream->delayed_error = 0;
-
-  do
-    r = connect(stream->fd, addr, addrlen);
-  while (r == -1 && errno == EINTR);
-
-  if (r == -1) {
-    if (errno == EINPROGRESS)
-      ; /* not an error */
-    else if (errno == ECONNREFUSED)
-    /* If we get a ECONNREFUSED wait until the next tick to report the
-     * error. Solaris wants to report immediately--other unixes want to
-     * wait.
-     */
-      stream->delayed_error = errno;
-    else
-      return uv__set_sys_error(stream->loop, errno);
-  }
-
-  uv__req_init(stream->loop, req, UV_CONNECT);
-  req->cb = cb;
-  req->handle = stream;
-  ngx_queue_init(&req->queue);
-  stream->connect_req = req;
-
-  uv__io_start(stream->loop, &stream->write_watcher);
-
-  if (stream->delayed_error)
-    uv__io_feed(stream->loop, &stream->write_watcher, UV__IO_WRITE);
-
-  return 0;
-}
-
-
 int uv_write2(uv_write_t* req, uv_stream_t* stream, uv_buf_t bufs[], int bufcnt,
     uv_stream_t* send_handle, uv_write_cb cb) {
   int empty_queue;
index 07ad2d9..1aeba0e 100644 (file)
@@ -34,6 +34,26 @@ int uv_tcp_init(uv_loop_t* loop, uv_tcp_t* tcp) {
 }
 
 
+static int maybe_new_socket(uv_tcp_t* handle, int domain, int flags) {
+  int sockfd;
+
+  if (handle->fd != -1)
+    return 0;
+
+  sockfd = uv__socket(domain, SOCK_STREAM, 0);
+
+  if (sockfd == -1)
+    return uv__set_sys_error(handle->loop, errno);
+
+  if (uv__stream_open((uv_stream_t*)handle, sockfd, flags)) {
+    close(sockfd);
+    return -1;
+  }
+
+  return 0;
+}
+
+
 static int uv__bind(uv_tcp_t* tcp,
                     int domain,
                     struct sockaddr* addr,
@@ -44,23 +64,8 @@ static int uv__bind(uv_tcp_t* tcp,
   saved_errno = errno;
   status = -1;
 
-  if (tcp->fd < 0) {
-    if ((tcp->fd = uv__socket(domain, SOCK_STREAM, 0)) == -1) {
-      uv__set_sys_error(tcp->loop, errno);
-      goto out;
-    }
-
-    if (uv__stream_open((uv_stream_t*)tcp,
-                        tcp->fd,
-                        UV_STREAM_READABLE | UV_STREAM_WRITABLE)) {
-      close(tcp->fd);
-      tcp->fd = -1;
-      status = -2;
-      goto out;
-    }
-  }
-
-  assert(tcp->fd >= 0);
+  if (maybe_new_socket(tcp, domain, UV_STREAM_READABLE|UV_STREAM_WRITABLE))
+    return -1;
 
   tcp->delayed_error = 0;
   if (bind(tcp->fd, addr, addrsize) == -1) {
@@ -79,6 +84,67 @@ out:
 }
 
 
+static int uv__connect(uv_connect_t* req,
+                       uv_tcp_t* handle,
+                       struct sockaddr* addr,
+                       socklen_t addrlen,
+                       uv_connect_cb cb) {
+  int r;
+
+  assert(handle->type == UV_TCP);
+
+  if (handle->connect_req)
+    return uv__set_sys_error(handle->loop, EALREADY);
+
+  if (maybe_new_socket(handle,
+                       addr->sa_family,
+                       UV_STREAM_READABLE|UV_STREAM_WRITABLE)) {
+    return -1;
+  }
+
+  handle->delayed_error = 0;
+
+  do
+    r = connect(handle->fd, addr, addrlen);
+  while (r == -1 && errno == EINTR);
+
+  if (r == -1) {
+    if (errno == EINPROGRESS) {
+      /* Not an error. However, we need to keep the event loop from spinning
+       * while the connection is in progress. Artificially start the handle
+       * and stop it again in uv__stream_connect() in stream.c. Yes, it's a
+       * hack but there's no good alternative, the v0.8 ABI is frozen.
+       */
+      if (!uv__is_active(handle)) {
+        handle->flags |= UV_TCP_CONNECTING;
+        uv__handle_start(handle);
+      }
+    }
+    else if (errno == ECONNREFUSED)
+    /* If we get a ECONNREFUSED wait until the next tick to report the
+     * error. Solaris wants to report immediately--other unixes want to
+     * wait.
+     */
+      handle->delayed_error = errno;
+    else
+      return uv__set_sys_error(handle->loop, errno);
+  }
+
+  uv__req_init(handle->loop, req, UV_CONNECT);
+  req->cb = cb;
+  req->handle = (uv_stream_t*) handle;
+  ngx_queue_init(&req->queue);
+  handle->connect_req = req;
+
+  uv__io_start(handle->loop, &handle->write_watcher);
+
+  if (handle->delayed_error)
+    uv__io_feed(handle->loop, &handle->write_watcher, UV__IO_WRITE);
+
+  return 0;
+}
+
+
 int uv__tcp_bind(uv_tcp_t* handle, struct sockaddr_in addr) {
   return uv__bind(handle,
                   AF_INET,
@@ -170,33 +236,14 @@ out:
 
 
 int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb) {
-  int r;
+  if (tcp->delayed_error)
+    return uv__set_sys_error(tcp->loop, tcp->delayed_error);
 
-  if (tcp->delayed_error) {
-    uv__set_sys_error(tcp->loop, tcp->delayed_error);
+  if (maybe_new_socket(tcp, AF_INET, UV_STREAM_READABLE))
     return -1;
-  }
-
-  if (tcp->fd < 0) {
-    if ((tcp->fd = uv__socket(AF_INET, SOCK_STREAM, 0)) == -1) {
-      uv__set_sys_error(tcp->loop, errno);
-      return -1;
-    }
-
-    if (uv__stream_open((uv_stream_t*)tcp, tcp->fd, UV_STREAM_READABLE)) {
-      close(tcp->fd);
-      tcp->fd = -1;
-      return -1;
-    }
-  }
 
-  assert(tcp->fd >= 0);
-
-  r = listen(tcp->fd, backlog);
-  if (r < 0) {
-    uv__set_sys_error(tcp->loop, errno);
-    return -1;
-  }
+  if (listen(tcp->fd, backlog))
+    return uv__set_sys_error(tcp->loop, errno);
 
   tcp->connection_cb = cb;
 
@@ -209,37 +256,31 @@ int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb) {
 
 
 int uv__tcp_connect(uv_connect_t* req,
-                   uv_tcp_t* handle,
-                   struct sockaddr_in address,
-                   uv_connect_cb cb) {
-  int saved_errno = errno;
+                    uv_tcp_t* handle,
+                    struct sockaddr_in addr,
+                    uv_connect_cb cb) {
+  int saved_errno;
   int status;
 
-  status = uv__connect(req,
-                       (uv_stream_t*)handle,
-                       (struct sockaddr*)&address,
-                       sizeof address,
-                       cb);
-
+  saved_errno = errno;
+  status = uv__connect(req, handle, (struct sockaddr*)&addr, sizeof addr, cb);
   errno = saved_errno;
+
   return status;
 }
 
 
 int uv__tcp_connect6(uv_connect_t* req,
-                    uv_tcp_t* handle,
-                    struct sockaddr_in6 address,
-                    uv_connect_cb cb) {
-  int saved_errno = errno;
+                     uv_tcp_t* handle,
+                     struct sockaddr_in6 addr,
+                     uv_connect_cb cb) {
+  int saved_errno;
   int status;
 
-  status = uv__connect(req,
-                       (uv_stream_t*)handle,
-                       (struct sockaddr*)&address,
-                       sizeof address,
-                       cb);
-
+  saved_errno = errno;
+  status = uv__connect(req, handle, (struct sockaddr*)&addr, sizeof addr, cb);
   errno = saved_errno;
+
   return status;
 }
 
index e49c69c..1df2aaa 100644 (file)
@@ -27,8 +27,6 @@
 #include <string.h> /* strlen */
 
 static ares_channel channel;
-static struct ares_options options;
-static int optmask;
 
 static int ares_bynamecallbacks;
 static int bynamecallbacksig;
@@ -63,19 +61,12 @@ static void aresbyaddrcallback( void *arg,
 }
 
 
-static void prep_tcploopback() {
-  /* for test, use echo server - TCP port TEST_PORT on loopback */
-  struct sockaddr_in test_server = uv_ip4_addr("127.0.0.1", 0);
-  int rc;
-
-  optmask = ARES_OPT_SERVERS | ARES_OPT_TCP_PORT | ARES_OPT_FLAGS;
-  options.servers = &test_server.sin_addr;
-  options.nservers = 1;
-  options.tcp_port = htons(TEST_PORT);
-  options.flags = ARES_FLAG_USEVC;
-
-  rc = uv_ares_init_options(uv_default_loop(), &channel, &options, optmask);
-  ASSERT(rc == ARES_SUCCESS);
+static void setup_cares() {
+  int r;
+  struct ares_options options;
+  memset(&options, 0, sizeof options);
+  r = uv_ares_init_options(uv_default_loop(), &channel, &options, 0);
+  ASSERT(r == ARES_SUCCESS);
 }
 
 
@@ -91,7 +82,7 @@ TEST_IMPL(gethostbyname) {
   }
 
   printf("Start basic gethostbyname test\n");
-  prep_tcploopback();
+  setup_cares();
 
   ares_bynamecallbacks = 0;
   bynamecallbacksig = 7;
@@ -112,7 +103,7 @@ TEST_IMPL(gethostbyname) {
   /* two sequential call on new channel */
 
   printf("Start gethostbyname and gethostbyaddr sequential test\n");
-  prep_tcploopback();
+  setup_cares();
 
   ares_bynamecallbacks = 0;
   bynamecallbacksig = 7;
@@ -151,7 +142,7 @@ TEST_IMPL(gethostbyname) {
   /* two simultaneous calls on new channel */
 
   printf("Start gethostbyname and gethostbyaddr concurrent test\n");
-  prep_tcploopback();
+  setup_cares();
 
   ares_bynamecallbacks = 0;
   bynamecallbacksig = 7;
index cf9a02e..7665149 100644 (file)
@@ -56,6 +56,7 @@ TEST_DECLARE   (tcp_close)
 TEST_DECLARE   (tcp_flags)
 TEST_DECLARE   (tcp_write_error)
 TEST_DECLARE   (tcp_write_to_half_open_connection)
+TEST_DECLARE   (tcp_unexpected_read)
 TEST_DECLARE   (tcp_bind6_error_addrinuse)
 TEST_DECLARE   (tcp_bind6_error_addrnotavail)
 TEST_DECLARE   (tcp_bind6_error_fault)
@@ -251,6 +252,7 @@ TASK_LIST_START
   TEST_ENTRY  (tcp_flags)
   TEST_ENTRY  (tcp_write_error)
   TEST_ENTRY  (tcp_write_to_half_open_connection)
+  TEST_ENTRY  (tcp_unexpected_read)
 
   TEST_ENTRY  (tcp_bind6_error_addrinuse)
   TEST_ENTRY  (tcp_bind6_error_addrnotavail)
@@ -342,7 +344,6 @@ TASK_LIST_START
   TEST_ENTRY  (getaddrinfo_concurrent)
 
   TEST_ENTRY  (gethostbyname)
-  TEST_HELPER (gethostbyname, tcp4_echo_server)
 
   TEST_ENTRY  (getsockname_tcp)
   TEST_ENTRY  (getsockname_udp)
diff --git a/deps/uv/test/test-tcp-unexpected-read.c b/deps/uv/test/test-tcp-unexpected-read.c
new file mode 100644 (file)
index 0000000..7adb4da
--- /dev/null
@@ -0,0 +1,111 @@
+/* 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 "uv.h"
+#include "task.h"
+
+static uv_check_t check_handle;
+static uv_timer_t timer_handle;
+static uv_tcp_t server_handle;
+static uv_tcp_t client_handle;
+static uv_tcp_t peer_handle;
+static uv_write_t write_req;
+static uv_connect_t connect_req;
+
+static unsigned long ticks; /* event loop ticks */
+
+
+static void check_cb(uv_check_t* handle, int status) {
+  ticks++;
+}
+
+
+static void timer_cb(uv_timer_t* handle, int status) {
+  uv_close((uv_handle_t*) &check_handle, NULL);
+  uv_close((uv_handle_t*) &timer_handle, NULL);
+  uv_close((uv_handle_t*) &server_handle, NULL);
+  uv_close((uv_handle_t*) &client_handle, NULL);
+  uv_close((uv_handle_t*) &peer_handle, NULL);
+}
+
+
+static uv_buf_t alloc_cb(uv_handle_t* handle, size_t suggested_size) {
+  ASSERT(0 && "alloc_cb should not have been called");
+}
+
+
+static void read_cb(uv_stream_t* handle, ssize_t nread, uv_buf_t buf) {
+  ASSERT(0 && "read_cb should not have been called");
+}
+
+
+static void connect_cb(uv_connect_t* req, int status) {
+  ASSERT(req->handle == (uv_stream_t*) &client_handle);
+  ASSERT(0 == status);
+}
+
+
+static void write_cb(uv_write_t* req, int status) {
+  ASSERT(req->handle == (uv_stream_t*) &peer_handle);
+  ASSERT(0 == status);
+}
+
+
+static void connection_cb(uv_stream_t* handle, int status) {
+  uv_buf_t buf;
+
+  buf = uv_buf_init("PING", 4);
+
+  ASSERT(0 == status);
+  ASSERT(0 == uv_tcp_init(uv_default_loop(), &peer_handle));
+  ASSERT(0 == uv_accept(handle, (uv_stream_t*) &peer_handle));
+  ASSERT(0 == uv_read_start((uv_stream_t*) &peer_handle, alloc_cb, read_cb));
+  ASSERT(0 == uv_write(&write_req, (uv_stream_t*) &peer_handle,
+                       &buf, 1, write_cb));
+}
+
+
+TEST_IMPL(tcp_unexpected_read) {
+  struct sockaddr_in addr;
+  uv_loop_t* loop;
+
+  addr = uv_ip4_addr("127.0.0.1", TEST_PORT);
+  loop = uv_default_loop();
+
+  ASSERT(0 == uv_timer_init(loop, &timer_handle));
+  ASSERT(0 == uv_timer_start(&timer_handle, timer_cb, 1000, 0));
+  ASSERT(0 == uv_check_init(loop, &check_handle));
+  ASSERT(0 == uv_check_start(&check_handle, check_cb));
+  ASSERT(0 == uv_tcp_init(loop, &server_handle));
+  ASSERT(0 == uv_tcp_init(loop, &client_handle));
+  ASSERT(0 == uv_tcp_bind(&server_handle, addr));
+  ASSERT(0 == uv_listen((uv_stream_t*) &server_handle, 1, connection_cb));
+  ASSERT(0 == uv_tcp_connect(&connect_req, &client_handle, addr, connect_cb));
+  ASSERT(0 == uv_run(loop));
+
+  /* This is somewhat inexact but the idea is that the event loop should not
+   * start busy looping when the server sends a message and the client isn't
+   * reading.
+   */
+  ASSERT(ticks <= 10);
+
+  return 0;
+}
index 5b9273a..0fa5033 100644 (file)
         'test/test-tcp-write-error.c',
         'test/test-tcp-write-to-half-open-connection.c',
         'test/test-tcp-writealot.c',
+        'test/test-tcp-unexpected-read.c',
         'test/test-threadpool.c',
         'test/test-mutexes.c',
         'test/test-thread.c',