uv: upgrade to 3a8bb3b
authorBert Belder <bertbelder@gmail.com>
Mon, 6 Aug 2012 23:25:06 +0000 (01:25 +0200)
committerBert Belder <bertbelder@gmail.com>
Mon, 6 Aug 2012 23:57:56 +0000 (01:57 +0200)
28 files changed:
deps/uv/LICENSE
deps/uv/README.md
deps/uv/config-mingw.mk
deps/uv/config-unix.mk
deps/uv/include/uv-private/uv-unix.h
deps/uv/include/uv.h
deps/uv/src/inet.c [new file with mode: 0644]
deps/uv/src/unix/core.c
deps/uv/src/unix/freebsd.c
deps/uv/src/unix/internal.h
deps/uv/src/unix/pipe.c
deps/uv/src/unix/stream.c
deps/uv/src/unix/sunos.c
deps/uv/src/unix/tcp.c
deps/uv/src/unix/thread.c
deps/uv/src/uv-common.c
deps/uv/src/win/error.c
deps/uv/src/win/pipe.c
deps/uv/src/win/tcp.c
deps/uv/src/win/tty.c
deps/uv/test/benchmark-udp-packet-storm.c
deps/uv/test/test-hrtime.c
deps/uv/test/test-list.h
deps/uv/test/test-process-title.c
deps/uv/test/test-shutdown-close.c
deps/uv/test/test-tcp-close-while-connecting.c
deps/uv/test/test-tcp-unexpected-read.c
deps/uv/uv.gyp

index f62d7f1..57279fc 100644 (file)
@@ -40,3 +40,7 @@ The externally maintained libraries used by libuv are:
 
   - libeio, located at eio/ is copyright Marc Alexander Lehmann, and
     dual-licensed under the MIT license and GPL2.
+
+  - inet_pton and inet_ntop implementations, contained in src/inet.c, are
+    copyright the Internet Systems Consortium, Inc., and licensed under the ISC
+    license.
index f86a000..1359742 100644 (file)
@@ -39,8 +39,10 @@ http://nodejs.org/
 
 ## Documentation
 
-See `include/uv.h`.
-
+ * [include/uv.h](https://github.com/joyent/libuv/blob/master/include/uv.h)
+   &mdash; API documentation in the form of detailed header comments.
+ * [An Introduction to libuv](http://nikhilm.github.com/uvbook/) &mdash; An
+   overview of libuv with tutorials.
 
 ## Build Instructions
 
index 9e49ec7..8a253ba 100644 (file)
@@ -37,7 +37,7 @@ RUNNER_LINKFLAGS=$(LINKFLAGS)
 RUNNER_LIBS=-lws2_32 -lpsapi -liphlpapi
 RUNNER_SRC=test/runner-win.c
 
-uv.a: $(WIN_OBJS) src/cares.o src/fs-poll.o src/uv-common.o $(CARES_OBJS)
+uv.a: $(WIN_OBJS) src/cares.o src/fs-poll.o src/inet.o src/uv-common.o $(CARES_OBJS)
        $(AR) rcs uv.a $^
 
 src/%.o: src/%.c include/uv.h include/uv-private/uv-win.h
@@ -46,16 +46,10 @@ src/%.o: src/%.c include/uv.h include/uv-private/uv-win.h
 src/win/%.o: src/win/%.c include/uv.h include/uv-private/uv-win.h src/win/internal.h
        $(CC) $(CFLAGS) -o $@ -c $<
 
-EIO_CPPFLAGS += $(CPPFLAGS)
-EIO_CPPFLAGS += -DEIO_STACKSIZE=65536
-EIO_CPPFLAGS += -D_GNU_SOURCE
-
 clean-platform:
        -rm -f src/ares/*.o
-       -rm -f src/eio/*.o
        -rm -f src/win/*.o
 
 distclean-platform:
        -rm -f src/ares/*.o
-       -rm -f src/eio/*.o
        -rm -f src/win/*.o
index 0581b51..667e7b9 100644 (file)
@@ -131,7 +131,7 @@ endif
 RUNNER_LIBS=
 RUNNER_SRC=test/runner-unix.c
 
-uv.a: $(OBJS) src/cares.o src/fs-poll.o src/uv-common.o src/unix/ev/ev.o src/unix/uv-eio.o src/unix/eio/eio.o $(CARES_OBJS)
+uv.a: $(OBJS) src/cares.o src/fs-poll.o src/inet.o src/uv-common.o src/unix/ev/ev.o src/unix/uv-eio.o src/unix/eio/eio.o $(CARES_OBJS)
        $(AR) rcs uv.a $^
 
 src/%.o: src/%.c include/uv.h include/uv-private/uv-unix.h
index 31524c0..a8dda72 100644 (file)
 #include <termios.h>
 #include <pwd.h>
 
-#include <semaphore.h>
 #include <pthread.h>
 #include <signal.h>
 
+#if defined(__APPLE__) && defined(__MACH__)
+# include <mach/mach.h>
+# include <mach/task.h>
+# include <mach/semaphore.h>
+#else
+# include <semaphore.h>
+#endif
+
 #if __sun
 # include <sys/port.h>
 # include <port.h>
@@ -67,7 +74,11 @@ typedef pthread_once_t uv_once_t;
 typedef pthread_t uv_thread_t;
 typedef pthread_mutex_t uv_mutex_t;
 typedef pthread_rwlock_t uv_rwlock_t;
+#if defined(__APPLE__) && defined(__MACH__)
+typedef semaphore_t uv_sem_t;
+#else
 typedef sem_t uv_sem_t;
+#endif
 
 /* Platform-specific definitions for uv_spawn support. */
 typedef gid_t uv_gid_t;
@@ -173,8 +184,9 @@ struct uv__io_s {
   int fd; \
 
 
-/* UV_TCP */
-#define UV_TCP_PRIVATE_FIELDS
+/* UV_TCP, idle_handle is for UV_TCP_SINGLE_ACCEPT handles */
+#define UV_TCP_PRIVATE_FIELDS         \
+  uv_idle_t* idle_handle;             \
 
 
 /* UV_UDP */
index 0cdc2ed..1f8beca 100644 (file)
@@ -121,7 +121,8 @@ extern "C" {
   XX( 54, ENOSPC, "no space left on device") \
   XX( 55, EIO, "i/o error") \
   XX( 56, EROFS, "read-only file system" ) \
-  XX( 57, ENODEV, "no such device" )
+  XX( 57, ENODEV, "no such device" ) \
+  XX( 58, ECANCELED, "operation canceled" )
 
 
 #define UV_ERRNO_GEN(val, name, s) UV_##name = val,
@@ -427,6 +428,10 @@ UV_EXTERN void uv_walk(uv_loop_t* loop, uv_walk_cb walk_cb, void* arg);
  * Note that handles that wrap file descriptors are closed immediately but
  * close_cb will still be deferred to the next iteration of the event loop.
  * It gives you a chance to free up any resources associated with the handle.
+ *
+ * In-progress requests, like uv_connect_t or uv_write_t, are cancelled and
+ * have their callbacks called asynchronously with status=-1 and the error code
+ * set to UV_ECANCELED.
  */
 UV_EXTERN void uv_close(uv_handle_t* handle, uv_close_cb close_cb);
 
@@ -528,9 +533,12 @@ UV_EXTERN int uv_read2_start(uv_stream_t*, uv_alloc_cb alloc_cb,
  *     { .base = "4", .len = 1 }
  *   };
  *
+ *   uv_write_t req1;
+ *   uv_write_t req2;
+ *
  *   // writes "1234"
- *   uv_write(req, stream, a, 2);
- *   uv_write(req, stream, b, 2);
+ *   uv_write(&req1, stream, a, 2);
+ *   uv_write(&req2, stream, b, 2);
  *
  */
 UV_EXTERN int uv_write(uv_write_t* req, uv_stream_t* handle,
@@ -1614,6 +1622,12 @@ UV_EXTERN struct sockaddr_in6 uv_ip6_addr(const char* ip, int port);
 UV_EXTERN int uv_ip4_name(struct sockaddr_in* src, char* dst, size_t size);
 UV_EXTERN int uv_ip6_name(struct sockaddr_in6* src, char* dst, size_t size);
 
+/* Cross-platform IPv6-capable implementation of the 'standard' inet_ntop */
+/* and inet_pton functions. On success they return UV_OK. If an error */
+/* the target of the `dst` pointer is unmodified. */
+uv_err_t uv_inet_ntop(int af, const void* src, char* dst, size_t size);
+uv_err_t uv_inet_pton(int af, const char* src, void* dst);
+
 /* Gets the executable path */
 UV_EXTERN int uv_exepath(char* buffer, size_t* size);
 
diff --git a/deps/uv/src/inet.c b/deps/uv/src/inet.c
new file mode 100644 (file)
index 0000000..293fbf6
--- /dev/null
@@ -0,0 +1,293 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "uv.h"
+#include "uv-common.h"
+
+
+static const uv_err_t uv_eafnosupport_ = { UV_EAFNOSUPPORT, 0 };
+static const uv_err_t uv_enospc_ = { UV_ENOSPC, 0 };
+static const uv_err_t uv_einval_ = { UV_EINVAL, 0 };
+
+static uv_err_t inet_ntop4(const unsigned char *src, char *dst, size_t size);
+static uv_err_t inet_ntop6(const unsigned char *src, char *dst, size_t size);
+static uv_err_t inet_pton4(const char *src, unsigned char *dst);
+static uv_err_t inet_pton6(const char *src, unsigned char *dst);
+
+
+uv_err_t uv_inet_ntop(int af, const void* src, char* dst, size_t size) {
+  switch (af) {
+  case AF_INET:
+    return (inet_ntop4(src, dst, size));
+  case AF_INET6:
+    return (inet_ntop6(src, dst, size));
+  default:
+    return uv_eafnosupport_;
+  }
+  /* NOTREACHED */
+}
+
+
+static uv_err_t inet_ntop4(const unsigned char *src, char *dst, size_t size) {
+  static const char fmt[] = "%u.%u.%u.%u";
+  char tmp[sizeof "255.255.255.255"];
+  size_t l;
+
+#ifndef _WIN32
+  l = snprintf(tmp, sizeof(tmp), fmt, src[0], src[1], src[2], src[3]);
+#else
+  l = _snprintf(tmp, sizeof(tmp), fmt, src[0], src[1], src[2], src[3]);
+#endif
+  if (l <= 0 || l >= size) {
+    return uv_enospc_;
+  }
+  strncpy(dst, tmp, size);
+  dst[size - 1] = '\0';
+  return uv_ok_;
+}
+
+
+static uv_err_t inet_ntop6(const unsigned char *src, char *dst, size_t size) {
+  /*
+   * Note that int32_t and int16_t need only be "at least" large enough
+   * to contain a value of the specified size.  On some systems, like
+   * Crays, there is no such thing as an integer variable with 16 bits.
+   * Keep this in mind if you think this function should have been coded
+   * to use pointer overlays.  All the world's not a VAX.
+   */
+  char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp;
+  struct { int base, len; } best, cur;
+  unsigned int words[sizeof(struct in6_addr) / sizeof(uint16_t)];
+  int i;
+
+  /*
+   * Preprocess:
+   *  Copy the input (bytewise) array into a wordwise array.
+   *  Find the longest run of 0x00's in src[] for :: shorthanding.
+   */
+  memset(words, '\0', sizeof words);
+  for (i = 0; i < (int) sizeof(struct in6_addr); i++)
+    words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));
+  best.base = -1;
+  best.len = 0;
+  cur.base = -1;
+  cur.len = 0;
+  for (i = 0; i < (int) ARRAY_SIZE(words); i++) {
+    if (words[i] == 0) {
+      if (cur.base == -1)
+        cur.base = i, cur.len = 1;
+      else
+        cur.len++;
+    } else {
+      if (cur.base != -1) {
+        if (best.base == -1 || cur.len > best.len)
+          best = cur;
+        cur.base = -1;
+      }
+    }
+  }
+  if (cur.base != -1) {
+    if (best.base == -1 || cur.len > best.len)
+      best = cur;
+  }
+  if (best.base != -1 && best.len < 2)
+    best.base = -1;
+
+  /*
+   * Format the result.
+   */
+  tp = tmp;
+  for (i = 0; i < (int) ARRAY_SIZE(words); i++) {
+    /* Are we inside the best run of 0x00's? */
+    if (best.base != -1 && i >= best.base &&
+        i < (best.base + best.len)) {
+      if (i == best.base)
+        *tp++ = ':';
+      continue;
+    }
+    /* Are we following an initial run of 0x00s or any real hex? */
+    if (i != 0)
+      *tp++ = ':';
+    /* Is this address an encapsulated IPv4? */
+    if (i == 6 && best.base == 0 && (best.len == 6 ||
+        (best.len == 7 && words[7] != 0x0001) ||
+        (best.len == 5 && words[5] == 0xffff))) {
+      uv_err_t err = inet_ntop4(src+12, tp, sizeof tmp - (tp - tmp));
+      if (err.code != UV_OK)
+        return err;
+      tp += strlen(tp);
+      break;
+    }
+    tp += sprintf(tp, "%x", words[i]);
+  }
+  /* Was it a trailing run of 0x00's? */
+  if (best.base != -1 && (best.base + best.len) == ARRAY_SIZE(words))
+    *tp++ = ':';
+  *tp++ = '\0';
+
+  /*
+   * Check for overflow, copy, and we're done.
+   */
+  if ((size_t)(tp - tmp) > size) {
+    return uv_enospc_;
+  }
+  strcpy(dst, tmp);
+  return uv_ok_;
+}
+
+
+uv_err_t uv_inet_pton(int af, const char* src, void* dst) {
+  switch (af) {
+  case AF_INET:
+    return (inet_pton4(src, dst));
+  case AF_INET6:
+    return (inet_pton6(src, dst));
+  default:
+    return uv_eafnosupport_;
+  }
+  /* NOTREACHED */
+}
+
+
+static uv_err_t inet_pton4(const char *src, unsigned char *dst) {
+  static const char digits[] = "0123456789";
+  int saw_digit, octets, ch;
+  unsigned char tmp[sizeof(struct in_addr)], *tp;
+
+  saw_digit = 0;
+  octets = 0;
+  *(tp = tmp) = 0;
+  while ((ch = *src++) != '\0') {
+    const char *pch;
+
+    if ((pch = strchr(digits, ch)) != NULL) {
+      unsigned int nw = *tp * 10 + (pch - digits);
+
+      if (saw_digit && *tp == 0)
+        return uv_einval_;
+      if (nw > 255)
+        return uv_einval_;
+      *tp = nw;
+      if (!saw_digit) {
+        if (++octets > 4)
+          return uv_einval_;
+        saw_digit = 1;
+      }
+    } else if (ch == '.' && saw_digit) {
+      if (octets == 4)
+        return uv_einval_;
+      *++tp = 0;
+      saw_digit = 0;
+    } else
+      return uv_einval_;
+  }
+  if (octets < 4)
+    return uv_einval_;
+  memcpy(dst, tmp, sizeof(struct in_addr));
+  return uv_ok_;
+}
+
+
+static uv_err_t inet_pton6(const char *src, unsigned char *dst) {
+  static const char xdigits_l[] = "0123456789abcdef",
+                    xdigits_u[] = "0123456789ABCDEF";
+  unsigned char tmp[sizeof(struct in6_addr)], *tp, *endp, *colonp;
+  const char *xdigits, *curtok;
+  int ch, seen_xdigits;
+  unsigned int val;
+
+  memset((tp = tmp), '\0', sizeof tmp);
+  endp = tp + sizeof tmp;
+  colonp = NULL;
+  /* Leading :: requires some special handling. */
+  if (*src == ':')
+    if (*++src != ':')
+      return uv_einval_;
+  curtok = src;
+  seen_xdigits = 0;
+  val = 0;
+  while ((ch = *src++) != '\0') {
+    const char *pch;
+
+    if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
+      pch = strchr((xdigits = xdigits_u), ch);
+    if (pch != NULL) {
+      val <<= 4;
+      val |= (pch - xdigits);
+      if (++seen_xdigits > 4)
+        return uv_einval_;
+      continue;
+    }
+    if (ch == ':') {
+      curtok = src;
+      if (!seen_xdigits) {
+        if (colonp)
+          return uv_einval_;
+        colonp = tp;
+        continue;
+      } else if (*src == '\0') {
+        return uv_einval_;
+      }
+      if (tp + sizeof(uint16_t) > endp)
+        return uv_einval_;
+      *tp++ = (unsigned char) (val >> 8) & 0xff;
+      *tp++ = (unsigned char) val & 0xff;
+      seen_xdigits = 0;
+      val = 0;
+      continue;
+    }
+    if (ch == '.' && ((tp + sizeof(struct in_addr)) <= endp)) {
+      uv_err_t err = inet_pton4(curtok, tp);
+      if (err.code == 0) {
+        tp += sizeof(struct in_addr);
+        seen_xdigits = 0;
+        break;  /*%< '\\0' was seen by inet_pton4(). */
+      }
+    }
+    return uv_einval_;
+  }
+  if (seen_xdigits) {
+    if (tp + sizeof(uint16_t) > endp)
+      return uv_einval_;
+    *tp++ = (unsigned char) (val >> 8) & 0xff;
+    *tp++ = (unsigned char) val & 0xff;
+  }
+  if (colonp != NULL) {
+    /*
+     * Since some memmove()'s erroneously fail to handle
+     * overlapping regions, we'll do the shift by hand.
+     */
+    const int n = tp - colonp;
+    int i;
+
+    if (tp == endp)
+      return uv_einval_;
+    for (i = 1; i <= n; i++) {
+      endp[- i] = colonp[n - i];
+      colonp[n - i] = 0;
+    }
+    tp = endp;
+  }
+  if (tp != endp)
+    return uv_einval_;
+  memcpy(dst, tmp, sizeof tmp);
+  return uv_ok_;
+}
index 2f88159..4bc6b77 100644 (file)
@@ -69,10 +69,13 @@ void uv_close(uv_handle_t* handle, uv_close_cb close_cb) {
     break;
 
   case UV_TTY:
-  case UV_TCP:
     uv__stream_close((uv_stream_t*)handle);
     break;
 
+  case UV_TCP:
+    uv__tcp_close((uv_tcp_t*)handle);
+    break;
+
   case UV_UDP:
     uv__udp_close((uv_udp_t*)handle);
     break;
@@ -228,7 +231,7 @@ void uv_loop_delete(uv_loop_t* loop) {
 
 
 static unsigned int uv__poll_timeout(uv_loop_t* loop) {
-  if (!uv__has_active_handles(loop))
+  if (!uv__has_active_handles(loop) && !uv__has_active_reqs(loop))
     return 0;
 
   if (!ngx_queue_empty(&loop->idle_handles))
index d916b0b..be8006c 100644 (file)
@@ -139,9 +139,23 @@ char** uv_setup_args(int argc, char** argv) {
 
 
 uv_err_t uv_set_process_title(const char* title) {
+  int oid[4];
+
   if (process_title) free(process_title);
   process_title = strdup(title);
-  setproctitle(title);
+
+  oid[0] = CTL_KERN;
+  oid[1] = KERN_PROC;
+  oid[2] = KERN_PROC_ARGS;
+  oid[3] = getpid();
+
+  sysctl(oid,
+         ARRAY_SIZE(oid),
+         NULL,
+         NULL,
+         process_title,
+         strlen(process_title) + 1);
+
   return uv_ok_;
 }
 
@@ -261,7 +275,7 @@ uv_err_t uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
     return uv__new_sys_error(ENOMEM);
   }
 
-  if (sysctlbyname("kern.cp_times", &cp_times, &size, NULL, 0) < 0) {
+  if (sysctlbyname("kern.cp_times", cp_times, &size, NULL, 0) < 0) {
     free(cp_times);
     free(*cpu_infos);
     return uv__new_sys_error(errno);
index 23f16f7..233f742 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_SINGLE_ACCEPT = 0x400  /* Only accept() when idle. */
 };
 
 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);
@@ -164,6 +163,7 @@ void uv__poll_close(uv_poll_t* handle);
 void uv__prepare_close(uv_prepare_t* handle);
 void uv__process_close(uv_process_t* handle);
 void uv__stream_close(uv_stream_t* handle);
+void uv__tcp_close(uv_tcp_t* handle);
 void uv__timer_close(uv_timer_t* handle);
 void uv__udp_close(uv_udp_t* handle);
 void uv__udp_finish_close(uv_udp_t* handle);
index 317ac67..957e96f 100644 (file)
@@ -170,18 +170,17 @@ void uv_pipe_connect(uv_connect_t* req,
                     uv_connect_cb cb) {
   struct sockaddr_un saddr;
   int saved_errno;
-  int sockfd;
-  int status;
+  int new_sock;
+  int err;
   int r;
 
   saved_errno = errno;
-  sockfd = -1;
-  status = -1;
+  new_sock = (handle->fd == -1);
+  err = -1;
 
-  if ((sockfd = uv__socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
-    uv__set_sys_error(handle->loop, errno);
-    goto out;
-  }
+  if (new_sock)
+    if ((handle->fd = uv__socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
+      goto out;
 
   memset(&saddr, 0, sizeof saddr);
   uv_strlcpy(saddr.sun_path, name, sizeof(saddr.sun_path));
@@ -191,25 +190,25 @@ void uv_pipe_connect(uv_connect_t* req,
    * is either there or not.
    */
   do {
-    r = connect(sockfd, (struct sockaddr*)&saddr, sizeof saddr);
+    r = connect(handle->fd, (struct sockaddr*)&saddr, sizeof saddr);
   }
   while (r == -1 && errno == EINTR);
 
-  if (r == -1) {
-    status = errno;
-    close(sockfd);
+  if (r == -1)
     goto out;
-  }
 
-  uv__stream_open((uv_stream_t*)handle,
-                  sockfd,
-                  UV_STREAM_READABLE | UV_STREAM_WRITABLE);
+  if (new_sock)
+    if (uv__stream_open((uv_stream_t*)handle,
+                        handle->fd,
+                        UV_STREAM_READABLE | UV_STREAM_WRITABLE))
+      goto out;
+
   uv__io_start(handle->loop, &handle->read_watcher);
   uv__io_start(handle->loop, &handle->write_watcher);
-  status = 0;
+  err = 0;
 
 out:
-  handle->delayed_error = status; /* Passed to callback. */
+  handle->delayed_error = err ? errno : 0; /* Passed to callback. */
   handle->connect_req = req;
 
   uv__req_init(handle->loop, req, UV_CONNECT);
index 8c33ee0..26875a7 100644 (file)
@@ -120,7 +120,7 @@ void uv__stream_destroy(uv_stream_t* stream) {
 
   if (stream->connect_req) {
     uv__req_unregister(stream->loop, stream->connect_req);
-    uv__set_artificial_error(stream->loop, UV_EINTR);
+    uv__set_artificial_error(stream->loop, UV_ECANCELED);
     stream->connect_req->cb(stream->connect_req, -1);
     stream->connect_req = NULL;
   }
@@ -136,7 +136,7 @@ void uv__stream_destroy(uv_stream_t* stream) {
       free(req->bufs);
 
     if (req->cb) {
-      uv__set_artificial_error(req->handle->loop, UV_EINTR);
+      uv__set_artificial_error(req->handle->loop, UV_ECANCELED);
       req->cb(req, -1);
     }
   }
@@ -156,13 +156,23 @@ void uv__stream_destroy(uv_stream_t* stream) {
 
   if (stream->shutdown_req) {
     uv__req_unregister(stream->loop, stream->shutdown_req);
-    uv__set_artificial_error(stream->loop, UV_EINTR);
+    uv__set_artificial_error(stream->loop, UV_ECANCELED);
     stream->shutdown_req->cb(stream->shutdown_req, -1);
     stream->shutdown_req = NULL;
   }
 }
 
 
+static void uv__next_accept(uv_idle_t* idle, int status) {
+  uv_stream_t* stream = idle->data;
+
+  uv_idle_stop(idle);
+
+  if (stream->accepted_fd == -1)
+    uv__io_start(stream->loop, &stream->read_watcher);
+}
+
+
 void uv__server_io(uv_loop_t* loop, uv__io_t* w, int events) {
   int fd;
   uv_stream_t* stream = container_of(w, uv_stream_t, read_watcher);
@@ -198,14 +208,44 @@ void uv__server_io(uv_loop_t* loop, uv__io_t* w, int events) {
       }
     } else {
       stream->accepted_fd = fd;
-      stream->connection_cb((uv_stream_t*)stream, 0);
-      if (stream->accepted_fd >= 0) {
+      stream->connection_cb(stream, 0);
+
+      if (stream->accepted_fd != -1 ||
+          (stream->type == UV_TCP && stream->flags == UV_TCP_SINGLE_ACCEPT)) {
         /* The user hasn't yet accepted called uv_accept() */
         uv__io_stop(stream->loop, &stream->read_watcher);
-        return;
+        break;
       }
     }
   }
+
+  if (stream->fd != -1 &&
+      stream->accepted_fd == -1 &&
+      (stream->type == UV_TCP && stream->flags == UV_TCP_SINGLE_ACCEPT))
+  {
+    /* Defer the next accept() syscall to the next event loop tick.
+     * This lets us guarantee fair load balancing in in multi-process setups.
+     * The problem is as follows:
+     *
+     *  1. Multiple processes listen on the same socket.
+     *  2. The OS scheduler commonly gives preference to one process to
+     *     avoid task switches.
+     *  3. That process therefore accepts most of the new connections,
+     *     leading to a (sometimes very) unevenly distributed load.
+     *
+     * Here is how we mitigate this issue:
+     *
+     *  1. Accept a connection.
+     *  2. Start an idle watcher.
+     *  3. Don't accept new connections until the idle callback fires.
+     *
+     * This works because the callback only fires when there have been
+     * no recent events, i.e. none of the watched file descriptors have
+     * recently been readable or writable.
+     */
+    uv_tcp_t* tcp = (uv_tcp_t*) stream;
+    uv_idle_start(tcp->idle_handle, uv__next_accept);
+  }
 }
 
 
@@ -784,9 +824,6 @@ 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);
 
@@ -797,65 +834,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 a33ec9d..8c626a3 100644 (file)
@@ -127,7 +127,7 @@ static void uv__fs_event_rearm(uv_fs_event_t *handle) {
 
 
 static void uv__fs_event_read(uv_loop_t* loop, uv__io_t* w, int revents) {
-  uv_fs_event_t *handle;
+  uv_fs_event_t *handle = NULL;
   timespec_t timeout;
   port_event_t pe;
   int events;
@@ -137,14 +137,23 @@ static void uv__fs_event_read(uv_loop_t* loop, uv__io_t* w, int revents) {
   (void) revents;
 
   do {
-    /* TODO use port_getn() */
+    uint_t n = 1;
+
+    /*
+     * Note that our use of port_getn() here (and not port_get()) is deliberate:
+     * there is a bug in event ports (Sun bug 6456558) whereby a zeroed timeout
+     * causes port_get() to return success instead of ETIME when there aren't
+     * actually any events (!); by using port_getn() in lieu of port_get(),
+     * we can at least workaround the bug by checking for zero returned events
+     * and treating it as we would ETIME.
+     */
     do {
       memset(&timeout, 0, sizeof timeout);
-      r = port_get(loop->fs_fd, &pe, &timeout);
+      r = port_getn(loop->fs_fd, &pe, 1, &n, &timeout);
     }
     while (r == -1 && errno == EINTR);
 
-    if (r == -1 && errno == ETIME)
+    if ((r == -1 && errno == ETIME) || n == 0)
       break;
 
     handle = (uv_fs_event_t *)pe.portev_user;
@@ -161,7 +170,7 @@ static void uv__fs_event_read(uv_loop_t* loop, uv__io_t* w, int revents) {
   }
   while (handle->fd != PORT_DELETED);
 
-  if (handle->fd != PORT_DELETED)
+  if (handle != NULL && handle->fd != PORT_DELETED)
     uv__fs_event_rearm(handle);
 }
 
index 07ad2d9..d9cbd0b 100644 (file)
@@ -22,6 +22,7 @@
 #include "uv.h"
 #include "internal.h"
 
+#include <stdlib.h>
 #include <unistd.h>
 #include <assert.h>
 #include <errno.h>
 int uv_tcp_init(uv_loop_t* loop, uv_tcp_t* tcp) {
   uv__stream_init(loop, (uv_stream_t*)tcp, UV_TCP);
   loop->counters.tcp_init++;
+  tcp->idle_handle = NULL;
+  return 0;
+}
+
+
+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;
 }
 
@@ -44,23 +66,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 +86,58 @@ 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 */
+    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 +229,34 @@ out:
 
 
 int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb) {
-  int r;
+  static int single_accept = -1;
 
-  if (tcp->delayed_error) {
-    uv__set_sys_error(tcp->loop, tcp->delayed_error);
-    return -1;
+  if (tcp->delayed_error)
+    return uv__set_sys_error(tcp->loop, tcp->delayed_error);
+
+  if (single_accept == -1) {
+    const char* val = getenv("UV_TCP_SINGLE_ACCEPT");
+    single_accept = (val == NULL) || (atoi(val) != 0); /* on by default */
   }
 
-  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 (!single_accept)
+    goto no_single_accept;
 
-    if (uv__stream_open((uv_stream_t*)tcp, tcp->fd, UV_STREAM_READABLE)) {
-      close(tcp->fd);
-      tcp->fd = -1;
-      return -1;
-    }
-  }
+  tcp->idle_handle = malloc(sizeof(*tcp->idle_handle));
+  if (tcp->idle_handle == NULL)
+    return uv__set_sys_error(tcp->loop, ENOMEM);
+
+  if (uv_idle_init(tcp->loop, tcp->idle_handle))
+    abort();
 
-  assert(tcp->fd >= 0);
+  tcp->flags |= UV_TCP_SINGLE_ACCEPT;
 
-  r = listen(tcp->fd, backlog);
-  if (r < 0) {
-    uv__set_sys_error(tcp->loop, errno);
+no_single_accept:
+  if (maybe_new_socket(tcp, AF_INET, UV_STREAM_READABLE))
     return -1;
-  }
+
+  if (listen(tcp->fd, backlog))
+    return uv__set_sys_error(tcp->loop, errno);
 
   tcp->connection_cb = cb;
 
@@ -209,37 +269,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;
 }
 
@@ -324,5 +378,17 @@ int uv_tcp_keepalive(uv_tcp_t* handle, int enable, unsigned int delay) {
 
 
 int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable) {
+  if (enable)
+    handle->flags |= UV_TCP_SINGLE_ACCEPT;
+  else
+    handle->flags &= ~UV_TCP_SINGLE_ACCEPT;
   return 0;
 }
+
+
+void uv__tcp_close(uv_tcp_t* handle) {
+  if (handle->idle_handle)
+    uv_close((uv_handle_t*)handle->idle_handle, (uv_close_cb)free);
+
+  uv__stream_close((uv_stream_t*)handle);
+}
index 5a17bcb..67c7876 100644 (file)
@@ -167,6 +167,44 @@ void uv_once(uv_once_t* guard, void (*callback)(void)) {
     abort();
 }
 
+#if defined(__APPLE__) && defined(__MACH__)
+
+int uv_sem_init(uv_sem_t* sem, unsigned int value) {
+  return semaphore_create(mach_task_self(), sem, SYNC_POLICY_FIFO, value);
+}
+
+
+void uv_sem_destroy(uv_sem_t* sem) {
+  if (semaphore_destroy(mach_task_self(), *sem))
+    abort();
+}
+
+
+void uv_sem_post(uv_sem_t* sem) {
+  if (semaphore_signal(*sem))
+    abort();
+}
+
+
+void uv_sem_wait(uv_sem_t* sem) {
+  if (semaphore_wait(*sem))
+    abort();
+}
+
+
+int uv_sem_trywait(uv_sem_t* sem) {
+  mach_timespec_t interval;
+
+  interval.tv_sec = 0;
+  interval.tv_nsec = 0;
+
+  if (semaphore_timedwait(*sem, interval) == KERN_SUCCESS)
+    return 0;
+  else
+    return -1;
+}
+
+#else /* !(defined(__APPLE__) && defined(__MACH__)) */
 
 int uv_sem_init(uv_sem_t* sem, unsigned int value) {
   return sem_init(sem, 0, value);
@@ -209,3 +247,5 @@ int uv_sem_trywait(uv_sem_t* sem) {
 
   return r;
 }
+
+#endif /* defined(__APPLE__) && defined(__MACH__) */
index 9639634..75dfcd8 100644 (file)
 #include <stdlib.h> /* malloc */
 #include <string.h> /* memset */
 
-/* use inet_pton from c-ares if necessary */
-#include "ares_config.h"
-#include "ares/inet_net_pton.h"
-#include "ares/inet_ntop.h"
 
 #define XX(uc, lc) case UV_##uc: return sizeof(uv_##lc##_t);
 
@@ -182,21 +178,21 @@ struct sockaddr_in6 uv_ip6_addr(const char* ip, int port) {
 
   addr.sin6_family = AF_INET6;
   addr.sin6_port = htons(port);
-  ares_inet_pton(AF_INET6, ip, &addr.sin6_addr);
+  uv_inet_pton(AF_INET6, ip, &addr.sin6_addr);
 
   return addr;
 }
 
 
 int uv_ip4_name(struct sockaddr_in* src, char* dst, size_t size) {
-  const char* d = ares_inet_ntop(AF_INET, &src->sin_addr, dst, size);
-  return d != dst;
+  uv_err_t err = uv_inet_ntop(AF_INET, &src->sin_addr, dst, size);
+  return err.code != UV_OK;
 }
 
 
 int uv_ip6_name(struct sockaddr_in6* src, char* dst, size_t size) {
-  const char* d = ares_inet_ntop(AF_INET6, &src->sin6_addr, dst, size);
-  return d != dst;
+  uv_err_t err = uv_inet_ntop(AF_INET6, &src->sin6_addr, dst, size);
+  return err.code != UV_OK;
 }
 
 
index 6490547..91f5111 100644 (file)
@@ -86,6 +86,7 @@ uv_err_code uv_translate_sys_error(int sys_errno) {
     case ERROR_INVALID_REPARSE_DATA:        return UV_ENOENT;
     case ERROR_MOD_NOT_FOUND:               return UV_ENOENT;
     case ERROR_PATH_NOT_FOUND:              return UV_ENOENT;
+    case WSANO_DATA:                        return UV_ENOENT;
     case ERROR_ACCESS_DENIED:               return UV_EPERM;
     case ERROR_PRIVILEGE_NOT_HELD:          return UV_EPERM;
     case ERROR_NOACCESS:                    return UV_EACCES;
index 77a1c7b..5da14ea 100644 (file)
@@ -300,7 +300,7 @@ void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) {
 
       /* Already closing. Cancel the shutdown. */
       if (req->cb) {
-        uv__set_sys_error(loop, WSAEINTR);
+        uv__set_artificial_error(loop, UV_ECANCELED);
         req->cb(req, -1);
       }
 
index e13c0f3..2a25358 100644 (file)
@@ -157,7 +157,6 @@ int uv_tcp_init(uv_loop_t* loop, uv_tcp_t* handle) {
 
 void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) {
   int status;
-  int sys_error;
   unsigned int i;
   uv_tcp_accept_t* req;
 
@@ -169,19 +168,16 @@ void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) {
 
     if (handle->flags & UV_HANDLE_CLOSING) {
       status = -1;
-      sys_error = WSAEINTR;
+      uv__set_artificial_error(loop, UV_ECANCELED);
     } else if (shutdown(handle->socket, SD_SEND) != SOCKET_ERROR) {
       status = 0;
       handle->flags |= UV_HANDLE_SHUT;
     } else {
       status = -1;
-      sys_error = WSAGetLastError();
+      uv__set_sys_error(loop, WSAGetLastError());
     }
 
     if (handle->shutdown_req->cb) {
-      if (status == -1) {
-        uv__set_sys_error(loop, sys_error);
-      }
       handle->shutdown_req->cb(handle->shutdown_req, status);
     }
 
index 340bcdc..66103e6 100644 (file)
@@ -1751,7 +1751,7 @@ void uv_tty_endgame(uv_loop_t* loop, uv_tty_t* handle) {
     /* TTY shutdown is really just a no-op */
     if (handle->shutdown_req->cb) {
       if (handle->flags & UV_HANDLE_CLOSING) {
-        uv__set_sys_error(loop, WSAEINTR);
+        uv__set_artificial_error(loop, UV_ECANCELED);
         handle->shutdown_req->cb(handle->shutdown_req, -1);
       } else {
         handle->shutdown_req->cb(handle->shutdown_req, 0);
index 5941287..9842e4c 100644 (file)
@@ -91,7 +91,7 @@ static void recv_cb(uv_udp_t* handle,
     return;
 
   if (nread == -1) {
-    ASSERT(uv_last_error(loop).code == UV_EINTR); /* FIXME change error code */
+    ASSERT(uv_last_error(loop).code == UV_ECANCELED);
     return;
   }
 
index 2a9156e..72a4d4b 100644 (file)
@@ -47,7 +47,7 @@ TEST_IMPL(hrtime) {
     /* Check that the difference between the two hrtime values is somewhat in */
     /* the range we expect it to be. */
     ASSERT(diff > (uint64_t) 25 * NANOSEC / MILLISEC);
-    ASSERT(diff < (uint64_t) 60 * NANOSEC / MILLISEC);
+    ASSERT(diff < (uint64_t) 80 * NANOSEC / MILLISEC);
     --i;
   }
   return 0;
index 75e8f2e..19670e5 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)
@@ -252,6 +253,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)
index 59fceda..13d9ddd 100644 (file)
 #include "task.h"
 #include <string.h>
 
-TEST_IMPL(process_title) {
+
+static void set_title(const char* title) {
   char buffer[512];
   uv_err_t err;
 
   err = uv_get_process_title(buffer, sizeof(buffer));
   ASSERT(UV_OK == err.code);
 
-  err = uv_set_process_title("new title");
+  err = uv_set_process_title(title);
   ASSERT(UV_OK == err.code);
 
   err = uv_get_process_title(buffer, sizeof(buffer));
   ASSERT(UV_OK == err.code);
 
-  ASSERT(strcmp(buffer, "new title") == 0);
+  ASSERT(strcmp(buffer, title) == 0);
+}
 
+
+TEST_IMPL(process_title) {
+  /* Check for format string vulnerabilities. */
+  set_title("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s");
+  set_title("new title");
   return 0;
 }
index eabbefc..6ce46b2 100644 (file)
@@ -37,9 +37,9 @@ static int close_cb_called = 0;
 
 
 static void shutdown_cb(uv_shutdown_t* req, int status) {
+  int err = uv_last_error(uv_default_loop()).code;
   ASSERT(req == &shutdown_req);
-  ASSERT(status == 0 ||
-         (status == -1 && uv_last_error(uv_default_loop()).code == UV_EINTR));
+  ASSERT(status == 0 || (status == -1 && err == UV_ECANCELED));
   shutdown_cb_called++;
 }
 
index 93e331d..90471ec 100644 (file)
@@ -38,7 +38,7 @@ static void close_cb(uv_handle_t* handle) {
 
 static void connect_cb(uv_connect_t* req, int status) {
   ASSERT(status == -1);
-  ASSERT(uv_last_error(req->handle->loop).code == UV_EINTR);
+  ASSERT(uv_last_error(req->handle->loop).code == UV_ECANCELED);
   uv_timer_stop(&timer2_handle);
   connect_cb_called++;
 }
index 7adb4da..45559c0 100644 (file)
@@ -49,6 +49,8 @@ static void timer_cb(uv_timer_t* handle, int status) {
 
 static uv_buf_t alloc_cb(uv_handle_t* handle, size_t suggested_size) {
   ASSERT(0 && "alloc_cb should not have been called");
+  /* Satisfy the compiler. */
+  return uv_buf_init(NULL, 0);
 }
 
 
index c14df2c..d6a9754 100644 (file)
@@ -52,6 +52,7 @@
         'include/uv-private/tree.h',
         'src/cares.c',
         'src/fs-poll.c',
+        'src/inet.c',
         'src/uv-common.c',
         'src/uv-common.h',
         'src/ares/ares_cancel.c',
         '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',