blob: eee6320e78a1960a85c4c82f131f8be2d2e07012 [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
54typedef struct {
55 void(*cb)(void *arg, grpc_endpoint *tcp);
56 void *cb_arg;
57 gpr_mu mu;
58 grpc_winsocket *socket;
59 gpr_timespec deadline;
60 grpc_alarm alarm;
61 int refs;
62} async_connect;
63
64static void async_connect_cleanup(async_connect *ac) {
65 int done = (--ac->refs == 0);
66 gpr_mu_unlock(&ac->mu);
67 if (done) {
68 gpr_mu_destroy(&ac->mu);
69 gpr_free(ac);
70 }
71}
72
73static void on_alarm(void *acp, int success) {
74 async_connect *ac = acp;
75 gpr_mu_lock(&ac->mu);
76 if (ac->socket != NULL && success) {
77 grpc_winsocket_shutdown(ac->socket);
78 }
79 async_connect_cleanup(ac);
80}
81
82static void on_connect(void *acp, int success) {
83 async_connect *ac = acp;
84 SOCKET sock = ac->socket->socket;
85 grpc_endpoint *ep = NULL;
86 grpc_winsocket_callback_info *info = &ac->socket->write_info;
87 void(*cb)(void *arg, grpc_endpoint *tcp) = ac->cb;
88 void *cb_arg = ac->cb_arg;
89
90 grpc_alarm_cancel(&ac->alarm);
91
92 if (success) {
93 DWORD transfered_bytes = 0;
94 DWORD flags;
95 BOOL wsa_success = WSAGetOverlappedResult(sock, &info->overlapped,
96 &transfered_bytes, FALSE,
97 &flags);
98 GPR_ASSERT(transfered_bytes == 0);
99 if (!wsa_success) {
100 char *utf8_message = gpr_format_message(WSAGetLastError());
101 gpr_log(GPR_ERROR, "on_connect error: %s", utf8_message);
102 gpr_free(utf8_message);
103 goto finish;
104 } else {
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100105 ep = grpc_tcp_create(ac->socket);
106 goto finish;
107 }
108 } else {
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100109 gpr_log(GPR_ERROR, "on_connect is shutting down");
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100110 goto finish;
111 }
112
113 abort();
114
115finish:
116 gpr_mu_lock(&ac->mu);
117 if (!ep) {
Nicolas "Pixel" Noble404fc6a2015-05-02 02:34:39 -0700118 if (success) {
119 ac->socket->closed_early = 1;
120 }
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100121 grpc_winsocket_orphan(ac->socket);
122 }
123 async_connect_cleanup(ac);
124 cb(cb_arg, ep);
125}
126
127void grpc_tcp_client_connect(void(*cb)(void *arg, grpc_endpoint *tcp),
128 void *arg, const struct sockaddr *addr,
129 int addr_len, gpr_timespec deadline) {
130 SOCKET sock = INVALID_SOCKET;
131 BOOL success;
132 int status;
133 struct sockaddr_in6 addr6_v4mapped;
134 struct sockaddr_in6 local_address;
135 async_connect *ac;
136 grpc_winsocket *socket = NULL;
137 LPFN_CONNECTEX ConnectEx;
138 GUID guid = WSAID_CONNECTEX;
139 DWORD ioctl_num_bytes;
140 const char *message = NULL;
141 char *utf8_message;
142 grpc_winsocket_callback_info *info;
143
144 /* Use dualstack sockets where available. */
145 if (grpc_sockaddr_to_v4mapped(addr, &addr6_v4mapped)) {
146 addr = (const struct sockaddr *)&addr6_v4mapped;
147 addr_len = sizeof(addr6_v4mapped);
148 }
149
150 sock = WSASocket(AF_INET6, SOCK_STREAM, IPPROTO_TCP, NULL, 0,
151 WSA_FLAG_OVERLAPPED);
152 if (sock == INVALID_SOCKET) {
153 message = "Unable to create socket: %s";
154 goto failure;
155 }
156
157 if (!grpc_tcp_prepare_socket(sock)) {
158 message = "Unable to set socket options: %s";
159 goto failure;
160 }
161
162 status = WSAIoctl(sock, SIO_GET_EXTENSION_FUNCTION_POINTER,
163 &guid, sizeof(guid), &ConnectEx, sizeof(ConnectEx),
164 &ioctl_num_bytes, NULL, NULL);
165
166 if (status != 0) {
167 message = "Unable to retreive ConnectEx pointer: %s";
168 goto failure;
169 }
170
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100171 grpc_sockaddr_make_wildcard6(0, &local_address);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100172
173 status = bind(sock, (struct sockaddr *) &local_address,
174 sizeof(local_address));
175 if (status != 0) {
176 message = "Unable to bind socket: %s";
177 goto failure;
178 }
179
180 socket = grpc_winsocket_create(sock);
181 info = &socket->write_info;
182 success = ConnectEx(sock, addr, addr_len, NULL, 0, NULL, &info->overlapped);
183
Jan Tattermusch5618a9d2015-04-21 18:10:16 -0700184 if (!success) {
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100185 int error = WSAGetLastError();
186 if (error != ERROR_IO_PENDING) {
187 message = "ConnectEx failed: %s";
188 goto failure;
189 }
190 }
191
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100192 ac = gpr_malloc(sizeof(async_connect));
193 ac->cb = cb;
194 ac->cb_arg = arg;
195 ac->socket = socket;
196 gpr_mu_init(&ac->mu);
197 ac->refs = 2;
198
199 grpc_alarm_init(&ac->alarm, deadline, on_alarm, ac, gpr_now());
Nicolas Noble45e67a32015-02-09 16:20:49 -0800200 grpc_socket_notify_on_write(socket, on_connect, ac);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100201 return;
202
203failure:
204 utf8_message = gpr_format_message(WSAGetLastError());
205 gpr_log(GPR_ERROR, message, utf8_message);
206 gpr_free(utf8_message);
207 if (socket) {
Nicolas "Pixel" Noble404fc6a2015-05-02 02:34:39 -0700208 socket->closed_early = 1;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100209 grpc_winsocket_orphan(socket);
210 } else if (sock != INVALID_SOCKET) {
211 closesocket(sock);
212 }
213 cb(arg, NULL);
214}
215
Craig Tiller190d3602015-02-18 09:23:38 -0800216#endif /* GPR_WINSOCK_SOCKET */