• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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