• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #region Copyright notice and license
2 // Copyright 2015 gRPC authors.
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //     http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 #endregion
16 using System;
17 using System.Runtime.InteropServices;
18 using System.Threading;
19 using System.Threading.Tasks;
20 
21 using Grpc.Core.Logging;
22 using Grpc.Core.Utils;
23 
24 namespace Grpc.Core.Internal
25 {
NativeMetadataInterceptor(IntPtr statePtr, IntPtr serviceUrlPtr, IntPtr methodNamePtr, IntPtr callbackPtr, IntPtr userDataPtr, bool isDestroy)26     internal delegate void NativeMetadataInterceptor(IntPtr statePtr, IntPtr serviceUrlPtr, IntPtr methodNamePtr, IntPtr callbackPtr, IntPtr userDataPtr, bool isDestroy);
27 
28     internal class NativeMetadataCredentialsPlugin
29     {
30         const string GetMetadataExceptionStatusMsg = "Exception occurred in metadata credentials plugin.";
31         const string GetMetadataExceptionLogMsg = GetMetadataExceptionStatusMsg + " This is likely not a problem with gRPC itself. Please verify that the code supplying the metadata (usually an authentication token) works correctly.";
32         static readonly ILogger Logger = GrpcEnvironment.Logger.ForType<NativeMetadataCredentialsPlugin>();
33         static readonly NativeMethods Native = NativeMethods.Get();
34 
35         AsyncAuthInterceptor interceptor;
36         GCHandle gcHandle;
37         NativeMetadataInterceptor nativeInterceptor;
38         CallCredentialsSafeHandle credentials;
39 
NativeMetadataCredentialsPlugin(AsyncAuthInterceptor interceptor)40         public NativeMetadataCredentialsPlugin(AsyncAuthInterceptor interceptor)
41         {
42             this.interceptor = GrpcPreconditions.CheckNotNull(interceptor, "interceptor");
43             this.nativeInterceptor = NativeMetadataInterceptorHandler;
44 
45             // Make sure the callback doesn't get garbage collected until it is destroyed.
46             this.gcHandle = GCHandle.Alloc(this.nativeInterceptor, GCHandleType.Normal);
47             this.credentials = Native.grpcsharp_metadata_credentials_create_from_plugin(nativeInterceptor);
48         }
49 
50         public CallCredentialsSafeHandle Credentials
51         {
52             get { return credentials; }
53         }
54 
NativeMetadataInterceptorHandler(IntPtr statePtr, IntPtr serviceUrlPtr, IntPtr methodNamePtr, IntPtr callbackPtr, IntPtr userDataPtr, bool isDestroy)55         private void NativeMetadataInterceptorHandler(IntPtr statePtr, IntPtr serviceUrlPtr, IntPtr methodNamePtr, IntPtr callbackPtr, IntPtr userDataPtr, bool isDestroy)
56         {
57             if (isDestroy)
58             {
59                 gcHandle.Free();
60                 return;
61             }
62 
63             try
64             {
65                 var context = new AuthInterceptorContext(Marshal.PtrToStringAnsi(serviceUrlPtr), Marshal.PtrToStringAnsi(methodNamePtr));
66                 // Make a guarantee that credentials_notify_from_plugin is invoked async to be compliant with c-core API.
67                 ThreadPool.QueueUserWorkItem(async (stateInfo) => await GetMetadataAsync(context, callbackPtr, userDataPtr));
68             }
69             catch (Exception e)
70             {
71                 // eat the exception, we must not throw when inside callback from native code.
72                 Logger.Error(e, "Exception occurred while invoking native metadata interceptor handler.");
73             }
74         }
75 
GetMetadataAsync(AuthInterceptorContext context, IntPtr callbackPtr, IntPtr userDataPtr)76         private async Task GetMetadataAsync(AuthInterceptorContext context, IntPtr callbackPtr, IntPtr userDataPtr)
77         {
78             try
79             {
80                 var metadata = new Metadata();
81                 await interceptor(context, metadata).ConfigureAwait(false);
82 
83                 using (var metadataArray = MetadataArraySafeHandle.Create(metadata))
84                 {
85                     Native.grpcsharp_metadata_credentials_notify_from_plugin(callbackPtr, userDataPtr, metadataArray, StatusCode.OK, null);
86                 }
87             }
88             catch (Exception e)
89             {
90                 string detail = GetMetadataExceptionStatusMsg + " " + e.ToString();
91                 Native.grpcsharp_metadata_credentials_notify_from_plugin(callbackPtr, userDataPtr, MetadataArraySafeHandle.Create(Metadata.Empty), StatusCode.Unknown, detail);
92                 Logger.Error(e, GetMetadataExceptionLogMsg);
93             }
94         }
95     }
96 }
97