blob: 95f38ecab752e119a7921a5514178c43a7e2bd10 [file] [log] [blame]
Craig Tillercd29c582015-06-24 09:15:15 -07001/*
2 *
3 * Copyright 2015, 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/client_config/resolvers/dns_resolver.h"
35
Craig Tiller3bc8ebd2015-06-24 15:41:15 -070036#include <string.h>
37
38#include <grpc/support/alloc.h>
39#include <grpc/support/string_util.h>
40
41#include "src/core/iomgr/resolve_address.h"
42#include "src/core/support/string.h"
43
44typedef struct {
45 /** base class: must be first */
46 grpc_resolver base;
47 /** refcount */
48 gpr_refcount refs;
49 /** name to resolve */
50 char *name;
51 /** default port to use */
52 char *default_port;
53 /** subchannel factory */
54 grpc_subchannel_factory *subchannel_factory;
55 /** load balancing policy factory */
56 grpc_lb_policy *(*lb_policy_factory)(grpc_subchannel **subchannels,
57 size_t num_subchannels);
58
59 /** mutex guarding the rest of the state */
60 gpr_mu mu;
61 /** are we currently resolving? */
62 int resolving;
63 /** which version of resolved_config have we published? */
64 int published_version;
65 /** which version of resolved_config is current? */
66 int resolved_version;
67 /** pending next completion, or NULL */
68 grpc_iomgr_closure *next_completion;
69 /** target config address for next completion */
70 grpc_client_config **target_config;
71 /** current (fully resolved) config */
72 grpc_client_config *resolved_config;
73} dns_resolver;
74
75static void dns_destroy(dns_resolver *r);
76
77static void dns_start_resolving_locked(dns_resolver *r);
78static void dns_maybe_finish_next_locked(dns_resolver *r);
79
80static void dns_ref(grpc_resolver *r);
81static void dns_unref(grpc_resolver *r);
82static void dns_shutdown(grpc_resolver *r);
83static void dns_channel_saw_error(grpc_resolver *r,
84 struct sockaddr *failing_address,
85 int failing_address_len);
86static void dns_next(grpc_resolver *r, grpc_client_config **target_config,
87 grpc_iomgr_closure *on_complete);
88
89static const grpc_resolver_vtable dns_resolver_vtable = {
90 dns_ref, dns_unref, dns_shutdown, dns_channel_saw_error, dns_next};
91
92static void dns_ref(grpc_resolver *resolver) {
93 dns_resolver *r = (dns_resolver *)resolver;
94 gpr_ref(&r->refs);
95}
96
97static void dns_unref(grpc_resolver *resolver) {
98 dns_resolver *r = (dns_resolver *)resolver;
99 if (gpr_unref(&r->refs)) {
100 dns_destroy(r);
101 }
102}
103
104static void dns_shutdown(grpc_resolver *resolver) {
105 dns_resolver *r = (dns_resolver *)resolver;
106 gpr_mu_lock(&r->mu);
107 if (r->next_completion != NULL) {
108 *r->target_config = NULL;
109 /* TODO(ctiller): add delayed callback */
110 grpc_iomgr_add_callback(r->next_completion);
111 r->next_completion = NULL;
112 }
113 gpr_mu_unlock(&r->mu);
114}
115
116static void dns_channel_saw_error(grpc_resolver *resolver, struct sockaddr *sa,
117 int len) {
118 dns_resolver *r = (dns_resolver *)resolver;
119 gpr_mu_lock(&r->mu);
120 if (!r->resolving) {
121 dns_start_resolving_locked(r);
122 }
123 gpr_mu_unlock(&r->mu);
124}
125
126static void dns_next(grpc_resolver *resolver,
127 grpc_client_config **target_config,
128 grpc_iomgr_closure *on_complete) {
129 dns_resolver *r = (dns_resolver *)resolver;
130 gpr_mu_lock(&r->mu);
131 GPR_ASSERT(!r->next_completion);
132 r->next_completion = on_complete;
133 r->target_config = target_config;
134 if (r->resolved_version == 0 && !r->resolving) {
135 dns_start_resolving_locked(r);
136 } else {
137 dns_maybe_finish_next_locked(r);
138 }
139 gpr_mu_unlock(&r->mu);
140}
141
142static void dns_on_resolved(void *arg, grpc_resolved_addresses *addresses) {
143 dns_resolver *r = arg;
144 grpc_client_config *config = NULL;
145 grpc_subchannel **subchannels;
146 grpc_subchannel_args args;
147 size_t i;
148 if (addresses) {
149 config = grpc_client_config_create();
150 subchannels = gpr_malloc(sizeof(grpc_subchannel *) * addresses->naddrs);
151 for (i = 0; i < addresses->naddrs; i++) {
152 memset(&args, 0, sizeof(args));
153 args.addr = (struct sockaddr *)(addresses->addrs[i].addr);
154 args.addr_len = addresses->addrs[i].len;
155 subchannels[i] = grpc_subchannel_factory_create_subchannel(
156 r->subchannel_factory, &args);
157 }
158 grpc_client_config_set_lb_policy(
159 config, r->lb_policy_factory(subchannels, addresses->naddrs));
160 }
161 gpr_mu_lock(&r->mu);
162 if (r->resolved_config) {
163 grpc_client_config_unref(r->resolved_config);
164 }
165 r->resolved_config = config;
166 r->resolved_version++;
167 dns_maybe_finish_next_locked(r);
168 gpr_mu_unlock(&r->mu);
169}
170
171static void dns_start_resolving_locked(dns_resolver *r) {
172 dns_ref(&r->base);
173 r->resolving = 1;
174 grpc_resolve_address(r->name, r->default_port, dns_on_resolved, r);
175}
176
177static void dns_maybe_finish_next_locked(dns_resolver *r) {
178 if (r->next_completion != NULL &&
179 r->resolved_version != r->published_version) {
180 grpc_iomgr_add_callback(r->next_completion);
181 r->next_completion = NULL;
182 r->published_version = r->resolved_version;
183 }
184}
185
186static void dns_destroy(dns_resolver *r) {
187 gpr_mu_destroy(&r->mu);
188 grpc_subchannel_factory_unref(r->subchannel_factory);
189 gpr_free(r->name);
190 gpr_free(r->default_port);
191 gpr_free(r);
192}
193
194static grpc_resolver *dns_create(grpc_uri *uri, const char *default_port,
195 grpc_subchannel_factory *subchannel_factory) {
196 dns_resolver *r;
197 const char *path = uri->path;
198
199 if (0 != strcmp(uri->authority, "")) {
200 gpr_log(GPR_ERROR, "authority based uri's not supported");
201 return NULL;
202 }
203
204 if (path[0] == '/') ++path;
205
206 r = gpr_malloc(sizeof(dns_resolver));
207 memset(r, 0, sizeof(*r));
208 gpr_ref_init(&r->refs, 1);
209 gpr_mu_init(&r->mu);
210 r->base.vtable = &dns_resolver_vtable;
211 r->name = gpr_strdup(path);
212 r->default_port = gpr_strdup(default_port);
213 r->subchannel_factory = subchannel_factory;
214 grpc_subchannel_factory_ref(subchannel_factory);
215 return &r->base;
216}
217
218/*
219 * FACTORY
220 */
221
222typedef struct {
223 /** base: must be first */
224 grpc_resolver_factory base;
225 /** ref count */
226 gpr_refcount refs;
227 /** default port */
228 char *default_port;
229} dns_resolver_factory;
230
231static void dns_factory_ref(grpc_resolver_factory *factory) {
232 dns_resolver_factory *f = (dns_resolver_factory *)factory;
233 gpr_ref(&f->refs);
234}
235
236static void dns_factory_unref(grpc_resolver_factory *factory) {
237 dns_resolver_factory *f = (dns_resolver_factory *)factory;
238 if (gpr_unref(&f->refs)) {
239 gpr_free(f->default_port);
240 gpr_free(f);
241 }
242}
243
244static grpc_resolver *dns_factory_create_resolver(
245 grpc_resolver_factory *factory, grpc_uri *uri,
246 grpc_subchannel_factory *subchannel_factory) {
247 dns_resolver_factory *f = (dns_resolver_factory *)factory;
248 return dns_create(uri, f->default_port, subchannel_factory);
249}
250
251static const grpc_resolver_factory_vtable dns_factory_vtable = {
252 dns_factory_ref, dns_factory_unref, dns_factory_create_resolver};
253
254grpc_resolver_factory *grpc_dns_resolver_factory_create(
255 const char *default_port) {
256 dns_resolver_factory *f = gpr_malloc(sizeof(*f));
257 memset(f, 0, sizeof(*f));
258 f->base.vtable = &dns_factory_vtable;
259 f->default_port = gpr_strdup(default_port);
260 return &f->base;
261}