mirror of https://github.com/grpc/grpc.git
commit
da61668122
1628 changed files with 110545 additions and 32336 deletions
@ -1,289 +0,0 @@ |
||||
#gRPC Authentication support |
||||
|
||||
gRPC is designed to plug-in a number of authentication mechanisms. This document |
||||
provides a quick overview of the various auth mechanisms supported, discusses |
||||
the API with some examples, and concludes with a discussion of extensibility. |
||||
More documentation and examples are coming soon! |
||||
|
||||
## Supported auth mechanisms |
||||
|
||||
###SSL/TLS |
||||
gRPC has SSL/TLS integration and promotes the use of SSL/TLS to authenticate the |
||||
server, and encrypt all the data exchanged between the client and the server. |
||||
Optional mechanisms are available for clients to provide certificates to |
||||
accomplish mutual authentication. |
||||
|
||||
###OAuth 2.0 |
||||
gRPC provides a generic mechanism (described below) to attach metadata to |
||||
requests and responses. This mechanism can be used to attach OAuth 2.0 Access |
||||
Tokens to RPCs being made at a client. Additional support for acquiring Access |
||||
Tokens while accessing Google APIs through gRPC is provided for certain auth |
||||
flows, demonstrated through code examples below. |
||||
|
||||
## API |
||||
To reduce complexity and minimize API clutter, gRPC works with a unified concept |
||||
of a Credentials object. Users construct gRPC credentials using corresponding |
||||
bootstrap credentials (e.g., SSL client certs or Service Account Keys), and use |
||||
the credentials while creating a gRPC channel to any server. Depending on the |
||||
type of credential supplied, the channel uses the credentials during the initial |
||||
SSL/TLS handshake with the server, or uses the credential to generate and |
||||
attach Access Tokens to each request being made on the channel. |
||||
|
||||
###SSL/TLS for server authentication and encryption |
||||
This is the simplest authentication scenario, where a client just wants to |
||||
authenticate the server and encrypt all data. |
||||
|
||||
```cpp |
||||
SslCredentialsOptions ssl_opts; // Options to override SSL params, empty by default |
||||
// Create the credentials object by providing service account key in constructor |
||||
std::shared_ptr<ChannelCredentials> creds = SslCredentials(ssl_opts); |
||||
// Create a channel using the credentials created in the previous step |
||||
std::shared_ptr<Channel> channel = CreateChannel(server_name, creds); |
||||
// Create a stub on the channel |
||||
std::unique_ptr<Greeter::Stub> stub(Greeter::NewStub(channel)); |
||||
// Make actual RPC calls on the stub. |
||||
grpc::Status s = stub->sayHello(&context, *request, response); |
||||
``` |
||||
|
||||
For advanced use cases such as modifying the root CA or using client certs, |
||||
the corresponding options can be set in the SslCredentialsOptions parameter |
||||
passed to the factory method. |
||||
|
||||
|
||||
###Authenticating with Google |
||||
|
||||
gRPC applications can use a simple API to create a credential that works in various deployment scenarios. |
||||
|
||||
```cpp |
||||
std::shared_ptr<ChannelCredentials> creds = GoogleDefaultCredentials(); |
||||
// Create a channel, stub and make RPC calls (same as in the previous example) |
||||
std::shared_ptr<Channel> channel = CreateChannel(server_name, creds); |
||||
std::unique_ptr<Greeter::Stub> stub(Greeter::NewStub(channel)); |
||||
grpc::Status s = stub->sayHello(&context, *request, response); |
||||
``` |
||||
|
||||
This credential works for applications using Service Accounts as well as for |
||||
applications running in [Google Compute Engine (GCE)](https://cloud.google.com/compute/). In the former case, the |
||||
service account’s private keys are loaded from the file named in the environment |
||||
variable `GOOGLE_APPLICATION_CREDENTIALS`. The |
||||
keys are used to generate bearer tokens that are attached to each outgoing RPC |
||||
on the corresponding channel. |
||||
|
||||
For applications running in GCE, a default service account and corresponding |
||||
OAuth scopes can be configured during VM setup. At run-time, this credential |
||||
handles communication with the authentication systems to obtain OAuth2 access |
||||
tokens and attaches them to each outgoing RPC on the corresponding channel. |
||||
Extending gRPC to support other authentication mechanisms |
||||
The gRPC protocol is designed with a general mechanism for sending metadata |
||||
associated with RPC. Clients can send metadata at the beginning of an RPC and |
||||
servers can send back metadata at the beginning and end of the RPC. This |
||||
provides a natural mechanism to support OAuth2 and other authentication |
||||
mechanisms that need attach bearer tokens to individual request. |
||||
|
||||
In the simplest case, there is a single line of code required on the client |
||||
to add a specific token as metadata to an RPC and a corresponding access on |
||||
the server to retrieve this piece of metadata. The generation of the token |
||||
on the client side and its verification at the server can be done separately. |
||||
|
||||
A deeper integration can be achieved by plugging in a gRPC credentials implementation for any custom authentication mechanism that needs to attach per-request tokens. gRPC internals also allow switching out SSL/TLS with other encryption mechanisms. |
||||
|
||||
## Examples |
||||
|
||||
These authentication mechanisms will be available in all gRPC's supported languages. |
||||
The following sections demonstrate how authentication and authorization features described above appear in each language: more languages are coming soon. |
||||
|
||||
###SSL/TLS for server authentication and encryption (Ruby) |
||||
```ruby |
||||
# Base case - No encryption |
||||
stub = Helloworld::Greeter::Stub.new('localhost:50051') |
||||
... |
||||
|
||||
# With server authentication SSL/TLS |
||||
creds = GRPC::Core::Credentials.new(load_certs) # load_certs typically loads a CA roots file |
||||
stub = Helloworld::Greeter::Stub.new('localhost:50051', creds: creds) |
||||
``` |
||||
|
||||
###SSL/TLS for server authentication and encryption (C#) |
||||
```csharp |
||||
// Base case - No encryption |
||||
var channel = new Channel("localhost:50051"); |
||||
var client = new Greeter.GreeterClient(channel); |
||||
... |
||||
|
||||
// With server authentication SSL/TLS |
||||
var credentials = new SslCredentials(File.ReadAllText("ca.pem")); // Load a CA file |
||||
var channel = new Channel("localhost:50051", credentials); |
||||
var client = new Greeter.GreeterClient(channel); |
||||
``` |
||||
|
||||
###SSL/TLS for server authentication and encryption (Objective-C) |
||||
|
||||
The default for Objective-C is to use SSL/TLS, as that's the most common use case when accessing |
||||
remote APIs. |
||||
|
||||
```objective-c |
||||
// Base case - With server authentication SSL/TLS |
||||
HLWGreeter *client = [[HLWGreeter alloc] initWithHost:@"localhost:50051"]; |
||||
// Same as using @"https://localhost:50051". |
||||
... |
||||
|
||||
// No encryption |
||||
HLWGreeter *client = [[HLWGreeter alloc] initWithHost:@"http://localhost:50051"]; |
||||
// Specifying the HTTP scheme explicitly forces no encryption. |
||||
``` |
||||
|
||||
###SSL/TLS for server authentication and encryption (Python) |
||||
```python |
||||
# Base case - No encryption |
||||
stub = early_adopter_create_GreeterService_stub('localhost', 50051) |
||||
... |
||||
|
||||
# With server authentication SSL/TLS |
||||
stub = early_adopter_create_GreeterService_stub( |
||||
'localhost', 50051, secure=True, root_certificates=open('ca.pem').read()) |
||||
... |
||||
``` |
||||
n.b.: the beta API will look different |
||||
|
||||
###Authenticating with Google (Ruby) |
||||
```ruby |
||||
# Base case - No encryption/authorization |
||||
stub = Helloworld::Greeter::Stub.new('localhost:50051') |
||||
... |
||||
|
||||
# Authenticating with Google |
||||
require 'googleauth' # from http://www.rubydoc.info/gems/googleauth/0.1.0 |
||||
... |
||||
creds = GRPC::Core::Credentials.new(load_certs) # load_certs typically loads a CA roots file |
||||
scope = 'https://www.googleapis.com/auth/grpc-testing' |
||||
authorization = Google::Auth.get_application_default(scope) |
||||
stub = Helloworld::Greeter::Stub.new('localhost:50051', |
||||
creds: creds, |
||||
update_metadata: authorization.updater_proc) |
||||
``` |
||||
|
||||
###Authenticating with Google (Node.js) |
||||
|
||||
```node |
||||
// Base case - No encryption/authorization |
||||
var stub = new helloworld.Greeter('localhost:50051'); |
||||
... |
||||
// Authenticating with Google |
||||
var GoogleAuth = require('google-auth-library'); // from https://www.npmjs.com/package/google-auth-library |
||||
... |
||||
var creds = grpc.Credentials.createSsl(load_certs); // load_certs typically loads a CA roots file |
||||
var scope = 'https://www.googleapis.com/auth/grpc-testing'; |
||||
(new GoogleAuth()).getApplicationDefault(function(err, auth) { |
||||
if (auth.createScopeRequired()) { |
||||
auth = auth.createScoped(scope); |
||||
} |
||||
var stub = new helloworld.Greeter('localhost:50051', |
||||
{credentials: creds}, |
||||
grpc.getGoogleAuthDelegate(auth)); |
||||
}); |
||||
``` |
||||
|
||||
###Authenticating with Google (C#) |
||||
```csharp |
||||
// Base case - No encryption/authorization |
||||
var channel = new Channel("localhost:50051"); |
||||
var client = new Greeter.GreeterClient(channel); |
||||
... |
||||
|
||||
// Authenticating with Google |
||||
using Grpc.Auth; // from Grpc.Auth NuGet package |
||||
... |
||||
var credentials = new SslCredentials(File.ReadAllText("ca.pem")); // Load a CA file |
||||
var channel = new Channel("localhost:50051", credentials); |
||||
|
||||
string scope = "https://www.googleapis.com/auth/grpc-testing"; |
||||
var authorization = GoogleCredential.GetApplicationDefault(); |
||||
if (authorization.IsCreateScopedRequired) |
||||
{ |
||||
authorization = credential.CreateScoped(new[] { scope }); |
||||
} |
||||
var client = new Greeter.GreeterClient(channel, |
||||
new StubConfiguration(OAuth2InterceptorFactory.Create(credential))); |
||||
``` |
||||
|
||||
###Authenticating with Google (PHP) |
||||
```php |
||||
// Base case - No encryption/authorization |
||||
$client = new helloworld\GreeterClient( |
||||
new Grpc\BaseStub('localhost:50051', [])); |
||||
... |
||||
|
||||
// Authenticating with Google |
||||
// the environment variable "GOOGLE_APPLICATION_CREDENTIALS" needs to be set |
||||
$scope = "https://www.googleapis.com/auth/grpc-testing"; |
||||
$auth = Google\Auth\ApplicationDefaultCredentials::getCredentials($scope); |
||||
$opts = [ |
||||
'credentials' => Grpc\Credentials::createSsl(file_get_contents('ca.pem')); |
||||
'update_metadata' => $auth->getUpdateMetadataFunc(), |
||||
]; |
||||
|
||||
$client = new helloworld\GreeterClient( |
||||
new Grpc\BaseStub('localhost:50051', $opts)); |
||||
|
||||
``` |
||||
|
||||
###Authenticating with Google (Objective-C) |
||||
|
||||
This example uses the [Google iOS Sign-In library](https://developers.google.com/identity/sign-in/ios/), |
||||
but it's easily extrapolated to any other OAuth2 library. |
||||
|
||||
```objective-c |
||||
// Base case - No authentication |
||||
[client sayHelloWithRequest:request handler:^(HLWHelloReply *response, NSError *error) { |
||||
... |
||||
}]; |
||||
|
||||
... |
||||
|
||||
// Authenticating with Google |
||||
|
||||
// When signing the user in, ask her for the relevant scopes. |
||||
GIDSignIn.sharedInstance.scopes = @[@"https://www.googleapis.com/auth/grpc-testing"]; |
||||
|
||||
... |
||||
|
||||
#import <ProtoRPC/ProtoRPC.h> |
||||
|
||||
// Create a not-yet-started RPC. We want to set the request headers on this object before starting |
||||
// it. |
||||
ProtoRPC *call = |
||||
[client RPCToSayHelloWithRequest:request handler:^(HLWHelloReply *response, NSError *error) { |
||||
... |
||||
}]; |
||||
|
||||
// Set the access token to be used. |
||||
NSString *accessToken = GIDSignIn.sharedInstance.currentUser.authentication.accessToken; |
||||
call.requestMetadata[@"Authorization"] = [@"Bearer " stringByAppendingString:accessToken]}]; |
||||
|
||||
// Start the RPC. |
||||
[call start]; |
||||
``` |
||||
|
||||
You can see a working example app, with a more detailed explanation, [here](examples/objective-c/auth_sample). |
||||
|
||||
### Authenticating with Google (Python) |
||||
```python |
||||
# Base case - No encryption |
||||
stub = early_adopter_create_GreeterService_stub('localhost', 50051) |
||||
... |
||||
|
||||
# With server authentication SSL/TLS |
||||
import oauth2client.client |
||||
credentials = oauth2client.GoogleCredentials.get_application_default() |
||||
scope = 'https://www.googleapis.com/auth/grpc-testing' |
||||
scoped_credentials = credentials.create_scoped([scope]) |
||||
access_token = scoped_credentials.get_access_token().access_token |
||||
metadata_transformer = ( |
||||
lambda x: [('Authorization', 'Bearer {}'.format(access_token))]) |
||||
|
||||
stub = early_adopter_create_GreeterService_stub( |
||||
'localhost', 50051, secure=True, root_certificates=open('ca.pem').read(), |
||||
metadata_transformer=metadata_transformer) |
||||
... |
||||
``` |
||||
n.b.: the beta API will look different |
@ -0,0 +1,91 @@ |
||||
/*
|
||||
* |
||||
* 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_SUPPORT_AVL_H |
||||
#define GRPC_SUPPORT_AVL_H |
||||
|
||||
#include <grpc/support/sync.h> |
||||
|
||||
/** internal node of an AVL tree */ |
||||
typedef struct gpr_avl_node { |
||||
gpr_refcount refs; |
||||
void *key; |
||||
void *value; |
||||
struct gpr_avl_node *left; |
||||
struct gpr_avl_node *right; |
||||
long height; |
||||
} gpr_avl_node; |
||||
|
||||
typedef struct gpr_avl_vtable { |
||||
/** destroy a key */ |
||||
void (*destroy_key)(void *key); |
||||
/** copy a key, returning new value */ |
||||
void *(*copy_key)(void *key); |
||||
/** compare key1, key2; return <0 if key1 < key2,
|
||||
>0 if key1 > key2, 0 if key1 == key2 */ |
||||
long (*compare_keys)(void *key1, void *key2); |
||||
/** destroy a value */ |
||||
void (*destroy_value)(void *value); |
||||
/** copy a value */ |
||||
void *(*copy_value)(void *value); |
||||
} gpr_avl_vtable; |
||||
|
||||
/** "pointer" to an AVL tree - this is a reference
|
||||
counted object - use gpr_avl_ref to add a reference, |
||||
gpr_avl_unref when done with a reference */ |
||||
typedef struct gpr_avl { |
||||
const gpr_avl_vtable *vtable; |
||||
gpr_avl_node *root; |
||||
} gpr_avl; |
||||
|
||||
/** create an immutable AVL tree */ |
||||
gpr_avl gpr_avl_create(const gpr_avl_vtable *vtable); |
||||
/** add a reference to an existing tree - returns
|
||||
the tree as a convenience */ |
||||
gpr_avl gpr_avl_ref(gpr_avl avl); |
||||
/** remove a reference to a tree - destroying it if there
|
||||
are no references left */ |
||||
void gpr_avl_unref(gpr_avl avl); |
||||
/** return a new tree with (key, value) added to avl.
|
||||
implicitly unrefs avl to allow easy chaining. |
||||
if key exists in avl, the new tree's key entry updated |
||||
(i.e. a duplicate is not created) */ |
||||
gpr_avl gpr_avl_add(gpr_avl avl, void *key, void *value); |
||||
/** return a new tree with key deleted */ |
||||
gpr_avl gpr_avl_remove(gpr_avl avl, void *key); |
||||
/** lookup key, and return the associated value.
|
||||
does not mutate avl. |
||||
returns NULL if key is not found. */ |
||||
void *gpr_avl_get(gpr_avl avl, void *key); |
||||
|
||||
#endif |
@ -1,122 +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/noop_filter.h" |
||||
#include <grpc/support/log.h> |
||||
|
||||
typedef struct call_data { |
||||
int unused; /* C89 requires at least one struct element */ |
||||
} call_data; |
||||
|
||||
typedef struct channel_data { |
||||
int unused; /* C89 requires at least one struct element */ |
||||
} channel_data; |
||||
|
||||
/* used to silence 'variable not used' warnings */ |
||||
static void ignore_unused(void *ignored) {} |
||||
|
||||
static void noop_mutate_op(grpc_call_element *elem, |
||||
grpc_transport_stream_op *op) { |
||||
/* grab pointers to our data from the call element */ |
||||
call_data *calld = elem->call_data; |
||||
channel_data *channeld = elem->channel_data; |
||||
|
||||
ignore_unused(calld); |
||||
ignore_unused(channeld); |
||||
|
||||
/* do nothing */ |
||||
} |
||||
|
||||
/* Called either:
|
||||
- in response to an API call (or similar) from above, to send something |
||||
- a network event (or similar) from below, to receive something |
||||
op contains type and call direction information, in addition to the data |
||||
that is being sent or received. */ |
||||
static void noop_start_transport_stream_op(grpc_exec_ctx *exec_ctx, |
||||
grpc_call_element *elem, |
||||
grpc_transport_stream_op *op) { |
||||
noop_mutate_op(elem, op); |
||||
|
||||
/* pass control down the stack */ |
||||
grpc_call_next_op(exec_ctx, elem, op); |
||||
} |
||||
|
||||
/* Constructor for call_data */ |
||||
static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, |
||||
const void *server_transport_data, |
||||
grpc_transport_stream_op *initial_op) { |
||||
/* grab pointers to our data from the call element */ |
||||
call_data *calld = elem->call_data; |
||||
channel_data *channeld = elem->channel_data; |
||||
|
||||
/* initialize members */ |
||||
calld->unused = channeld->unused; |
||||
|
||||
if (initial_op) noop_mutate_op(elem, initial_op); |
||||
} |
||||
|
||||
/* Destructor for call_data */ |
||||
static void destroy_call_elem(grpc_exec_ctx *exec_ctx, |
||||
grpc_call_element *elem) {} |
||||
|
||||
/* Constructor for channel_data */ |
||||
static void init_channel_elem(grpc_exec_ctx *exec_ctx, |
||||
grpc_channel_element *elem, grpc_channel *master, |
||||
const grpc_channel_args *args, grpc_mdctx *mdctx, |
||||
int is_first, int is_last) { |
||||
/* grab pointers to our data from the channel element */ |
||||
channel_data *channeld = elem->channel_data; |
||||
|
||||
/* The first and the last filters tend to be implemented differently to
|
||||
handle the case that there's no 'next' filter to call on the up or down |
||||
path */ |
||||
GPR_ASSERT(!is_first); |
||||
GPR_ASSERT(!is_last); |
||||
|
||||
/* initialize members */ |
||||
channeld->unused = 0; |
||||
} |
||||
|
||||
/* Destructor for channel data */ |
||||
static void destroy_channel_elem(grpc_exec_ctx *exec_ctx, |
||||
grpc_channel_element *elem) { |
||||
/* grab pointers to our data from the channel element */ |
||||
channel_data *channeld = elem->channel_data; |
||||
|
||||
ignore_unused(channeld); |
||||
} |
||||
|
||||
const grpc_channel_filter grpc_no_op_filter = { |
||||
noop_start_transport_stream_op, grpc_channel_next_op, sizeof(call_data), |
||||
init_call_elem, destroy_call_elem, sizeof(channel_data), init_channel_elem, |
||||
destroy_channel_elem, grpc_call_next_get_peer, "no-op"}; |
@ -0,0 +1,259 @@ |
||||
/*
|
||||
* |
||||
* 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/subchannel_call_holder.h" |
||||
|
||||
#include <grpc/support/alloc.h> |
||||
|
||||
#include "src/core/profiling/timers.h" |
||||
|
||||
#define GET_CALL(holder) \ |
||||
((grpc_subchannel_call *)(gpr_atm_acq_load(&(holder)->subchannel_call))) |
||||
|
||||
#define CANCELLED_CALL ((grpc_subchannel_call *)1) |
||||
|
||||
static void subchannel_ready(grpc_exec_ctx *exec_ctx, void *holder, |
||||
int success); |
||||
static void retry_ops(grpc_exec_ctx *exec_ctx, void *retry_ops_args, |
||||
int success); |
||||
|
||||
static void add_waiting_locked(grpc_subchannel_call_holder *holder, |
||||
grpc_transport_stream_op *op); |
||||
static void fail_locked(grpc_exec_ctx *exec_ctx, |
||||
grpc_subchannel_call_holder *holder); |
||||
static void retry_waiting_locked(grpc_exec_ctx *exec_ctx, |
||||
grpc_subchannel_call_holder *holder); |
||||
|
||||
void grpc_subchannel_call_holder_init( |
||||
grpc_subchannel_call_holder *holder, |
||||
grpc_subchannel_call_holder_pick_subchannel pick_subchannel, |
||||
void *pick_subchannel_arg, grpc_call_stack *owning_call) { |
||||
gpr_atm_rel_store(&holder->subchannel_call, 0); |
||||
holder->pick_subchannel = pick_subchannel; |
||||
holder->pick_subchannel_arg = pick_subchannel_arg; |
||||
gpr_mu_init(&holder->mu); |
||||
holder->connected_subchannel = NULL; |
||||
holder->waiting_ops = NULL; |
||||
holder->waiting_ops_count = 0; |
||||
holder->waiting_ops_capacity = 0; |
||||
holder->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING; |
||||
holder->owning_call = owning_call; |
||||
} |
||||
|
||||
void grpc_subchannel_call_holder_destroy(grpc_exec_ctx *exec_ctx, |
||||
grpc_subchannel_call_holder *holder) { |
||||
grpc_subchannel_call *call = GET_CALL(holder); |
||||
if (call != NULL && call != CANCELLED_CALL) { |
||||
GRPC_SUBCHANNEL_CALL_UNREF(exec_ctx, call, "holder"); |
||||
} |
||||
GPR_ASSERT(holder->creation_phase == |
||||
GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING); |
||||
gpr_mu_destroy(&holder->mu); |
||||
GPR_ASSERT(holder->waiting_ops_count == 0); |
||||
gpr_free(holder->waiting_ops); |
||||
} |
||||
|
||||
void grpc_subchannel_call_holder_perform_op(grpc_exec_ctx *exec_ctx, |
||||
grpc_subchannel_call_holder *holder, |
||||
grpc_transport_stream_op *op) { |
||||
/* try to (atomically) get the call */ |
||||
grpc_subchannel_call *call = GET_CALL(holder); |
||||
GPR_TIMER_BEGIN("grpc_subchannel_call_holder_perform_op", 0); |
||||
if (call == CANCELLED_CALL) { |
||||
grpc_transport_stream_op_finish_with_failure(exec_ctx, op); |
||||
GPR_TIMER_END("grpc_subchannel_call_holder_perform_op", 0); |
||||
return; |
||||
} |
||||
if (call != NULL) { |
||||
grpc_subchannel_call_process_op(exec_ctx, call, op); |
||||
GPR_TIMER_END("grpc_subchannel_call_holder_perform_op", 0); |
||||
return; |
||||
} |
||||
/* we failed; lock and figure out what to do */ |
||||
gpr_mu_lock(&holder->mu); |
||||
retry: |
||||
/* need to recheck that another thread hasn't set the call */ |
||||
call = GET_CALL(holder); |
||||
if (call == CANCELLED_CALL) { |
||||
gpr_mu_unlock(&holder->mu); |
||||
grpc_transport_stream_op_finish_with_failure(exec_ctx, op); |
||||
GPR_TIMER_END("grpc_subchannel_call_holder_perform_op", 0); |
||||
return; |
||||
} |
||||
if (call != NULL) { |
||||
gpr_mu_unlock(&holder->mu); |
||||
grpc_subchannel_call_process_op(exec_ctx, call, op); |
||||
GPR_TIMER_END("grpc_subchannel_call_holder_perform_op", 0); |
||||
return; |
||||
} |
||||
/* if this is a cancellation, then we can raise our cancelled flag */ |
||||
if (op->cancel_with_status != GRPC_STATUS_OK) { |
||||
if (!gpr_atm_rel_cas(&holder->subchannel_call, 0, 1)) { |
||||
goto retry; |
||||
} else { |
||||
switch (holder->creation_phase) { |
||||
case GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING: |
||||
fail_locked(exec_ctx, holder); |
||||
break; |
||||
case GRPC_SUBCHANNEL_CALL_HOLDER_PICKING_SUBCHANNEL: |
||||
holder->pick_subchannel(exec_ctx, holder->pick_subchannel_arg, NULL, |
||||
&holder->connected_subchannel, NULL); |
||||
break; |
||||
} |
||||
gpr_mu_unlock(&holder->mu); |
||||
grpc_transport_stream_op_finish_with_failure(exec_ctx, op); |
||||
GPR_TIMER_END("grpc_subchannel_call_holder_perform_op", 0); |
||||
return; |
||||
} |
||||
} |
||||
/* if we don't have a subchannel, try to get one */ |
||||
if (holder->creation_phase == GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING && |
||||
holder->connected_subchannel == NULL && |
||||
op->send_initial_metadata != NULL) { |
||||
holder->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_PICKING_SUBCHANNEL; |
||||
grpc_closure_init(&holder->next_step, subchannel_ready, holder); |
||||
GRPC_CALL_STACK_REF(holder->owning_call, "pick_subchannel"); |
||||
if (holder->pick_subchannel( |
||||
exec_ctx, holder->pick_subchannel_arg, op->send_initial_metadata, |
||||
&holder->connected_subchannel, &holder->next_step)) { |
||||
holder->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING; |
||||
GRPC_CALL_STACK_UNREF(exec_ctx, holder->owning_call, "pick_subchannel"); |
||||
} |
||||
} |
||||
/* if we've got a subchannel, then let's ask it to create a call */ |
||||
if (holder->creation_phase == GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING && |
||||
holder->connected_subchannel != NULL) { |
||||
gpr_atm_rel_store( |
||||
&holder->subchannel_call, |
||||
(gpr_atm)(gpr_uintptr)grpc_connected_subchannel_create_call( |
||||
exec_ctx, holder->connected_subchannel, holder->pollset)); |
||||
retry_waiting_locked(exec_ctx, holder); |
||||
goto retry; |
||||
} |
||||
/* nothing to be done but wait */ |
||||
add_waiting_locked(holder, op); |
||||
gpr_mu_unlock(&holder->mu); |
||||
GPR_TIMER_END("grpc_subchannel_call_holder_perform_op", 0); |
||||
} |
||||
|
||||
static void subchannel_ready(grpc_exec_ctx *exec_ctx, void *arg, int success) { |
||||
grpc_subchannel_call_holder *holder = arg; |
||||
grpc_subchannel_call *call; |
||||
gpr_mu_lock(&holder->mu); |
||||
GPR_ASSERT(holder->creation_phase == |
||||
GRPC_SUBCHANNEL_CALL_HOLDER_PICKING_SUBCHANNEL); |
||||
call = GET_CALL(holder); |
||||
GPR_ASSERT(call == NULL || call == CANCELLED_CALL); |
||||
holder->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING; |
||||
if (holder->connected_subchannel == NULL) { |
||||
fail_locked(exec_ctx, holder); |
||||
} else { |
||||
gpr_atm_rel_store( |
||||
&holder->subchannel_call, |
||||
(gpr_atm)(gpr_uintptr)grpc_connected_subchannel_create_call( |
||||
exec_ctx, holder->connected_subchannel, holder->pollset)); |
||||
retry_waiting_locked(exec_ctx, holder); |
||||
} |
||||
gpr_mu_unlock(&holder->mu); |
||||
GRPC_CALL_STACK_UNREF(exec_ctx, holder->owning_call, "pick_subchannel"); |
||||
} |
||||
|
||||
typedef struct { |
||||
grpc_transport_stream_op *ops; |
||||
size_t nops; |
||||
grpc_subchannel_call *call; |
||||
} retry_ops_args; |
||||
|
||||
static void retry_waiting_locked(grpc_exec_ctx *exec_ctx, |
||||
grpc_subchannel_call_holder *holder) { |
||||
retry_ops_args *a = gpr_malloc(sizeof(*a)); |
||||
a->ops = holder->waiting_ops; |
||||
a->nops = holder->waiting_ops_count; |
||||
a->call = GET_CALL(holder); |
||||
if (a->call == CANCELLED_CALL) { |
||||
gpr_free(a); |
||||
fail_locked(exec_ctx, holder); |
||||
return; |
||||
} |
||||
holder->waiting_ops = NULL; |
||||
holder->waiting_ops_count = 0; |
||||
holder->waiting_ops_capacity = 0; |
||||
GRPC_SUBCHANNEL_CALL_REF(a->call, "retry_ops"); |
||||
grpc_exec_ctx_enqueue(exec_ctx, grpc_closure_create(retry_ops, a), 1); |
||||
} |
||||
|
||||
static void retry_ops(grpc_exec_ctx *exec_ctx, void *args, int success) { |
||||
retry_ops_args *a = args; |
||||
size_t i; |
||||
for (i = 0; i < a->nops; i++) { |
||||
grpc_subchannel_call_process_op(exec_ctx, a->call, &a->ops[i]); |
||||
} |
||||
GRPC_SUBCHANNEL_CALL_UNREF(exec_ctx, a->call, "retry_ops"); |
||||
gpr_free(a->ops); |
||||
gpr_free(a); |
||||
} |
||||
|
||||
static void add_waiting_locked(grpc_subchannel_call_holder *holder, |
||||
grpc_transport_stream_op *op) { |
||||
GPR_TIMER_BEGIN("add_waiting_locked", 0); |
||||
if (holder->waiting_ops_count == holder->waiting_ops_capacity) { |
||||
holder->waiting_ops_capacity = GPR_MAX(3, 2 * holder->waiting_ops_capacity); |
||||
holder->waiting_ops = |
||||
gpr_realloc(holder->waiting_ops, holder->waiting_ops_capacity * |
||||
sizeof(*holder->waiting_ops)); |
||||
} |
||||
holder->waiting_ops[holder->waiting_ops_count++] = *op; |
||||
GPR_TIMER_END("add_waiting_locked", 0); |
||||
} |
||||
|
||||
static void fail_locked(grpc_exec_ctx *exec_ctx, |
||||
grpc_subchannel_call_holder *holder) { |
||||
size_t i; |
||||
for (i = 0; i < holder->waiting_ops_count; i++) { |
||||
grpc_exec_ctx_enqueue(exec_ctx, holder->waiting_ops[i].on_complete, 0); |
||||
grpc_exec_ctx_enqueue(exec_ctx, holder->waiting_ops[i].recv_message_ready, |
||||
0); |
||||
} |
||||
holder->waiting_ops_count = 0; |
||||
} |
||||
|
||||
char *grpc_subchannel_call_holder_get_peer( |
||||
grpc_exec_ctx *exec_ctx, grpc_subchannel_call_holder *holder) { |
||||
grpc_subchannel_call *subchannel_call = GET_CALL(holder); |
||||
|
||||
if (subchannel_call) { |
||||
return grpc_subchannel_call_get_peer(exec_ctx, subchannel_call); |
||||
} else { |
||||
return NULL; |
||||
} |
||||
} |
@ -0,0 +1,98 @@ |
||||
/*
|
||||
* |
||||
* 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_SUBCHANNEL_CALL_HOLDER_H |
||||
#define GRPC_INTERNAL_CORE_CHANNEL_SUBCHANNEL_CALL_HOLDER_H |
||||
|
||||
#include "src/core/client_config/subchannel.h" |
||||
|
||||
/** Pick a subchannel for grpc_subchannel_call_holder;
|
||||
Return 1 if subchannel is available immediately (in which case on_ready |
||||
should not be called), or 0 otherwise (in which case on_ready should be |
||||
called when the subchannel is available) */ |
||||
typedef int (*grpc_subchannel_call_holder_pick_subchannel)( |
||||
grpc_exec_ctx *exec_ctx, void *arg, grpc_metadata_batch *initial_metadata, |
||||
grpc_connected_subchannel **connected_subchannel, grpc_closure *on_ready); |
||||
|
||||
typedef enum { |
||||
GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING, |
||||
GRPC_SUBCHANNEL_CALL_HOLDER_PICKING_SUBCHANNEL |
||||
} grpc_subchannel_call_holder_creation_phase; |
||||
|
||||
/** Wrapper for holding a pointer to grpc_subchannel_call, and the
|
||||
associated machinery to create such a pointer. |
||||
Handles queueing of stream ops until a call object is ready, waiting |
||||
for initial metadata before trying to create a call object, |
||||
and handling cancellation gracefully. |
||||
|
||||
Both the channel and uchannel filter use this as their call_data. */ |
||||
typedef struct grpc_subchannel_call_holder { |
||||
/** either 0 for no call, 1 for cancelled, or a pointer to a
|
||||
grpc_subchannel_call */ |
||||
gpr_atm subchannel_call; |
||||
/** Helper function to choose the subchannel on which to create
|
||||
the call object. Channel filter delegates to the load |
||||
balancing policy (once it's ready); uchannel returns |
||||
immediately */ |
||||
grpc_subchannel_call_holder_pick_subchannel pick_subchannel; |
||||
void *pick_subchannel_arg; |
||||
|
||||
gpr_mu mu; |
||||
|
||||
grpc_subchannel_call_holder_creation_phase creation_phase; |
||||
grpc_connected_subchannel *connected_subchannel; |
||||
grpc_pollset *pollset; |
||||
|
||||
grpc_transport_stream_op *waiting_ops; |
||||
size_t waiting_ops_count; |
||||
size_t waiting_ops_capacity; |
||||
|
||||
grpc_closure next_step; |
||||
|
||||
grpc_call_stack *owning_call; |
||||
} grpc_subchannel_call_holder; |
||||
|
||||
void grpc_subchannel_call_holder_init( |
||||
grpc_subchannel_call_holder *holder, |
||||
grpc_subchannel_call_holder_pick_subchannel pick_subchannel, |
||||
void *pick_subchannel_arg, grpc_call_stack *owning_call); |
||||
void grpc_subchannel_call_holder_destroy(grpc_exec_ctx *exec_ctx, |
||||
grpc_subchannel_call_holder *holder); |
||||
|
||||
void grpc_subchannel_call_holder_perform_op(grpc_exec_ctx *exec_ctx, |
||||
grpc_subchannel_call_holder *holder, |
||||
grpc_transport_stream_op *op); |
||||
char *grpc_subchannel_call_holder_get_peer(grpc_exec_ctx *exec_ctx, |
||||
grpc_subchannel_call_holder *holder); |
||||
|
||||
#endif |
@ -0,0 +1,53 @@ |
||||
/*
|
||||
* |
||||
* 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/initial_connect_string.h" |
||||
|
||||
#include <stddef.h> |
||||
|
||||
extern void grpc_set_default_initial_connect_string(struct sockaddr **addr, |
||||
size_t *addr_len, |
||||
gpr_slice *initial_str); |
||||
|
||||
static grpc_set_initial_connect_string_func g_set_initial_connect_string_func = |
||||
grpc_set_default_initial_connect_string; |
||||
|
||||
void grpc_test_set_initial_connect_string_function( |
||||
grpc_set_initial_connect_string_func func) { |
||||
g_set_initial_connect_string_func = func; |
||||
} |
||||
|
||||
void grpc_set_initial_connect_string(struct sockaddr **addr, size_t *addr_len, |
||||
gpr_slice *initial_str) { |
||||
g_set_initial_connect_string_func(addr, addr_len, initial_str); |
||||
} |
@ -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. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPC_INTERNAL_CORE_CLIENT_CONFIG_INITIAL_CONNECT_STRING_H |
||||
#define GRPC_INTERNAL_CORE_CLIENT_CONFIG_INITIAL_CONNECT_STRING_H |
||||
|
||||
#include <grpc/support/slice.h> |
||||
#include "src/core/iomgr/sockaddr.h" |
||||
|
||||
typedef void (*grpc_set_initial_connect_string_func)(struct sockaddr **addr, |
||||
size_t *addr_len, |
||||
gpr_slice *initial_str); |
||||
void grpc_test_set_initial_connect_string_function( |
||||
grpc_set_initial_connect_string_func func); |
||||
|
||||
/** Set a string to be sent once connected. Optionally reset addr. */ |
||||
void grpc_set_initial_connect_string(struct sockaddr **addr, size_t *addr_len, |
||||
gpr_slice *connect_string); |
||||
|
||||
#endif /* GRPC_INTERNAL_CORE_CLIENT_CONFIG_INITIAL_CONNECT_STRING_H */ |
File diff suppressed because it is too large
Load Diff
@ -1,86 +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/client_config/subchannel_factory_decorators/merge_channel_args.h" |
||||
#include <grpc/support/alloc.h> |
||||
#include "src/core/channel/channel_args.h" |
||||
|
||||
typedef struct { |
||||
grpc_subchannel_factory base; |
||||
gpr_refcount refs; |
||||
grpc_subchannel_factory *wrapped; |
||||
grpc_channel_args *merge_args; |
||||
} merge_args_factory; |
||||
|
||||
static void merge_args_factory_ref(grpc_subchannel_factory *scf) { |
||||
merge_args_factory *f = (merge_args_factory *)scf; |
||||
gpr_ref(&f->refs); |
||||
} |
||||
|
||||
static void merge_args_factory_unref(grpc_exec_ctx *exec_ctx, |
||||
grpc_subchannel_factory *scf) { |
||||
merge_args_factory *f = (merge_args_factory *)scf; |
||||
if (gpr_unref(&f->refs)) { |
||||
grpc_subchannel_factory_unref(exec_ctx, f->wrapped); |
||||
grpc_channel_args_destroy(f->merge_args); |
||||
gpr_free(f); |
||||
} |
||||
} |
||||
|
||||
static grpc_subchannel *merge_args_factory_create_subchannel( |
||||
grpc_exec_ctx *exec_ctx, grpc_subchannel_factory *scf, |
||||
grpc_subchannel_args *args) { |
||||
merge_args_factory *f = (merge_args_factory *)scf; |
||||
grpc_channel_args *final_args = |
||||
grpc_channel_args_merge(args->args, f->merge_args); |
||||
grpc_subchannel *s; |
||||
args->args = final_args; |
||||
s = grpc_subchannel_factory_create_subchannel(exec_ctx, f->wrapped, args); |
||||
grpc_channel_args_destroy(final_args); |
||||
return s; |
||||
} |
||||
|
||||
static const grpc_subchannel_factory_vtable merge_args_factory_vtable = { |
||||
merge_args_factory_ref, merge_args_factory_unref, |
||||
merge_args_factory_create_subchannel}; |
||||
|
||||
grpc_subchannel_factory *grpc_subchannel_factory_merge_channel_args( |
||||
grpc_subchannel_factory *input, const grpc_channel_args *args) { |
||||
merge_args_factory *f = gpr_malloc(sizeof(*f)); |
||||
f->base.vtable = &merge_args_factory_vtable; |
||||
gpr_ref_init(&f->refs, 1); |
||||
grpc_subchannel_factory_ref(input); |
||||
f->wrapped = input; |
||||
f->merge_args = grpc_channel_args_copy(args); |
||||
return &f->base; |
||||
} |
@ -0,0 +1,53 @@ |
||||
/*
|
||||
* |
||||
* 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_COMPRESSION_ALGORITHM_METADATA_H |
||||
#define GRPC_INTERNAL_CORE_COMPRESSION_ALGORITHM_METADATA_H |
||||
|
||||
#include <grpc/compression.h> |
||||
#include "src/core/transport/metadata.h" |
||||
|
||||
/** Return compression algorithm based metadata value */ |
||||
grpc_mdstr *grpc_compression_algorithm_mdstr( |
||||
grpc_compression_algorithm algorithm); |
||||
|
||||
/** Return compression algorithm based metadata element (grpc-encoding: xxx) */ |
||||
grpc_mdelem *grpc_compression_encoding_mdelem( |
||||
grpc_compression_algorithm algorithm); |
||||
|
||||
/** Find compression algorithm based on passed in mdstr - returns
|
||||
* GRPC_COMPRESS_ALGORITHM_COUNT on failure */ |
||||
grpc_compression_algorithm grpc_compression_algorithm_from_mdstr( |
||||
grpc_mdstr *str); |
||||
|
||||
#endif /* GRPC_INTERNAL_CORE_COMPRESSION_ALGORITHM_METADATA_H */ |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue