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 "absl/strings/str_format.h"
31
32 #include <grpc/support/alloc.h>
33 #include <grpc/support/log.h>
34 #include <grpc/support/log_windows.h>
35
36 #include "src/core/lib/iomgr/iocp_windows.h"
37 #include "src/core/lib/iomgr/iomgr_internal.h"
38 #include "src/core/lib/iomgr/pollset.h"
39 #include "src/core/lib/iomgr/pollset_windows.h"
40 #include "src/core/lib/iomgr/sockaddr_windows.h"
41 #include "src/core/lib/iomgr/socket_windows.h"
42
43 static DWORD s_wsa_socket_flags;
44
grpc_winsocket_create(SOCKET socket,const char * name)45 grpc_winsocket* grpc_winsocket_create(SOCKET socket, const char* name) {
46 grpc_winsocket* r = (grpc_winsocket*)gpr_malloc(sizeof(grpc_winsocket));
47 memset(r, 0, sizeof(grpc_winsocket));
48 r->socket = socket;
49 gpr_mu_init(&r->state_mu);
50 grpc_iomgr_register_object(
51 &r->iomgr_object, absl::StrFormat("%s:socket=0x%p", name, r).c_str());
52 grpc_iocp_add_socket(r);
53 return r;
54 }
55
grpc_winsocket_wrapped_socket(grpc_winsocket * socket)56 SOCKET grpc_winsocket_wrapped_socket(grpc_winsocket* socket) {
57 return socket->socket;
58 }
59
60 /* Schedule a shutdown of the socket operations. Will call the pending
61 operations to abort them. We need to do that this way because of the
62 various callsites of that function, which happens to be in various
63 mutex hold states, and that'd be unsafe to call them directly. */
grpc_winsocket_shutdown(grpc_winsocket * winsocket)64 void grpc_winsocket_shutdown(grpc_winsocket* winsocket) {
65 /* Grab the function pointer for DisconnectEx for that specific socket.
66 It may change depending on the interface. */
67 int status;
68 GUID guid = WSAID_DISCONNECTEX;
69 LPFN_DISCONNECTEX DisconnectEx;
70 DWORD ioctl_num_bytes;
71
72 gpr_mu_lock(&winsocket->state_mu);
73 if (winsocket->shutdown_called) {
74 gpr_mu_unlock(&winsocket->state_mu);
75 return;
76 }
77 winsocket->shutdown_called = true;
78 gpr_mu_unlock(&winsocket->state_mu);
79
80 status = WSAIoctl(winsocket->socket, SIO_GET_EXTENSION_FUNCTION_POINTER,
81 &guid, sizeof(guid), &DisconnectEx, sizeof(DisconnectEx),
82 &ioctl_num_bytes, NULL, NULL);
83
84 if (status == 0) {
85 DisconnectEx(winsocket->socket, NULL, 0, 0);
86 } else {
87 char* utf8_message = gpr_format_message(WSAGetLastError());
88 gpr_log(GPR_INFO, "Unable to retrieve DisconnectEx pointer : %s",
89 utf8_message);
90 gpr_free(utf8_message);
91 }
92 closesocket(winsocket->socket);
93 }
94
destroy(grpc_winsocket * winsocket)95 static void destroy(grpc_winsocket* winsocket) {
96 grpc_iomgr_unregister_object(&winsocket->iomgr_object);
97 gpr_mu_destroy(&winsocket->state_mu);
98 gpr_free(winsocket);
99 }
100
check_destroyable(grpc_winsocket * winsocket)101 static bool check_destroyable(grpc_winsocket* winsocket) {
102 return winsocket->destroy_called == true &&
103 winsocket->write_info.closure == NULL &&
104 winsocket->read_info.closure == NULL;
105 }
106
grpc_winsocket_destroy(grpc_winsocket * winsocket)107 void grpc_winsocket_destroy(grpc_winsocket* winsocket) {
108 gpr_mu_lock(&winsocket->state_mu);
109 GPR_ASSERT(!winsocket->destroy_called);
110 winsocket->destroy_called = true;
111 bool should_destroy = check_destroyable(winsocket);
112 gpr_mu_unlock(&winsocket->state_mu);
113 if (should_destroy) destroy(winsocket);
114 }
115
116 /* Calling notify_on_read or write means either of two things:
117 -) The IOCP already completed in the background, and we need to call
118 the callback now.
119 -) The IOCP hasn't completed yet, and we're queuing it for later. */
socket_notify_on_iocp(grpc_winsocket * socket,grpc_closure * closure,grpc_winsocket_callback_info * info)120 static void socket_notify_on_iocp(grpc_winsocket* socket, grpc_closure* closure,
121 grpc_winsocket_callback_info* info) {
122 GPR_ASSERT(info->closure == NULL);
123 gpr_mu_lock(&socket->state_mu);
124 if (info->has_pending_iocp) {
125 info->has_pending_iocp = 0;
126 grpc_core::ExecCtx::Run(DEBUG_LOCATION, closure, GRPC_ERROR_NONE);
127 } else {
128 info->closure = closure;
129 }
130 gpr_mu_unlock(&socket->state_mu);
131 }
132
grpc_socket_notify_on_write(grpc_winsocket * socket,grpc_closure * closure)133 void grpc_socket_notify_on_write(grpc_winsocket* socket,
134 grpc_closure* closure) {
135 socket_notify_on_iocp(socket, closure, &socket->write_info);
136 }
137
grpc_socket_notify_on_read(grpc_winsocket * socket,grpc_closure * closure)138 void grpc_socket_notify_on_read(grpc_winsocket* socket, grpc_closure* closure) {
139 socket_notify_on_iocp(socket, closure, &socket->read_info);
140 }
141
grpc_socket_become_ready(grpc_winsocket * socket,grpc_winsocket_callback_info * info)142 void grpc_socket_become_ready(grpc_winsocket* socket,
143 grpc_winsocket_callback_info* info) {
144 GPR_ASSERT(!info->has_pending_iocp);
145 gpr_mu_lock(&socket->state_mu);
146 if (info->closure) {
147 grpc_core::ExecCtx::Run(DEBUG_LOCATION, info->closure, GRPC_ERROR_NONE);
148 info->closure = NULL;
149 } else {
150 info->has_pending_iocp = 1;
151 }
152 bool should_destroy = check_destroyable(socket);
153 gpr_mu_unlock(&socket->state_mu);
154 if (should_destroy) destroy(socket);
155 }
156
157 static gpr_once g_probe_ipv6_once = GPR_ONCE_INIT;
158 static bool g_ipv6_loopback_available = false;
159
probe_ipv6_once(void)160 static void probe_ipv6_once(void) {
161 SOCKET s = socket(AF_INET6, SOCK_STREAM, 0);
162 g_ipv6_loopback_available = 0;
163 if (s == INVALID_SOCKET) {
164 gpr_log(GPR_INFO, "Disabling AF_INET6 sockets because socket() failed.");
165 } else {
166 grpc_sockaddr_in6 addr;
167 memset(&addr, 0, sizeof(addr));
168 addr.sin6_family = AF_INET6;
169 addr.sin6_addr.s6_addr[15] = 1; /* [::1]:0 */
170 if (bind(s, reinterpret_cast<grpc_sockaddr*>(&addr), sizeof(addr)) == 0) {
171 g_ipv6_loopback_available = 1;
172 } else {
173 gpr_log(GPR_INFO,
174 "Disabling AF_INET6 sockets because ::1 is not available.");
175 }
176 closesocket(s);
177 }
178 }
179
grpc_ipv6_loopback_available(void)180 int grpc_ipv6_loopback_available(void) {
181 gpr_once_init(&g_probe_ipv6_once, probe_ipv6_once);
182 return g_ipv6_loopback_available;
183 }
184
grpc_get_default_wsa_socket_flags()185 DWORD grpc_get_default_wsa_socket_flags() { return s_wsa_socket_flags; }
186
grpc_wsa_socket_flags_init()187 void grpc_wsa_socket_flags_init() {
188 s_wsa_socket_flags = WSA_FLAG_OVERLAPPED;
189 /* WSA_FLAG_NO_HANDLE_INHERIT may be not supported on the older Windows
190 versions, see
191 https://msdn.microsoft.com/en-us/library/windows/desktop/ms742212(v=vs.85).aspx
192 for details. */
193 SOCKET sock = WSASocket(AF_INET6, SOCK_STREAM, IPPROTO_TCP, NULL, 0,
194 s_wsa_socket_flags | WSA_FLAG_NO_HANDLE_INHERIT);
195 if (sock != INVALID_SOCKET) {
196 /* Windows 7, Windows 2008 R2 with SP1 or later */
197 s_wsa_socket_flags |= WSA_FLAG_NO_HANDLE_INHERIT;
198 closesocket(sock);
199 }
200 }
201
202 #endif /* GRPC_WINSOCK_SOCKET */
203