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.Text;
19 
20 namespace Grpc.Core.Internal
21 {
22     /// <summary>
23     /// grpc_metadata_array from <c>grpc/grpc.h</c>
24     /// </summary>
25     internal class MetadataArraySafeHandle : SafeHandleZeroIsInvalid
26     {
27         static readonly NativeMethods Native = NativeMethods.Get();
28 
MetadataArraySafeHandle()29         private MetadataArraySafeHandle()
30         {
31         }
32 
Create(Metadata metadata)33         public static MetadataArraySafeHandle Create(Metadata metadata)
34         {
35             if (metadata.Count == 0)
36             {
37                 return new MetadataArraySafeHandle();
38             }
39 
40             // TODO(jtattermusch): we might wanna check that the metadata is readonly
41             var metadataArray = Native.grpcsharp_metadata_array_create(new UIntPtr((ulong)metadata.Count));
42             for (int i = 0; i < metadata.Count; i++)
43             {
44                 var valueBytes = metadata[i].GetSerializedValueUnsafe();
45                 Native.grpcsharp_metadata_array_add(metadataArray, metadata[i].Key, valueBytes, new UIntPtr((ulong)valueBytes.Length));
46             }
47             return metadataArray;
48         }
49 
50         /// <summary>
51         /// Reads metadata from pointer to grpc_metadata_array
52         /// </summary>
ReadMetadataFromPtrUnsafe(IntPtr metadataArray)53         public static Metadata ReadMetadataFromPtrUnsafe(IntPtr metadataArray)
54         {
55             if (metadataArray == IntPtr.Zero)
56             {
57                 return null;
58             }
59 
60             ulong count = Native.grpcsharp_metadata_array_count(metadataArray).ToUInt64();
61 
62             var metadata = new Metadata();
63             for (ulong i = 0; i < count; i++)
64             {
65                 var index = new UIntPtr(i);
66                 UIntPtr keyLen;
67                 IntPtr keyPtr = Native.grpcsharp_metadata_array_get_key(metadataArray, index, out keyLen);
68                 int keyLen32 = checked((int)keyLen.ToUInt32());
69                 string key = WellKnownStrings.TryIdentify(keyPtr, keyLen32)
70                     ?? Marshal.PtrToStringAnsi(keyPtr, keyLen32);
71                 UIntPtr valueLen;
72                 IntPtr valuePtr = Native.grpcsharp_metadata_array_get_value(metadataArray, index, out valueLen);
73                 int len32 = checked((int)valueLen.ToUInt64());
74                 metadata.Add(Metadata.Entry.CreateUnsafe(key, valuePtr, len32));
75             }
76             return metadata;
77         }
78 
79         internal IntPtr Handle
80         {
81             get
82             {
83                 return handle;
84             }
85         }
86 
ReleaseHandle()87         protected override bool ReleaseHandle()
88         {
89             Native.grpcsharp_metadata_array_destroy_full(handle);
90             return true;
91         }
92     }
93 }
94