blob: 3540c5567644b314215b740e603fa1f481dcb3e1 [file] [log] [blame]
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +01001/*
2 *
Craig Tiller06059952015-02-18 08:34:56 -08003 * Copyright 2015, Google Inc.
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +01004 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above
13 * copyright notice, this list of conditions and the following disclaimer
14 * in the documentation and/or other materials provided with the
15 * distribution.
16 * * Neither the name of Google Inc. nor the names of its
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 */
33
34#include <grpc/support/port_platform.h>
35
36#ifdef GPR_WINSOCK_SOCKET
37
38#include "src/core/iomgr/sockaddr_win32.h"
39
40#include <grpc/support/alloc.h>
41#include <grpc/support/log.h>
42#include <grpc/support/log_win32.h>
43#include <grpc/support/slice_buffer.h>
44#include <grpc/support/useful.h>
45
Nicolas "Pixel" Noble94964fd2015-02-21 07:19:19 +010046#include "src/core/iomgr/alarm.h"
47#include "src/core/iomgr/iocp_windows.h"
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +010048#include "src/core/iomgr/tcp_client.h"
49#include "src/core/iomgr/tcp_windows.h"
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +010050#include "src/core/iomgr/sockaddr.h"
51#include "src/core/iomgr/sockaddr_utils.h"
Nicolas "Pixel" Noble94964fd2015-02-21 07:19:19 +010052#include "src/core/iomgr/socket_windows.h"
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +010053
Craig Tillera82950e2015-09-22 12:33:20 -070054typedef struct {
Craig Tiller82f9bd82015-09-23 09:31:51 -070055 grpc_closure *on_done;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +010056 gpr_mu mu;
57 grpc_winsocket *socket;
58 gpr_timespec deadline;
59 grpc_alarm alarm;
Craig Tiller81bcc4c2015-07-20 14:04:18 -070060 char *addr_name;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +010061 int refs;
Craig Tiller82f9bd82015-09-23 09:31:51 -070062 grpc_closure on_connect;
63 grpc_endpoint **endpoint;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +010064} async_connect;
65
Craig Tillera82950e2015-09-22 12:33:20 -070066static void async_connect_unlock_and_cleanup(async_connect *ac) {
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +010067 int done = (--ac->refs == 0);
Craig Tillera82950e2015-09-22 12:33:20 -070068 gpr_mu_unlock(&ac->mu);
69 if (done) {
70 if (ac->socket != NULL) grpc_winsocket_destroy(ac->socket);
71 gpr_mu_destroy(&ac->mu);
72 gpr_free(ac->addr_name);
73 gpr_free(ac);
74 }
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +010075}
76
Craig Tiller82f9bd82015-09-23 09:31:51 -070077static void on_alarm(grpc_exec_ctx *exec_ctx, void *acp, int occured) {
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +010078 async_connect *ac = acp;
Craig Tillera82950e2015-09-22 12:33:20 -070079 gpr_mu_lock(&ac->mu);
Nicolas "Pixel" Noble7f2e98c2015-05-08 01:41:21 +020080 /* If the alarm didn't occur, it got cancelled. */
Craig Tillera82950e2015-09-22 12:33:20 -070081 if (ac->socket != NULL && occured) {
82 grpc_winsocket_shutdown(ac->socket);
83 }
84 async_connect_unlock_and_cleanup(ac);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +010085}
86
Craig Tiller82f9bd82015-09-23 09:31:51 -070087static void on_connect(grpc_exec_ctx *exec_ctx, void *acp, int from_iocp) {
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +010088 async_connect *ac = acp;
89 SOCKET sock = ac->socket->socket;
Craig Tiller82f9bd82015-09-23 09:31:51 -070090 grpc_endpoint **ep = ac->endpoint;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +010091 grpc_winsocket_callback_info *info = &ac->socket->write_info;
Craig Tiller82f9bd82015-09-23 09:31:51 -070092 grpc_closure *on_done = ac->on_done;
Craig Tilleraf73d782015-09-22 09:30:46 -070093
Craig Tiller82f9bd82015-09-23 09:31:51 -070094 grpc_alarm_cancel(exec_ctx, &ac->alarm);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +010095
Craig Tillera82950e2015-09-22 12:33:20 -070096 gpr_mu_lock(&ac->mu);
Craig Tiller49d03c82015-09-03 14:34:30 -070097
Craig Tillera82950e2015-09-22 12:33:20 -070098 if (from_iocp) {
99 DWORD transfered_bytes = 0;
100 DWORD flags;
101 BOOL wsa_success = WSAGetOverlappedResult(sock, &info->overlapped,
102 &transfered_bytes, FALSE, &flags);
103 GPR_ASSERT(transfered_bytes == 0);
104 if (!wsa_success) {
105 char *utf8_message = gpr_format_message(WSAGetLastError());
106 gpr_log(GPR_ERROR, "on_connect error: %s", utf8_message);
107 gpr_free(utf8_message);
108 } else {
Craig Tiller82f9bd82015-09-23 09:31:51 -0700109 *ep = grpc_tcp_create(ac->socket, ac->addr_name);
Craig Tillera82950e2015-09-22 12:33:20 -0700110 ac->socket = NULL;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100111 }
Craig Tillera82950e2015-09-22 12:33:20 -0700112 }
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100113
Craig Tillera82950e2015-09-22 12:33:20 -0700114 async_connect_unlock_and_cleanup(ac);
Nicolas "Pixel" Noble8e1a55d2015-05-02 15:21:25 -0700115 /* If the connection was aborted, the callback was already called when
116 the deadline was met. */
Craig Tiller82f9bd82015-09-23 09:31:51 -0700117 on_done->cb(exec_ctx, on_done->cb_arg, *ep != NULL);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100118}
119
Nicolas "Pixel" Noble8e1a55d2015-05-02 15:21:25 -0700120/* Tries to issue one async connection, then schedules both an IOCP
121 notification request for the connection, and one timeout alert. */
Craig Tiller82f9bd82015-09-23 09:31:51 -0700122void grpc_tcp_client_connect(grpc_exec_ctx *exec_ctx, grpc_closure *on_done,
Craig Tiller565b18b2015-09-23 10:09:42 -0700123 grpc_endpoint **endpoint,
Craig Tiller82f9bd82015-09-23 09:31:51 -0700124 grpc_pollset_set *interested_parties,
125 const struct sockaddr *addr, size_t addr_len,
Craig Tillera82950e2015-09-22 12:33:20 -0700126 gpr_timespec deadline) {
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100127 SOCKET sock = INVALID_SOCKET;
128 BOOL success;
129 int status;
130 struct sockaddr_in6 addr6_v4mapped;
131 struct sockaddr_in6 local_address;
132 async_connect *ac;
133 grpc_winsocket *socket = NULL;
134 LPFN_CONNECTEX ConnectEx;
135 GUID guid = WSAID_CONNECTEX;
136 DWORD ioctl_num_bytes;
137 const char *message = NULL;
138 char *utf8_message;
139 grpc_winsocket_callback_info *info;
140
Craig Tiller82f9bd82015-09-23 09:31:51 -0700141 *endpoint = NULL;
142
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100143 /* Use dualstack sockets where available. */
Craig Tillera82950e2015-09-22 12:33:20 -0700144 if (grpc_sockaddr_to_v4mapped(addr, &addr6_v4mapped)) {
145 addr = (const struct sockaddr *)&addr6_v4mapped;
146 addr_len = sizeof(addr6_v4mapped);
147 }
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100148
Craig Tillera82950e2015-09-22 12:33:20 -0700149 sock = WSASocket(AF_INET6, SOCK_STREAM, IPPROTO_TCP, NULL, 0,
150 WSA_FLAG_OVERLAPPED);
151 if (sock == INVALID_SOCKET) {
152 message = "Unable to create socket: %s";
153 goto failure;
154 }
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100155
Craig Tillera82950e2015-09-22 12:33:20 -0700156 if (!grpc_tcp_prepare_socket(sock)) {
157 message = "Unable to set socket options: %s";
158 goto failure;
159 }
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100160
Nicolas "Pixel" Noble8e1a55d2015-05-02 15:21:25 -0700161 /* Grab the function pointer for ConnectEx for that specific socket.
162 It may change depending on the interface. */
Craig Tillera82950e2015-09-22 12:33:20 -0700163 status =
164 WSAIoctl(sock, SIO_GET_EXTENSION_FUNCTION_POINTER, &guid, sizeof(guid),
165 &ConnectEx, sizeof(ConnectEx), &ioctl_num_bytes, NULL, NULL);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100166
Craig Tillera82950e2015-09-22 12:33:20 -0700167 if (status != 0) {
168 message = "Unable to retrieve ConnectEx pointer: %s";
169 goto failure;
170 }
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100171
Craig Tillera82950e2015-09-22 12:33:20 -0700172 grpc_sockaddr_make_wildcard6(0, &local_address);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100173
Craig Tillera82950e2015-09-22 12:33:20 -0700174 status = bind(sock, (struct sockaddr *)&local_address, sizeof(local_address));
175 if (status != 0) {
176 message = "Unable to bind socket: %s";
177 goto failure;
178 }
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100179
Craig Tillera82950e2015-09-22 12:33:20 -0700180 socket = grpc_winsocket_create(sock, "client");
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100181 info = &socket->write_info;
Craig Tiller565b18b2015-09-23 10:09:42 -0700182 success =
183 ConnectEx(sock, addr, (int)addr_len, NULL, 0, NULL, &info->overlapped);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100184
Nicolas "Pixel" Noble8e1a55d2015-05-02 15:21:25 -0700185 /* It wouldn't be unusual to get a success immediately. But we'll still get
186 an IOCP notification, so let's ignore it. */
Craig Tillera82950e2015-09-22 12:33:20 -0700187 if (!success) {
188 int error = WSAGetLastError();
189 if (error != ERROR_IO_PENDING) {
190 message = "ConnectEx failed: %s";
191 goto failure;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100192 }
Craig Tillera82950e2015-09-22 12:33:20 -0700193 }
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100194
Craig Tillera82950e2015-09-22 12:33:20 -0700195 ac = gpr_malloc(sizeof(async_connect));
Craig Tiller82f9bd82015-09-23 09:31:51 -0700196 ac->on_done = on_done;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100197 ac->socket = socket;
Craig Tillera82950e2015-09-22 12:33:20 -0700198 gpr_mu_init(&ac->mu);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100199 ac->refs = 2;
Craig Tillera82950e2015-09-22 12:33:20 -0700200 ac->addr_name = grpc_sockaddr_to_uri(addr);
Craig Tiller82f9bd82015-09-23 09:31:51 -0700201 ac->endpoint = endpoint;
202 grpc_closure_init(&ac->on_connect, on_connect, ac);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100203
Craig Tiller82f9bd82015-09-23 09:31:51 -0700204 grpc_alarm_init(exec_ctx, &ac->alarm, deadline, on_alarm, ac,
Craig Tillera82950e2015-09-22 12:33:20 -0700205 gpr_now(GPR_CLOCK_MONOTONIC));
Craig Tiller82f9bd82015-09-23 09:31:51 -0700206 grpc_socket_notify_on_write(exec_ctx, socket, &ac->on_connect);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100207 return;
208
209failure:
Craig Tillera82950e2015-09-22 12:33:20 -0700210 utf8_message = gpr_format_message(WSAGetLastError());
211 gpr_log(GPR_ERROR, message, utf8_message);
212 gpr_free(utf8_message);
213 if (socket != NULL) {
214 grpc_winsocket_destroy(socket);
215 } else if (sock != INVALID_SOCKET) {
216 closesocket(sock);
217 }
Craig Tiller82f9bd82015-09-23 09:31:51 -0700218 grpc_exec_ctx_enqueue(exec_ctx, on_done, 0);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100219}
220
Craig Tiller8674cb12015-06-05 07:09:25 -0700221#endif /* GPR_WINSOCK_SOCKET */