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/gprpp/crash.h"
37 #include "src/core/lib/iomgr/iocp_windows.h"
38 #include "src/core/lib/iomgr/iomgr_internal.h"
39 #include "src/core/lib/iomgr/pollset.h"
40 #include "src/core/lib/iomgr/pollset_windows.h"
41 #include "src/core/lib/iomgr/sockaddr_windows.h"
42 #include "src/core/lib/iomgr/socket_windows.h"
43
44 static DWORD s_wsa_socket_flags;
45
grpc_winsocket_create(SOCKET socket,const char * name)46 grpc_winsocket* grpc_winsocket_create(SOCKET socket, const char* name) {
47 grpc_winsocket* r = (grpc_winsocket*)gpr_malloc(sizeof(grpc_winsocket));
48 memset(r, 0, sizeof(grpc_winsocket));
49 r->socket = socket;
50 gpr_mu_init(&r->state_mu);
51 grpc_iomgr_register_object(
52 &r->iomgr_object, absl::StrFormat("%s:socket=0x%p", name, r).c_str());
53 grpc_iocp_add_socket(r);
54 return r;
55 }
56
grpc_winsocket_wrapped_socket(grpc_winsocket * socket)57 SOCKET grpc_winsocket_wrapped_socket(grpc_winsocket* socket) {
58 return socket->socket;
59 }
60
61 // Schedule a shutdown of the socket operations. Will call the pending
62 // operations to abort them. We need to do that this way because of the
63 // various callsites of that function, which happens to be in various
64 // mutex hold states, and that'd be unsafe to call them directly.
grpc_winsocket_shutdown(grpc_winsocket * winsocket)65 void grpc_winsocket_shutdown(grpc_winsocket* winsocket) {
66 // Grab the function pointer for DisconnectEx for that specific socket.
67 // It may change depending on the interface.
68 int status;
69 GUID guid = WSAID_DISCONNECTEX;
70 LPFN_DISCONNECTEX DisconnectEx;
71 DWORD ioctl_num_bytes;
72
73 gpr_mu_lock(&winsocket->state_mu);
74 if (winsocket->shutdown_called) {
75 gpr_mu_unlock(&winsocket->state_mu);
76 return;
77 }
78 winsocket->shutdown_called = true;
79 bool register_shutdown = false;
80 // If there is already a scheduled read closure, run it immediately. This
81 // follows the same semantics applied to posix endpoint which also runs any
82 // already registered closure immediately in the event of a shutdown.
83 if (winsocket->read_info.closure && !winsocket->read_info.has_pending_iocp) {
84 winsocket->read_info.bytes_transferred = 0;
85 winsocket->read_info.wsa_error = WSA_OPERATION_ABORTED;
86 grpc_core::ExecCtx::Run(DEBUG_LOCATION, winsocket->read_info.closure,
87 absl::OkStatus());
88 // Note that while the read_info.closure closure is run, it is not set to
89 // NULL here. This ensures that the socket cannot get deleted yet until any
90 // pending I/O operations are flushed by the thread executing
91 // grpc_iocp_work. We set read_info.closure_already_executed_at_shutdown to
92 // true so that when the pending read I/O operations are flushed, the
93 // associated closure is not executed in the grpc_socket_became_ready
94 // function.
95 winsocket->read_info.closure_already_executed_at_shutdown = true;
96 register_shutdown = true;
97 }
98
99 // If there is already a scheduled write closure, run it immediately. This
100 // follows the same semantics applied to posix endpoint which also runs any
101 // already registered closure immediately in the event of a shutdown.
102 if (winsocket->write_info.closure &&
103 !winsocket->write_info.has_pending_iocp) {
104 winsocket->write_info.bytes_transferred = 0;
105 winsocket->write_info.wsa_error = WSA_OPERATION_ABORTED;
106 grpc_core::ExecCtx::Run(DEBUG_LOCATION, winsocket->write_info.closure,
107 absl::OkStatus());
108 // Note that while the write_info.closure closure is run, it is not set to
109 // NULL here. This ensures that the socket cannot get deleted yet until any
110 // pending I/O operations are flushed by the thread executing
111 // grpc_iocp_work. We set
112 // write_info.closure.closure_already_executed_at_shutdown to true so that
113 // when the pending write I/O operations are flushed, the associated closure
114 // is not executed in the grpc_socket_became_ready function.
115 winsocket->write_info.closure_already_executed_at_shutdown = true;
116 register_shutdown = true;
117 }
118
119 if (register_shutdown) {
120 // Instruct gRPC to avoid completing any shutdowns until this socket is
121 // cleaned up.
122 grpc_iocp_register_socket_shutdown_socket_locked(winsocket);
123 }
124 gpr_mu_unlock(&winsocket->state_mu);
125
126 status = WSAIoctl(winsocket->socket, SIO_GET_EXTENSION_FUNCTION_POINTER,
127 &guid, sizeof(guid), &DisconnectEx, sizeof(DisconnectEx),
128 &ioctl_num_bytes, NULL, NULL);
129
130 if (status == 0) {
131 DisconnectEx(winsocket->socket, NULL, 0, 0);
132 } else {
133 char* utf8_message = gpr_format_message(WSAGetLastError());
134 gpr_log(GPR_INFO, "Unable to retrieve DisconnectEx pointer : %s",
135 utf8_message);
136 gpr_free(utf8_message);
137 }
138 // Calling closesocket triggers invocation of any pending I/O operations with
139 // ABORTED status.
140 closesocket(winsocket->socket);
141 }
142
destroy(grpc_winsocket * winsocket)143 static void destroy(grpc_winsocket* winsocket) {
144 grpc_iomgr_unregister_object(&winsocket->iomgr_object);
145 gpr_mu_destroy(&winsocket->state_mu);
146 gpr_free(winsocket);
147 }
148
check_destroyable(grpc_winsocket * winsocket)149 static bool check_destroyable(grpc_winsocket* winsocket) {
150 return winsocket->destroy_called == true &&
151 winsocket->write_info.closure == NULL &&
152 winsocket->read_info.closure == NULL;
153 }
154
grpc_winsocket_finish(grpc_winsocket * winsocket)155 void grpc_winsocket_finish(grpc_winsocket* winsocket) {
156 grpc_iocp_finish_socket_shutdown(winsocket);
157 destroy(winsocket);
158 }
159
grpc_winsocket_destroy(grpc_winsocket * winsocket)160 void grpc_winsocket_destroy(grpc_winsocket* winsocket) {
161 gpr_mu_lock(&winsocket->state_mu);
162 GPR_ASSERT(!winsocket->destroy_called);
163 winsocket->destroy_called = true;
164 bool should_destroy = check_destroyable(winsocket);
165 gpr_mu_unlock(&winsocket->state_mu);
166 if (should_destroy) {
167 grpc_winsocket_finish(winsocket);
168 }
169 }
170
171 // Calling notify_on_read or write means either of two things:
172 //-) The IOCP already completed in the background, and we need to call
173 // the callback now.
174 //-) 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)175 static void socket_notify_on_iocp(grpc_winsocket* socket, grpc_closure* closure,
176 grpc_winsocket_callback_info* info) {
177 GPR_ASSERT(info->closure == NULL);
178 gpr_mu_lock(&socket->state_mu);
179 if (info->has_pending_iocp) {
180 info->has_pending_iocp = 0;
181 grpc_core::ExecCtx::Run(DEBUG_LOCATION, closure, absl::OkStatus());
182 } else {
183 info->closure = closure;
184 }
185 gpr_mu_unlock(&socket->state_mu);
186 }
187
grpc_socket_notify_on_write(grpc_winsocket * socket,grpc_closure * closure)188 void grpc_socket_notify_on_write(grpc_winsocket* socket,
189 grpc_closure* closure) {
190 socket_notify_on_iocp(socket, closure, &socket->write_info);
191 }
192
grpc_socket_notify_on_read(grpc_winsocket * socket,grpc_closure * closure)193 void grpc_socket_notify_on_read(grpc_winsocket* socket, grpc_closure* closure) {
194 socket_notify_on_iocp(socket, closure, &socket->read_info);
195 }
196
grpc_socket_become_ready(grpc_winsocket * socket,grpc_winsocket_callback_info * info)197 bool grpc_socket_become_ready(grpc_winsocket* socket,
198 grpc_winsocket_callback_info* info) {
199 GPR_ASSERT(!info->has_pending_iocp);
200 if (info->closure) {
201 // Only run the closure once at shutdown.
202 if (!info->closure_already_executed_at_shutdown) {
203 grpc_core::ExecCtx::Run(DEBUG_LOCATION, info->closure, absl::OkStatus());
204 }
205 info->closure = NULL;
206 } else {
207 info->has_pending_iocp = 1;
208 }
209 return check_destroyable(socket);
210 }
211
212 static gpr_once g_probe_ipv6_once = GPR_ONCE_INIT;
213 static bool g_ipv6_loopback_available = false;
214
probe_ipv6_once(void)215 static void probe_ipv6_once(void) {
216 SOCKET s = socket(AF_INET6, SOCK_STREAM, 0);
217 g_ipv6_loopback_available = 0;
218 if (s == INVALID_SOCKET) {
219 gpr_log(GPR_INFO, "Disabling AF_INET6 sockets because socket() failed.");
220 } else {
221 grpc_sockaddr_in6 addr;
222 memset(&addr, 0, sizeof(addr));
223 addr.sin6_family = AF_INET6;
224 addr.sin6_addr.s6_addr[15] = 1; // [::1]:0
225 if (bind(s, reinterpret_cast<grpc_sockaddr*>(&addr), sizeof(addr)) == 0) {
226 g_ipv6_loopback_available = 1;
227 } else {
228 gpr_log(GPR_INFO,
229 "Disabling AF_INET6 sockets because ::1 is not available.");
230 }
231 closesocket(s);
232 }
233 }
234
grpc_ipv6_loopback_available(void)235 int grpc_ipv6_loopback_available(void) {
236 gpr_once_init(&g_probe_ipv6_once, probe_ipv6_once);
237 return g_ipv6_loopback_available;
238 }
239
grpc_get_default_wsa_socket_flags()240 DWORD grpc_get_default_wsa_socket_flags() { return s_wsa_socket_flags; }
241
grpc_wsa_socket_flags_init()242 void grpc_wsa_socket_flags_init() {
243 s_wsa_socket_flags = WSA_FLAG_OVERLAPPED;
244 // WSA_FLAG_NO_HANDLE_INHERIT may be not supported on the older Windows
245 // versions, see
246 // https://msdn.microsoft.com/en-us/library/windows/desktop/ms742212(v=vs.85).aspx
247 // for details.
248 SOCKET sock = WSASocket(AF_INET6, SOCK_STREAM, IPPROTO_TCP, NULL, 0,
249 s_wsa_socket_flags | WSA_FLAG_NO_HANDLE_INHERIT);
250 if (sock != INVALID_SOCKET) {
251 // Windows 7, Windows 2008 R2 with SP1 or later
252 s_wsa_socket_flags |= WSA_FLAG_NO_HANDLE_INHERIT;
253 closesocket(sock);
254 }
255 }
256
257 #endif // GRPC_WINSOCK_SOCKET
258