• 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 <grpc/support/alloc.h>
31 #include <grpc/support/log.h>
32 #include <grpc/support/log_windows.h>
33 #include <grpc/support/string_util.h>
34 
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"
41 
grpc_winsocket_create(SOCKET socket,const char * name)42 grpc_winsocket* grpc_winsocket_create(SOCKET socket, const char* name) {
43   char* final_name;
44   grpc_winsocket* r = (grpc_winsocket*)gpr_malloc(sizeof(grpc_winsocket));
45   memset(r, 0, sizeof(grpc_winsocket));
46   r->socket = socket;
47   gpr_mu_init(&r->state_mu);
48   gpr_asprintf(&final_name, "%s:socket=0x%p", name, r);
49   grpc_iomgr_register_object(&r->iomgr_object, final_name);
50   gpr_free(final_name);
51   grpc_iocp_add_socket(r);
52   return r;
53 }
54 
grpc_winsocket_wrapped_socket(grpc_winsocket * socket)55 SOCKET grpc_winsocket_wrapped_socket(grpc_winsocket* socket) {
56   return socket->socket;
57 }
58 
59 /* Schedule a shutdown of the socket operations. Will call the pending
60    operations to abort them. We need to do that this way because of the
61    various callsites of that function, which happens to be in various
62    mutex hold states, and that'd be unsafe to call them directly. */
grpc_winsocket_shutdown(grpc_winsocket * winsocket)63 void grpc_winsocket_shutdown(grpc_winsocket* winsocket) {
64   /* Grab the function pointer for DisconnectEx for that specific socket.
65      It may change depending on the interface. */
66   int status;
67   GUID guid = WSAID_DISCONNECTEX;
68   LPFN_DISCONNECTEX DisconnectEx;
69   DWORD ioctl_num_bytes;
70 
71   gpr_mu_lock(&winsocket->state_mu);
72   if (winsocket->shutdown_called) {
73     gpr_mu_unlock(&winsocket->state_mu);
74     return;
75   }
76   winsocket->shutdown_called = true;
77   gpr_mu_unlock(&winsocket->state_mu);
78 
79   status = WSAIoctl(winsocket->socket, SIO_GET_EXTENSION_FUNCTION_POINTER,
80                     &guid, sizeof(guid), &DisconnectEx, sizeof(DisconnectEx),
81                     &ioctl_num_bytes, NULL, NULL);
82 
83   if (status == 0) {
84     DisconnectEx(winsocket->socket, NULL, 0, 0);
85   } else {
86     char* utf8_message = gpr_format_message(WSAGetLastError());
87     gpr_log(GPR_INFO, "Unable to retrieve DisconnectEx pointer : %s",
88             utf8_message);
89     gpr_free(utf8_message);
90   }
91   closesocket(winsocket->socket);
92 }
93 
destroy(grpc_winsocket * winsocket)94 static void destroy(grpc_winsocket* winsocket) {
95   grpc_iomgr_unregister_object(&winsocket->iomgr_object);
96   gpr_mu_destroy(&winsocket->state_mu);
97   gpr_free(winsocket);
98 }
99 
check_destroyable(grpc_winsocket * winsocket)100 static bool check_destroyable(grpc_winsocket* winsocket) {
101   return winsocket->destroy_called == true &&
102          winsocket->write_info.closure == NULL &&
103          winsocket->read_info.closure == NULL;
104 }
105 
grpc_winsocket_destroy(grpc_winsocket * winsocket)106 void grpc_winsocket_destroy(grpc_winsocket* winsocket) {
107   gpr_mu_lock(&winsocket->state_mu);
108   GPR_ASSERT(!winsocket->destroy_called);
109   winsocket->destroy_called = true;
110   bool should_destroy = check_destroyable(winsocket);
111   gpr_mu_unlock(&winsocket->state_mu);
112   if (should_destroy) destroy(winsocket);
113 }
114 
115 /* Calling notify_on_read or write means either of two things:
116 -) The IOCP already completed in the background, and we need to call
117 the callback now.
118 -) 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)119 static void socket_notify_on_iocp(grpc_winsocket* socket, grpc_closure* closure,
120                                   grpc_winsocket_callback_info* info) {
121   GPR_ASSERT(info->closure == NULL);
122   gpr_mu_lock(&socket->state_mu);
123   if (info->has_pending_iocp) {
124     info->has_pending_iocp = 0;
125     GRPC_CLOSURE_SCHED(closure, GRPC_ERROR_NONE);
126   } else {
127     info->closure = closure;
128   }
129   gpr_mu_unlock(&socket->state_mu);
130 }
131 
grpc_socket_notify_on_write(grpc_winsocket * socket,grpc_closure * closure)132 void grpc_socket_notify_on_write(grpc_winsocket* socket,
133                                  grpc_closure* closure) {
134   socket_notify_on_iocp(socket, closure, &socket->write_info);
135 }
136 
grpc_socket_notify_on_read(grpc_winsocket * socket,grpc_closure * closure)137 void grpc_socket_notify_on_read(grpc_winsocket* socket, grpc_closure* closure) {
138   socket_notify_on_iocp(socket, closure, &socket->read_info);
139 }
140 
grpc_socket_become_ready(grpc_winsocket * socket,grpc_winsocket_callback_info * info)141 void grpc_socket_become_ready(grpc_winsocket* socket,
142                               grpc_winsocket_callback_info* info) {
143   GPR_ASSERT(!info->has_pending_iocp);
144   gpr_mu_lock(&socket->state_mu);
145   if (info->closure) {
146     GRPC_CLOSURE_SCHED(info->closure, GRPC_ERROR_NONE);
147     info->closure = NULL;
148   } else {
149     info->has_pending_iocp = 1;
150   }
151   bool should_destroy = check_destroyable(socket);
152   gpr_mu_unlock(&socket->state_mu);
153   if (should_destroy) destroy(socket);
154 }
155 
156 static gpr_once g_probe_ipv6_once = GPR_ONCE_INIT;
157 static bool g_ipv6_loopback_available = false;
158 
probe_ipv6_once(void)159 static void probe_ipv6_once(void) {
160   SOCKET s = socket(AF_INET6, SOCK_STREAM, 0);
161   g_ipv6_loopback_available = 0;
162   if (s == INVALID_SOCKET) {
163     gpr_log(GPR_INFO, "Disabling AF_INET6 sockets because socket() failed.");
164   } else {
165     grpc_sockaddr_in6 addr;
166     memset(&addr, 0, sizeof(addr));
167     addr.sin6_family = AF_INET6;
168     addr.sin6_addr.s6_addr[15] = 1; /* [::1]:0 */
169     if (bind(s, reinterpret_cast<grpc_sockaddr*>(&addr), sizeof(addr)) == 0) {
170       g_ipv6_loopback_available = 1;
171     } else {
172       gpr_log(GPR_INFO,
173               "Disabling AF_INET6 sockets because ::1 is not available.");
174     }
175     closesocket(s);
176   }
177 }
178 
grpc_ipv6_loopback_available(void)179 int grpc_ipv6_loopback_available(void) {
180   gpr_once_init(&g_probe_ipv6_once, probe_ipv6_once);
181   return g_ipv6_loopback_available;
182 }
183 
184 #endif /* GRPC_WINSOCK_SOCKET */
185