Built motion from commit 6a09e18b.|2.6.11
[motion2.git] / legacy-libs / grpc-cloned / deps / grpc / src / core / lib / iomgr / socket_windows.cc
diff --git a/legacy-libs/grpc-cloned/deps/grpc/src/core/lib/iomgr/socket_windows.cc b/legacy-libs/grpc-cloned/deps/grpc/src/core/lib/iomgr/socket_windows.cc
new file mode 100644 (file)
index 0000000..c87cfa8
--- /dev/null
@@ -0,0 +1,203 @@
+/*
+ *
+ * Copyright 2015 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#include "src/core/lib/iomgr/port.h"
+
+#ifdef GRPC_WINSOCK_SOCKET
+
+#include <winsock2.h>
+
+// must be included after winsock2.h
+#include <mswsock.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/log_windows.h>
+#include <grpc/support/string_util.h>
+
+#include "src/core/lib/iomgr/iocp_windows.h"
+#include "src/core/lib/iomgr/iomgr_internal.h"
+#include "src/core/lib/iomgr/pollset.h"
+#include "src/core/lib/iomgr/pollset_windows.h"
+#include "src/core/lib/iomgr/sockaddr_windows.h"
+#include "src/core/lib/iomgr/socket_windows.h"
+
+static DWORD s_wsa_socket_flags;
+
+grpc_winsocket* grpc_winsocket_create(SOCKET socket, const char* name) {
+  char* final_name;
+  grpc_winsocket* r = (grpc_winsocket*)gpr_malloc(sizeof(grpc_winsocket));
+  memset(r, 0, sizeof(grpc_winsocket));
+  r->socket = socket;
+  gpr_mu_init(&r->state_mu);
+  gpr_asprintf(&final_name, "%s:socket=0x%p", name, r);
+  grpc_iomgr_register_object(&r->iomgr_object, final_name);
+  gpr_free(final_name);
+  grpc_iocp_add_socket(r);
+  return r;
+}
+
+SOCKET grpc_winsocket_wrapped_socket(grpc_winsocket* socket) {
+  return socket->socket;
+}
+
+/* Schedule a shutdown of the socket operations. Will call the pending
+   operations to abort them. We need to do that this way because of the
+   various callsites of that function, which happens to be in various
+   mutex hold states, and that'd be unsafe to call them directly. */
+void grpc_winsocket_shutdown(grpc_winsocket* winsocket) {
+  /* Grab the function pointer for DisconnectEx for that specific socket.
+     It may change depending on the interface. */
+  int status;
+  GUID guid = WSAID_DISCONNECTEX;
+  LPFN_DISCONNECTEX DisconnectEx;
+  DWORD ioctl_num_bytes;
+
+  gpr_mu_lock(&winsocket->state_mu);
+  if (winsocket->shutdown_called) {
+    gpr_mu_unlock(&winsocket->state_mu);
+    return;
+  }
+  winsocket->shutdown_called = true;
+  gpr_mu_unlock(&winsocket->state_mu);
+
+  status = WSAIoctl(winsocket->socket, SIO_GET_EXTENSION_FUNCTION_POINTER,
+                    &guid, sizeof(guid), &DisconnectEx, sizeof(DisconnectEx),
+                    &ioctl_num_bytes, NULL, NULL);
+
+  if (status == 0) {
+    DisconnectEx(winsocket->socket, NULL, 0, 0);
+  } else {
+    char* utf8_message = gpr_format_message(WSAGetLastError());
+    gpr_log(GPR_INFO, "Unable to retrieve DisconnectEx pointer : %s",
+            utf8_message);
+    gpr_free(utf8_message);
+  }
+  closesocket(winsocket->socket);
+}
+
+static void destroy(grpc_winsocket* winsocket) {
+  grpc_iomgr_unregister_object(&winsocket->iomgr_object);
+  gpr_mu_destroy(&winsocket->state_mu);
+  gpr_free(winsocket);
+}
+
+static bool check_destroyable(grpc_winsocket* winsocket) {
+  return winsocket->destroy_called == true &&
+         winsocket->write_info.closure == NULL &&
+         winsocket->read_info.closure == NULL;
+}
+
+void grpc_winsocket_destroy(grpc_winsocket* winsocket) {
+  gpr_mu_lock(&winsocket->state_mu);
+  GPR_ASSERT(!winsocket->destroy_called);
+  winsocket->destroy_called = true;
+  bool should_destroy = check_destroyable(winsocket);
+  gpr_mu_unlock(&winsocket->state_mu);
+  if (should_destroy) destroy(winsocket);
+}
+
+/* Calling notify_on_read or write means either of two things:
+-) The IOCP already completed in the background, and we need to call
+the callback now.
+-) The IOCP hasn't completed yet, and we're queuing it for later. */
+static void socket_notify_on_iocp(grpc_winsocket* socket, grpc_closure* closure,
+                                  grpc_winsocket_callback_info* info) {
+  GPR_ASSERT(info->closure == NULL);
+  gpr_mu_lock(&socket->state_mu);
+  if (info->has_pending_iocp) {
+    info->has_pending_iocp = 0;
+    GRPC_CLOSURE_SCHED(closure, GRPC_ERROR_NONE);
+  } else {
+    info->closure = closure;
+  }
+  gpr_mu_unlock(&socket->state_mu);
+}
+
+void grpc_socket_notify_on_write(grpc_winsocket* socket,
+                                 grpc_closure* closure) {
+  socket_notify_on_iocp(socket, closure, &socket->write_info);
+}
+
+void grpc_socket_notify_on_read(grpc_winsocket* socket, grpc_closure* closure) {
+  socket_notify_on_iocp(socket, closure, &socket->read_info);
+}
+
+void grpc_socket_become_ready(grpc_winsocket* socket,
+                              grpc_winsocket_callback_info* info) {
+  GPR_ASSERT(!info->has_pending_iocp);
+  gpr_mu_lock(&socket->state_mu);
+  if (info->closure) {
+    GRPC_CLOSURE_SCHED(info->closure, GRPC_ERROR_NONE);
+    info->closure = NULL;
+  } else {
+    info->has_pending_iocp = 1;
+  }
+  bool should_destroy = check_destroyable(socket);
+  gpr_mu_unlock(&socket->state_mu);
+  if (should_destroy) destroy(socket);
+}
+
+static gpr_once g_probe_ipv6_once = GPR_ONCE_INIT;
+static bool g_ipv6_loopback_available = false;
+
+static void probe_ipv6_once(void) {
+  SOCKET s = socket(AF_INET6, SOCK_STREAM, 0);
+  g_ipv6_loopback_available = 0;
+  if (s == INVALID_SOCKET) {
+    gpr_log(GPR_INFO, "Disabling AF_INET6 sockets because socket() failed.");
+  } else {
+    grpc_sockaddr_in6 addr;
+    memset(&addr, 0, sizeof(addr));
+    addr.sin6_family = AF_INET6;
+    addr.sin6_addr.s6_addr[15] = 1; /* [::1]:0 */
+    if (bind(s, reinterpret_cast<grpc_sockaddr*>(&addr), sizeof(addr)) == 0) {
+      g_ipv6_loopback_available = 1;
+    } else {
+      gpr_log(GPR_INFO,
+              "Disabling AF_INET6 sockets because ::1 is not available.");
+    }
+    closesocket(s);
+  }
+}
+
+int grpc_ipv6_loopback_available(void) {
+  gpr_once_init(&g_probe_ipv6_once, probe_ipv6_once);
+  return g_ipv6_loopback_available;
+}
+
+DWORD grpc_get_default_wsa_socket_flags() { return s_wsa_socket_flags; }
+
+void grpc_wsa_socket_flags_init() {
+  s_wsa_socket_flags = WSA_FLAG_OVERLAPPED;
+  /* WSA_FLAG_NO_HANDLE_INHERIT may be not supported on the older Windows
+     versions, see
+     https://msdn.microsoft.com/en-us/library/windows/desktop/ms742212(v=vs.85).aspx
+     for details. */
+  SOCKET sock = WSASocket(AF_INET6, SOCK_STREAM, IPPROTO_TCP, NULL, 0,
+                          s_wsa_socket_flags | WSA_FLAG_NO_HANDLE_INHERIT);
+  if (sock != INVALID_SOCKET) {
+    /* Windows 7, Windows 2008 R2 with SP1 or later */
+    s_wsa_socket_flags |= WSA_FLAG_NO_HANDLE_INHERIT;
+    closesocket(sock);
+  }
+}
+
+#endif /* GRPC_WINSOCK_SOCKET */