|
| 1 | +// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited |
| 2 | +// SPDX-License-Identifier: MIT |
| 3 | + |
| 4 | +using Microsoft.Extensions.DependencyInjection; |
| 5 | +using Nethermind.Libp2p.Core; |
| 6 | +using Nethermind.Libp2p.Protocols; |
| 7 | +using StackExchange.Redis; |
| 8 | +using System.Diagnostics; |
| 9 | +using System.Net.NetworkInformation; |
| 10 | +using Microsoft.Extensions.Logging; |
| 11 | + |
| 12 | +try |
| 13 | +{ |
| 14 | + string transport = Environment.GetEnvironmentVariable("transport")!; |
| 15 | + string muxer = Environment.GetEnvironmentVariable("muxer")!; |
| 16 | + string security = Environment.GetEnvironmentVariable("security")!; |
| 17 | + |
| 18 | + bool isDialer = bool.Parse(Environment.GetEnvironmentVariable("is_dialer")!); |
| 19 | + string ip = Environment.GetEnvironmentVariable("ip") ?? "0.0.0.0"; |
| 20 | + |
| 21 | + string redisAddr = Environment.GetEnvironmentVariable("redis_addr") ?? "redis:6379"; |
| 22 | + |
| 23 | + int testTimeoutSeconds = int.Parse(Environment.GetEnvironmentVariable("test_timeout_seconds") ?? "180"); |
| 24 | + |
| 25 | + IPeerFactory peerFactory = new TestPlansPeerFactoryBuilder(transport, muxer, security).Build(); |
| 26 | + |
| 27 | + Log($"Connecting to redis at {redisAddr}..."); |
| 28 | + ConnectionMultiplexer redis = ConnectionMultiplexer.Connect(redisAddr); |
| 29 | + IDatabase db = redis.GetDatabase(); |
| 30 | + |
| 31 | + if (isDialer) |
| 32 | + { |
| 33 | + ILocalPeer localPeer = peerFactory.Create(localAddr: $"/ip4/0.0.0.0/tcp/0"); |
| 34 | + string? listenerAddr = null; |
| 35 | + while ((listenerAddr = db.ListRightPop("listenerAddr")) is null) |
| 36 | + { |
| 37 | + await Task.Delay(20); |
| 38 | + } |
| 39 | + |
| 40 | + Log($"Dialing {listenerAddr}..."); |
| 41 | + Stopwatch handshakeStartInstant = Stopwatch.StartNew(); |
| 42 | + IRemotePeer remotePeer = await localPeer.DialAsync(listenerAddr); |
| 43 | + |
| 44 | + Stopwatch pingIstant = Stopwatch.StartNew(); |
| 45 | + await remotePeer.DialAsync<PingProtocol>(); |
| 46 | + long pingRTT = pingIstant.ElapsedMilliseconds; |
| 47 | + |
| 48 | + long handshakePlusOneRTT = handshakeStartInstant.ElapsedMilliseconds; |
| 49 | + |
| 50 | + PrintResult($"{{\"handshakePlusOneRTTMillis\": {handshakePlusOneRTT}, \"pingRTTMilllis\": {pingRTT}}}"); |
| 51 | + Log("Done"); |
| 52 | + return 0; |
| 53 | + } |
| 54 | + else |
| 55 | + { |
| 56 | + if (ip == "0.0.0.0") |
| 57 | + { |
| 58 | + IEnumerable<UnicastIPAddressInformation> addresses = NetworkInterface.GetAllNetworkInterfaces()! |
| 59 | + .FirstOrDefault(i => i.Name == "eth0")! |
| 60 | + .GetIPProperties() |
| 61 | + .UnicastAddresses |
| 62 | + .Where(a => a.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork); |
| 63 | + |
| 64 | + Log("Available addresses detected, picking the first: " + string.Join(",", addresses.Select(a => a.Address))); |
| 65 | + ip = addresses.First().Address.ToString()!; |
| 66 | + } |
| 67 | + Log("Starting to listen..."); |
| 68 | + ILocalPeer localPeer = peerFactory.Create(localAddr: $"/ip4/{ip}/tcp/0"); |
| 69 | + IListener listener = await localPeer.ListenAsync(localPeer.Address); |
| 70 | + listener.OnConnection += async (peer) => Log($"Connected {peer.Address}"); |
| 71 | + Log($"Listening on {listener.Address}"); |
| 72 | + db.ListRightPush(new RedisKey("listenerAddr"), new RedisValue(localPeer.Address.ToString())); |
| 73 | + await Task.Delay(testTimeoutSeconds * 1000); |
| 74 | + await listener.DisconnectAsync(); |
| 75 | + return -1; |
| 76 | + } |
| 77 | +} |
| 78 | +catch (Exception ex) |
| 79 | +{ |
| 80 | + Log(ex.Message); |
| 81 | + return -1; |
| 82 | +} |
| 83 | + |
| 84 | +static void Log(string info) => Console.Error.WriteLine(info); |
| 85 | +static void PrintResult(string info) => Console.WriteLine(info); |
| 86 | + |
| 87 | +class TestPlansPeerFactoryBuilder : PeerFactoryBuilderBase<TestPlansPeerFactoryBuilder, PeerFactory> |
| 88 | +{ |
| 89 | + private readonly string transport; |
| 90 | + private readonly string? muxer; |
| 91 | + private readonly string? security; |
| 92 | + private static IPeerFactoryBuilder? defaultPeerFactoryBuilder; |
| 93 | + |
| 94 | + public TestPlansPeerFactoryBuilder(string transport, string? muxer, string? security) |
| 95 | + : base(new ServiceCollection() |
| 96 | + .AddLogging(builder => |
| 97 | + builder.SetMinimumLevel(LogLevel.Trace) |
| 98 | + .AddSimpleConsole(l => |
| 99 | + { |
| 100 | + l.SingleLine = true; |
| 101 | + l.TimestampFormat = "[HH:mm:ss.FFF]"; |
| 102 | + })) |
| 103 | + .AddScoped(_ => defaultPeerFactoryBuilder!) |
| 104 | + .BuildServiceProvider()) |
| 105 | + { |
| 106 | + defaultPeerFactoryBuilder = this; |
| 107 | + this.transport = transport; |
| 108 | + this.muxer = muxer; |
| 109 | + this.security = security; |
| 110 | + } |
| 111 | + |
| 112 | + private static readonly string[] stacklessProtocols = new[] { "quic", "quic-v1", "webtransport" }; |
| 113 | + |
| 114 | + protected override ProtocolStack BuildStack() |
| 115 | + { |
| 116 | + ProtocolStack stack = transport switch |
| 117 | + { |
| 118 | + "tcp" => Over<IpTcpProtocol>(), |
| 119 | + _ => throw new NotImplementedException(), |
| 120 | + }; |
| 121 | + |
| 122 | + if (!stacklessProtocols.Contains(transport)) |
| 123 | + { |
| 124 | + stack = stack.Over<MultistreamProtocol>(); |
| 125 | + stack = security switch |
| 126 | + { |
| 127 | + "noise" => stack.Over<NoiseProtocol>(), |
| 128 | + _ => throw new NotImplementedException(), |
| 129 | + }; |
| 130 | + stack = stack.Over<MultistreamProtocol>(); |
| 131 | + stack = muxer switch |
| 132 | + { |
| 133 | + "yamux" => stack.Over<YamuxProtocol>(), |
| 134 | + _ => throw new NotImplementedException(), |
| 135 | + }; |
| 136 | + stack = stack.Over<MultistreamProtocol>(); |
| 137 | + } |
| 138 | + |
| 139 | + return stack.AddAppLayerProtocol<IdentifyProtocol>() |
| 140 | + .AddAppLayerProtocol<PingProtocol>(); |
| 141 | + } |
| 142 | +} |
0 commit comments