mirror of https://github.com/grpc/grpc.git
Merge pull request #2208 from ctiller/tis-but-thy-name
Client configuration for corepull/2303/head^2
commit
772187cdf0
117 changed files with 5275 additions and 2559 deletions
@ -1,308 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#include "src/core/channel/child_channel.h" |
||||
#include "src/core/iomgr/iomgr.h" |
||||
#include <grpc/support/alloc.h> |
||||
|
||||
/* Link back filter: passes up calls to the client channel, pushes down calls
|
||||
down */ |
||||
|
||||
static void maybe_destroy_channel(grpc_child_channel *channel); |
||||
|
||||
typedef struct { |
||||
gpr_mu mu; |
||||
gpr_cv cv; |
||||
grpc_channel_element *back; |
||||
/* # of active calls on the channel */ |
||||
gpr_uint32 active_calls; |
||||
/* has grpc_child_channel_destroy been called? */ |
||||
gpr_uint8 destroyed; |
||||
/* has the transport reported itself disconnected? */ |
||||
gpr_uint8 disconnected; |
||||
/* are we calling 'back' - our parent channel */ |
||||
gpr_uint8 calling_back; |
||||
/* have we or our parent sent goaway yet? - dup suppression */ |
||||
gpr_uint8 sent_goaway; |
||||
/* are we currently sending farewell (in this file: goaway + disconnect) */ |
||||
gpr_uint8 sending_farewell; |
||||
/* have we sent farewell (goaway + disconnect) */ |
||||
gpr_uint8 sent_farewell; |
||||
|
||||
grpc_iomgr_closure finally_destroy_channel_closure; |
||||
grpc_iomgr_closure send_farewells_closure; |
||||
} lb_channel_data; |
||||
|
||||
typedef struct { grpc_child_channel *channel; } lb_call_data; |
||||
|
||||
static void lb_start_transport_op(grpc_call_element *elem, |
||||
grpc_transport_op *op) { |
||||
grpc_call_next_op(elem, op); |
||||
} |
||||
|
||||
/* Currently we assume all channel operations should just be pushed up. */ |
||||
static void lb_channel_op(grpc_channel_element *elem, |
||||
grpc_channel_element *from_elem, |
||||
grpc_channel_op *op) { |
||||
lb_channel_data *chand = elem->channel_data; |
||||
grpc_channel_element *back; |
||||
int calling_back = 0; |
||||
|
||||
switch (op->dir) { |
||||
case GRPC_CALL_UP: |
||||
gpr_mu_lock(&chand->mu); |
||||
back = chand->back; |
||||
if (back) { |
||||
chand->calling_back++; |
||||
calling_back = 1; |
||||
} |
||||
gpr_mu_unlock(&chand->mu); |
||||
if (back) { |
||||
back->filter->channel_op(chand->back, elem, op); |
||||
} else if (op->type == GRPC_TRANSPORT_GOAWAY) { |
||||
gpr_slice_unref(op->data.goaway.message); |
||||
} |
||||
break; |
||||
case GRPC_CALL_DOWN: |
||||
grpc_channel_next_op(elem, op); |
||||
break; |
||||
} |
||||
|
||||
gpr_mu_lock(&chand->mu); |
||||
switch (op->type) { |
||||
case GRPC_TRANSPORT_CLOSED: |
||||
chand->disconnected = 1; |
||||
maybe_destroy_channel(grpc_channel_stack_from_top_element(elem)); |
||||
break; |
||||
case GRPC_CHANNEL_GOAWAY: |
||||
chand->sent_goaway = 1; |
||||
break; |
||||
case GRPC_CHANNEL_DISCONNECT: |
||||
case GRPC_TRANSPORT_GOAWAY: |
||||
case GRPC_ACCEPT_CALL: |
||||
break; |
||||
} |
||||
|
||||
if (calling_back) { |
||||
chand->calling_back--; |
||||
gpr_cv_signal(&chand->cv); |
||||
maybe_destroy_channel(grpc_channel_stack_from_top_element(elem)); |
||||
} |
||||
gpr_mu_unlock(&chand->mu); |
||||
} |
||||
|
||||
/* Constructor for call_data */ |
||||
static void lb_init_call_elem(grpc_call_element *elem, |
||||
const void *server_transport_data, |
||||
grpc_transport_op *initial_op) {} |
||||
|
||||
/* Destructor for call_data */ |
||||
static void lb_destroy_call_elem(grpc_call_element *elem) {} |
||||
|
||||
/* Constructor for channel_data */ |
||||
static void lb_init_channel_elem(grpc_channel_element *elem, |
||||
const grpc_channel_args *args, |
||||
grpc_mdctx *metadata_context, int is_first, |
||||
int is_last) { |
||||
lb_channel_data *chand = elem->channel_data; |
||||
GPR_ASSERT(is_first); |
||||
GPR_ASSERT(!is_last); |
||||
gpr_mu_init(&chand->mu); |
||||
gpr_cv_init(&chand->cv); |
||||
chand->back = NULL; |
||||
chand->destroyed = 0; |
||||
chand->disconnected = 0; |
||||
chand->active_calls = 0; |
||||
chand->sent_goaway = 0; |
||||
chand->calling_back = 0; |
||||
chand->sending_farewell = 0; |
||||
chand->sent_farewell = 0; |
||||
} |
||||
|
||||
/* Destructor for channel_data */ |
||||
static void lb_destroy_channel_elem(grpc_channel_element *elem) { |
||||
lb_channel_data *chand = elem->channel_data; |
||||
gpr_mu_destroy(&chand->mu); |
||||
gpr_cv_destroy(&chand->cv); |
||||
} |
||||
|
||||
const grpc_channel_filter grpc_child_channel_top_filter = { |
||||
lb_start_transport_op, lb_channel_op, |
||||
sizeof(lb_call_data), lb_init_call_elem, lb_destroy_call_elem, |
||||
sizeof(lb_channel_data), lb_init_channel_elem, lb_destroy_channel_elem, |
||||
"child-channel", |
||||
}; |
||||
|
||||
/* grpc_child_channel proper */ |
||||
|
||||
#define LINK_BACK_ELEM_FROM_CHANNEL(channel) \ |
||||
grpc_channel_stack_element((channel), 0) |
||||
|
||||
#define LINK_BACK_ELEM_FROM_CALL(call) grpc_call_stack_element((call), 0) |
||||
|
||||
static void finally_destroy_channel(void *c, int success) { |
||||
/* ignore success or not... this is a destruction callback and will only
|
||||
happen once - the only purpose here is to release resources */ |
||||
grpc_child_channel *channel = c; |
||||
lb_channel_data *chand = LINK_BACK_ELEM_FROM_CHANNEL(channel)->channel_data; |
||||
/* wait for the initiator to leave the mutex */ |
||||
gpr_mu_lock(&chand->mu); |
||||
gpr_mu_unlock(&chand->mu); |
||||
grpc_channel_stack_destroy(channel); |
||||
gpr_free(channel); |
||||
} |
||||
|
||||
static void send_farewells(void *c, int success) { |
||||
grpc_child_channel *channel = c; |
||||
grpc_channel_element *lbelem = LINK_BACK_ELEM_FROM_CHANNEL(channel); |
||||
lb_channel_data *chand = lbelem->channel_data; |
||||
int send_goaway; |
||||
grpc_channel_op op; |
||||
|
||||
gpr_mu_lock(&chand->mu); |
||||
send_goaway = !chand->sent_goaway; |
||||
chand->sent_goaway = 1; |
||||
gpr_mu_unlock(&chand->mu); |
||||
|
||||
if (send_goaway) { |
||||
op.type = GRPC_CHANNEL_GOAWAY; |
||||
op.dir = GRPC_CALL_DOWN; |
||||
op.data.goaway.status = GRPC_STATUS_OK; |
||||
op.data.goaway.message = gpr_slice_from_copied_string("Client disconnect"); |
||||
grpc_channel_next_op(lbelem, &op); |
||||
} |
||||
|
||||
op.type = GRPC_CHANNEL_DISCONNECT; |
||||
op.dir = GRPC_CALL_DOWN; |
||||
grpc_channel_next_op(lbelem, &op); |
||||
|
||||
gpr_mu_lock(&chand->mu); |
||||
chand->sending_farewell = 0; |
||||
chand->sent_farewell = 1; |
||||
maybe_destroy_channel(channel); |
||||
gpr_mu_unlock(&chand->mu); |
||||
} |
||||
|
||||
static void maybe_destroy_channel(grpc_child_channel *channel) { |
||||
lb_channel_data *chand = LINK_BACK_ELEM_FROM_CHANNEL(channel)->channel_data; |
||||
if (chand->destroyed && chand->disconnected && chand->active_calls == 0 && |
||||
!chand->sending_farewell && !chand->calling_back) { |
||||
chand->finally_destroy_channel_closure.cb = finally_destroy_channel; |
||||
chand->finally_destroy_channel_closure.cb_arg = channel; |
||||
grpc_iomgr_add_callback(&chand->finally_destroy_channel_closure); |
||||
} else if (chand->destroyed && !chand->disconnected && |
||||
chand->active_calls == 0 && !chand->sending_farewell && |
||||
!chand->sent_farewell) { |
||||
chand->sending_farewell = 1; |
||||
chand->send_farewells_closure.cb = send_farewells; |
||||
chand->send_farewells_closure.cb_arg = channel; |
||||
grpc_iomgr_add_callback(&chand->send_farewells_closure); |
||||
} |
||||
} |
||||
|
||||
grpc_child_channel *grpc_child_channel_create( |
||||
grpc_channel_element *parent, const grpc_channel_filter **filters, |
||||
size_t filter_count, const grpc_channel_args *args, |
||||
grpc_mdctx *metadata_context) { |
||||
grpc_channel_stack *stk = |
||||
gpr_malloc(grpc_channel_stack_size(filters, filter_count)); |
||||
lb_channel_data *lb; |
||||
|
||||
grpc_channel_stack_init(filters, filter_count, args, metadata_context, stk); |
||||
|
||||
lb = LINK_BACK_ELEM_FROM_CHANNEL(stk)->channel_data; |
||||
gpr_mu_lock(&lb->mu); |
||||
lb->back = parent; |
||||
gpr_mu_unlock(&lb->mu); |
||||
|
||||
return stk; |
||||
} |
||||
|
||||
void grpc_child_channel_destroy(grpc_child_channel *channel, |
||||
int wait_for_callbacks) { |
||||
grpc_channel_element *lbelem = LINK_BACK_ELEM_FROM_CHANNEL(channel); |
||||
lb_channel_data *chand = lbelem->channel_data; |
||||
|
||||
gpr_mu_lock(&chand->mu); |
||||
while (wait_for_callbacks && chand->calling_back) { |
||||
gpr_cv_wait(&chand->cv, &chand->mu, gpr_inf_future); |
||||
} |
||||
|
||||
chand->back = NULL; |
||||
chand->destroyed = 1; |
||||
maybe_destroy_channel(channel); |
||||
gpr_mu_unlock(&chand->mu); |
||||
} |
||||
|
||||
void grpc_child_channel_handle_op(grpc_child_channel *channel, |
||||
grpc_channel_op *op) { |
||||
grpc_channel_next_op(LINK_BACK_ELEM_FROM_CHANNEL(channel), op); |
||||
} |
||||
|
||||
grpc_child_call *grpc_child_channel_create_call(grpc_child_channel *channel, |
||||
grpc_call_element *parent, |
||||
grpc_transport_op *initial_op) { |
||||
grpc_call_stack *stk = gpr_malloc((channel)->call_stack_size); |
||||
grpc_call_element *lbelem; |
||||
lb_call_data *lbcalld; |
||||
lb_channel_data *lbchand; |
||||
|
||||
grpc_call_stack_init(channel, NULL, initial_op, stk); |
||||
lbelem = LINK_BACK_ELEM_FROM_CALL(stk); |
||||
lbchand = lbelem->channel_data; |
||||
lbcalld = lbelem->call_data; |
||||
lbcalld->channel = channel; |
||||
|
||||
gpr_mu_lock(&lbchand->mu); |
||||
lbchand->active_calls++; |
||||
gpr_mu_unlock(&lbchand->mu); |
||||
|
||||
return stk; |
||||
} |
||||
|
||||
void grpc_child_call_destroy(grpc_child_call *call) { |
||||
grpc_call_element *lbelem = LINK_BACK_ELEM_FROM_CALL(call); |
||||
lb_call_data *calld = lbelem->call_data; |
||||
lb_channel_data *chand = lbelem->channel_data; |
||||
grpc_child_channel *channel = calld->channel; |
||||
grpc_call_stack_destroy(call); |
||||
gpr_free(call); |
||||
gpr_mu_lock(&chand->mu); |
||||
chand->active_calls--; |
||||
maybe_destroy_channel(channel); |
||||
gpr_mu_unlock(&chand->mu); |
||||
} |
||||
|
||||
grpc_call_element *grpc_child_call_get_top_element(grpc_child_call *call) { |
||||
return LINK_BACK_ELEM_FROM_CALL(call); |
||||
} |
@ -1,302 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#include "src/core/channel/client_setup.h" |
||||
#include "src/core/channel/channel_args.h" |
||||
#include "src/core/channel/channel_stack.h" |
||||
#include "src/core/iomgr/alarm.h" |
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/log.h> |
||||
#include <grpc/support/time.h> |
||||
|
||||
struct grpc_client_setup { |
||||
grpc_transport_setup base; /* must be first */ |
||||
void (*initiate)(void *user_data, grpc_client_setup_request *request); |
||||
void (*done)(void *user_data); |
||||
void *user_data; |
||||
grpc_channel_args *args; |
||||
grpc_mdctx *mdctx; |
||||
grpc_alarm backoff_alarm; |
||||
gpr_timespec current_backoff_interval; |
||||
int in_alarm; |
||||
int in_cb; |
||||
int cancelled; |
||||
|
||||
gpr_mu mu; |
||||
gpr_cv cv; |
||||
grpc_client_setup_request *active_request; |
||||
int refs; |
||||
/** The set of pollsets that are currently interested in this
|
||||
connection being established */ |
||||
grpc_pollset_set interested_parties; |
||||
}; |
||||
|
||||
struct grpc_client_setup_request { |
||||
/* pointer back to the setup object */ |
||||
grpc_client_setup *setup; |
||||
gpr_timespec deadline; |
||||
}; |
||||
|
||||
gpr_timespec grpc_client_setup_request_deadline(grpc_client_setup_request *r) { |
||||
return r->deadline; |
||||
} |
||||
|
||||
grpc_pollset_set *grpc_client_setup_get_interested_parties( |
||||
grpc_client_setup_request *r) { |
||||
return &r->setup->interested_parties; |
||||
} |
||||
|
||||
static void destroy_setup(grpc_client_setup *s) { |
||||
gpr_mu_destroy(&s->mu); |
||||
gpr_cv_destroy(&s->cv); |
||||
s->done(s->user_data); |
||||
grpc_channel_args_destroy(s->args); |
||||
grpc_pollset_set_destroy(&s->interested_parties); |
||||
gpr_free(s); |
||||
} |
||||
|
||||
static void destroy_request(grpc_client_setup_request *r) { gpr_free(r); } |
||||
|
||||
/* initiate handshaking */ |
||||
static void setup_initiate(grpc_transport_setup *sp) { |
||||
grpc_client_setup *s = (grpc_client_setup *)sp; |
||||
grpc_client_setup_request *r = gpr_malloc(sizeof(grpc_client_setup_request)); |
||||
int in_alarm = 0; |
||||
|
||||
r->setup = s; |
||||
r->deadline = gpr_time_add(gpr_now(), gpr_time_from_seconds(60)); |
||||
|
||||
gpr_mu_lock(&s->mu); |
||||
GPR_ASSERT(s->refs > 0); |
||||
/* there might be more than one request outstanding if the caller calls
|
||||
initiate in some kind of rapid-fire way: we try to connect each time, |
||||
and keep track of the latest request (which is the only one that gets |
||||
to finish) */ |
||||
if (!s->in_alarm) { |
||||
s->active_request = r; |
||||
s->refs++; |
||||
} else { |
||||
/* TODO(klempner): Maybe do something more clever here */ |
||||
in_alarm = 1; |
||||
} |
||||
gpr_mu_unlock(&s->mu); |
||||
|
||||
if (!in_alarm) { |
||||
s->initiate(s->user_data, r); |
||||
} else { |
||||
destroy_request(r); |
||||
} |
||||
} |
||||
|
||||
/** implementation of add_interested_party for setup vtable */ |
||||
static void setup_add_interested_party(grpc_transport_setup *sp, |
||||
grpc_pollset *pollset) { |
||||
grpc_client_setup *s = (grpc_client_setup *)sp; |
||||
|
||||
gpr_mu_lock(&s->mu); |
||||
grpc_pollset_set_add_pollset(&s->interested_parties, pollset); |
||||
gpr_mu_unlock(&s->mu); |
||||
} |
||||
|
||||
/** implementation of del_interested_party for setup vtable */ |
||||
static void setup_del_interested_party(grpc_transport_setup *sp, |
||||
grpc_pollset *pollset) { |
||||
grpc_client_setup *s = (grpc_client_setup *)sp; |
||||
|
||||
gpr_mu_lock(&s->mu); |
||||
grpc_pollset_set_del_pollset(&s->interested_parties, pollset); |
||||
gpr_mu_unlock(&s->mu); |
||||
} |
||||
|
||||
/* cancel handshaking: cancel all requests, and shutdown (the caller promises
|
||||
not to initiate again) */ |
||||
static void setup_cancel(grpc_transport_setup *sp) { |
||||
grpc_client_setup *s = (grpc_client_setup *)sp; |
||||
int cancel_alarm = 0; |
||||
|
||||
gpr_mu_lock(&s->mu); |
||||
s->cancelled = 1; |
||||
while (s->in_cb) { |
||||
gpr_cv_wait(&s->cv, &s->mu, gpr_inf_future); |
||||
} |
||||
|
||||
GPR_ASSERT(s->refs > 0); |
||||
/* effectively cancels the current request (if any) */ |
||||
s->active_request = NULL; |
||||
if (s->in_alarm) { |
||||
cancel_alarm = 1; |
||||
} |
||||
if (--s->refs == 0) { |
||||
gpr_mu_unlock(&s->mu); |
||||
destroy_setup(s); |
||||
} else { |
||||
gpr_mu_unlock(&s->mu); |
||||
} |
||||
if (cancel_alarm) { |
||||
grpc_alarm_cancel(&s->backoff_alarm); |
||||
} |
||||
} |
||||
|
||||
int grpc_client_setup_cb_begin(grpc_client_setup_request *r, |
||||
const char *reason) { |
||||
gpr_mu_lock(&r->setup->mu); |
||||
if (r->setup->cancelled) { |
||||
gpr_mu_unlock(&r->setup->mu); |
||||
return 0; |
||||
} |
||||
r->setup->in_cb++; |
||||
gpr_mu_unlock(&r->setup->mu); |
||||
return 1; |
||||
} |
||||
|
||||
void grpc_client_setup_cb_end(grpc_client_setup_request *r, |
||||
const char *reason) { |
||||
gpr_mu_lock(&r->setup->mu); |
||||
r->setup->in_cb--; |
||||
if (r->setup->cancelled) gpr_cv_signal(&r->setup->cv); |
||||
gpr_mu_unlock(&r->setup->mu); |
||||
} |
||||
|
||||
/* vtable for transport setup */ |
||||
static const grpc_transport_setup_vtable setup_vtable = { |
||||
setup_initiate, setup_add_interested_party, setup_del_interested_party, |
||||
setup_cancel}; |
||||
|
||||
void grpc_client_setup_create_and_attach( |
||||
grpc_channel_stack *newly_minted_channel, const grpc_channel_args *args, |
||||
grpc_mdctx *mdctx, |
||||
void (*initiate)(void *user_data, grpc_client_setup_request *request), |
||||
void (*done)(void *user_data), void *user_data) { |
||||
grpc_client_setup *s = gpr_malloc(sizeof(grpc_client_setup)); |
||||
|
||||
s->base.vtable = &setup_vtable; |
||||
gpr_mu_init(&s->mu); |
||||
gpr_cv_init(&s->cv); |
||||
s->refs = 1; |
||||
s->mdctx = mdctx; |
||||
s->initiate = initiate; |
||||
s->done = done; |
||||
s->user_data = user_data; |
||||
s->active_request = NULL; |
||||
s->args = grpc_channel_args_copy(args); |
||||
s->current_backoff_interval = gpr_time_from_micros(1000000); |
||||
s->in_alarm = 0; |
||||
s->in_cb = 0; |
||||
s->cancelled = 0; |
||||
grpc_pollset_set_init(&s->interested_parties); |
||||
|
||||
grpc_client_channel_set_transport_setup(newly_minted_channel, &s->base); |
||||
} |
||||
|
||||
int grpc_client_setup_request_should_continue(grpc_client_setup_request *r, |
||||
const char *reason) { |
||||
int result; |
||||
if (gpr_time_cmp(gpr_now(), r->deadline) > 0) { |
||||
result = 0; |
||||
} else { |
||||
gpr_mu_lock(&r->setup->mu); |
||||
result = r->setup->active_request == r; |
||||
gpr_mu_unlock(&r->setup->mu); |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
static void backoff_alarm_done(void *arg /* grpc_client_setup_request */,
|
||||
int success) { |
||||
grpc_client_setup_request *r = arg; |
||||
grpc_client_setup *s = r->setup; |
||||
/* Handle status cancelled? */ |
||||
gpr_mu_lock(&s->mu); |
||||
s->in_alarm = 0; |
||||
if (s->active_request != NULL || !success) { |
||||
if (0 == --s->refs) { |
||||
gpr_mu_unlock(&s->mu); |
||||
destroy_setup(s); |
||||
destroy_request(r); |
||||
return; |
||||
} else { |
||||
gpr_mu_unlock(&s->mu); |
||||
destroy_request(r); |
||||
return; |
||||
} |
||||
} |
||||
s->active_request = r; |
||||
gpr_mu_unlock(&s->mu); |
||||
s->initiate(s->user_data, r); |
||||
} |
||||
|
||||
void grpc_client_setup_request_finish(grpc_client_setup_request *r, |
||||
int was_successful) { |
||||
int retry = !was_successful; |
||||
grpc_client_setup *s = r->setup; |
||||
|
||||
gpr_mu_lock(&s->mu); |
||||
if (s->active_request == r) { |
||||
s->active_request = NULL; |
||||
} else { |
||||
retry = 0; |
||||
} |
||||
|
||||
if (!retry && 0 == --s->refs) { |
||||
gpr_mu_unlock(&s->mu); |
||||
destroy_setup(s); |
||||
destroy_request(r); |
||||
} else if (retry) { |
||||
/* TODO(klempner): Replace these values with further consideration. 2x is
|
||||
probably too aggressive of a backoff. */ |
||||
gpr_timespec max_backoff = gpr_time_from_minutes(2); |
||||
gpr_timespec now = gpr_now(); |
||||
gpr_timespec deadline = gpr_time_add(s->current_backoff_interval, now); |
||||
GPR_ASSERT(!s->in_alarm); |
||||
s->in_alarm = 1; |
||||
grpc_alarm_init(&s->backoff_alarm, deadline, backoff_alarm_done, r, now); |
||||
s->current_backoff_interval = |
||||
gpr_time_add(s->current_backoff_interval, s->current_backoff_interval); |
||||
if (gpr_time_cmp(s->current_backoff_interval, max_backoff) > 0) { |
||||
s->current_backoff_interval = max_backoff; |
||||
} |
||||
gpr_mu_unlock(&s->mu); |
||||
} else { |
||||
gpr_mu_unlock(&s->mu); |
||||
destroy_request(r); |
||||
} |
||||
} |
||||
|
||||
const grpc_channel_args *grpc_client_setup_get_channel_args( |
||||
grpc_client_setup_request *r) { |
||||
return r->setup->args; |
||||
} |
||||
|
||||
grpc_mdctx *grpc_client_setup_get_mdctx(grpc_client_setup_request *r) { |
||||
return r->setup->mdctx; |
||||
} |
@ -1,77 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPC_INTERNAL_CORE_CHANNEL_CLIENT_SETUP_H |
||||
#define GRPC_INTERNAL_CORE_CHANNEL_CLIENT_SETUP_H |
||||
|
||||
#include "src/core/channel/client_channel.h" |
||||
#include "src/core/transport/metadata.h" |
||||
#include <grpc/support/time.h> |
||||
|
||||
/* Convenience API's to simplify transport setup */ |
||||
|
||||
typedef struct grpc_client_setup grpc_client_setup; |
||||
typedef struct grpc_client_setup_request grpc_client_setup_request; |
||||
|
||||
void grpc_client_setup_create_and_attach( |
||||
grpc_channel_stack *newly_minted_channel, const grpc_channel_args *args, |
||||
grpc_mdctx *mdctx, |
||||
void (*initiate)(void *user_data, grpc_client_setup_request *request), |
||||
void (*done)(void *user_data), void *user_data); |
||||
|
||||
/* Check that r is the active request: needs to be performed at each callback.
|
||||
If this races, we'll have two connection attempts running at once and the |
||||
old one will get cleaned up in due course, which is fine. */ |
||||
int grpc_client_setup_request_should_continue(grpc_client_setup_request *r, |
||||
const char *reason); |
||||
void grpc_client_setup_request_finish(grpc_client_setup_request *r, |
||||
int was_successful); |
||||
const grpc_channel_args *grpc_client_setup_get_channel_args( |
||||
grpc_client_setup_request *r); |
||||
|
||||
/* Call before calling back into the setup listener, and call only if
|
||||
this function returns 1. If it returns 1, also promise to call |
||||
grpc_client_setup_cb_end */ |
||||
int grpc_client_setup_cb_begin(grpc_client_setup_request *r, |
||||
const char *reason); |
||||
void grpc_client_setup_cb_end(grpc_client_setup_request *r, const char *reason); |
||||
|
||||
/* Get the deadline for a request passed in to initiate. Implementations should
|
||||
make a best effort to honor this deadline. */ |
||||
gpr_timespec grpc_client_setup_request_deadline(grpc_client_setup_request *r); |
||||
grpc_pollset_set *grpc_client_setup_get_interested_parties( |
||||
grpc_client_setup_request *r); |
||||
|
||||
grpc_mdctx *grpc_client_setup_get_mdctx(grpc_client_setup_request *r); |
||||
|
||||
#endif /* GRPC_INTERNAL_CORE_CHANNEL_CLIENT_SETUP_H */ |
@ -0,0 +1,60 @@ |
||||
Client Configuration Support for GRPC |
||||
===================================== |
||||
|
||||
This library provides high level configuration machinery to construct client |
||||
channels and load balance between them. |
||||
|
||||
Each grpc_channel is created with a grpc_resolver. It is the resolver's duty |
||||
to resolve a name into configuration data for the channel. Such configuration |
||||
data might include: |
||||
|
||||
- a list of (ip, port) addresses to connect to |
||||
- a load balancing policy to decide which server to send a request to |
||||
- a set of filters to mutate outgoing requests (say, by adding metadata) |
||||
|
||||
The resolver provides this data as a stream of grpc_client_config objects to |
||||
the channel. We represent configuration as a stream so that it can be changed |
||||
by the resolver during execution, by reacting to external events (such as a |
||||
new configuration file being pushed to some store). |
||||
|
||||
|
||||
Load Balancing |
||||
-------------- |
||||
|
||||
Load balancing configuration is provided by a grpc_lb_policy object, stored as |
||||
part of grpc_client_config. |
||||
|
||||
A load balancing policies primary job is to pick a target server given only the |
||||
initial metadata for a request. It does this by providing a grpc_subchannel |
||||
object to the owning channel. |
||||
|
||||
|
||||
Sub-Channels |
||||
------------ |
||||
|
||||
A sub-channel provides a connection to a server for a client channel. It has a |
||||
connectivity state like a regular channel, and so can be connected or |
||||
disconnected. This connectivity state can be used to inform load balancing |
||||
decisions (for example, by avoiding disconnected backends). |
||||
|
||||
Configured sub-channels are fully setup to participate in the grpc data plane. |
||||
Their behavior is specified by a set of grpc channel filters defined at their |
||||
construction. To customize this behavior, resolvers build grpc_subchannel_factory |
||||
objects, which use the decorator pattern to customize construction arguments for |
||||
concrete grpc_subchannel instances. |
||||
|
||||
|
||||
Naming for GRPC |
||||
=============== |
||||
|
||||
Names in GRPC are represented by a URI. |
||||
|
||||
The following schemes are currently supported: |
||||
|
||||
dns:///host:port - dns schemes are currently supported so long as authority is |
||||
empty (authority based dns resolution is expected in a future |
||||
release) |
||||
|
||||
unix:path - the unix scheme is used to create and connect to unix domain |
||||
sockets - the authority must be empty, and the path represents |
||||
the absolute or relative path to the desired socket |
@ -0,0 +1,74 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#include "src/core/client_config/client_config.h" |
||||
|
||||
#include <string.h> |
||||
|
||||
#include <grpc/support/alloc.h> |
||||
|
||||
struct grpc_client_config { |
||||
gpr_refcount refs; |
||||
grpc_lb_policy *lb_policy; |
||||
}; |
||||
|
||||
grpc_client_config *grpc_client_config_create() { |
||||
grpc_client_config *c = gpr_malloc(sizeof(*c)); |
||||
memset(c, 0, sizeof(*c)); |
||||
gpr_ref_init(&c->refs, 1); |
||||
return c; |
||||
} |
||||
|
||||
void grpc_client_config_ref(grpc_client_config *c) { gpr_ref(&c->refs); } |
||||
|
||||
void grpc_client_config_unref(grpc_client_config *c) { |
||||
if (gpr_unref(&c->refs)) { |
||||
GRPC_LB_POLICY_UNREF(c->lb_policy, "client_config"); |
||||
gpr_free(c); |
||||
} |
||||
} |
||||
|
||||
void grpc_client_config_set_lb_policy(grpc_client_config *c, |
||||
grpc_lb_policy *lb_policy) { |
||||
if (lb_policy) { |
||||
GRPC_LB_POLICY_REF(lb_policy, "client_config"); |
||||
} |
||||
if (c->lb_policy) { |
||||
GRPC_LB_POLICY_UNREF(c->lb_policy, "client_config"); |
||||
} |
||||
c->lb_policy = lb_policy; |
||||
} |
||||
|
||||
grpc_lb_policy *grpc_client_config_get_lb_policy(grpc_client_config *c) { |
||||
return c->lb_policy; |
||||
} |
@ -0,0 +1,52 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPC_INTERNAL_CORE_CLIENT_CONFIG_CLIENT_CONFIG_H |
||||
#define GRPC_INTERNAL_CORE_CLIENT_CONFIG_CLIENT_CONFIG_H |
||||
|
||||
#include "src/core/client_config/lb_policy.h" |
||||
|
||||
/** Total configuration for a client. Provided, and updated, by
|
||||
grpc_resolver */ |
||||
typedef struct grpc_client_config grpc_client_config; |
||||
|
||||
grpc_client_config *grpc_client_config_create(); |
||||
void grpc_client_config_ref(grpc_client_config *client_config); |
||||
void grpc_client_config_unref(grpc_client_config *client_config); |
||||
|
||||
void grpc_client_config_set_lb_policy(grpc_client_config *client_config, |
||||
grpc_lb_policy *lb_policy); |
||||
grpc_lb_policy *grpc_client_config_get_lb_policy( |
||||
grpc_client_config *client_config); |
||||
|
||||
#endif /* GRPC_INTERNAL_CORE_CLIENT_CONFIG_CLIENT_CONFIG_H */ |
@ -0,0 +1,49 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#include "src/core/client_config/connector.h" |
||||
|
||||
void grpc_connector_ref(grpc_connector *connector) { |
||||
connector->vtable->ref(connector); |
||||
} |
||||
|
||||
void grpc_connector_unref(grpc_connector *connector) { |
||||
connector->vtable->unref(connector); |
||||
} |
||||
|
||||
void grpc_connector_connect(grpc_connector *connector, |
||||
const grpc_connect_in_args *in_args, |
||||
grpc_connect_out_args *out_args, |
||||
grpc_iomgr_closure *notify) { |
||||
connector->vtable->connect(connector, in_args, out_args, notify); |
||||
} |
@ -0,0 +1,85 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPC_INTERNAL_CORE_CLIENT_CONFIG_CONNECTOR_H |
||||
#define GRPC_INTERNAL_CORE_CLIENT_CONFIG_CONNECTOR_H |
||||
|
||||
#include "src/core/channel/channel_stack.h" |
||||
#include "src/core/iomgr/sockaddr.h" |
||||
#include "src/core/transport/transport.h" |
||||
|
||||
typedef struct grpc_connector grpc_connector; |
||||
typedef struct grpc_connector_vtable grpc_connector_vtable; |
||||
|
||||
struct grpc_connector { |
||||
const grpc_connector_vtable *vtable; |
||||
}; |
||||
|
||||
typedef struct { |
||||
/** set of pollsets interested in this connection */ |
||||
grpc_pollset_set *interested_parties; |
||||
/** address to connect to */ |
||||
const struct sockaddr *addr; |
||||
int addr_len; |
||||
/** deadline for connection */ |
||||
gpr_timespec deadline; |
||||
/** channel arguments (to be passed to transport) */ |
||||
const grpc_channel_args *channel_args; |
||||
/** metadata context */ |
||||
grpc_mdctx *metadata_context; |
||||
} grpc_connect_in_args; |
||||
|
||||
typedef struct { |
||||
/** the connected transport */ |
||||
grpc_transport *transport; |
||||
/** any additional filters (owned by the caller of connect) */ |
||||
const grpc_channel_filter **filters; |
||||
size_t num_filters; |
||||
} grpc_connect_out_args; |
||||
|
||||
struct grpc_connector_vtable { |
||||
void (*ref)(grpc_connector *connector); |
||||
void (*unref)(grpc_connector *connector); |
||||
void (*connect)(grpc_connector *connector, |
||||
const grpc_connect_in_args *in_args, |
||||
grpc_connect_out_args *out_args, grpc_iomgr_closure *notify); |
||||
}; |
||||
|
||||
void grpc_connector_ref(grpc_connector *connector); |
||||
void grpc_connector_unref(grpc_connector *connector); |
||||
void grpc_connector_connect(grpc_connector *connector, |
||||
const grpc_connect_in_args *in_args, |
||||
grpc_connect_out_args *out_args, |
||||
grpc_iomgr_closure *notify); |
||||
|
||||
#endif |
@ -0,0 +1,268 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#include "src/core/client_config/lb_policies/pick_first.h" |
||||
|
||||
#include <string.h> |
||||
|
||||
#include <grpc/support/alloc.h> |
||||
#include "src/core/transport/connectivity_state.h" |
||||
|
||||
typedef struct pending_pick { |
||||
struct pending_pick *next; |
||||
grpc_pollset *pollset; |
||||
grpc_subchannel **target; |
||||
grpc_iomgr_closure *on_complete; |
||||
} pending_pick; |
||||
|
||||
typedef struct { |
||||
/** base policy: must be first */ |
||||
grpc_lb_policy base; |
||||
/** all our subchannels */ |
||||
grpc_subchannel **subchannels; |
||||
size_t num_subchannels; |
||||
|
||||
grpc_iomgr_closure connectivity_changed; |
||||
|
||||
/** mutex protecting remaining members */ |
||||
gpr_mu mu; |
||||
/** the selected channel
|
||||
TODO(ctiller): this should be atomically set so we don't |
||||
need to take a mutex in the common case */ |
||||
grpc_subchannel *selected; |
||||
/** have we started picking? */ |
||||
int started_picking; |
||||
/** which subchannel are we watching? */ |
||||
size_t checking_subchannel; |
||||
/** what is the connectivity of that channel? */ |
||||
grpc_connectivity_state checking_connectivity; |
||||
/** list of picks that are waiting on connectivity */ |
||||
pending_pick *pending_picks; |
||||
|
||||
/** our connectivity state tracker */ |
||||
grpc_connectivity_state_tracker state_tracker; |
||||
} pick_first_lb_policy; |
||||
|
||||
void pf_destroy(grpc_lb_policy *pol) { |
||||
pick_first_lb_policy *p = (pick_first_lb_policy *)pol; |
||||
size_t i; |
||||
for (i = 0; i < p->num_subchannels; i++) { |
||||
GRPC_SUBCHANNEL_UNREF(p->subchannels[i], "pick_first"); |
||||
} |
||||
gpr_free(p->subchannels); |
||||
gpr_mu_destroy(&p->mu); |
||||
gpr_free(p); |
||||
} |
||||
|
||||
void pf_shutdown(grpc_lb_policy *pol) { |
||||
pick_first_lb_policy *p = (pick_first_lb_policy *)pol; |
||||
pending_pick *pp; |
||||
gpr_mu_lock(&p->mu); |
||||
while ((pp = p->pending_picks)) { |
||||
p->pending_picks = pp->next; |
||||
*pp->target = NULL; |
||||
grpc_iomgr_add_delayed_callback(pp->on_complete, 0); |
||||
gpr_free(pp); |
||||
} |
||||
gpr_mu_unlock(&p->mu); |
||||
} |
||||
|
||||
void pf_pick(grpc_lb_policy *pol, grpc_pollset *pollset, |
||||
grpc_metadata_batch *initial_metadata, grpc_subchannel **target, |
||||
grpc_iomgr_closure *on_complete) { |
||||
pick_first_lb_policy *p = (pick_first_lb_policy *)pol; |
||||
pending_pick *pp; |
||||
gpr_mu_lock(&p->mu); |
||||
if (p->selected) { |
||||
gpr_mu_unlock(&p->mu); |
||||
*target = p->selected; |
||||
on_complete->cb(on_complete->cb_arg, 1); |
||||
} else { |
||||
if (!p->started_picking) { |
||||
p->started_picking = 1; |
||||
p->checking_subchannel = 0; |
||||
p->checking_connectivity = GRPC_CHANNEL_IDLE; |
||||
GRPC_LB_POLICY_REF(pol, "pick_first_connectivity"); |
||||
grpc_subchannel_notify_on_state_change( |
||||
p->subchannels[p->checking_subchannel], &p->checking_connectivity, |
||||
&p->connectivity_changed); |
||||
} |
||||
grpc_subchannel_add_interested_party(p->subchannels[p->checking_subchannel], |
||||
pollset); |
||||
pp = gpr_malloc(sizeof(*pp)); |
||||
pp->next = p->pending_picks; |
||||
pp->pollset = pollset; |
||||
pp->target = target; |
||||
pp->on_complete = on_complete; |
||||
p->pending_picks = pp; |
||||
gpr_mu_unlock(&p->mu); |
||||
} |
||||
} |
||||
|
||||
static void del_interested_parties_locked(pick_first_lb_policy *p) { |
||||
pending_pick *pp; |
||||
for (pp = p->pending_picks; pp; pp = pp->next) { |
||||
grpc_subchannel_del_interested_party(p->subchannels[p->checking_subchannel], |
||||
pp->pollset); |
||||
} |
||||
} |
||||
|
||||
static void add_interested_parties_locked(pick_first_lb_policy *p) { |
||||
pending_pick *pp; |
||||
for (pp = p->pending_picks; pp; pp = pp->next) { |
||||
grpc_subchannel_add_interested_party(p->subchannels[p->checking_subchannel], |
||||
pp->pollset); |
||||
} |
||||
} |
||||
|
||||
static void pf_connectivity_changed(void *arg, int iomgr_success) { |
||||
pick_first_lb_policy *p = arg; |
||||
pending_pick *pp; |
||||
int unref = 0; |
||||
|
||||
gpr_mu_lock(&p->mu); |
||||
loop: |
||||
switch (p->checking_connectivity) { |
||||
case GRPC_CHANNEL_READY: |
||||
p->selected = p->subchannels[p->checking_subchannel]; |
||||
while ((pp = p->pending_picks)) { |
||||
p->pending_picks = pp->next; |
||||
*pp->target = p->selected; |
||||
grpc_subchannel_del_interested_party(p->selected, pp->pollset); |
||||
grpc_iomgr_add_delayed_callback(pp->on_complete, 1); |
||||
gpr_free(pp); |
||||
} |
||||
unref = 1; |
||||
break; |
||||
case GRPC_CHANNEL_TRANSIENT_FAILURE: |
||||
del_interested_parties_locked(p); |
||||
p->checking_subchannel = |
||||
(p->checking_subchannel + 1) % p->num_subchannels; |
||||
p->checking_connectivity = grpc_subchannel_check_connectivity( |
||||
p->subchannels[p->checking_subchannel]); |
||||
add_interested_parties_locked(p); |
||||
goto loop; |
||||
case GRPC_CHANNEL_CONNECTING: |
||||
case GRPC_CHANNEL_IDLE: |
||||
grpc_subchannel_notify_on_state_change( |
||||
p->subchannels[p->checking_subchannel], &p->checking_connectivity, |
||||
&p->connectivity_changed); |
||||
break; |
||||
case GRPC_CHANNEL_FATAL_FAILURE: |
||||
del_interested_parties_locked(p); |
||||
GPR_SWAP(grpc_subchannel *, p->subchannels[p->checking_subchannel], |
||||
p->subchannels[p->num_subchannels - 1]); |
||||
p->num_subchannels--; |
||||
GRPC_SUBCHANNEL_UNREF(p->subchannels[p->num_subchannels], "pick_first"); |
||||
if (p->num_subchannels == 0) { |
||||
while ((pp = p->pending_picks)) { |
||||
p->pending_picks = pp->next; |
||||
*pp->target = NULL; |
||||
grpc_iomgr_add_delayed_callback(pp->on_complete, 1); |
||||
gpr_free(pp); |
||||
} |
||||
unref = 1; |
||||
} else { |
||||
p->checking_subchannel %= p->num_subchannels; |
||||
p->checking_connectivity = grpc_subchannel_check_connectivity( |
||||
p->subchannels[p->checking_subchannel]); |
||||
add_interested_parties_locked(p); |
||||
goto loop; |
||||
} |
||||
} |
||||
gpr_mu_unlock(&p->mu); |
||||
|
||||
if (unref) { |
||||
GRPC_LB_POLICY_UNREF(&p->base, "pick_first_connectivity"); |
||||
} |
||||
} |
||||
|
||||
static void pf_broadcast(grpc_lb_policy *pol, grpc_transport_op *op) { |
||||
pick_first_lb_policy *p = (pick_first_lb_policy *)pol; |
||||
size_t i; |
||||
size_t n; |
||||
grpc_subchannel **subchannels; |
||||
|
||||
gpr_mu_lock(&p->mu); |
||||
n = p->num_subchannels; |
||||
subchannels = gpr_malloc(n * sizeof(*subchannels)); |
||||
for (i = 0; i < n; i++) { |
||||
subchannels[i] = p->subchannels[i]; |
||||
GRPC_SUBCHANNEL_REF(subchannels[i], "pf_broadcast"); |
||||
} |
||||
gpr_mu_unlock(&p->mu); |
||||
|
||||
for (i = 0; i < n; i++) { |
||||
grpc_subchannel_process_transport_op(subchannels[i], op); |
||||
GRPC_SUBCHANNEL_UNREF(subchannels[i], "pf_broadcast"); |
||||
} |
||||
gpr_free(subchannels); |
||||
} |
||||
|
||||
static grpc_connectivity_state pf_check_connectivity(grpc_lb_policy *pol) { |
||||
pick_first_lb_policy *p = (pick_first_lb_policy *)pol; |
||||
grpc_connectivity_state st; |
||||
gpr_mu_lock(&p->mu); |
||||
st = grpc_connectivity_state_check(&p->state_tracker); |
||||
gpr_mu_unlock(&p->mu); |
||||
return st; |
||||
} |
||||
|
||||
static void pf_notify_on_state_change(grpc_lb_policy *pol, |
||||
grpc_connectivity_state *current, |
||||
grpc_iomgr_closure *notify) { |
||||
pick_first_lb_policy *p = (pick_first_lb_policy *)pol; |
||||
gpr_mu_lock(&p->mu); |
||||
grpc_connectivity_state_notify_on_state_change(&p->state_tracker, current, |
||||
notify); |
||||
gpr_mu_unlock(&p->mu); |
||||
} |
||||
|
||||
static const grpc_lb_policy_vtable pick_first_lb_policy_vtable = { |
||||
pf_destroy, pf_shutdown, pf_pick, |
||||
pf_broadcast, pf_check_connectivity, pf_notify_on_state_change}; |
||||
|
||||
grpc_lb_policy *grpc_create_pick_first_lb_policy(grpc_subchannel **subchannels, |
||||
size_t num_subchannels) { |
||||
pick_first_lb_policy *p = gpr_malloc(sizeof(*p)); |
||||
GPR_ASSERT(num_subchannels); |
||||
memset(p, 0, sizeof(*p)); |
||||
grpc_lb_policy_init(&p->base, &pick_first_lb_policy_vtable); |
||||
p->subchannels = gpr_malloc(sizeof(grpc_subchannel *) * num_subchannels); |
||||
p->num_subchannels = num_subchannels; |
||||
memcpy(p->subchannels, subchannels, |
||||
sizeof(grpc_subchannel *) * num_subchannels); |
||||
grpc_iomgr_closure_init(&p->connectivity_changed, pf_connectivity_changed, p); |
||||
gpr_mu_init(&p->mu); |
||||
return &p->base; |
||||
} |
@ -0,0 +1,79 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#include "src/core/client_config/lb_policy.h" |
||||
|
||||
void grpc_lb_policy_init(grpc_lb_policy *policy, |
||||
const grpc_lb_policy_vtable *vtable) { |
||||
policy->vtable = vtable; |
||||
gpr_ref_init(&policy->refs, 1); |
||||
} |
||||
|
||||
#ifdef GRPC_LB_POLICY_REFCOUNT_DEBUG |
||||
void grpc_lb_policy_ref(grpc_lb_policy *policy, const char *file, int line, |
||||
const char *reason) { |
||||
gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "LB_POLICY:%p ref %d -> %d %s", |
||||
policy, (int)policy->refs.count, (int)policy->refs.count + 1, reason); |
||||
#else |
||||
void grpc_lb_policy_ref(grpc_lb_policy *policy) { |
||||
#endif |
||||
gpr_ref(&policy->refs); |
||||
} |
||||
|
||||
#ifdef GRPC_LB_POLICY_REFCOUNT_DEBUG |
||||
void grpc_lb_policy_unref(grpc_lb_policy *policy, const char *file, int line, |
||||
const char *reason) { |
||||
gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "LB_POLICY:%p unref %d -> %d %s", |
||||
policy, (int)policy->refs.count, (int)policy->refs.count - 1, reason); |
||||
#else |
||||
void grpc_lb_policy_unref(grpc_lb_policy *policy) { |
||||
#endif |
||||
if (gpr_unref(&policy->refs)) { |
||||
policy->vtable->destroy(policy); |
||||
} |
||||
} |
||||
|
||||
void grpc_lb_policy_shutdown(grpc_lb_policy *policy) { |
||||
policy->vtable->shutdown(policy); |
||||
} |
||||
|
||||
void grpc_lb_policy_pick(grpc_lb_policy *policy, grpc_pollset *pollset, |
||||
grpc_metadata_batch *initial_metadata, |
||||
grpc_subchannel **target, |
||||
grpc_iomgr_closure *on_complete) { |
||||
policy->vtable->pick(policy, pollset, initial_metadata, target, on_complete); |
||||
} |
||||
|
||||
void grpc_lb_policy_broadcast(grpc_lb_policy *policy, grpc_transport_op *op) { |
||||
policy->vtable->broadcast(policy, op); |
||||
} |
@ -0,0 +1,109 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPC_INTERNAL_CORE_CLIENT_CONFIG_LB_POLICY_H |
||||
#define GRPC_INTERNAL_CORE_CLIENT_CONFIG_LB_POLICY_H |
||||
|
||||
#include "src/core/client_config/subchannel.h" |
||||
|
||||
/** A load balancing policy: specified by a vtable and a struct (which
|
||||
is expected to be extended to contain some parameters) */ |
||||
typedef struct grpc_lb_policy grpc_lb_policy; |
||||
typedef struct grpc_lb_policy_vtable grpc_lb_policy_vtable; |
||||
|
||||
typedef void (*grpc_lb_completion)(void *cb_arg, grpc_subchannel *subchannel, |
||||
grpc_status_code status, const char *errmsg); |
||||
|
||||
struct grpc_lb_policy { |
||||
const grpc_lb_policy_vtable *vtable; |
||||
gpr_refcount refs; |
||||
}; |
||||
|
||||
struct grpc_lb_policy_vtable { |
||||
void (*destroy)(grpc_lb_policy *policy); |
||||
|
||||
void (*shutdown)(grpc_lb_policy *policy); |
||||
|
||||
/** implement grpc_lb_policy_pick */ |
||||
void (*pick)(grpc_lb_policy *policy, grpc_pollset *pollset, |
||||
grpc_metadata_batch *initial_metadata, grpc_subchannel **target, |
||||
grpc_iomgr_closure *on_complete); |
||||
|
||||
/** broadcast a transport op to all subchannels */ |
||||
void (*broadcast)(grpc_lb_policy *policy, grpc_transport_op *op); |
||||
|
||||
/** check the current connectivity of the lb_policy */ |
||||
grpc_connectivity_state (*check_connectivity)(grpc_lb_policy *policy); |
||||
|
||||
/** call notify when the connectivity state of a channel changes from *state.
|
||||
Updates *state with the new state of the policy */ |
||||
void (*notify_on_state_change)(grpc_lb_policy *policy, |
||||
grpc_connectivity_state *state, |
||||
grpc_iomgr_closure *closure); |
||||
}; |
||||
|
||||
#ifdef GRPC_LB_POLICY_REFCOUNT_DEBUG |
||||
#define GRPC_LB_POLICY_REF(p, r) \ |
||||
grpc_lb_policy_ref((p), __FILE__, __LINE__, (r)) |
||||
#define GRPC_LB_POLICY_UNREF(p, r) \ |
||||
grpc_lb_policy_unref((p), __FILE__, __LINE__, (r)) |
||||
void grpc_lb_policy_ref(grpc_lb_policy *policy, const char *file, int line, |
||||
const char *reason); |
||||
void grpc_lb_policy_unref(grpc_lb_policy *policy, const char *file, int line, |
||||
const char *reason); |
||||
#else |
||||
#define GRPC_LB_POLICY_REF(p, r) grpc_lb_policy_ref((p)) |
||||
#define GRPC_LB_POLICY_UNREF(p, r) grpc_lb_policy_unref((p)) |
||||
void grpc_lb_policy_ref(grpc_lb_policy *policy); |
||||
void grpc_lb_policy_unref(grpc_lb_policy *policy); |
||||
#endif |
||||
|
||||
/** called by concrete implementations to initialize the base struct */ |
||||
void grpc_lb_policy_init(grpc_lb_policy *policy, |
||||
const grpc_lb_policy_vtable *vtable); |
||||
|
||||
/** Start shutting down (fail any pending picks) */ |
||||
void grpc_lb_policy_shutdown(grpc_lb_policy *policy); |
||||
|
||||
/** Given initial metadata in \a initial_metadata, find an appropriate
|
||||
target for this rpc, and 'return' it by calling \a on_complete after setting |
||||
\a target. |
||||
Picking can be asynchronous. Any IO should be done under \a pollset. */ |
||||
void grpc_lb_policy_pick(grpc_lb_policy *policy, grpc_pollset *pollset, |
||||
grpc_metadata_batch *initial_metadata, |
||||
grpc_subchannel **target, |
||||
grpc_iomgr_closure *on_complete); |
||||
|
||||
void grpc_lb_policy_broadcast(grpc_lb_policy *policy, grpc_transport_op *op); |
||||
|
||||
#endif /* GRPC_INTERNAL_CORE_CONFIG_LB_POLICY_H */ |
@ -0,0 +1,83 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#include "src/core/client_config/resolver.h" |
||||
|
||||
void grpc_resolver_init(grpc_resolver *resolver, |
||||
const grpc_resolver_vtable *vtable) { |
||||
resolver->vtable = vtable; |
||||
gpr_ref_init(&resolver->refs, 1); |
||||
} |
||||
|
||||
#ifdef GRPC_RESOLVER_REFCOUNT_DEBUG |
||||
void grpc_resolver_ref(grpc_resolver *resolver, const char *file, int line, |
||||
const char *reason) { |
||||
gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "RESOLVER:%p ref %d -> %d %s", |
||||
resolver, (int)resolver->refs.count, (int)resolver->refs.count + 1, |
||||
reason); |
||||
#else |
||||
void grpc_resolver_ref(grpc_resolver *resolver) { |
||||
#endif |
||||
gpr_ref(&resolver->refs); |
||||
} |
||||
|
||||
#ifdef GRPC_RESOLVER_REFCOUNT_DEBUG |
||||
void grpc_resolver_unref(grpc_resolver *resolver, const char *file, int line, |
||||
const char *reason) { |
||||
gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "RESOLVER:%p unref %d -> %d %s", |
||||
resolver, (int)resolver->refs.count, (int)resolver->refs.count - 1, |
||||
reason); |
||||
#else |
||||
void grpc_resolver_unref(grpc_resolver *resolver) { |
||||
#endif |
||||
if (gpr_unref(&resolver->refs)) { |
||||
resolver->vtable->destroy(resolver); |
||||
} |
||||
} |
||||
|
||||
void grpc_resolver_shutdown(grpc_resolver *resolver) { |
||||
resolver->vtable->shutdown(resolver); |
||||
} |
||||
|
||||
void grpc_resolver_channel_saw_error(grpc_resolver *resolver, |
||||
struct sockaddr *failing_address, |
||||
int failing_address_len) { |
||||
resolver->vtable->channel_saw_error(resolver, failing_address, |
||||
failing_address_len); |
||||
} |
||||
|
||||
void grpc_resolver_next(grpc_resolver *resolver, |
||||
grpc_client_config **target_config, |
||||
grpc_iomgr_closure *on_complete) { |
||||
resolver->vtable->next(resolver, target_config, on_complete); |
||||
} |
@ -0,0 +1,97 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPC_INTERNAL_CORE_CLIENT_CONFIG_RESOLVER_H |
||||
#define GRPC_INTERNAL_CORE_CLIENT_CONFIG_RESOLVER_H |
||||
|
||||
#include "src/core/client_config/client_config.h" |
||||
#include "src/core/iomgr/iomgr.h" |
||||
#include "src/core/iomgr/sockaddr.h" |
||||
|
||||
typedef struct grpc_resolver grpc_resolver; |
||||
typedef struct grpc_resolver_vtable grpc_resolver_vtable; |
||||
|
||||
/** grpc_resolver provides grpc_client_config objects to grpc_channel
|
||||
objects */ |
||||
struct grpc_resolver { |
||||
const grpc_resolver_vtable *vtable; |
||||
gpr_refcount refs; |
||||
}; |
||||
|
||||
struct grpc_resolver_vtable { |
||||
void (*destroy)(grpc_resolver *resolver); |
||||
void (*shutdown)(grpc_resolver *resolver); |
||||
void (*channel_saw_error)(grpc_resolver *resolver, |
||||
struct sockaddr *failing_address, |
||||
int failing_address_len); |
||||
void (*next)(grpc_resolver *resolver, grpc_client_config **target_config, |
||||
grpc_iomgr_closure *on_complete); |
||||
}; |
||||
|
||||
#ifdef GRPC_RESOLVER_REFCOUNT_DEBUG |
||||
#define GRPC_RESOLVER_REF(p, r) grpc_resolver_ref((p), __FILE__, __LINE__, (r)) |
||||
#define GRPC_RESOLVER_UNREF(p, r) \ |
||||
grpc_resolver_unref((p), __FILE__, __LINE__, (r)) |
||||
void grpc_resolver_ref(grpc_resolver *policy, const char *file, int line, |
||||
const char *reason); |
||||
void grpc_resolver_unref(grpc_resolver *policy, const char *file, int line, |
||||
const char *reason); |
||||
#else |
||||
#define GRPC_RESOLVER_REF(p, r) grpc_resolver_ref((p)) |
||||
#define GRPC_RESOLVER_UNREF(p, r) grpc_resolver_unref((p)) |
||||
void grpc_resolver_ref(grpc_resolver *policy); |
||||
void grpc_resolver_unref(grpc_resolver *policy); |
||||
#endif |
||||
|
||||
void grpc_resolver_init(grpc_resolver *resolver, |
||||
const grpc_resolver_vtable *vtable); |
||||
|
||||
void grpc_resolver_shutdown(grpc_resolver *resolver); |
||||
|
||||
/** Notification that the channel has seen an error on some address.
|
||||
Can be used as a hint that re-resolution is desirable soon. */ |
||||
void grpc_resolver_channel_saw_error(grpc_resolver *resolver, |
||||
struct sockaddr *failing_address, |
||||
int failing_address_len); |
||||
|
||||
/** Get the next client config. Called by the channel to fetch a new
|
||||
configuration. Expected to set *target_config with a new configuration, |
||||
and then schedule on_complete for execution. |
||||
|
||||
If resolution is fatally broken, set *target_config to NULL and |
||||
schedule on_complete. */ |
||||
void grpc_resolver_next(grpc_resolver *resolver, |
||||
grpc_client_config **target_config, |
||||
grpc_iomgr_closure *on_complete); |
||||
|
||||
#endif /* GRPC_INTERNAL_CORE_CONFIG_RESOLVER_H */ |
@ -0,0 +1,50 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#include "src/core/client_config/resolver_factory.h" |
||||
|
||||
void grpc_resolver_factory_ref(grpc_resolver_factory *factory) { |
||||
factory->vtable->ref(factory); |
||||
} |
||||
|
||||
void grpc_resolver_factory_unref(grpc_resolver_factory *factory) { |
||||
factory->vtable->unref(factory); |
||||
} |
||||
|
||||
/** Create a resolver instance for a name */ |
||||
grpc_resolver *grpc_resolver_factory_create_resolver( |
||||
grpc_resolver_factory *factory, grpc_uri *uri, |
||||
grpc_subchannel_factory *subchannel_factory) { |
||||
if (!factory) return NULL; |
||||
return factory->vtable->create_resolver(factory, uri, subchannel_factory); |
||||
} |
@ -0,0 +1,67 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPC_INTERNAL_CORE_CLIENT_CONFIG_RESOLVER_FACTORY_H |
||||
#define GRPC_INTERNAL_CORE_CLIENT_CONFIG_RESOLVER_FACTORY_H |
||||
|
||||
#include "src/core/client_config/resolver.h" |
||||
#include "src/core/client_config/subchannel_factory.h" |
||||
#include "src/core/client_config/uri_parser.h" |
||||
|
||||
typedef struct grpc_resolver_factory grpc_resolver_factory; |
||||
typedef struct grpc_resolver_factory_vtable grpc_resolver_factory_vtable; |
||||
|
||||
/** grpc_resolver provides grpc_client_config objects to grpc_channel
|
||||
objects */ |
||||
struct grpc_resolver_factory { |
||||
const grpc_resolver_factory_vtable *vtable; |
||||
}; |
||||
|
||||
struct grpc_resolver_factory_vtable { |
||||
void (*ref)(grpc_resolver_factory *factory); |
||||
void (*unref)(grpc_resolver_factory *factory); |
||||
|
||||
grpc_resolver *(*create_resolver)( |
||||
grpc_resolver_factory *factory, grpc_uri *uri, |
||||
grpc_subchannel_factory *subchannel_factory); |
||||
}; |
||||
|
||||
void grpc_resolver_factory_ref(grpc_resolver_factory *resolver); |
||||
void grpc_resolver_factory_unref(grpc_resolver_factory *resolver); |
||||
|
||||
/** Create a resolver instance for a name */ |
||||
grpc_resolver *grpc_resolver_factory_create_resolver( |
||||
grpc_resolver_factory *factory, grpc_uri *uri, |
||||
grpc_subchannel_factory *subchannel_factory); |
||||
|
||||
#endif /* GRPC_INTERNAL_CORE_CONFIG_RESOLVER_FACTORY_H */ |
@ -0,0 +1,124 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#include "src/core/client_config/resolver_registry.h" |
||||
|
||||
#include <string.h> |
||||
|
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/log.h> |
||||
#include <grpc/support/string_util.h> |
||||
|
||||
#define MAX_RESOLVERS 10 |
||||
|
||||
typedef struct { |
||||
char *scheme; |
||||
grpc_resolver_factory *factory; |
||||
} registered_resolver; |
||||
|
||||
static registered_resolver g_all_of_the_resolvers[MAX_RESOLVERS]; |
||||
static int g_number_of_resolvers = 0; |
||||
|
||||
static char *g_default_resolver_scheme; |
||||
|
||||
void grpc_resolver_registry_init(const char *default_resolver_scheme) { |
||||
g_number_of_resolvers = 0; |
||||
g_default_resolver_scheme = gpr_strdup(default_resolver_scheme); |
||||
} |
||||
|
||||
void grpc_resolver_registry_shutdown(void) { |
||||
int i; |
||||
for (i = 0; i < g_number_of_resolvers; i++) { |
||||
gpr_free(g_all_of_the_resolvers[i].scheme); |
||||
grpc_resolver_factory_unref(g_all_of_the_resolvers[i].factory); |
||||
} |
||||
gpr_free(g_default_resolver_scheme); |
||||
} |
||||
|
||||
void grpc_register_resolver_type(const char *scheme, |
||||
grpc_resolver_factory *factory) { |
||||
int i; |
||||
for (i = 0; i < g_number_of_resolvers; i++) { |
||||
GPR_ASSERT(0 != strcmp(scheme, g_all_of_the_resolvers[i].scheme)); |
||||
} |
||||
GPR_ASSERT(g_number_of_resolvers != MAX_RESOLVERS); |
||||
g_all_of_the_resolvers[g_number_of_resolvers].scheme = gpr_strdup(scheme); |
||||
grpc_resolver_factory_ref(factory); |
||||
g_all_of_the_resolvers[g_number_of_resolvers].factory = factory; |
||||
g_number_of_resolvers++; |
||||
} |
||||
|
||||
static grpc_resolver_factory *lookup_factory(grpc_uri *uri) { |
||||
int i; |
||||
|
||||
/* handling NULL uri's here simplifies grpc_resolver_create */ |
||||
if (!uri) return NULL; |
||||
|
||||
for (i = 0; i < g_number_of_resolvers; i++) { |
||||
if (0 == strcmp(uri->scheme, g_all_of_the_resolvers[i].scheme)) { |
||||
return g_all_of_the_resolvers[i].factory; |
||||
} |
||||
} |
||||
|
||||
return NULL; |
||||
} |
||||
|
||||
grpc_resolver *grpc_resolver_create( |
||||
const char *name, grpc_subchannel_factory *subchannel_factory) { |
||||
grpc_uri *uri; |
||||
char *tmp; |
||||
grpc_resolver_factory *factory = NULL; |
||||
grpc_resolver *resolver; |
||||
|
||||
uri = grpc_uri_parse(name, 1); |
||||
factory = lookup_factory(uri); |
||||
if (factory == NULL && g_default_resolver_scheme != NULL) { |
||||
grpc_uri_destroy(uri); |
||||
gpr_asprintf(&tmp, "%s%s", g_default_resolver_scheme, name); |
||||
uri = grpc_uri_parse(tmp, 1); |
||||
factory = lookup_factory(uri); |
||||
if (factory == NULL) { |
||||
grpc_uri_destroy(grpc_uri_parse(name, 0)); |
||||
grpc_uri_destroy(grpc_uri_parse(tmp, 0)); |
||||
gpr_log(GPR_ERROR, "don't know how to resolve '%s' or '%s'", name, tmp); |
||||
} |
||||
gpr_free(tmp); |
||||
} else if (factory == NULL) { |
||||
grpc_uri_destroy(grpc_uri_parse(name, 0)); |
||||
gpr_log(GPR_ERROR, "don't know how to resolve '%s'", name); |
||||
} |
||||
resolver = |
||||
grpc_resolver_factory_create_resolver(factory, uri, subchannel_factory); |
||||
grpc_uri_destroy(uri); |
||||
return resolver; |
||||
} |
@ -0,0 +1,62 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPC_INTERNAL_CORE_CLIENT_CONFIG_RESOLVER_REGISTRY_H |
||||
#define GRPC_INTERNAL_CORE_CLIENT_CONFIG_RESOLVER_REGISTRY_H |
||||
|
||||
#include "src/core/client_config/resolver_factory.h" |
||||
|
||||
void grpc_resolver_registry_init(const char *default_prefix); |
||||
void grpc_resolver_registry_shutdown(void); |
||||
|
||||
/** Register a resolver type.
|
||||
URI's of \a scheme will be resolved with the given resolver. |
||||
If \a priority is greater than zero, then the resolver will be eligible |
||||
to resolve names that are passed in with no scheme. Higher priority |
||||
resolvers will be tried before lower priority schemes. */ |
||||
void grpc_register_resolver_type(const char *scheme, |
||||
grpc_resolver_factory *factory); |
||||
|
||||
/** Create a resolver given \a name.
|
||||
First tries to parse \a name as a URI. If this succeeds, tries |
||||
to locate a registered resolver factory based on the URI scheme. |
||||
If parsing or location fails, prefixes default_prefix from |
||||
grpc_resolver_registry_init to name, and tries again (if default_prefix |
||||
was not NULL). |
||||
If a resolver factory was found, use it to instantiate a resolver and |
||||
return it. |
||||
If a resolver factory was not found, return NULL. */ |
||||
grpc_resolver *grpc_resolver_create( |
||||
const char *name, grpc_subchannel_factory *subchannel_factory); |
||||
|
||||
#endif /* GRPC_INTERNAL_CORE_CLIENT_CONFIG_RESOLVER_REGISTRY_H */ |
@ -0,0 +1,246 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#include "src/core/client_config/resolvers/dns_resolver.h" |
||||
|
||||
#include <string.h> |
||||
|
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/string_util.h> |
||||
|
||||
#include "src/core/client_config/lb_policies/pick_first.h" |
||||
#include "src/core/iomgr/resolve_address.h" |
||||
#include "src/core/support/string.h" |
||||
|
||||
typedef struct { |
||||
/** base class: must be first */ |
||||
grpc_resolver base; |
||||
/** refcount */ |
||||
gpr_refcount refs; |
||||
/** name to resolve */ |
||||
char *name; |
||||
/** default port to use */ |
||||
char *default_port; |
||||
/** subchannel factory */ |
||||
grpc_subchannel_factory *subchannel_factory; |
||||
/** load balancing policy factory */ |
||||
grpc_lb_policy *(*lb_policy_factory)(grpc_subchannel **subchannels, |
||||
size_t num_subchannels); |
||||
|
||||
/** mutex guarding the rest of the state */ |
||||
gpr_mu mu; |
||||
/** are we currently resolving? */ |
||||
int resolving; |
||||
/** which version of resolved_config have we published? */ |
||||
int published_version; |
||||
/** which version of resolved_config is current? */ |
||||
int resolved_version; |
||||
/** pending next completion, or NULL */ |
||||
grpc_iomgr_closure *next_completion; |
||||
/** target config address for next completion */ |
||||
grpc_client_config **target_config; |
||||
/** current (fully resolved) config */ |
||||
grpc_client_config *resolved_config; |
||||
} dns_resolver; |
||||
|
||||
static void dns_destroy(grpc_resolver *r); |
||||
|
||||
static void dns_start_resolving_locked(dns_resolver *r); |
||||
static void dns_maybe_finish_next_locked(dns_resolver *r); |
||||
|
||||
static void dns_shutdown(grpc_resolver *r); |
||||
static void dns_channel_saw_error(grpc_resolver *r, |
||||
struct sockaddr *failing_address, |
||||
int failing_address_len); |
||||
static void dns_next(grpc_resolver *r, grpc_client_config **target_config, |
||||
grpc_iomgr_closure *on_complete); |
||||
|
||||
static const grpc_resolver_vtable dns_resolver_vtable = { |
||||
dns_destroy, dns_shutdown, dns_channel_saw_error, dns_next}; |
||||
|
||||
static void dns_shutdown(grpc_resolver *resolver) { |
||||
dns_resolver *r = (dns_resolver *)resolver; |
||||
gpr_mu_lock(&r->mu); |
||||
if (r->next_completion != NULL) { |
||||
*r->target_config = NULL; |
||||
grpc_iomgr_add_callback(r->next_completion); |
||||
r->next_completion = NULL; |
||||
} |
||||
gpr_mu_unlock(&r->mu); |
||||
} |
||||
|
||||
static void dns_channel_saw_error(grpc_resolver *resolver, struct sockaddr *sa, |
||||
int len) { |
||||
dns_resolver *r = (dns_resolver *)resolver; |
||||
gpr_mu_lock(&r->mu); |
||||
if (!r->resolving) { |
||||
dns_start_resolving_locked(r); |
||||
} |
||||
gpr_mu_unlock(&r->mu); |
||||
} |
||||
|
||||
static void dns_next(grpc_resolver *resolver, |
||||
grpc_client_config **target_config, |
||||
grpc_iomgr_closure *on_complete) { |
||||
dns_resolver *r = (dns_resolver *)resolver; |
||||
gpr_mu_lock(&r->mu); |
||||
GPR_ASSERT(!r->next_completion); |
||||
r->next_completion = on_complete; |
||||
r->target_config = target_config; |
||||
if (r->resolved_version == 0 && !r->resolving) { |
||||
dns_start_resolving_locked(r); |
||||
} else { |
||||
dns_maybe_finish_next_locked(r); |
||||
} |
||||
gpr_mu_unlock(&r->mu); |
||||
} |
||||
|
||||
static void dns_on_resolved(void *arg, grpc_resolved_addresses *addresses) { |
||||
dns_resolver *r = arg; |
||||
grpc_client_config *config = NULL; |
||||
grpc_subchannel **subchannels; |
||||
grpc_subchannel_args args; |
||||
grpc_lb_policy *lb_policy; |
||||
size_t i; |
||||
if (addresses) { |
||||
config = grpc_client_config_create(); |
||||
subchannels = gpr_malloc(sizeof(grpc_subchannel *) * addresses->naddrs); |
||||
for (i = 0; i < addresses->naddrs; i++) { |
||||
memset(&args, 0, sizeof(args)); |
||||
args.addr = (struct sockaddr *)(addresses->addrs[i].addr); |
||||
args.addr_len = addresses->addrs[i].len; |
||||
subchannels[i] = grpc_subchannel_factory_create_subchannel( |
||||
r->subchannel_factory, &args); |
||||
} |
||||
lb_policy = r->lb_policy_factory(subchannels, addresses->naddrs); |
||||
grpc_client_config_set_lb_policy(config, lb_policy); |
||||
GRPC_LB_POLICY_UNREF(lb_policy, "construction"); |
||||
grpc_resolved_addresses_destroy(addresses); |
||||
gpr_free(subchannels); |
||||
} |
||||
gpr_mu_lock(&r->mu); |
||||
GPR_ASSERT(r->resolving); |
||||
r->resolving = 0; |
||||
if (r->resolved_config) { |
||||
grpc_client_config_unref(r->resolved_config); |
||||
} |
||||
r->resolved_config = config; |
||||
r->resolved_version++; |
||||
dns_maybe_finish_next_locked(r); |
||||
gpr_mu_unlock(&r->mu); |
||||
|
||||
GRPC_RESOLVER_UNREF(&r->base, "dns-resolving"); |
||||
} |
||||
|
||||
static void dns_start_resolving_locked(dns_resolver *r) { |
||||
GRPC_RESOLVER_REF(&r->base, "dns-resolving"); |
||||
GPR_ASSERT(!r->resolving); |
||||
r->resolving = 1; |
||||
grpc_resolve_address(r->name, r->default_port, dns_on_resolved, r); |
||||
} |
||||
|
||||
static void dns_maybe_finish_next_locked(dns_resolver *r) { |
||||
if (r->next_completion != NULL && |
||||
r->resolved_version != r->published_version) { |
||||
*r->target_config = r->resolved_config; |
||||
if (r->resolved_config) { |
||||
grpc_client_config_ref(r->resolved_config); |
||||
} |
||||
grpc_iomgr_add_callback(r->next_completion); |
||||
r->next_completion = NULL; |
||||
r->published_version = r->resolved_version; |
||||
} |
||||
} |
||||
|
||||
static void dns_destroy(grpc_resolver *gr) { |
||||
dns_resolver *r = (dns_resolver *)gr; |
||||
gpr_mu_destroy(&r->mu); |
||||
if (r->resolved_config) { |
||||
grpc_client_config_unref(r->resolved_config); |
||||
} |
||||
grpc_subchannel_factory_unref(r->subchannel_factory); |
||||
gpr_free(r->name); |
||||
gpr_free(r->default_port); |
||||
gpr_free(r); |
||||
} |
||||
|
||||
static grpc_resolver *dns_create( |
||||
grpc_uri *uri, const char *default_port, |
||||
grpc_lb_policy *(*lb_policy_factory)(grpc_subchannel **subchannels, |
||||
size_t num_subchannels), |
||||
grpc_subchannel_factory *subchannel_factory) { |
||||
dns_resolver *r; |
||||
const char *path = uri->path; |
||||
|
||||
if (0 != strcmp(uri->authority, "")) { |
||||
gpr_log(GPR_ERROR, "authority based uri's not supported"); |
||||
return NULL; |
||||
} |
||||
|
||||
if (path[0] == '/') ++path; |
||||
|
||||
r = gpr_malloc(sizeof(dns_resolver)); |
||||
memset(r, 0, sizeof(*r)); |
||||
gpr_ref_init(&r->refs, 1); |
||||
gpr_mu_init(&r->mu); |
||||
grpc_resolver_init(&r->base, &dns_resolver_vtable); |
||||
r->name = gpr_strdup(path); |
||||
r->default_port = gpr_strdup(default_port); |
||||
r->subchannel_factory = subchannel_factory; |
||||
r->lb_policy_factory = lb_policy_factory; |
||||
grpc_subchannel_factory_ref(subchannel_factory); |
||||
return &r->base; |
||||
} |
||||
|
||||
/*
|
||||
* FACTORY |
||||
*/ |
||||
|
||||
static void dns_factory_ref(grpc_resolver_factory *factory) {} |
||||
|
||||
static void dns_factory_unref(grpc_resolver_factory *factory) {} |
||||
|
||||
static grpc_resolver *dns_factory_create_resolver( |
||||
grpc_resolver_factory *factory, grpc_uri *uri, |
||||
grpc_subchannel_factory *subchannel_factory) { |
||||
return dns_create(uri, "https", grpc_create_pick_first_lb_policy, |
||||
subchannel_factory); |
||||
} |
||||
|
||||
static const grpc_resolver_factory_vtable dns_factory_vtable = { |
||||
dns_factory_ref, dns_factory_unref, dns_factory_create_resolver}; |
||||
static grpc_resolver_factory dns_resolver_factory = {&dns_factory_vtable}; |
||||
|
||||
grpc_resolver_factory *grpc_dns_resolver_factory_create() { |
||||
return &dns_resolver_factory; |
||||
} |
@ -0,0 +1,42 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPC_INTERNAL_CORE_CLIENT_CONFIG_RESOLVERS_DNS_RESOLVER_H |
||||
#define GRPC_INTERNAL_CORE_CLIENT_CONFIG_RESOLVERS_DNS_RESOLVER_H |
||||
|
||||
#include "src/core/client_config/resolver_factory.h" |
||||
|
||||
/** Create a dns resolver factory */ |
||||
grpc_resolver_factory *grpc_dns_resolver_factory_create(void); |
||||
|
||||
#endif /* GRPC_INTERNAL_CORE_CLIENT_CONFIG_RESOLVERS_DNS_RESOLVER_H */ |
@ -0,0 +1,195 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
#ifdef GPR_POSIX_SOCKET |
||||
|
||||
#include "src/core/client_config/resolvers/unix_resolver_posix.h" |
||||
|
||||
#include <string.h> |
||||
#include <sys/un.h> |
||||
|
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/string_util.h> |
||||
|
||||
#include "src/core/client_config/lb_policies/pick_first.h" |
||||
#include "src/core/iomgr/resolve_address.h" |
||||
#include "src/core/support/string.h" |
||||
|
||||
typedef struct { |
||||
/** base class: must be first */ |
||||
grpc_resolver base; |
||||
/** refcount */ |
||||
gpr_refcount refs; |
||||
/** subchannel factory */ |
||||
grpc_subchannel_factory *subchannel_factory; |
||||
/** load balancing policy factory */ |
||||
grpc_lb_policy *(*lb_policy_factory)(grpc_subchannel **subchannels, |
||||
size_t num_subchannels); |
||||
|
||||
/** the address that we've 'resolved' */ |
||||
struct sockaddr_un addr; |
||||
int addr_len; |
||||
|
||||
/** mutex guarding the rest of the state */ |
||||
gpr_mu mu; |
||||
/** have we published? */ |
||||
int published; |
||||
/** pending next completion, or NULL */ |
||||
grpc_iomgr_closure *next_completion; |
||||
/** target config address for next completion */ |
||||
grpc_client_config **target_config; |
||||
} unix_resolver; |
||||
|
||||
static void unix_destroy(grpc_resolver *r); |
||||
|
||||
static void unix_maybe_finish_next_locked(unix_resolver *r); |
||||
|
||||
static void unix_shutdown(grpc_resolver *r); |
||||
static void unix_channel_saw_error(grpc_resolver *r, |
||||
struct sockaddr *failing_address, |
||||
int failing_address_len); |
||||
static void unix_next(grpc_resolver *r, grpc_client_config **target_config, |
||||
grpc_iomgr_closure *on_complete); |
||||
|
||||
static const grpc_resolver_vtable unix_resolver_vtable = { |
||||
unix_destroy, unix_shutdown, unix_channel_saw_error, unix_next}; |
||||
|
||||
static void unix_shutdown(grpc_resolver *resolver) { |
||||
unix_resolver *r = (unix_resolver *)resolver; |
||||
gpr_mu_lock(&r->mu); |
||||
if (r->next_completion != NULL) { |
||||
*r->target_config = NULL; |
||||
/* TODO(ctiller): add delayed callback */ |
||||
grpc_iomgr_add_callback(r->next_completion); |
||||
r->next_completion = NULL; |
||||
} |
||||
gpr_mu_unlock(&r->mu); |
||||
} |
||||
|
||||
static void unix_channel_saw_error(grpc_resolver *resolver, struct sockaddr *sa, |
||||
int len) {} |
||||
|
||||
static void unix_next(grpc_resolver *resolver, |
||||
grpc_client_config **target_config, |
||||
grpc_iomgr_closure *on_complete) { |
||||
unix_resolver *r = (unix_resolver *)resolver; |
||||
gpr_mu_lock(&r->mu); |
||||
GPR_ASSERT(!r->next_completion); |
||||
r->next_completion = on_complete; |
||||
r->target_config = target_config; |
||||
unix_maybe_finish_next_locked(r); |
||||
gpr_mu_unlock(&r->mu); |
||||
} |
||||
|
||||
static void unix_maybe_finish_next_locked(unix_resolver *r) { |
||||
grpc_client_config *cfg; |
||||
grpc_lb_policy *lb_policy; |
||||
grpc_subchannel *subchannel; |
||||
grpc_subchannel_args args; |
||||
|
||||
if (r->next_completion != NULL && !r->published) { |
||||
cfg = grpc_client_config_create(); |
||||
memset(&args, 0, sizeof(args)); |
||||
args.addr = (struct sockaddr *)&r->addr; |
||||
args.addr_len = r->addr_len; |
||||
subchannel = |
||||
grpc_subchannel_factory_create_subchannel(r->subchannel_factory, &args); |
||||
lb_policy = r->lb_policy_factory(&subchannel, 1); |
||||
grpc_client_config_set_lb_policy(cfg, lb_policy); |
||||
GRPC_LB_POLICY_UNREF(lb_policy, "unix"); |
||||
r->published = 1; |
||||
*r->target_config = cfg; |
||||
grpc_iomgr_add_callback(r->next_completion); |
||||
r->next_completion = NULL; |
||||
} |
||||
} |
||||
|
||||
static void unix_destroy(grpc_resolver *gr) { |
||||
unix_resolver *r = (unix_resolver *)gr; |
||||
gpr_mu_destroy(&r->mu); |
||||
grpc_subchannel_factory_unref(r->subchannel_factory); |
||||
gpr_free(r); |
||||
} |
||||
|
||||
static grpc_resolver *unix_create( |
||||
grpc_uri *uri, |
||||
grpc_lb_policy *(*lb_policy_factory)(grpc_subchannel **subchannels, |
||||
size_t num_subchannels), |
||||
grpc_subchannel_factory *subchannel_factory) { |
||||
unix_resolver *r; |
||||
|
||||
if (0 != strcmp(uri->authority, "")) { |
||||
gpr_log(GPR_ERROR, "authority based uri's not supported"); |
||||
return NULL; |
||||
} |
||||
|
||||
r = gpr_malloc(sizeof(unix_resolver)); |
||||
memset(r, 0, sizeof(*r)); |
||||
gpr_ref_init(&r->refs, 1); |
||||
gpr_mu_init(&r->mu); |
||||
grpc_resolver_init(&r->base, &unix_resolver_vtable); |
||||
r->subchannel_factory = subchannel_factory; |
||||
r->lb_policy_factory = lb_policy_factory; |
||||
|
||||
r->addr.sun_family = AF_UNIX; |
||||
strcpy(r->addr.sun_path, uri->path); |
||||
r->addr_len = strlen(r->addr.sun_path) + sizeof(r->addr.sun_family) + 1; |
||||
|
||||
grpc_subchannel_factory_ref(subchannel_factory); |
||||
return &r->base; |
||||
} |
||||
|
||||
/*
|
||||
* FACTORY |
||||
*/ |
||||
|
||||
static void unix_factory_ref(grpc_resolver_factory *factory) {} |
||||
|
||||
static void unix_factory_unref(grpc_resolver_factory *factory) {} |
||||
|
||||
static grpc_resolver *unix_factory_create_resolver( |
||||
grpc_resolver_factory *factory, grpc_uri *uri, |
||||
grpc_subchannel_factory *subchannel_factory) { |
||||
return unix_create(uri, grpc_create_pick_first_lb_policy, subchannel_factory); |
||||
} |
||||
|
||||
static const grpc_resolver_factory_vtable unix_factory_vtable = { |
||||
unix_factory_ref, unix_factory_unref, unix_factory_create_resolver}; |
||||
static grpc_resolver_factory unix_resolver_factory = {&unix_factory_vtable}; |
||||
|
||||
grpc_resolver_factory *grpc_unix_resolver_factory_create() { |
||||
return &unix_resolver_factory; |
||||
} |
||||
|
||||
#endif |
@ -0,0 +1,44 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPC_INTERNAL_CORE_CLIENT_CONFIG_RESOLVERS_UNIX_RESOLVER_H |
||||
#define GRPC_INTERNAL_CORE_CLIENT_CONFIG_RESOLVERS_UNIX_RESOLVER_H |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include "src/core/client_config/resolver_factory.h" |
||||
|
||||
/** Create a unix resolver factory */ |
||||
grpc_resolver_factory *grpc_unix_resolver_factory_create(void); |
||||
|
||||
#endif /* GRPC_INTERNAL_CORE_CLIENT_CONFIG_RESOLVERS_UNIX_RESOLVER_H */ |
@ -0,0 +1,659 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#include "src/core/client_config/subchannel.h" |
||||
|
||||
#include <string.h> |
||||
|
||||
#include <grpc/support/alloc.h> |
||||
|
||||
#include "src/core/channel/channel_args.h" |
||||
#include "src/core/channel/connected_channel.h" |
||||
#include "src/core/iomgr/alarm.h" |
||||
#include "src/core/transport/connectivity_state.h" |
||||
|
||||
typedef struct { |
||||
/* all fields protected by subchannel->mu */ |
||||
/** refcount */ |
||||
int refs; |
||||
/** parent subchannel */ |
||||
grpc_subchannel *subchannel; |
||||
} connection; |
||||
|
||||
typedef struct { |
||||
grpc_iomgr_closure closure; |
||||
size_t version; |
||||
grpc_subchannel *subchannel; |
||||
grpc_connectivity_state connectivity_state; |
||||
} state_watcher; |
||||
|
||||
typedef struct waiting_for_connect { |
||||
struct waiting_for_connect *next; |
||||
grpc_iomgr_closure *notify; |
||||
grpc_pollset *pollset; |
||||
grpc_subchannel_call **target; |
||||
grpc_subchannel *subchannel; |
||||
grpc_iomgr_closure continuation; |
||||
} waiting_for_connect; |
||||
|
||||
struct grpc_subchannel { |
||||
grpc_connector *connector; |
||||
|
||||
/** non-transport related channel filters */ |
||||
const grpc_channel_filter **filters; |
||||
size_t num_filters; |
||||
/** channel arguments */ |
||||
grpc_channel_args *args; |
||||
/** address to connect to */ |
||||
struct sockaddr *addr; |
||||
size_t addr_len; |
||||
/** metadata context */ |
||||
grpc_mdctx *mdctx; |
||||
/** master channel - the grpc_channel instance that ultimately owns
|
||||
this channel_data via its channel stack. |
||||
We occasionally use this to bump the refcount on the master channel |
||||
to keep ourselves alive through an asynchronous operation. */ |
||||
grpc_channel *master; |
||||
/** have we seen a disconnection? */ |
||||
int disconnected; |
||||
|
||||
/** set during connection */ |
||||
grpc_connect_out_args connecting_result; |
||||
|
||||
/** callback for connection finishing */ |
||||
grpc_iomgr_closure connected; |
||||
|
||||
/** pollset_set tracking who's interested in a connection
|
||||
being setup */ |
||||
grpc_pollset_set pollset_set; |
||||
|
||||
/** mutex protecting remaining elements */ |
||||
gpr_mu mu; |
||||
|
||||
/** active connection */ |
||||
connection *active; |
||||
/** version number for the active connection */ |
||||
size_t active_version; |
||||
/** refcount */ |
||||
int refs; |
||||
/** are we connecting */ |
||||
int connecting; |
||||
/** things waiting for a connection */ |
||||
waiting_for_connect *waiting; |
||||
/** connectivity state tracking */ |
||||
grpc_connectivity_state_tracker state_tracker; |
||||
|
||||
/** next connect attempt time */ |
||||
gpr_timespec next_attempt; |
||||
/** amount to backoff each failure */ |
||||
gpr_timespec backoff_delta; |
||||
/** do we have an active alarm? */ |
||||
int have_alarm; |
||||
/** our alarm */ |
||||
grpc_alarm alarm; |
||||
}; |
||||
|
||||
struct grpc_subchannel_call { |
||||
connection *connection; |
||||
gpr_refcount refs; |
||||
}; |
||||
|
||||
#define SUBCHANNEL_CALL_TO_CALL_STACK(call) ((grpc_call_stack *)((call) + 1)) |
||||
#define CHANNEL_STACK_FROM_CONNECTION(con) ((grpc_channel_stack *)((con) + 1)) |
||||
|
||||
static grpc_subchannel_call *create_call(connection *con); |
||||
static void connectivity_state_changed_locked(grpc_subchannel *c); |
||||
static grpc_connectivity_state compute_connectivity_locked(grpc_subchannel *c); |
||||
static gpr_timespec compute_connect_deadline(grpc_subchannel *c); |
||||
static void subchannel_connected(void *subchannel, int iomgr_success); |
||||
|
||||
static void subchannel_ref_locked( |
||||
grpc_subchannel *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS); |
||||
static int subchannel_unref_locked( |
||||
grpc_subchannel *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) GRPC_MUST_USE_RESULT; |
||||
static void connection_ref_locked(connection *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS); |
||||
static grpc_subchannel *connection_unref_locked( |
||||
connection *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) GRPC_MUST_USE_RESULT; |
||||
static void subchannel_destroy(grpc_subchannel *c); |
||||
|
||||
#ifdef GRPC_SUBCHANNEL_REFCOUNT_DEBUG |
||||
#define SUBCHANNEL_REF_LOCKED(p, r) \ |
||||
subchannel_ref_locked((p), __FILE__, __LINE__, (r)) |
||||
#define SUBCHANNEL_UNREF_LOCKED(p, r) \ |
||||
subchannel_unref_locked((p), __FILE__, __LINE__, (r)) |
||||
#define CONNECTION_REF_LOCKED(p, r) \ |
||||
connection_ref_locked((p), __FILE__, __LINE__, (r)) |
||||
#define CONNECTION_UNREF_LOCKED(p, r) \ |
||||
connection_unref_locked((p), __FILE__, __LINE__, (r)) |
||||
#define REF_PASS_ARGS , file, line, reason |
||||
#define REF_LOG(name, p) \ |
||||
gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "%s: %p ref %d -> %d %s", \
|
||||
(name), (p), (p)->refs, (p)->refs + 1, reason) |
||||
#define UNREF_LOG(name, p) \ |
||||
gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "%s: %p unref %d -> %d %s", \
|
||||
(name), (p), (p)->refs, (p)->refs - 1, reason) |
||||
#else |
||||
#define SUBCHANNEL_REF_LOCKED(p, r) subchannel_ref_locked((p)) |
||||
#define SUBCHANNEL_UNREF_LOCKED(p, r) subchannel_unref_locked((p)) |
||||
#define CONNECTION_REF_LOCKED(p, r) connection_ref_locked((p)) |
||||
#define CONNECTION_UNREF_LOCKED(p, r) connection_unref_locked((p)) |
||||
#define REF_PASS_ARGS |
||||
#define REF_LOG(name, p) \ |
||||
do { \
|
||||
} while (0) |
||||
#define UNREF_LOG(name, p) \ |
||||
do { \
|
||||
} while (0) |
||||
#endif |
||||
|
||||
/*
|
||||
* connection implementation |
||||
*/ |
||||
|
||||
static void connection_destroy(connection *c) { |
||||
GPR_ASSERT(c->refs == 0); |
||||
grpc_channel_stack_destroy(CHANNEL_STACK_FROM_CONNECTION(c)); |
||||
gpr_free(c); |
||||
} |
||||
|
||||
static void connection_ref_locked( |
||||
connection *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) { |
||||
REF_LOG("CONNECTION", c); |
||||
subchannel_ref_locked(c->subchannel REF_PASS_ARGS); |
||||
++c->refs; |
||||
} |
||||
|
||||
static grpc_subchannel *connection_unref_locked( |
||||
connection *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) { |
||||
grpc_subchannel *destroy = NULL; |
||||
UNREF_LOG("CONNECTION", c); |
||||
if (subchannel_unref_locked(c->subchannel REF_PASS_ARGS)) { |
||||
destroy = c->subchannel; |
||||
} |
||||
if (--c->refs == 0 && c->subchannel->active != c) { |
||||
connection_destroy(c); |
||||
} |
||||
return destroy; |
||||
} |
||||
|
||||
/*
|
||||
* grpc_subchannel implementation |
||||
*/ |
||||
|
||||
static void subchannel_ref_locked( |
||||
grpc_subchannel *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) { |
||||
REF_LOG("SUBCHANNEL", c); |
||||
++c->refs; |
||||
} |
||||
|
||||
static int subchannel_unref_locked( |
||||
grpc_subchannel *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) { |
||||
UNREF_LOG("SUBCHANNEL", c); |
||||
return --c->refs == 0; |
||||
} |
||||
|
||||
void grpc_subchannel_ref(grpc_subchannel *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) { |
||||
gpr_mu_lock(&c->mu); |
||||
subchannel_ref_locked(c REF_PASS_ARGS); |
||||
gpr_mu_unlock(&c->mu); |
||||
} |
||||
|
||||
void grpc_subchannel_unref(grpc_subchannel *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) { |
||||
int destroy; |
||||
gpr_mu_lock(&c->mu); |
||||
destroy = subchannel_unref_locked(c REF_PASS_ARGS); |
||||
gpr_mu_unlock(&c->mu); |
||||
if (destroy) subchannel_destroy(c); |
||||
} |
||||
|
||||
static void subchannel_destroy(grpc_subchannel *c) { |
||||
if (c->active != NULL) { |
||||
connection_destroy(c->active); |
||||
} |
||||
gpr_free(c->filters); |
||||
grpc_channel_args_destroy(c->args); |
||||
gpr_free(c->addr); |
||||
grpc_mdctx_unref(c->mdctx); |
||||
grpc_pollset_set_destroy(&c->pollset_set); |
||||
grpc_connectivity_state_destroy(&c->state_tracker); |
||||
grpc_connector_unref(c->connector); |
||||
gpr_free(c); |
||||
} |
||||
|
||||
void grpc_subchannel_add_interested_party(grpc_subchannel *c, |
||||
grpc_pollset *pollset) { |
||||
grpc_pollset_set_add_pollset(&c->pollset_set, pollset); |
||||
} |
||||
|
||||
void grpc_subchannel_del_interested_party(grpc_subchannel *c, |
||||
grpc_pollset *pollset) { |
||||
grpc_pollset_set_del_pollset(&c->pollset_set, pollset); |
||||
} |
||||
|
||||
grpc_subchannel *grpc_subchannel_create(grpc_connector *connector, |
||||
grpc_subchannel_args *args) { |
||||
grpc_subchannel *c = gpr_malloc(sizeof(*c)); |
||||
memset(c, 0, sizeof(*c)); |
||||
c->refs = 1; |
||||
c->connector = connector; |
||||
grpc_connector_ref(c->connector); |
||||
c->num_filters = args->filter_count; |
||||
c->filters = gpr_malloc(sizeof(grpc_channel_filter *) * c->num_filters); |
||||
memcpy(c->filters, args->filters, |
||||
sizeof(grpc_channel_filter *) * c->num_filters); |
||||
c->addr = gpr_malloc(args->addr_len); |
||||
memcpy(c->addr, args->addr, args->addr_len); |
||||
c->addr_len = args->addr_len; |
||||
c->args = grpc_channel_args_copy(args->args); |
||||
c->mdctx = args->mdctx; |
||||
c->master = args->master; |
||||
grpc_mdctx_ref(c->mdctx); |
||||
grpc_pollset_set_init(&c->pollset_set); |
||||
grpc_iomgr_closure_init(&c->connected, subchannel_connected, c); |
||||
grpc_connectivity_state_init(&c->state_tracker, GRPC_CHANNEL_IDLE); |
||||
gpr_mu_init(&c->mu); |
||||
return c; |
||||
} |
||||
|
||||
static void continue_connect(grpc_subchannel *c) { |
||||
grpc_connect_in_args args; |
||||
|
||||
args.interested_parties = &c->pollset_set; |
||||
args.addr = c->addr; |
||||
args.addr_len = c->addr_len; |
||||
args.deadline = compute_connect_deadline(c); |
||||
args.channel_args = c->args; |
||||
args.metadata_context = c->mdctx; |
||||
|
||||
grpc_connector_connect(c->connector, &args, &c->connecting_result, |
||||
&c->connected); |
||||
} |
||||
|
||||
static void start_connect(grpc_subchannel *c) { |
||||
gpr_timespec now = gpr_now(); |
||||
c->next_attempt = now; |
||||
c->backoff_delta = gpr_time_from_seconds(1); |
||||
|
||||
continue_connect(c); |
||||
} |
||||
|
||||
static void continue_creating_call(void *arg, int iomgr_success) { |
||||
waiting_for_connect *w4c = arg; |
||||
grpc_subchannel_create_call(w4c->subchannel, w4c->pollset, w4c->target, |
||||
w4c->notify); |
||||
GRPC_SUBCHANNEL_UNREF(w4c->subchannel, "waiting_for_connect"); |
||||
gpr_free(w4c); |
||||
} |
||||
|
||||
void grpc_subchannel_create_call(grpc_subchannel *c, grpc_pollset *pollset, |
||||
grpc_subchannel_call **target, |
||||
grpc_iomgr_closure *notify) { |
||||
connection *con; |
||||
gpr_mu_lock(&c->mu); |
||||
if (c->active != NULL) { |
||||
con = c->active; |
||||
CONNECTION_REF_LOCKED(con, "call"); |
||||
gpr_mu_unlock(&c->mu); |
||||
|
||||
*target = create_call(con); |
||||
notify->cb(notify->cb_arg, 1); |
||||
} else { |
||||
waiting_for_connect *w4c = gpr_malloc(sizeof(*w4c)); |
||||
w4c->next = c->waiting; |
||||
w4c->notify = notify; |
||||
w4c->pollset = pollset; |
||||
w4c->target = target; |
||||
w4c->subchannel = c; |
||||
/* released when clearing w4c */ |
||||
SUBCHANNEL_REF_LOCKED(c, "waiting_for_connect"); |
||||
grpc_iomgr_closure_init(&w4c->continuation, continue_creating_call, w4c); |
||||
c->waiting = w4c; |
||||
grpc_subchannel_add_interested_party(c, pollset); |
||||
if (!c->connecting) { |
||||
c->connecting = 1; |
||||
connectivity_state_changed_locked(c); |
||||
/* released by connection */ |
||||
SUBCHANNEL_REF_LOCKED(c, "connecting"); |
||||
gpr_mu_unlock(&c->mu); |
||||
|
||||
start_connect(c); |
||||
} else { |
||||
gpr_mu_unlock(&c->mu); |
||||
} |
||||
} |
||||
} |
||||
|
||||
grpc_connectivity_state grpc_subchannel_check_connectivity(grpc_subchannel *c) { |
||||
grpc_connectivity_state state; |
||||
gpr_mu_lock(&c->mu); |
||||
state = grpc_connectivity_state_check(&c->state_tracker); |
||||
gpr_mu_unlock(&c->mu); |
||||
return state; |
||||
} |
||||
|
||||
void grpc_subchannel_notify_on_state_change(grpc_subchannel *c, |
||||
grpc_connectivity_state *state, |
||||
grpc_iomgr_closure *notify) { |
||||
int do_connect = 0; |
||||
gpr_mu_lock(&c->mu); |
||||
if (grpc_connectivity_state_notify_on_state_change(&c->state_tracker, state, |
||||
notify)) { |
||||
do_connect = 1; |
||||
c->connecting = 1; |
||||
/* released by connection */ |
||||
SUBCHANNEL_REF_LOCKED(c, "connecting"); |
||||
connectivity_state_changed_locked(c); |
||||
} |
||||
gpr_mu_unlock(&c->mu); |
||||
if (do_connect) { |
||||
start_connect(c); |
||||
} |
||||
} |
||||
|
||||
void grpc_subchannel_process_transport_op(grpc_subchannel *c, |
||||
grpc_transport_op *op) { |
||||
connection *con = NULL; |
||||
grpc_subchannel *destroy; |
||||
int cancel_alarm = 0; |
||||
gpr_mu_lock(&c->mu); |
||||
if (op->disconnect) { |
||||
c->disconnected = 1; |
||||
connectivity_state_changed_locked(c); |
||||
if (c->have_alarm) { |
||||
cancel_alarm = 1; |
||||
} |
||||
} |
||||
if (c->active != NULL) { |
||||
con = c->active; |
||||
CONNECTION_REF_LOCKED(con, "transport-op"); |
||||
} |
||||
gpr_mu_unlock(&c->mu); |
||||
|
||||
if (con != NULL) { |
||||
grpc_channel_stack *channel_stack = CHANNEL_STACK_FROM_CONNECTION(con); |
||||
grpc_channel_element *top_elem = |
||||
grpc_channel_stack_element(channel_stack, 0); |
||||
top_elem->filter->start_transport_op(top_elem, op); |
||||
|
||||
gpr_mu_lock(&c->mu); |
||||
destroy = CONNECTION_UNREF_LOCKED(con, "transport-op"); |
||||
gpr_mu_unlock(&c->mu); |
||||
if (destroy) { |
||||
subchannel_destroy(destroy); |
||||
} |
||||
} |
||||
|
||||
if (cancel_alarm) { |
||||
grpc_alarm_cancel(&c->alarm); |
||||
} |
||||
} |
||||
|
||||
static void on_state_changed(void *p, int iomgr_success) { |
||||
state_watcher *sw = p; |
||||
grpc_subchannel *c = sw->subchannel; |
||||
gpr_mu *mu = &c->mu; |
||||
int destroy; |
||||
grpc_transport_op op; |
||||
grpc_channel_element *elem; |
||||
connection *destroy_connection = NULL; |
||||
|
||||
gpr_mu_lock(mu); |
||||
|
||||
/* if we failed or there is a version number mismatch, just leave
|
||||
this closure */ |
||||
if (!iomgr_success || sw->subchannel->active_version != sw->version) { |
||||
goto done; |
||||
} |
||||
|
||||
switch (sw->connectivity_state) { |
||||
case GRPC_CHANNEL_CONNECTING: |
||||
case GRPC_CHANNEL_READY: |
||||
case GRPC_CHANNEL_IDLE: |
||||
/* all is still good: keep watching */ |
||||
memset(&op, 0, sizeof(op)); |
||||
op.connectivity_state = &sw->connectivity_state; |
||||
op.on_connectivity_state_change = &sw->closure; |
||||
elem = grpc_channel_stack_element( |
||||
CHANNEL_STACK_FROM_CONNECTION(c->active), 0); |
||||
elem->filter->start_transport_op(elem, &op); |
||||
/* early out */ |
||||
gpr_mu_unlock(mu); |
||||
return; |
||||
case GRPC_CHANNEL_FATAL_FAILURE: |
||||
case GRPC_CHANNEL_TRANSIENT_FAILURE: |
||||
/* things have gone wrong, deactivate and enter idle */ |
||||
if (sw->subchannel->active->refs == 0) { |
||||
destroy_connection = sw->subchannel->active; |
||||
} |
||||
sw->subchannel->active = NULL; |
||||
grpc_connectivity_state_set(&c->state_tracker, |
||||
GRPC_CHANNEL_TRANSIENT_FAILURE); |
||||
break; |
||||
} |
||||
|
||||
done: |
||||
connectivity_state_changed_locked(c); |
||||
destroy = SUBCHANNEL_UNREF_LOCKED(c, "state_watcher"); |
||||
gpr_free(sw); |
||||
gpr_mu_unlock(mu); |
||||
if (destroy) { |
||||
subchannel_destroy(c); |
||||
} |
||||
if (destroy_connection != NULL) { |
||||
connection_destroy(destroy_connection); |
||||
} |
||||
} |
||||
|
||||
static void publish_transport(grpc_subchannel *c) { |
||||
size_t channel_stack_size; |
||||
connection *con; |
||||
grpc_channel_stack *stk; |
||||
size_t num_filters; |
||||
const grpc_channel_filter **filters; |
||||
waiting_for_connect *w4c; |
||||
grpc_transport_op op; |
||||
state_watcher *sw; |
||||
connection *destroy_connection = NULL; |
||||
grpc_channel_element *elem; |
||||
|
||||
/* build final filter list */ |
||||
num_filters = c->num_filters + c->connecting_result.num_filters + 1; |
||||
filters = gpr_malloc(sizeof(*filters) * num_filters); |
||||
memcpy(filters, c->filters, sizeof(*filters) * c->num_filters); |
||||
memcpy(filters + c->num_filters, c->connecting_result.filters, |
||||
sizeof(*filters) * c->connecting_result.num_filters); |
||||
filters[num_filters - 1] = &grpc_connected_channel_filter; |
||||
|
||||
/* construct channel stack */ |
||||
channel_stack_size = grpc_channel_stack_size(filters, num_filters); |
||||
con = gpr_malloc(sizeof(connection) + channel_stack_size); |
||||
stk = (grpc_channel_stack *)(con + 1); |
||||
con->refs = 0; |
||||
con->subchannel = c; |
||||
grpc_channel_stack_init(filters, num_filters, c->master, c->args, c->mdctx, |
||||
stk); |
||||
grpc_connected_channel_bind_transport(stk, c->connecting_result.transport); |
||||
gpr_free(c->connecting_result.filters); |
||||
memset(&c->connecting_result, 0, sizeof(c->connecting_result)); |
||||
|
||||
/* initialize state watcher */ |
||||
sw = gpr_malloc(sizeof(*sw)); |
||||
grpc_iomgr_closure_init(&sw->closure, on_state_changed, sw); |
||||
sw->subchannel = c; |
||||
sw->connectivity_state = GRPC_CHANNEL_READY; |
||||
|
||||
gpr_mu_lock(&c->mu); |
||||
|
||||
if (c->disconnected) { |
||||
gpr_mu_unlock(&c->mu); |
||||
gpr_free(sw); |
||||
gpr_free(filters); |
||||
grpc_channel_stack_destroy(stk); |
||||
return; |
||||
} |
||||
|
||||
/* publish */ |
||||
if (c->active != NULL && c->active->refs == 0) { |
||||
destroy_connection = c->active; |
||||
} |
||||
c->active = con; |
||||
c->active_version++; |
||||
sw->version = c->active_version; |
||||
c->connecting = 0; |
||||
|
||||
/* watch for changes; subchannel ref for connecting is donated
|
||||
to the state watcher */ |
||||
memset(&op, 0, sizeof(op)); |
||||
op.connectivity_state = &sw->connectivity_state; |
||||
op.on_connectivity_state_change = &sw->closure; |
||||
SUBCHANNEL_REF_LOCKED(c, "state_watcher"); |
||||
GPR_ASSERT(!SUBCHANNEL_UNREF_LOCKED(c, "connecting")); |
||||
elem = |
||||
grpc_channel_stack_element(CHANNEL_STACK_FROM_CONNECTION(c->active), 0); |
||||
elem->filter->start_transport_op(elem, &op); |
||||
|
||||
/* signal completion */ |
||||
connectivity_state_changed_locked(c); |
||||
while ((w4c = c->waiting)) { |
||||
c->waiting = w4c->next; |
||||
grpc_iomgr_add_callback(&w4c->continuation); |
||||
} |
||||
|
||||
gpr_mu_unlock(&c->mu); |
||||
|
||||
gpr_free(filters); |
||||
|
||||
if (destroy_connection != NULL) { |
||||
connection_destroy(destroy_connection); |
||||
} |
||||
} |
||||
|
||||
static void on_alarm(void *arg, int iomgr_success) { |
||||
grpc_subchannel *c = arg; |
||||
gpr_mu_lock(&c->mu); |
||||
c->have_alarm = 0; |
||||
if (c->disconnected) { |
||||
iomgr_success = 0; |
||||
} |
||||
connectivity_state_changed_locked(c); |
||||
gpr_mu_unlock(&c->mu); |
||||
if (iomgr_success) { |
||||
continue_connect(c); |
||||
} else { |
||||
GRPC_SUBCHANNEL_UNREF(c, "connecting"); |
||||
} |
||||
} |
||||
|
||||
static void subchannel_connected(void *arg, int iomgr_success) { |
||||
grpc_subchannel *c = arg; |
||||
if (c->connecting_result.transport != NULL) { |
||||
publish_transport(c); |
||||
} else { |
||||
gpr_mu_lock(&c->mu); |
||||
connectivity_state_changed_locked(c); |
||||
GPR_ASSERT(!c->have_alarm); |
||||
c->have_alarm = 1; |
||||
c->next_attempt = gpr_time_add(c->next_attempt, c->backoff_delta); |
||||
c->backoff_delta = gpr_time_add(c->backoff_delta, c->backoff_delta); |
||||
grpc_alarm_init(&c->alarm, c->next_attempt, on_alarm, c, gpr_now()); |
||||
gpr_mu_unlock(&c->mu); |
||||
} |
||||
} |
||||
|
||||
static gpr_timespec compute_connect_deadline(grpc_subchannel *c) { |
||||
return gpr_time_add(c->next_attempt, c->backoff_delta); |
||||
} |
||||
|
||||
static grpc_connectivity_state compute_connectivity_locked(grpc_subchannel *c) { |
||||
if (c->disconnected) { |
||||
return GRPC_CHANNEL_FATAL_FAILURE; |
||||
} |
||||
if (c->connecting) { |
||||
if (c->have_alarm) { |
||||
return GRPC_CHANNEL_TRANSIENT_FAILURE; |
||||
} |
||||
return GRPC_CHANNEL_CONNECTING; |
||||
} |
||||
if (c->active) { |
||||
return GRPC_CHANNEL_READY; |
||||
} |
||||
return GRPC_CHANNEL_IDLE; |
||||
} |
||||
|
||||
static void connectivity_state_changed_locked(grpc_subchannel *c) { |
||||
grpc_connectivity_state current = compute_connectivity_locked(c); |
||||
grpc_connectivity_state_set(&c->state_tracker, current); |
||||
} |
||||
|
||||
/*
|
||||
* grpc_subchannel_call implementation |
||||
*/ |
||||
|
||||
void grpc_subchannel_call_ref( |
||||
grpc_subchannel_call *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) { |
||||
gpr_ref(&c->refs); |
||||
} |
||||
|
||||
void grpc_subchannel_call_unref( |
||||
grpc_subchannel_call *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) { |
||||
if (gpr_unref(&c->refs)) { |
||||
gpr_mu *mu = &c->connection->subchannel->mu; |
||||
grpc_subchannel *destroy; |
||||
grpc_call_stack_destroy(SUBCHANNEL_CALL_TO_CALL_STACK(c)); |
||||
gpr_mu_lock(mu); |
||||
destroy = CONNECTION_UNREF_LOCKED(c->connection, "call"); |
||||
gpr_mu_unlock(mu); |
||||
gpr_free(c); |
||||
if (destroy != NULL) { |
||||
subchannel_destroy(destroy); |
||||
} |
||||
} |
||||
} |
||||
|
||||
void grpc_subchannel_call_process_op(grpc_subchannel_call *call, |
||||
grpc_transport_stream_op *op) { |
||||
grpc_call_stack *call_stack = SUBCHANNEL_CALL_TO_CALL_STACK(call); |
||||
grpc_call_element *top_elem = grpc_call_stack_element(call_stack, 0); |
||||
top_elem->filter->start_transport_stream_op(top_elem, op); |
||||
} |
||||
|
||||
grpc_subchannel_call *create_call(connection *con) { |
||||
grpc_channel_stack *chanstk = CHANNEL_STACK_FROM_CONNECTION(con); |
||||
grpc_subchannel_call *call = |
||||
gpr_malloc(sizeof(grpc_subchannel_call) + chanstk->call_stack_size); |
||||
grpc_call_stack *callstk = SUBCHANNEL_CALL_TO_CALL_STACK(call); |
||||
call->connection = con; |
||||
gpr_ref_init(&call->refs, 1); |
||||
grpc_call_stack_init(chanstk, NULL, NULL, callstk); |
||||
return call; |
||||
} |
@ -0,0 +1,124 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPC_INTERNAL_CORE_CLIENT_CONFIG_SUBCHANNEL_H |
||||
#define GRPC_INTERNAL_CORE_CLIENT_CONFIG_SUBCHANNEL_H |
||||
|
||||
#include "src/core/channel/channel_stack.h" |
||||
#include "src/core/client_config/connector.h" |
||||
|
||||
/** A (sub-)channel that knows how to connect to exactly one target
|
||||
address. Provides a target for load balancing. */ |
||||
typedef struct grpc_subchannel grpc_subchannel; |
||||
typedef struct grpc_subchannel_call grpc_subchannel_call; |
||||
typedef struct grpc_subchannel_args grpc_subchannel_args; |
||||
|
||||
#ifdef GRPC_SUBCHANNEL_REFCOUNT_DEBUG |
||||
#define GRPC_SUBCHANNEL_REF(p, r) \ |
||||
grpc_subchannel_ref((p), __FILE__, __LINE__, (r)) |
||||
#define GRPC_SUBCHANNEL_UNREF(p, r) \ |
||||
grpc_subchannel_unref((p), __FILE__, __LINE__, (r)) |
||||
#define GRPC_SUBCHANNEL_CALL_REF(p, r) \ |
||||
grpc_subchannel_call_ref((p), __FILE__, __LINE__, (r)) |
||||
#define GRPC_SUBCHANNEL_CALL_UNREF(p, r) \ |
||||
grpc_subchannel_call_unref((p), __FILE__, __LINE__, (r)) |
||||
#define GRPC_SUBCHANNEL_REF_EXTRA_ARGS \ |
||||
, const char *file, int line, const char *reason |
||||
#else |
||||
#define GRPC_SUBCHANNEL_REF(p, r) grpc_subchannel_ref((p)) |
||||
#define GRPC_SUBCHANNEL_UNREF(p, r) grpc_subchannel_unref((p)) |
||||
#define GRPC_SUBCHANNEL_CALL_REF(p, r) grpc_subchannel_call_ref((p)) |
||||
#define GRPC_SUBCHANNEL_CALL_UNREF(p, r) grpc_subchannel_call_unref((p)) |
||||
#define GRPC_SUBCHANNEL_REF_EXTRA_ARGS |
||||
#endif |
||||
|
||||
void grpc_subchannel_ref( |
||||
grpc_subchannel *channel GRPC_SUBCHANNEL_REF_EXTRA_ARGS); |
||||
void grpc_subchannel_unref( |
||||
grpc_subchannel *channel GRPC_SUBCHANNEL_REF_EXTRA_ARGS); |
||||
void grpc_subchannel_call_ref( |
||||
grpc_subchannel_call *call GRPC_SUBCHANNEL_REF_EXTRA_ARGS); |
||||
void grpc_subchannel_call_unref( |
||||
grpc_subchannel_call *call GRPC_SUBCHANNEL_REF_EXTRA_ARGS); |
||||
|
||||
/** construct a call (possibly asynchronously) */ |
||||
void grpc_subchannel_create_call(grpc_subchannel *subchannel, |
||||
grpc_pollset *pollset, |
||||
grpc_subchannel_call **target, |
||||
grpc_iomgr_closure *notify); |
||||
|
||||
/** process a transport level op */ |
||||
void grpc_subchannel_process_transport_op(grpc_subchannel *subchannel, |
||||
grpc_transport_op *op); |
||||
|
||||
/** poll the current connectivity state of a channel */ |
||||
grpc_connectivity_state grpc_subchannel_check_connectivity( |
||||
grpc_subchannel *channel); |
||||
|
||||
/** call notify when the connectivity state of a channel changes from *state.
|
||||
Updates *state with the new state of the channel */ |
||||
void grpc_subchannel_notify_on_state_change(grpc_subchannel *channel, |
||||
grpc_connectivity_state *state, |
||||
grpc_iomgr_closure *notify); |
||||
|
||||
void grpc_subchannel_add_interested_party(grpc_subchannel *channel, |
||||
grpc_pollset *pollset); |
||||
void grpc_subchannel_del_interested_party(grpc_subchannel *channel, |
||||
grpc_pollset *pollset); |
||||
|
||||
/** continue processing a transport op */ |
||||
void grpc_subchannel_call_process_op(grpc_subchannel_call *subchannel_call, |
||||
grpc_transport_stream_op *op); |
||||
|
||||
struct grpc_subchannel_args { |
||||
/** Channel filters for this channel - wrapped factories will likely
|
||||
want to mutate this */ |
||||
const grpc_channel_filter **filters; |
||||
/** The number of filters in the above array */ |
||||
size_t filter_count; |
||||
/** Channel arguments to be supplied to the newly created channel */ |
||||
const grpc_channel_args *args; |
||||
/** Address to connect to */ |
||||
struct sockaddr *addr; |
||||
size_t addr_len; |
||||
/** metadata context to use */ |
||||
grpc_mdctx *mdctx; |
||||
/** master channel */ |
||||
grpc_channel *master; |
||||
}; |
||||
|
||||
/** create a subchannel given a connector */ |
||||
grpc_subchannel *grpc_subchannel_create(grpc_connector *connector, |
||||
grpc_subchannel_args *args); |
||||
|
||||
#endif /* GRPC_INTERNAL_CORE_CLIENT_CONFIG_SUBCHANNEL_H */ |
@ -0,0 +1,46 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#include "src/core/client_config/subchannel_factory.h" |
||||
|
||||
void grpc_subchannel_factory_ref(grpc_subchannel_factory *factory) { |
||||
factory->vtable->ref(factory); |
||||
} |
||||
void grpc_subchannel_factory_unref(grpc_subchannel_factory *factory) { |
||||
factory->vtable->unref(factory); |
||||
} |
||||
|
||||
grpc_subchannel *grpc_subchannel_factory_create_subchannel( |
||||
grpc_subchannel_factory *factory, grpc_subchannel_args *args) { |
||||
return factory->vtable->create_subchannel(factory, args); |
||||
} |
@ -0,0 +1,149 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#include "src/core/client_config/uri_parser.h" |
||||
|
||||
#include <string.h> |
||||
|
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/log.h> |
||||
#include <grpc/support/string_util.h> |
||||
|
||||
static grpc_uri *bad_uri(const char *uri_text, int pos, const char *section, |
||||
int suppress_errors) { |
||||
char *line_prefix; |
||||
int pfx_len; |
||||
|
||||
if (!suppress_errors) { |
||||
gpr_asprintf(&line_prefix, "bad uri.%s: '", section); |
||||
pfx_len = strlen(line_prefix) + pos; |
||||
gpr_log(GPR_ERROR, "%s%s'", line_prefix, uri_text); |
||||
gpr_free(line_prefix); |
||||
|
||||
line_prefix = gpr_malloc(pfx_len + 1); |
||||
memset(line_prefix, ' ', pfx_len); |
||||
line_prefix[pfx_len] = 0; |
||||
gpr_log(GPR_ERROR, "%s^ here", line_prefix); |
||||
gpr_free(line_prefix); |
||||
} |
||||
|
||||
return NULL; |
||||
} |
||||
|
||||
static char *copy_fragment(const char *src, int begin, int end) { |
||||
char *out = gpr_malloc(end - begin + 1); |
||||
memcpy(out, src + begin, end - begin); |
||||
out[end - begin] = 0; |
||||
return out; |
||||
} |
||||
|
||||
grpc_uri *grpc_uri_parse(const char *uri_text, int suppress_errors) { |
||||
grpc_uri *uri; |
||||
int scheme_begin = 0; |
||||
int scheme_end = -1; |
||||
int authority_begin = -1; |
||||
int authority_end = -1; |
||||
int path_begin = -1; |
||||
int path_end = -1; |
||||
int i; |
||||
|
||||
for (i = scheme_begin; uri_text[i] != 0; i++) { |
||||
if (uri_text[i] == ':') { |
||||
scheme_end = i; |
||||
break; |
||||
} |
||||
if (uri_text[i] >= 'a' && uri_text[i] <= 'z') continue; |
||||
if (uri_text[i] >= 'A' && uri_text[i] <= 'Z') continue; |
||||
if (i != scheme_begin) { |
||||
if (uri_text[i] >= '0' && uri_text[i] <= '9') continue; |
||||
if (uri_text[i] == '+') continue; |
||||
if (uri_text[i] == '-') continue; |
||||
if (uri_text[i] == '.') continue; |
||||
} |
||||
break; |
||||
} |
||||
if (scheme_end == -1) { |
||||
return bad_uri(uri_text, i, "scheme", suppress_errors); |
||||
} |
||||
|
||||
if (uri_text[scheme_end + 1] == '/' && uri_text[scheme_end + 2] == '/') { |
||||
authority_begin = scheme_end + 3; |
||||
for (i = authority_begin; uri_text[i] != 0; i++) { |
||||
if (uri_text[i] == '/') { |
||||
authority_end = i; |
||||
} |
||||
if (uri_text[i] == '?') { |
||||
return bad_uri(uri_text, i, "query_not_supported", suppress_errors); |
||||
} |
||||
if (uri_text[i] == '#') { |
||||
return bad_uri(uri_text, i, "fragment_not_supported", suppress_errors); |
||||
} |
||||
} |
||||
if (authority_end == -1 && uri_text[i] == 0) { |
||||
authority_end = i; |
||||
} |
||||
if (authority_end == -1) { |
||||
return bad_uri(uri_text, i, "authority", suppress_errors); |
||||
} |
||||
/* TODO(ctiller): parse the authority correctly */ |
||||
path_begin = authority_end; |
||||
} else { |
||||
path_begin = scheme_end + 1; |
||||
} |
||||
|
||||
for (i = path_begin; uri_text[i] != 0; i++) { |
||||
if (uri_text[i] == '?') { |
||||
return bad_uri(uri_text, i, "query_not_supported", suppress_errors); |
||||
} |
||||
if (uri_text[i] == '#') { |
||||
return bad_uri(uri_text, i, "fragment_not_supported", suppress_errors); |
||||
} |
||||
} |
||||
path_end = i; |
||||
|
||||
uri = gpr_malloc(sizeof(*uri)); |
||||
memset(uri, 0, sizeof(*uri)); |
||||
uri->scheme = copy_fragment(uri_text, scheme_begin, scheme_end); |
||||
uri->authority = copy_fragment(uri_text, authority_begin, authority_end); |
||||
uri->path = copy_fragment(uri_text, path_begin, path_end); |
||||
|
||||
return uri; |
||||
} |
||||
|
||||
void grpc_uri_destroy(grpc_uri *uri) { |
||||
if (!uri) return; |
||||
gpr_free(uri->scheme); |
||||
gpr_free(uri->authority); |
||||
gpr_free(uri->path); |
||||
gpr_free(uri); |
||||
} |
@ -0,0 +1,49 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPC_INTERNAL_CORE_CLIENT_CONFIG_URI_PARSER_H |
||||
#define GRPC_INTERNAL_CORE_CLIENT_CONFIG_URI_PARSER_H |
||||
|
||||
typedef struct { |
||||
char *scheme; |
||||
char *authority; |
||||
char *path; |
||||
} grpc_uri; |
||||
|
||||
/** parse a uri, return NULL on failure */ |
||||
grpc_uri *grpc_uri_parse(const char *uri_text, int suppress_errors); |
||||
|
||||
/** destroy a uri */ |
||||
void grpc_uri_destroy(grpc_uri *uri); |
||||
|
||||
#endif |
@ -1,89 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#include "src/core/surface/client.h" |
||||
|
||||
#include "src/core/surface/call.h" |
||||
#include "src/core/surface/channel.h" |
||||
#include "src/core/support/string.h" |
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/log.h> |
||||
|
||||
typedef struct { void *unused; } call_data; |
||||
|
||||
typedef struct { void *unused; } channel_data; |
||||
|
||||
static void client_start_transport_op(grpc_call_element *elem, |
||||
grpc_transport_op *op) { |
||||
GRPC_CALL_LOG_OP(GPR_INFO, elem, op); |
||||
grpc_call_next_op(elem, op); |
||||
} |
||||
|
||||
static void channel_op(grpc_channel_element *elem, |
||||
grpc_channel_element *from_elem, grpc_channel_op *op) { |
||||
switch (op->type) { |
||||
case GRPC_ACCEPT_CALL: |
||||
gpr_log(GPR_ERROR, "Client cannot accept new calls"); |
||||
break; |
||||
case GRPC_TRANSPORT_CLOSED: |
||||
grpc_client_channel_closed(elem); |
||||
break; |
||||
case GRPC_TRANSPORT_GOAWAY: |
||||
gpr_slice_unref(op->data.goaway.message); |
||||
break; |
||||
default: |
||||
GPR_ASSERT(op->dir == GRPC_CALL_DOWN); |
||||
grpc_channel_next_op(elem, op); |
||||
} |
||||
} |
||||
|
||||
static void init_call_elem(grpc_call_element *elem, |
||||
const void *transport_server_data, |
||||
grpc_transport_op *initial_op) {} |
||||
|
||||
static void destroy_call_elem(grpc_call_element *elem) {} |
||||
|
||||
static void init_channel_elem(grpc_channel_element *elem, |
||||
const grpc_channel_args *args, grpc_mdctx *mdctx, |
||||
int is_first, int is_last) { |
||||
GPR_ASSERT(is_first); |
||||
GPR_ASSERT(!is_last); |
||||
} |
||||
|
||||
static void destroy_channel_elem(grpc_channel_element *elem) {} |
||||
|
||||
const grpc_channel_filter grpc_client_surface_filter = { |
||||
client_start_transport_op, channel_op, sizeof(call_data), init_call_elem, |
||||
destroy_call_elem, sizeof(channel_data), init_channel_elem, |
||||
destroy_channel_elem, "client", |
||||
}; |
@ -0,0 +1,112 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#include "src/core/transport/connectivity_state.h" |
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/log.h> |
||||
|
||||
void grpc_connectivity_state_init(grpc_connectivity_state_tracker *tracker, |
||||
grpc_connectivity_state init_state) { |
||||
tracker->current_state = init_state; |
||||
tracker->watchers = NULL; |
||||
} |
||||
|
||||
void grpc_connectivity_state_destroy(grpc_connectivity_state_tracker *tracker) { |
||||
grpc_connectivity_state_watcher *w; |
||||
while ((w = tracker->watchers)) { |
||||
tracker->watchers = w->next; |
||||
|
||||
if (GRPC_CHANNEL_FATAL_FAILURE != *w->current) { |
||||
*w->current = GRPC_CHANNEL_FATAL_FAILURE; |
||||
grpc_iomgr_add_callback(w->notify); |
||||
} else { |
||||
grpc_iomgr_add_delayed_callback(w->notify, 0); |
||||
} |
||||
gpr_free(w); |
||||
} |
||||
} |
||||
|
||||
grpc_connectivity_state grpc_connectivity_state_check( |
||||
grpc_connectivity_state_tracker *tracker) { |
||||
return tracker->current_state; |
||||
} |
||||
|
||||
int grpc_connectivity_state_notify_on_state_change( |
||||
grpc_connectivity_state_tracker *tracker, grpc_connectivity_state *current, |
||||
grpc_iomgr_closure *notify) { |
||||
if (tracker->current_state != *current) { |
||||
*current = tracker->current_state; |
||||
grpc_iomgr_add_callback(notify); |
||||
} else { |
||||
grpc_connectivity_state_watcher *w = gpr_malloc(sizeof(*w)); |
||||
w->current = current; |
||||
w->notify = notify; |
||||
w->next = tracker->watchers; |
||||
tracker->watchers = w; |
||||
} |
||||
return tracker->current_state == GRPC_CHANNEL_IDLE; |
||||
} |
||||
|
||||
void grpc_connectivity_state_set_with_scheduler( |
||||
grpc_connectivity_state_tracker *tracker, grpc_connectivity_state state, |
||||
void (*scheduler)(void *arg, grpc_iomgr_closure *closure), void *arg) { |
||||
grpc_connectivity_state_watcher *new = NULL; |
||||
grpc_connectivity_state_watcher *w; |
||||
if (tracker->current_state == state) { |
||||
return; |
||||
} |
||||
tracker->current_state = state; |
||||
while ((w = tracker->watchers)) { |
||||
tracker->watchers = w->next; |
||||
|
||||
if (state != *w->current) { |
||||
*w->current = state; |
||||
scheduler(arg, w->notify); |
||||
gpr_free(w); |
||||
} else { |
||||
w->next = new; |
||||
new = w; |
||||
} |
||||
} |
||||
tracker->watchers = new; |
||||
} |
||||
|
||||
static void default_scheduler(void *ignored, grpc_iomgr_closure *closure) { |
||||
grpc_iomgr_add_callback(closure); |
||||
} |
||||
|
||||
void grpc_connectivity_state_set(grpc_connectivity_state_tracker *tracker, |
||||
grpc_connectivity_state state) { |
||||
grpc_connectivity_state_set_with_scheduler(tracker, state, default_scheduler, |
||||
NULL); |
||||
} |
@ -0,0 +1,74 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPC_INTERNAL_CORE_TRANSPORT_CONNECTIVITY_STATE_H |
||||
#define GRPC_INTERNAL_CORE_TRANSPORT_CONNECTIVITY_STATE_H |
||||
|
||||
#include <grpc/grpc.h> |
||||
#include "src/core/iomgr/iomgr.h" |
||||
|
||||
typedef struct grpc_connectivity_state_watcher { |
||||
/** we keep watchers in a linked list */ |
||||
struct grpc_connectivity_state_watcher *next; |
||||
/** closure to notify on change */ |
||||
grpc_iomgr_closure *notify; |
||||
/** the current state as believed by the watcher */ |
||||
grpc_connectivity_state *current; |
||||
} grpc_connectivity_state_watcher; |
||||
|
||||
typedef struct { |
||||
/** current connectivity state */ |
||||
grpc_connectivity_state current_state; |
||||
/** all our watchers */ |
||||
grpc_connectivity_state_watcher *watchers; |
||||
} grpc_connectivity_state_tracker; |
||||
|
||||
void grpc_connectivity_state_init(grpc_connectivity_state_tracker *tracker, |
||||
grpc_connectivity_state init_state); |
||||
void grpc_connectivity_state_destroy(grpc_connectivity_state_tracker *tracker); |
||||
|
||||
void grpc_connectivity_state_set(grpc_connectivity_state_tracker *tracker, |
||||
grpc_connectivity_state state); |
||||
void grpc_connectivity_state_set_with_scheduler( |
||||
grpc_connectivity_state_tracker *tracker, grpc_connectivity_state state, |
||||
void (*scheduler)(void *arg, grpc_iomgr_closure *closure), void *arg); |
||||
|
||||
grpc_connectivity_state grpc_connectivity_state_check( |
||||
grpc_connectivity_state_tracker *tracker); |
||||
|
||||
/** Return 1 if the channel should start connecting, 0 otherwise */ |
||||
int grpc_connectivity_state_notify_on_state_change( |
||||
grpc_connectivity_state_tracker *tracker, grpc_connectivity_state *current, |
||||
grpc_iomgr_closure *notify); |
||||
|
||||
#endif /* GRPC_INTERNAL_CORE_TRANSPORT_CONNECTIVITY_STATE_H */ |
@ -0,0 +1,69 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#include "src/core/client_config/uri_parser.h" |
||||
|
||||
#include <string.h> |
||||
|
||||
#include <grpc/support/log.h> |
||||
|
||||
#include "test/core/util/test_config.h" |
||||
|
||||
static void test_succeeds(const char *uri_text, const char *scheme, |
||||
const char *authority, const char *path) { |
||||
grpc_uri *uri = grpc_uri_parse(uri_text, 0); |
||||
GPR_ASSERT(uri); |
||||
GPR_ASSERT(0 == strcmp(scheme, uri->scheme)); |
||||
GPR_ASSERT(0 == strcmp(authority, uri->authority)); |
||||
GPR_ASSERT(0 == strcmp(path, uri->path)); |
||||
grpc_uri_destroy(uri); |
||||
} |
||||
|
||||
static void test_fails(const char *uri_text) { |
||||
GPR_ASSERT(NULL == grpc_uri_parse(uri_text, 0)); |
||||
} |
||||
|
||||
int main(int argc, char **argv) { |
||||
grpc_test_init(argc, argv); |
||||
test_succeeds("http://www.google.com", "http", "www.google.com", ""); |
||||
test_succeeds("dns:///foo", "dns", "", "/foo"); |
||||
test_succeeds("http://www.google.com:90", "http", "www.google.com:90", ""); |
||||
test_succeeds("a192.4-df:foo.coom", "a192.4-df", "", "foo.coom"); |
||||
test_succeeds("a+b:foo.coom", "a+b", "", "foo.coom"); |
||||
test_fails("xyz"); |
||||
test_fails("http://www.google.com?why-are-you-using-queries"); |
||||
test_fails("dns:foo.com#fragments-arent-supported-here"); |
||||
test_fails("http:?huh"); |
||||
test_fails("unix:#yeah-right"); |
||||
return 0; |
||||
} |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue