1 #region Copyright notice and license 2 3 // Copyright 2020 The gRPC Authors 4 // 5 // Licensed under the Apache License, Version 2.0 (the "License"); 6 // you may not use this file except in compliance with the License. 7 // You may obtain a copy of the License at 8 // 9 // http://www.apache.org/licenses/LICENSE-2.0 10 // 11 // Unless required by applicable law or agreed to in writing, software 12 // distributed under the License is distributed on an "AS IS" BASIS, 13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 // See the License for the specific language governing permissions and 15 // limitations under the License. 16 17 #endregion 18 19 using System; 20 using System.Threading.Tasks; 21 using System.IO; 22 using System.Linq; 23 using Grpc.Core; 24 using Grpc.Core.Internal; 25 using Grpc.Core.Utils; 26 using NUnit.Framework; 27 28 namespace Grpc.Core.Tests 29 { 30 public class ServerBindFailedTest 31 { 32 Method<string, string> UnimplementedMethod = new Method<string, string>( 33 MethodType.Unary, 34 "FooService", 35 "SomeNonExistentMethod", 36 Marshallers.StringMarshaller, 37 Marshallers.StringMarshaller); 38 39 // https://github.com/grpc/grpc/issues/18100 40 [Test] Issue18100()41 public async Task Issue18100() 42 { 43 var server = new Server(new[] { new ChannelOption(ChannelOptions.SoReuseport, 0) }); 44 45 // this port will successfully bind 46 int successfullyBoundPort = server.Ports.Add(new ServerPort("localhost", ServerPort.PickUnused, ServerCredentials.Insecure)); 47 Assert.AreNotEqual(0, successfullyBoundPort); 48 49 // use bad ssl server credentials so this port is guaranteed to fail to bind 50 Assert.AreEqual(0, server.Ports.Add(new ServerPort("localhost", ServerPort.PickUnused, MakeBadSslServerCredentials()))); 51 52 try 53 { 54 server.Start(); 55 } 56 catch (IOException ex) 57 { 58 // eat the expected "Failed to bind port" exception. 59 Console.Error.WriteLine($"Ignoring expected exception when starting the server: {ex}"); 60 } 61 62 // Create a channel to the port that has been bound successfully 63 var channel = new Channel("localhost", successfullyBoundPort, ChannelCredentials.Insecure); 64 65 var callDeadline = DateTime.UtcNow.AddSeconds(5); // set deadline to make sure we fail quickly if the server doesn't respond 66 67 // call a method that's not implemented on the server. 68 var call = Calls.AsyncUnaryCall(new CallInvocationDetails<string, string>(channel, UnimplementedMethod, new CallOptions(deadline: callDeadline)), "someRequest"); 69 try 70 { 71 await call; 72 Assert.Fail("the call should have failed."); 73 } 74 catch (RpcException) 75 { 76 // We called a nonexistent method. A healthy server should immediately respond with StatusCode.Unimplemented 77 Assert.AreEqual(StatusCode.Unimplemented, call.GetStatus().StatusCode); 78 } 79 80 await channel.ShutdownAsync(); 81 await server.ShutdownAsync(); 82 } 83 MakeBadSslServerCredentials()84 private static SslServerCredentials MakeBadSslServerCredentials() 85 { 86 var serverCert = new[] { new KeyCertificatePair("this is a bad certificate chain", "this is a bad private key") }; 87 return new SslServerCredentials(serverCert, "this is a bad root set", forceClientAuth: false); 88 } 89 } 90 } 91