add NativeCallbackDispatcher

pull/18327/head
Jan Tattermusch 6 years ago
parent f422acdb7e
commit 5a65985bf8
  1. 120
      src/csharp/Grpc.Core/Internal/NativeCallbackDispatcher.cs
  2. 3
      src/csharp/Grpc.Core/Internal/NativeExtension.cs
  3. 21
      src/csharp/Grpc.Core/Internal/NativeMetadataCredentialsPlugin.cs
  4. 17
      src/csharp/Grpc.Core/Internal/NativeMethods.Generated.cs
  5. 32
      src/csharp/ext/grpc_csharp_ext.c
  6. 4
      src/csharp/unitypackage/unitypackage_skeleton/Plugins/Grpc.Core/runtimes/grpc_csharp_ext_dummy_stubs.c
  7. 3
      templates/src/csharp/Grpc.Core/Internal/native_methods.include

@ -0,0 +1,120 @@
#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
using System;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading;
using System.Collections.Generic;
using Grpc.Core.Logging;
namespace Grpc.Core.Internal
{
internal delegate void UniversalNativeCallback(IntPtr arg0, IntPtr arg1, IntPtr arg2, IntPtr arg3, IntPtr arg4, IntPtr arg5);
internal delegate void NativeCallbackDispatcherCallback(IntPtr tag, IntPtr arg0, IntPtr arg1, IntPtr arg2, IntPtr arg3, IntPtr arg4, IntPtr arg5);
internal class NativeCallbackDispatcher
{
static readonly ILogger Logger = GrpcEnvironment.Logger.ForType<NativeCallbackDispatcher>();
static readonly object staticLock = new object();
static readonly AtomicCounter atomicCounter = new AtomicCounter();
static readonly ConcurrentDictionary<IntPtr, UniversalNativeCallback> registry = new ConcurrentDictionary<IntPtr, UniversalNativeCallback>();
static NativeCallbackDispatcherCallback dispatcherCallback;
public static void Init(NativeMethods native)
{
lock (staticLock)
{
if (dispatcherCallback == null)
{
dispatcherCallback = new NativeCallbackDispatcherCallback(HandleDispatcherCallback);
native.grpcsharp_native_callback_dispatcher_init(dispatcherCallback);
}
}
}
public static NativeCallbackRegistration RegisterCallback(UniversalNativeCallback callback)
{
while (true)
{
// TODO: retries might not work well on 32-bit
var tag = NextTag();
if (registry.TryAdd(tag, callback))
{
return new NativeCallbackRegistration(tag);
}
}
}
public static void UnregisterCallback(IntPtr tag)
{
registry.TryRemove(tag, out UniversalNativeCallback callback);
}
private static bool TryGetCallback(IntPtr tag, out UniversalNativeCallback callback)
{
return registry.TryGetValue(tag, out callback);
}
private static IntPtr NextTag()
{
return (IntPtr) atomicCounter.Increment();
}
[MonoPInvokeCallback(typeof(NativeCallbackDispatcherCallback))]
private static void HandleDispatcherCallback(IntPtr tag, IntPtr arg0, IntPtr arg1, IntPtr arg2, IntPtr arg3, IntPtr arg4, IntPtr arg5)
{
try
{
UniversalNativeCallback callback;
if (!TryGetCallback(tag, out callback))
{
Logger.Error("No native callback handler registered for tag {0}.", tag);
}
callback(arg0, arg1, arg2, arg3, arg4, arg5);
}
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.");
}
}
}
internal class NativeCallbackRegistration : IDisposable
{
readonly IntPtr tag;
readonly Action disposeAction;
public NativeCallbackRegistration(IntPtr tag, Action disposeAction)
{
this.tag = tag;
}
public IntPtr Tag => tag;
public void Dispose()
{
NativeCallbackDispatcher.UnregisterCallback(tag);
}
}
}

@ -43,6 +43,9 @@ namespace Grpc.Core.Internal
// to make sure we don't lose any logs.
NativeLogRedirector.Redirect(this.nativeMethods);
// Initialize
NativeCallbackDispatcher.Init(this.nativeMethods);
DefaultSslRootsOverride.Override(this.nativeMethods);
Logger.Debug("gRPC native library loaded successfully.");

@ -23,8 +23,6 @@ using Grpc.Core.Utils;
namespace Grpc.Core.Internal
{
internal delegate void NativeMetadataInterceptor(IntPtr statePtr, IntPtr serviceUrlPtr, IntPtr methodNamePtr, IntPtr callbackPtr, IntPtr userDataPtr, bool isDestroy);
internal class NativeMetadataCredentialsPlugin
{
const string GetMetadataExceptionStatusMsg = "Exception occurred in metadata credentials plugin.";
@ -33,18 +31,14 @@ namespace Grpc.Core.Internal
static readonly NativeMethods Native = NativeMethods.Get();
AsyncAuthInterceptor interceptor;
GCHandle gcHandle;
NativeMetadataInterceptor nativeInterceptor;
CallCredentialsSafeHandle credentials;
NativeCallbackRegistration callbackRegistration;
public NativeMetadataCredentialsPlugin(AsyncAuthInterceptor interceptor)
{
this.interceptor = GrpcPreconditions.CheckNotNull(interceptor, "interceptor");
this.nativeInterceptor = NativeMetadataInterceptorHandler;
// Make sure the callback doesn't get garbage collected until it is destroyed.
this.gcHandle = GCHandle.Alloc(this.nativeInterceptor, GCHandleType.Normal);
this.credentials = Native.grpcsharp_metadata_credentials_create_from_plugin(nativeInterceptor);
this.callbackRegistration = NativeCallbackDispatcher.RegisterCallback(HandleUniversalCallback);
this.credentials = Native.grpcsharp_metadata_credentials_create_from_plugin(this.callbackRegistration.Tag);
}
public CallCredentialsSafeHandle Credentials
@ -52,11 +46,16 @@ namespace Grpc.Core.Internal
get { return credentials; }
}
private void NativeMetadataInterceptorHandler(IntPtr statePtr, IntPtr serviceUrlPtr, IntPtr methodNamePtr, IntPtr callbackPtr, IntPtr userDataPtr, bool isDestroy)
private void HandleUniversalCallback(IntPtr arg0, IntPtr arg1, IntPtr arg2, IntPtr arg3, IntPtr arg4, IntPtr arg5)
{
NativeMetadataInterceptorHandler(arg0, arg1, arg2, arg3, arg4 != IntPtr.Zero);
}
private void NativeMetadataInterceptorHandler(IntPtr serviceUrlPtr, IntPtr methodNamePtr, IntPtr callbackPtr, IntPtr userDataPtr, bool isDestroy)
{
if (isDestroy)
{
gcHandle.Free();
this.callbackRegistration.Dispose();
return;
}

@ -103,6 +103,7 @@ namespace Grpc.Core.Internal
public readonly Delegates.grpcsharp_metadata_array_get_value_delegate grpcsharp_metadata_array_get_value;
public readonly Delegates.grpcsharp_metadata_array_destroy_full_delegate grpcsharp_metadata_array_destroy_full;
public readonly Delegates.grpcsharp_redirect_log_delegate grpcsharp_redirect_log;
public readonly Delegates.grpcsharp_native_callback_dispatcher_init_delegate grpcsharp_native_callback_dispatcher_init;
public readonly Delegates.grpcsharp_metadata_credentials_create_from_plugin_delegate grpcsharp_metadata_credentials_create_from_plugin;
public readonly Delegates.grpcsharp_metadata_credentials_notify_from_plugin_delegate grpcsharp_metadata_credentials_notify_from_plugin;
public readonly Delegates.grpcsharp_ssl_server_credentials_create_delegate grpcsharp_ssl_server_credentials_create;
@ -203,6 +204,7 @@ namespace Grpc.Core.Internal
this.grpcsharp_metadata_array_get_value = GetMethodDelegate<Delegates.grpcsharp_metadata_array_get_value_delegate>(library);
this.grpcsharp_metadata_array_destroy_full = GetMethodDelegate<Delegates.grpcsharp_metadata_array_destroy_full_delegate>(library);
this.grpcsharp_redirect_log = GetMethodDelegate<Delegates.grpcsharp_redirect_log_delegate>(library);
this.grpcsharp_native_callback_dispatcher_init = GetMethodDelegate<Delegates.grpcsharp_native_callback_dispatcher_init_delegate>(library);
this.grpcsharp_metadata_credentials_create_from_plugin = GetMethodDelegate<Delegates.grpcsharp_metadata_credentials_create_from_plugin_delegate>(library);
this.grpcsharp_metadata_credentials_notify_from_plugin = GetMethodDelegate<Delegates.grpcsharp_metadata_credentials_notify_from_plugin_delegate>(library);
this.grpcsharp_ssl_server_credentials_create = GetMethodDelegate<Delegates.grpcsharp_ssl_server_credentials_create_delegate>(library);
@ -302,6 +304,7 @@ namespace Grpc.Core.Internal
this.grpcsharp_metadata_array_get_value = DllImportsFromStaticLib.grpcsharp_metadata_array_get_value;
this.grpcsharp_metadata_array_destroy_full = DllImportsFromStaticLib.grpcsharp_metadata_array_destroy_full;
this.grpcsharp_redirect_log = DllImportsFromStaticLib.grpcsharp_redirect_log;
this.grpcsharp_native_callback_dispatcher_init = DllImportsFromStaticLib.grpcsharp_native_callback_dispatcher_init;
this.grpcsharp_metadata_credentials_create_from_plugin = DllImportsFromStaticLib.grpcsharp_metadata_credentials_create_from_plugin;
this.grpcsharp_metadata_credentials_notify_from_plugin = DllImportsFromStaticLib.grpcsharp_metadata_credentials_notify_from_plugin;
this.grpcsharp_ssl_server_credentials_create = DllImportsFromStaticLib.grpcsharp_ssl_server_credentials_create;
@ -401,6 +404,7 @@ namespace Grpc.Core.Internal
this.grpcsharp_metadata_array_get_value = DllImportsFromSharedLib.grpcsharp_metadata_array_get_value;
this.grpcsharp_metadata_array_destroy_full = DllImportsFromSharedLib.grpcsharp_metadata_array_destroy_full;
this.grpcsharp_redirect_log = DllImportsFromSharedLib.grpcsharp_redirect_log;
this.grpcsharp_native_callback_dispatcher_init = DllImportsFromSharedLib.grpcsharp_native_callback_dispatcher_init;
this.grpcsharp_metadata_credentials_create_from_plugin = DllImportsFromSharedLib.grpcsharp_metadata_credentials_create_from_plugin;
this.grpcsharp_metadata_credentials_notify_from_plugin = DllImportsFromSharedLib.grpcsharp_metadata_credentials_notify_from_plugin;
this.grpcsharp_ssl_server_credentials_create = DllImportsFromSharedLib.grpcsharp_ssl_server_credentials_create;
@ -503,7 +507,8 @@ namespace Grpc.Core.Internal
public delegate IntPtr grpcsharp_metadata_array_get_value_delegate(IntPtr metadataArray, UIntPtr index, out UIntPtr valueLength);
public delegate void grpcsharp_metadata_array_destroy_full_delegate(IntPtr array);
public delegate void grpcsharp_redirect_log_delegate(GprLogDelegate callback);
public delegate CallCredentialsSafeHandle grpcsharp_metadata_credentials_create_from_plugin_delegate(NativeMetadataInterceptor interceptor);
public delegate void grpcsharp_native_callback_dispatcher_init_delegate(NativeCallbackDispatcherCallback dispatcher);
public delegate CallCredentialsSafeHandle grpcsharp_metadata_credentials_create_from_plugin_delegate(IntPtr nativeCallbackTag);
public delegate void grpcsharp_metadata_credentials_notify_from_plugin_delegate(IntPtr callbackPtr, IntPtr userData, MetadataArraySafeHandle metadataArray, StatusCode statusCode, string errorDetails);
public delegate ServerCredentialsSafeHandle grpcsharp_ssl_server_credentials_create_delegate(string pemRootCerts, string[] keyCertPairCertChainArray, string[] keyCertPairPrivateKeyArray, UIntPtr numKeyCertPairs, SslClientCertificateRequestType clientCertificateRequest);
public delegate void grpcsharp_server_credentials_release_delegate(IntPtr credentials);
@ -746,7 +751,10 @@ namespace Grpc.Core.Internal
public static extern void grpcsharp_redirect_log(GprLogDelegate callback);
[DllImport(ImportName)]
public static extern CallCredentialsSafeHandle grpcsharp_metadata_credentials_create_from_plugin(NativeMetadataInterceptor interceptor);
public static extern void grpcsharp_native_callback_dispatcher_init(NativeCallbackDispatcherCallback dispatcher);
[DllImport(ImportName)]
public static extern CallCredentialsSafeHandle grpcsharp_metadata_credentials_create_from_plugin(IntPtr nativeCallbackTag);
[DllImport(ImportName)]
public static extern void grpcsharp_metadata_credentials_notify_from_plugin(IntPtr callbackPtr, IntPtr userData, MetadataArraySafeHandle metadataArray, StatusCode statusCode, string errorDetails);
@ -1039,7 +1047,10 @@ namespace Grpc.Core.Internal
public static extern void grpcsharp_redirect_log(GprLogDelegate callback);
[DllImport(ImportName)]
public static extern CallCredentialsSafeHandle grpcsharp_metadata_credentials_create_from_plugin(NativeMetadataInterceptor interceptor);
public static extern void grpcsharp_native_callback_dispatcher_init(NativeCallbackDispatcherCallback dispatcher);
[DllImport(ImportName)]
public static extern CallCredentialsSafeHandle grpcsharp_metadata_credentials_create_from_plugin(IntPtr nativeCallbackTag);
[DllImport(ImportName)]
public static extern void grpcsharp_metadata_credentials_notify_from_plugin(IntPtr callbackPtr, IntPtr userData, MetadataArraySafeHandle metadataArray, StatusCode statusCode, string errorDetails);

@ -1010,6 +1010,18 @@ grpcsharp_composite_call_credentials_create(grpc_call_credentials* creds1,
return grpc_composite_call_credentials_create(creds1, creds2, NULL);
}
/* Native callback dispatcher */
typedef void(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(
@ -1023,37 +1035,27 @@ GPR_EXPORT void GPR_CALLTYPE grpcsharp_metadata_credentials_notify_from_plugin(
}
}
typedef void(GPR_CALLTYPE* grpcsharp_metadata_interceptor_func)(
void* state, const char* service_url, const char* method_name,
grpc_credentials_plugin_metadata_cb cb, void* user_data,
int32_t is_destroy);
static int grpcsharp_get_metadata_handler(
void* state, grpc_auth_metadata_context context,
grpc_credentials_plugin_metadata_cb cb, void* user_data,
grpc_metadata creds_md[GRPC_METADATA_CREDENTIALS_PLUGIN_SYNC_MAX],
size_t* num_creds_md, grpc_status_code* status,
const char** error_details) {
grpcsharp_metadata_interceptor_func interceptor =
(grpcsharp_metadata_interceptor_func)(intptr_t)state;
interceptor(state, context.service_url, context.method_name, cb, user_data,
0);
native_callback_dispatcher(state, context.service_url, context.method_name, cb, user_data,
0, NULL);
return 0; /* Asynchronous return. */
}
static void grpcsharp_metadata_credentials_destroy_handler(void* state) {
grpcsharp_metadata_interceptor_func interceptor =
(grpcsharp_metadata_interceptor_func)(intptr_t)state;
interceptor(state, NULL, NULL, NULL, NULL, 1);
native_callback_dispatcher(state, NULL, NULL, NULL, NULL, 1, NULL);
}
GPR_EXPORT grpc_call_credentials* GPR_CALLTYPE
grpcsharp_metadata_credentials_create_from_plugin(
grpcsharp_metadata_interceptor_func metadata_interceptor) {
grpcsharp_metadata_credentials_create_from_plugin(void *callback_tag) {
grpc_metadata_credentials_plugin plugin;
plugin.get_metadata = grpcsharp_get_metadata_handler;
plugin.destroy = grpcsharp_metadata_credentials_destroy_handler;
plugin.state = (void*)(intptr_t)metadata_interceptor;
plugin.state = callback_tag;
plugin.type = "";
return grpc_metadata_credentials_create_from_plugin(plugin, NULL);
}

@ -298,6 +298,10 @@ void grpcsharp_redirect_log() {
fprintf(stderr, "Should never reach here");
abort();
}
void grpcsharp_native_callback_dispatcher_init() {
fprintf(stderr, "Should never reach here");
abort();
}
void grpcsharp_metadata_credentials_create_from_plugin() {
fprintf(stderr, "Should never reach here");
abort();

@ -69,7 +69,8 @@ native_method_signatures = [
'IntPtr grpcsharp_metadata_array_get_value(IntPtr metadataArray, UIntPtr index, out UIntPtr valueLength)',
'void grpcsharp_metadata_array_destroy_full(IntPtr array)',
'void grpcsharp_redirect_log(GprLogDelegate callback)',
'CallCredentialsSafeHandle grpcsharp_metadata_credentials_create_from_plugin(NativeMetadataInterceptor interceptor)',
'void grpcsharp_native_callback_dispatcher_init(NativeCallbackDispatcherCallback dispatcher)',
'CallCredentialsSafeHandle grpcsharp_metadata_credentials_create_from_plugin(IntPtr nativeCallbackTag)',
'void grpcsharp_metadata_credentials_notify_from_plugin(IntPtr callbackPtr, IntPtr userData, MetadataArraySafeHandle metadataArray, StatusCode statusCode, string errorDetails)',
'ServerCredentialsSafeHandle grpcsharp_ssl_server_credentials_create(string pemRootCerts, string[] keyCertPairCertChainArray, string[] keyCertPairPrivateKeyArray, UIntPtr numKeyCertPairs, SslClientCertificateRequestType clientCertificateRequest)',
'void grpcsharp_server_credentials_release(IntPtr credentials)',

Loading…
Cancel
Save