aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/csharp/Grpc.Core
diff options
context:
space:
mode:
authorGravatar Craig Tiller <craig.tiller@gmail.com>2015-07-26 12:55:47 -0700
committerGravatar Craig Tiller <craig.tiller@gmail.com>2015-07-26 12:55:47 -0700
commitd9aed1d0103122c235c5577f7a00ead9cbc1a7b9 (patch)
treec28b50ccab7a19287984857daf40d552e50247ab /src/csharp/Grpc.Core
parent7cb085375581ff2b18865e4e72b335276d08d09d (diff)
parent5c575dd6e4b01cd68cca5d1917b58023dcf4ca0f (diff)
Merge github.com:grpc/grpc into elliptic-orange-chamelion
Conflicts: src/csharp/ext/grpc_csharp_ext.c
Diffstat (limited to 'src/csharp/Grpc.Core')
-rw-r--r--src/csharp/Grpc.Core/Call.cs15
-rw-r--r--src/csharp/Grpc.Core/Calls.cs18
-rw-r--r--src/csharp/Grpc.Core/Channel.cs18
-rw-r--r--src/csharp/Grpc.Core/ClientBase.cs6
-rw-r--r--src/csharp/Grpc.Core/Credentials.cs75
-rw-r--r--src/csharp/Grpc.Core/Grpc.Core.csproj9
-rw-r--r--src/csharp/Grpc.Core/GrpcEnvironment.cs33
-rw-r--r--src/csharp/Grpc.Core/Internal/AsyncCall.cs21
-rw-r--r--src/csharp/Grpc.Core/Internal/AsyncCallBase.cs13
-rw-r--r--src/csharp/Grpc.Core/Internal/AsyncCallServer.cs28
-rw-r--r--src/csharp/Grpc.Core/Internal/CStringSafeHandle.cs60
-rw-r--r--src/csharp/Grpc.Core/Internal/CallSafeHandle.cs21
-rw-r--r--src/csharp/Grpc.Core/Internal/ChannelSafeHandle.cs16
-rw-r--r--src/csharp/Grpc.Core/Internal/CompletionRegistry.cs5
-rw-r--r--src/csharp/Grpc.Core/Internal/CredentialsSafeHandle.cs18
-rw-r--r--src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs10
-rw-r--r--src/csharp/Grpc.Core/Internal/NativeLogRedirector.cs (renamed from src/csharp/Grpc.Core/Internal/GrpcLog.cs)37
-rw-r--r--src/csharp/Grpc.Core/Internal/ServerCallHandler.cs33
-rw-r--r--src/csharp/Grpc.Core/Internal/ServerCredentialsSafeHandle.cs4
-rw-r--r--src/csharp/Grpc.Core/Internal/ServerSafeHandle.cs8
-rw-r--r--src/csharp/Grpc.Core/Internal/Timespec.cs183
-rw-r--r--src/csharp/Grpc.Core/KeyCertificatePair.cs84
-rw-r--r--src/csharp/Grpc.Core/Logging/ConsoleLogger.cs103
-rw-r--r--src/csharp/Grpc.Core/Logging/ILogger.cs57
-rw-r--r--src/csharp/Grpc.Core/Server.cs60
-rw-r--r--src/csharp/Grpc.Core/ServerCallContext.cs13
-rw-r--r--src/csharp/Grpc.Core/ServerCredentials.cs89
-rw-r--r--src/csharp/Grpc.Core/Utils/BenchmarkUtil.cs10
28 files changed, 848 insertions, 199 deletions
diff --git a/src/csharp/Grpc.Core/Call.cs b/src/csharp/Grpc.Core/Call.cs
index 37b452f020..94c5e26082 100644
--- a/src/csharp/Grpc.Core/Call.cs
+++ b/src/csharp/Grpc.Core/Call.cs
@@ -47,14 +47,21 @@ namespace Grpc.Core
readonly Marshaller<TResponse> responseMarshaller;
readonly Channel channel;
readonly Metadata headers;
+ readonly DateTime deadline;
public Call(string serviceName, Method<TRequest, TResponse> method, Channel channel, Metadata headers)
+ : this(serviceName, method, channel, headers, DateTime.MaxValue)
+ {
+ }
+
+ public Call(string serviceName, Method<TRequest, TResponse> method, Channel channel, Metadata headers, DateTime deadline)
{
this.name = method.GetFullName(serviceName);
this.requestMarshaller = method.RequestMarshaller;
this.responseMarshaller = method.ResponseMarshaller;
this.channel = Preconditions.CheckNotNull(channel);
this.headers = Preconditions.CheckNotNull(headers);
+ this.deadline = deadline;
}
public Channel Channel
@@ -87,6 +94,14 @@ namespace Grpc.Core
}
}
+ public DateTime Deadline
+ {
+ get
+ {
+ return this.deadline;
+ }
+ }
+
public Marshaller<TRequest> RequestMarshaller
{
get
diff --git a/src/csharp/Grpc.Core/Calls.cs b/src/csharp/Grpc.Core/Calls.cs
index 359fe53741..054fc27491 100644
--- a/src/csharp/Grpc.Core/Calls.cs
+++ b/src/csharp/Grpc.Core/Calls.cs
@@ -50,7 +50,7 @@ namespace Grpc.Core
var asyncCall = new AsyncCall<TRequest, TResponse>(call.RequestMarshaller.Serializer, call.ResponseMarshaller.Deserializer);
// TODO(jtattermusch): this gives a race that cancellation can be requested before the call even starts.
RegisterCancellationCallback(asyncCall, token);
- return asyncCall.UnaryCall(call.Channel, call.Name, req, call.Headers);
+ return asyncCall.UnaryCall(call.Channel, call.Name, req, call.Headers, call.Deadline);
}
public static AsyncUnaryCall<TResponse> AsyncUnaryCall<TRequest, TResponse>(Call<TRequest, TResponse> call, TRequest req, CancellationToken token)
@@ -58,8 +58,8 @@ namespace Grpc.Core
where TResponse : class
{
var asyncCall = new AsyncCall<TRequest, TResponse>(call.RequestMarshaller.Serializer, call.ResponseMarshaller.Deserializer);
- asyncCall.Initialize(call.Channel, call.Channel.CompletionQueue, call.Name);
- var asyncResult = asyncCall.UnaryCallAsync(req, call.Headers);
+ asyncCall.Initialize(call.Channel, call.Channel.CompletionQueue, call.Name, Timespec.FromDateTime(call.Deadline));
+ var asyncResult = asyncCall.UnaryCallAsync(req, call.Headers, call.Deadline);
RegisterCancellationCallback(asyncCall, token);
return new AsyncUnaryCall<TResponse>(asyncResult, asyncCall.GetStatus, asyncCall.GetTrailers, asyncCall.Cancel);
}
@@ -69,8 +69,8 @@ namespace Grpc.Core
where TResponse : class
{
var asyncCall = new AsyncCall<TRequest, TResponse>(call.RequestMarshaller.Serializer, call.ResponseMarshaller.Deserializer);
- asyncCall.Initialize(call.Channel, call.Channel.CompletionQueue, call.Name);
- asyncCall.StartServerStreamingCall(req, call.Headers);
+ asyncCall.Initialize(call.Channel, call.Channel.CompletionQueue, call.Name, Timespec.FromDateTime(call.Deadline));
+ asyncCall.StartServerStreamingCall(req, call.Headers, call.Deadline);
RegisterCancellationCallback(asyncCall, token);
var responseStream = new ClientResponseStream<TRequest, TResponse>(asyncCall);
return new AsyncServerStreamingCall<TResponse>(responseStream, asyncCall.GetStatus, asyncCall.GetTrailers, asyncCall.Cancel);
@@ -81,8 +81,8 @@ namespace Grpc.Core
where TResponse : class
{
var asyncCall = new AsyncCall<TRequest, TResponse>(call.RequestMarshaller.Serializer, call.ResponseMarshaller.Deserializer);
- asyncCall.Initialize(call.Channel, call.Channel.CompletionQueue, call.Name);
- var resultTask = asyncCall.ClientStreamingCallAsync(call.Headers);
+ asyncCall.Initialize(call.Channel, call.Channel.CompletionQueue, call.Name, Timespec.FromDateTime(call.Deadline));
+ var resultTask = asyncCall.ClientStreamingCallAsync(call.Headers, call.Deadline);
RegisterCancellationCallback(asyncCall, token);
var requestStream = new ClientRequestStream<TRequest, TResponse>(asyncCall);
return new AsyncClientStreamingCall<TRequest, TResponse>(requestStream, resultTask, asyncCall.GetStatus, asyncCall.GetTrailers, asyncCall.Cancel);
@@ -93,8 +93,8 @@ namespace Grpc.Core
where TResponse : class
{
var asyncCall = new AsyncCall<TRequest, TResponse>(call.RequestMarshaller.Serializer, call.ResponseMarshaller.Deserializer);
- asyncCall.Initialize(call.Channel, call.Channel.CompletionQueue, call.Name);
- asyncCall.StartDuplexStreamingCall(call.Headers);
+ asyncCall.Initialize(call.Channel, call.Channel.CompletionQueue, call.Name, Timespec.FromDateTime(call.Deadline));
+ asyncCall.StartDuplexStreamingCall(call.Headers, call.Deadline);
RegisterCancellationCallback(asyncCall, token);
var requestStream = new ClientRequestStream<TRequest, TResponse>(asyncCall);
var responseStream = new ClientResponseStream<TRequest, TResponse>(asyncCall);
diff --git a/src/csharp/Grpc.Core/Channel.cs b/src/csharp/Grpc.Core/Channel.cs
index e5c6abd2cb..18e6f2fda5 100644
--- a/src/csharp/Grpc.Core/Channel.cs
+++ b/src/csharp/Grpc.Core/Channel.cs
@@ -56,26 +56,24 @@ namespace Grpc.Core
/// Port will default to 80 for an unsecure channel and to 443 a secure channel.
/// </summary>
/// <param name="host">The DNS name of IP address of the host.</param>
- /// <param name="credentials">Optional credentials to create a secure channel.</param>
+ /// <param name="credentials">Credentials to secure the channel.</param>
/// <param name="options">Channel options.</param>
- public Channel(string host, Credentials credentials = null, IEnumerable<ChannelOption> options = null)
+ public Channel(string host, Credentials credentials, IEnumerable<ChannelOption> options = null)
{
this.environment = GrpcEnvironment.GetInstance();
this.options = options != null ? new List<ChannelOption>(options) : new List<ChannelOption>();
EnsureUserAgentChannelOption(this.options);
+ using (CredentialsSafeHandle nativeCredentials = credentials.ToNativeCredentials())
using (ChannelArgsSafeHandle nativeChannelArgs = ChannelOptions.CreateChannelArgs(this.options))
{
- if (credentials != null)
+ if (nativeCredentials != null)
{
- using (CredentialsSafeHandle nativeCredentials = credentials.ToNativeCredentials())
- {
- this.handle = ChannelSafeHandle.CreateSecure(nativeCredentials, host, nativeChannelArgs);
- }
+ this.handle = ChannelSafeHandle.CreateSecure(nativeCredentials, host, nativeChannelArgs);
}
else
{
- this.handle = ChannelSafeHandle.Create(host, nativeChannelArgs);
+ this.handle = ChannelSafeHandle.CreateInsecure(host, nativeChannelArgs);
}
}
this.target = GetOverridenTarget(host, this.options);
@@ -86,9 +84,9 @@ namespace Grpc.Core
/// </summary>
/// <param name="host">DNS name or IP address</param>
/// <param name="port">the port</param>
- /// <param name="credentials">Optional credentials to create a secure channel.</param>
+ /// <param name="credentials">Credentials to secure the channel.</param>
/// <param name="options">Channel options.</param>
- public Channel(string host, int port, Credentials credentials = null, IEnumerable<ChannelOption> options = null) :
+ public Channel(string host, int port, Credentials credentials, IEnumerable<ChannelOption> options = null) :
this(string.Format("{0}:{1}", host, port), credentials, options)
{
}
diff --git a/src/csharp/Grpc.Core/ClientBase.cs b/src/csharp/Grpc.Core/ClientBase.cs
index a099f96aea..fd3473128a 100644
--- a/src/csharp/Grpc.Core/ClientBase.cs
+++ b/src/csharp/Grpc.Core/ClientBase.cs
@@ -76,7 +76,7 @@ namespace Grpc.Core
/// <summary>
/// Creates a new call to given method.
/// </summary>
- protected Call<TRequest, TResponse> CreateCall<TRequest, TResponse>(string serviceName, Method<TRequest, TResponse> method, Metadata metadata)
+ protected Call<TRequest, TResponse> CreateCall<TRequest, TResponse>(string serviceName, Method<TRequest, TResponse> method, Metadata metadata, DateTime? deadline)
where TRequest : class
where TResponse : class
{
@@ -87,8 +87,8 @@ namespace Grpc.Core
interceptor(metadata);
metadata.Freeze();
}
- metadata = metadata ?? Metadata.Empty;
- return new Call<TRequest, TResponse>(serviceName, method, channel, metadata);
+ return new Call<TRequest, TResponse>(serviceName, method, channel,
+ metadata ?? Metadata.Empty, deadline ?? DateTime.MaxValue);
}
}
}
diff --git a/src/csharp/Grpc.Core/Credentials.cs b/src/csharp/Grpc.Core/Credentials.cs
index e64c1e3dc1..4fcac0c4c0 100644
--- a/src/csharp/Grpc.Core/Credentials.cs
+++ b/src/csharp/Grpc.Core/Credentials.cs
@@ -41,39 +41,98 @@ namespace Grpc.Core
/// </summary>
public abstract class Credentials
{
+ static readonly Credentials InsecureInstance = new InsecureCredentialsImpl();
+
+ /// <summary>
+ /// Returns instance of credential that provides no security and
+ /// will result in creating an unsecure channel with no encryption whatsoever.
+ /// </summary>
+ public static Credentials Insecure
+ {
+ get
+ {
+ return InsecureInstance;
+ }
+ }
+
/// <summary>
- /// Creates native object for the credentials.
+ /// Creates native object for the credentials. May return null if insecure channel
+ /// should be created.
/// </summary>
/// <returns>The native credentials.</returns>
internal abstract CredentialsSafeHandle ToNativeCredentials();
+
+ private sealed class InsecureCredentialsImpl : Credentials
+ {
+ internal override CredentialsSafeHandle ToNativeCredentials()
+ {
+ return null;
+ }
+ }
}
/// <summary>
/// Client-side SSL credentials.
/// </summary>
- public class SslCredentials : Credentials
+ public sealed class SslCredentials : Credentials
{
- string pemRootCerts;
+ readonly string rootCertificates;
+ readonly KeyCertificatePair keyCertificatePair;
- public SslCredentials(string pemRootCerts)
+ /// <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)
{
- this.pemRootCerts = pemRootCerts;
+ }
+
+ /// <summary>
+ /// Creates client-side SSL credentials from
+ /// a string containing PEM encoded root certificates.
+ /// </summary>
+ public SslCredentials(string rootCertificates) : this(rootCertificates, 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 = rootCertificates;
+ this.keyCertificatePair = keyCertificatePair;
}
/// <summary>
/// PEM encoding of the server root certificates.
/// </summary>
- public string RootCerts
+ public string RootCertificates
+ {
+ get
+ {
+ return this.rootCertificates;
+ }
+ }
+
+ /// <summary>
+ /// Client side key and certificate pair.
+ /// If null, client will not use key and certificate pair.
+ /// </summary>
+ public KeyCertificatePair KeyCertificatePair
{
get
{
- return this.pemRootCerts;
+ return this.keyCertificatePair;
}
}
internal override CredentialsSafeHandle ToNativeCredentials()
{
- return CredentialsSafeHandle.CreateSslCredentials(pemRootCerts);
+ return CredentialsSafeHandle.CreateSslCredentials(rootCertificates, keyCertificatePair);
}
}
}
diff --git a/src/csharp/Grpc.Core/Grpc.Core.csproj b/src/csharp/Grpc.Core/Grpc.Core.csproj
index fd68b91851..0d879e9b1e 100644
--- a/src/csharp/Grpc.Core/Grpc.Core.csproj
+++ b/src/csharp/Grpc.Core/Grpc.Core.csproj
@@ -47,7 +47,6 @@
<Compile Include="IServerStreamWriter.cs" />
<Compile Include="IAsyncStreamWriter.cs" />
<Compile Include="IAsyncStreamReader.cs" />
- <Compile Include="Internal\GrpcLog.cs" />
<Compile Include="Version.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="RpcException.cs" />
@@ -103,6 +102,11 @@
<Compile Include="ChannelOptions.cs" />
<Compile Include="AsyncUnaryCall.cs" />
<Compile Include="VersionInfo.cs" />
+ <Compile Include="Internal\CStringSafeHandle.cs" />
+ <Compile Include="KeyCertificatePair.cs" />
+ <Compile Include="Logging\ILogger.cs" />
+ <Compile Include="Logging\ConsoleLogger.cs" />
+ <Compile Include="Internal\NativeLogRedirector.cs" />
</ItemGroup>
<ItemGroup>
<None Include="Grpc.Core.nuspec" />
@@ -133,4 +137,7 @@
</Target>
<Import Project="..\packages\grpc.dependencies.openssl.redist.1.0.2.2\build\portable-net45\grpc.dependencies.openssl.redist.targets" Condition="Exists('..\packages\grpc.dependencies.openssl.redist.1.0.2.2\build\portable-net45\grpc.dependencies.openssl.redist.targets')" />
<Import Project="..\packages\grpc.dependencies.zlib.redist.1.2.8.9\build\portable-net45\grpc.dependencies.zlib.redist.targets" Condition="Exists('..\packages\grpc.dependencies.zlib.redist.1.2.8.9\build\portable-net45\grpc.dependencies.zlib.redist.targets')" />
+ <ItemGroup>
+ <Folder Include="Logging\" />
+ </ItemGroup>
</Project> \ No newline at end of file
diff --git a/src/csharp/Grpc.Core/GrpcEnvironment.cs b/src/csharp/Grpc.Core/GrpcEnvironment.cs
index 47d1651aab..034a66be3c 100644
--- a/src/csharp/Grpc.Core/GrpcEnvironment.cs
+++ b/src/csharp/Grpc.Core/GrpcEnvironment.cs
@@ -35,6 +35,7 @@ using System;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using Grpc.Core.Internal;
+using Grpc.Core.Logging;
using Grpc.Core.Utils;
namespace Grpc.Core
@@ -55,6 +56,8 @@ namespace Grpc.Core
static object staticLock = new object();
static GrpcEnvironment instance;
+ static ILogger logger = new ConsoleLogger();
+
readonly GrpcThreadPool threadPool;
readonly CompletionRegistry completionRegistry;
readonly DebugStats debugStats = new DebugStats();
@@ -93,17 +96,38 @@ namespace Grpc.Core
}
/// <summary>
+ /// Gets application-wide logger used by gRPC.
+ /// </summary>
+ /// <value>The logger.</value>
+ public static ILogger Logger
+ {
+ get
+ {
+ return logger;
+ }
+ }
+
+ /// <summary>
+ /// Sets the application-wide logger that should be used by gRPC.
+ /// </summary>
+ public static void SetLogger(ILogger customLogger)
+ {
+ Preconditions.CheckNotNull(customLogger);
+ logger = customLogger;
+ }
+
+ /// <summary>
/// Creates gRPC environment.
/// </summary>
private GrpcEnvironment()
{
- GrpcLog.RedirectNativeLogs(Console.Error);
+ NativeLogRedirector.Redirect();
grpcsharp_init();
completionRegistry = new CompletionRegistry(this);
threadPool = new GrpcThreadPool(this, THREAD_POOL_SIZE);
threadPool.Start();
// TODO: use proper logging here
- Console.WriteLine("GRPC initialized.");
+ Logger.Info("gRPC initialized.");
}
/// <summary>
@@ -154,8 +178,7 @@ namespace Grpc.Core
debugStats.CheckOK();
- // TODO: use proper logging here
- Console.WriteLine("GRPC shutdown.");
+ Logger.Info("gRPC shutdown.");
}
/// <summary>
@@ -171,7 +194,7 @@ namespace Grpc.Core
}
catch (Exception e)
{
- Console.WriteLine("Error occured while shutting down GrpcEnvironment: " + e);
+ Logger.Error(e, "Error occured while shutting down GrpcEnvironment.");
}
});
}
diff --git a/src/csharp/Grpc.Core/Internal/AsyncCall.cs b/src/csharp/Grpc.Core/Internal/AsyncCall.cs
index f983dbb759..bfcb9366a1 100644
--- a/src/csharp/Grpc.Core/Internal/AsyncCall.cs
+++ b/src/csharp/Grpc.Core/Internal/AsyncCall.cs
@@ -38,6 +38,7 @@ using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using Grpc.Core.Internal;
+using Grpc.Core.Logging;
using Grpc.Core.Utils;
namespace Grpc.Core.Internal
@@ -47,6 +48,8 @@ namespace Grpc.Core.Internal
/// </summary>
internal class AsyncCall<TRequest, TResponse> : AsyncCallBase<TRequest, TResponse>
{
+ static readonly ILogger Logger = GrpcEnvironment.Logger.ForType<AsyncCall<TRequest, TResponse>>();
+
Channel channel;
// Completion of a pending unary response if not null.
@@ -61,10 +64,10 @@ namespace Grpc.Core.Internal
{
}
- public void Initialize(Channel channel, CompletionQueueSafeHandle cq, string methodName)
+ public void Initialize(Channel channel, CompletionQueueSafeHandle cq, string methodName, Timespec deadline)
{
this.channel = channel;
- var call = CallSafeHandle.Create(channel.Handle, channel.CompletionRegistry, cq, methodName, channel.Target, Timespec.InfFuture);
+ var call = channel.Handle.CreateCall(channel.CompletionRegistry, cq, methodName, channel.Target, deadline);
channel.Environment.DebugStats.ActiveClientCalls.Increment();
InitializeInternal(call);
}
@@ -76,7 +79,7 @@ namespace Grpc.Core.Internal
/// <summary>
/// Blocking unary request - unary response call.
/// </summary>
- public TResponse UnaryCall(Channel channel, string methodName, TRequest msg, Metadata headers)
+ public TResponse UnaryCall(Channel channel, string methodName, TRequest msg, Metadata headers, DateTime deadline)
{
using (CompletionQueueSafeHandle cq = CompletionQueueSafeHandle.Create())
{
@@ -86,7 +89,7 @@ namespace Grpc.Core.Internal
lock (myLock)
{
- Initialize(channel, cq, methodName);
+ Initialize(channel, cq, methodName, Timespec.FromDateTime(deadline));
started = true;
halfcloseRequested = true;
readingDone = true;
@@ -106,7 +109,7 @@ namespace Grpc.Core.Internal
}
catch (Exception e)
{
- Console.WriteLine("Exception occured while invoking completion delegate: " + e);
+ Logger.Error(e, "Exception occured while invoking completion delegate.");
}
}
}
@@ -126,7 +129,7 @@ namespace Grpc.Core.Internal
/// <summary>
/// Starts a unary request - unary response call.
/// </summary>
- public Task<TResponse> UnaryCallAsync(TRequest msg, Metadata headers)
+ public Task<TResponse> UnaryCallAsync(TRequest msg, Metadata headers, DateTime deadline)
{
lock (myLock)
{
@@ -151,7 +154,7 @@ namespace Grpc.Core.Internal
/// Starts a streamed request - unary response call.
/// Use StartSendMessage and StartSendCloseFromClient to stream requests.
/// </summary>
- public Task<TResponse> ClientStreamingCallAsync(Metadata headers)
+ public Task<TResponse> ClientStreamingCallAsync(Metadata headers, DateTime deadline)
{
lock (myLock)
{
@@ -173,7 +176,7 @@ namespace Grpc.Core.Internal
/// <summary>
/// Starts a unary request - streamed response call.
/// </summary>
- public void StartServerStreamingCall(TRequest msg, Metadata headers)
+ public void StartServerStreamingCall(TRequest msg, Metadata headers, DateTime deadline)
{
lock (myLock)
{
@@ -196,7 +199,7 @@ namespace Grpc.Core.Internal
/// Starts a streaming request - streaming response call.
/// Use StartSendMessage and StartSendCloseFromClient to stream requests.
/// </summary>
- public void StartDuplexStreamingCall(Metadata headers)
+ public void StartDuplexStreamingCall(Metadata headers, DateTime deadline)
{
lock (myLock)
{
diff --git a/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs b/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs
index 64713c8c52..38f2a5baeb 100644
--- a/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs
+++ b/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs
@@ -38,6 +38,7 @@ using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using Grpc.Core.Internal;
+using Grpc.Core.Logging;
using Grpc.Core.Utils;
namespace Grpc.Core.Internal
@@ -48,6 +49,8 @@ namespace Grpc.Core.Internal
/// </summary>
internal abstract class AsyncCallBase<TWrite, TRead>
{
+ static readonly ILogger Logger = GrpcEnvironment.Logger.ForType<AsyncCallBase<TWrite, TRead>>();
+
readonly Func<TWrite, byte[]> serializer;
readonly Func<byte[], TRead> deserializer;
@@ -233,9 +236,9 @@ namespace Grpc.Core.Internal
payload = serializer(msg);
return true;
}
- catch (Exception)
+ catch (Exception e)
{
- Console.WriteLine("Exception occured while trying to serialize message");
+ Logger.Error(e, "Exception occured while trying to serialize message");
payload = null;
return false;
}
@@ -248,9 +251,9 @@ namespace Grpc.Core.Internal
msg = deserializer(payload);
return true;
}
- catch (Exception)
+ catch (Exception e)
{
- Console.WriteLine("Exception occured while trying to deserialize message");
+ Logger.Error(e, "Exception occured while trying to deserialize message.");
msg = default(TRead);
return false;
}
@@ -264,7 +267,7 @@ namespace Grpc.Core.Internal
}
catch (Exception e)
{
- Console.WriteLine("Exception occured while invoking completion delegate: " + e);
+ Logger.Error(e, "Exception occured while invoking completion delegate.");
}
}
diff --git a/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs b/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs
index f809f4a84c..513902ee36 100644
--- a/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs
+++ b/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs
@@ -48,6 +48,7 @@ namespace Grpc.Core.Internal
internal class AsyncCallServer<TRequest, TResponse> : AsyncCallBase<TResponse, TRequest>
{
readonly TaskCompletionSource<object> finishedServersideTcs = new TaskCompletionSource<object>();
+ readonly CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
readonly GrpcEnvironment environment;
public AsyncCallServer(Func<TResponse, byte[]> serializer, Func<byte[], TRequest> deserializer, GrpcEnvironment environment) : base(serializer, deserializer)
@@ -118,6 +119,26 @@ namespace Grpc.Core.Internal
}
}
+ /// <summary>
+ /// Gets cancellation token that gets cancelled once close completion
+ /// is received and the cancelled flag is set.
+ /// </summary>
+ public CancellationToken CancellationToken
+ {
+ get
+ {
+ return cancellationTokenSource.Token;
+ }
+ }
+
+ public string Peer
+ {
+ get
+ {
+ return call.GetPeer();
+ }
+ }
+
protected override void OnReleaseResources()
{
environment.DebugStats.ActiveServerCalls.Decrement();
@@ -138,6 +159,8 @@ namespace Grpc.Core.Internal
{
// Once we cancel, we don't have to care that much
// about reads and writes.
+
+ // TODO(jtattermusch): is this still necessary?
Cancel();
}
@@ -145,6 +168,11 @@ namespace Grpc.Core.Internal
}
// TODO(jtattermusch): handle error
+ if (cancelled)
+ {
+ cancellationTokenSource.Cancel();
+ }
+
finishedServersideTcs.SetResult(null);
}
}
diff --git a/src/csharp/Grpc.Core/Internal/CStringSafeHandle.cs b/src/csharp/Grpc.Core/Internal/CStringSafeHandle.cs
new file mode 100644
index 0000000000..92fbe8cf0f
--- /dev/null
+++ b/src/csharp/Grpc.Core/Internal/CStringSafeHandle.cs
@@ -0,0 +1,60 @@
+#region Copyright notice and license
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+using System;
+using System.Runtime.InteropServices;
+using System.Threading.Tasks;
+
+namespace Grpc.Core.Internal
+{
+ /// <summary>
+ /// Owned char* object.
+ /// </summary>
+ internal class CStringSafeHandle : SafeHandleZeroIsInvalid
+ {
+ [DllImport("grpc_csharp_ext.dll")]
+ static extern void gprsharp_free(IntPtr ptr);
+
+ private CStringSafeHandle()
+ {
+ }
+
+ public string GetValue()
+ {
+ return Marshal.PtrToStringAnsi(handle);
+ }
+
+ protected override bool ReleaseHandle()
+ {
+ gprsharp_free(handle);
+ return true;
+ }
+ }
+}
diff --git a/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs b/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs
index 19dbb83f24..714749b171 100644
--- a/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs
+++ b/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs
@@ -46,9 +46,6 @@ namespace Grpc.Core.Internal
CompletionRegistry completionRegistry;
[DllImport("grpc_csharp_ext.dll")]
- static extern CallSafeHandle grpcsharp_channel_create_call(ChannelSafeHandle channel, CompletionQueueSafeHandle cq, string method, string host, Timespec deadline);
-
- [DllImport("grpc_csharp_ext.dll")]
static extern GRPCCallError grpcsharp_call_cancel(CallSafeHandle call);
[DllImport("grpc_csharp_ext.dll")]
@@ -92,19 +89,15 @@ namespace Grpc.Core.Internal
BatchContextSafeHandle ctx);
[DllImport("grpc_csharp_ext.dll")]
+ static extern CStringSafeHandle grpcsharp_call_get_peer(CallSafeHandle call);
+
+ [DllImport("grpc_csharp_ext.dll")]
static extern void grpcsharp_call_destroy(IntPtr call);
private CallSafeHandle()
{
}
- public static CallSafeHandle Create(ChannelSafeHandle channel, CompletionRegistry registry, CompletionQueueSafeHandle cq, string method, string host, Timespec deadline)
- {
- var result = grpcsharp_channel_create_call(channel, cq, method, host, deadline);
- result.SetCompletionRegistry(registry);
- return result;
- }
-
public void SetCompletionRegistry(CompletionRegistry completionRegistry)
{
this.completionRegistry = completionRegistry;
@@ -190,6 +183,14 @@ namespace Grpc.Core.Internal
grpcsharp_call_cancel_with_status(this, status.StatusCode, status.Detail).CheckOk();
}
+ public string GetPeer()
+ {
+ using (var cstring = grpcsharp_call_get_peer(this))
+ {
+ return cstring.GetValue();
+ }
+ }
+
protected override bool ReleaseHandle()
{
grpcsharp_call_destroy(handle);
diff --git a/src/csharp/Grpc.Core/Internal/ChannelSafeHandle.cs b/src/csharp/Grpc.Core/Internal/ChannelSafeHandle.cs
index f046f4c6d0..20815efbd3 100644
--- a/src/csharp/Grpc.Core/Internal/ChannelSafeHandle.cs
+++ b/src/csharp/Grpc.Core/Internal/ChannelSafeHandle.cs
@@ -41,21 +41,24 @@ namespace Grpc.Core.Internal
internal class ChannelSafeHandle : SafeHandleZeroIsInvalid
{
[DllImport("grpc_csharp_ext.dll")]
- static extern ChannelSafeHandle grpcsharp_channel_create(string target, ChannelArgsSafeHandle channelArgs);
+ static extern ChannelSafeHandle grpcsharp_insecure_channel_create(string target, ChannelArgsSafeHandle channelArgs);
[DllImport("grpc_csharp_ext.dll")]
static extern ChannelSafeHandle grpcsharp_secure_channel_create(CredentialsSafeHandle credentials, string target, ChannelArgsSafeHandle channelArgs);
[DllImport("grpc_csharp_ext.dll")]
+ static extern CallSafeHandle grpcsharp_channel_create_call(ChannelSafeHandle channel, CompletionQueueSafeHandle cq, string method, string host, Timespec deadline);
+
+ [DllImport("grpc_csharp_ext.dll")]
static extern void grpcsharp_channel_destroy(IntPtr channel);
private ChannelSafeHandle()
{
}
- public static ChannelSafeHandle Create(string target, ChannelArgsSafeHandle channelArgs)
+ public static ChannelSafeHandle CreateInsecure(string target, ChannelArgsSafeHandle channelArgs)
{
- return grpcsharp_channel_create(target, channelArgs);
+ return grpcsharp_insecure_channel_create(target, channelArgs);
}
public static ChannelSafeHandle CreateSecure(CredentialsSafeHandle credentials, string target, ChannelArgsSafeHandle channelArgs)
@@ -63,6 +66,13 @@ namespace Grpc.Core.Internal
return grpcsharp_secure_channel_create(credentials, target, channelArgs);
}
+ public CallSafeHandle CreateCall(CompletionRegistry registry, CompletionQueueSafeHandle cq, string method, string host, Timespec deadline)
+ {
+ var result = grpcsharp_channel_create_call(this, cq, method, host, deadline);
+ result.SetCompletionRegistry(registry);
+ return result;
+ }
+
protected override bool ReleaseHandle()
{
grpcsharp_channel_destroy(handle);
diff --git a/src/csharp/Grpc.Core/Internal/CompletionRegistry.cs b/src/csharp/Grpc.Core/Internal/CompletionRegistry.cs
index f6d8aa0600..2796c959a3 100644
--- a/src/csharp/Grpc.Core/Internal/CompletionRegistry.cs
+++ b/src/csharp/Grpc.Core/Internal/CompletionRegistry.cs
@@ -35,6 +35,7 @@ using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Runtime.InteropServices;
+using Grpc.Core.Logging;
using Grpc.Core.Utils;
namespace Grpc.Core.Internal
@@ -45,6 +46,8 @@ namespace Grpc.Core.Internal
internal class CompletionRegistry
{
+ static readonly ILogger Logger = GrpcEnvironment.Logger.ForType<CompletionRegistry>();
+
readonly GrpcEnvironment environment;
readonly ConcurrentDictionary<IntPtr, OpCompletionDelegate> dict = new ConcurrentDictionary<IntPtr, OpCompletionDelegate>();
@@ -81,7 +84,7 @@ namespace Grpc.Core.Internal
}
catch (Exception e)
{
- Console.WriteLine("Exception occured while invoking completion delegate: " + e);
+ Logger.Error(e, "Exception occured while invoking completion delegate.");
}
finally
{
diff --git a/src/csharp/Grpc.Core/Internal/CredentialsSafeHandle.cs b/src/csharp/Grpc.Core/Internal/CredentialsSafeHandle.cs
index f361199068..8b4fa85e5d 100644
--- a/src/csharp/Grpc.Core/Internal/CredentialsSafeHandle.cs
+++ b/src/csharp/Grpc.Core/Internal/CredentialsSafeHandle.cs
@@ -50,9 +50,23 @@ namespace Grpc.Core.Internal
{
}
- public static CredentialsSafeHandle CreateSslCredentials(string pemRootCerts)
+ public static CredentialsSafeHandle CreateNullCredentials()
{
- return grpcsharp_ssl_credentials_create(pemRootCerts, null, null);
+ var creds = new CredentialsSafeHandle();
+ creds.SetHandle(IntPtr.Zero);
+ return creds;
+ }
+
+ public static CredentialsSafeHandle CreateSslCredentials(string pemRootCerts, KeyCertificatePair keyCertPair)
+ {
+ if (keyCertPair != null)
+ {
+ return grpcsharp_ssl_credentials_create(pemRootCerts, keyCertPair.CertificateChain, keyCertPair.PrivateKey);
+ }
+ else
+ {
+ return grpcsharp_ssl_credentials_create(pemRootCerts, null, null);
+ }
}
protected override bool ReleaseHandle()
diff --git a/src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs b/src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs
index b77e893044..cb4c7c821e 100644
--- a/src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs
+++ b/src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs
@@ -36,7 +36,7 @@ using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
-using Grpc.Core.Internal;
+using Grpc.Core.Logging;
namespace Grpc.Core.Internal
{
@@ -45,6 +45,8 @@ namespace Grpc.Core.Internal
/// </summary>
internal class GrpcThreadPool
{
+ static readonly ILogger Logger = GrpcEnvironment.Logger.ForType<GrpcThreadPool>();
+
readonly GrpcEnvironment environment;
readonly object myLock = new object();
readonly List<Thread> threads = new List<Thread>();
@@ -82,7 +84,7 @@ namespace Grpc.Core.Internal
{
cq.Shutdown();
- Console.WriteLine("Waiting for GRPC threads to finish.");
+ Logger.Info("Waiting for GRPC threads to finish.");
foreach (var thread in threads)
{
thread.Join();
@@ -129,12 +131,12 @@ namespace Grpc.Core.Internal
}
catch (Exception e)
{
- Console.WriteLine("Exception occured while invoking completion delegate: " + e);
+ Logger.Error(e, "Exception occured while invoking completion delegate");
}
}
}
while (ev.type != GRPCCompletionType.Shutdown);
- Console.WriteLine("Completion queue has shutdown successfully, thread " + Thread.CurrentThread.Name + " exiting.");
+ Logger.Info("Completion queue has shutdown successfully, thread {0} exiting.", Thread.CurrentThread.Name);
}
}
}
diff --git a/src/csharp/Grpc.Core/Internal/GrpcLog.cs b/src/csharp/Grpc.Core/Internal/NativeLogRedirector.cs
index 2f3c8ad71c..b8a55c5fe8 100644
--- a/src/csharp/Grpc.Core/Internal/GrpcLog.cs
+++ b/src/csharp/Grpc.Core/Internal/NativeLogRedirector.cs
@@ -44,30 +44,26 @@ namespace Grpc.Core.Internal
/// <summary>
/// Logs from gRPC C core library can get lost if your application is not a console app.
- /// This class allows redirection of logs to arbitrary destination.
+ /// This class allows redirection of logs to gRPC logger.
/// </summary>
- internal static class GrpcLog
+ internal static class NativeLogRedirector
{
static object staticLock = new object();
static GprLogDelegate writeCallback;
- static TextWriter dest;
[DllImport("grpc_csharp_ext.dll")]
static extern void grpcsharp_redirect_log(GprLogDelegate callback);
/// <summary>
- /// Sets text writer as destination for logs from native gRPC C core library.
- /// Only first invocation has effect.
+ /// Redirects logs from native gRPC C core library to a general logger.
/// </summary>
- /// <param name="textWriter"></param>
- public static void RedirectNativeLogs(TextWriter textWriter)
+ public static void Redirect()
{
lock (staticLock)
{
if (writeCallback == null)
{
writeCallback = new GprLogDelegate(HandleWrite);
- dest = textWriter;
grpcsharp_redirect_log(writeCallback);
}
}
@@ -77,13 +73,30 @@ namespace Grpc.Core.Internal
{
try
{
- // TODO: DateTime format used here is different than in C core.
- dest.WriteLine(string.Format("{0}{1} {2} {3}:{4}: {5}",
- Marshal.PtrToStringAnsi(severityStringPtr), DateTime.Now,
+ var logger = GrpcEnvironment.Logger;
+ string severityString = Marshal.PtrToStringAnsi(severityStringPtr);
+ string message = string.Format("{0} {1}:{2}: {3}",
threadId,
Marshal.PtrToStringAnsi(fileStringPtr),
line,
- Marshal.PtrToStringAnsi(msgPtr)));
+ Marshal.PtrToStringAnsi(msgPtr));
+
+ switch (severityString)
+ {
+ case "D":
+ logger.Debug(message);
+ break;
+ case "I":
+ logger.Info(message);
+ break;
+ case "E":
+ logger.Error(message);
+ break;
+ default:
+ // severity not recognized, default to error.
+ logger.Error(message);
+ break;
+ }
}
catch (Exception e)
{
diff --git a/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs b/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs
index 3680b1e791..19f0e3c57f 100644
--- a/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs
+++ b/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs
@@ -37,6 +37,7 @@ using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Grpc.Core.Internal;
+using Grpc.Core.Logging;
using Grpc.Core.Utils;
namespace Grpc.Core.Internal
@@ -50,6 +51,8 @@ namespace Grpc.Core.Internal
where TRequest : class
where TResponse : class
{
+ static readonly ILogger Logger = GrpcEnvironment.Logger.ForType<UnaryServerCallHandler<TRequest, TResponse>>();
+
readonly Method<TRequest, TResponse> method;
readonly UnaryServerMethod<TRequest, TResponse> handler;
@@ -72,7 +75,7 @@ namespace Grpc.Core.Internal
var responseStream = new ServerResponseStream<TRequest, TResponse>(asyncCall);
Status status;
- var context = HandlerUtils.NewContext(newRpc);
+ var context = HandlerUtils.NewContext(newRpc, asyncCall.Peer, asyncCall.CancellationToken);
try
{
Preconditions.CheckArgument(await requestStream.MoveNext());
@@ -85,7 +88,7 @@ namespace Grpc.Core.Internal
}
catch (Exception e)
{
- Console.WriteLine("Exception occured in handler: " + e);
+ Logger.Error(e, "Exception occured in handler.");
status = HandlerUtils.StatusFromException(e);
}
try
@@ -104,6 +107,8 @@ namespace Grpc.Core.Internal
where TRequest : class
where TResponse : class
{
+ static readonly ILogger Logger = GrpcEnvironment.Logger.ForType<ServerStreamingServerCallHandler<TRequest, TResponse>>();
+
readonly Method<TRequest, TResponse> method;
readonly ServerStreamingServerMethod<TRequest, TResponse> handler;
@@ -126,7 +131,7 @@ namespace Grpc.Core.Internal
var responseStream = new ServerResponseStream<TRequest, TResponse>(asyncCall);
Status status;
- var context = HandlerUtils.NewContext(newRpc);
+ var context = HandlerUtils.NewContext(newRpc, asyncCall.Peer, asyncCall.CancellationToken);
try
{
Preconditions.CheckArgument(await requestStream.MoveNext());
@@ -138,7 +143,7 @@ namespace Grpc.Core.Internal
}
catch (Exception e)
{
- Console.WriteLine("Exception occured in handler: " + e);
+ Logger.Error(e, "Exception occured in handler.");
status = HandlerUtils.StatusFromException(e);
}
@@ -158,6 +163,8 @@ namespace Grpc.Core.Internal
where TRequest : class
where TResponse : class
{
+ static readonly ILogger Logger = GrpcEnvironment.Logger.ForType<ClientStreamingServerCallHandler<TRequest, TResponse>>();
+
readonly Method<TRequest, TResponse> method;
readonly ClientStreamingServerMethod<TRequest, TResponse> handler;
@@ -180,7 +187,7 @@ namespace Grpc.Core.Internal
var responseStream = new ServerResponseStream<TRequest, TResponse>(asyncCall);
Status status;
- var context = HandlerUtils.NewContext(newRpc);
+ var context = HandlerUtils.NewContext(newRpc, asyncCall.Peer, asyncCall.CancellationToken);
try
{
var result = await handler(requestStream, context);
@@ -196,7 +203,7 @@ namespace Grpc.Core.Internal
}
catch (Exception e)
{
- Console.WriteLine("Exception occured in handler: " + e);
+ Logger.Error(e, "Exception occured in handler.");
status = HandlerUtils.StatusFromException(e);
}
@@ -216,6 +223,8 @@ namespace Grpc.Core.Internal
where TRequest : class
where TResponse : class
{
+ static readonly ILogger Logger = GrpcEnvironment.Logger.ForType<DuplexStreamingServerCallHandler<TRequest, TResponse>>();
+
readonly Method<TRequest, TResponse> method;
readonly DuplexStreamingServerMethod<TRequest, TResponse> handler;
@@ -238,7 +247,7 @@ namespace Grpc.Core.Internal
var responseStream = new ServerResponseStream<TRequest, TResponse>(asyncCall);
Status status;
- var context = HandlerUtils.NewContext(newRpc);
+ var context = HandlerUtils.NewContext(newRpc, asyncCall.Peer, asyncCall.CancellationToken);
try
{
await handler(requestStream, responseStream, context);
@@ -246,7 +255,7 @@ namespace Grpc.Core.Internal
}
catch (Exception e)
{
- Console.WriteLine("Exception occured in handler: " + e);
+ Logger.Error(e, "Exception occured in handler.");
status = HandlerUtils.StatusFromException(e);
}
try
@@ -295,11 +304,13 @@ namespace Grpc.Core.Internal
return new Status(StatusCode.Unknown, "Exception was thrown by handler.");
}
- public static ServerCallContext NewContext(ServerRpcNew newRpc)
+ public static ServerCallContext NewContext(ServerRpcNew newRpc, string peer, CancellationToken cancellationToken)
{
+ DateTime realtimeDeadline = newRpc.Deadline.ToClockType(GPRClockType.Realtime).ToDateTime();
+
return new ServerCallContext(
- newRpc.Method, newRpc.Host, newRpc.Deadline.ToDateTime(),
- newRpc.RequestMetadata, CancellationToken.None);
+ newRpc.Method, newRpc.Host, peer, realtimeDeadline,
+ newRpc.RequestMetadata, cancellationToken);
}
}
}
diff --git a/src/csharp/Grpc.Core/Internal/ServerCredentialsSafeHandle.cs b/src/csharp/Grpc.Core/Internal/ServerCredentialsSafeHandle.cs
index 961180741a..59238a452c 100644
--- a/src/csharp/Grpc.Core/Internal/ServerCredentialsSafeHandle.cs
+++ b/src/csharp/Grpc.Core/Internal/ServerCredentialsSafeHandle.cs
@@ -51,10 +51,10 @@ namespace Grpc.Core.Internal
{
}
- public static ServerCredentialsSafeHandle CreateSslCredentials(string[] keyCertPairCertChainArray, string[] keyCertPairPrivateKeyArray)
+ public static ServerCredentialsSafeHandle CreateSslCredentials(string pemRootCerts, string[] keyCertPairCertChainArray, string[] keyCertPairPrivateKeyArray)
{
Preconditions.CheckArgument(keyCertPairCertChainArray.Length == keyCertPairPrivateKeyArray.Length);
- return grpcsharp_ssl_server_credentials_create(null,
+ return grpcsharp_ssl_server_credentials_create(pemRootCerts,
keyCertPairCertChainArray, keyCertPairPrivateKeyArray,
new UIntPtr((ulong)keyCertPairCertChainArray.Length));
}
diff --git a/src/csharp/Grpc.Core/Internal/ServerSafeHandle.cs b/src/csharp/Grpc.Core/Internal/ServerSafeHandle.cs
index 9e1170e6dd..f9b44b1acf 100644
--- a/src/csharp/Grpc.Core/Internal/ServerSafeHandle.cs
+++ b/src/csharp/Grpc.Core/Internal/ServerSafeHandle.cs
@@ -48,7 +48,7 @@ namespace Grpc.Core.Internal
static extern ServerSafeHandle grpcsharp_server_create(CompletionQueueSafeHandle cq, ChannelArgsSafeHandle args);
[DllImport("grpc_csharp_ext.dll")]
- static extern int grpcsharp_server_add_http2_port(ServerSafeHandle server, string addr);
+ static extern int grpcsharp_server_add_insecure_http2_port(ServerSafeHandle server, string addr);
[DllImport("grpc_csharp_ext.dll")]
static extern int grpcsharp_server_add_secure_http2_port(ServerSafeHandle server, string addr, ServerCredentialsSafeHandle creds);
@@ -77,12 +77,12 @@ namespace Grpc.Core.Internal
return grpcsharp_server_create(cq, args);
}
- public int AddListeningPort(string addr)
+ public int AddInsecurePort(string addr)
{
- return grpcsharp_server_add_http2_port(this, addr);
+ return grpcsharp_server_add_insecure_http2_port(this, addr);
}
- public int AddListeningPort(string addr, ServerCredentialsSafeHandle credentials)
+ public int AddSecurePort(string addr, ServerCredentialsSafeHandle credentials)
{
return grpcsharp_server_add_secure_http2_port(this, addr, credentials);
}
diff --git a/src/csharp/Grpc.Core/Internal/Timespec.cs b/src/csharp/Grpc.Core/Internal/Timespec.cs
index da2819f14d..e83d21f4a4 100644
--- a/src/csharp/Grpc.Core/Internal/Timespec.cs
+++ b/src/csharp/Grpc.Core/Internal/Timespec.cs
@@ -32,6 +32,8 @@ using System;
using System.Runtime.InteropServices;
using System.Threading;
+using Grpc.Core.Utils;
+
namespace Grpc.Core.Internal
{
/// <summary>
@@ -40,32 +42,43 @@ namespace Grpc.Core.Internal
[StructLayout(LayoutKind.Sequential)]
internal struct Timespec
{
- const int NanosPerSecond = 1000 * 1000 * 1000;
- const int NanosPerTick = 100;
+ const long NanosPerSecond = 1000 * 1000 * 1000;
+ const long NanosPerTick = 100;
+ const long TicksPerSecond = NanosPerSecond / NanosPerTick;
static readonly DateTime UnixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
[DllImport("grpc_csharp_ext.dll")]
- static extern Timespec gprsharp_now();
+ static extern Timespec gprsharp_now(GPRClockType clockType);
+
+ [DllImport("grpc_csharp_ext.dll")]
+ static extern Timespec gprsharp_inf_future(GPRClockType clockType);
+
+ [DllImport("grpc_csharp_ext.dll")]
+ static extern Timespec gprsharp_inf_past(GPRClockType clockType);
[DllImport("grpc_csharp_ext.dll")]
- static extern Timespec gprsharp_inf_future();
+ static extern Timespec gprsharp_convert_clock_type(Timespec t, GPRClockType targetClock);
[DllImport("grpc_csharp_ext.dll")]
static extern int gprsharp_sizeof_timespec();
- public Timespec(IntPtr tv_sec, int tv_nsec)
+ public Timespec(IntPtr tv_sec, int tv_nsec) : this(tv_sec, tv_nsec, GPRClockType.Realtime)
+ {
+ }
+
+ public Timespec(IntPtr tv_sec, int tv_nsec, GPRClockType clock_type)
{
this.tv_sec = tv_sec;
this.tv_nsec = tv_nsec;
- this.clock_type = GPRClockType.Realtime;
+ this.clock_type = clock_type;
}
// NOTE: on linux 64bit sizeof(gpr_timespec) = 16, on windows 32bit sizeof(gpr_timespec) = 8
// so IntPtr seems to have the right size to work on both.
- public System.IntPtr tv_sec;
- public int tv_nsec;
- public GPRClockType clock_type;
+ private System.IntPtr tv_sec;
+ private int tv_nsec;
+ private GPRClockType clock_type;
/// <summary>
/// Timespec a long time in the future.
@@ -74,54 +87,164 @@ namespace Grpc.Core.Internal
{
get
{
- return gprsharp_inf_future();
+ return gprsharp_inf_future(GPRClockType.Realtime);
+ }
+ }
+
+ /// <summary>
+ /// Timespec a long time in the past.
+ /// </summary>
+ public static Timespec InfPast
+ {
+ get
+ {
+ return gprsharp_inf_past(GPRClockType.Realtime);
}
}
+ /// <summary>
+ /// Return Timespec representing the current time.
+ /// </summary>
public static Timespec Now
{
get
{
- return gprsharp_now();
+ return gprsharp_now(GPRClockType.Realtime);
}
}
-
- public DateTime ToDateTime()
+
+ /// <summary>
+ /// Seconds since unix epoch.
+ /// </summary>
+ public IntPtr TimevalSeconds
{
- return UnixEpoch.AddTicks(tv_sec.ToInt64() * (NanosPerSecond / NanosPerTick) + tv_nsec / NanosPerTick);
+ get
+ {
+ return tv_sec;
+ }
}
- internal static int NativeSize
+ /// <summary>
+ /// The nanoseconds part of timeval.
+ /// </summary>
+ public int TimevalNanos
{
get
{
- return gprsharp_sizeof_timespec();
+ return tv_nsec;
}
}
/// <summary>
- /// Creates a GPR deadline from current instant and given timeout.
+ /// Converts the timespec to desired clock type.
/// </summary>
- /// <returns>The from timeout.</returns>
- public static Timespec DeadlineFromTimeout(TimeSpan timeout)
+ public Timespec ToClockType(GPRClockType targetClock)
+ {
+ return gprsharp_convert_clock_type(this, targetClock);
+ }
+
+ /// <summary>
+ /// Converts Timespec to DateTime.
+ /// Timespec needs to be of type GPRClockType.Realtime and needs to represent a legal value.
+ /// DateTime has lower resolution (100ns), so rounding can occurs.
+ /// Value are always rounded up to the nearest DateTime value in the future.
+ ///
+ /// For Timespec.InfFuture or if timespec is after the largest representable DateTime, DateTime.MaxValue is returned.
+ /// For Timespec.InfPast or if timespec is before the lowest representable DateTime, DateTime.MinValue is returned.
+ ///
+ /// Unless DateTime.MaxValue or DateTime.MinValue is returned, the resulting DateTime is always in UTC
+ /// (DateTimeKind.Utc)
+ /// </summary>
+ public DateTime ToDateTime()
{
- if (timeout == Timeout.InfiniteTimeSpan)
+ Preconditions.CheckState(tv_nsec >= 0 && tv_nsec < NanosPerSecond);
+ Preconditions.CheckState(clock_type == GPRClockType.Realtime);
+
+ // fast path for InfFuture
+ if (this.Equals(InfFuture))
+ {
+ return DateTime.MaxValue;
+ }
+
+ // fast path for InfPast
+ if (this.Equals(InfPast))
+ {
+ return DateTime.MinValue;
+ }
+
+ try
+ {
+ // convert nanos to ticks, round up to the nearest tick
+ long ticksFromNanos = tv_nsec / NanosPerTick + ((tv_nsec % NanosPerTick != 0) ? 1 : 0);
+ long ticksTotal = checked(tv_sec.ToInt64() * TicksPerSecond + ticksFromNanos);
+ return UnixEpoch.AddTicks(ticksTotal);
+ }
+ catch (OverflowException)
+ {
+ // ticks out of long range
+ return tv_sec.ToInt64() > 0 ? DateTime.MaxValue : DateTime.MinValue;
+ }
+ catch (ArgumentOutOfRangeException)
+ {
+ // resulting date time would be larger than MaxValue
+ return tv_sec.ToInt64() > 0 ? DateTime.MaxValue : DateTime.MinValue;
+ }
+ }
+
+ /// <summary>
+ /// Creates DateTime to Timespec.
+ /// DateTime has to be in UTC (DateTimeKind.Utc) unless it's DateTime.MaxValue or DateTime.MinValue.
+ /// For DateTime.MaxValue of date time after the largest representable Timespec, Timespec.InfFuture is returned.
+ /// For DateTime.MinValue of date time before the lowest representable Timespec, Timespec.InfPast is returned.
+ /// </summary>
+ /// <returns>The date time.</returns>
+ /// <param name="dateTime">Date time.</param>
+ public static Timespec FromDateTime(DateTime dateTime)
+ {
+ if (dateTime == DateTime.MaxValue)
{
return Timespec.InfFuture;
}
- return Timespec.Now.Add(timeout);
+
+ if (dateTime == DateTime.MinValue)
+ {
+ return Timespec.InfPast;
+ }
+
+ Preconditions.CheckArgument(dateTime.Kind == DateTimeKind.Utc, "dateTime");
+
+ try
+ {
+ TimeSpan timeSpan = dateTime - UnixEpoch;
+ long ticks = timeSpan.Ticks;
+
+ long seconds = ticks / TicksPerSecond;
+ int nanos = (int)((ticks % TicksPerSecond) * NanosPerTick);
+ if (nanos < 0)
+ {
+ // correct the result based on C# modulo semantics for negative dividend
+ seconds--;
+ nanos += (int)NanosPerSecond;
+ }
+ // new IntPtr possibly throws OverflowException
+ return new Timespec(new IntPtr(seconds), nanos);
+ }
+ catch (OverflowException)
+ {
+ return dateTime > UnixEpoch ? Timespec.InfFuture : Timespec.InfPast;
+ }
+ catch (ArgumentOutOfRangeException)
+ {
+ return dateTime > UnixEpoch ? Timespec.InfFuture : Timespec.InfPast;
+ }
}
- public Timespec Add(TimeSpan timeSpan)
+ internal static int NativeSize
{
- long nanos = (long)tv_nsec + (timeSpan.Ticks % TimeSpan.TicksPerSecond) * NanosPerTick;
- long overflow_sec = (nanos > NanosPerSecond) ? 1 : 0;
-
- Timespec result;
- result.tv_nsec = (int)(nanos % NanosPerSecond);
- result.tv_sec = new IntPtr(tv_sec.ToInt64() + (timeSpan.Ticks / TimeSpan.TicksPerSecond) + overflow_sec);
- result.clock_type = GPRClockType.Realtime;
- return result;
+ get
+ {
+ return gprsharp_sizeof_timespec();
+ }
}
}
}
diff --git a/src/csharp/Grpc.Core/KeyCertificatePair.cs b/src/csharp/Grpc.Core/KeyCertificatePair.cs
new file mode 100644
index 0000000000..7cea18618e
--- /dev/null
+++ b/src/csharp/Grpc.Core/KeyCertificatePair.cs
@@ -0,0 +1,84 @@
+#region Copyright notice and license
+
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Collections.Immutable;
+
+using Grpc.Core.Internal;
+using Grpc.Core.Utils;
+
+namespace Grpc.Core
+{
+ /// <summary>
+ /// Key certificate pair (in PEM encoding).
+ /// </summary>
+ public sealed class KeyCertificatePair
+ {
+ readonly string certificateChain;
+ readonly string privateKey;
+
+ /// <summary>
+ /// Creates a new certificate chain - private key pair.
+ /// </summary>
+ /// <param name="certificateChain">PEM encoded certificate chain.</param>
+ /// <param name="privateKey">PEM encoded private key.</param>
+ public KeyCertificatePair(string certificateChain, string privateKey)
+ {
+ this.certificateChain = Preconditions.CheckNotNull(certificateChain);
+ this.privateKey = Preconditions.CheckNotNull(privateKey);
+ }
+
+ /// <summary>
+ /// PEM encoded certificate chain.
+ /// </summary>
+ public string CertificateChain
+ {
+ get
+ {
+ return certificateChain;
+ }
+ }
+
+ /// <summary>
+ /// PEM encoded private key.
+ /// </summary>
+ public string PrivateKey
+ {
+ get
+ {
+ return privateKey;
+ }
+ }
+ }
+}
diff --git a/src/csharp/Grpc.Core/Logging/ConsoleLogger.cs b/src/csharp/Grpc.Core/Logging/ConsoleLogger.cs
new file mode 100644
index 0000000000..c67765c78d
--- /dev/null
+++ b/src/csharp/Grpc.Core/Logging/ConsoleLogger.cs
@@ -0,0 +1,103 @@
+#region Copyright notice and license
+
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#endregion
+
+using System;
+using System.Collections.Generic;
+
+namespace Grpc.Core.Logging
+{
+ /// <summary>Logger that logs to System.Console.</summary>
+ public class ConsoleLogger : ILogger
+ {
+ readonly Type forType;
+ readonly string forTypeString;
+
+ public ConsoleLogger() : this(null)
+ {
+ }
+
+ private ConsoleLogger(Type forType)
+ {
+ this.forType = forType;
+ this.forTypeString = forType != null ? forType.FullName + " " : "";
+ }
+
+ public ILogger ForType<T>()
+ {
+ if (typeof(T) == forType)
+ {
+ return this;
+ }
+ return new ConsoleLogger(typeof(T));
+ }
+
+ public void Debug(string message, params object[] formatArgs)
+ {
+ Log("D", message, formatArgs);
+ }
+
+ public void Info(string message, params object[] formatArgs)
+ {
+ Log("I", message, formatArgs);
+ }
+
+ public void Warning(string message, params object[] formatArgs)
+ {
+ Log("W", message, formatArgs);
+ }
+
+ public void Warning(Exception exception, string message, params object[] formatArgs)
+ {
+ Log("W", message + " " + exception, formatArgs);
+ }
+
+ public void Error(string message, params object[] formatArgs)
+ {
+ Log("E", message, formatArgs);
+ }
+
+ public void Error(Exception exception, string message, params object[] formatArgs)
+ {
+ Log("E", message + " " + exception, formatArgs);
+ }
+
+ private void Log(string severityString, string message, object[] formatArgs)
+ {
+ Console.Error.WriteLine("{0}{1} {2}{3}",
+ severityString,
+ DateTime.Now,
+ forTypeString,
+ string.Format(message, formatArgs));
+ }
+ }
+}
diff --git a/src/csharp/Grpc.Core/Logging/ILogger.cs b/src/csharp/Grpc.Core/Logging/ILogger.cs
new file mode 100644
index 0000000000..0d58f133e3
--- /dev/null
+++ b/src/csharp/Grpc.Core/Logging/ILogger.cs
@@ -0,0 +1,57 @@
+#region Copyright notice and license
+
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#endregion
+
+using System;
+using System.Collections.Generic;
+
+namespace Grpc.Core.Logging
+{
+ /// <summary>For logging messages.</summary>
+ public interface ILogger
+ {
+ /// <summary>Returns a logger associated with the specified type.</summary>
+ ILogger ForType<T>();
+
+ void Debug(string message, params object[] formatArgs);
+
+ void Info(string message, params object[] formatArgs);
+
+ void Warning(string message, params object[] formatArgs);
+
+ void Warning(Exception exception, string message, params object[] formatArgs);
+
+ void Error(string message, params object[] formatArgs);
+
+ void Error(Exception exception, string message, params object[] formatArgs);
+ }
+}
diff --git a/src/csharp/Grpc.Core/Server.cs b/src/csharp/Grpc.Core/Server.cs
index fd30735359..3217547cc4 100644
--- a/src/csharp/Grpc.Core/Server.cs
+++ b/src/csharp/Grpc.Core/Server.cs
@@ -38,6 +38,7 @@ using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using Grpc.Core.Internal;
+using Grpc.Core.Logging;
using Grpc.Core.Utils;
namespace Grpc.Core
@@ -52,6 +53,8 @@ namespace Grpc.Core
/// </summary>
public const int PickUnusedPort = 0;
+ static readonly ILogger Logger = GrpcEnvironment.Logger.ForType<Server>();
+
readonly GrpcEnvironment environment;
readonly List<ChannelOption> options;
readonly ServerSafeHandle handle;
@@ -95,28 +98,31 @@ namespace Grpc.Core
}
/// <summary>
- /// Add a non-secure port on which server should listen.
+ /// Add a port on which server should listen.
/// Only call this before Start().
/// </summary>
/// <returns>The port on which server will be listening.</returns>
/// <param name="host">the host</param>
/// <param name="port">the port. If zero, an unused port is chosen automatically.</param>
- public int AddListeningPort(string host, int port)
+ public int AddPort(string host, int port, ServerCredentials credentials)
{
- return AddListeningPortInternal(host, port, null);
- }
-
- /// <summary>
- /// Add a non-secure port on which server should listen.
- /// Only call this before Start().
- /// </summary>
- /// <returns>The port on which server will be listening.</returns>
- /// <param name="host">the host</param>
- /// <param name="port">the port. If zero, an unused port is chosen automatically.</param>
- public int AddListeningPort(string host, int port, ServerCredentials credentials)
- {
- Preconditions.CheckNotNull(credentials);
- return AddListeningPortInternal(host, port, credentials);
+ lock (myLock)
+ {
+ Preconditions.CheckNotNull(credentials);
+ Preconditions.CheckState(!startRequested);
+ var address = string.Format("{0}:{1}", host, port);
+ using (var nativeCredentials = credentials.ToNativeCredentials())
+ {
+ if (nativeCredentials != null)
+ {
+ return handle.AddSecurePort(address, nativeCredentials);
+ }
+ else
+ {
+ return handle.AddInsecurePort(address);
+ }
+ }
+ }
}
/// <summary>
@@ -183,26 +189,6 @@ namespace Grpc.Core
handle.Dispose();
}
- private int AddListeningPortInternal(string host, int port, ServerCredentials credentials)
- {
- lock (myLock)
- {
- Preconditions.CheckState(!startRequested);
- var address = string.Format("{0}:{1}", host, port);
- if (credentials != null)
- {
- using (var nativeCredentials = credentials.ToNativeCredentials())
- {
- return handle.AddListeningPort(address, nativeCredentials);
- }
- }
- else
- {
- return handle.AddListeningPort(address);
- }
- }
- }
-
/// <summary>
/// Allows one new RPC call to be received by server.
/// </summary>
@@ -233,7 +219,7 @@ namespace Grpc.Core
}
catch (Exception e)
{
- Console.WriteLine("Exception while handling RPC: " + e);
+ Logger.Warning(e, "Exception while handling RPC.");
}
}
diff --git a/src/csharp/Grpc.Core/ServerCallContext.cs b/src/csharp/Grpc.Core/ServerCallContext.cs
index 17a2eefd07..0c48adaea5 100644
--- a/src/csharp/Grpc.Core/ServerCallContext.cs
+++ b/src/csharp/Grpc.Core/ServerCallContext.cs
@@ -47,6 +47,7 @@ namespace Grpc.Core
private readonly string method;
private readonly string host;
+ private readonly string peer;
private readonly DateTime deadline;
private readonly Metadata requestHeaders;
private readonly CancellationToken cancellationToken;
@@ -54,10 +55,11 @@ namespace Grpc.Core
private Status status = Status.DefaultSuccess;
- public ServerCallContext(string method, string host, DateTime deadline, Metadata requestHeaders, CancellationToken cancellationToken)
+ public ServerCallContext(string method, string host, string peer, DateTime deadline, Metadata requestHeaders, CancellationToken cancellationToken)
{
this.method = method;
this.host = host;
+ this.peer = peer;
this.deadline = deadline;
this.requestHeaders = requestHeaders;
this.cancellationToken = cancellationToken;
@@ -81,6 +83,15 @@ namespace Grpc.Core
}
}
+ /// <summary> Address of the remote endpoint in URI format. </summary>
+ public string Peer
+ {
+ get
+ {
+ return this.peer;
+ }
+ }
+
/// <summary> Deadline for this RPC. </summary>
public DateTime Deadline
{
diff --git a/src/csharp/Grpc.Core/ServerCredentials.cs b/src/csharp/Grpc.Core/ServerCredentials.cs
index ab7d0b4914..32ed4b78a1 100644
--- a/src/csharp/Grpc.Core/ServerCredentials.cs
+++ b/src/csharp/Grpc.Core/ServerCredentials.cs
@@ -35,6 +35,7 @@ using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using Grpc.Core.Internal;
+using Grpc.Core.Utils;
namespace Grpc.Core
{
@@ -43,67 +44,99 @@ namespace Grpc.Core
/// </summary>
public abstract class ServerCredentials
{
+ static readonly ServerCredentials InsecureInstance = new InsecureServerCredentialsImpl();
+
+ /// <summary>
+ /// Returns instance of credential that provides no security and
+ /// will result in creating an unsecure server port with no encryption whatsoever.
+ /// </summary>
+ public static ServerCredentials Insecure
+ {
+ get
+ {
+ return InsecureInstance;
+ }
+ }
+
/// <summary>
/// Creates native object for the credentials.
/// </summary>
/// <returns>The native credentials.</returns>
internal abstract ServerCredentialsSafeHandle ToNativeCredentials();
+
+ private sealed class InsecureServerCredentialsImpl : ServerCredentials
+ {
+ internal override ServerCredentialsSafeHandle ToNativeCredentials()
+ {
+ return null;
+ }
+ }
}
/// <summary>
- /// Key certificate pair (in PEM encoding).
+ /// Server-side SSL credentials.
/// </summary>
- public class KeyCertificatePair
+ public class SslServerCredentials : ServerCredentials
{
- readonly string certChain;
- readonly string privateKey;
+ readonly IList<KeyCertificatePair> keyCertificatePairs;
+ readonly string rootCertificates;
- public KeyCertificatePair(string certChain, string privateKey)
+ /// <summary>
+ /// Creates server-side SSL credentials.
+ /// </summary>
+ /// <param name="rootCertificates">PEM encoded client root certificates used to authenticate client.</param>
+ /// <param name="keyCertificatePairs">Key-certificates to use.</param>
+ public SslServerCredentials(IEnumerable<KeyCertificatePair> keyCertificatePairs, string rootCertificates)
{
- this.certChain = certChain;
- this.privateKey = privateKey;
+ this.keyCertificatePairs = new List<KeyCertificatePair>(keyCertificatePairs).AsReadOnly();
+ Preconditions.CheckArgument(this.keyCertificatePairs.Count > 0,
+ "At least one KeyCertificatePair needs to be provided");
+ this.rootCertificates = rootCertificates;
}
- public string CertChain
+ /// <summary>
+ /// Creates server-side SSL credentials.
+ /// This constructor should be use if you do not wish to autheticate client
+ /// using client root certificates.
+ /// </summary>
+ /// <param name="keyCertificatePairs">Key-certificates to use.</param>
+ public SslServerCredentials(IEnumerable<KeyCertificatePair> keyCertificatePairs) : this(keyCertificatePairs, null)
{
- get
- {
- return certChain;
- }
}
- public string PrivateKey
+ /// <summary>
+ /// Key-certificate pairs.
+ /// </summary>
+ public IList<KeyCertificatePair> KeyCertificatePairs
{
get
{
- return privateKey;
+ return this.keyCertificatePairs;
}
}
- }
-
- /// <summary>
- /// Server-side SSL credentials.
- /// </summary>
- public class SslServerCredentials : ServerCredentials
- {
- ImmutableList<KeyCertificatePair> keyCertPairs;
- public SslServerCredentials(ImmutableList<KeyCertificatePair> keyCertPairs)
+ /// <summary>
+ /// PEM encoded client root certificates.
+ /// </summary>
+ public string RootCertificates
{
- this.keyCertPairs = keyCertPairs;
+ get
+ {
+ return this.rootCertificates;
+ }
}
internal override ServerCredentialsSafeHandle ToNativeCredentials()
{
- int count = keyCertPairs.Count;
+ int count = keyCertificatePairs.Count;
string[] certChains = new string[count];
string[] keys = new string[count];
for (int i = 0; i < count; i++)
{
- certChains[i] = keyCertPairs[i].CertChain;
- keys[i] = keyCertPairs[i].PrivateKey;
+ certChains[i] = keyCertificatePairs[i].CertificateChain;
+ keys[i] = keyCertificatePairs[i].PrivateKey;
}
- return ServerCredentialsSafeHandle.CreateSslCredentials(certChains, keys);
+ return ServerCredentialsSafeHandle.CreateSslCredentials(rootCertificates, certChains, keys);
}
}
}
diff --git a/src/csharp/Grpc.Core/Utils/BenchmarkUtil.cs b/src/csharp/Grpc.Core/Utils/BenchmarkUtil.cs
index 4180d98938..82653c3a1f 100644
--- a/src/csharp/Grpc.Core/Utils/BenchmarkUtil.cs
+++ b/src/csharp/Grpc.Core/Utils/BenchmarkUtil.cs
@@ -46,13 +46,15 @@ namespace Grpc.Core.Utils
/// </summary>
public static void RunBenchmark(int warmupIterations, int benchmarkIterations, Action action)
{
- Console.WriteLine("Warmup iterations: " + warmupIterations);
+ var logger = GrpcEnvironment.Logger;
+
+ logger.Info("Warmup iterations: {0}", warmupIterations);
for (int i = 0; i < warmupIterations; i++)
{
action();
}
- Console.WriteLine("Benchmark iterations: " + benchmarkIterations);
+ logger.Info("Benchmark iterations: {0}", benchmarkIterations);
var stopwatch = new Stopwatch();
stopwatch.Start();
for (int i = 0; i < benchmarkIterations; i++)
@@ -60,8 +62,8 @@ namespace Grpc.Core.Utils
action();
}
stopwatch.Stop();
- Console.WriteLine("Elapsed time: " + stopwatch.ElapsedMilliseconds + "ms");
- Console.WriteLine("Ops per second: " + (int)((double)benchmarkIterations * 1000 / stopwatch.ElapsedMilliseconds));
+ logger.Info("Elapsed time: {0}ms", stopwatch.ElapsedMilliseconds);
+ logger.Info("Ops per second: {0}", (int)((double)benchmarkIterations * 1000 / stopwatch.ElapsedMilliseconds));
}
}
}