socket_windows.cc
Go to the documentation of this file.
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 
20 
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>
35 
42 
43 static DWORD s_wsa_socket_flags;
44 
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);
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 
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. */
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 
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 
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 
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. */
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;
127  } else {
128  info->closure = closure;
129  }
130  gpr_mu_unlock(&socket->state_mu);
131 }
132 
133 void grpc_socket_notify_on_write(grpc_winsocket* socket,
135  socket_notify_on_iocp(socket, closure, &socket->write_info);
136 }
137 
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 
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) {
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 
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 {
174  "Disabling AF_INET6 sockets because ::1 is not available.");
175  }
176  closesocket(s);
177  }
178 }
179 
181  gpr_once_init(&g_probe_ipv6_once, probe_ipv6_once);
182  return g_ipv6_loopback_available;
183 }
184 
185 DWORD grpc_get_default_wsa_socket_flags() { return s_wsa_socket_flags; }
186 
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 */
GPR_INFO
#define GPR_INFO
Definition: include/grpc/impl/codegen/log.h:56
gpr_mu_unlock
GPRAPI void gpr_mu_unlock(gpr_mu *mu)
pollset.h
GRPC_ERROR_NONE
#define GRPC_ERROR_NONE
Definition: error.h:234
log.h
AF_INET6
#define AF_INET6
Definition: ares_setup.h:208
pollset_windows.h
memset
return memset(p, 0, total)
absl::StrFormat
ABSL_MUST_USE_RESULT std::string StrFormat(const FormatSpec< Args... > &format, const Args &... args)
Definition: abseil-cpp/absl/strings/str_format.h:338
gpr_once
pthread_once_t gpr_once
Definition: impl/codegen/sync_posix.h:50
iomgr_internal.h
gpr_free
GPRAPI void gpr_free(void *ptr)
Definition: alloc.cc:51
gpr_format_message
GPRAPI char * gpr_format_message(int messageid)
gpr_malloc
GPRAPI void * gpr_malloc(size_t size)
Definition: alloc.cc:29
status
absl::Status status
Definition: rls.cc:251
socket_windows.h
GPR_ONCE_INIT
#define GPR_ONCE_INIT
Definition: impl/codegen/sync_posix.h:52
setup.name
name
Definition: setup.py:542
absl::FormatConversionChar::s
@ s
iocp_windows.h
grpc_iomgr_unregister_object
void grpc_iomgr_unregister_object(grpc_iomgr_object *obj)
Definition: iomgr.cc:193
gpr_once_init
GPRAPI void gpr_once_init(gpr_once *once, void(*init_function)(void))
grpc_ipv6_loopback_available
int grpc_ipv6_loopback_available(void)
gpr_mu_destroy
GPRAPI void gpr_mu_destroy(gpr_mu *mu)
DEBUG_LOCATION
#define DEBUG_LOCATION
Definition: debug_location.h:41
GPR_ASSERT
#define GPR_ASSERT(x)
Definition: include/grpc/impl/codegen/log.h:94
gpr_log
GPRAPI void gpr_log(const char *file, int line, gpr_log_severity severity, const char *format,...) GPR_PRINT_FORMAT_CHECK(4
gpr_mu_init
GPRAPI void gpr_mu_init(gpr_mu *mu)
closure
grpc_closure closure
Definition: src/core/lib/surface/server.cc:466
gpr_mu_lock
GPRAPI void gpr_mu_lock(gpr_mu *mu)
grpc_iomgr_register_object
void grpc_iomgr_register_object(grpc_iomgr_object *obj, const char *name)
Definition: iomgr.cc:184
LPFN_DISCONNECTEX
BOOL(PASCAL * LPFN_DISCONNECTEX)(SOCKET hSocket, LPOVERLAPPED lpOverlapped, DWORD dwFlags, DWORD reserved)
Definition: win.h:159
port.h
WSAID_DISCONNECTEX
#define WSAID_DISCONNECTEX
Definition: win.h:121
alloc.h
fix_build_deps.r
r
Definition: fix_build_deps.py:491
log_windows.h
sockaddr_windows.h
closure
Definition: proxy.cc:59
grpc_core::ExecCtx::Run
static void Run(const DebugLocation &location, grpc_closure *closure, grpc_error_handle error)
Definition: exec_ctx.cc:98
test_server.socket
socket
Definition: test_server.py:65
closesocket
static int closesocket(int sock)
Definition: bio_test.cc:46
grpc_closure
Definition: closure.h:56
addr
struct sockaddr_in addr
Definition: libuv/docs/code/tcp-echo-server/main.c:10
destroy
static std::function< void(void *, Slot *)> destroy
Definition: abseil-cpp/absl/container/internal/hash_policy_traits_test.cc:42
port_platform.h


grpc
Author(s):
autogenerated on Thu Mar 13 2025 03:01:19