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.Collections.Generic; 18 using System.Runtime.InteropServices; 19 using System.Threading; 20 using System.Threading.Tasks; 21 using Grpc.Core.Internal; 22 using Grpc.Core.Utils; 23 24 namespace Grpc.Core 25 { 26 /// <summary> 27 /// Channel option specified when creating a channel. 28 /// Corresponds to grpc_channel_args from grpc/grpc.h. 29 /// Commonly used channel option names are defined in <c>ChannelOptions</c>, 30 /// but any of the GRPC_ARG_* channel options names defined in grpc_types.h can be used. 31 /// </summary> 32 public sealed class ChannelOption : IEquatable<ChannelOption> 33 { 34 /// <summary> 35 /// Type of <c>ChannelOption</c>. 36 /// </summary> 37 public enum OptionType 38 { 39 /// <summary> 40 /// Channel option with integer value. 41 /// </summary> 42 Integer, 43 44 /// <summary> 45 /// Channel option with string value. 46 /// </summary> 47 String 48 } 49 50 private readonly OptionType type; 51 private readonly string name; 52 private readonly int intValue; 53 private readonly string stringValue; 54 55 /// <summary> 56 /// Creates a channel option with a string value. 57 /// </summary> 58 /// <param name="name">Name.</param> 59 /// <param name="stringValue">String value.</param> ChannelOption(string name, string stringValue)60 public ChannelOption(string name, string stringValue) 61 { 62 this.type = OptionType.String; 63 this.name = GrpcPreconditions.CheckNotNull(name, "name"); 64 this.stringValue = GrpcPreconditions.CheckNotNull(stringValue, "stringValue"); 65 } 66 67 /// <summary> 68 /// Creates a channel option with an integer value. 69 /// </summary> 70 /// <param name="name">Name.</param> 71 /// <param name="intValue">Integer value.</param> ChannelOption(string name, int intValue)72 public ChannelOption(string name, int intValue) 73 { 74 this.type = OptionType.Integer; 75 this.name = GrpcPreconditions.CheckNotNull(name, "name"); 76 this.intValue = intValue; 77 } 78 79 /// <summary> 80 /// Gets the type of the <c>ChannelOption</c>. 81 /// </summary> 82 public OptionType Type 83 { 84 get 85 { 86 return type; 87 } 88 } 89 90 /// <summary> 91 /// Gets the name of the <c>ChannelOption</c>. 92 /// </summary> 93 public string Name 94 { 95 get 96 { 97 return name; 98 } 99 } 100 101 /// <summary> 102 /// Gets the integer value the <c>ChannelOption</c>. 103 /// </summary> 104 public int IntValue 105 { 106 get 107 { 108 GrpcPreconditions.CheckState(type == OptionType.Integer); 109 return intValue; 110 } 111 } 112 113 /// <summary> 114 /// Gets the string value the <c>ChannelOption</c>. 115 /// </summary> 116 public string StringValue 117 { 118 get 119 { 120 GrpcPreconditions.CheckState(type == OptionType.String); 121 return stringValue; 122 } 123 } 124 125 /// <summary> 126 /// Determines whether the specified object is equal to the current object. 127 /// </summary> Equals(object obj)128 public override bool Equals(object obj) 129 { 130 return Equals(obj as ChannelOption); 131 } 132 133 /// <summary> 134 /// Determines whether the specified object is equal to the current object. 135 /// </summary> Equals(ChannelOption other)136 public bool Equals(ChannelOption other) 137 { 138 return other != null && 139 type == other.type && 140 name == other.name && 141 intValue == other.intValue && 142 stringValue == other.stringValue; 143 } 144 145 /// <summary> 146 /// A hash code for the current object. 147 /// </summary> GetHashCode()148 public override int GetHashCode() 149 { 150 var hashCode = 1412678443; 151 hashCode = hashCode * -1521134295 + type.GetHashCode(); 152 hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(name); 153 hashCode = hashCode * -1521134295 + intValue.GetHashCode(); 154 hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(stringValue); 155 return hashCode; 156 } 157 158 /// <summary> 159 /// Equality operator. 160 /// </summary> operator ==(ChannelOption option1, ChannelOption option2)161 public static bool operator ==(ChannelOption option1, ChannelOption option2) 162 { 163 return EqualityComparer<ChannelOption>.Default.Equals(option1, option2); 164 } 165 166 /// <summary> 167 /// Inequality operator. 168 /// </summary> operator !=(ChannelOption option1, ChannelOption option2)169 public static bool operator !=(ChannelOption option1, ChannelOption option2) 170 { 171 return !(option1 == option2); 172 } 173 } 174 175 /// <summary> 176 /// Defines names of most commonly used channel options. 177 /// Other supported options names can be found in grpc_types.h (GRPC_ARG_* definitions) 178 /// </summary> 179 public static class ChannelOptions 180 { 181 /// <summary>Override SSL target check. Only to be used for testing.</summary> 182 public const string SslTargetNameOverride = "grpc.ssl_target_name_override"; 183 184 /// <summary>Enable census for tracing and stats collection</summary> 185 public const string Census = "grpc.census"; 186 187 /// <summary>Maximum number of concurrent incoming streams to allow on a http2 connection</summary> 188 public const string MaxConcurrentStreams = "grpc.max_concurrent_streams"; 189 190 /// <summary>Maximum message length that the channel can receive</summary> 191 public const string MaxReceiveMessageLength = "grpc.max_receive_message_length"; 192 193 /// <summary>Maximum message length that the channel can send</summary> 194 public const string MaxSendMessageLength = "grpc.max_send_message_length"; 195 196 /// <summary>Obsolete, for backward compatibility only.</summary> 197 [Obsolete("Use MaxReceiveMessageLength instead.")] 198 public const string MaxMessageLength = MaxReceiveMessageLength; 199 200 /// <summary>Initial sequence number for http2 transports</summary> 201 public const string Http2InitialSequenceNumber = "grpc.http2.initial_sequence_number"; 202 203 /// <summary>Default authority for calls.</summary> 204 public const string DefaultAuthority = "grpc.default_authority"; 205 206 /// <summary>Primary user agent: goes at the start of the user-agent metadata</summary> 207 public const string PrimaryUserAgentString = "grpc.primary_user_agent"; 208 209 /// <summary>Secondary user agent: goes at the end of the user-agent metadata</summary> 210 public const string SecondaryUserAgentString = "grpc.secondary_user_agent"; 211 212 /// <summary>If non-zero, allow the use of SO_REUSEPORT for server if it's available (default 1)</summary> 213 public const string SoReuseport = "grpc.so_reuseport"; 214 215 /// <summary> 216 /// Creates native object for a collection of channel options. 217 /// </summary> 218 /// <returns>The native channel arguments.</returns> CreateChannelArgs(ICollection<ChannelOption> options)219 internal static ChannelArgsSafeHandle CreateChannelArgs(ICollection<ChannelOption> options) 220 { 221 if (options == null || options.Count == 0) 222 { 223 return ChannelArgsSafeHandle.CreateNull(); 224 } 225 ChannelArgsSafeHandle nativeArgs = null; 226 try 227 { 228 nativeArgs = ChannelArgsSafeHandle.Create(options.Count); 229 int i = 0; 230 foreach (var option in options) 231 { 232 if (option.Type == ChannelOption.OptionType.Integer) 233 { 234 nativeArgs.SetInteger(i, option.Name, option.IntValue); 235 } 236 else if (option.Type == ChannelOption.OptionType.String) 237 { 238 nativeArgs.SetString(i, option.Name, option.StringValue); 239 } 240 else 241 { 242 throw new InvalidOperationException("Unknown option type"); 243 } 244 i++; 245 } 246 return nativeArgs; 247 } 248 catch (Exception) 249 { 250 if (nativeArgs != null) 251 { 252 nativeArgs.Dispose(); 253 } 254 throw; 255 } 256 } 257 } 258 } 259