Skip to content

Commit

Permalink
add tcp keep alive hack to net5 target (#560)
Browse files Browse the repository at this point in the history
* add tcp keep alive hack to net5 target

* remove unused code

* fix ep

* Update buildtest.yaml

* fix netstandard21

* fix space

* fix net5 warning

* more comment
  • Loading branch information
tg123 committed Mar 11, 2021
1 parent d48e93c commit 655a42c
Show file tree
Hide file tree
Showing 8 changed files with 53 additions and 11 deletions.
35 changes: 35 additions & 0 deletions src/KubernetesClient/Kubernetes.ConfigInit.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
using System.Net;
using System.Net.Http;
using System.Net.Security;
using System.Net.Sockets;
using System.Reflection;
using System.Security.Cryptography.X509Certificates;
using k8s.Exceptions;
using k8s.Models;
Expand Down Expand Up @@ -166,6 +168,39 @@ private void AppendDelegatingHandler<T>()
private void CreateHttpClient(DelegatingHandler[] handlers)
{
FirstMessageHandler = HttpClientHandler = CreateRootHandler();


#if NET5_0

// https://github.com/kubernetes-client/csharp/issues/533
// net5 only
// this is a temp fix to attach SocketsHttpHandler to HttpClient in order to set SO_KEEPALIVE
// https://tldp.org/HOWTO/html_single/TCP-Keepalive-HOWTO/
//
// _underlyingHandler is not a public accessible field
// src of net5 HttpClientHandler and _underlyingHandler field defined here
// https://github.com/dotnet/runtime/blob/79ae74f5ca5c8a6fe3a48935e85bd7374959c570/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.cs#L22
//
// Should remove after better solution

var sh = new SocketsHttpHandler();
sh.ConnectCallback = async (context, token) =>
{
var socket = new Socket(SocketType.Stream, ProtocolType.Tcp)
{
NoDelay = true,
};
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);
await socket.ConnectAsync(context.DnsEndPoint.Host, context.DnsEndPoint.Port, token).ConfigureAwait(false);
return new NetworkStream(socket, ownsSocket: true);
};

var p = HttpClientHandler.GetType().GetField("_underlyingHandler", BindingFlags.NonPublic | BindingFlags.Instance);
p.SetValue(HttpClientHandler, (sh));
#endif

if (handlers == null || handlers.Length == 0)
{
// ensure we have at least one DelegatingHandler so AppendDelegatingHandler will work
Expand Down
4 changes: 4 additions & 0 deletions src/KubernetesClient/Kubernetes.Watch.cs
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,11 @@ public async Task<Watcher<T>> WatchObjectAsync<T>(string path, string @continue
httpResponse.StatusCode));
if (httpResponse.Content != null)
{
#if NET5_0
responseContent = await httpResponse.Content.ReadAsStringAsync(cancellationToken).ConfigureAwait(false);
#else
responseContent = await httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false);
#endif
}

ex.Request = new HttpRequestMessageWrapper(httpRequest, responseContent);
Expand Down
9 changes: 6 additions & 3 deletions src/KubernetesClient/Kubernetes.WebSocket.cs
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@ protected async Task<WebSocket> StreamConnectAsync(Uri uri, string invocationId
}
#endif

#if NETSTANDARD2_1
#if NETSTANDARD2_1 || NET5_0
if (this.CaCerts != null)
{
webSocketBuilder.ExpectServerCertificate(this.CaCerts);
Expand All @@ -334,7 +334,7 @@ protected async Task<WebSocket> StreamConnectAsync(Uri uri, string invocationId
{
webSocketBuilder.Options.AddSubProtocol(webSocketSubProtocol);
}
#endif // NETSTANDARD2_1
#endif // NETSTANDARD2_1 || NET5_0

// Send Request
cancellationToken.ThrowIfCancellationRequested();
Expand Down Expand Up @@ -366,8 +366,11 @@ protected async Task<WebSocket> StreamConnectAsync(Uri uri, string invocationId
}
else
{
#if NET5_0
var content = await response.Content.ReadAsStringAsync(cancellationToken).ConfigureAwait(false);
#else
var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false);

#endif
// Try to parse the content as a V1Status object
var genericObject = SafeJsonConvert.DeserializeObject<KubernetesObject>(content);
V1Status status = null;
Expand Down
2 changes: 1 addition & 1 deletion src/KubernetesClient/KubernetesClient.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<PackageIconUrl>https://raw.githubusercontent.com/kubernetes/kubernetes/master/logo/logo.png</PackageIconUrl>
<PackageTags>kubernetes;docker;containers;</PackageTags>

<TargetFrameworks>netstandard2.0;netstandard2.1</TargetFrameworks>
<TargetFrameworks>netstandard2.0;netstandard2.1;net5</TargetFrameworks>
<RootNamespace>k8s</RootNamespace>
<SignAssembly>true</SignAssembly>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
Expand Down
4 changes: 2 additions & 2 deletions src/KubernetesClient/WebSocketBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public void CleanupServerCertificateValidationCallback(RemoteCertificateValidati
}
#endif

#if NETSTANDARD2_1
#if NETSTANDARD2_1 || NET5_0
public WebSocketBuilder ExpectServerCertificate(X509Certificate2Collection serverCertificate)
{
Options.RemoteCertificateValidationCallback
Expand All @@ -70,7 +70,7 @@ public WebSocketBuilder SkipServerCertificateValidation()
return this;
}

#endif // NETSTANDARD2_1
#endif // NETSTANDARD2_1 || NET5_0

public virtual async Task<WebSocket> BuildAndConnectAsync(Uri uri, CancellationToken cancellationToken)
{
Expand Down
4 changes: 2 additions & 2 deletions tests/KubernetesClient.Tests/AuthTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ public void BasicAuth()
}
}

#if NETSTANDARD2_1 // The functionality under test, here, is dependent on managed HTTP / WebSocket in .NET Core 2.1 or newer.
#if NETSTANDARD2_1 || NET5_0 // The functionality under test, here, is dependent on managed HTTP / WebSocket in .NET Core 2.1 or newer.
// this test doesn't work on OSX and is inconsistent on windows
[OperatingSystemDependentFact(Exclude = OperatingSystems.OSX | OperatingSystems.Windows)]
public void Cert()
Expand Down Expand Up @@ -338,7 +338,7 @@ public void ExternalCertificate()
}
}
}
#endif // NETSTANDARD2_1
#endif // NETSTANDARD2_1 || NET5_0

[Fact]
public void ExternalToken()
Expand Down
2 changes: 1 addition & 1 deletion tests/KubernetesClient.Tests/KubernetesExecTests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#if !NETSTANDARD2_1
#if !NETSTANDARD2_1 || NET5_0
/*
* These tests are only for the netstandard version of the client (there are separate tests for netcoreapp that connect to a local test-hosted server).
*/
Expand Down
4 changes: 2 additions & 2 deletions tests/KubernetesClient.Tests/Mock/MockWebSocketBuilder.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#if !NETSTANDARD2_1
#if !NETSTANDARD2_1 || NET5_0
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
Expand Down Expand Up @@ -43,4 +43,4 @@ public override WebSocketBuilder SetRequestHeader(string headerName, string head
}
}

#endif // !NETSTANDARD2_1
#endif // !NETSTANDARD2_1 || NET5_0

0 comments on commit 655a42c

Please sign in to comment.