tcp_client_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 
21 #include <inttypes.h>
22 
24 
25 #ifdef GRPC_WINSOCK_SOCKET
26 
27 #include <grpc/slice_buffer.h>
28 #include <grpc/support/alloc.h>
29 #include <grpc/support/log.h>
31 
42 
43 struct async_connect {
44  grpc_closure* on_done;
45  gpr_mu mu;
46  grpc_winsocket* socket;
47  grpc_timer alarm;
48  grpc_closure on_alarm;
49  std::string addr_name;
50  int refs;
52  grpc_endpoint** endpoint;
53  grpc_channel_args* channel_args;
54 };
55 
56 static void async_connect_unlock_and_cleanup(async_connect* ac,
57  grpc_winsocket* socket) {
58  int done = (--ac->refs == 0);
59  gpr_mu_unlock(&ac->mu);
60  if (done) {
61  grpc_channel_args_destroy(ac->channel_args);
62  gpr_mu_destroy(&ac->mu);
63  delete ac;
64  }
65  if (socket != NULL) grpc_winsocket_destroy(socket);
66 }
67 
68 static void on_alarm(void* acp, grpc_error_handle error) {
69  async_connect* ac = (async_connect*)acp;
70  gpr_mu_lock(&ac->mu);
71  grpc_winsocket* socket = ac->socket;
72  ac->socket = NULL;
73  if (socket != NULL) {
74  grpc_winsocket_shutdown(socket);
75  }
76  async_connect_unlock_and_cleanup(ac, socket);
77 }
78 
79 static void on_connect(void* acp, grpc_error_handle error) {
80  async_connect* ac = (async_connect*)acp;
81  grpc_endpoint** ep = ac->endpoint;
82  GPR_ASSERT(*ep == NULL);
83  grpc_closure* on_done = ac->on_done;
84 
85  (void)GRPC_ERROR_REF(error);
86 
87  gpr_mu_lock(&ac->mu);
88  grpc_winsocket* socket = ac->socket;
89  ac->socket = NULL;
90  gpr_mu_unlock(&ac->mu);
91 
92  grpc_timer_cancel(&ac->alarm);
93 
94  gpr_mu_lock(&ac->mu);
95 
97  if (socket != NULL) {
98  DWORD transfered_bytes = 0;
99  DWORD flags;
100  BOOL wsa_success =
101  WSAGetOverlappedResult(socket->socket, &socket->write_info.overlapped,
102  &transfered_bytes, FALSE, &flags);
103  GPR_ASSERT(transfered_bytes == 0);
104  if (!wsa_success) {
105  error = GRPC_WSA_ERROR(WSAGetLastError(), "ConnectEx");
106  closesocket(socket->socket);
107  } else {
108  *ep = grpc_tcp_create(socket, ac->channel_args, ac->addr_name);
109  socket = nullptr;
110  }
111  } else {
112  error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("socket is null");
113  }
114  }
115 
116  async_connect_unlock_and_cleanup(ac, socket);
117  /* If the connection was aborted, the callback was already called when
118  the deadline was met. */
120 }
121 
122 /* Tries to issue one async connection, then schedules both an IOCP
123  notification request for the connection, and one timeout alert. */
124 static int64_t tcp_connect(grpc_closure* on_done, grpc_endpoint** endpoint,
125  grpc_pollset_set* interested_parties,
126  const grpc_channel_args* channel_args,
128  grpc_core::Timestamp deadline) {
129  SOCKET sock = INVALID_SOCKET;
130  BOOL success;
131  int status;
132  grpc_resolved_address addr6_v4mapped;
133  grpc_resolved_address local_address;
134  grpc_winsocket* socket = NULL;
135  LPFN_CONNECTEX ConnectEx;
136  GUID guid = WSAID_CONNECTEX;
137  DWORD ioctl_num_bytes;
138  grpc_winsocket_callback_info* info;
140  async_connect* ac = NULL;
142 
143  addr_uri = grpc_sockaddr_to_uri(addr);
144  if (!addr_uri.ok()) {
146  goto failure;
147  }
148 
149  *endpoint = NULL;
150 
151  /* Use dualstack sockets where available. */
152  if (grpc_sockaddr_to_v4mapped(addr, &addr6_v4mapped)) {
153  addr = &addr6_v4mapped;
154  }
155 
156  sock = WSASocket(AF_INET6, SOCK_STREAM, IPPROTO_TCP, NULL, 0,
157  grpc_get_default_wsa_socket_flags());
158  if (sock == INVALID_SOCKET) {
159  error = GRPC_WSA_ERROR(WSAGetLastError(), "WSASocket");
160  goto failure;
161  }
162 
163  error = grpc_tcp_prepare_socket(sock);
164  if (!GRPC_ERROR_IS_NONE(error)) {
165  goto failure;
166  }
167 
168  /* Grab the function pointer for ConnectEx for that specific socket.
169  It may change depending on the interface. */
170  status =
171  WSAIoctl(sock, SIO_GET_EXTENSION_FUNCTION_POINTER, &guid, sizeof(guid),
172  &ConnectEx, sizeof(ConnectEx), &ioctl_num_bytes, NULL, NULL);
173 
174  if (status != 0) {
175  error = GRPC_WSA_ERROR(WSAGetLastError(),
176  "WSAIoctl(SIO_GET_EXTENSION_FUNCTION_POINTER)");
177  goto failure;
178  }
179 
180  grpc_sockaddr_make_wildcard6(0, &local_address);
181 
182  status =
183  bind(sock, (grpc_sockaddr*)&local_address.addr, (int)local_address.len);
184  if (status != 0) {
185  error = GRPC_WSA_ERROR(WSAGetLastError(), "bind");
186  goto failure;
187  }
188 
189  socket = grpc_winsocket_create(sock, "client");
190  info = &socket->write_info;
191  success = ConnectEx(sock, (grpc_sockaddr*)&addr->addr, (int)addr->len, NULL,
192  0, NULL, &info->overlapped);
193 
194  /* It wouldn't be unusual to get a success immediately. But we'll still get
195  an IOCP notification, so let's ignore it. */
196  if (!success) {
197  int last_error = WSAGetLastError();
198  if (last_error != ERROR_IO_PENDING) {
199  error = GRPC_WSA_ERROR(last_error, "ConnectEx");
200  goto failure;
201  }
202  }
203 
204  ac = new async_connect();
205  ac->on_done = on_done;
206  ac->socket = socket;
207  gpr_mu_init(&ac->mu);
208  ac->refs = 2;
209  ac->addr_name = addr_uri.value();
210  ac->endpoint = endpoint;
211  ac->channel_args = grpc_channel_args_copy(channel_args);
212  GRPC_CLOSURE_INIT(&ac->on_connect, on_connect, ac, grpc_schedule_on_exec_ctx);
213 
214  GRPC_CLOSURE_INIT(&ac->on_alarm, on_alarm, ac, grpc_schedule_on_exec_ctx);
215  gpr_mu_lock(&ac->mu);
216  grpc_timer_init(&ac->alarm, deadline, &ac->on_alarm);
217  grpc_socket_notify_on_write(socket, &ac->on_connect);
218  gpr_mu_unlock(&ac->mu);
219  return 0;
220 
221 failure:
225  &error, 1),
227  addr_uri.ok() ? *addr_uri : addr_uri.status().ToString());
229  if (socket != NULL) {
230  grpc_winsocket_destroy(socket);
231  } else if (sock != INVALID_SOCKET) {
232  closesocket(sock);
233  }
234  grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_done, final_error);
235  return 0;
236 }
237 
238 static bool tcp_cancel_connect(int64_t /*connection_handle*/) { return false; }
239 
240 grpc_tcp_client_vtable grpc_windows_tcp_client_vtable = {tcp_connect,
241  tcp_cancel_connect};
242 
243 #endif /* GRPC_WINSOCK_SOCKET */
GRPC_CLOSURE_INIT
#define GRPC_CLOSURE_INIT(closure, cb, cb_arg, scheduler)
Definition: closure.h:115
gpr_mu_unlock
GPRAPI void gpr_mu_unlock(gpr_mu *mu)
GRPC_ERROR_NONE
#define GRPC_ERROR_NONE
Definition: error.h:234
log.h
sockaddr_utils.h
LPFN_CONNECTEX
BOOL(PASCAL * LPFN_CONNECTEX)(SOCKET s, const struct sockaddr *name, int namelen, PVOID lpSendBuffer, DWORD dwSendDataLength, LPDWORD lpdwBytesSent, LPOVERLAPPED lpOverlapped)
Definition: win.h:140
AF_INET6
#define AF_INET6
Definition: ares_setup.h:208
absl::Status::ToString
std::string ToString(StatusToStringMode mode=StatusToStringMode::kDefault) const
Definition: third_party/abseil-cpp/absl/status/status.h:821
grpc_pollset_set
struct grpc_pollset_set grpc_pollset_set
Definition: iomgr_fwd.h:23
grpc_core::Timestamp
Definition: src/core/lib/gprpp/time.h:62
testing::internal::string
::std::string string
Definition: bloaty/third_party/protobuf/third_party/googletest/googletest/include/gtest/internal/gtest-port.h:881
error
grpc_error_handle error
Definition: retry_filter.cc:499
grpc_resolved_address
Definition: resolved_address.h:34
GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING
#define GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(desc, errs, count)
Definition: error.h:307
status
absl::Status status
Definition: rls.cc:251
socket_windows.h
grpc_timer
Definition: iomgr/timer.h:33
sockaddr.h
iocp_windows.h
grpc_channel_args
Definition: grpc_types.h:132
BOOL
int BOOL
Definition: undname.c:46
grpc_error_set_str
grpc_error_handle grpc_error_set_str(grpc_error_handle src, grpc_error_strs which, absl::string_view str)
Definition: error.cc:650
GRPC_ERROR_STR_TARGET_ADDRESS
@ GRPC_ERROR_STR_TARGET_ADDRESS
peer that we were trying to communicate when this error occurred
Definition: error.h:117
gpr_mu_destroy
GPRAPI void gpr_mu_destroy(gpr_mu *mu)
DEBUG_LOCATION
#define DEBUG_LOCATION
Definition: debug_location.h:41
GRPC_WSA_ERROR
#define GRPC_WSA_ERROR(err, call_name)
windows only: create an error associated with WSAGetLastError()!=0
Definition: error.h:357
refs
std::vector< CordRep * > refs
Definition: cordz_info_statistics_test.cc:81
GPR_ASSERT
#define GPR_ASSERT(x)
Definition: include/grpc/impl/codegen/log.h:94
int64_t
signed __int64 int64_t
Definition: stdint-msvc2008.h:89
mu
Mutex mu
Definition: server_config_selector_filter.cc:74
gpr_mu_init
GPRAPI void gpr_mu_init(gpr_mu *mu)
grpc_tcp_create
grpc_endpoint * grpc_tcp_create(grpc_fd *fd, const grpc_channel_args *args, absl::string_view peer_string)
done
struct tab * done
Definition: bloaty/third_party/zlib/examples/enough.c:176
slice_buffer.h
grpc_channel_args_destroy
void grpc_channel_args_destroy(grpc_channel_args *a)
Definition: channel_args.cc:360
grpc_channel_args_copy
grpc_channel_args * grpc_channel_args_copy(const grpc_channel_args *src)
Definition: channel_args.cc:285
gpr_mu_lock
GPRAPI void gpr_mu_lock(gpr_mu *mu)
grpc_resolved_address::len
socklen_t len
Definition: resolved_address.h:36
slice_internal.h
grpc_sockaddr_to_v4mapped
int grpc_sockaddr_to_v4mapped(const grpc_resolved_address *resolved_addr, grpc_resolved_address *resolved_addr6_out)
Definition: sockaddr_utils.cc:111
tcp_client.h
on_connect
void on_connect(uv_connect_t *req, int status)
Definition: libuv/docs/code/dns/main.c:32
GRPC_ERROR_CREATE_FROM_STATIC_STRING
#define GRPC_ERROR_CREATE_FROM_STATIC_STRING(desc)
Definition: error.h:291
tcp_windows.h
grpc_timer_cancel
void grpc_timer_cancel(grpc_timer *timer)
Definition: iomgr/timer.cc:36
FALSE
const BOOL FALSE
Definition: undname.c:47
absl::StatusOr::ok
ABSL_MUST_USE_RESULT bool ok() const
Definition: abseil-cpp/absl/status/statusor.h:491
GRPC_ERROR_REF
#define GRPC_ERROR_REF(err)
Definition: error.h:261
absl::flags_internal
Definition: abseil-cpp/absl/flags/commandlineflag.h:40
gpr_mu
pthread_mutex_t gpr_mu
Definition: impl/codegen/sync_posix.h:47
port.h
GRPC_ERROR_CREATE_FROM_CPP_STRING
#define GRPC_ERROR_CREATE_FROM_CPP_STRING(desc)
Definition: error.h:297
alloc.h
grpc_sockaddr_make_wildcard6
void grpc_sockaddr_make_wildcard6(int port, grpc_resolved_address *resolved_wild_out)
Definition: sockaddr_utils.cc:183
log_windows.h
sockaddr_windows.h
grpc_timer_init
void grpc_timer_init(grpc_timer *timer, grpc_core::Timestamp deadline, grpc_closure *closure)
Definition: iomgr/timer.cc:31
GRPC_ERROR_UNREF
#define GRPC_ERROR_UNREF(err)
Definition: error.h:262
grpc_core::ExecCtx::Run
static void Run(const DebugLocation &location, grpc_closure *closure, grpc_error_handle error)
Definition: exec_ctx.cc:98
channel_args.h
timer.h
WSAID_CONNECTEX
#define WSAID_CONNECTEX
Definition: win.h:113
test_server.socket
socket
Definition: test_server.py:65
closesocket
static int closesocket(int sock)
Definition: bio_test.cc:46
grpc_tcp_client_vtable
Definition: tcp_client.h:32
flags
uint32_t flags
Definition: retry_filter.cc:632
absl::StatusOr::value
const T & value() const &ABSL_ATTRIBUTE_LIFETIME_BOUND
Definition: abseil-cpp/absl/status/statusor.h:687
absl::StatusOr< std::string >
grpc_error
Definition: error_internal.h:42
grpc_closure
Definition: closure.h:56
grpc_sockaddr_to_uri
absl::StatusOr< std::string > grpc_sockaddr_to_uri(const grpc_resolved_address *resolved_addr)
Definition: sockaddr_utils.cc:260
grpc_resolved_address::addr
char addr[GRPC_MAX_SOCKADDR_SIZE]
Definition: resolved_address.h:35
grpc_endpoint
Definition: endpoint.h:105
addr
struct sockaddr_in addr
Definition: libuv/docs/code/tcp-echo-server/main.c:10
tcp_connect
Definition: tcp_connect.py:1
absl::StatusOr::status
const Status & status() const &
Definition: abseil-cpp/absl/status/statusor.h:678
GRPC_ERROR_IS_NONE
#define GRPC_ERROR_IS_NONE(err)
Definition: error.h:241
port_platform.h


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