Merge branch 'master' into grpc_namespace_server_credentials

pull/18452/head
Karthik Ravi Shankar 6 years ago
commit 87d2d68c4f
  1. 31
      BUILD
  2. 1
      BUILD.gn
  3. 31
      gRPC-Core.podspec
  4. 6
      gRPC-ProtoRPC.podspec
  5. 7
      gRPC.podspec
  6. 2
      include/grpc/impl/codegen/port_platform.h
  7. 16
      src/compiler/objective_c_generator.cc
  8. 321
      src/core/ext/filters/client_channel/client_channel.cc
  9. 26
      src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc
  10. 13
      src/core/lib/gpr/time_posix.cc
  11. 7
      src/core/lib/iomgr/cfstream_handle.cc
  12. 5
      src/core/lib/security/credentials/jwt/jwt_verifier.cc
  13. 17
      src/core/lib/security/security_connector/ssl/ssl_security_connector.cc
  14. 26
      src/core/lib/transport/transport.h
  15. 27
      src/cpp/server/channelz/channelz_service.cc
  16. 90
      src/csharp/Grpc.Core/ChannelCredentials.cs
  17. 6
      src/csharp/Grpc.Core/Internal/ChannelCredentialsSafeHandle.cs
  18. 2
      src/csharp/Grpc.Core/Internal/NativeCallbackDispatcher.cs
  19. 6
      src/csharp/Grpc.Core/Internal/NativeMethods.Generated.cs
  20. 48
      src/csharp/Grpc.Core/VerifyPeerContext.cs
  21. 51
      src/csharp/Grpc.IntegrationTesting/SslCredentialsTest.cs
  22. 64
      src/csharp/ext/grpc_csharp_ext.c
  23. 3
      src/objective-c/GRPCClient/GRPCCall.m
  24. 30
      src/objective-c/tests/Podfile
  25. 11
      templates/gRPC-Core.podspec.template
  26. 6
      templates/gRPC-ProtoRPC.podspec.template
  27. 7
      templates/gRPC.podspec.template
  28. 2
      templates/src/csharp/Grpc.Core/Internal/native_methods.include
  29. 43
      test/core/security/security_connector_test.cc
  30. 26
      test/cpp/end2end/client_lb_end2end_test.cc
  31. 2
      tools/internal_ci/linux/grpc_bazel_on_foundry_base.sh
  32. 23
      tools/internal_ci/linux/grpc_bazel_rbe_incompatible_changes.sh

31
BUILD

@ -314,7 +314,6 @@ grpc_cc_library(
public_hdrs = GRPC_PUBLIC_HDRS + GRPC_SECURE_PUBLIC_HDRS,
standalone = True,
deps = [
"grpc_cfstream",
"grpc_common",
"grpc_lb_policy_grpclb_secure",
"grpc_lb_policy_xds_secure",
@ -371,7 +370,6 @@ grpc_cc_library(
"grpc++_codegen_base",
"grpc++_codegen_base_src",
"grpc++_codegen_proto",
"grpc_cfstream",
],
)
@ -734,12 +732,15 @@ grpc_cc_library(
"src/core/lib/http/parser.cc",
"src/core/lib/iomgr/buffer_list.cc",
"src/core/lib/iomgr/call_combiner.cc",
"src/core/lib/iomgr/cfstream_handle.cc",
"src/core/lib/iomgr/combiner.cc",
"src/core/lib/iomgr/endpoint.cc",
"src/core/lib/iomgr/endpoint_cfstream.cc",
"src/core/lib/iomgr/endpoint_pair_posix.cc",
"src/core/lib/iomgr/endpoint_pair_uv.cc",
"src/core/lib/iomgr/endpoint_pair_windows.cc",
"src/core/lib/iomgr/error.cc",
"src/core/lib/iomgr/error_cfstream.cc",
"src/core/lib/iomgr/ev_epoll1_linux.cc",
"src/core/lib/iomgr/ev_epollex_linux.cc",
"src/core/lib/iomgr/ev_poll_posix.cc",
@ -760,6 +761,7 @@ grpc_cc_library(
"src/core/lib/iomgr/iomgr_custom.cc",
"src/core/lib/iomgr/iomgr_internal.cc",
"src/core/lib/iomgr/iomgr_posix.cc",
"src/core/lib/iomgr/iomgr_posix_cfstream.cc",
"src/core/lib/iomgr/iomgr_windows.cc",
"src/core/lib/iomgr/is_epollexclusive_available.cc",
"src/core/lib/iomgr/load_file.cc",
@ -786,6 +788,7 @@ grpc_cc_library(
"src/core/lib/iomgr/socket_utils_windows.cc",
"src/core/lib/iomgr/socket_windows.cc",
"src/core/lib/iomgr/tcp_client.cc",
"src/core/lib/iomgr/tcp_client_cfstream.cc",
"src/core/lib/iomgr/tcp_client_custom.cc",
"src/core/lib/iomgr/tcp_client_posix.cc",
"src/core/lib/iomgr/tcp_client_windows.cc",
@ -885,12 +888,15 @@ grpc_cc_library(
"src/core/lib/iomgr/block_annotate.h",
"src/core/lib/iomgr/buffer_list.h",
"src/core/lib/iomgr/call_combiner.h",
"src/core/lib/iomgr/cfstream_handle.h",
"src/core/lib/iomgr/closure.h",
"src/core/lib/iomgr/combiner.h",
"src/core/lib/iomgr/dynamic_annotations.h",
"src/core/lib/iomgr/endpoint.h",
"src/core/lib/iomgr/endpoint_cfstream.h",
"src/core/lib/iomgr/endpoint_pair.h",
"src/core/lib/iomgr/error.h",
"src/core/lib/iomgr/error_cfstream.h",
"src/core/lib/iomgr/error_internal.h",
"src/core/lib/iomgr/ev_epoll1_linux.h",
"src/core/lib/iomgr/ev_epollex_linux.h",
@ -1045,27 +1051,6 @@ grpc_cc_library(
],
)
grpc_cc_library(
name = "grpc_cfstream",
srcs = [
"src/core/lib/iomgr/cfstream_handle.cc",
"src/core/lib/iomgr/endpoint_cfstream.cc",
"src/core/lib/iomgr/error_cfstream.cc",
"src/core/lib/iomgr/iomgr_posix_cfstream.cc",
"src/core/lib/iomgr/tcp_client_cfstream.cc",
],
hdrs = [
"src/core/lib/iomgr/cfstream_handle.h",
"src/core/lib/iomgr/endpoint_cfstream.h",
"src/core/lib/iomgr/error_cfstream.h",
],
use_cfstream = True,
deps = [
":gpr_base",
":grpc_base",
],
)
grpc_cc_library(
name = "grpc_client_channel",
srcs = [

@ -1076,6 +1076,7 @@ config("grpc_config") {
"include/grpcpp/impl/server_initializer_impl.h",
"include/grpcpp/impl/service_type.h",
"include/grpcpp/resource_quota.h",
"include/grpcpp/resource_quota_impl.h",
"include/grpcpp/security/auth_context.h",
"include/grpcpp/security/auth_metadata_processor.h",
"include/grpcpp/security/credentials.h",

@ -857,7 +857,15 @@ Pod::Spec.new do |s|
'src/core/ext/filters/http/client_authority_filter.cc',
'src/core/ext/filters/workarounds/workaround_cronet_compression_filter.cc',
'src/core/ext/filters/workarounds/workaround_utils.cc',
'src/core/plugin_registry/grpc_plugin_registry.cc'
'src/core/plugin_registry/grpc_plugin_registry.cc',
'src/core/lib/iomgr/cfstream_handle.cc',
'src/core/lib/iomgr/endpoint_cfstream.cc',
'src/core/lib/iomgr/error_cfstream.cc',
'src/core/lib/iomgr/iomgr_posix_cfstream.cc',
'src/core/lib/iomgr/tcp_client_cfstream.cc',
'src/core/lib/iomgr/cfstream_handle.h',
'src/core/lib/iomgr/endpoint_cfstream.h',
'src/core/lib/iomgr/error_cfstream.h'
ss.private_header_files = 'src/core/lib/gpr/alloc.h',
'src/core/lib/gpr/arena.h',
@ -1164,26 +1172,15 @@ Pod::Spec.new do |s|
'src/core/ext/filters/message_size/message_size_filter.h',
'src/core/ext/filters/http/client_authority_filter.h',
'src/core/ext/filters/workarounds/workaround_cronet_compression_filter.h',
'src/core/ext/filters/workarounds/workaround_utils.h'
'src/core/ext/filters/workarounds/workaround_utils.h',
'src/core/lib/iomgr/cfstream_handle.h',
'src/core/lib/iomgr/endpoint_cfstream.h',
'src/core/lib/iomgr/error_cfstream.h'
end
# CFStream is now default. Leaving this subspec only for compatibility purpose.
s.subspec 'CFStream-Implementation' do |ss|
ss.header_mappings_dir = '.'
ss.dependency "#{s.name}/Implementation", version
ss.pod_target_xcconfig = {
'GCC_PREPROCESSOR_DEFINITIONS' => 'GRPC_CFSTREAM=1'
}
ss.source_files = 'src/core/lib/iomgr/cfstream_handle.cc',
'src/core/lib/iomgr/endpoint_cfstream.cc',
'src/core/lib/iomgr/error_cfstream.cc',
'src/core/lib/iomgr/iomgr_posix_cfstream.cc',
'src/core/lib/iomgr/tcp_client_cfstream.cc',
'src/core/lib/iomgr/cfstream_handle.h',
'src/core/lib/iomgr/endpoint_cfstream.h',
'src/core/lib/iomgr/error_cfstream.h'
ss.private_header_files = 'src/core/lib/iomgr/cfstream_handle.h',
'src/core/lib/iomgr/endpoint_cfstream.h',
'src/core/lib/iomgr/error_cfstream.h'
end
s.subspec 'Cronet-Interface' do |ss|

@ -53,12 +53,10 @@ Pod::Spec.new do |s|
ss.source_files = "#{src_dir}/*.{h,m}"
end
# CFStream is now default. Leaving this subspec only for compatibility purpose.
s.subspec 'CFStream' do |ss|
ss.dependency 'gRPC/CFStream', version
ss.dependency "#{s.name}/Main", version
ss.pod_target_xcconfig = {
'GCC_PREPROCESSOR_DEFINITIONS' => 'GRPC_CFSTREAM=1'
}
end
s.pod_target_xcconfig = {

@ -64,14 +64,9 @@ Pod::Spec.new do |s|
ss.dependency 'gRPC-Core', version
end
# This subspec is mutually exclusive with the `Main` subspec
# CFStream is now default. Leaving this subspec only for compatibility purpose.
s.subspec 'CFStream' do |ss|
ss.dependency 'gRPC-Core/CFStream-Implementation', version
ss.dependency "#{s.name}/Main", version
ss.pod_target_xcconfig = {
'GCC_PREPROCESSOR_DEFINITIONS' => 'GRPC_CFSTREAM=1'
}
end
s.subspec 'GID' do |ss|

@ -193,6 +193,7 @@
#define GPR_PLATFORM_STRING "ios"
#define GPR_CPU_IPHONE 1
#define GPR_PTHREAD_TLS 1
#define GRPC_CFSTREAM 1
/* the c-ares resolver isnt safe to enable on iOS */
#define GRPC_ARES 0
#else /* TARGET_OS_IPHONE */
@ -235,7 +236,6 @@
#define GPR_POSIX_SYNC 1
#define GPR_POSIX_TIME 1
#define GPR_GETPID_IN_UNISTD_H 1
/* TODO(mxyan): Remove when CFStream becomes default */
#ifndef GRPC_CFSTREAM
#define GPR_SUPPORT_CHANNELS_FROM_FD 1
#endif

@ -70,6 +70,10 @@ static void PrintAllComments(const DescriptorType* desc, Printer* printer) {
}
printer->Print("\n");
}
printer->Print(" *\n");
printer->Print(
" * This method belongs to a set of APIs that have been deprecated. Using"
" the v2 API is recommended.\n");
printer->Print(" */\n");
}
@ -278,6 +282,13 @@ void PrintMethodImplementations(Printer* printer,
map< ::grpc::string, ::grpc::string> vars = {
{"service_class", ServiceClassName(service)}};
printer.Print(vars,
"/**\n"
" * The methods in this protocol belong to a set of old APIs "
"that have been deprecated. They do not\n"
" * recognize call options provided in the initializer. Using "
"the v2 protocol is recommended.\n"
" */\n");
printer.Print(vars, "@protocol $service_class$ <NSObject>\n\n");
for (int i = 0; i < service->method_count(); i++) {
PrintMethodDeclarations(&printer, service->method(i));
@ -329,10 +340,13 @@ void PrintMethodImplementations(Printer* printer,
"callOptions:(GRPCCallOptions "
"*_Nullable)callOptions"
" NS_DESIGNATED_INITIALIZER;\n");
printer.Print("- (instancetype)initWithHost:(NSString *)host;\n");
printer.Print(
"+ (instancetype)serviceWithHost:(NSString *)host "
"callOptions:(GRPCCallOptions *_Nullable)callOptions;\n");
printer.Print(
"// The following methods belong to a set of old APIs that have been "
"deprecated.\n");
printer.Print("- (instancetype)initWithHost:(NSString *)host;\n");
printer.Print("+ (instancetype)serviceWithHost:(NSString *)host;\n");
printer.Print("@end\n");

@ -51,6 +51,7 @@
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/gprpp/inlined_vector.h"
#include "src/core/lib/gprpp/manual_constructor.h"
#include "src/core/lib/gprpp/mutex_lock.h"
#include "src/core/lib/iomgr/combiner.h"
#include "src/core/lib/iomgr/iomgr.h"
#include "src/core/lib/iomgr/polling_entity.h"
@ -91,7 +92,55 @@ grpc_core::TraceFlag grpc_client_channel_routing_trace(
* CHANNEL-WIDE FUNCTIONS
*/
struct external_connectivity_watcher;
// Forward declaration.
typedef struct client_channel_channel_data channel_data;
namespace grpc_core {
namespace {
class ExternalConnectivityWatcher {
public:
class WatcherList {
public:
WatcherList() { gpr_mu_init(&mu_); }
~WatcherList() { gpr_mu_destroy(&mu_); }
int size() const;
ExternalConnectivityWatcher* Lookup(grpc_closure* on_complete) const;
void Add(ExternalConnectivityWatcher* watcher);
void Remove(const ExternalConnectivityWatcher* watcher);
private:
// head_ is guarded by a mutex, since the size() method needs to
// iterate over the list, and it's called from the C-core API
// function grpc_channel_num_external_connectivity_watchers(), which
// is synchronous and therefore cannot run in the combiner.
mutable gpr_mu mu_;
ExternalConnectivityWatcher* head_ = nullptr;
};
ExternalConnectivityWatcher(channel_data* chand, grpc_polling_entity pollent,
grpc_connectivity_state* state,
grpc_closure* on_complete,
grpc_closure* watcher_timer_init);
~ExternalConnectivityWatcher();
private:
static void OnWatchCompleteLocked(void* arg, grpc_error* error);
static void WatchConnectivityStateLocked(void* arg, grpc_error* ignored);
channel_data* chand_;
grpc_polling_entity pollent_;
grpc_connectivity_state* state_;
grpc_closure* on_complete_;
grpc_closure* watcher_timer_init_;
grpc_closure my_closure_;
ExternalConnectivityWatcher* next_ = nullptr;
};
} // namespace
} // namespace grpc_core
struct QueuedPick {
LoadBalancingPolicy::PickArgs pick;
@ -99,7 +148,7 @@ struct QueuedPick {
QueuedPick* next = nullptr;
};
typedef struct client_channel_channel_data {
struct client_channel_channel_data {
bool deadline_checking_enabled;
bool enable_retries;
size_t per_rpc_retry_buffer_size;
@ -139,11 +188,10 @@ typedef struct client_channel_channel_data {
grpc_connectivity_state_tracker state_tracker;
grpc_error* disconnect_error;
/* external_connectivity_watcher_list head is guarded by its own mutex, since
* counts need to be grabbed immediately without polling on a cq */
gpr_mu external_connectivity_watcher_list_mu;
struct external_connectivity_watcher* external_connectivity_watcher_list_head;
} channel_data;
grpc_core::ManualConstructor<
grpc_core::ExternalConnectivityWatcher::WatcherList>
external_connectivity_watcher_list;
};
// Forward declarations.
static void start_pick_locked(void* arg, grpc_error* ignored);
@ -191,6 +239,123 @@ static void set_connectivity_state_and_picker_locked(
namespace grpc_core {
namespace {
//
// ExternalConnectivityWatcher::WatcherList
//
int ExternalConnectivityWatcher::WatcherList::size() const {
MutexLock lock(&mu_);
int count = 0;
for (ExternalConnectivityWatcher* w = head_; w != nullptr; w = w->next_) {
++count;
}
return count;
}
ExternalConnectivityWatcher* ExternalConnectivityWatcher::WatcherList::Lookup(
grpc_closure* on_complete) const {
MutexLock lock(&mu_);
ExternalConnectivityWatcher* w = head_;
while (w != nullptr && w->on_complete_ != on_complete) {
w = w->next_;
}
return w;
}
void ExternalConnectivityWatcher::WatcherList::Add(
ExternalConnectivityWatcher* watcher) {
GPR_ASSERT(Lookup(watcher->on_complete_) == nullptr);
MutexLock lock(&mu_);
GPR_ASSERT(watcher->next_ == nullptr);
watcher->next_ = head_;
head_ = watcher;
}
void ExternalConnectivityWatcher::WatcherList::Remove(
const ExternalConnectivityWatcher* watcher) {
MutexLock lock(&mu_);
if (watcher == head_) {
head_ = watcher->next_;
return;
}
for (ExternalConnectivityWatcher* w = head_; w != nullptr; w = w->next_) {
if (w->next_ == watcher) {
w->next_ = w->next_->next_;
return;
}
}
GPR_UNREACHABLE_CODE(return );
}
//
// ExternalConnectivityWatcher
//
ExternalConnectivityWatcher::ExternalConnectivityWatcher(
channel_data* chand, grpc_polling_entity pollent,
grpc_connectivity_state* state, grpc_closure* on_complete,
grpc_closure* watcher_timer_init)
: chand_(chand),
pollent_(pollent),
state_(state),
on_complete_(on_complete),
watcher_timer_init_(watcher_timer_init) {
grpc_polling_entity_add_to_pollset_set(&pollent_, chand_->interested_parties);
GRPC_CHANNEL_STACK_REF(chand_->owning_stack, "ExternalConnectivityWatcher");
GRPC_CLOSURE_SCHED(
GRPC_CLOSURE_INIT(&my_closure_, WatchConnectivityStateLocked, this,
grpc_combiner_scheduler(chand_->combiner)),
GRPC_ERROR_NONE);
}
ExternalConnectivityWatcher::~ExternalConnectivityWatcher() {
grpc_polling_entity_del_from_pollset_set(&pollent_,
chand_->interested_parties);
GRPC_CHANNEL_STACK_UNREF(chand_->owning_stack, "ExternalConnectivityWatcher");
}
void ExternalConnectivityWatcher::OnWatchCompleteLocked(void* arg,
grpc_error* error) {
ExternalConnectivityWatcher* self =
static_cast<ExternalConnectivityWatcher*>(arg);
grpc_closure* on_complete = self->on_complete_;
self->chand_->external_connectivity_watcher_list->Remove(self);
Delete(self);
GRPC_CLOSURE_SCHED(on_complete, GRPC_ERROR_REF(error));
}
void ExternalConnectivityWatcher::WatchConnectivityStateLocked(
void* arg, grpc_error* ignored) {
ExternalConnectivityWatcher* self =
static_cast<ExternalConnectivityWatcher*>(arg);
if (self->state_ == nullptr) {
// Handle cancellation.
GPR_ASSERT(self->watcher_timer_init_ == nullptr);
ExternalConnectivityWatcher* found =
self->chand_->external_connectivity_watcher_list->Lookup(
self->on_complete_);
if (found != nullptr) {
grpc_connectivity_state_notify_on_state_change(
&found->chand_->state_tracker, nullptr, &found->my_closure_);
}
Delete(self);
return;
}
// New watcher.
self->chand_->external_connectivity_watcher_list->Add(self);
// This assumes that the closure is scheduled on the ExecCtx scheduler
// and that GRPC_CLOSURE_RUN would run the closure immediately.
GRPC_CLOSURE_RUN(self->watcher_timer_init_, GRPC_ERROR_NONE);
GRPC_CLOSURE_INIT(&self->my_closure_, OnWatchCompleteLocked, self,
grpc_combiner_scheduler(self->chand_->combiner));
grpc_connectivity_state_notify_on_state_change(
&self->chand_->state_tracker, self->state_, &self->my_closure_);
}
//
// ClientChannelControlHelper
//
class ClientChannelControlHelper
: public LoadBalancingPolicy::ChannelControlHelper {
public:
@ -402,12 +567,7 @@ static grpc_error* cc_init_channel_elem(grpc_channel_element* elem,
"client_channel");
chand->disconnect_error = GRPC_ERROR_NONE;
gpr_mu_init(&chand->info_mu);
gpr_mu_init(&chand->external_connectivity_watcher_list_mu);
gpr_mu_lock(&chand->external_connectivity_watcher_list_mu);
chand->external_connectivity_watcher_list_head = nullptr;
gpr_mu_unlock(&chand->external_connectivity_watcher_list_mu);
chand->external_connectivity_watcher_list.Init();
chand->owning_stack = args->channel_stack;
chand->deadline_checking_enabled =
grpc_deadline_checking_enabled(args->channel_args);
@ -515,7 +675,7 @@ static void cc_destroy_channel_elem(grpc_channel_element* elem) {
GRPC_ERROR_UNREF(chand->disconnect_error);
grpc_connectivity_state_destroy(&chand->state_tracker);
gpr_mu_destroy(&chand->info_mu);
gpr_mu_destroy(&chand->external_connectivity_watcher_list_mu);
chand->external_connectivity_watcher_list.Destroy();
}
/*************************************************************************
@ -2875,6 +3035,10 @@ const grpc_channel_filter grpc_client_channel_filter = {
"client-channel",
};
//
// functions exported to the rest of core
//
void grpc_client_channel_set_channelz_node(
grpc_channel_element* elem, grpc_core::channelz::ClientChannelNode* node) {
channel_data* chand = static_cast<channel_data*>(elem->channel_data);
@ -2914,120 +3078,10 @@ grpc_connectivity_state grpc_client_channel_check_connectivity_state(
return out;
}
typedef struct external_connectivity_watcher {
channel_data* chand;
grpc_polling_entity pollent;
grpc_closure* on_complete;
grpc_closure* watcher_timer_init;
grpc_connectivity_state* state;
grpc_closure my_closure;
struct external_connectivity_watcher* next;
} external_connectivity_watcher;
static external_connectivity_watcher* lookup_external_connectivity_watcher(
channel_data* chand, grpc_closure* on_complete) {
gpr_mu_lock(&chand->external_connectivity_watcher_list_mu);
external_connectivity_watcher* w =
chand->external_connectivity_watcher_list_head;
while (w != nullptr && w->on_complete != on_complete) {
w = w->next;
}
gpr_mu_unlock(&chand->external_connectivity_watcher_list_mu);
return w;
}
static void external_connectivity_watcher_list_append(
channel_data* chand, external_connectivity_watcher* w) {
GPR_ASSERT(!lookup_external_connectivity_watcher(chand, w->on_complete));
gpr_mu_lock(&w->chand->external_connectivity_watcher_list_mu);
GPR_ASSERT(!w->next);
w->next = chand->external_connectivity_watcher_list_head;
chand->external_connectivity_watcher_list_head = w;
gpr_mu_unlock(&w->chand->external_connectivity_watcher_list_mu);
}
static void external_connectivity_watcher_list_remove(
channel_data* chand, external_connectivity_watcher* to_remove) {
GPR_ASSERT(
lookup_external_connectivity_watcher(chand, to_remove->on_complete));
gpr_mu_lock(&chand->external_connectivity_watcher_list_mu);
if (to_remove == chand->external_connectivity_watcher_list_head) {
chand->external_connectivity_watcher_list_head = to_remove->next;
gpr_mu_unlock(&chand->external_connectivity_watcher_list_mu);
return;
}
external_connectivity_watcher* w =
chand->external_connectivity_watcher_list_head;
while (w != nullptr) {
if (w->next == to_remove) {
w->next = w->next->next;
gpr_mu_unlock(&chand->external_connectivity_watcher_list_mu);
return;
}
w = w->next;
}
GPR_UNREACHABLE_CODE(return );
}
int grpc_client_channel_num_external_connectivity_watchers(
grpc_channel_element* elem) {
channel_data* chand = static_cast<channel_data*>(elem->channel_data);
int count = 0;
gpr_mu_lock(&chand->external_connectivity_watcher_list_mu);
external_connectivity_watcher* w =
chand->external_connectivity_watcher_list_head;
while (w != nullptr) {
count++;
w = w->next;
}
gpr_mu_unlock(&chand->external_connectivity_watcher_list_mu);
return count;
}
static void on_external_watch_complete_locked(void* arg, grpc_error* error) {
external_connectivity_watcher* w =
static_cast<external_connectivity_watcher*>(arg);
grpc_closure* follow_up = w->on_complete;
grpc_polling_entity_del_from_pollset_set(&w->pollent,
w->chand->interested_parties);
GRPC_CHANNEL_STACK_UNREF(w->chand->owning_stack,
"external_connectivity_watcher");
external_connectivity_watcher_list_remove(w->chand, w);
gpr_free(w);
GRPC_CLOSURE_SCHED(follow_up, GRPC_ERROR_REF(error));
}
static void watch_connectivity_state_locked(void* arg,
grpc_error* error_ignored) {
external_connectivity_watcher* w =
static_cast<external_connectivity_watcher*>(arg);
external_connectivity_watcher* found = nullptr;
if (w->state != nullptr) {
external_connectivity_watcher_list_append(w->chand, w);
// An assumption is being made that the closure is scheduled on the exec ctx
// scheduler and that GRPC_CLOSURE_RUN would run the closure immediately.
GRPC_CLOSURE_RUN(w->watcher_timer_init, GRPC_ERROR_NONE);
GRPC_CLOSURE_INIT(&w->my_closure, on_external_watch_complete_locked, w,
grpc_combiner_scheduler(w->chand->combiner));
grpc_connectivity_state_notify_on_state_change(&w->chand->state_tracker,
w->state, &w->my_closure);
} else {
GPR_ASSERT(w->watcher_timer_init == nullptr);
found = lookup_external_connectivity_watcher(w->chand, w->on_complete);
if (found) {
GPR_ASSERT(found->on_complete == w->on_complete);
grpc_connectivity_state_notify_on_state_change(
&found->chand->state_tracker, nullptr, &found->my_closure);
}
grpc_polling_entity_del_from_pollset_set(&w->pollent,
w->chand->interested_parties);
GRPC_CHANNEL_STACK_UNREF(w->chand->owning_stack,
"external_connectivity_watcher");
gpr_free(w);
}
return chand->external_connectivity_watcher_list->size();
}
void grpc_client_channel_watch_connectivity_state(
@ -3035,21 +3089,8 @@ void grpc_client_channel_watch_connectivity_state(
grpc_connectivity_state* state, grpc_closure* closure,
grpc_closure* watcher_timer_init) {
channel_data* chand = static_cast<channel_data*>(elem->channel_data);
external_connectivity_watcher* w =
static_cast<external_connectivity_watcher*>(gpr_zalloc(sizeof(*w)));
w->chand = chand;
w->pollent = pollent;
w->on_complete = closure;
w->state = state;
w->watcher_timer_init = watcher_timer_init;
grpc_polling_entity_add_to_pollset_set(&w->pollent,
chand->interested_parties);
GRPC_CHANNEL_STACK_REF(w->chand->owning_stack,
"external_connectivity_watcher");
GRPC_CLOSURE_SCHED(
GRPC_CLOSURE_INIT(&w->my_closure, watch_connectivity_state_locked, w,
grpc_combiner_scheduler(chand->combiner)),
GRPC_ERROR_NONE);
grpc_core::New<grpc_core::ExternalConnectivityWatcher>(
chand, pollent, state, closure, watcher_timer_init);
}
grpc_core::RefCountedPtr<grpc_core::SubchannelCall>

@ -188,8 +188,14 @@ void PickFirst::ShutdownLocked() {
void PickFirst::ExitIdleLocked() {
if (idle_) {
idle_ = false;
if (subchannel_list_ != nullptr &&
subchannel_list_->num_subchannels() > 0) {
if (subchannel_list_ == nullptr ||
subchannel_list_->num_subchannels() == 0) {
grpc_error* error =
GRPC_ERROR_CREATE_FROM_STATIC_STRING("No addresses to connect to");
channel_control_helper()->UpdateState(
GRPC_CHANNEL_TRANSIENT_FAILURE, GRPC_ERROR_REF(error),
UniquePtr<SubchannelPicker>(New<TransientFailurePicker>(error)));
} else {
subchannel_list_->subchannel(0)
->CheckConnectivityStateAndStartWatchingLocked();
}
@ -253,13 +259,19 @@ void PickFirst::UpdateLocked(UpdateArgs args) {
grpc_channel_args_destroy(new_args);
if (subchannel_list->num_subchannels() == 0) {
// Empty update or no valid subchannels. Unsubscribe from all current
// subchannels and put the channel in TRANSIENT_FAILURE.
// subchannels.
subchannel_list_ = std::move(subchannel_list); // Empty list.
selected_ = nullptr;
grpc_error* error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Empty update");
channel_control_helper()->UpdateState(
GRPC_CHANNEL_TRANSIENT_FAILURE, GRPC_ERROR_REF(error),
UniquePtr<SubchannelPicker>(New<TransientFailurePicker>(error)));
// If not idle, put the channel in TRANSIENT_FAILURE.
// (If we are idle, then this will happen in ExitIdleLocked() if we
// haven't gotten a non-empty update by the time the application tries
// to start a new call.)
if (!idle_) {
grpc_error* error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Empty update");
channel_control_helper()->UpdateState(
GRPC_CHANNEL_TRANSIENT_FAILURE, GRPC_ERROR_REF(error),
UniquePtr<SubchannelPicker>(New<TransientFailurePicker>(error)));
}
return;
}
// If one of the subchannels in the new list is already in state

@ -108,6 +108,9 @@ static gpr_timespec now_impl(gpr_clock_type clock) {
now.clock_type = clock;
switch (clock) {
case GPR_CLOCK_REALTIME:
// gettimeofday(...) function may return with a value whose tv_usec is
// greater than 1e6 on iOS The case is resolved with the guard at end of
// this function.
gettimeofday(&now_tv, nullptr);
now.tv_sec = now_tv.tv_sec;
now.tv_nsec = now_tv.tv_usec * 1000;
@ -124,6 +127,16 @@ static gpr_timespec now_impl(gpr_clock_type clock) {
abort();
}
// Guard the tv_nsec field in valid range for all clock types
while (GPR_UNLIKELY(now.tv_nsec >= 1e9)) {
now.tv_sec++;
now.tv_nsec -= 1e9;
}
while (GPR_UNLIKELY(now.tv_nsec < 0)) {
now.tv_sec--;
now.tv_nsec += 1e9;
}
return now;
}
#endif

@ -192,4 +192,11 @@ void CFStreamHandle::Unref(const char* file, int line, const char* reason) {
}
}
#else
/* Creating a dummy function so that the grpc_cfstream library will be
* non-empty.
*/
void CFStreamDummy() {}
#endif

@ -624,9 +624,8 @@ static int verify_jwt_signature(EVP_PKEY* key, const char* alg,
gpr_log(GPR_ERROR, "EVP_DigestVerifyUpdate failed.");
goto end;
}
if (EVP_DigestVerifyFinal(
md_ctx, const_cast<uint8_t*>(GRPC_SLICE_START_PTR(signature)),
GRPC_SLICE_LENGTH(signature)) != 1) {
if (EVP_DigestVerifyFinal(md_ctx, GRPC_SLICE_START_PTR(signature),
GRPC_SLICE_LENGTH(signature)) != 1) {
gpr_log(GPR_ERROR, "JWT signature verification failed.");
goto end;
}

@ -44,24 +44,15 @@ namespace {
grpc_error* ssl_check_peer(
const char* peer_name, const tsi_peer* peer,
grpc_core::RefCountedPtr<grpc_auth_context>* auth_context) {
#if TSI_OPENSSL_ALPN_SUPPORT
/* Check the ALPN if ALPN is supported. */
const tsi_peer_property* p =
tsi_peer_get_property_by_name(peer, TSI_SSL_ALPN_SELECTED_PROTOCOL);
if (p == nullptr) {
return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Cannot check peer: missing selected ALPN property.");
}
if (!grpc_chttp2_is_alpn_version_supported(p->value.data, p->value.length)) {
return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Cannot check peer: invalid ALPN value.");
grpc_error* error = grpc_ssl_check_alpn(peer);
if (error != GRPC_ERROR_NONE) {
return error;
}
#endif /* TSI_OPENSSL_ALPN_SUPPORT */
/* Check the peer name if specified. */
if (peer_name != nullptr && !grpc_ssl_host_matches_name(peer, peer_name)) {
char* msg;
gpr_asprintf(&msg, "Peer name %s is not in peer certificate", peer_name);
grpc_error* error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
gpr_free(msg);
return error;
}

@ -273,40 +273,40 @@ struct grpc_transport_stream_op_batch_payload {
/** Transport op: a set of operations to perform on a transport as a whole */
typedef struct grpc_transport_op {
/** Called when processing of this op is done. */
grpc_closure* on_consumed;
grpc_closure* on_consumed = nullptr;
/** connectivity monitoring - set connectivity_state to NULL to unsubscribe */
grpc_closure* on_connectivity_state_change;
grpc_connectivity_state* connectivity_state;
grpc_closure* on_connectivity_state_change = nullptr;
grpc_connectivity_state* connectivity_state = nullptr;
/** should the transport be disconnected
* Error contract: the transport that gets this op must cause
* disconnect_with_error to be unref'ed after processing it */
grpc_error* disconnect_with_error;
grpc_error* disconnect_with_error = nullptr;
/** what should the goaway contain?
* Error contract: the transport that gets this op must cause
* goaway_error to be unref'ed after processing it */
grpc_error* goaway_error;
grpc_error* goaway_error = nullptr;
/** set the callback for accepting new streams;
this is a permanent callback, unlike the other one-shot closures.
If true, the callback is set to set_accept_stream_fn, with its
user_data argument set to set_accept_stream_user_data */
bool set_accept_stream;
bool set_accept_stream = false;
void (*set_accept_stream_fn)(void* user_data, grpc_transport* transport,
const void* server_data);
void* set_accept_stream_user_data;
const void* server_data) = nullptr;
void* set_accept_stream_user_data = nullptr;
/** add this transport to a pollset */
grpc_pollset* bind_pollset;
grpc_pollset* bind_pollset = nullptr;
/** add this transport to a pollset_set */
grpc_pollset_set* bind_pollset_set;
grpc_pollset_set* bind_pollset_set = nullptr;
/** send a ping, if either on_initiate or on_ack is not NULL */
struct {
/** Ping may be delayed by the transport, on_initiate callback will be
called when the ping is actually being sent. */
grpc_closure* on_initiate;
grpc_closure* on_initiate = nullptr;
/** Called when the ping ack is received */
grpc_closure* on_ack;
grpc_closure* on_ack = nullptr;
} send_ping;
// If true, will reset the channel's connection backoff.
bool reset_connect_backoff;
bool reset_connect_backoff = false;
/***************************************************************************
* remaining fields are initialized and used at the discretion of the

@ -24,6 +24,12 @@
#include <grpc/support/alloc.h>
namespace grpc {
grpc::protobuf::util::Status ParseJson(const char* json_str,
grpc::protobuf::Message* message) {
grpc::protobuf::json::JsonParseOptions options;
options.case_insensitive_enum_parsing = true;
return grpc::protobuf::json::JsonStringToMessage(json_str, message, options);
}
Status ChannelzService::GetTopChannels(
ServerContext* unused, const channelz::v1::GetTopChannelsRequest* request,
@ -33,8 +39,7 @@ Status ChannelzService::GetTopChannels(
return Status(StatusCode::INTERNAL,
"grpc_channelz_get_top_channels returned null");
}
grpc::protobuf::util::Status s =
grpc::protobuf::json::JsonStringToMessage(json_str, response);
grpc::protobuf::util::Status s = ParseJson(json_str, response);
gpr_free(json_str);
if (!s.ok()) {
return Status(StatusCode::INTERNAL, s.ToString());
@ -50,8 +55,7 @@ Status ChannelzService::GetServers(
return Status(StatusCode::INTERNAL,
"grpc_channelz_get_servers returned null");
}
grpc::protobuf::util::Status s =
grpc::protobuf::json::JsonStringToMessage(json_str, response);
grpc::protobuf::util::Status s = ParseJson(json_str, response);
gpr_free(json_str);
if (!s.ok()) {
return Status(StatusCode::INTERNAL, s.ToString());
@ -67,8 +71,7 @@ Status ChannelzService::GetServer(ServerContext* unused,
return Status(StatusCode::INTERNAL,
"grpc_channelz_get_server returned null");
}
grpc::protobuf::util::Status s =
grpc::protobuf::json::JsonStringToMessage(json_str, response);
grpc::protobuf::util::Status s = ParseJson(json_str, response);
gpr_free(json_str);
if (!s.ok()) {
return Status(StatusCode::INTERNAL, s.ToString());
@ -85,8 +88,7 @@ Status ChannelzService::GetServerSockets(
return Status(StatusCode::INTERNAL,
"grpc_channelz_get_server_sockets returned null");
}
grpc::protobuf::util::Status s =
grpc::protobuf::json::JsonStringToMessage(json_str, response);
grpc::protobuf::util::Status s = ParseJson(json_str, response);
gpr_free(json_str);
if (!s.ok()) {
return Status(StatusCode::INTERNAL, s.ToString());
@ -101,8 +103,7 @@ Status ChannelzService::GetChannel(
if (json_str == nullptr) {
return Status(StatusCode::NOT_FOUND, "No object found for that ChannelId");
}
grpc::protobuf::util::Status s =
grpc::protobuf::json::JsonStringToMessage(json_str, response);
grpc::protobuf::util::Status s = ParseJson(json_str, response);
gpr_free(json_str);
if (!s.ok()) {
return Status(StatusCode::INTERNAL, s.ToString());
@ -118,8 +119,7 @@ Status ChannelzService::GetSubchannel(
return Status(StatusCode::NOT_FOUND,
"No object found for that SubchannelId");
}
grpc::protobuf::util::Status s =
grpc::protobuf::json::JsonStringToMessage(json_str, response);
grpc::protobuf::util::Status s = ParseJson(json_str, response);
gpr_free(json_str);
if (!s.ok()) {
return Status(StatusCode::INTERNAL, s.ToString());
@ -134,8 +134,7 @@ Status ChannelzService::GetSocket(ServerContext* unused,
if (json_str == nullptr) {
return Status(StatusCode::NOT_FOUND, "No object found for that SocketId");
}
grpc::protobuf::util::Status s =
grpc::protobuf::json::JsonStringToMessage(json_str, response);
grpc::protobuf::util::Status s = ParseJson(json_str, response);
gpr_free(json_str);
if (!s.ok()) {
return Status(StatusCode::INTERNAL, s.ToString());

@ -18,9 +18,11 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using Grpc.Core.Internal;
using Grpc.Core.Logging;
using Grpc.Core.Utils;
namespace Grpc.Core
@ -104,20 +106,38 @@ namespace Grpc.Core
}
}
/// <summary>
/// Callback invoked with the expected targetHost and the peer's certificate.
/// If false is returned by this callback then it is treated as a
/// verification failure and the attempted connection will fail.
/// Invocation of the callback is blocking, so any
/// implementation should be light-weight.
/// Note that the callback can potentially be invoked multiple times,
/// concurrently from different threads (e.g. when multiple connections
/// are being created for the same credentials).
/// </summary>
/// <param name="context">The <see cref="T:Grpc.Core.VerifyPeerContext"/> associated with the callback</param>
/// <returns>true if verification succeeded, false otherwise.</returns>
/// Note: experimental API that can change or be removed without any prior notice.
public delegate bool VerifyPeerCallback(VerifyPeerContext context);
/// <summary>
/// Client-side SSL credentials.
/// </summary>
public sealed class SslCredentials : ChannelCredentials
{
static readonly ILogger Logger = GrpcEnvironment.Logger.ForType<SslCredentials>();
readonly string rootCertificates;
readonly KeyCertificatePair keyCertificatePair;
readonly VerifyPeerCallback verifyPeerCallback;
/// <summary>
/// Creates client-side SSL credentials loaded from
/// disk file pointed to by the GRPC_DEFAULT_SSL_ROOTS_FILE_PATH environment variable.
/// If that fails, gets the roots certificates from a well known place on disk.
/// </summary>
public SslCredentials() : this(null, null)
public SslCredentials() : this(null, null, null)
{
}
@ -125,19 +145,32 @@ namespace Grpc.Core
/// Creates client-side SSL credentials from
/// a string containing PEM encoded root certificates.
/// </summary>
public SslCredentials(string rootCertificates) : this(rootCertificates, null)
public SslCredentials(string rootCertificates) : this(rootCertificates, null, null)
{
}
/// <summary>
/// Creates client-side SSL credentials.
/// </summary>
/// <param name="rootCertificates">string containing PEM encoded server root certificates.</param>
/// <param name="keyCertificatePair">a key certificate pair.</param>
public SslCredentials(string rootCertificates, KeyCertificatePair keyCertificatePair) :
this(rootCertificates, keyCertificatePair, null)
{
}
/// <summary>
/// Creates client-side SSL credentials.
/// </summary>
/// <param name="rootCertificates">string containing PEM encoded server root certificates.</param>
/// <param name="keyCertificatePair">a key certificate pair.</param>
public SslCredentials(string rootCertificates, KeyCertificatePair keyCertificatePair)
/// <param name="verifyPeerCallback">a callback to verify peer's target name and certificate.</param>
/// Note: experimental API that can change or be removed without any prior notice.
public SslCredentials(string rootCertificates, KeyCertificatePair keyCertificatePair, VerifyPeerCallback verifyPeerCallback)
{
this.rootCertificates = rootCertificates;
this.keyCertificatePair = keyCertificatePair;
this.verifyPeerCallback = verifyPeerCallback;
}
/// <summary>
@ -171,7 +204,54 @@ namespace Grpc.Core
internal override ChannelCredentialsSafeHandle CreateNativeCredentials()
{
return ChannelCredentialsSafeHandle.CreateSslCredentials(rootCertificates, keyCertificatePair);
IntPtr verifyPeerCallbackTag = IntPtr.Zero;
if (verifyPeerCallback != null)
{
verifyPeerCallbackTag = new VerifyPeerCallbackRegistration(verifyPeerCallback).CallbackRegistration.Tag;
}
return ChannelCredentialsSafeHandle.CreateSslCredentials(rootCertificates, keyCertificatePair, verifyPeerCallbackTag);
}
private class VerifyPeerCallbackRegistration
{
readonly VerifyPeerCallback verifyPeerCallback;
readonly NativeCallbackRegistration callbackRegistration;
public VerifyPeerCallbackRegistration(VerifyPeerCallback verifyPeerCallback)
{
this.verifyPeerCallback = verifyPeerCallback;
this.callbackRegistration = NativeCallbackDispatcher.RegisterCallback(HandleUniversalCallback);
}
public NativeCallbackRegistration CallbackRegistration => callbackRegistration;
private int HandleUniversalCallback(IntPtr arg0, IntPtr arg1, IntPtr arg2, IntPtr arg3, IntPtr arg4, IntPtr arg5)
{
return VerifyPeerCallbackHandler(arg0, arg1, arg2 != IntPtr.Zero);
}
private int VerifyPeerCallbackHandler(IntPtr targetName, IntPtr peerPem, bool isDestroy)
{
if (isDestroy)
{
this.callbackRegistration.Dispose();
return 0;
}
try
{
var context = new VerifyPeerContext(Marshal.PtrToStringAnsi(targetName), Marshal.PtrToStringAnsi(peerPem));
return this.verifyPeerCallback(context) ? 0 : 1;
}
catch (Exception e)
{
// eat the exception, we must not throw when inside callback from native code.
Logger.Error(e, "Exception occurred while invoking verify peer callback handler.");
// Return validation failure in case of exception.
return 1;
}
}
}
}

@ -38,15 +38,15 @@ namespace Grpc.Core.Internal
return creds;
}
public static ChannelCredentialsSafeHandle CreateSslCredentials(string pemRootCerts, KeyCertificatePair keyCertPair)
public static ChannelCredentialsSafeHandle CreateSslCredentials(string pemRootCerts, KeyCertificatePair keyCertPair, IntPtr verifyPeerCallbackTag)
{
if (keyCertPair != null)
{
return Native.grpcsharp_ssl_credentials_create(pemRootCerts, keyCertPair.CertificateChain, keyCertPair.PrivateKey);
return Native.grpcsharp_ssl_credentials_create(pemRootCerts, keyCertPair.CertificateChain, keyCertPair.PrivateKey, verifyPeerCallbackTag);
}
else
{
return Native.grpcsharp_ssl_credentials_create(pemRootCerts, null, null);
return Native.grpcsharp_ssl_credentials_create(pemRootCerts, null, null, verifyPeerCallbackTag);
}
}

@ -63,7 +63,7 @@ namespace Grpc.Core.Internal
catch (Exception e)
{
// eat the exception, we must not throw when inside callback from native code.
Logger.Error(e, "Caught exception inside callback from native callback.");
Logger.Error(e, "Caught exception inside callback from native code.");
return 0;
}
}

@ -482,7 +482,7 @@ namespace Grpc.Core.Internal
public delegate void grpcsharp_channel_args_set_integer_delegate(ChannelArgsSafeHandle args, UIntPtr index, string key, int value);
public delegate void grpcsharp_channel_args_destroy_delegate(IntPtr args);
public delegate void grpcsharp_override_default_ssl_roots_delegate(string pemRootCerts);
public delegate ChannelCredentialsSafeHandle grpcsharp_ssl_credentials_create_delegate(string pemRootCerts, string keyCertPairCertChain, string keyCertPairPrivateKey);
public delegate ChannelCredentialsSafeHandle grpcsharp_ssl_credentials_create_delegate(string pemRootCerts, string keyCertPairCertChain, string keyCertPairPrivateKey, IntPtr verifyPeerCallbackTag);
public delegate ChannelCredentialsSafeHandle grpcsharp_composite_channel_credentials_create_delegate(ChannelCredentialsSafeHandle channelCreds, CallCredentialsSafeHandle callCreds);
public delegate void grpcsharp_channel_credentials_release_delegate(IntPtr credentials);
public delegate ChannelSafeHandle grpcsharp_insecure_channel_create_delegate(string target, ChannelArgsSafeHandle channelArgs);
@ -676,7 +676,7 @@ namespace Grpc.Core.Internal
public static extern void grpcsharp_override_default_ssl_roots(string pemRootCerts);
[DllImport(ImportName)]
public static extern ChannelCredentialsSafeHandle grpcsharp_ssl_credentials_create(string pemRootCerts, string keyCertPairCertChain, string keyCertPairPrivateKey);
public static extern ChannelCredentialsSafeHandle grpcsharp_ssl_credentials_create(string pemRootCerts, string keyCertPairCertChain, string keyCertPairPrivateKey, IntPtr verifyPeerCallbackTag);
[DllImport(ImportName)]
public static extern ChannelCredentialsSafeHandle grpcsharp_composite_channel_credentials_create(ChannelCredentialsSafeHandle channelCreds, CallCredentialsSafeHandle callCreds);
@ -972,7 +972,7 @@ namespace Grpc.Core.Internal
public static extern void grpcsharp_override_default_ssl_roots(string pemRootCerts);
[DllImport(ImportName)]
public static extern ChannelCredentialsSafeHandle grpcsharp_ssl_credentials_create(string pemRootCerts, string keyCertPairCertChain, string keyCertPairPrivateKey);
public static extern ChannelCredentialsSafeHandle grpcsharp_ssl_credentials_create(string pemRootCerts, string keyCertPairCertChain, string keyCertPairPrivateKey, IntPtr verifyPeerCallbackTag);
[DllImport(ImportName)]
public static extern ChannelCredentialsSafeHandle grpcsharp_composite_channel_credentials_create(ChannelCredentialsSafeHandle channelCreds, CallCredentialsSafeHandle callCreds);

@ -0,0 +1,48 @@
#region Copyright notice and license
// Copyright 2019 The gRPC Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#endregion
namespace Grpc.Core
{
/// <summary>
/// Verification context for VerifyPeerCallback.
/// Note: experimental API that can change or be removed without any prior notice.
/// </summary>
public class VerifyPeerContext
{
/// <summary>
/// Initializes a new instance of the <see cref="T:Grpc.Core.VerifyPeerContext"/> class.
/// </summary>
/// <param name="targetName">The target name of the peer.</param>
/// <param name="peerPem">The PEM encoded certificate of the peer.</param>
internal VerifyPeerContext(string targetName, string peerPem)
{
this.TargetName = targetName;
this.PeerPem = peerPem;
}
/// <summary>
/// The target name of the peer.
/// </summary>
public string TargetName { get; }
/// <summary>
/// The PEM encoded certificate of the peer.
/// </summary>
public string PeerPem { get; }
}
}

@ -46,7 +46,8 @@ namespace Grpc.IntegrationTesting
KeyCertificatePair keyCertPair;
public void InitClientAndServer(bool clientAddKeyCertPair,
SslClientCertificateRequestType clientCertRequestType)
SslClientCertificateRequestType clientCertRequestType,
VerifyPeerCallback verifyPeerCallback = null)
{
rootCert = File.ReadAllText(TestCredentials.ClientCertAuthorityPath);
keyCertPair = new KeyCertificatePair(
@ -54,7 +55,7 @@ namespace Grpc.IntegrationTesting
File.ReadAllText(TestCredentials.ServerPrivateKeyPath));
var serverCredentials = new SslServerCredentials(new[] { keyCertPair }, rootCert, clientCertRequestType);
var clientCredentials = clientAddKeyCertPair ? new SslCredentials(rootCert, keyCertPair) : new SslCredentials(rootCert);
var clientCredentials = new SslCredentials(rootCert, clientAddKeyCertPair ? keyCertPair : null, verifyPeerCallback);
// Disable SO_REUSEPORT to prevent https://github.com/grpc/grpc/issues/10755
server = new Server(new[] { new ChannelOption(ChannelOptions.SoReuseport, 0) })
@ -188,6 +189,52 @@ namespace Grpc.IntegrationTesting
Assert.Throws(typeof(ArgumentNullException), () => new SslServerCredentials(keyCertPairs, null, SslClientCertificateRequestType.RequestAndRequireAndVerify));
}
[Test]
public async Task VerifyPeerCallback_Accepted()
{
string targetNameFromCallback = null;
string peerPemFromCallback = null;
InitClientAndServer(
clientAddKeyCertPair: false,
clientCertRequestType: SslClientCertificateRequestType.DontRequest,
verifyPeerCallback: (ctx) =>
{
targetNameFromCallback = ctx.TargetName;
peerPemFromCallback = ctx.PeerPem;
return true;
});
await CheckAccepted(expectPeerAuthenticated: false);
Assert.AreEqual(TestCredentials.DefaultHostOverride, targetNameFromCallback);
var expectedServerPem = File.ReadAllText(TestCredentials.ServerCertChainPath).Replace("\r", "");
Assert.AreEqual(expectedServerPem, peerPemFromCallback);
}
[Test]
public void VerifyPeerCallback_CallbackThrows_Rejected()
{
InitClientAndServer(
clientAddKeyCertPair: false,
clientCertRequestType: SslClientCertificateRequestType.DontRequest,
verifyPeerCallback: (ctx) =>
{
throw new Exception("VerifyPeerCallback has thrown on purpose.");
});
CheckRejected();
}
[Test]
public void VerifyPeerCallback_Rejected()
{
InitClientAndServer(
clientAddKeyCertPair: false,
clientCertRequestType: SslClientCertificateRequestType.DontRequest,
verifyPeerCallback: (ctx) =>
{
return false;
});
CheckRejected();
}
private async Task CheckAccepted(bool expectPeerAuthenticated)
{
var call = client.UnaryCallAsync(new SimpleRequest { ResponseSize = 10 });

@ -901,6 +901,21 @@ grpcsharp_server_request_call(grpc_server* server, grpc_completion_queue* cq,
&(ctx->request_metadata), cq, cq, ctx);
}
/* Native callback dispatcher */
typedef int(GPR_CALLTYPE* grpcsharp_native_callback_dispatcher_func)(
void* tag, void* arg0, void* arg1, void* arg2, void* arg3, void* arg4,
void* arg5);
static grpcsharp_native_callback_dispatcher_func native_callback_dispatcher =
NULL;
GPR_EXPORT void GPR_CALLTYPE grpcsharp_native_callback_dispatcher_init(
grpcsharp_native_callback_dispatcher_func func) {
GPR_ASSERT(func);
native_callback_dispatcher = func;
}
/* Security */
static char* default_pem_root_certs = NULL;
@ -927,21 +942,47 @@ grpcsharp_override_default_ssl_roots(const char* pem_root_certs) {
grpc_set_ssl_roots_override_callback(override_ssl_roots_handler);
}
static void grpcsharp_verify_peer_destroy_handler(void* userdata) {
native_callback_dispatcher(userdata, NULL, NULL, (void*)1, NULL, NULL, NULL);
}
static int grpcsharp_verify_peer_handler(const char* target_name,
const char* peer_pem, void* userdata) {
return native_callback_dispatcher(userdata, (void*)target_name,
(void*)peer_pem, (void*)0, NULL, NULL,
NULL);
}
GPR_EXPORT grpc_channel_credentials* GPR_CALLTYPE
grpcsharp_ssl_credentials_create(const char* pem_root_certs,
const char* key_cert_pair_cert_chain,
const char* key_cert_pair_private_key) {
const char* key_cert_pair_private_key,
void* verify_peer_callback_tag) {
grpc_ssl_pem_key_cert_pair key_cert_pair;
verify_peer_options verify_options;
grpc_ssl_pem_key_cert_pair* key_cert_pair_ptr = NULL;
verify_peer_options* verify_options_ptr = NULL;
if (key_cert_pair_cert_chain || key_cert_pair_private_key) {
memset(&key_cert_pair, 0, sizeof(key_cert_pair));
key_cert_pair.cert_chain = key_cert_pair_cert_chain;
key_cert_pair.private_key = key_cert_pair_private_key;
return grpc_ssl_credentials_create(pem_root_certs, &key_cert_pair, NULL,
NULL);
key_cert_pair_ptr = &key_cert_pair;
} else {
GPR_ASSERT(!key_cert_pair_cert_chain);
GPR_ASSERT(!key_cert_pair_private_key);
return grpc_ssl_credentials_create(pem_root_certs, NULL, NULL, NULL);
}
if (verify_peer_callback_tag != NULL) {
memset(&verify_options, 0, sizeof(verify_peer_options));
verify_options.verify_peer_callback_userdata = verify_peer_callback_tag;
verify_options.verify_peer_destruct = grpcsharp_verify_peer_destroy_handler;
verify_options.verify_peer_callback = grpcsharp_verify_peer_handler;
verify_options_ptr = &verify_options;
}
return grpc_ssl_credentials_create(pem_root_certs, key_cert_pair_ptr,
verify_options_ptr, NULL);
}
GPR_EXPORT void GPR_CALLTYPE
@ -1010,21 +1051,6 @@ grpcsharp_composite_call_credentials_create(grpc_call_credentials* creds1,
return grpc_composite_call_credentials_create(creds1, creds2, NULL);
}
/* Native callback dispatcher */
typedef int(GPR_CALLTYPE* grpcsharp_native_callback_dispatcher_func)(
void* tag, void* arg0, void* arg1, void* arg2, void* arg3, void* arg4,
void* arg5);
static grpcsharp_native_callback_dispatcher_func native_callback_dispatcher =
NULL;
GPR_EXPORT void GPR_CALLTYPE grpcsharp_native_callback_dispatcher_init(
grpcsharp_native_callback_dispatcher_func func) {
GPR_ASSERT(func);
native_callback_dispatcher = func;
}
/* Metadata credentials plugin */
GPR_EXPORT void GPR_CALLTYPE grpcsharp_metadata_credentials_notify_from_plugin(

@ -434,6 +434,9 @@ const char *kCFStreamVarName = "grpc_cfstream";
// Guarantees the code in {} block is invoked only once. See ref at:
// https://developer.apple.com/documentation/objectivec/nsobject/1418639-initialize?language=objc
if (self == [GRPCCall self]) {
// Enable CFStream by default by do not overwrite if the user explicitly disables CFStream with
// environment variable "grpc_cfstream=0"
setenv(kCFStreamVarName, "1", 0);
grpc_init();
callFlags = [NSMutableDictionary dictionary];
}

@ -17,6 +17,9 @@ GRPC_LOCAL_SRC = '../../..'
InteropTestsMultipleChannels
InteropTestsCallOptions
UnitTests
InteropTestsRemoteCFStream
InteropTestsLocalSSLCFStream
InteropTestsLocalCleartextCFStream
APIv2Tests
).each do |target_name|
target target_name do
@ -40,27 +43,6 @@ GRPC_LOCAL_SRC = '../../..'
end
end
%w(
InteropTestsRemoteCFStream
InteropTestsLocalSSLCFStream
InteropTestsLocalCleartextCFStream
).each do |target_name|
target target_name do
pod 'Protobuf', :path => "#{GRPC_LOCAL_SRC}/third_party/protobuf", :inhibit_warnings => true
pod '!ProtoCompiler', :path => "#{GRPC_LOCAL_SRC}/src/objective-c"
pod '!ProtoCompiler-gRPCPlugin', :path => "#{GRPC_LOCAL_SRC}/src/objective-c"
pod 'BoringSSL-GRPC', :podspec => "#{GRPC_LOCAL_SRC}/src/objective-c", :inhibit_warnings => true
pod 'gRPC/CFStream', :path => GRPC_LOCAL_SRC
pod 'gRPC-Core/CFStream-Implementation', :path => GRPC_LOCAL_SRC
pod 'gRPC-RxLibrary', :path => GRPC_LOCAL_SRC
pod 'gRPC-ProtoRPC', :path => GRPC_LOCAL_SRC, :inhibit_warnings => true
pod 'RemoteTest', :path => "RemoteTestClient", :inhibit_warnings => true
end
end
%w(
CoreCronetEnd2EndTests
CronetUnitTests
@ -127,11 +109,7 @@ post_install do |installer|
# GPR_UNREACHABLE_CODE causes "Control may reach end of non-void
# function" warning
config.build_settings['GCC_WARN_ABOUT_RETURN_TYPE'] = 'NO'
if target.name.include?('CFStream')
config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] = '$(inherited) COCOAPODS=1 GRPC_CFSTREAM=1'
else
config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] = '$(inherited) COCOAPODS=1 GRPC_CRONET_WITH_PACKET_COALESCING=1'
end
config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] = '$(inherited) COCOAPODS=1 GRPC_CRONET_WITH_PACKET_COALESCING=1'
end
end

@ -183,19 +183,14 @@
ss.compiler_flags = '-DGRPC_SHADOW_BORINGSSL_SYMBOLS'
# To save you from scrolling, this is the last part of the podspec.
ss.source_files = ${ruby_multiline_list(grpc_private_files(libs), 22)}
ss.source_files = ${ruby_multiline_list(grpc_private_files(libs) + cfstream_private_files(filegroups), 22)}
ss.private_header_files = ${ruby_multiline_list(grpc_private_headers(libs), 30)}
ss.private_header_files = ${ruby_multiline_list(grpc_private_headers(libs) + cfstream_private_headers(filegroups), 30)}
end
# CFStream is now default. Leaving this subspec only for compatibility purpose.
s.subspec 'CFStream-Implementation' do |ss|
ss.header_mappings_dir = '.'
ss.dependency "#{s.name}/Implementation", version
ss.pod_target_xcconfig = {
'GCC_PREPROCESSOR_DEFINITIONS' => 'GRPC_CFSTREAM=1'
}
ss.source_files = ${ruby_multiline_list(cfstream_private_files(filegroups), 22)}
ss.private_header_files = ${ruby_multiline_list(cfstream_private_headers(filegroups), 30)}
end
s.subspec 'Cronet-Interface' do |ss|

@ -55,12 +55,10 @@
ss.source_files = "#{src_dir}/*.{h,m}"
end
# CFStream is now default. Leaving this subspec only for compatibility purpose.
s.subspec 'CFStream' do |ss|
ss.dependency 'gRPC/CFStream', version
ss.dependency "#{s.name}/Main", version
ss.pod_target_xcconfig = {
'GCC_PREPROCESSOR_DEFINITIONS' => 'GRPC_CFSTREAM=1'
}
end
s.pod_target_xcconfig = {

@ -66,14 +66,9 @@
ss.dependency 'gRPC-Core', version
end
# This subspec is mutually exclusive with the `Main` subspec
# CFStream is now default. Leaving this subspec only for compatibility purpose.
s.subspec 'CFStream' do |ss|
ss.dependency 'gRPC-Core/CFStream-Implementation', version
ss.dependency "#{s.name}/Main", version
ss.pod_target_xcconfig = {
'GCC_PREPROCESSOR_DEFINITIONS' => 'GRPC_CFSTREAM=1'
}
end
s.subspec 'GID' do |ss|

@ -44,7 +44,7 @@ native_method_signatures = [
'void grpcsharp_channel_args_set_integer(ChannelArgsSafeHandle args, UIntPtr index, string key, int value)',
'void grpcsharp_channel_args_destroy(IntPtr args)',
'void grpcsharp_override_default_ssl_roots(string pemRootCerts)',
'ChannelCredentialsSafeHandle grpcsharp_ssl_credentials_create(string pemRootCerts, string keyCertPairCertChain, string keyCertPairPrivateKey)',
'ChannelCredentialsSafeHandle grpcsharp_ssl_credentials_create(string pemRootCerts, string keyCertPairCertChain, string keyCertPairPrivateKey, IntPtr verifyPeerCallbackTag)',
'ChannelCredentialsSafeHandle grpcsharp_composite_channel_credentials_create(ChannelCredentialsSafeHandle channelCreds, CallCredentialsSafeHandle callCreds)',
'void grpcsharp_channel_credentials_release(IntPtr credentials)',
'ChannelSafeHandle grpcsharp_insecure_channel_create(string target, ChannelArgsSafeHandle channelArgs)',

@ -36,6 +36,10 @@
#include "src/core/tsi/transport_security.h"
#include "test/core/util/test_config.h"
#ifndef TSI_OPENSSL_ALPN_SUPPORT
#define TSI_OPENSSL_ALPN_SUPPORT 1
#endif
static int check_transport_security_type(const grpc_auth_context* ctx) {
grpc_auth_property_iterator it = grpc_auth_context_find_properties_by_name(
ctx, GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME);
@ -432,6 +436,43 @@ static void test_default_ssl_roots(void) {
gpr_free(roots_env_var_file_path);
}
static void test_peer_alpn_check(void) {
#if TSI_OPENSSL_ALPN_SUPPORT
tsi_peer peer;
const char* alpn = "grpc";
const char* wrong_alpn = "wrong";
// peer does not have a TSI_SSL_ALPN_SELECTED_PROTOCOL property.
GPR_ASSERT(tsi_construct_peer(1, &peer) == TSI_OK);
GPR_ASSERT(tsi_construct_string_peer_property("wrong peer property name",
alpn, strlen(alpn),
&peer.properties[0]) == TSI_OK);
grpc_error* error = grpc_ssl_check_alpn(&peer);
GPR_ASSERT(error != GRPC_ERROR_NONE);
tsi_peer_destruct(&peer);
GRPC_ERROR_UNREF(error);
// peer has a TSI_SSL_ALPN_SELECTED_PROTOCOL property but with an incorrect
// property value.
GPR_ASSERT(tsi_construct_peer(1, &peer) == TSI_OK);
GPR_ASSERT(tsi_construct_string_peer_property(TSI_SSL_ALPN_SELECTED_PROTOCOL,
wrong_alpn, strlen(wrong_alpn),
&peer.properties[0]) == TSI_OK);
error = grpc_ssl_check_alpn(&peer);
GPR_ASSERT(error != GRPC_ERROR_NONE);
tsi_peer_destruct(&peer);
GRPC_ERROR_UNREF(error);
// peer has a TSI_SSL_ALPN_SELECTED_PROTOCOL property with a correct property
// value.
GPR_ASSERT(tsi_construct_peer(1, &peer) == TSI_OK);
GPR_ASSERT(tsi_construct_string_peer_property(TSI_SSL_ALPN_SELECTED_PROTOCOL,
alpn, strlen(alpn),
&peer.properties[0]) == TSI_OK);
GPR_ASSERT(grpc_ssl_check_alpn(&peer) == GRPC_ERROR_NONE);
tsi_peer_destruct(&peer);
#else
GPR_ASSERT(grpc_ssl_check_alpn(nullptr) == GRPC_ERROR_NONE);
#endif
}
int main(int argc, char** argv) {
grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
@ -443,7 +484,7 @@ int main(int argc, char** argv) {
test_cn_and_multiple_sans_and_others_ssl_peer_to_auth_context();
test_ipv6_address_san();
test_default_ssl_roots();
test_peer_alpn_check();
grpc_shutdown();
return 0;
}

@ -940,6 +940,32 @@ TEST_F(ClientLbEnd2endTest, PickFirstPendingUpdateAndSelectedSubchannelFails) {
WaitForServer(stub, 1, DEBUG_LOCATION, true /* ignore_failure */);
}
TEST_F(ClientLbEnd2endTest, PickFirstStaysIdleUponEmptyUpdate) {
// Start server, send RPC, and make sure channel is READY.
const int kNumServers = 1;
StartServers(kNumServers);
auto channel = BuildChannel(""); // pick_first is the default.
auto stub = BuildStub(channel);
SetNextResolution(GetServersPorts());
CheckRpcSendOk(stub, DEBUG_LOCATION);
EXPECT_EQ(channel->GetState(false), GRPC_CHANNEL_READY);
// Stop server. Channel should go into state IDLE.
servers_[0]->Shutdown();
EXPECT_TRUE(WaitForChannelNotReady(channel.get()));
EXPECT_EQ(channel->GetState(false), GRPC_CHANNEL_IDLE);
// Now send resolver update that includes no addresses. Channel
// should stay in state IDLE.
SetNextResolution({});
EXPECT_FALSE(channel->WaitForStateChange(
GRPC_CHANNEL_IDLE, grpc_timeout_seconds_to_deadline(3)));
// Now bring the backend back up and send a non-empty resolver update,
// and then try to send an RPC. Channel should go back into state READY.
StartServer(0);
SetNextResolution(GetServersPorts());
CheckRpcSendOk(stub, DEBUG_LOCATION);
EXPECT_EQ(channel->GetState(false), GRPC_CHANNEL_READY);
}
TEST_F(ClientLbEnd2endTest, RoundRobin) {
// Start servers and send one RPC per server.
const int kNumServers = 3;

@ -23,7 +23,7 @@ cp ${KOKORO_GFILE_DIR}/GrpcTesting-d0eeee2db331.json ${KOKORO_KEYSTORE_DIR}/4321
# Download bazel
temp_dir="$(mktemp -d)"
wget -q https://github.com/bazelbuild/bazel/releases/download/0.20.0/bazel-0.20.0-linux-x86_64 -O "${temp_dir}/bazel"
wget -q https://github.com/bazelbuild/bazel/releases/download/0.22.0/bazel-0.22.0-linux-x86_64 -O "${temp_dir}/bazel"
chmod 755 "${temp_dir}/bazel"
export PATH="${temp_dir}:${PATH}"
# This should show ${temp_dir}/bazel

@ -0,0 +1,23 @@
#!/usr/bin/env bash
# Copyright 2017 gRPC authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
set -ex
# TODO(jtattermusch): use the latest version of bazel
# Use --all_incompatible_changes to give an early warning about future
# bazel incompatibilities.
EXTRA_FLAGS="--config=opt --cache_test_results=no --all_incompatible_changes"
github/grpc/tools/internal_ci/linux/grpc_bazel_on_foundry_base.sh "${EXTRA_FLAGS}"
Loading…
Cancel
Save