3 * Copyright 2015 gRPC authors.
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <grpc/support/port_platform.h>
21 #include "src/core/lib/iomgr/port.h"
23 #ifdef GRPC_WINSOCK_SOCKET
27 // must be included after winsock2.h
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>
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"
42 static DWORD s_wsa_socket_flags;
44 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));
49 gpr_mu_init(&r->state_mu);
50 gpr_asprintf(&final_name, "%s:socket=0x%p", name, r);
51 grpc_iomgr_register_object(&r->iomgr_object, final_name);
53 grpc_iocp_add_socket(r);
57 SOCKET grpc_winsocket_wrapped_socket(grpc_winsocket* socket) {
58 return socket->socket;
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. */
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. */
69 GUID guid = WSAID_DISCONNECTEX;
70 LPFN_DISCONNECTEX DisconnectEx;
71 DWORD ioctl_num_bytes;
73 gpr_mu_lock(&winsocket->state_mu);
74 if (winsocket->shutdown_called) {
75 gpr_mu_unlock(&winsocket->state_mu);
78 winsocket->shutdown_called = true;
79 gpr_mu_unlock(&winsocket->state_mu);
81 status = WSAIoctl(winsocket->socket, SIO_GET_EXTENSION_FUNCTION_POINTER,
82 &guid, sizeof(guid), &DisconnectEx, sizeof(DisconnectEx),
83 &ioctl_num_bytes, NULL, NULL);
86 DisconnectEx(winsocket->socket, NULL, 0, 0);
88 char* utf8_message = gpr_format_message(WSAGetLastError());
89 gpr_log(GPR_INFO, "Unable to retrieve DisconnectEx pointer : %s",
91 gpr_free(utf8_message);
93 closesocket(winsocket->socket);
96 static void destroy(grpc_winsocket* winsocket) {
97 grpc_iomgr_unregister_object(&winsocket->iomgr_object);
98 gpr_mu_destroy(&winsocket->state_mu);
102 static bool check_destroyable(grpc_winsocket* winsocket) {
103 return winsocket->destroy_called == true &&
104 winsocket->write_info.closure == NULL &&
105 winsocket->read_info.closure == NULL;
108 void grpc_winsocket_destroy(grpc_winsocket* winsocket) {
109 gpr_mu_lock(&winsocket->state_mu);
110 GPR_ASSERT(!winsocket->destroy_called);
111 winsocket->destroy_called = true;
112 bool should_destroy = check_destroyable(winsocket);
113 gpr_mu_unlock(&winsocket->state_mu);
114 if (should_destroy) destroy(winsocket);
117 /* Calling notify_on_read or write means either of two things:
118 -) The IOCP already completed in the background, and we need to call
120 -) The IOCP hasn't completed yet, and we're queuing it for later. */
121 static void socket_notify_on_iocp(grpc_winsocket* socket, grpc_closure* closure,
122 grpc_winsocket_callback_info* info) {
123 GPR_ASSERT(info->closure == NULL);
124 gpr_mu_lock(&socket->state_mu);
125 if (info->has_pending_iocp) {
126 info->has_pending_iocp = 0;
127 GRPC_CLOSURE_SCHED(closure, GRPC_ERROR_NONE);
129 info->closure = closure;
131 gpr_mu_unlock(&socket->state_mu);
134 void grpc_socket_notify_on_write(grpc_winsocket* socket,
135 grpc_closure* closure) {
136 socket_notify_on_iocp(socket, closure, &socket->write_info);
139 void grpc_socket_notify_on_read(grpc_winsocket* socket, grpc_closure* closure) {
140 socket_notify_on_iocp(socket, closure, &socket->read_info);
143 void grpc_socket_become_ready(grpc_winsocket* socket,
144 grpc_winsocket_callback_info* info) {
145 GPR_ASSERT(!info->has_pending_iocp);
146 gpr_mu_lock(&socket->state_mu);
148 GRPC_CLOSURE_SCHED(info->closure, GRPC_ERROR_NONE);
149 info->closure = NULL;
151 info->has_pending_iocp = 1;
153 bool should_destroy = check_destroyable(socket);
154 gpr_mu_unlock(&socket->state_mu);
155 if (should_destroy) destroy(socket);
158 static gpr_once g_probe_ipv6_once = GPR_ONCE_INIT;
159 static bool g_ipv6_loopback_available = false;
161 static void probe_ipv6_once(void) {
162 SOCKET s = socket(AF_INET6, SOCK_STREAM, 0);
163 g_ipv6_loopback_available = 0;
164 if (s == INVALID_SOCKET) {
165 gpr_log(GPR_INFO, "Disabling AF_INET6 sockets because socket() failed.");
167 grpc_sockaddr_in6 addr;
168 memset(&addr, 0, sizeof(addr));
169 addr.sin6_family = AF_INET6;
170 addr.sin6_addr.s6_addr[15] = 1; /* [::1]:0 */
171 if (bind(s, reinterpret_cast<grpc_sockaddr*>(&addr), sizeof(addr)) == 0) {
172 g_ipv6_loopback_available = 1;
175 "Disabling AF_INET6 sockets because ::1 is not available.");
181 int grpc_ipv6_loopback_available(void) {
182 gpr_once_init(&g_probe_ipv6_once, probe_ipv6_once);
183 return g_ipv6_loopback_available;
186 DWORD grpc_get_default_wsa_socket_flags() { return s_wsa_socket_flags; }
188 void grpc_wsa_socket_flags_init() {
189 s_wsa_socket_flags = WSA_FLAG_OVERLAPPED;
190 /* WSA_FLAG_NO_HANDLE_INHERIT may be not supported on the older Windows
192 https://msdn.microsoft.com/en-us/library/windows/desktop/ms742212(v=vs.85).aspx
194 SOCKET sock = WSASocket(AF_INET6, SOCK_STREAM, IPPROTO_TCP, NULL, 0,
195 s_wsa_socket_flags | WSA_FLAG_NO_HANDLE_INHERIT);
196 if (sock != INVALID_SOCKET) {
197 /* Windows 7, Windows 2008 R2 with SP1 or later */
198 s_wsa_socket_flags |= WSA_FLAG_NO_HANDLE_INHERIT;
203 #endif /* GRPC_WINSOCK_SOCKET */