1 /* 2 * 3 * Copyright 2015 gRPC authors. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 */ 18 19 #include <grpc/support/port_platform.h> 20 21 #include "src/core/lib/iomgr/port.h" 22 23 #ifdef GRPC_WINSOCK_SOCKET 24 25 #include <winsock2.h> 26 27 // must be included after winsock2.h 28 #include <mswsock.h> 29 30 #include <grpc/support/alloc.h> 31 #include <grpc/support/log.h> 32 #include <grpc/support/log_windows.h> 33 #include <grpc/support/string_util.h> 34 35 #include "src/core/lib/iomgr/iocp_windows.h" 36 #include "src/core/lib/iomgr/iomgr_internal.h" 37 #include "src/core/lib/iomgr/pollset.h" 38 #include "src/core/lib/iomgr/pollset_windows.h" 39 #include "src/core/lib/iomgr/sockaddr_windows.h" 40 #include "src/core/lib/iomgr/socket_windows.h" 41 42 grpc_winsocket* grpc_winsocket_create(SOCKET socket, const char* name) { 43 char* final_name; 44 grpc_winsocket* r = (grpc_winsocket*)gpr_malloc(sizeof(grpc_winsocket)); 45 memset(r, 0, sizeof(grpc_winsocket)); 46 r->socket = socket; 47 gpr_mu_init(&r->state_mu); 48 gpr_asprintf(&final_name, "%s:socket=0x%p", name, r); 49 grpc_iomgr_register_object(&r->iomgr_object, final_name); 50 gpr_free(final_name); 51 grpc_iocp_add_socket(r); 52 return r; 53 } 54 55 SOCKET grpc_winsocket_wrapped_socket(grpc_winsocket* socket) { 56 return socket->socket; 57 } 58 59 /* Schedule a shutdown of the socket operations. Will call the pending 60 operations to abort them. We need to do that this way because of the 61 various callsites of that function, which happens to be in various 62 mutex hold states, and that'd be unsafe to call them directly. */ 63 void grpc_winsocket_shutdown(grpc_winsocket* winsocket) { 64 /* Grab the function pointer for DisconnectEx for that specific socket. 65 It may change depending on the interface. */ 66 int status; 67 GUID guid = WSAID_DISCONNECTEX; 68 LPFN_DISCONNECTEX DisconnectEx; 69 DWORD ioctl_num_bytes; 70 71 gpr_mu_lock(&winsocket->state_mu); 72 if (winsocket->shutdown_called) { 73 gpr_mu_unlock(&winsocket->state_mu); 74 return; 75 } 76 winsocket->shutdown_called = true; 77 gpr_mu_unlock(&winsocket->state_mu); 78 79 status = WSAIoctl(winsocket->socket, SIO_GET_EXTENSION_FUNCTION_POINTER, 80 &guid, sizeof(guid), &DisconnectEx, sizeof(DisconnectEx), 81 &ioctl_num_bytes, NULL, NULL); 82 83 if (status == 0) { 84 DisconnectEx(winsocket->socket, NULL, 0, 0); 85 } else { 86 char* utf8_message = gpr_format_message(WSAGetLastError()); 87 gpr_log(GPR_INFO, "Unable to retrieve DisconnectEx pointer : %s", 88 utf8_message); 89 gpr_free(utf8_message); 90 } 91 closesocket(winsocket->socket); 92 } 93 94 static void destroy(grpc_winsocket* winsocket) { 95 grpc_iomgr_unregister_object(&winsocket->iomgr_object); 96 gpr_mu_destroy(&winsocket->state_mu); 97 gpr_free(winsocket); 98 } 99 100 static bool check_destroyable(grpc_winsocket* winsocket) { 101 return winsocket->destroy_called == true && 102 winsocket->write_info.closure == NULL && 103 winsocket->read_info.closure == NULL; 104 } 105 106 void grpc_winsocket_destroy(grpc_winsocket* winsocket) { 107 gpr_mu_lock(&winsocket->state_mu); 108 GPR_ASSERT(!winsocket->destroy_called); 109 winsocket->destroy_called = true; 110 bool should_destroy = check_destroyable(winsocket); 111 gpr_mu_unlock(&winsocket->state_mu); 112 if (should_destroy) destroy(winsocket); 113 } 114 115 /* Calling notify_on_read or write means either of two things: 116 -) The IOCP already completed in the background, and we need to call 117 the callback now. 118 -) The IOCP hasn't completed yet, and we're queuing it for later. */ 119 static void socket_notify_on_iocp(grpc_winsocket* socket, grpc_closure* closure, 120 grpc_winsocket_callback_info* info) { 121 GPR_ASSERT(info->closure == NULL); 122 gpr_mu_lock(&socket->state_mu); 123 if (info->has_pending_iocp) { 124 info->has_pending_iocp = 0; 125 GRPC_CLOSURE_SCHED(closure, GRPC_ERROR_NONE); 126 } else { 127 info->closure = closure; 128 } 129 gpr_mu_unlock(&socket->state_mu); 130 } 131 132 void grpc_socket_notify_on_write(grpc_winsocket* socket, 133 grpc_closure* closure) { 134 socket_notify_on_iocp(socket, closure, &socket->write_info); 135 } 136 137 void grpc_socket_notify_on_read(grpc_winsocket* socket, grpc_closure* closure) { 138 socket_notify_on_iocp(socket, closure, &socket->read_info); 139 } 140 141 void grpc_socket_become_ready(grpc_winsocket* socket, 142 grpc_winsocket_callback_info* info) { 143 GPR_ASSERT(!info->has_pending_iocp); 144 gpr_mu_lock(&socket->state_mu); 145 if (info->closure) { 146 GRPC_CLOSURE_SCHED(info->closure, GRPC_ERROR_NONE); 147 info->closure = NULL; 148 } else { 149 info->has_pending_iocp = 1; 150 } 151 bool should_destroy = check_destroyable(socket); 152 gpr_mu_unlock(&socket->state_mu); 153 if (should_destroy) destroy(socket); 154 } 155 156 static gpr_once g_probe_ipv6_once = GPR_ONCE_INIT; 157 static bool g_ipv6_loopback_available = false; 158 159 static void probe_ipv6_once(void) { 160 SOCKET s = socket(AF_INET6, SOCK_STREAM, 0); 161 g_ipv6_loopback_available = 0; 162 if (s == INVALID_SOCKET) { 163 gpr_log(GPR_INFO, "Disabling AF_INET6 sockets because socket() failed."); 164 } else { 165 grpc_sockaddr_in6 addr; 166 memset(&addr, 0, sizeof(addr)); 167 addr.sin6_family = AF_INET6; 168 addr.sin6_addr.s6_addr[15] = 1; /* [::1]:0 */ 169 if (bind(s, reinterpret_cast<grpc_sockaddr*>(&addr), sizeof(addr)) == 0) { 170 g_ipv6_loopback_available = 1; 171 } else { 172 gpr_log(GPR_INFO, 173 "Disabling AF_INET6 sockets because ::1 is not available."); 174 } 175 closesocket(s); 176 } 177 } 178 179 int grpc_ipv6_loopback_available(void) { 180 gpr_once_init(&g_probe_ipv6_once, probe_ipv6_once); 181 return g_ipv6_loopback_available; 182 } 183 184 #endif /* GRPC_WINSOCK_SOCKET */ 185