• 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/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