Skip to content

Commit

Permalink
Add dotnet tcp/noise/yamux
Browse files Browse the repository at this point in the history
  • Loading branch information
flcl42 committed Sep 5, 2023
1 parent 09d15c0 commit 93c53c4
Show file tree
Hide file tree
Showing 8 changed files with 232 additions and 2 deletions.
7 changes: 5 additions & 2 deletions multidim-interop/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ RUST_SUBDIRS := $(wildcard impl/rust/*/.)
NIM_SUBDIRS := $(wildcard impl/nim/*/.)
ZIG_SUBDIRS := $(wildcard impl/zig/*/.)
JAVA_SUBDIRS := $(wildcard impl/java/*/.)
DOTNET_SUBDIRS := $(wildcard dotnet/*/.)

all: $(GO_SUBDIRS) $(JS_SUBDIRS) $(RUST_SUBDIRS) $(NIM_SUBDIRS) $(ZIG_SUBDIRS) $(JAVA_SUBDIRS)
all: $(GO_SUBDIRS) $(JS_SUBDIRS) $(RUST_SUBDIRS) $(NIM_SUBDIRS) $(ZIG_SUBDIRS) $(JAVA_SUBDIRS) $(DOTNET_SUBDIRS)
$(JS_SUBDIRS):
$(MAKE) -C $@
$(GO_SUBDIRS):
Expand All @@ -18,5 +19,7 @@ $(ZIG_SUBDIRS):
$(MAKE) -C $@
$(JAVA_SUBDIRS):
$(MAKE) -C $@
$(DOTNET_SUBDIRS):
$(MAKE) -C $@

.PHONY: $(GO_SUBDIRS) $(JS_SUBDIRS) $(RUST_SUBDIRS) $(NIM_SUBDIRS) $(ZIG_SUBDIRS) $(JAVA_SUBDIRS) all
.PHONY: $(GO_SUBDIRS) $(JS_SUBDIRS) $(RUST_SUBDIRS) $(NIM_SUBDIRS) $(ZIG_SUBDIRS) $(JAVA_SUBDIRS) $(DOTNET_SUBDIRS) all
5 changes: 5 additions & 0 deletions multidim-interop/impl/dotnet/v1.0/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
bin/
obj/
.vs/
.vscode/
image.json
11 changes: 11 additions & 0 deletions multidim-interop/impl/dotnet/v1.0/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build-env
WORKDIR /app

COPY . ./
RUN dotnet restore
RUN dotnet publish -c Release -o out

FROM mcr.microsoft.com/dotnet/runtime:7.0
WORKDIR /app
COPY --from=build-env /app/out .
ENTRYPOINT ["dotnet", "TestPlansApp.dll"]
13 changes: 13 additions & 0 deletions multidim-interop/impl/dotnet/v1.0/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
image_name := dotnet-v1.0

all: image.json

image.json: Dockerfile Program.cs Protocols.cs TestPlansApp.csproj TestPlansApp.sln
IMAGE_NAME=${image_name} ../../../dockerBuildWrapper.sh .
docker image inspect ${image_name} -f "{{.Id}}" | \
xargs -I {} echo "{\"imageID\": \"{}\"}" > $@

.PHONY: clean all

clean:
rm -f bin/ obj/
142 changes: 142 additions & 0 deletions multidim-interop/impl/dotnet/v1.0/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited
// SPDX-License-Identifier: MIT

using Microsoft.Extensions.DependencyInjection;
using Nethermind.Libp2p.Core;
using Nethermind.Libp2p.Protocols;
using StackExchange.Redis;
using System.Diagnostics;
using System.Net.NetworkInformation;
using Microsoft.Extensions.Logging;

try
{
string transport = Environment.GetEnvironmentVariable("transport")!;
string muxer = Environment.GetEnvironmentVariable("muxer")!;
string security = Environment.GetEnvironmentVariable("security")!;

bool isDialer = bool.Parse(Environment.GetEnvironmentVariable("is_dialer")!);
string ip = Environment.GetEnvironmentVariable("ip") ?? "0.0.0.0";

string redisAddr = Environment.GetEnvironmentVariable("redis_addr") ?? "redis:6379";

int testTimeoutSeconds = int.Parse(Environment.GetEnvironmentVariable("test_timeout_seconds") ?? "180");

IPeerFactory peerFactory = new TestPlansPeerFactoryBuilder(transport, muxer, security).Build();

Log($"Connecting to redis at {redisAddr}...");
ConnectionMultiplexer redis = ConnectionMultiplexer.Connect(redisAddr);
IDatabase db = redis.GetDatabase();

if (isDialer)
{
ILocalPeer localPeer = peerFactory.Create(localAddr: $"/ip4/0.0.0.0/tcp/0");
string? listenerAddr = null;
while ((listenerAddr = db.ListRightPop("listenerAddr")) is null)
{
await Task.Delay(20);
}

Log($"Dialing {listenerAddr}...");
Stopwatch handshakeStartInstant = Stopwatch.StartNew();
IRemotePeer remotePeer = await localPeer.DialAsync(listenerAddr);

Stopwatch pingIstant = Stopwatch.StartNew();
await remotePeer.DialAsync<PingProtocol>();
long pingRTT = pingIstant.ElapsedMilliseconds;

long handshakePlusOneRTT = handshakeStartInstant.ElapsedMilliseconds;

PrintResult($"{{\"handshakePlusOneRTTMillis\": {handshakePlusOneRTT}, \"pingRTTMilllis\": {pingRTT}}}");
Log("Done");
return 0;
}
else
{
if (ip == "0.0.0.0")
{
IEnumerable<UnicastIPAddressInformation> addresses = NetworkInterface.GetAllNetworkInterfaces()!
.FirstOrDefault(i => i.Name == "eth0")!
.GetIPProperties()
.UnicastAddresses
.Where(a => a.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork);

Log("Available addresses detected, picking the first: " + string.Join(",", addresses.Select(a => a.Address)));
ip = addresses.First().Address.ToString()!;
}
Log("Starting to listen...");
ILocalPeer localPeer = peerFactory.Create(localAddr: $"/ip4/{ip}/tcp/0");
IListener listener = await localPeer.ListenAsync(localPeer.Address);
listener.OnConnection += async (peer) => Log($"Connected {peer.Address}");
Log($"Listening on {listener.Address}");
db.ListRightPush(new RedisKey("listenerAddr"), new RedisValue(localPeer.Address.ToString()));
await Task.Delay(testTimeoutSeconds * 1000);
await listener.DisconnectAsync();
return -1;
}
}
catch (Exception ex)
{
Log(ex.Message);
return -1;
}

static void Log(string info) => Console.Error.WriteLine(info);
static void PrintResult(string info) => Console.WriteLine(info);

class TestPlansPeerFactoryBuilder : PeerFactoryBuilderBase<TestPlansPeerFactoryBuilder, PeerFactory>
{
private readonly string transport;
private readonly string? muxer;
private readonly string? security;
private static IPeerFactoryBuilder? defaultPeerFactoryBuilder;

public TestPlansPeerFactoryBuilder(string transport, string? muxer, string? security)
: base(new ServiceCollection()
.AddLogging(builder =>
builder.SetMinimumLevel(LogLevel.Trace)
.AddSimpleConsole(l =>
{
l.SingleLine = true;
l.TimestampFormat = "[HH:mm:ss.FFF]";
}))
.AddScoped(_ => defaultPeerFactoryBuilder!)
.BuildServiceProvider())
{
defaultPeerFactoryBuilder = this;
this.transport = transport;
this.muxer = muxer;
this.security = security;
}

private static readonly string[] stacklessProtocols = new[] { "quic", "quic-v1", "webtransport" };

protected override ProtocolStack BuildStack()
{
ProtocolStack stack = transport switch
{
"tcp" => Over<IpTcpProtocol>(),
_ => throw new NotImplementedException(),
};

if (!stacklessProtocols.Contains(transport))
{
stack = stack.Over<MultistreamProtocol>();
stack = security switch
{
"noise" => stack.Over<NoiseProtocol>(),
_ => throw new NotImplementedException(),
};
stack = stack.Over<MultistreamProtocol>();
stack = muxer switch
{
"yamux" => stack.Over<YamuxProtocol>(),
_ => throw new NotImplementedException(),
};
stack = stack.Over<MultistreamProtocol>();
}

return stack.AddAppLayerProtocol<IdentifyProtocol>()
.AddAppLayerProtocol<PingProtocol>();
}
}
25 changes: 25 additions & 0 deletions multidim-interop/impl/dotnet/v1.0/TestPlansApp.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="NRedisStack" Version="0.8.1" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="7.0.1" />

<PackageReference Include="Nethermind.Libp2p.Core" Version="1.0.0-preview.27" />
<PackageReference Include="Nethermind.Libp2p.Protocols.IpTcp" Version="1.0.0-preview.27" />
<PackageReference Include="Nethermind.Libp2p.Protocols.Noise" Version="1.0.0-preview.27" />
<PackageReference Include="Nethermind.Libp2p.Protocols.Ping" Version="1.0.0-preview.27" />
<PackageReference Include="Nethermind.Libp2p.Protocols.Yamux" Version="1.0.0-preview.27" />
<PackageReference Include="Nethermind.Libp2p.Protocols.Identify" Version="1.0.0-preview.27" />
<PackageReference Include="Nethermind.Libp2p.Protocols.Multistream" Version="1.0.0-preview.27" />
</ItemGroup>

</Project>
25 changes: 25 additions & 0 deletions multidim-interop/impl/dotnet/v1.0/TestPlansApp.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.7.34018.315
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestPlansApp", "TestPlansApp.csproj", "{4B9D7919-740C-4EF0-8890-AB43E6102952}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{4B9D7919-740C-4EF0-8890-AB43E6102952}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4B9D7919-740C-4EF0-8890-AB43E6102952}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4B9D7919-740C-4EF0-8890-AB43E6102952}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4B9D7919-740C-4EF0-8890-AB43E6102952}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {7BF72338-A0C5-4E70-A0F1-54B1EB8BB378}
EndGlobalSection
EndGlobal
6 changes: 6 additions & 0 deletions multidim-interop/versions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,4 +125,10 @@ export const versions: Array<Version> = [
secureChannels: ["tls", "noise"],
muxers: ["mplex", "yamux"],
},
{
id: "dotnet-v1.0",
transports: ["tcp"],
secureChannels: ["noise"],
muxers: ["yamux"],
},
].map((v: Version) => (typeof v.containerImageID === "undefined" ? ({ ...v, containerImageID: canonicalImageIDLookup }) : v))

0 comments on commit 93c53c4

Please sign in to comment.