blob: 9975b1ef7954b2193d9b544e11b2726bddd91927 [file] [log] [blame]
Yuchen Zengd4bbfc72016-08-05 10:33:16 -07001/*
2 *
Jan Tattermusch7897ae92017-06-07 22:57:36 +02003 * Copyright 2016 gRPC authors.
Yuchen Zengd4bbfc72016-08-05 10:33:16 -07004 *
Jan Tattermusch7897ae92017-06-07 22:57:36 +02005 * 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
Yuchen Zengd4bbfc72016-08-05 10:33:16 -07008 *
Jan Tattermusch7897ae92017-06-07 22:57:36 +02009 * http://www.apache.org/licenses/LICENSE-2.0
Yuchen Zengd4bbfc72016-08-05 10:33:16 -070010 *
Jan Tattermusch7897ae92017-06-07 22:57:36 +020011 * 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.
Yuchen Zengd4bbfc72016-08-05 10:33:16 -070016 *
17 */
18
19#include <grpc/support/port_platform.h>
Yuchen Zengd6b49852017-03-20 01:44:27 -070020#if GRPC_ARES == 1 && !defined(GRPC_UV)
Yuchen Zengd79f92a2016-08-08 01:18:32 -070021
Craig Tiller9eb0fde2017-03-31 16:59:30 -070022#include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h"
Yuchen Zeng299dd8d2016-08-16 21:40:13 -070023#include "src/core/lib/iomgr/sockaddr.h"
Yuchen Zeng6eb83cc2016-08-23 00:44:18 -070024#include "src/core/lib/iomgr/socket_utils_posix.h"
Yuchen Zeng85750b02016-08-08 14:16:34 -070025
Yuchen Zengd4bbfc72016-08-05 10:33:16 -070026#include <string.h>
27#include <sys/types.h>
28
29#include <ares.h>
30#include <grpc/support/alloc.h>
31#include <grpc/support/host_port.h>
32#include <grpc/support/log.h>
33#include <grpc/support/string_util.h>
Yuchen Zengd4bbfc72016-08-05 10:33:16 -070034#include <grpc/support/time.h>
35#include <grpc/support/useful.h>
Mark D. Roth96fc54c2017-05-18 14:33:07 -070036
37#include "src/core/ext/filters/client_channel/parse_address.h"
Craig Tiller9eb0fde2017-03-31 16:59:30 -070038#include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h"
Mark D. Roth96fc54c2017-05-18 14:33:07 -070039#include "src/core/lib/iomgr/error.h"
Yuchen Zengd4bbfc72016-08-05 10:33:16 -070040#include "src/core/lib/iomgr/executor.h"
41#include "src/core/lib/iomgr/iomgr_internal.h"
Yuchen Zengf630ff22017-07-25 13:28:45 -070042#include "src/core/lib/iomgr/nameser.h"
Yuchen Zengd4bbfc72016-08-05 10:33:16 -070043#include "src/core/lib/iomgr/sockaddr_utils.h"
Yuchen Zengd4bbfc72016-08-05 10:33:16 -070044#include "src/core/lib/support/string.h"
45
Yuchen Zeng459480b2016-08-09 11:40:26 -070046static gpr_once g_basic_init = GPR_ONCE_INIT;
47static gpr_mu g_init_mu;
48
Yuchen Zeng3b4bed22017-06-04 01:41:15 -070049struct grpc_ares_request {
Mark D. Roth96fc54c2017-05-18 14:33:07 -070050 /** indicates the DNS server to use, if specified */
51 struct ares_addr_port_node dns_server_addr;
Yuchen Zeng3ae26632016-11-09 15:53:50 -080052 /** following members are set in grpc_resolve_address_ares_impl */
Yuchen Zeng3ae26632016-11-09 15:53:50 -080053 /** closure to call when the request completes */
Yuchen Zengd4bbfc72016-08-05 10:33:16 -070054 grpc_closure *on_done;
Yuchen Zeng3ae26632016-11-09 15:53:50 -080055 /** the pointer to receive the resolved addresses */
Yuchen Zeng3385b4f2017-05-24 11:40:20 -070056 grpc_lb_addresses **lb_addrs_out;
Mark D. Rothf9bf4282017-08-03 14:47:23 -070057 /** the pointer to receive the service config in JSON */
58 char **service_config_json_out;
Yuchen Zeng3ae26632016-11-09 15:53:50 -080059 /** the evernt driver used by this request */
Yuchen Zeng2648a952016-11-02 18:52:25 -070060 grpc_ares_ev_driver *ev_driver;
Yuchen Zeng3ae26632016-11-09 15:53:50 -080061 /** number of ongoing queries */
Yuchen Zeng2648a952016-11-02 18:52:25 -070062 gpr_refcount pending_queries;
63
64 /** mutex guarding the rest of the state */
65 gpr_mu mu;
Yuchen Zeng912327e2016-10-25 18:27:17 -070066 /** is there at least one successful query, set in on_done_cb */
67 bool success;
68 /** the errors explaining the request failure, set in on_done_cb */
Yuchen Zeng1d0c1c42016-08-18 15:36:24 -070069 grpc_error *error;
Yuchen Zeng3b4bed22017-06-04 01:41:15 -070070};
Yuchen Zengd4bbfc72016-08-05 10:33:16 -070071
Yuchen Zengf3bdbb72017-05-18 18:22:23 -070072typedef struct grpc_ares_hostbyname_request {
73 /** following members are set in create_hostbyname_request */
74 /** the top-level request instance */
75 grpc_ares_request *parent_request;
76 /** host to resolve, parsed from the name to resolve */
77 char *host;
78 /** port to fill in sockaddr_in, parsed from the name to resolve */
79 uint16_t port;
80 /** is it a grpclb address */
81 bool is_balancer;
82} grpc_ares_hostbyname_request;
Yuchen Zengd4bbfc72016-08-05 10:33:16 -070083
Yuchen Zengb48000c2016-08-09 22:44:23 -070084static void do_basic_init(void) { gpr_mu_init(&g_init_mu); }
Yuchen Zengd4bbfc72016-08-05 10:33:16 -070085
Yuchen Zenga0dbd9f2016-08-16 23:08:09 -070086static uint16_t strhtons(const char *port) {
87 if (strcmp(port, "http") == 0) {
88 return htons(80);
89 } else if (strcmp(port, "https") == 0) {
90 return htons(443);
91 }
92 return htons((unsigned short)atoi(port));
93}
94
Yuchen Zengf3bdbb72017-05-18 18:22:23 -070095static void grpc_ares_request_ref(grpc_ares_request *r) {
96 gpr_ref(&r->pending_queries);
97}
98
Yuchen Zeng117a3002016-11-17 19:43:36 -080099static void grpc_ares_request_unref(grpc_exec_ctx *exec_ctx,
100 grpc_ares_request *r) {
Yuchen Zenge5230b72017-03-17 15:10:49 -0700101 /* If there are no pending queries, invoke on_done callback and destroy the
102 request */
Yuchen Zeng117a3002016-11-17 19:43:36 -0800103 if (gpr_unref(&r->pending_queries)) {
Yuchen Zeng15618622017-03-19 22:31:14 -0700104 /* TODO(zyc): Sort results with RFC6724 before invoking on_done. */
Yuchen Zeng117a3002016-11-17 19:43:36 -0800105 if (exec_ctx == NULL) {
Yuchen Zenge5230b72017-03-17 15:10:49 -0700106 /* A new exec_ctx is created here, as the c-ares interface does not
107 provide one in ares_host_callback. It's safe to schedule on_done with
108 the newly created exec_ctx, since the caller has been warned not to
109 acquire locks in on_done. ares_dns_resolver is using combiner to
110 protect resources needed by on_done. */
Yuchen Zeng117a3002016-11-17 19:43:36 -0800111 grpc_exec_ctx new_exec_ctx = GRPC_EXEC_CTX_INIT;
ncteisen274bbbe2017-06-08 14:57:11 -0700112 GRPC_CLOSURE_SCHED(&new_exec_ctx, r->on_done, r->error);
Yuchen Zeng117a3002016-11-17 19:43:36 -0800113 grpc_exec_ctx_finish(&new_exec_ctx);
114 } else {
ncteisen274bbbe2017-06-08 14:57:11 -0700115 GRPC_CLOSURE_SCHED(exec_ctx, r->on_done, r->error);
Yuchen Zeng117a3002016-11-17 19:43:36 -0800116 }
117 gpr_mu_destroy(&r->mu);
118 grpc_ares_ev_driver_destroy(r->ev_driver);
Yuchen Zeng117a3002016-11-17 19:43:36 -0800119 gpr_free(r);
120 }
121}
122
Yuchen Zengf3bdbb72017-05-18 18:22:23 -0700123static grpc_ares_hostbyname_request *create_hostbyname_request(
124 grpc_ares_request *parent_request, char *host, uint16_t port,
125 bool is_balancer) {
Yash Tibrewalbc130da2017-09-12 22:44:08 -0700126 grpc_ares_hostbyname_request *hr = (grpc_ares_hostbyname_request *)gpr_zalloc(
127 sizeof(grpc_ares_hostbyname_request));
Yuchen Zengf3bdbb72017-05-18 18:22:23 -0700128 hr->parent_request = parent_request;
129 hr->host = gpr_strdup(host);
130 hr->port = port;
131 hr->is_balancer = is_balancer;
132 grpc_ares_request_ref(parent_request);
133 return hr;
134}
135
136static void destroy_hostbyname_request(grpc_exec_ctx *exec_ctx,
137 grpc_ares_hostbyname_request *hr) {
138 grpc_ares_request_unref(exec_ctx, hr->parent_request);
139 gpr_free(hr->host);
140 gpr_free(hr);
141}
142
143static void on_hostbyname_done_cb(void *arg, int status, int timeouts,
144 struct hostent *hostent) {
145 grpc_ares_hostbyname_request *hr = (grpc_ares_hostbyname_request *)arg;
146 grpc_ares_request *r = hr->parent_request;
Yuchen Zeng2648a952016-11-02 18:52:25 -0700147 gpr_mu_lock(&r->mu);
Yuchen Zengd4bbfc72016-08-05 10:33:16 -0700148 if (status == ARES_SUCCESS) {
Yuchen Zeng1d0c1c42016-08-18 15:36:24 -0700149 GRPC_ERROR_UNREF(r->error);
150 r->error = GRPC_ERROR_NONE;
Yuchen Zeng912327e2016-10-25 18:27:17 -0700151 r->success = true;
Yuchen Zeng3385b4f2017-05-24 11:40:20 -0700152 grpc_lb_addresses **lb_addresses = r->lb_addrs_out;
153 if (*lb_addresses == NULL) {
154 *lb_addresses = grpc_lb_addresses_create(0, NULL);
Yuchen Zengd4bbfc72016-08-05 10:33:16 -0700155 }
Yuchen Zeng3385b4f2017-05-24 11:40:20 -0700156 size_t prev_naddr = (*lb_addresses)->num_addresses;
Yuchen Zeng912327e2016-10-25 18:27:17 -0700157 size_t i;
Yuchen Zeng9248d352016-08-16 16:33:10 -0700158 for (i = 0; hostent->h_addr_list[i] != NULL; i++) {
159 }
Yuchen Zeng3385b4f2017-05-24 11:40:20 -0700160 (*lb_addresses)->num_addresses += i;
Yash Tibrewalca3c1c02017-09-07 22:47:16 -0700161 (*lb_addresses)->addresses = (grpc_lb_address *)gpr_realloc(
162 (*lb_addresses)->addresses,
163 sizeof(grpc_lb_address) * (*lb_addresses)->num_addresses);
Yuchen Zeng3385b4f2017-05-24 11:40:20 -0700164 for (i = prev_naddr; i < (*lb_addresses)->num_addresses; i++) {
Yuchen Zeng3385b4f2017-05-24 11:40:20 -0700165 switch (hostent->h_addrtype) {
166 case AF_INET6: {
167 size_t addr_len = sizeof(struct sockaddr_in6);
168 struct sockaddr_in6 addr;
Yuchen Zeng3b4bed22017-06-04 01:41:15 -0700169 memset(&addr, 0, addr_len);
Yuchen Zeng3385b4f2017-05-24 11:40:20 -0700170 memcpy(&addr.sin6_addr, hostent->h_addr_list[i - prev_naddr],
171 sizeof(struct in6_addr));
172 addr.sin6_family = (sa_family_t)hostent->h_addrtype;
173 addr.sin6_port = hr->port;
174 grpc_lb_addresses_set_address(
175 *lb_addresses, i, &addr, addr_len,
176 hr->is_balancer /* is_balancer */,
Alexander Polcyn3a243642017-09-12 12:06:27 -0700177 hr->is_balancer ? hr->host : NULL /* balancer_name */,
Yuchen Zeng3385b4f2017-05-24 11:40:20 -0700178 NULL /* user_data */);
179 char output[INET6_ADDRSTRLEN];
180 ares_inet_ntop(AF_INET6, &addr.sin6_addr, output, INET6_ADDRSTRLEN);
181 gpr_log(GPR_DEBUG,
182 "c-ares resolver gets a AF_INET6 result: \n"
183 " addr: %s\n port: %d\n sin6_scope_id: %d\n",
184 output, ntohs(hr->port), addr.sin6_scope_id);
185 break;
Yuchen Zengf3bdbb72017-05-18 18:22:23 -0700186 }
Yuchen Zeng3385b4f2017-05-24 11:40:20 -0700187 case AF_INET: {
188 size_t addr_len = sizeof(struct sockaddr_in);
189 struct sockaddr_in addr;
Yuchen Zeng3b4bed22017-06-04 01:41:15 -0700190 memset(&addr, 0, addr_len);
Yuchen Zeng3385b4f2017-05-24 11:40:20 -0700191 memcpy(&addr.sin_addr, hostent->h_addr_list[i - prev_naddr],
192 sizeof(struct in_addr));
193 addr.sin_family = (sa_family_t)hostent->h_addrtype;
194 addr.sin_port = hr->port;
195 grpc_lb_addresses_set_address(
196 *lb_addresses, i, &addr, addr_len,
197 hr->is_balancer /* is_balancer */,
Alexander Polcyn3a243642017-09-12 12:06:27 -0700198 hr->is_balancer ? hr->host : NULL /* balancer_name */,
Yuchen Zeng3385b4f2017-05-24 11:40:20 -0700199 NULL /* user_data */);
200 char output[INET_ADDRSTRLEN];
201 ares_inet_ntop(AF_INET, &addr.sin_addr, output, INET_ADDRSTRLEN);
202 gpr_log(GPR_DEBUG,
203 "c-ares resolver gets a AF_INET result: \n"
204 " addr: %s\n port: %d\n",
205 output, ntohs(hr->port));
206 break;
Yuchen Zengf3bdbb72017-05-18 18:22:23 -0700207 }
Yuchen Zengd4bbfc72016-08-05 10:33:16 -0700208 }
209 }
Yuchen Zeng15a71c82016-08-17 11:50:06 -0700210 } else if (!r->success) {
Yuchen Zeng912327e2016-10-25 18:27:17 -0700211 char *error_msg;
212 gpr_asprintf(&error_msg, "C-ares status is not ARES_SUCCESS: %s",
213 ares_strerror(status));
Yuchen Zeng0e8bc452017-03-23 14:44:14 -0700214 grpc_error *error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(error_msg);
Yuchen Zeng912327e2016-10-25 18:27:17 -0700215 gpr_free(error_msg);
Yuchen Zeng1d0c1c42016-08-18 15:36:24 -0700216 if (r->error == GRPC_ERROR_NONE) {
Yuchen Zeng912327e2016-10-25 18:27:17 -0700217 r->error = error;
218 } else {
219 r->error = grpc_error_add_child(error, r->error);
Yuchen Zeng15a71c82016-08-17 11:50:06 -0700220 }
Yuchen Zengd4bbfc72016-08-05 10:33:16 -0700221 }
Yuchen Zeng2648a952016-11-02 18:52:25 -0700222 gpr_mu_unlock(&r->mu);
Yuchen Zengf3bdbb72017-05-18 18:22:23 -0700223 destroy_hostbyname_request(NULL, hr);
Yuchen Zengd4bbfc72016-08-05 10:33:16 -0700224}
225
Yuchen Zengf3bdbb72017-05-18 18:22:23 -0700226static void on_srv_query_done_cb(void *arg, int status, int timeouts,
227 unsigned char *abuf, int alen) {
228 grpc_ares_request *r = (grpc_ares_request *)arg;
229 grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
230 gpr_log(GPR_DEBUG, "on_query_srv_done_cb");
231 if (status == ARES_SUCCESS) {
232 gpr_log(GPR_DEBUG, "on_query_srv_done_cb ARES_SUCCESS");
233 struct ares_srv_reply *reply;
234 const int parse_status = ares_parse_srv_reply(abuf, alen, &reply);
235 if (parse_status == ARES_SUCCESS) {
236 ares_channel *channel = grpc_ares_ev_driver_get_channel(r->ev_driver);
237 for (struct ares_srv_reply *srv_it = reply; srv_it != NULL;
238 srv_it = srv_it->next) {
239 if (grpc_ipv6_loopback_available()) {
240 grpc_ares_hostbyname_request *hr = create_hostbyname_request(
Alex Polcynddf6c492017-06-27 22:06:35 +0000241 r, srv_it->host, htons(srv_it->port), true /* is_balancer */);
Yuchen Zengf3bdbb72017-05-18 18:22:23 -0700242 ares_gethostbyname(*channel, hr->host, AF_INET6,
243 on_hostbyname_done_cb, hr);
244 }
245 grpc_ares_hostbyname_request *hr = create_hostbyname_request(
Alex Polcynddf6c492017-06-27 22:06:35 +0000246 r, srv_it->host, htons(srv_it->port), true /* is_balancer */);
Yuchen Zengf3bdbb72017-05-18 18:22:23 -0700247 ares_gethostbyname(*channel, hr->host, AF_INET, on_hostbyname_done_cb,
248 hr);
249 grpc_ares_ev_driver_start(&exec_ctx, r->ev_driver);
250 }
251 }
Yuchen Zengf3bdbb72017-05-18 18:22:23 -0700252 if (reply != NULL) {
253 ares_free_data(reply);
254 }
255 } else if (!r->success) {
256 char *error_msg;
257 gpr_asprintf(&error_msg, "C-ares status is not ARES_SUCCESS: %s",
258 ares_strerror(status));
259 grpc_error *error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(error_msg);
260 gpr_free(error_msg);
261 if (r->error == GRPC_ERROR_NONE) {
262 r->error = error;
263 } else {
264 r->error = grpc_error_add_child(error, r->error);
265 }
266 }
267 grpc_ares_request_unref(&exec_ctx, r);
268 grpc_exec_ctx_finish(&exec_ctx);
269}
270
Mark D. Rothf9bf4282017-08-03 14:47:23 -0700271static const char g_service_config_attribute_prefix[] = "grpc_config=";
272
273static void on_txt_done_cb(void *arg, int status, int timeouts,
274 unsigned char *buf, int len) {
275 gpr_log(GPR_DEBUG, "on_txt_done_cb");
276 char *error_msg;
277 grpc_ares_request *r = (grpc_ares_request *)arg;
Yash Tibrewal533d1182017-09-18 10:48:22 -0700278 const size_t prefix_len = sizeof(g_service_config_attribute_prefix) - 1;
279 struct ares_txt_ext *result;
280 struct ares_txt_ext *reply = NULL;
281 grpc_error *error = GRPC_ERROR_NONE;
Mark D. Rothf9bf4282017-08-03 14:47:23 -0700282 gpr_mu_lock(&r->mu);
283 if (status != ARES_SUCCESS) goto fail;
Mark D. Rothf9bf4282017-08-03 14:47:23 -0700284 status = ares_parse_txt_reply_ext(buf, len, &reply);
285 if (status != ARES_SUCCESS) goto fail;
286 // Find service config in TXT record.
Mark D. Rothf9bf4282017-08-03 14:47:23 -0700287 for (result = reply; result != NULL; result = result->next) {
288 if (result->record_start &&
289 memcmp(result->txt, g_service_config_attribute_prefix, prefix_len) ==
290 0) {
291 break;
292 }
293 }
294 // Found a service config record.
295 if (result != NULL) {
296 size_t service_config_len = result->length - prefix_len;
Yash Tibrewalca3c1c02017-09-07 22:47:16 -0700297 *r->service_config_json_out = (char *)gpr_malloc(service_config_len + 1);
Mark D. Rothf9bf4282017-08-03 14:47:23 -0700298 memcpy(*r->service_config_json_out, result->txt + prefix_len,
299 service_config_len);
300 for (result = result->next; result != NULL && !result->record_start;
301 result = result->next) {
Yash Tibrewalca3c1c02017-09-07 22:47:16 -0700302 *r->service_config_json_out = (char *)gpr_realloc(
Mark D. Rothf9bf4282017-08-03 14:47:23 -0700303 *r->service_config_json_out, service_config_len + result->length + 1);
304 memcpy(*r->service_config_json_out + service_config_len, result->txt,
305 result->length);
306 service_config_len += result->length;
307 }
308 (*r->service_config_json_out)[service_config_len] = '\0';
309 gpr_log(GPR_INFO, "found service config: %s", *r->service_config_json_out);
310 }
311 // Clean up.
312 ares_free_data(reply);
313 goto done;
314fail:
315 gpr_asprintf(&error_msg, "C-ares TXT lookup status is not ARES_SUCCESS: %s",
316 ares_strerror(status));
Yash Tibrewal533d1182017-09-18 10:48:22 -0700317 error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(error_msg);
Mark D. Rothf9bf4282017-08-03 14:47:23 -0700318 gpr_free(error_msg);
319 if (r->error == GRPC_ERROR_NONE) {
320 r->error = error;
321 } else {
322 r->error = grpc_error_add_child(error, r->error);
323 }
324done:
325 gpr_mu_unlock(&r->mu);
326 grpc_ares_request_unref(NULL, r);
327}
328
Yuchen Zeng4ebace72017-06-05 17:24:06 -0700329static grpc_ares_request *grpc_dns_lookup_ares_impl(
Yuchen Zeng3b4bed22017-06-04 01:41:15 -0700330 grpc_exec_ctx *exec_ctx, const char *dns_server, const char *name,
331 const char *default_port, grpc_pollset_set *interested_parties,
Mark D. Rothf9bf4282017-08-03 14:47:23 -0700332 grpc_closure *on_done, grpc_lb_addresses **addrs, bool check_grpclb,
333 char **service_config_json) {
Mark D. Roth96fc54c2017-05-18 14:33:07 -0700334 grpc_error *error = GRPC_ERROR_NONE;
Yash Tibrewal533d1182017-09-18 10:48:22 -0700335 grpc_ares_hostbyname_request *hr = NULL;
336 grpc_ares_request *r = NULL;
337 ares_channel *channel = NULL;
Yuchen Zenge5230b72017-03-17 15:10:49 -0700338 /* TODO(zyc): Enable tracing after #9603 is checked in */
339 /* if (grpc_dns_trace) {
340 gpr_log(GPR_DEBUG, "resolve_address (blocking): name=%s, default_port=%s",
341 name, default_port);
342 } */
343
Yuchen Zengd4bbfc72016-08-05 10:33:16 -0700344 /* parse name, splitting it into host and port parts */
Yuchen Zeng3ae26632016-11-09 15:53:50 -0800345 char *host;
346 char *port;
Yuchen Zengd4bbfc72016-08-05 10:33:16 -0700347 gpr_split_host_port(name, &host, &port);
348 if (host == NULL) {
Mark D. Roth96fc54c2017-05-18 14:33:07 -0700349 error = grpc_error_set_str(
Yuchen Zeng0e8bc452017-03-23 14:44:14 -0700350 GRPC_ERROR_CREATE_FROM_STATIC_STRING("unparseable host:port"),
351 GRPC_ERROR_STR_TARGET_ADDRESS, grpc_slice_from_copied_string(name));
Yuchen Zeng3ae26632016-11-09 15:53:50 -0800352 goto error_cleanup;
Yuchen Zengd4bbfc72016-08-05 10:33:16 -0700353 } else if (port == NULL) {
354 if (default_port == NULL) {
Mark D. Roth96fc54c2017-05-18 14:33:07 -0700355 error = grpc_error_set_str(
Yuchen Zeng0e8bc452017-03-23 14:44:14 -0700356 GRPC_ERROR_CREATE_FROM_STATIC_STRING("no port in name"),
357 GRPC_ERROR_STR_TARGET_ADDRESS, grpc_slice_from_copied_string(name));
Yuchen Zeng3ae26632016-11-09 15:53:50 -0800358 goto error_cleanup;
Yuchen Zengd4bbfc72016-08-05 10:33:16 -0700359 }
360 port = gpr_strdup(default_port);
Yuchen Zengdb53cc02016-08-10 05:04:53 -0700361 }
362
Yuchen Zeng117a3002016-11-17 19:43:36 -0800363 grpc_ares_ev_driver *ev_driver;
Mark D. Roth96fc54c2017-05-18 14:33:07 -0700364 error = grpc_ares_ev_driver_create(&ev_driver, interested_parties);
365 if (error != GRPC_ERROR_NONE) goto error_cleanup;
Yuchen Zeng117a3002016-11-17 19:43:36 -0800366
Yash Tibrewal533d1182017-09-18 10:48:22 -0700367 r = (grpc_ares_request *)gpr_zalloc(sizeof(grpc_ares_request));
Yuchen Zeng3ae26632016-11-09 15:53:50 -0800368 gpr_mu_init(&r->mu);
369 r->ev_driver = ev_driver;
370 r->on_done = on_done;
Yuchen Zeng3385b4f2017-05-24 11:40:20 -0700371 r->lb_addrs_out = addrs;
Mark D. Rothf9bf4282017-08-03 14:47:23 -0700372 r->service_config_json_out = service_config_json;
Yuchen Zeng3ae26632016-11-09 15:53:50 -0800373 r->success = false;
374 r->error = GRPC_ERROR_NONE;
Yash Tibrewal533d1182017-09-18 10:48:22 -0700375 channel = grpc_ares_ev_driver_get_channel(r->ev_driver);
Mark D. Roth96fc54c2017-05-18 14:33:07 -0700376
377 // If dns_server is specified, use it.
378 if (dns_server != NULL) {
379 gpr_log(GPR_INFO, "Using DNS server %s", dns_server);
380 grpc_resolved_address addr;
381 if (grpc_parse_ipv4_hostport(dns_server, &addr, false /* log_errors */)) {
382 r->dns_server_addr.family = AF_INET;
Mark D. Rothf9bf4282017-08-03 14:47:23 -0700383 struct sockaddr_in *in = (struct sockaddr_in *)addr.addr;
384 memcpy(&r->dns_server_addr.addr.addr4, &in->sin_addr,
385 sizeof(struct in_addr));
Mark D. Roth96fc54c2017-05-18 14:33:07 -0700386 r->dns_server_addr.tcp_port = grpc_sockaddr_get_port(&addr);
387 r->dns_server_addr.udp_port = grpc_sockaddr_get_port(&addr);
388 } else if (grpc_parse_ipv6_hostport(dns_server, &addr,
389 false /* log_errors */)) {
390 r->dns_server_addr.family = AF_INET6;
Mark D. Rothf9bf4282017-08-03 14:47:23 -0700391 struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)addr.addr;
392 memcpy(&r->dns_server_addr.addr.addr6, &in6->sin6_addr,
393 sizeof(struct in6_addr));
Mark D. Roth96fc54c2017-05-18 14:33:07 -0700394 r->dns_server_addr.tcp_port = grpc_sockaddr_get_port(&addr);
395 r->dns_server_addr.udp_port = grpc_sockaddr_get_port(&addr);
396 } else {
397 error = grpc_error_set_str(
398 GRPC_ERROR_CREATE_FROM_STATIC_STRING("cannot parse authority"),
399 GRPC_ERROR_STR_TARGET_ADDRESS, grpc_slice_from_copied_string(name));
Yuchen Zeng42e1f692017-05-21 15:34:37 -0700400 gpr_free(r);
Mark D. Roth96fc54c2017-05-18 14:33:07 -0700401 goto error_cleanup;
402 }
403 int status = ares_set_servers_ports(*channel, &r->dns_server_addr);
404 if (status != ARES_SUCCESS) {
405 char *error_msg;
406 gpr_asprintf(&error_msg, "C-ares status is not ARES_SUCCESS: %s",
407 ares_strerror(status));
408 error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(error_msg);
409 gpr_free(error_msg);
Yuchen Zeng42e1f692017-05-21 15:34:37 -0700410 gpr_free(r);
Mark D. Roth96fc54c2017-05-18 14:33:07 -0700411 goto error_cleanup;
412 }
413 }
Yuchen Zengf3bdbb72017-05-18 18:22:23 -0700414 gpr_ref_init(&r->pending_queries, 1);
Yuchen Zengdc6b5692017-02-13 22:44:01 -0800415 if (grpc_ipv6_loopback_available()) {
Yash Tibrewal533d1182017-09-18 10:48:22 -0700416 hr = create_hostbyname_request(r, host, strhtons(port),
417 false /* is_balancer */);
Yuchen Zengf3bdbb72017-05-18 18:22:23 -0700418 ares_gethostbyname(*channel, hr->host, AF_INET6, on_hostbyname_done_cb, hr);
Yuchen Zengdc6b5692017-02-13 22:44:01 -0800419 }
Yash Tibrewal533d1182017-09-18 10:48:22 -0700420 hr = create_hostbyname_request(r, host, strhtons(port),
421 false /* is_balancer */);
Yuchen Zengf3bdbb72017-05-18 18:22:23 -0700422 ares_gethostbyname(*channel, hr->host, AF_INET, on_hostbyname_done_cb, hr);
Yuchen Zeng94c57762017-05-19 16:30:08 -0700423 if (check_grpclb) {
Yuchen Zengf3bdbb72017-05-18 18:22:23 -0700424 /* Query the SRV record */
425 grpc_ares_request_ref(r);
426 char *service_name;
427 gpr_asprintf(&service_name, "_grpclb._tcp.%s", host);
428 ares_query(*channel, service_name, ns_c_in, ns_t_srv, on_srv_query_done_cb,
429 r);
430 gpr_free(service_name);
431 }
Mark D. Rothf9bf4282017-08-03 14:47:23 -0700432 if (service_config_json != NULL) {
433 grpc_ares_request_ref(r);
434 ares_search(*channel, hr->host, ns_c_in, ns_t_txt, on_txt_done_cb, r);
435 }
Yuchen Zenge5230b72017-03-17 15:10:49 -0700436 /* TODO(zyc): Handle CNAME records here. */
Yuchen Zengdc6b5692017-02-13 22:44:01 -0800437 grpc_ares_ev_driver_start(exec_ctx, r->ev_driver);
438 grpc_ares_request_unref(exec_ctx, r);
Yuchen Zeng42e1f692017-05-21 15:34:37 -0700439 gpr_free(host);
440 gpr_free(port);
Yuchen Zeng3b4bed22017-06-04 01:41:15 -0700441 return r;
Yuchen Zengd4bbfc72016-08-05 10:33:16 -0700442
Yuchen Zeng3ae26632016-11-09 15:53:50 -0800443error_cleanup:
ncteisen274bbbe2017-06-08 14:57:11 -0700444 GRPC_CLOSURE_SCHED(exec_ctx, on_done, error);
Yuchen Zengd4bbfc72016-08-05 10:33:16 -0700445 gpr_free(host);
446 gpr_free(port);
Yuchen Zeng3b4bed22017-06-04 01:41:15 -0700447 return NULL;
Yuchen Zengd4bbfc72016-08-05 10:33:16 -0700448}
449
Yuchen Zeng3b4bed22017-06-04 01:41:15 -0700450grpc_ares_request *(*grpc_dns_lookup_ares)(
451 grpc_exec_ctx *exec_ctx, const char *dns_server, const char *name,
452 const char *default_port, grpc_pollset_set *interested_parties,
Mark D. Rothf9bf4282017-08-03 14:47:23 -0700453 grpc_closure *on_done, grpc_lb_addresses **addrs, bool check_grpclb,
454 char **service_config_json) = grpc_dns_lookup_ares_impl;
Mark D. Roth96fc54c2017-05-18 14:33:07 -0700455
Yuchen Zeng3b4bed22017-06-04 01:41:15 -0700456void grpc_cancel_ares_request(grpc_exec_ctx *exec_ctx, grpc_ares_request *r) {
457 if (grpc_dns_lookup_ares == grpc_dns_lookup_ares_impl) {
458 grpc_ares_ev_driver_shutdown(exec_ctx, r->ev_driver);
459 }
460}
Yuchen Zeng8917aec2016-08-09 18:41:31 -0700461
Yuchen Zeng85750b02016-08-08 14:16:34 -0700462grpc_error *grpc_ares_init(void) {
Yuchen Zeng459480b2016-08-09 11:40:26 -0700463 gpr_once_init(&g_basic_init, do_basic_init);
464 gpr_mu_lock(&g_init_mu);
Yuchen Zengd4bbfc72016-08-05 10:33:16 -0700465 int status = ares_library_init(ARES_LIB_INIT_ALL);
Yuchen Zeng459480b2016-08-09 11:40:26 -0700466 gpr_mu_unlock(&g_init_mu);
467
Yuchen Zengd4bbfc72016-08-05 10:33:16 -0700468 if (status != ARES_SUCCESS) {
Yuchen Zeng912327e2016-10-25 18:27:17 -0700469 char *error_msg;
470 gpr_asprintf(&error_msg, "ares_library_init failed: %s",
471 ares_strerror(status));
Yuchen Zeng0e8bc452017-03-23 14:44:14 -0700472 grpc_error *error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(error_msg);
Yuchen Zeng912327e2016-10-25 18:27:17 -0700473 gpr_free(error_msg);
474 return error;
Yuchen Zengd4bbfc72016-08-05 10:33:16 -0700475 }
Yuchen Zeng85750b02016-08-08 14:16:34 -0700476 return GRPC_ERROR_NONE;
477}
478
Yuchen Zeng459480b2016-08-09 11:40:26 -0700479void grpc_ares_cleanup(void) {
480 gpr_mu_lock(&g_init_mu);
481 ares_library_cleanup();
482 gpr_mu_unlock(&g_init_mu);
483}
Yuchen Zeng299dd8d2016-08-16 21:40:13 -0700484
Yuchen Zeng3385b4f2017-05-24 11:40:20 -0700485/*
486 * grpc_resolve_address_ares related structs and functions
487 */
488
489typedef struct grpc_resolve_address_ares_request {
490 /** the pointer to receive the resolved addresses */
491 grpc_resolved_addresses **addrs_out;
492 /** currently resolving lb addresses */
493 grpc_lb_addresses *lb_addrs;
494 /** closure to call when the resolve_address_ares request completes */
495 grpc_closure *on_resolve_address_done;
496 /** a closure wrapping on_dns_lookup_done_cb, which should be invoked when the
497 grpc_dns_lookup_ares operation is done. */
498 grpc_closure on_dns_lookup_done;
499} grpc_resolve_address_ares_request;
500
501static void on_dns_lookup_done_cb(grpc_exec_ctx *exec_ctx, void *arg,
502 grpc_error *error) {
503 grpc_resolve_address_ares_request *r =
504 (grpc_resolve_address_ares_request *)arg;
505 grpc_resolved_addresses **resolved_addresses = r->addrs_out;
506 if (r->lb_addrs == NULL || r->lb_addrs->num_addresses == 0) {
507 *resolved_addresses = NULL;
508 } else {
Yash Tibrewalca3c1c02017-09-07 22:47:16 -0700509 *resolved_addresses =
510 (grpc_resolved_addresses *)gpr_zalloc(sizeof(grpc_resolved_addresses));
Yuchen Zeng3385b4f2017-05-24 11:40:20 -0700511 (*resolved_addresses)->naddrs = r->lb_addrs->num_addresses;
Yash Tibrewalca3c1c02017-09-07 22:47:16 -0700512 (*resolved_addresses)->addrs = (grpc_resolved_address *)gpr_zalloc(
513 sizeof(grpc_resolved_address) * (*resolved_addresses)->naddrs);
Yuchen Zeng3385b4f2017-05-24 11:40:20 -0700514 for (size_t i = 0; i < (*resolved_addresses)->naddrs; i++) {
515 GPR_ASSERT(!r->lb_addrs->addresses[i].is_balancer);
516 memcpy(&(*resolved_addresses)->addrs[i],
517 &r->lb_addrs->addresses[i].address, sizeof(grpc_resolved_address));
518 }
519 }
ncteisen274bbbe2017-06-08 14:57:11 -0700520 GRPC_CLOSURE_SCHED(exec_ctx, r->on_resolve_address_done,
Yuchen Zeng3385b4f2017-05-24 11:40:20 -0700521 GRPC_ERROR_REF(error));
Yuchen Zeng4c15fac2017-05-24 16:40:20 -0700522 grpc_lb_addresses_destroy(exec_ctx, r->lb_addrs);
Yuchen Zeng3385b4f2017-05-24 11:40:20 -0700523 gpr_free(r);
524}
525
Yuchen Zeng4ebace72017-06-05 17:24:06 -0700526static void grpc_resolve_address_ares_impl(grpc_exec_ctx *exec_ctx,
527 const char *name,
528 const char *default_port,
529 grpc_pollset_set *interested_parties,
530 grpc_closure *on_done,
531 grpc_resolved_addresses **addrs) {
Yuchen Zeng3385b4f2017-05-24 11:40:20 -0700532 grpc_resolve_address_ares_request *r =
Yash Tibrewalbc130da2017-09-12 22:44:08 -0700533 (grpc_resolve_address_ares_request *)gpr_zalloc(
534 sizeof(grpc_resolve_address_ares_request));
Yuchen Zeng3385b4f2017-05-24 11:40:20 -0700535 r->addrs_out = addrs;
536 r->on_resolve_address_done = on_done;
ncteisen274bbbe2017-06-08 14:57:11 -0700537 GRPC_CLOSURE_INIT(&r->on_dns_lookup_done, on_dns_lookup_done_cb, r,
Yuchen Zeng3385b4f2017-05-24 11:40:20 -0700538 grpc_schedule_on_exec_ctx);
539 grpc_dns_lookup_ares(exec_ctx, NULL /* dns_server */, name, default_port,
540 interested_parties, &r->on_dns_lookup_done, &r->lb_addrs,
Mark D. Rothf9bf4282017-08-03 14:47:23 -0700541 false /* check_grpclb */,
542 NULL /* service_config_json */);
Yuchen Zeng3385b4f2017-05-24 11:40:20 -0700543}
544
545void (*grpc_resolve_address_ares)(
546 grpc_exec_ctx *exec_ctx, const char *name, const char *default_port,
547 grpc_pollset_set *interested_parties, grpc_closure *on_done,
548 grpc_resolved_addresses **addrs) = grpc_resolve_address_ares_impl;
549
Yuchen Zengd6b49852017-03-20 01:44:27 -0700550#endif /* GRPC_ARES == 1 && !defined(GRPC_UV) */