blob: ae66577cafd23226577a03647fc744037b8c9a78 [file] [log] [blame]
murgatroid999030c812016-09-16 13:25:08 -07001/*
2 *
3 * Copyright 2016, Google Inc.
4 * 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 "src/core/lib/iomgr/port.h"
35
36#ifdef GRPC_UV
37
38#include <string.h>
39
40#include <grpc/support/alloc.h>
41#include <grpc/support/log.h>
42
43#include "src/core/lib/iomgr/error.h"
44#include "src/core/lib/iomgr/sockaddr_utils.h"
45#include "src/core/lib/iomgr/tcp_client.h"
46#include "src/core/lib/iomgr/tcp_uv.h"
47#include "src/core/lib/iomgr/timer.h"
48
murgatroid99c7308962017-01-31 09:00:01 -080049extern int grpc_tcp_trace;
50
murgatroid999030c812016-09-16 13:25:08 -070051typedef struct grpc_uv_tcp_connect {
52 uv_connect_t connect_req;
53 grpc_timer alarm;
Masood Malekghassemib5b43722017-01-05 15:07:26 -080054 grpc_closure on_alarm;
murgatroid999030c812016-09-16 13:25:08 -070055 uv_tcp_t *tcp_handle;
56 grpc_closure *closure;
57 grpc_endpoint **endpoint;
58 int refs;
59 char *addr_name;
murgatroid9969259d42016-10-31 14:34:10 -070060 grpc_resource_quota *resource_quota;
murgatroid999030c812016-09-16 13:25:08 -070061} grpc_uv_tcp_connect;
62
murgatroid9969259d42016-10-31 14:34:10 -070063static void uv_tcp_connect_cleanup(grpc_exec_ctx *exec_ctx,
64 grpc_uv_tcp_connect *connect) {
Craig Tiller58833762016-12-06 19:36:23 -080065 grpc_resource_quota_unref_internal(exec_ctx, connect->resource_quota);
murgatroid999030c812016-09-16 13:25:08 -070066 gpr_free(connect);
67}
68
murgatroid99aa9c5782016-10-10 12:16:13 -070069static void tcp_close_callback(uv_handle_t *handle) { gpr_free(handle); }
murgatroid999030c812016-09-16 13:25:08 -070070
murgatroid99dedb9232016-09-26 13:54:04 -070071static void uv_tc_on_alarm(grpc_exec_ctx *exec_ctx, void *acp,
72 grpc_error *error) {
murgatroid999030c812016-09-16 13:25:08 -070073 int done;
74 grpc_uv_tcp_connect *connect = acp;
murgatroid99c7308962017-01-31 09:00:01 -080075 if (grpc_tcp_trace) {
76 const char *str = grpc_error_string(error);
77 gpr_log(GPR_DEBUG, "CLIENT_CONNECT: %s: on_alarm: error=%s",
78 connect->addr_name, str);
79 grpc_error_free_string(str);
80 }
murgatroid999030c812016-09-16 13:25:08 -070081 if (error == GRPC_ERROR_NONE) {
82 /* error == NONE implies that the timer ran out, and wasn't cancelled. If
83 it was cancelled, then the handler that cancelled it also should close
84 the handle, if applicable */
murgatroid999030c812016-09-16 13:25:08 -070085 uv_close((uv_handle_t *)connect->tcp_handle, tcp_close_callback);
86 }
87 done = (--connect->refs == 0);
88 if (done) {
murgatroid9969259d42016-10-31 14:34:10 -070089 uv_tcp_connect_cleanup(exec_ctx, connect);
murgatroid999030c812016-09-16 13:25:08 -070090 }
91}
92
93static void uv_tc_on_connect(uv_connect_t *req, int status) {
94 grpc_uv_tcp_connect *connect = req->data;
95 grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
96 grpc_error *error = GRPC_ERROR_NONE;
97 int done;
98 grpc_closure *closure = connect->closure;
99 grpc_timer_cancel(&exec_ctx, &connect->alarm);
100 if (status == 0) {
murgatroid9969259d42016-10-31 14:34:10 -0700101 *connect->endpoint = grpc_tcp_create(
102 connect->tcp_handle, connect->resource_quota, connect->addr_name);
murgatroid999030c812016-09-16 13:25:08 -0700103 } else {
104 error = GRPC_ERROR_CREATE("Failed to connect to remote host");
105 error = grpc_error_set_int(error, GRPC_ERROR_INT_ERRNO, -status);
murgatroid99dedb9232016-09-26 13:54:04 -0700106 error =
107 grpc_error_set_str(error, GRPC_ERROR_STR_OS_ERROR, uv_strerror(status));
murgatroid999030c812016-09-16 13:25:08 -0700108 if (status == UV_ECANCELED) {
109 error = grpc_error_set_str(error, GRPC_ERROR_STR_OS_ERROR,
110 "Timeout occurred");
111 // This should only happen if the handle is already closed
112 } else {
113 error = grpc_error_set_str(error, GRPC_ERROR_STR_OS_ERROR,
114 uv_strerror(status));
murgatroid999030c812016-09-16 13:25:08 -0700115 uv_close((uv_handle_t *)connect->tcp_handle, tcp_close_callback);
116 }
117 }
118 done = (--connect->refs == 0);
119 if (done) {
murgatroid9969259d42016-10-31 14:34:10 -0700120 uv_tcp_connect_cleanup(&exec_ctx, connect);
murgatroid999030c812016-09-16 13:25:08 -0700121 }
Craig Tiller91031da2016-12-28 15:44:25 -0800122 grpc_closure_sched(&exec_ctx, closure, error);
murgatroid999030c812016-09-16 13:25:08 -0700123 grpc_exec_ctx_finish(&exec_ctx);
124}
125
murgatroid99c36f6ea2016-10-03 09:24:09 -0700126static void tcp_client_connect_impl(grpc_exec_ctx *exec_ctx,
127 grpc_closure *closure, grpc_endpoint **ep,
128 grpc_pollset_set *interested_parties,
murgatroid9969259d42016-10-31 14:34:10 -0700129 const grpc_channel_args *channel_args,
murgatroid99c36f6ea2016-10-03 09:24:09 -0700130 const grpc_resolved_address *resolved_addr,
131 gpr_timespec deadline) {
murgatroid999030c812016-09-16 13:25:08 -0700132 grpc_uv_tcp_connect *connect;
murgatroid9969259d42016-10-31 14:34:10 -0700133 grpc_resource_quota *resource_quota = grpc_resource_quota_create(NULL);
134 (void)channel_args;
murgatroid999030c812016-09-16 13:25:08 -0700135 (void)interested_parties;
murgatroid9969259d42016-10-31 14:34:10 -0700136
137 if (channel_args != NULL) {
138 for (size_t i = 0; i < channel_args->num_args; i++) {
139 if (0 == strcmp(channel_args->args[i].key, GRPC_ARG_RESOURCE_QUOTA)) {
Craig Tiller58833762016-12-06 19:36:23 -0800140 grpc_resource_quota_unref_internal(exec_ctx, resource_quota);
141 resource_quota = grpc_resource_quota_ref_internal(
murgatroid9969259d42016-10-31 14:34:10 -0700142 channel_args->args[i].value.pointer.p);
143 }
144 }
145 }
146
Craig Tiller6f417882017-02-16 14:09:39 -0800147 connect = gpr_zalloc(sizeof(grpc_uv_tcp_connect));
murgatroid999030c812016-09-16 13:25:08 -0700148 connect->closure = closure;
149 connect->endpoint = ep;
150 connect->tcp_handle = gpr_malloc(sizeof(uv_tcp_t));
murgatroid997871f732016-09-23 13:49:05 -0700151 connect->addr_name = grpc_sockaddr_to_uri(resolved_addr);
murgatroid9969259d42016-10-31 14:34:10 -0700152 connect->resource_quota = resource_quota;
murgatroid999030c812016-09-16 13:25:08 -0700153 uv_tcp_init(uv_default_loop(), connect->tcp_handle);
154 connect->connect_req.data = connect;
murgatroid99c7308962017-01-31 09:00:01 -0800155
156 if (grpc_tcp_trace) {
157 gpr_log(GPR_DEBUG, "CLIENT_CONNECT: %s: asynchronously connecting",
158 connect->addr_name);
159 }
160
murgatroid999030c812016-09-16 13:25:08 -0700161 // TODO(murgatroid99): figure out what the return value here means
murgatroid997871f732016-09-23 13:49:05 -0700162 uv_tcp_connect(&connect->connect_req, connect->tcp_handle,
163 (const struct sockaddr *)resolved_addr->addr,
murgatroid999030c812016-09-16 13:25:08 -0700164 uv_tc_on_connect);
Masood Malekghassemib5b43722017-01-05 15:07:26 -0800165 grpc_closure_init(&connect->on_alarm, uv_tc_on_alarm, connect,
166 grpc_schedule_on_exec_ctx);
murgatroid999030c812016-09-16 13:25:08 -0700167 grpc_timer_init(exec_ctx, &connect->alarm,
168 gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC),
Masood Malekghassemib5b43722017-01-05 15:07:26 -0800169 &connect->on_alarm, gpr_now(GPR_CLOCK_MONOTONIC));
murgatroid999030c812016-09-16 13:25:08 -0700170}
171
murgatroid99c36f6ea2016-10-03 09:24:09 -0700172// overridden by api_fuzzer.c
173void (*grpc_tcp_client_connect_impl)(
174 grpc_exec_ctx *exec_ctx, grpc_closure *closure, grpc_endpoint **ep,
murgatroid9969259d42016-10-31 14:34:10 -0700175 grpc_pollset_set *interested_parties, const grpc_channel_args *channel_args,
176 const grpc_resolved_address *addr,
murgatroid99c36f6ea2016-10-03 09:24:09 -0700177 gpr_timespec deadline) = tcp_client_connect_impl;
178
179void grpc_tcp_client_connect(grpc_exec_ctx *exec_ctx, grpc_closure *closure,
180 grpc_endpoint **ep,
181 grpc_pollset_set *interested_parties,
murgatroid9969259d42016-10-31 14:34:10 -0700182 const grpc_channel_args *channel_args,
murgatroid99c36f6ea2016-10-03 09:24:09 -0700183 const grpc_resolved_address *addr,
184 gpr_timespec deadline) {
murgatroid9969259d42016-10-31 14:34:10 -0700185 grpc_tcp_client_connect_impl(exec_ctx, closure, ep, interested_parties,
186 channel_args, addr, deadline);
murgatroid99c36f6ea2016-10-03 09:24:09 -0700187}
188
murgatroid999030c812016-09-16 13:25:08 -0700189#endif /* GRPC_UV */