Merge github.com:grpc/grpc into always-use-port-server
diff --git a/CMakeLists.txt b/CMakeLists.txt
index ca0a668..abf5175 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1432,10 +1432,8 @@
   test/core/util/mock_endpoint.c
   test/core/util/parse_hexstring.c
   test/core/util/passthru_endpoint.c
-  test/core/util/port_posix.c
+  test/core/util/port.c
   test/core/util/port_server_client.c
-  test/core/util/port_uv.c
-  test/core/util/port_windows.c
   test/core/util/slice_splitter.c
   test/core/util/trickle_endpoint.c
   src/core/lib/channel/channel_args.c
@@ -1641,10 +1639,8 @@
   test/core/util/mock_endpoint.c
   test/core/util/parse_hexstring.c
   test/core/util/passthru_endpoint.c
-  test/core/util/port_posix.c
+  test/core/util/port.c
   test/core/util/port_server_client.c
-  test/core/util/port_uv.c
-  test/core/util/port_windows.c
   test/core/util/slice_splitter.c
   test/core/util/trickle_endpoint.c
 )
diff --git a/Makefile b/Makefile
index 93486bd..5898e70 100644
--- a/Makefile
+++ b/Makefile
@@ -3286,10 +3286,8 @@
     test/core/util/mock_endpoint.c \
     test/core/util/parse_hexstring.c \
     test/core/util/passthru_endpoint.c \
-    test/core/util/port_posix.c \
+    test/core/util/port.c \
     test/core/util/port_server_client.c \
-    test/core/util/port_uv.c \
-    test/core/util/port_windows.c \
     test/core/util/slice_splitter.c \
     test/core/util/trickle_endpoint.c \
     src/core/lib/channel/channel_args.c \
@@ -3488,10 +3486,8 @@
     test/core/util/mock_endpoint.c \
     test/core/util/parse_hexstring.c \
     test/core/util/passthru_endpoint.c \
-    test/core/util/port_posix.c \
+    test/core/util/port.c \
     test/core/util/port_server_client.c \
-    test/core/util/port_uv.c \
-    test/core/util/port_windows.c \
     test/core/util/slice_splitter.c \
     test/core/util/trickle_endpoint.c \
 
diff --git a/build.yaml b/build.yaml
index 55f0111..6a8a684 100644
--- a/build.yaml
+++ b/build.yaml
@@ -610,10 +610,8 @@
   - test/core/util/mock_endpoint.c
   - test/core/util/parse_hexstring.c
   - test/core/util/passthru_endpoint.c
-  - test/core/util/port_posix.c
+  - test/core/util/port.c
   - test/core/util/port_server_client.c
-  - test/core/util/port_uv.c
-  - test/core/util/port_windows.c
   - test/core/util/slice_splitter.c
   - test/core/util/trickle_endpoint.c
   deps:
diff --git a/test/core/util/BUILD b/test/core/util/BUILD
index 5c90f1d..e6d0d24 100644
--- a/test/core/util/BUILD
+++ b/test/core/util/BUILD
@@ -51,9 +51,8 @@
         "mock_endpoint.c",
         "parse_hexstring.c",
         "passthru_endpoint.c",
-        "port_posix.c",
+        "port.c",
         "port_server_client.c",
-        "port_windows.c",
         "reconnect_server.c",
         "slice_splitter.c",
         "test_tcp_server.c",
diff --git a/test/core/util/port_uv.c b/test/core/util/port.c
similarity index 78%
rename from test/core/util/port_uv.c
rename to test/core/util/port.c
index 0c9c0d8..da1ed4e 100644
--- a/test/core/util/port_uv.c
+++ b/test/core/util/port.c
@@ -33,17 +33,24 @@
 
 #include "src/core/lib/iomgr/port.h"
 #include "test/core/util/test_config.h"
-#if defined(GRPC_UV) && defined(GRPC_TEST_PICK_PORT)
+#if defined(GRPC_TEST_PICK_PORT)
 
+#include "test/core/util/port.h"
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <grpc/grpc.h>
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
 
-#include "src/core/lib/support/env.h"
-#include "test/core/util/port.h"
+#include "src/core/lib/http/httpcli.h"
+#include "src/core/lib/iomgr/resolve_address.h"
+#include "src/core/lib/iomgr/sockaddr_utils.h"
 #include "test/core/util/port_server_client.h"
 
-// Almost everything in this file has been copied from port_posix.c
-
 static int *chosen_ports = NULL;
 static size_t num_chosen_ports = 0;
 
@@ -51,7 +58,6 @@
   size_t i;
   int found = 0;
   size_t found_at = 0;
-  char *env = gpr_getenv("GRPC_TEST_PORT_SERVER");
   /* Find the port and erase it from the list, then tell the server it can be
      freed. */
   for (i = 0; i < num_chosen_ports; i++) {
@@ -64,24 +70,16 @@
   if (found) {
     chosen_ports[found_at] = chosen_ports[num_chosen_ports - 1];
     num_chosen_ports--;
-    if (env) {
-      grpc_free_port_using_server(env, port);
-    }
+    grpc_free_port_using_server(port);
   }
-  gpr_free(env);
   return found;
 }
 
 static void free_chosen_ports(void) {
-  char *env = gpr_getenv("GRPC_TEST_PORT_SERVER");
-  if (env != NULL) {
-    size_t i;
-    for (i = 0; i < num_chosen_ports; i++) {
-      grpc_free_port_using_server(env, chosen_ports[i]);
-    }
-    gpr_free(env);
+  size_t i;
+  for (i = 0; i < num_chosen_ports; i++) {
+    grpc_free_port_using_server(chosen_ports[i]);
   }
-
   gpr_free(chosen_ports);
 }
 
@@ -95,23 +93,27 @@
 }
 
 int grpc_pick_unused_port(void) {
-  // Currently only works with the port server
-  char *env = gpr_getenv("GRPC_TEST_PORT_SERVER");
-  GPR_ASSERT(env);
-  int port = grpc_pick_port_using_server(env);
-  gpr_free(env);
+  int port = grpc_pick_port_using_server();
   if (port != 0) {
     chose_port(port);
   }
+
   return port;
 }
 
 int grpc_pick_unused_port_or_die(void) {
   int port = grpc_pick_unused_port();
-  GPR_ASSERT(port > 0);
+  if (port == 0) {
+    fprintf(stderr,
+            "gRPC tests require a helper port server to allocate ports used \n"
+            "during the test.\n\n"
+            "This server is not currently running.\n\n"
+            "To start it, run tools/run_tests/start_port_server.py\n\n");
+    exit(1);
+  }
   return port;
 }
 
 void grpc_recycle_unused_port(int port) { GPR_ASSERT(free_chosen_port(port)); }
 
-#endif /* GRPC_UV && GRPC_TEST_PICK_PORT */
+#endif /* GRPC_TEST_PICK_PORT */
diff --git a/test/core/util/port_posix.c b/test/core/util/port_posix.c
deleted file mode 100644
index 4a42e4c..0000000
--- a/test/core/util/port_posix.c
+++ /dev/null
@@ -1,256 +0,0 @@
-/*
- *
- * Copyright 2015, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "src/core/lib/iomgr/port.h"
-#include "test/core/util/test_config.h"
-#if defined(GRPC_POSIX_SOCKET) && defined(GRPC_TEST_PICK_PORT)
-
-#include "test/core/util/port.h"
-
-#include <errno.h>
-#include <netinet/in.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/socket.h>
-#include <unistd.h>
-
-#include <grpc/grpc.h>
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/string_util.h>
-
-#include "src/core/lib/http/httpcli.h"
-#include "src/core/lib/iomgr/resolve_address.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
-#include "src/core/lib/support/env.h"
-#include "test/core/util/port_server_client.h"
-
-#define NUM_RANDOM_PORTS_TO_PICK 100
-
-static int *chosen_ports = NULL;
-static size_t num_chosen_ports = 0;
-
-static int has_port_been_chosen(int port) {
-  size_t i;
-  for (i = 0; i < num_chosen_ports; i++) {
-    if (chosen_ports[i] == port) {
-      return 1;
-    }
-  }
-  return 0;
-}
-
-static int free_chosen_port(int port) {
-  size_t i;
-  int found = 0;
-  size_t found_at = 0;
-  char *env = gpr_getenv("GRPC_TEST_PORT_SERVER");
-  /* Find the port and erase it from the list, then tell the server it can be
-     freed. */
-  for (i = 0; i < num_chosen_ports; i++) {
-    if (chosen_ports[i] == port) {
-      GPR_ASSERT(found == 0);
-      found = 1;
-      found_at = i;
-    }
-  }
-  if (found) {
-    chosen_ports[found_at] = chosen_ports[num_chosen_ports - 1];
-    num_chosen_ports--;
-    if (env) {
-      grpc_free_port_using_server(env, port);
-    }
-  }
-  gpr_free(env);
-  return found;
-}
-
-static void free_chosen_ports(void) {
-  char *env = gpr_getenv("GRPC_TEST_PORT_SERVER");
-  if (env != NULL) {
-    size_t i;
-    for (i = 0; i < num_chosen_ports; i++) {
-      grpc_free_port_using_server(env, chosen_ports[i]);
-    }
-    gpr_free(env);
-  }
-
-  gpr_free(chosen_ports);
-}
-
-static void chose_port(int port) {
-  if (chosen_ports == NULL) {
-    atexit(free_chosen_ports);
-  }
-  num_chosen_ports++;
-  chosen_ports = gpr_realloc(chosen_ports, sizeof(int) * num_chosen_ports);
-  chosen_ports[num_chosen_ports - 1] = port;
-}
-
-static bool is_port_available(int *port, bool is_tcp) {
-  GPR_ASSERT(*port >= 0);
-  GPR_ASSERT(*port <= 65535);
-
-  /* For a port to be considered available, the kernel must support
-     at least one of (IPv6, IPv4), and the port must be available
-     on each supported family. */
-  bool got_socket = false;
-  for (int is_ipv6 = 1; is_ipv6 >= 0; is_ipv6--) {
-    const int fd =
-        socket(is_ipv6 ? AF_INET6 : AF_INET, is_tcp ? SOCK_STREAM : SOCK_DGRAM,
-               is_tcp ? IPPROTO_TCP : 0);
-    if (fd >= 0) {
-      got_socket = true;
-    } else {
-      continue;
-    }
-
-    /* Reuseaddr lets us start up a server immediately after it exits */
-    const int one = 1;
-    if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0) {
-      gpr_log(GPR_ERROR, "setsockopt() failed: %s", strerror(errno));
-      close(fd);
-      return false;
-    }
-
-    /* Try binding to port */
-    grpc_resolved_address addr;
-    if (is_ipv6) {
-      grpc_sockaddr_make_wildcard6(*port, &addr); /* [::]:port */
-    } else {
-      grpc_sockaddr_make_wildcard4(*port, &addr); /* 0.0.0.0:port */
-    }
-    if (bind(fd, (struct sockaddr *)addr.addr, (socklen_t)addr.len) < 0) {
-      gpr_log(GPR_DEBUG, "bind(port=%d) failed: %s", *port, strerror(errno));
-      close(fd);
-      return false;
-    }
-
-    /* Get the bound port number */
-    if (getsockname(fd, (struct sockaddr *)addr.addr, (socklen_t *)&addr.len) <
-        0) {
-      gpr_log(GPR_ERROR, "getsockname() failed: %s", strerror(errno));
-      close(fd);
-      return false;
-    }
-    GPR_ASSERT(addr.len <= sizeof(addr.addr));
-    const int actual_port = grpc_sockaddr_get_port(&addr);
-    GPR_ASSERT(actual_port > 0);
-    if (*port == 0) {
-      *port = actual_port;
-    } else {
-      GPR_ASSERT(*port == actual_port);
-    }
-
-    close(fd);
-  }
-  if (!got_socket) {
-    gpr_log(GPR_ERROR, "socket() failed: %s", strerror(errno));
-    return false;
-  }
-  return true;
-}
-
-int grpc_pick_unused_port(void) {
-  /* We repeatedly pick a port and then see whether or not it is
-     available for use both as a TCP socket and a UDP socket.  First, we
-     pick a random large port number.  For subsequent
-     iterations, we bind to an anonymous port and let the OS pick the
-     port number.  The random port picking reduces the probability of
-     races with other processes on kernels that want to reuse the same
-     port numbers over and over. */
-
-  /* In alternating iterations we trial UDP ports before TCP ports UDP
-     ports -- it could be the case that this machine has been using up
-     UDP ports and they are scarcer. */
-
-  /* Type of port to first pick in next iteration */
-  bool is_tcp = true;
-  int trial = 0;
-
-  char *env = gpr_getenv("GRPC_TEST_PORT_SERVER");
-  if (env) {
-    int port = grpc_pick_port_using_server(env);
-    gpr_free(env);
-    if (port != 0) {
-      chose_port(port);
-    }
-    return port;
-  }
-
-  for (;;) {
-    int port;
-    trial++;
-    if (trial == 1) {
-      port = getpid() % (65536 - 30000) + 30000;
-    } else if (trial <= NUM_RANDOM_PORTS_TO_PICK) {
-      port = rand() % (65536 - 30000) + 30000;
-    } else {
-      port = 0;
-    }
-
-    if (has_port_been_chosen(port)) {
-      continue;
-    }
-
-    if (!is_port_available(&port, is_tcp)) {
-      continue;
-    }
-
-    GPR_ASSERT(port > 0);
-    /* Check that the port # is free for the other type of socket also */
-    if (!is_port_available(&port, !is_tcp)) {
-      /* In the next iteration trial to bind to the other type first
-         because perhaps it is more rare. */
-      is_tcp = !is_tcp;
-      continue;
-    }
-
-    chose_port(port);
-    return port;
-  }
-
-  /* The port iterator reached the end without finding a suitable port. */
-  return 0;
-}
-
-int grpc_pick_unused_port_or_die(void) {
-  int port = grpc_pick_unused_port();
-  GPR_ASSERT(port > 0);
-  return port;
-}
-
-void grpc_recycle_unused_port(int port) { GPR_ASSERT(free_chosen_port(port)); }
-
-#endif /* GRPC_POSIX_SOCKET && GRPC_TEST_PICK_PORT */
diff --git a/test/core/util/port_server_client.c b/test/core/util/port_server_client.c
index 7b733ab9c..455b4e0 100644
--- a/test/core/util/port_server_client.c
+++ b/test/core/util/port_server_client.c
@@ -74,7 +74,7 @@
   gpr_mu_unlock(pr->mu);
 }
 
-void grpc_free_port_using_server(char *server, int port) {
+void grpc_free_port_using_server(int port) {
   grpc_httpcli_context context;
   grpc_httpcli_request req;
   grpc_httpcli_response rsp;
@@ -95,7 +95,7 @@
   shutdown_closure = grpc_closure_create(destroy_pops_and_shutdown, &pr.pops,
                                          grpc_schedule_on_exec_ctx);
 
-  req.host = server;
+  req.host = GRPC_PORT_SERVER_ADDRESS;
   gpr_asprintf(&path, "/drop/%d", port);
   req.http.path = path;
 
@@ -198,7 +198,7 @@
   gpr_mu_unlock(pr->mu);
 }
 
-int grpc_pick_port_using_server(char *server) {
+int grpc_pick_port_using_server(void) {
   grpc_httpcli_context context;
   grpc_httpcli_request req;
   portreq pr;
@@ -215,10 +215,10 @@
   shutdown_closure = grpc_closure_create(destroy_pops_and_shutdown, &pr.pops,
                                          grpc_schedule_on_exec_ctx);
   pr.port = -1;
-  pr.server = server;
+  pr.server = GRPC_PORT_SERVER_ADDRESS;
   pr.ctx = &context;
 
-  req.host = server;
+  req.host = GRPC_PORT_SERVER_ADDRESS;
   req.http.path = "/get";
 
   grpc_httpcli_context_init(&context);
diff --git a/test/core/util/port_server_client.h b/test/core/util/port_server_client.h
index 4370064..70471ec 100644
--- a/test/core/util/port_server_client.h
+++ b/test/core/util/port_server_client.h
@@ -36,7 +36,10 @@
 
 // C interface to port_server.py
 
-int grpc_pick_port_using_server(char *server);
-void grpc_free_port_using_server(char *server, int port);
+// must be synchronized with tools/run_tests/python_utils/start_port_server.py
+#define GRPC_PORT_SERVER_ADDRESS "localhost:32766"
+
+int grpc_pick_port_using_server(void);
+void grpc_free_port_using_server(int port);
 
 #endif  // GRPC_TEST_CORE_UTIL_PORT_SERVER_CLIENT_H
diff --git a/test/core/util/port_windows.c b/test/core/util/port_windows.c
deleted file mode 100644
index 0c50a46..0000000
--- a/test/core/util/port_windows.c
+++ /dev/null
@@ -1,247 +0,0 @@
-/*
- *
- * Copyright 2015, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "src/core/lib/iomgr/port.h"
-#include "test/core/util/test_config.h"
-#if defined(GRPC_WINSOCK_SOCKET) && defined(GRPC_TEST_PICK_PORT)
-
-#include "src/core/lib/iomgr/sockaddr.h"
-
-#include "test/core/util/port.h"
-
-#include <errno.h>
-#include <process.h>
-#include <stdio.h>
-#include <string.h>
-
-#include <grpc/grpc.h>
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-
-#include "src/core/lib/http/httpcli.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
-#include "src/core/lib/support/env.h"
-#include "test/core/util/port_server_client.h"
-
-#if GPR_GETPID_IN_UNISTD_H
-#include <sys/unistd.h>
-static int _getpid() { return getpid(); }
-#endif
-
-#define NUM_RANDOM_PORTS_TO_PICK 100
-
-static int *chosen_ports = NULL;
-static size_t num_chosen_ports = 0;
-
-static int has_port_been_chosen(int port) {
-  size_t i;
-  for (i = 0; i < num_chosen_ports; i++) {
-    if (chosen_ports[i] == port) {
-      return 1;
-    }
-  }
-  return 0;
-}
-
-static int free_chosen_port(int port) {
-  size_t i;
-  int found = 0;
-  size_t found_at = 0;
-  char *env = gpr_getenv("GRPC_TEST_PORT_SERVER");
-  if (env != NULL) {
-    /* Find the port and erase it from the list, then tell the server it can be
-       freed. */
-    for (i = 0; i < num_chosen_ports; i++) {
-      if (chosen_ports[i] == port) {
-        GPR_ASSERT(found == 0);
-        found = 1;
-        found_at = i;
-      }
-    }
-    if (found) {
-      chosen_ports[found_at] = chosen_ports[num_chosen_ports - 1];
-      grpc_free_port_using_server(env, port);
-      num_chosen_ports--;
-    }
-  }
-  return found;
-}
-
-static void free_chosen_ports(void) {
-  char *env = gpr_getenv("GRPC_TEST_PORT_SERVER");
-  if (env != NULL) {
-    size_t i;
-    for (i = 0; i < num_chosen_ports; i++) {
-      grpc_free_port_using_server(env, chosen_ports[i]);
-    }
-    gpr_free(env);
-  }
-
-  gpr_free(chosen_ports);
-}
-
-static void chose_port(int port) {
-  if (chosen_ports == NULL) {
-    atexit(free_chosen_ports);
-  }
-  num_chosen_ports++;
-  chosen_ports = gpr_realloc(chosen_ports, sizeof(int) * num_chosen_ports);
-  chosen_ports[num_chosen_ports - 1] = port;
-}
-
-static int is_port_available(int *port, int is_tcp) {
-  const int proto = is_tcp ? IPPROTO_TCP : 0;
-  const SOCKET fd = socket(AF_INET, is_tcp ? SOCK_STREAM : SOCK_DGRAM, proto);
-  int one = 1;
-  struct sockaddr_in addr;
-  socklen_t alen = sizeof(addr);
-  int actual_port;
-
-  GPR_ASSERT(*port >= 0);
-  GPR_ASSERT(*port <= 65535);
-  if (INVALID_SOCKET == fd) {
-    gpr_log(GPR_ERROR, "socket() failed: %s", strerror(errno));
-    return 0;
-  }
-
-  /* Reuseaddr lets us start up a server immediately after it exits */
-  if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&one,
-                 sizeof(one)) < 0) {
-    gpr_log(GPR_ERROR, "setsockopt() failed: %s", strerror(errno));
-    closesocket(fd);
-    return 0;
-  }
-
-  /* Try binding to port */
-  addr.sin_family = AF_INET;
-  addr.sin_addr.s_addr = INADDR_ANY;
-  addr.sin_port = htons((u_short)*port);
-  if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
-    gpr_log(GPR_DEBUG, "bind(port=%d) failed: %s", *port, strerror(errno));
-    closesocket(fd);
-    return 0;
-  }
-
-  /* Get the bound port number */
-  if (getsockname(fd, (struct sockaddr *)&addr, &alen) < 0) {
-    gpr_log(GPR_ERROR, "getsockname() failed: %s", strerror(errno));
-    closesocket(fd);
-    return 0;
-  }
-  GPR_ASSERT(alen <= (socklen_t)sizeof(addr));
-  actual_port = ntohs(addr.sin_port);
-  GPR_ASSERT(actual_port > 0);
-  if (*port == 0) {
-    *port = actual_port;
-  } else {
-    GPR_ASSERT(*port == actual_port);
-  }
-
-  closesocket(fd);
-  return 1;
-}
-
-int grpc_pick_unused_port(void) {
-  /* We repeatedly pick a port and then see whether or not it is
-     available for use both as a TCP socket and a UDP socket.  First, we
-     pick a random large port number.  For subsequent
-     iterations, we bind to an anonymous port and let the OS pick the
-     port number.  The random port picking reduces the probability of
-     races with other processes on kernels that want to reuse the same
-     port numbers over and over. */
-
-  /* In alternating iterations we trial UDP ports before TCP ports UDP
-     ports -- it could be the case that this machine has been using up
-     UDP ports and they are scarcer. */
-
-  /* Type of port to first pick in next iteration */
-  int is_tcp = 1;
-  int trial = 0;
-
-  char *env = gpr_getenv("GRPC_TEST_PORT_SERVER");
-  if (env) {
-    int port = grpc_pick_port_using_server(env);
-    gpr_free(env);
-    if (port != 0) {
-      return port;
-    }
-  }
-
-  for (;;) {
-    int port;
-    trial++;
-    if (trial == 1) {
-      port = _getpid() % (65536 - 30000) + 30000;
-    } else if (trial <= NUM_RANDOM_PORTS_TO_PICK) {
-      port = rand() % (65536 - 30000) + 30000;
-    } else {
-      port = 0;
-    }
-
-    if (has_port_been_chosen(port)) {
-      continue;
-    }
-
-    if (!is_port_available(&port, is_tcp)) {
-      continue;
-    }
-
-    GPR_ASSERT(port > 0);
-    /* Check that the port # is free for the other type of socket also */
-    if (!is_port_available(&port, !is_tcp)) {
-      /* In the next iteration trial to bind to the other type first
-         because perhaps it is more rare. */
-      is_tcp = !is_tcp;
-      continue;
-    }
-
-    /* TODO(ctiller): consider caching this port in some structure, to avoid
-       handing it out again */
-
-    chose_port(port);
-    return port;
-  }
-
-  /* The port iterator reached the end without finding a suitable port. */
-  return 0;
-}
-
-int grpc_pick_unused_port_or_die(void) {
-  int port = grpc_pick_unused_port();
-  GPR_ASSERT(port > 0);
-  return port;
-}
-
-void grpc_recycle_unused_port(int port) { GPR_ASSERT(free_chosen_port(port)); }
-
-#endif /* GRPC_WINSOCK_SOCKET && GRPC_TEST_PICK_PORT */
diff --git a/tools/run_tests/generated/sources_and_headers.json b/tools/run_tests/generated/sources_and_headers.json
index 462353c..3e53ceb 100644
--- a/tools/run_tests/generated/sources_and_headers.json
+++ b/tools/run_tests/generated/sources_and_headers.json
@@ -7821,12 +7821,10 @@
       "test/core/util/parse_hexstring.h", 
       "test/core/util/passthru_endpoint.c", 
       "test/core/util/passthru_endpoint.h", 
+      "test/core/util/port.c", 
       "test/core/util/port.h", 
-      "test/core/util/port_posix.c", 
       "test/core/util/port_server_client.c", 
       "test/core/util/port_server_client.h", 
-      "test/core/util/port_uv.c", 
-      "test/core/util/port_windows.c", 
       "test/core/util/slice_splitter.c", 
       "test/core/util/slice_splitter.h", 
       "test/core/util/trickle_endpoint.c", 
diff --git a/tools/run_tests/python_utils/start_port_server.py b/tools/run_tests/python_utils/start_port_server.py
index 4c9f6aa..deb7354 100644
--- a/tools/run_tests/python_utils/start_port_server.py
+++ b/tools/run_tests/python_utils/start_port_server.py
@@ -40,7 +40,10 @@
 import time
 
 
-def start_port_server(port_server_port):
+# must be synchronized with test/core/utils/port_server_client.h
+_PORT_SERVER_PORT = 32766
+
+def start_port_server():
     # check if a compatible port server is running
     # if incompatible (version mismatch) ==> start a new one
     # if not running ==> start a new one
@@ -48,7 +51,7 @@
     try:
         version = int(
             urllib.request.urlopen(
-                'http://localhost:%d/version_number' % port_server_port,
+                'http://localhost:%d/version_number' % _PORT_SERVER_PORT,
                 timeout=10).read())
         logging.info('detected port server running version %d', version)
         running = True
@@ -67,7 +70,7 @@
         if not running:
             logging.info('port_server version mismatch: killing the old one')
             urllib.request.urlopen('http://localhost:%d/quitquitquit' %
-                                   port_server_port).read()
+                                   _PORT_SERVER_PORT).read()
             time.sleep(1)
     if not running:
         fd, logfile = tempfile.mkstemp()
@@ -76,7 +79,7 @@
         args = [
             sys.executable,
             os.path.abspath('tools/run_tests/python_utils/port_server.py'),
-            '-p', '%d' % port_server_port, '-l', logfile
+            '-p', '%d' % _PORT_SERVER_PORT, '-l', logfile
         ]
         env = dict(os.environ)
         env['BUILD_ID'] = 'pleaseDontKillMeJenkins'
@@ -107,7 +110,7 @@
                 time.sleep(1)
                 try:
                     urllib.request.urlopen(
-                        'http://localhost:%d/get' % port_server_port,
+                        'http://localhost:%d/get' % _PORT_SERVER_PORT,
                         timeout=1).read()
                     logging.info(
                         'last ditch attempt to contact port server succeeded')
@@ -119,7 +122,7 @@
                     print(port_log)
                     sys.exit(1)
             try:
-                port_server_url = 'http://localhost:%d/get' % port_server_port
+                port_server_url = 'http://localhost:%d/get' % _PORT_SERVER_PORT
                 urllib.request.urlopen(port_server_url, timeout=1).read()
                 logging.info('port server is up and ready')
                 break
diff --git a/tools/run_tests/run_microbenchmark.py b/tools/run_tests/run_microbenchmark.py
index b090847..1ab62ee 100755
--- a/tools/run_tests/run_microbenchmark.py
+++ b/tools/run_tests/run_microbenchmark.py
@@ -44,8 +44,7 @@
 if not os.path.exists('reports'):
   os.makedirs('reports')
 
-port_server_port = 32766
-start_port_server.start_port_server(port_server_port)
+start_port_server.start_port_server()
 
 def fnize(s):
   out = ''
@@ -110,8 +109,7 @@
     if len(benchmarks) >= min(16, multiprocessing.cpu_count()):
       # run up to half the cpu count: each benchmark can use up to two cores
       # (one for the microbenchmark, one for the data flush)
-      jobset.run(benchmarks, maxjobs=max(1, multiprocessing.cpu_count()/2),
-                 add_env={'GRPC_TEST_PORT_SERVER': 'localhost:%d' % port_server_port})
+      jobset.run(benchmarks, maxjobs=max(1, multiprocessing.cpu_count()/2))
       jobset.run(profile_analysis, maxjobs=multiprocessing.cpu_count())
       jobset.run(cleanup, maxjobs=multiprocessing.cpu_count())
       benchmarks = []
@@ -119,8 +117,7 @@
       cleanup = []
   # run the remaining benchmarks that weren't flushed
   if len(benchmarks):
-    jobset.run(benchmarks, maxjobs=max(1, multiprocessing.cpu_count()/2),
-               add_env={'GRPC_TEST_PORT_SERVER': 'localhost:%d' % port_server_port})
+    jobset.run(benchmarks, maxjobs=max(1, multiprocessing.cpu_count()/2))
     jobset.run(profile_analysis, maxjobs=multiprocessing.cpu_count())
     jobset.run(cleanup, maxjobs=multiprocessing.cpu_count())
 
@@ -156,8 +153,7 @@
     if len(benchmarks) >= 20:
       # run up to half the cpu count: each benchmark can use up to two cores
       # (one for the microbenchmark, one for the data flush)
-      jobset.run(benchmarks, maxjobs=1,
-                 add_env={'GRPC_TEST_PORT_SERVER': 'localhost:%d' % port_server_port})
+      jobset.run(benchmarks, maxjobs=1)
       jobset.run(profile_analysis, maxjobs=multiprocessing.cpu_count())
       jobset.run(cleanup, maxjobs=multiprocessing.cpu_count())
       benchmarks = []
@@ -165,8 +161,7 @@
       cleanup = []
   # run the remaining benchmarks that weren't flushed
   if len(benchmarks):
-    jobset.run(benchmarks, maxjobs=1,
-               add_env={'GRPC_TEST_PORT_SERVER': 'localhost:%d' % port_server_port})
+    jobset.run(benchmarks, maxjobs=1)
     jobset.run(profile_analysis, maxjobs=multiprocessing.cpu_count())
     jobset.run(cleanup, maxjobs=multiprocessing.cpu_count())
 
diff --git a/tools/run_tests/run_tests.py b/tools/run_tests/run_tests.py
index 2d9eb29..7c280eb 100755
--- a/tools/run_tests/run_tests.py
+++ b/tools/run_tests/run_tests.py
@@ -1438,8 +1438,7 @@
   # start antagonists
   antagonists = [subprocess.Popen(['tools/run_tests/python_utils/antagonist.py'])
                  for _ in range(0, args.antagonists)]
-  port_server_port = 32766
-  start_port_server.start_port_server(port_server_port)
+  start_port_server.start_port_server()
   resultset = None
   num_test_failures = 0
   try:
@@ -1482,7 +1481,6 @@
         all_runs, check_cancelled, newline_on_success=newline_on_success,
         travis=args.travis, maxjobs=args.jobs,
         stop_on_failure=args.stop_on_failure,
-        add_env={'GRPC_TEST_PORT_SERVER': 'localhost:%d' % port_server_port},
         quiet_success=args.quiet_success)
     if resultset:
       for k, v in sorted(resultset.items()):
diff --git a/tools/run_tests/start_port_server.py b/tools/run_tests/start_port_server.py
new file mode 100755
index 0000000..e33ac12
--- /dev/null
+++ b/tools/run_tests/start_port_server.py
@@ -0,0 +1,46 @@
+#!/usr/bin/env python
+
+# Copyright 2017, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""
+Wrapper around port server starting code.
+
+Used by developers who wish to run individual C/C++ tests outside of the
+run_tests.py infrastructure.
+
+The path to this file is called out in test/core/util/port.c, and printed as
+an error message to users.
+"""
+
+import python_utils.start_port_server as start_port_server
+
+start_port_server.start_port_server()
+
+print "Port server started successfully"
diff --git a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj
index 6d4b4f7..d08ceb6 100644
--- a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj
+++ b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj
@@ -335,14 +335,10 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\util\passthru_endpoint.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\test\core\util\port_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\test\core\util\port.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\util\port_server_client.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\test\core\util\port_uv.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\test\core\util\port_windows.c">
-    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\util\slice_splitter.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\util\trickle_endpoint.c">
diff --git a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters
index 5444f6f..3beaa80 100644
--- a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters
@@ -49,18 +49,12 @@
     <ClCompile Include="$(SolutionDir)\..\test\core\util\passthru_endpoint.c">
       <Filter>test\core\util</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\test\core\util\port_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\test\core\util\port.c">
       <Filter>test\core\util</Filter>
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\util\port_server_client.c">
       <Filter>test\core\util</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\test\core\util\port_uv.c">
-      <Filter>test\core\util</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\test\core\util\port_windows.c">
-      <Filter>test\core\util</Filter>
-    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\util\slice_splitter.c">
       <Filter>test\core\util</Filter>
     </ClCompile>
diff --git a/vsprojects/vcxproj/grpc_test_util_unsecure/grpc_test_util_unsecure.vcxproj b/vsprojects/vcxproj/grpc_test_util_unsecure/grpc_test_util_unsecure.vcxproj
index 1ea6465..5a58cae 100644
--- a/vsprojects/vcxproj/grpc_test_util_unsecure/grpc_test_util_unsecure.vcxproj
+++ b/vsprojects/vcxproj/grpc_test_util_unsecure/grpc_test_util_unsecure.vcxproj
@@ -186,14 +186,10 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\util\passthru_endpoint.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\test\core\util\port_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\test\core\util\port.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\util\port_server_client.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\test\core\util\port_uv.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\test\core\util\port_windows.c">
-    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\util\slice_splitter.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\util\trickle_endpoint.c">
diff --git a/vsprojects/vcxproj/grpc_test_util_unsecure/grpc_test_util_unsecure.vcxproj.filters b/vsprojects/vcxproj/grpc_test_util_unsecure/grpc_test_util_unsecure.vcxproj.filters
index e2ad88c..88c875c 100644
--- a/vsprojects/vcxproj/grpc_test_util_unsecure/grpc_test_util_unsecure.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc_test_util_unsecure/grpc_test_util_unsecure.vcxproj.filters
@@ -34,18 +34,12 @@
     <ClCompile Include="$(SolutionDir)\..\test\core\util\passthru_endpoint.c">
       <Filter>test\core\util</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\test\core\util\port_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\test\core\util\port.c">
       <Filter>test\core\util</Filter>
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\util\port_server_client.c">
       <Filter>test\core\util</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\test\core\util\port_uv.c">
-      <Filter>test\core\util</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\test\core\util\port_windows.c">
-      <Filter>test\core\util</Filter>
-    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\util\slice_splitter.c">
       <Filter>test\core\util</Filter>
     </ClCompile>