grpc-dotnet icon indicating copy to clipboard operation
grpc-dotnet copied to clipboard

Testing for a valid endpoint on a duplex connection

Open NullDoctor opened this issue 2 years ago • 3 comments

I need to test that an endpoint is valid for a duplex stream connection without sending a message. I have figured out a way to do it, but it doesn't work for every scenario.

`

    var saCerts = CertificateValidation.CreateTrustedRootCollection( certificateAthorities );

    var options = new GrpcChannelOptions();

    if( url.StartsWith( "https" ) )
    {
        var handler = new SocketsHttpHandler();
        handler.SslOptions = new SslClientAuthenticationOptions
        {
            RemoteCertificateValidationCallback = CertificateValidation.CreateRemoteCertificateValidationCallback( saCerts ),
            ClientCertificates = new X509CertificateCollection()
        };

        handler.SslOptions.ClientCertificates.Add( new X509Certificate2( /*Certificate*/ ) );

        options.HttpHandler = handler;
    }

    channel = GrpcChannel.ForAddress( url, options );

    //This is how I found to test a connection
    channel.ConnectAsync();

    var task = channel.WaitForStateChangedAsync( ConnectivityState.Connecting );
    task.Wait(5000);

    if( channel.State != ConnectivityState.Ready )
        throw new Exception( $"Could not connect to URL: {url}." );

    //End connection test

    var client = new MyMessage.MyMessageClient( channel );

    call = client.Stream( null, null, cancellationSource.Token );

`

Using ConnectAsync works when there is no endpoint at all. It also works (through the task timeout) when there is something at the endpoint, but not one I can connect to.

However, in the instance the url is correct, but the server port is secure and the used url is not secure (or vice versa), channel.ConnectAsync() works, and the channel state becomes ConnectivityState.Ready, despite the mismatch in security.

The only way I could figure out how to test if the endpoint is completely valid is to send a message. However, for reasons outside of my control, this is not going to work for me.

So my questions are: Is ConnectAsync the right way to test? And how do you check if the endpoint is completely valid without sending a message?

Any help is appreciated.

NullDoctor avatar Jun 17 '22 15:06 NullDoctor

However, in the instance the url is correct, but the server port is secure and the used url is not secure (or vice versa), channel.ConnectAsync() works, and the channel state becomes ConnectivityState.Ready, despite the mismatch in security.

This is a known limitation in grpc-dotnet. It only tests that the TCP connection is healthy. TLS only becomes involved when a message is sent.

JamesNK avatar Jun 21 '22 12:06 JamesNK

Thank you James for the reply. Forgive my ignorance about all of this, but isn't testing for the valid endpoint something that is done in Grpc.Core before sending a message? Is testing the connection without sending a message something that can be or is planned to be implemented in the future for this aspnetcore version?

NullDoctor avatar Jun 21 '22 21:06 NullDoctor

I'd like to support it, but it requires changes in the .NET networking layer.

JamesNK avatar Jun 22 '22 01:06 JamesNK