changed the way ports are added to the server

pull/2797/head
Jan Tattermusch 10 years ago
parent 021df8a7f2
commit 31ba063224
  1. 8
      src/csharp/Grpc.Core.Tests/ClientServerTest.cs
  2. 39
      src/csharp/Grpc.Core.Tests/ServerTest.cs
  3. 8
      src/csharp/Grpc.Core.Tests/TimeoutsTest.cs
  4. 1
      src/csharp/Grpc.Core/Grpc.Core.csproj
  5. 107
      src/csharp/Grpc.Core/Server.cs
  6. 120
      src/csharp/Grpc.Core/ServerPort.cs
  7. 11
      src/csharp/Grpc.Examples.MathServer/MathServer.cs
  8. 18
      src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs
  9. 8
      src/csharp/Grpc.HealthCheck.Tests/HealthClientServerTest.cs
  10. 12
      src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs
  11. 4
      src/csharp/Grpc.IntegrationTesting/InteropServer.cs
  12. 9
      src/csharp/Grpc.IntegrationTesting/SslCredentialsTest.cs

@ -77,13 +77,13 @@ namespace Grpc.Core.Tests
[SetUp]
public void Init()
{
server = new Server()
server = new Server
{
Services = { ServiceDefinition }
Services = { ServiceDefinition },
Ports = { { Host, ServerPort.PickUnused, ServerCredentials.Insecure } }
};
int port = server.AddPort(Host, Server.PickUnusedPort, ServerCredentials.Insecure);
server.Start();
channel = new Channel(Host, port, Credentials.Insecure);
channel = new Channel(Host, server.Ports.Single().BoundPort, Credentials.Insecure);
}
[TearDown]

@ -32,6 +32,7 @@
#endregion
using System;
using System.Linq;
using Grpc.Core;
using Grpc.Core.Internal;
using Grpc.Core.Utils;
@ -44,11 +45,45 @@ namespace Grpc.Core.Tests
[Test]
public void StartAndShutdownServer()
{
Server server = new Server();
server.AddPort("localhost", Server.PickUnusedPort, ServerCredentials.Insecure);
Server server = new Server
{
Ports = { new ServerPort("localhost", ServerPort.PickUnused, ServerCredentials.Insecure) }
};
server.Start();
server.ShutdownAsync().Wait();
GrpcEnvironment.Shutdown();
}
[Test]
public void PickUnusedPort()
{
Server server = new Server
{
Ports = { new ServerPort("localhost", ServerPort.PickUnused, ServerCredentials.Insecure) }
};
var boundPort = server.Ports.Single();
Assert.AreEqual(0, boundPort.Port);
Assert.Greater(boundPort.BoundPort, 0);
server.Start();
server.ShutdownAsync();
GrpcEnvironment.Shutdown();
}
[Test]
public void CannotModifyAfterStarted()
{
Server server = new Server
{
Ports = { new ServerPort("localhost", ServerPort.PickUnused, ServerCredentials.Insecure) }
};
server.Start();
Assert.Throws(typeof(InvalidOperationException), () => server.Ports.Add("localhost", 9999, ServerCredentials.Insecure));
Assert.Throws(typeof(InvalidOperationException), () => server.Services.Add(ServerServiceDefinition.CreateBuilder("serviceName").Build()));
server.ShutdownAsync().Wait();
GrpcEnvironment.Shutdown();
}
}
}

@ -70,13 +70,13 @@ namespace Grpc.Core.Tests
[SetUp]
public void Init()
{
server = new Server()
server = new Server
{
Services = { ServiceDefinition }
Services = { ServiceDefinition },
Ports = { { Host, ServerPort.PickUnused, ServerCredentials.Insecure } }
};
int port = server.AddPort(Host, Server.PickUnusedPort, ServerCredentials.Insecure);
server.Start();
channel = new Channel(Host, port, Credentials.Insecure);
channel = new Channel(Host, server.Ports.Single().BoundPort, Credentials.Insecure);
stringFromServerHandlerTcs = new TaskCompletionSource<string>();
}

@ -52,6 +52,7 @@
<Compile Include="IServerStreamWriter.cs" />
<Compile Include="IAsyncStreamWriter.cs" />
<Compile Include="IAsyncStreamReader.cs" />
<Compile Include="ServerPort.cs" />
<Compile Include="Version.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="RpcException.cs" />

@ -48,20 +48,17 @@ namespace Grpc.Core
/// </summary>
public class Server
{
/// <summary>
/// Pass this value as port to have the server choose an unused listening port for you.
/// </summary>
public const int PickUnusedPort = 0;
static readonly ILogger Logger = GrpcEnvironment.Logger.ForType<Server>();
readonly ServiceDefinitionCollection serviceDefinitions;
readonly ServerPortCollection ports;
readonly GrpcEnvironment environment;
readonly List<ChannelOption> options;
readonly ServerSafeHandle handle;
readonly object myLock = new object();
readonly List<ServerServiceDefinition> serviceDefinitionsList = new List<ServerServiceDefinition>();
readonly List<ServerPort> serverPortList = new List<ServerPort>();
readonly Dictionary<string, IServerCallHandler> callHandlers = new Dictionary<string, IServerCallHandler>();
readonly TaskCompletionSource<object> shutdownTcs = new TaskCompletionSource<object>();
@ -75,6 +72,7 @@ namespace Grpc.Core
public Server(IEnumerable<ChannelOption> options = null)
{
this.serviceDefinitions = new ServiceDefinitionCollection(this);
this.ports = new ServerPortCollection(this);
this.environment = GrpcEnvironment.GetInstance();
this.options = options != null ? new List<ChannelOption>(options) : new List<ChannelOption>();
using (var channelArgs = ChannelOptions.CreateChannelArgs(this.options))
@ -96,30 +94,14 @@ namespace Grpc.Core
}
/// <summary>
/// Add a port on which server should listen.
/// Only call this before Start().
/// Ports on which the server will listen once started. Register a port with this
/// server by adding its definition to this collection.
/// </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 AddPort(string host, int port, ServerCredentials credentials)
public ServerPortCollection Ports
{
lock (myLock)
get
{
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);
}
}
return ports;
}
}
@ -203,6 +185,34 @@ namespace Grpc.Core
}
}
/// <summary>
/// Adds a listening port.
/// </summary>
private int AddPortInternal(ServerPort serverPort)
{
lock (myLock)
{
Preconditions.CheckNotNull(serverPort.Credentials);
Preconditions.CheckState(!startRequested);
var address = string.Format("{0}:{1}", serverPort.Host, serverPort.Port);
int boundPort;
using (var nativeCredentials = serverPort.Credentials.ToNativeCredentials())
{
if (nativeCredentials != null)
{
boundPort = handle.AddSecurePort(address, nativeCredentials);
}
else
{
boundPort = handle.AddInsecurePort(address);
}
}
var newServerPort = new ServerPort(serverPort, boundPort);
this.serverPortList.Add(newServerPort);
return boundPort;
}
}
/// <summary>
/// Allows one new RPC call to be received by server.
/// </summary>
@ -295,5 +305,50 @@ namespace Grpc.Core
return server.serviceDefinitionsList.GetEnumerator();
}
}
/// <summary>
/// Collection of server ports.
/// </summary>
public class ServerPortCollection : IEnumerable<ServerPort>
{
readonly Server server;
internal ServerPortCollection(Server server)
{
this.server = server;
}
/// <summary>
/// Adds a new port on which server should listen.
/// Only call this before Start().
/// <returns>The port on which server will be listening.</returns>
/// </summary>
public int Add(ServerPort serverPort)
{
return server.AddPortInternal(serverPort);
}
/// <summary>
/// Adds a new port on which server should listen.
/// <returns>The port on which server will be listening.</returns>
/// </summary>
/// <param name="host">the host</param>
/// <param name="port">the port. If zero, an unused port is chosen automatically.</param>
/// <param name="credentials">credentials to use to secure this port.</param>
public int Add(string host, int port, ServerCredentials credentials)
{
return Add(new ServerPort(host, port, credentials));
}
public IEnumerator<ServerPort> GetEnumerator()
{
return server.serverPortList.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return server.serverPortList.GetEnumerator();
}
}
}
}

@ -0,0 +1,120 @@
#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 Grpc.Core.Utils;
namespace Grpc.Core
{
/// <summary>
/// A port exposed by a server.
/// </summary>
public class ServerPort
{
/// <summary>
/// Pass this value as port to have the server choose an unused listening port for you.
/// Ports added to a server will contain the bound port in their <see cref="BoundPort"/> property.
/// </summary>
public const int PickUnused = 0;
readonly string host;
readonly int port;
readonly ServerCredentials credentials;
readonly int boundPort;
/// <summary>
/// Creates a new port on which server should listen.
/// </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>
/// <param name="credentials">credentials to use to secure this port.</param>
public ServerPort(string host, int port, ServerCredentials credentials)
{
this.host = Preconditions.CheckNotNull(host);
this.port = port;
this.credentials = Preconditions.CheckNotNull(credentials);
}
/// <summary>
/// Creates a port from an existing <c>ServerPort</c> instance and boundPort value.
/// </summary>
internal ServerPort(ServerPort serverPort, int boundPort)
{
this.host = serverPort.host;
this.port = serverPort.port;
this.credentials = serverPort.credentials;
this.boundPort = boundPort;
}
/// <value>The host.</value>
public string Host
{
get
{
return host;
}
}
/// <value>The port.</value>
public int Port
{
get
{
return port;
}
}
/// <value>The server credentials.</value>
public ServerCredentials Credentials
{
get
{
return credentials;
}
}
/// <value>
/// The port actually bound by the server. This is useful if you let server
/// pick port automatically. <see cref="PickUnused"/>
/// </value>
public int BoundPort
{
get
{
return boundPort;
}
}
}
}

@ -38,18 +38,19 @@ namespace math
{
class MainClass
{
const string Host = "0.0.0.0";
const int Port = 23456;
public static void Main(string[] args)
{
string host = "0.0.0.0";
Server server = new Server()
Server server = new Server
{
Services = { Math.BindService(new MathServiceImpl()) },
Ports = { { Host, Port, ServerCredentials.Insecure } }
};
int port = server.AddPort(host, 23456, ServerCredentials.Insecure);
server.Start();
Console.WriteLine("MathServer listening on port " + port);
Console.WriteLine("MathServer listening on port " + Port);
Console.WriteLine("Press any key to stop the server...");
Console.ReadKey();

@ -33,6 +33,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Grpc.Core;
@ -46,7 +47,7 @@ namespace math.Tests
/// </summary>
public class MathClientServerTest
{
string host = "localhost";
const string Host = "localhost";
Server server;
Channel channel;
Math.MathClient client;
@ -54,21 +55,14 @@ namespace math.Tests
[TestFixtureSetUp]
public void Init()
{
server = new Server()
server = new Server
{
Services = { Math.BindService(new MathServiceImpl()) }
Services = { Math.BindService(new MathServiceImpl()) },
Ports = { { Host, ServerPort.PickUnused, ServerCredentials.Insecure } }
};
int port = server.AddPort(host, Server.PickUnusedPort, ServerCredentials.Insecure);
server.Start();
channel = new Channel(host, port, Credentials.Insecure);
channel = new Channel(Host, server.Ports.Single().BoundPort, Credentials.Insecure);
client = Math.NewClient(channel);
// TODO(jtattermusch): get rid of the custom header here once we have dedicated tests
// for header support.
client.HeaderInterceptor = (metadata) =>
{
metadata.Add(new Metadata.Entry("custom-header", "abcdef"));
};
}
[TestFixtureTearDown]

@ -57,13 +57,13 @@ namespace Grpc.HealthCheck.Tests
{
serviceImpl = new HealthServiceImpl();
server = new Server()
server = new Server
{
Services = { Grpc.Health.V1Alpha.Health.BindService(serviceImpl) }
Services = { Grpc.Health.V1Alpha.Health.BindService(serviceImpl) },
Ports = { { Host, ServerPort.PickUnused, ServerCredentials.Insecure } }
};
int port = server.AddPort(Host, Server.PickUnusedPort, ServerCredentials.Insecure);
server.Start();
channel = new Channel(Host, port, Credentials.Insecure);
channel = new Channel(Host, server.Ports.Single().BoundPort, Credentials.Insecure);
client = Grpc.Health.V1Alpha.Health.NewClient(channel);
}

@ -33,6 +33,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using grpc.testing;
@ -47,7 +48,7 @@ namespace Grpc.IntegrationTesting
/// </summary>
public class InteropClientServerTest
{
string host = "localhost";
const string Host = "localhost";
Server server;
Channel channel;
TestService.ITestServiceClient client;
@ -55,18 +56,19 @@ namespace Grpc.IntegrationTesting
[TestFixtureSetUp]
public void Init()
{
server = new Server()
server = new Server
{
Services = { TestService.BindService(new TestServiceImpl()) }
Services = { TestService.BindService(new TestServiceImpl()) },
Ports = { { Host, ServerPort.PickUnused, TestCredentials.CreateTestServerCredentials() } }
};
int port = server.AddPort(host, Server.PickUnusedPort, TestCredentials.CreateTestServerCredentials());
server.Start();
var options = new List<ChannelOption>
{
new ChannelOption(ChannelOptions.SslTargetNameOverride, TestCredentials.DefaultHostOverride)
};
channel = new Channel(host, port, TestCredentials.CreateTestClientCredentials(true), options);
int port = server.Ports.Single().BoundPort;
channel = new Channel(Host, port, TestCredentials.CreateTestClientCredentials(true), options);
client = TestService.NewClient(channel);
}

@ -97,11 +97,11 @@ namespace Grpc.IntegrationTesting
int port = options.port.Value;
if (options.useTls)
{
server.AddPort(host, port, TestCredentials.CreateTestServerCredentials());
server.Ports.Add(host, port, TestCredentials.CreateTestServerCredentials());
}
else
{
server.AddPort(host, options.port.Value, ServerCredentials.Insecure);
server.Ports.Add(host, options.port.Value, ServerCredentials.Insecure);
}
Console.WriteLine("Running server on " + string.Format("{0}:{1}", host, port));
server.Start();

@ -34,6 +34,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using grpc.testing;
@ -49,7 +50,7 @@ namespace Grpc.IntegrationTesting
/// </summary>
public class SslCredentialsTest
{
string host = "localhost";
const string Host = "localhost";
Server server;
Channel channel;
TestService.ITestServiceClient client;
@ -67,9 +68,9 @@ namespace Grpc.IntegrationTesting
server = new Server
{
Services = { TestService.BindService(new TestServiceImpl()) }
Services = { TestService.BindService(new TestServiceImpl()) },
Ports = { { Host, ServerPort.PickUnused, serverCredentials } }
};
int port = server.AddPort(host, Server.PickUnusedPort, serverCredentials);
server.Start();
var options = new List<ChannelOption>
@ -77,7 +78,7 @@ namespace Grpc.IntegrationTesting
new ChannelOption(ChannelOptions.SslTargetNameOverride, TestCredentials.DefaultHostOverride)
};
channel = new Channel(host, port, clientCredentials, options);
channel = new Channel(Host, server.Ports.Single().BoundPort, clientCredentials, options);
client = TestService.NewClient(channel);
}

Loading…
Cancel
Save