From a0272fef22fa2a3bffd7b952f7eb70f7ae432d4d Mon Sep 17 00:00:00 2001 From: Juanu Date: Wed, 29 Nov 2023 17:54:51 -0300 Subject: [PATCH 01/14] Added multiaddr code Referenced on project and modified a bunch of files to reference it --- src/cs-multiaddress/.editorconfig | 17 ++ src/cs-multiaddress/.gitattributes | 63 +++++ src/cs-multiaddress/.gitignore | 243 +++++++++++++++++ src/cs-multiaddress/.travis.yml | 51 ++++ src/cs-multiaddress/LICENSE | 21 ++ src/cs-multiaddress/Multiformats.Address.sln | 71 +++++ src/cs-multiaddress/NuGet.config | 8 + src/cs-multiaddress/README.md | 85 ++++++ src/cs-multiaddress/appveyor.yml | 113 ++++++++ src/cs-multiaddress/build.sh | 17 ++ .../src/Multiformats.Address/Extensions.cs | 18 ++ .../src/Multiformats.Address/Multiaddress.cs | 256 ++++++++++++++++++ .../Multiformats.Address.csproj | 43 +++ .../Net/MultiaddressExtensions.cs | 201 ++++++++++++++ .../Net/MultiaddressTools.cs | 21 ++ .../Multiformats.Address/Protocols/DCCP.cs | 16 ++ .../src/Multiformats.Address/Protocols/DNS.cs | 24 ++ .../Multiformats.Address/Protocols/DNS4.cs | 24 ++ .../Multiformats.Address/Protocols/DNS6.cs | 24 ++ .../Multiformats.Address/Protocols/HTTP.cs | 22 ++ .../Multiformats.Address/Protocols/HTTPS.cs | 22 ++ .../src/Multiformats.Address/Protocols/IP.cs | 20 ++ .../src/Multiformats.Address/Protocols/IP4.cs | 39 +++ .../src/Multiformats.Address/Protocols/IP6.cs | 39 +++ .../Multiformats.Address/Protocols/IPFS.cs | 30 ++ .../Protocols/MultiaddressProtocol.cs | 40 +++ .../Multiformats.Address/Protocols/Number.cs | 19 ++ .../Multiformats.Address/Protocols/Onion.cs | 70 +++++ .../Protocols/P2P.Circuit.cs | 20 ++ .../Protocols/P2P.Web.RTC.Star.cs | 20 ++ .../Protocols/P2P.WebRTC.Direct.cs | 20 ++ .../Protocols/P2P.WebSocket.Star.cs | 20 ++ .../src/Multiformats.Address/Protocols/P2P.cs | 28 ++ .../Multiformats.Address/Protocols/QUIC.cs | 20 ++ .../Multiformats.Address/Protocols/SCTP.cs | 16 ++ .../src/Multiformats.Address/Protocols/TCP.cs | 16 ++ .../src/Multiformats.Address/Protocols/UDP.cs | 16 ++ .../src/Multiformats.Address/Protocols/UDT.cs | 22 ++ .../src/Multiformats.Address/Protocols/UTP.cs | 22 ++ .../Multiformats.Address/Protocols/Unix.cs | 50 ++++ .../Protocols/WebSocket.cs | 22 ++ .../Protocols/WebSocketSecure.cs | 22 ++ .../ConvertTests.cs | 225 +++++++++++++++ .../MultiaddressTests.cs | 198 ++++++++++++++ .../Multiformats.Address.Tests.csproj | 45 +++ .../Discovery/IDiscoveryProtocol.cs | 8 +- src/libp2p/Libp2p.Core/IListener.cs | 3 +- src/libp2p/Libp2p.Core/ILocalPeer.cs | 6 +- src/libp2p/Libp2p.Core/IPeer.cs | 4 +- src/libp2p/Libp2p.Core/IPeerContext.cs | 5 +- src/libp2p/Libp2p.Core/IPeerFactory.cs | 4 +- src/libp2p/Libp2p.Core/Libp2p.Core.csproj | 1 + src/libp2p/Libp2p.Core/PeerContext.cs | 5 +- src/libp2p/Libp2p.Core/PeerFactory.cs | 22 +- .../Libp2p.Protocols.IpTcp/IpTcpProtocol.cs | 20 +- src/libp2p/Libp2p.sln | 6 + 56 files changed, 2452 insertions(+), 31 deletions(-) create mode 100644 src/cs-multiaddress/.editorconfig create mode 100644 src/cs-multiaddress/.gitattributes create mode 100644 src/cs-multiaddress/.gitignore create mode 100644 src/cs-multiaddress/.travis.yml create mode 100644 src/cs-multiaddress/LICENSE create mode 100644 src/cs-multiaddress/Multiformats.Address.sln create mode 100644 src/cs-multiaddress/NuGet.config create mode 100644 src/cs-multiaddress/README.md create mode 100644 src/cs-multiaddress/appveyor.yml create mode 100644 src/cs-multiaddress/build.sh create mode 100644 src/cs-multiaddress/src/Multiformats.Address/Extensions.cs create mode 100644 src/cs-multiaddress/src/Multiformats.Address/Multiaddress.cs create mode 100644 src/cs-multiaddress/src/Multiformats.Address/Multiformats.Address.csproj create mode 100644 src/cs-multiaddress/src/Multiformats.Address/Net/MultiaddressExtensions.cs create mode 100644 src/cs-multiaddress/src/Multiformats.Address/Net/MultiaddressTools.cs create mode 100644 src/cs-multiaddress/src/Multiformats.Address/Protocols/DCCP.cs create mode 100644 src/cs-multiaddress/src/Multiformats.Address/Protocols/DNS.cs create mode 100644 src/cs-multiaddress/src/Multiformats.Address/Protocols/DNS4.cs create mode 100644 src/cs-multiaddress/src/Multiformats.Address/Protocols/DNS6.cs create mode 100644 src/cs-multiaddress/src/Multiformats.Address/Protocols/HTTP.cs create mode 100644 src/cs-multiaddress/src/Multiformats.Address/Protocols/HTTPS.cs create mode 100644 src/cs-multiaddress/src/Multiformats.Address/Protocols/IP.cs create mode 100644 src/cs-multiaddress/src/Multiformats.Address/Protocols/IP4.cs create mode 100644 src/cs-multiaddress/src/Multiformats.Address/Protocols/IP6.cs create mode 100644 src/cs-multiaddress/src/Multiformats.Address/Protocols/IPFS.cs create mode 100644 src/cs-multiaddress/src/Multiformats.Address/Protocols/MultiaddressProtocol.cs create mode 100644 src/cs-multiaddress/src/Multiformats.Address/Protocols/Number.cs create mode 100644 src/cs-multiaddress/src/Multiformats.Address/Protocols/Onion.cs create mode 100644 src/cs-multiaddress/src/Multiformats.Address/Protocols/P2P.Circuit.cs create mode 100644 src/cs-multiaddress/src/Multiformats.Address/Protocols/P2P.Web.RTC.Star.cs create mode 100644 src/cs-multiaddress/src/Multiformats.Address/Protocols/P2P.WebRTC.Direct.cs create mode 100644 src/cs-multiaddress/src/Multiformats.Address/Protocols/P2P.WebSocket.Star.cs create mode 100644 src/cs-multiaddress/src/Multiformats.Address/Protocols/P2P.cs create mode 100644 src/cs-multiaddress/src/Multiformats.Address/Protocols/QUIC.cs create mode 100644 src/cs-multiaddress/src/Multiformats.Address/Protocols/SCTP.cs create mode 100644 src/cs-multiaddress/src/Multiformats.Address/Protocols/TCP.cs create mode 100644 src/cs-multiaddress/src/Multiformats.Address/Protocols/UDP.cs create mode 100644 src/cs-multiaddress/src/Multiformats.Address/Protocols/UDT.cs create mode 100644 src/cs-multiaddress/src/Multiformats.Address/Protocols/UTP.cs create mode 100644 src/cs-multiaddress/src/Multiformats.Address/Protocols/Unix.cs create mode 100644 src/cs-multiaddress/src/Multiformats.Address/Protocols/WebSocket.cs create mode 100644 src/cs-multiaddress/src/Multiformats.Address/Protocols/WebSocketSecure.cs create mode 100644 src/cs-multiaddress/test/Multiformats.Address.Tests/ConvertTests.cs create mode 100644 src/cs-multiaddress/test/Multiformats.Address.Tests/MultiaddressTests.cs create mode 100644 src/cs-multiaddress/test/Multiformats.Address.Tests/Multiformats.Address.Tests.csproj diff --git a/src/cs-multiaddress/.editorconfig b/src/cs-multiaddress/.editorconfig new file mode 100644 index 00000000..ad7283ed --- /dev/null +++ b/src/cs-multiaddress/.editorconfig @@ -0,0 +1,17 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +indent_style = space +insert_final_newline = true +trim_trailing_whitespace = true + +[*.cs] +indent_size = 4 + +[*.{sln,csproj,yml,config,md}] +indent_size = 2 + +[*.md] +trim_trailing_whitespace = false diff --git a/src/cs-multiaddress/.gitattributes b/src/cs-multiaddress/.gitattributes new file mode 100644 index 00000000..1ff0c423 --- /dev/null +++ b/src/cs-multiaddress/.gitattributes @@ -0,0 +1,63 @@ +############################################################################### +# Set default behavior to automatically normalize line endings. +############################################################################### +* text=auto + +############################################################################### +# Set default behavior for command prompt diff. +# +# This is need for earlier builds of msysgit that does not have it on by +# default for csharp files. +# Note: This is only used by command line +############################################################################### +#*.cs diff=csharp + +############################################################################### +# Set the merge driver for project and solution files +# +# Merging from the command prompt will add diff markers to the files if there +# are conflicts (Merging from VS is not affected by the settings below, in VS +# the diff markers are never inserted). Diff markers may cause the following +# file extensions to fail to load in VS. An alternative would be to treat +# these files as binary and thus will always conflict and require user +# intervention with every merge. To do so, just uncomment the entries below +############################################################################### +#*.sln merge=binary +#*.csproj merge=binary +#*.vbproj merge=binary +#*.vcxproj merge=binary +#*.vcproj merge=binary +#*.dbproj merge=binary +#*.fsproj merge=binary +#*.lsproj merge=binary +#*.wixproj merge=binary +#*.modelproj merge=binary +#*.sqlproj merge=binary +#*.wwaproj merge=binary + +############################################################################### +# behavior for image files +# +# image files are treated as binary by default. +############################################################################### +#*.jpg binary +#*.png binary +#*.gif binary + +############################################################################### +# diff behavior for common document formats +# +# Convert binary document formats to text before diffing them. This feature +# is only available from the command line. Turn it on by uncommenting the +# entries below. +############################################################################### +#*.doc diff=astextplain +#*.DOC diff=astextplain +#*.docx diff=astextplain +#*.DOCX diff=astextplain +#*.dot diff=astextplain +#*.DOT diff=astextplain +#*.pdf diff=astextplain +#*.PDF diff=astextplain +#*.rtf diff=astextplain +#*.RTF diff=astextplain diff --git a/src/cs-multiaddress/.gitignore b/src/cs-multiaddress/.gitignore new file mode 100644 index 00000000..87d73e39 --- /dev/null +++ b/src/cs-multiaddress/.gitignore @@ -0,0 +1,243 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +[Xx]64/ +[Xx]86/ +[Bb]uild/ +bld/ +[Bb]in/ +[Oo]bj/ + +# Visual Studio 2015 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# DNX +project.lock.json +artifacts/ + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml + +# TODO: Un-comment the next line if you do not want to checkin +# your web deploy settings because they may include unencrypted +# passwords +#*.pubxml +*.publishproj + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config +# NuGet v3's project.json files produces more ignoreable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directory +AppPackages/ +BundleArtifacts/ + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.pfx +*.publishsettings +node_modules/ +orleans.codegen.cs + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# LightSwitch generated files +GeneratedArtifacts/ +ModelManifest.xml + +# Paket dependency manager +.paket/paket.exe + +# FAKE - F# Make +.fake/ +.vscode diff --git a/src/cs-multiaddress/.travis.yml b/src/cs-multiaddress/.travis.yml new file mode 100644 index 00000000..e1c501d3 --- /dev/null +++ b/src/cs-multiaddress/.travis.yml @@ -0,0 +1,51 @@ +language: csharp +sudo: required +dist: trusty +env: + - CLI_VERSION=latest + +addons: + apt: + packages: + - gettext + - libcurl4-openssl-dev + - libicu-dev + - libssl-dev + - libunwind8 + - zlib1g +mono: + - latest +os: + - linux + - osx + +notifications: + email: + on_success: change + on_failure: always + +branches: + only: + - master + +cache: + bundler: true + directories: + - ./packages + - /.dotnetcli + - $HOME/Library/Caches/Homebrew + +before_install: + - if test "$TRAVIS_OS_NAME" == "osx"; then brew update; brew install openssl; ln -s /usr/local/opt/openssl/lib/libcrypto.1.0.0.dylib /usr/local/lib/; ln -s /usr/local/opt/openssl/lib/libssl.1.0.0.dylib /usr/local/lib/; fi + +install: + - export DOTNET_INSTALL_DIR="$PWD/.dotnetcli" + - export DOTNET_SKIP_FIRST_TIME_EXPERIENCE=true + - export DOTNET_CLI_TELEMETRY_OPTOUT=1 + - curl -sSL https://raw.githubusercontent.com/dotnet/cli/rel/1.0.1/scripts/obtain/dotnet-install.sh | bash /dev/stdin --version "$CLI_VERSION" --install-dir "$DOTNET_INSTALL_DIR" + - git config --global core.autocrlf input + - chmod +x ./build.sh + - export PATH="$DOTNET_INSTALL_DIR:$PATH" + +script: + - ./build.sh diff --git a/src/cs-multiaddress/LICENSE b/src/cs-multiaddress/LICENSE new file mode 100644 index 00000000..e0756c7b --- /dev/null +++ b/src/cs-multiaddress/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2016 Trond Bråthen + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/src/cs-multiaddress/Multiformats.Address.sln b/src/cs-multiaddress/Multiformats.Address.sln new file mode 100644 index 00000000..6164f59c --- /dev/null +++ b/src/cs-multiaddress/Multiformats.Address.sln @@ -0,0 +1,71 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.27130.2027 +MinimumVisualStudioVersion = 15.0.26124.0 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{5174FE92-E9D8-47EA-8738-0E94D8E8F85B}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Multiformats.Address", "src\Multiformats.Address\Multiformats.Address.csproj", "{BFFDDBBD-0073-49CC-8592-78140A5A7165}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{C0A9F493-26A9-4370-9B7B-EA3B2031B952}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Multiformats.Address.Tests", "test\Multiformats.Address.Tests\Multiformats.Address.Tests.csproj", "{B6E09410-D728-4184-A79D-B9195DB90C73}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{BCB0693C-373E-4379-B767-01319F264FFA}" + ProjectSection(SolutionItems) = preProject + .editorconfig = .editorconfig + .gitattributes = .gitattributes + .gitignore = .gitignore + .travis.yml = .travis.yml + appveyor.yml = appveyor.yml + build.sh = build.sh + LICENSE = LICENSE + NuGet.config = NuGet.config + README.md = README.md + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {BFFDDBBD-0073-49CC-8592-78140A5A7165}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BFFDDBBD-0073-49CC-8592-78140A5A7165}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BFFDDBBD-0073-49CC-8592-78140A5A7165}.Debug|x64.ActiveCfg = Debug|Any CPU + {BFFDDBBD-0073-49CC-8592-78140A5A7165}.Debug|x64.Build.0 = Debug|Any CPU + {BFFDDBBD-0073-49CC-8592-78140A5A7165}.Debug|x86.ActiveCfg = Debug|Any CPU + {BFFDDBBD-0073-49CC-8592-78140A5A7165}.Debug|x86.Build.0 = Debug|Any CPU + {BFFDDBBD-0073-49CC-8592-78140A5A7165}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BFFDDBBD-0073-49CC-8592-78140A5A7165}.Release|Any CPU.Build.0 = Release|Any CPU + {BFFDDBBD-0073-49CC-8592-78140A5A7165}.Release|x64.ActiveCfg = Release|Any CPU + {BFFDDBBD-0073-49CC-8592-78140A5A7165}.Release|x64.Build.0 = Release|Any CPU + {BFFDDBBD-0073-49CC-8592-78140A5A7165}.Release|x86.ActiveCfg = Release|Any CPU + {BFFDDBBD-0073-49CC-8592-78140A5A7165}.Release|x86.Build.0 = Release|Any CPU + {B6E09410-D728-4184-A79D-B9195DB90C73}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B6E09410-D728-4184-A79D-B9195DB90C73}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B6E09410-D728-4184-A79D-B9195DB90C73}.Debug|x64.ActiveCfg = Debug|Any CPU + {B6E09410-D728-4184-A79D-B9195DB90C73}.Debug|x64.Build.0 = Debug|Any CPU + {B6E09410-D728-4184-A79D-B9195DB90C73}.Debug|x86.ActiveCfg = Debug|Any CPU + {B6E09410-D728-4184-A79D-B9195DB90C73}.Debug|x86.Build.0 = Debug|Any CPU + {B6E09410-D728-4184-A79D-B9195DB90C73}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B6E09410-D728-4184-A79D-B9195DB90C73}.Release|Any CPU.Build.0 = Release|Any CPU + {B6E09410-D728-4184-A79D-B9195DB90C73}.Release|x64.ActiveCfg = Release|Any CPU + {B6E09410-D728-4184-A79D-B9195DB90C73}.Release|x64.Build.0 = Release|Any CPU + {B6E09410-D728-4184-A79D-B9195DB90C73}.Release|x86.ActiveCfg = Release|Any CPU + {B6E09410-D728-4184-A79D-B9195DB90C73}.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {BFFDDBBD-0073-49CC-8592-78140A5A7165} = {5174FE92-E9D8-47EA-8738-0E94D8E8F85B} + {B6E09410-D728-4184-A79D-B9195DB90C73} = {C0A9F493-26A9-4370-9B7B-EA3B2031B952} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {C1A38278-CB86-4A00-96FA-EE89A8D7293A} + EndGlobalSection +EndGlobal diff --git a/src/cs-multiaddress/NuGet.config b/src/cs-multiaddress/NuGet.config new file mode 100644 index 00000000..bcee4a62 --- /dev/null +++ b/src/cs-multiaddress/NuGet.config @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/cs-multiaddress/README.md b/src/cs-multiaddress/README.md new file mode 100644 index 00000000..74d34ea5 --- /dev/null +++ b/src/cs-multiaddress/README.md @@ -0,0 +1,85 @@ +**This project is no longer maintained and has been archived.** + +# Multiformats.Address (cs-multiaddress) + +[![](https://img.shields.io/badge/project-multiformats-blue.svg?style=flat-square)](https://github.com/multiformats/multiformats) +[![](https://img.shields.io/badge/freenode-%23ipfs-blue.svg?style=flat-square)](https://webchat.freenode.net/?channels=%23ipfs) +[![](https://img.shields.io/badge/readme%20style-standard-brightgreen.svg?style=flat-square)](https://github.com/RichardLitt/standard-readme) +[![Travis CI](https://img.shields.io/travis/multiformats/cs-multiaddress.svg?style=flat-square&branch=master)](https://travis-ci.org/multiformats/cs-multiaddress) +[![AppVeyor](https://img.shields.io/appveyor/ci/tabrath/cs-multiaddress/master.svg?style=flat-square)](https://ci.appveyor.com/project/tabrath/cs-multiaddress) +[![NuGet](https://buildstats.info/nuget/Multiformats.Address)](https://www.nuget.org/packages/Multiformats.Address/) +[![Codecov](https://img.shields.io/codecov/c/github/multiformats/cs-multiaddress/master.svg?style=flat-square)](https://codecov.io/gh/multiformats/cs-multiaddress) +[![Libraries.io](https://img.shields.io/librariesio/github/multiformats/cs-multiaddress.svg?style=flat-square)](https://libraries.io/github/multiformats/cs-multiaddress) + +> [Multiaddr](https://github.com/multiformats/multiaddr) implementation in C# .NET Standard 1.6 compliant. + +## Table of Contents + +- [Install](#install) +- [Usage](#usage) +- [Supported protocols](#supported-protocols) +- [Maintainers](#maintainers) +- [Contribute](#contribute) +- [License](#license) + +## Install + + PM> Install-Package Multiformats.Address + +--- + + dotnet add package Multiformats.Address + +## Usage +``` cs +var ma = Multiaddress.Decode("/ip4/127.0.0.1/udp/1234"); +var addresses = ma.Split(); +var joined = Multiaddress.Join(addresses); +var tcp = ma.Protocols.Get(); +``` + +There's some extension methods included that let's you create multiaddresses of IPEndPoints, and create IPEndPoints from multiaddresses. +Some let's you create sockets directly from IP4/IP6, TCP/UDP multiaddresses. + +``` cs +var socket = ma.CreateSocket(); +var localEndPoint = socket.GetLocalMultiaddress(); +var remoteEndPoint = socket.GetRemoteMultiaddress(); +``` + +## Supported protocols + +* DCCP +* DNS/4/6 +* HTTP +* HTTPS +* IPv4 +* IPv6 +* IPFS (deprecated - use P2P) +* Onion +* P2P +* SCTP +* TCP +* UDP +* UDT +* Unix +* WebRTCDirect +* WebRTCStar +* WebSocket +* WebSocket Secure + +## Maintainers + +Captain: [@tabrath](https://github.com/tabrath). + +## Contribute + +Contributions welcome. Please check out [the issues](https://github.com/multiformats/cs-multiaddress/issues). + +Check out our [contributing document](https://github.com/multiformats/multiformats/blob/master/contributing.md) for more information on how we work, and about contributing in general. Please be aware that all interactions related to multiformats are subject to the IPFS [Code of Conduct](https://github.com/ipfs/community/blob/master/code-of-conduct.md). + +Small note: If editing the README, please conform to the [standard-readme](https://github.com/RichardLitt/standard-readme) specification. + +## License + +[MIT](LICENSE) © 2017 Trond BrÃ¥then diff --git a/src/cs-multiaddress/appveyor.yml b/src/cs-multiaddress/appveyor.yml new file mode 100644 index 00000000..c7645af5 --- /dev/null +++ b/src/cs-multiaddress/appveyor.yml @@ -0,0 +1,113 @@ +environment: + PKG_VERSION: 1.1.1 + VERSION_SUFFIX: "" +version: ${PKG_VERSION}-{build} +configuration: Release +platform: x64 + +skip_commits: + message: /travis/ + files: + - '**\*.md' + - LICENSE + +skip_branch_with_pr: true + +matrix: + fast_finish: true + +init: + - git config --global core.autocrlf input + - ps: $env:BUILD_VERSION = "$env:PKG_VERSION-$env:APPVEYOR_BUILD_NUMBER" + - ps: | + if ($env:APPVEYOR_REPO_BRANCH -eq "master") + { + $env:VERSION_SUFFIX = "" + $env:NUGET_VERSION = "$env:PKG_VERSION" + } + else + { + $env:VERSION_SUFFIX = "beta$env:APPVEYOR_BUILD_NUMBER" + $env:NUGET_VERSION = "$env:PKG_VERSION-$env:VERSION_SUFFIX" + } + - ps: Update-AppveyorBuild -Version $env:BUILD_VERSION + - ps: Write-Host "Build version $env:BUILD_VERSION, NuGet version $env:NUGET_VERSION, Version suffix $env:VERSION_SUFFIX" + +install: + - git submodule update --init --recursive + +before_build: + - appveyor-retry dotnet restore -v Minimal + +build_script: + - ps: | + if ($env:APPVEYOR_REPO_BRANCH -eq "master") + { + dotnet build "src\Multiformats.Address" -c $env:CONFIGURATION + } + else + { + dotnet build "src\Multiformats.Address" -c $env:CONFIGURATION --version-suffix $env:VERSION_SUFFIX + } + +after_build: + - ps: | + if ($env:APPVEYOR_REPO_BRANCH -eq "master") + { + dotnet pack "src\Multiformats.Address" -c $env:CONFIGURATION --no-build -o $env:APPVEYOR_BUILD_FOLDER\artifacts + } + else + { + dotnet pack "src\Multiformats.Address" -c $env:CONFIGURATION --no-build --version-suffix $env:VERSION_SUFFIX -o $env:APPVEYOR_BUILD_FOLDER\artifacts + } + +test: off + +before_test: + - nuget install OpenCover -Version 4.6.519 -OutputDirectory .\tools + +test_script: + - .\tools\OpenCover.4.6.519\tools\OpenCover.Console.exe -register:user -returntargetcode -target:"%ProgramFiles%\dotnet\dotnet.exe" -targetargs:"test %APPVEYOR_BUILD_FOLDER%\test\Multiformats.Address.Tests\Multiformats.Address.Tests.csproj -c Debug -f netcoreapp1.1 -l trx;logfilename=TestResult.xml /p:Platform=AnyCPU" -filter:"+[Multiformats.Address]* -[Multiformats.Address.Benchmarks]* -[Multiformats.Address.Tests]*" -excludebyattribute:*.ExcludeFromCodeCoverage* -hideskipped:All -output:"%APPVEYOR_BUILD_FOLDER%\coverage.xml" -oldStyle + +after_test: + - ps: | + $wc = New-Object 'System.Net.WebClient' + $wc.UploadFile("https://ci.appveyor.com/api/testresults/xunit/$($env:APPVEYOR_JOB_ID)", (Resolve-Path .\test\Multiformats.Address.Tests\TestResults\TestResult.xml)) + +on_success: + - "SET PATH=C:\\Python34;C:\\Python34\\Scripts;%PATH%" + - pip install codecov + - codecov -f "%APPVEYOR_BUILD_FOLDER%\coverage.xml" -X gcov + +artifacts: + - path: artifacts\**\*.* + +cache: + - '%USERPROFILE%\.local' + - '%USERPROFILE%\.nuget\packages -> **\project.json' + - '%LocalAppData%\NuGet\Cache' + - '%LocalAppData%\Python' + - '.\packages -> **\project.json' + - '.\tools' + - '\Python34' + +nuget: + account_feed: true + +deploy: + - provider: NuGet + api_key: + secure: WcDqU36pLPvA+s5D4N0VEsi7AZGewvf4croE/D3rh3F+iqiztq9w5gHbrhgoTNS9 + on: + branch: master + appveyor_repo_tag: true + - provider: GitHub + description: 'Release description' + auth_token: + secure: nsZHZ5nFBFP4fZoVUEeWeZKx7LUASVqCZ+JblTox+02RfTAOlANdFWeCqOwhu7pk + artifact: /.*\.nupkg/ # upload all NuGet packages to release assets + draft: false + prerelease: false + on: + branch: master # release from master branch only + appveyor_repo_tag: true diff --git a/src/cs-multiaddress/build.sh b/src/cs-multiaddress/build.sh new file mode 100644 index 00000000..7c22621c --- /dev/null +++ b/src/cs-multiaddress/build.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash + +set -e + +if [ $TRAVIS_OS_NAME = "osx" ]; then + ulimit -n 1024 + dotnet restore --disable-parallel --runtime osx-x64 +else + dotnet restore --runtime ubuntu-x64 +fi + +export FrameworkPathOverride=$(dirname $(which mono))/../lib/mono/4.5/ + +dotnet test ./test/Multiformats.Address.Tests/Multiformats.Address.Tests.csproj -c Release -f netcoreapp1.1 +dotnet build ./test/Multiformats.Address.Tests/Multiformats.Address.Tests.csproj -c Release -f net461 + +mono $HOME/.nuget/packages/xunit.runner.console/2.3.1/tools/net452/xunit.console.exe ./test/Multiformats.Address.Tests/bin/Release/net461/Multiformats.Address.Tests.dll diff --git a/src/cs-multiaddress/src/Multiformats.Address/Extensions.cs b/src/cs-multiaddress/src/Multiformats.Address/Extensions.cs new file mode 100644 index 00000000..5b7d412a --- /dev/null +++ b/src/cs-multiaddress/src/Multiformats.Address/Extensions.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Multiformats.Address +{ + internal static class Extensions + { + public static T[] Slice(this T[] array, int offset, int? count = null) + { + var result = new T[count ?? array.Length - offset]; + Array.Copy(array, offset, result, 0, result.Length); + return result; + } + } +} diff --git a/src/cs-multiaddress/src/Multiformats.Address/Multiaddress.cs b/src/cs-multiaddress/src/Multiformats.Address/Multiaddress.cs new file mode 100644 index 00000000..b38e8d10 --- /dev/null +++ b/src/cs-multiaddress/src/Multiformats.Address/Multiaddress.cs @@ -0,0 +1,256 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using BinaryEncoding; +using Multiformats.Address.Protocols; +using Multiformats.Hash; + +namespace Multiformats.Address +{ + public class Multiaddress : IEquatable + { + static Multiaddress() + { + Setup("ip4", 4, 32, false, ip => ip != null ? new IP4((IPAddress)ip) : new IP4()); + Setup("ip6", 41, 128, false, ip => ip != null ? new IP6((IPAddress)ip) : new IP6()); + Setup("tcp", 6, 16, false, port => port != null ? new TCP((ushort)port) : new TCP()); + Setup("udp", 17, 16, false, port => port != null ? new UDP((ushort)port) : new UDP()); + Setup("p2p", 420, -1, false, address => address != null ? address is Multihash ? new P2P((Multihash)address) : new P2P((string)address) : new P2P()); + Setup("ipfs", 421, -1, false, address => address != null ? address is Multihash ? new IPFS((Multihash)address) : new IPFS((string)address) : new IPFS()); + Setup("ws", 477, 0, false, _ => new WebSocket()); + Setup("wss", 478, 0, false, _ => new WebSocketSecure()); + Setup("dccp", 33, 16, false, port => port != null ? new DCCP((short)port) : new DCCP()); + Setup("sctp", 132, 16, false, port => port != null ? new SCTP((short)port) : new SCTP()); + Setup("unix", 400, -1, true, address => address != null ? new Unix((string)address) : new Unix()); + Setup("onion", 444, 96, false, address => address != null ? new Onion((string)address) : new Onion()); + Setup("quic", 460, 0, false, _ => new QUIC()); + Setup("http", 480, 0, false, _ => new HTTP()); + Setup("https", 443, 0, false, _ => new HTTPS()); + Setup("utp", 301, 0, false, _ => new UTP()); + Setup("udt", 302, 0, false, _ => new UDT()); + Setup("dns", 53, -1, false, address => address != null ? new DNS((string)address) : new DNS()); + Setup("dns4", 54, -1, false, address => address != null ? new DNS4((string)address) : new DNS4()); + Setup("dns6", 55, -1, false, address => address != null ? new DNS6((string)address) : new DNS6()); + Setup("p2p-circuit", 290, 0, false, _ => new P2PCircuit()); + Setup("p2p-webrtc-star", 275, 0, false, _ => new P2PWebRTCStar()); + Setup("p2p-webrtc-direct", 276, 0, false, _ => new P2PWebRTCStar()); + Setup("p2p-websocket-star", 479, 0, false, _ => new P2PWebSocketStar()); + } + + private class Protocol + { + public string Name { get; } + public int Code { get; } + public int Size { get; } + public Func Factory { get; } + public Type Type { get; } + public bool Path { get; } + + public Protocol(string name, int code, int size, Type type, bool path, Func factory) + { + Name = name; + Code = code; + Size = size; + Type = type; + Path = path; + Factory = factory; + } + + } + private static readonly List _protocols = new List(); + + private static void Setup(string name, int code, int size, bool path, Func factory) + where TProtocol : MultiaddressProtocol + { + _protocols.Add(new Protocol(name, code, size, typeof(TProtocol), path, factory)); + } + + public List Protocols { get; } + + public Multiaddress() + { + Protocols = new List(); + } + + public Multiaddress Add(object value) + where TProtocol : MultiaddressProtocol + { + var proto = _protocols.SingleOrDefault(p => p.Type == typeof(TProtocol)); + Protocols.Add(proto.Factory(value)); + return this; + } + + public Multiaddress Add() where TProtocol : MultiaddressProtocol => Add(null); + + public Multiaddress Add(params MultiaddressProtocol[] protocols) + { + Protocols.AddRange(protocols); + return this; + } + + public TProtocol Get() where TProtocol : MultiaddressProtocol => Protocols.OfType().SingleOrDefault(); + + public void Remove() where TProtocol : MultiaddressProtocol + { + var protocol = Get(); + if (protocol != null) + Protocols.Remove(protocol); + } + + private static bool SupportsProtocol(string name) => _protocols.Any(p => p.Name.Equals(name)); + private static bool SupportsProtocol(int code) => _protocols.Any(p => p.Code.Equals(code)); + + private static MultiaddressProtocol CreateProtocol(string name) => _protocols.SingleOrDefault(p => p.Name == name)?.Factory(null); + private static MultiaddressProtocol CreateProtocol(int code) => _protocols.SingleOrDefault(p => p.Code == code)?.Factory(null); + + public static Multiaddress Decode(string value) => new Multiaddress().Add(DecodeProtocols(value.Split(new [] { '/' }, StringSplitOptions.RemoveEmptyEntries)).ToArray()); + public static Multiaddress Decode(byte[] bytes) => new Multiaddress().Add(DecodeProtocols(bytes).ToArray()); + + private static IEnumerable DecodeProtocols(params string[] parts) + { + for (var i = 0; i < parts.Length; i++) + { + if (!SupportsProtocol(parts[i])) + throw new NotSupportedException(parts[i]); + + var protocol = CreateProtocol(parts[i]); + if (protocol.Size != 0) + { + if (i + 1 >= parts.Length) + throw new Exception("Required parameter not found"); + + if (_protocols.SingleOrDefault(p => p.Code == protocol.Code).Path) + { + protocol.Decode(string.Join("/", parts.Slice(i + 1))); + i = parts.Length - 1; + } + else + { + protocol.Decode(parts[++i]); + } + } + + yield return protocol; + } + } + + private static IEnumerable DecodeProtocols(byte[] bytes) + { + var offset = 0; + short code = 0; + MultiaddressProtocol protocol = null; + while (offset < bytes.Length) + { + offset += ParseProtocolCode(bytes, offset, out code); + if (SupportsProtocol(code)) + { + offset += ParseProtocol(bytes, offset, code, out protocol); + + yield return protocol; + } + } + } + + private static int ParseProtocol(byte[] bytes, int offset, short code, out MultiaddressProtocol protocol) + { + var start = offset; + protocol = CreateProtocol(code); + offset += DecodeProtocol(protocol, bytes, offset); + return offset - start; + } + + private static int ParseProtocolCode(byte[] bytes, int offset, out short code) + { + code = Binary.LittleEndian.GetInt16(bytes, offset); + return 2; + } + + private static int DecodeProtocol(MultiaddressProtocol protocol, byte[] bytes, int offset) + { + int start = offset; + int count = 0; + if (protocol.Size > 0) + { + count = protocol.Size/8; + } + else if (protocol.Size == -1) + { + uint proxy = 0; + offset += Binary.Varint.Read(bytes, offset, out proxy); + count = (int) proxy; + } + + if (count > 0) + { + protocol.Decode(bytes.Slice(offset, count)); + offset += count; + } + + return offset - start; + } + + public override string ToString() => Protocols.Count > 0 ? "/" + string.Join("/", Protocols.SelectMany(ProtocolToStrings)) : string.Empty; + + private static IEnumerable ProtocolToStrings(MultiaddressProtocol p) + { + yield return p.Name; + if (p.Value != null) + yield return p.Value.ToString(); + } + + public byte[] ToBytes() => Protocols.SelectMany(EncodeProtocol).ToArray(); + + private static IEnumerable EncodeProtocol(MultiaddressProtocol p) + { + var code = Binary.Varint.GetBytes((ulong)p.Code); + + if (p.Size == 0) + return code; + + var bytes = p.ToBytes(); + + if (p.Size > 0) + return code.Concat(bytes); + + var prefix = Binary.Varint.GetBytes((ulong)bytes.Length); + + return code.Concat(prefix).Concat(bytes); + } + + public IEnumerable Split() => Protocols.Select(p => new Multiaddress().Add(p)); + + public static Multiaddress Join(IEnumerable addresses) + { + var result = new Multiaddress(); + foreach (var address in addresses) + { + result.Add(address.Protocols.ToArray()); + } + return result; + } + + public Multiaddress Encapsulate(Multiaddress address) + { + return new Multiaddress() + .Add(Protocols.Concat(address.Protocols).ToArray()); + } + + public Multiaddress Decapsulate(Multiaddress address) + { + return new Multiaddress() + .Add(Protocols.TakeWhile(p => !address.Protocols.Any(p.Equals)).ToArray()); + } + + public override bool Equals(object obj) => Equals((Multiaddress)obj); + public bool Equals(Multiaddress other) => other != null && ToBytes().SequenceEqual(other.ToBytes()); + + public static implicit operator Multiaddress(string value) + { + return Decode(value); + } + + public bool Has() where T : MultiaddressProtocol + => Protocols.OfType().Any(); + } +} diff --git a/src/cs-multiaddress/src/Multiformats.Address/Multiformats.Address.csproj b/src/cs-multiaddress/src/Multiformats.Address/Multiformats.Address.csproj new file mode 100644 index 00000000..8fb0f999 --- /dev/null +++ b/src/cs-multiaddress/src/Multiformats.Address/Multiformats.Address.csproj @@ -0,0 +1,43 @@ + + + netstandard1.6;net461 + win10-x64;osx-x64;ubuntu-x64 + Multiformat addresses + Copyright © tabrath 2017 + Multiformats.Address + 1.1.1 + tabrath + true + Multiformats.Address + Multiformats.Address + multiaddress + https://cdn.rawgit.com/multiformats/website/116894f6/favicon.png + https://github.com/multiformats/cs-multiaddress/blob/master/LICENSE + git + https://github.com/multiformats/cs-multiaddress + $(PackageTargetFallback);netstandard;portable-net461+win8 + 1.6.1 + AnyCPU + Library + https://github.com/multiformats/cs-multiaddress + + + true + full + false + $(DefineConstants);DEBUG + + + pdbonly + true + $(DefineConstants) + + + + + + + + + + diff --git a/src/cs-multiaddress/src/Multiformats.Address/Net/MultiaddressExtensions.cs b/src/cs-multiaddress/src/Multiformats.Address/Net/MultiaddressExtensions.cs new file mode 100644 index 00000000..7342591f --- /dev/null +++ b/src/cs-multiaddress/src/Multiformats.Address/Net/MultiaddressExtensions.cs @@ -0,0 +1,201 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Net.NetworkInformation; +using System.Net.Sockets; +using System.Threading.Tasks; +using Multiformats.Address.Protocols; + +namespace Multiformats.Address.Net +{ + public static class MultiaddressExtensions + { + public static Multiaddress GetLocalMultiaddress(this Socket socket) => socket.LocalEndPoint.ToMultiaddress(socket.ProtocolType); + public static Multiaddress GetRemoteMultiaddress(this Socket socket) => socket.RemoteEndPoint.ToMultiaddress(socket.ProtocolType); + + public static Multiaddress ToMultiaddress(this EndPoint ep, ProtocolType protocolType) + { + var ma = new Multiaddress(); + + var ip = (IPEndPoint) ep; + if (ip != null) + { + if (ip.AddressFamily == AddressFamily.InterNetwork) + ma.Add(ip.Address); + if (ip.AddressFamily == AddressFamily.InterNetworkV6) + ma.Add(ip.Address); + + if (protocolType == ProtocolType.Tcp) + ma.Add((ushort) ip.Port); + if (protocolType == ProtocolType.Udp) + ma.Add((ushort) ip.Port); + } + + return ma; + } + + public static Multiaddress ToMultiaddress(this IPAddress ip) + { + var ma = new Multiaddress(); + if (ip.AddressFamily == AddressFamily.InterNetwork) + ma.Add(ip); + if (ip.AddressFamily == AddressFamily.InterNetworkV6) + ma.Add(ip); + return ma; + } + + public static IPEndPoint ToEndPoint(this Multiaddress ma) + { + ProtocolType pt; + return ToEndPoint(ma, out pt); + } + + public static IPEndPoint ToEndPoint(this Multiaddress ma, out ProtocolType protocolType) + { + SocketType st; + return ToEndPoint(ma, out protocolType, out st); + } + + public static IPEndPoint ToEndPoint(this Multiaddress ma, out ProtocolType protocolType, out SocketType socketType) + { + IPAddress addr = null; + IP ip = ma.Protocols.OfType().SingleOrDefault(); + if (ip != null) + addr = (IPAddress) ip.Value; + else + { + ip = ma.Protocols.OfType().SingleOrDefault(); + if (ip != null) + addr = (IPAddress) ip.Value; + } + + int? port = null; + Number n = ma.Protocols.OfType().SingleOrDefault(); + if (n != null) + { + port = (ushort) n.Value; + protocolType = ProtocolType.Tcp; + socketType = SocketType.Stream; + } + else + { + n = ma.Protocols.OfType().SingleOrDefault(); + if (n != null) + { + port = (ushort) n.Value; + protocolType = ProtocolType.Udp; + socketType = SocketType.Dgram; + } + else + { + protocolType = ProtocolType.Unknown; + socketType = SocketType.Unknown; + } + } + + return new IPEndPoint(addr ?? IPAddress.Any, port ?? 0); + } + + public static Socket CreateSocket(this Multiaddress ma) + { + IPEndPoint ep; + return CreateSocket(ma, out ep); + } + + public static Socket CreateSocket(this Multiaddress ma, out IPEndPoint ep) + { + ProtocolType pt; + SocketType st; + ep = ma.ToEndPoint(out pt, out st); + + return new Socket(ep.AddressFamily, st, pt); + } + + public static Socket CreateConnection(this Multiaddress ma) + { + IPEndPoint ep; + var socket = CreateSocket(ma, out ep); + socket.Connect(ep); + return socket; + } + + public static Task CreateConnectionAsync(this Multiaddress ma) + { + IPEndPoint ep; + var socket = CreateSocket(ma, out ep); + +#if NETSTANDARD1_6 + return socket.ConnectAsync(ep) + .ContinueWith(_ => socket); +#else + var tcs = new TaskCompletionSource(); + + try + { + socket.BeginConnect(ep, ar => + { + try + { + socket.EndConnect(ar); + tcs.TrySetResult(socket); + } + catch (Exception e) + { + tcs.TrySetException(e); + } + }, null); + } + catch (Exception e) + { + tcs.TrySetException(e); + } + + return tcs.Task; +#endif + } + + public static Socket CreateListener(this Multiaddress ma, int backlog = 10) + { + IPEndPoint ep; + var socket = CreateSocket(ma, out ep); + socket.Bind(ep); + socket.Listen(backlog); + return socket; + } + + public static bool IsThinWaist(this Multiaddress ma) + { + if (!ma.Protocols.Any()) + return false; + + if (!(ma.Protocols[0] is IP4) && !(ma.Protocols[0] is IP6)) + return false; + + if (ma.Protocols.Count == 1) + return true; + + return ma.Protocols[1] is TCP || ma.Protocols[1] is UDP || + ma.Protocols[1] is IP4 || ma.Protocols[1] is IP6; + } + + public static IEnumerable GetMultiaddresses(this NetworkInterface nic) + { + return nic + .GetIPProperties() + .UnicastAddresses + .Select(addr => addr.Address.ToMultiaddress()); + } + + public static IEnumerable Match(this Multiaddress match, params Multiaddress[] addrs) + { + foreach (var a in addrs.Where(x => match.Protocols.Count == x.Protocols.Count)) + { + var i = 0; + + if (a.Protocols.All(p2 => match.Protocols[i++].Code == p2.Code)) + yield return a; + } + } + } +} \ No newline at end of file diff --git a/src/cs-multiaddress/src/Multiformats.Address/Net/MultiaddressTools.cs b/src/cs-multiaddress/src/Multiformats.Address/Net/MultiaddressTools.cs new file mode 100644 index 00000000..17c34112 --- /dev/null +++ b/src/cs-multiaddress/src/Multiformats.Address/Net/MultiaddressTools.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.NetworkInformation; + +namespace Multiformats.Address.Net +{ + public static class MultiaddressTools + { + public static IEnumerable GetInterfaceMultiaddresses() + { +#if __MonoCS__ + return Array.Empty(); +#else + return NetworkInterface + .GetAllNetworkInterfaces() + .SelectMany(MultiaddressExtensions.GetMultiaddresses); +#endif + } + } +} diff --git a/src/cs-multiaddress/src/Multiformats.Address/Protocols/DCCP.cs b/src/cs-multiaddress/src/Multiformats.Address/Protocols/DCCP.cs new file mode 100644 index 00000000..568e16d7 --- /dev/null +++ b/src/cs-multiaddress/src/Multiformats.Address/Protocols/DCCP.cs @@ -0,0 +1,16 @@ +namespace Multiformats.Address.Protocols +{ + public class DCCP : Number + { + public DCCP() + : base("dccp", 33) + { + } + + public DCCP(int port) + : this() + { + Value = port; + } + } +} diff --git a/src/cs-multiaddress/src/Multiformats.Address/Protocols/DNS.cs b/src/cs-multiaddress/src/Multiformats.Address/Protocols/DNS.cs new file mode 100644 index 00000000..758ae388 --- /dev/null +++ b/src/cs-multiaddress/src/Multiformats.Address/Protocols/DNS.cs @@ -0,0 +1,24 @@ +using System.Text; +using Multiformats.Hash; + +namespace Multiformats.Address.Protocols +{ + public class DNS : MultiaddressProtocol + { + public DNS() + : base("dns", 53, -1) + { + } + + public DNS(string address) + : this() + { + Value = address; + } + + public override void Decode(string value) => Value = value; + public override void Decode(byte[] bytes) => Value = Encoding.UTF8.GetString(bytes); + public override byte[] ToBytes() => Encoding.UTF8.GetBytes((string)Value); + public override string ToString() => (string)Value ?? string.Empty; + } +} diff --git a/src/cs-multiaddress/src/Multiformats.Address/Protocols/DNS4.cs b/src/cs-multiaddress/src/Multiformats.Address/Protocols/DNS4.cs new file mode 100644 index 00000000..e38c9b3e --- /dev/null +++ b/src/cs-multiaddress/src/Multiformats.Address/Protocols/DNS4.cs @@ -0,0 +1,24 @@ +using System.Text; +using Multiformats.Hash; + +namespace Multiformats.Address.Protocols +{ + public class DNS4 : MultiaddressProtocol + { + public DNS4() + : base("dns4", 54, -1) + { + } + + public DNS4(string address) + : this() + { + Value = address; + } + + public override void Decode(string value) => Value = value; + public override void Decode(byte[] bytes) => Value = Encoding.UTF8.GetString(bytes); + public override byte[] ToBytes() => Encoding.UTF8.GetBytes((string)Value); + public override string ToString() => (string)Value ?? string.Empty; + } +} diff --git a/src/cs-multiaddress/src/Multiformats.Address/Protocols/DNS6.cs b/src/cs-multiaddress/src/Multiformats.Address/Protocols/DNS6.cs new file mode 100644 index 00000000..5794d1da --- /dev/null +++ b/src/cs-multiaddress/src/Multiformats.Address/Protocols/DNS6.cs @@ -0,0 +1,24 @@ +using System.Text; +using Multiformats.Hash; + +namespace Multiformats.Address.Protocols +{ + public class DNS6 : MultiaddressProtocol + { + public DNS6() + : base("dns6", 55, -1) + { + } + + public DNS6(string address) + : this() + { + Value = address; + } + + public override void Decode(string value) => Value = value; + public override void Decode(byte[] bytes) => Value = Encoding.UTF8.GetString(bytes); + public override byte[] ToBytes() => Encoding.UTF8.GetBytes((string)Value); + public override string ToString() => (string)Value ?? string.Empty; + } +} diff --git a/src/cs-multiaddress/src/Multiformats.Address/Protocols/HTTP.cs b/src/cs-multiaddress/src/Multiformats.Address/Protocols/HTTP.cs new file mode 100644 index 00000000..b3015ad3 --- /dev/null +++ b/src/cs-multiaddress/src/Multiformats.Address/Protocols/HTTP.cs @@ -0,0 +1,22 @@ +using System; + +namespace Multiformats.Address.Protocols +{ + public class HTTP : MultiaddressProtocol + { + public HTTP() + : base("http", 480, 0) + { + } + + public override void Decode(string value) + { + } + + public override void Decode(byte[] bytes) + { + } + + public override byte[] ToBytes() => EmptyBuffer; + } +} \ No newline at end of file diff --git a/src/cs-multiaddress/src/Multiformats.Address/Protocols/HTTPS.cs b/src/cs-multiaddress/src/Multiformats.Address/Protocols/HTTPS.cs new file mode 100644 index 00000000..dbde99e7 --- /dev/null +++ b/src/cs-multiaddress/src/Multiformats.Address/Protocols/HTTPS.cs @@ -0,0 +1,22 @@ +using System; + +namespace Multiformats.Address.Protocols +{ + public class HTTPS : MultiaddressProtocol + { + public HTTPS() + : base("https", 480, 0) + { + } + + public override void Decode(string value) + { + } + + public override void Decode(byte[] bytes) + { + } + + public override byte[] ToBytes() => EmptyBuffer; + } +} \ No newline at end of file diff --git a/src/cs-multiaddress/src/Multiformats.Address/Protocols/IP.cs b/src/cs-multiaddress/src/Multiformats.Address/Protocols/IP.cs new file mode 100644 index 00000000..17e3245a --- /dev/null +++ b/src/cs-multiaddress/src/Multiformats.Address/Protocols/IP.cs @@ -0,0 +1,20 @@ +using System.Net; + +namespace Multiformats.Address.Protocols +{ + public abstract class IP : MultiaddressProtocol + { + public IPAddress Address => Value != null ? (IPAddress) Value : IPAddress.None; + + protected IP(string name, int code, int size) + : base(name, code, size) + { + } + + public override void Decode(string value) => Value = IPAddress.Parse(value); + public override void Decode(byte[] bytes) => Value = new IPAddress(bytes); + public override byte[] ToBytes() => Address.GetAddressBytes(); + public override string ToString() => Address.ToString(); + } + +} diff --git a/src/cs-multiaddress/src/Multiformats.Address/Protocols/IP4.cs b/src/cs-multiaddress/src/Multiformats.Address/Protocols/IP4.cs new file mode 100644 index 00000000..1ae278c6 --- /dev/null +++ b/src/cs-multiaddress/src/Multiformats.Address/Protocols/IP4.cs @@ -0,0 +1,39 @@ +using System; +using System.Net; +using System.Net.Sockets; + +namespace Multiformats.Address.Protocols +{ + public class IP4 : IP + { + public IP4() + : base("ip4", 4, 32) + { + } + + public IP4(IPAddress address) + : this() + { + if (address.AddressFamily != AddressFamily.InterNetwork) + throw new Exception("Address is not IPv4"); + + Value = address; + } + + public override void Decode(string value) + { + base.Decode(value); + + if (Value != null && ((IPAddress)Value).AddressFamily != AddressFamily.InterNetwork) + throw new Exception("Address is not IPv4"); + } + + public override void Decode(byte[] bytes) + { + base.Decode(bytes); + + if (Value != null && ((IPAddress)Value).AddressFamily != AddressFamily.InterNetwork) + throw new Exception("Address is not IPv4"); + } + } +} diff --git a/src/cs-multiaddress/src/Multiformats.Address/Protocols/IP6.cs b/src/cs-multiaddress/src/Multiformats.Address/Protocols/IP6.cs new file mode 100644 index 00000000..dcd93e1b --- /dev/null +++ b/src/cs-multiaddress/src/Multiformats.Address/Protocols/IP6.cs @@ -0,0 +1,39 @@ +using System; +using System.Net; +using System.Net.Sockets; + +namespace Multiformats.Address.Protocols +{ + public class IP6 : IP + { + public IP6() + : base("ip6", 41, 128) + { + } + + public IP6(IPAddress address) + : this() + { + if (address.AddressFamily != AddressFamily.InterNetworkV6) + throw new Exception("Address is not IPv6"); + + Value = address; + } + + public override void Decode(string value) + { + base.Decode(value); + + if (Value != null && ((IPAddress)Value).AddressFamily != AddressFamily.InterNetworkV6) + throw new Exception("Address is not IPv6"); + } + + public override void Decode(byte[] bytes) + { + base.Decode(bytes); + + if (Value != null && ((IPAddress)Value).AddressFamily != AddressFamily.InterNetworkV6) + throw new Exception("Address is not IPv6"); + } + } +} diff --git a/src/cs-multiaddress/src/Multiformats.Address/Protocols/IPFS.cs b/src/cs-multiaddress/src/Multiformats.Address/Protocols/IPFS.cs new file mode 100644 index 00000000..1be3f387 --- /dev/null +++ b/src/cs-multiaddress/src/Multiformats.Address/Protocols/IPFS.cs @@ -0,0 +1,30 @@ +using System; +using Multiformats.Hash; + +namespace Multiformats.Address.Protocols +{ + [Obsolete("Use P2P instead")] + public class IPFS : MultiaddressProtocol + { + public IPFS() + : base("ipfs", 421, -1) + { + } + + public IPFS(string address) + : this(Multihash.FromB58String(address)) + { + } + + public IPFS(Multihash address) + : this() + { + Value = address; + } + + public override void Decode(string value) => Value = Multihash.FromB58String(value); + public override void Decode(byte[] bytes) => Value = Multihash.Decode(bytes); + public override byte[] ToBytes() => (Multihash)Value; + public override string ToString() => ((Multihash)Value)?.B58String() ?? string.Empty; + } +} diff --git a/src/cs-multiaddress/src/Multiformats.Address/Protocols/MultiaddressProtocol.cs b/src/cs-multiaddress/src/Multiformats.Address/Protocols/MultiaddressProtocol.cs new file mode 100644 index 00000000..cb480046 --- /dev/null +++ b/src/cs-multiaddress/src/Multiformats.Address/Protocols/MultiaddressProtocol.cs @@ -0,0 +1,40 @@ +using System; + +namespace Multiformats.Address.Protocols +{ + public abstract class MultiaddressProtocol : IEquatable + { + public string Name { get; } + public int Code { get; } + public int Size { get; } + public object Value { get; protected set; } + + protected static readonly byte[] EmptyBuffer = new byte[] {}; + + protected MultiaddressProtocol(string name, int code, int size) + { + Name = name; + Code = code; + Size = size; + } + + public abstract void Decode(string value); + public abstract void Decode(byte[] bytes); + public abstract byte[] ToBytes(); + + public bool Equals(MultiaddressProtocol other) + { + var eq = Name.Equals(other.Name) && + Code.Equals(other.Code) && + Size.Equals(other.Size) && + Value.Equals(other.Value); + + return eq; + } + + public override bool Equals(object obj) => Equals((MultiaddressProtocol)obj); + + public override string ToString() => Value?.ToString() ?? string.Empty; + public override int GetHashCode() => Value?.GetHashCode() ?? Code ^ Size; + } +} diff --git a/src/cs-multiaddress/src/Multiformats.Address/Protocols/Number.cs b/src/cs-multiaddress/src/Multiformats.Address/Protocols/Number.cs new file mode 100644 index 00000000..f1b5c842 --- /dev/null +++ b/src/cs-multiaddress/src/Multiformats.Address/Protocols/Number.cs @@ -0,0 +1,19 @@ +using System.Globalization; +using BinaryEncoding; + +namespace Multiformats.Address.Protocols +{ + public abstract class Number : MultiaddressProtocol + { + public ushort Port => (ushort?) Value ?? 0; + + protected Number(string name, int code) + : base(name, code, 16) + { + } + + public override void Decode(string value) => Value = ushort.Parse(value, NumberStyles.Number); + public override void Decode(byte[] bytes) => Value = Binary.BigEndian.GetUInt16(bytes, 0); + public override byte[] ToBytes() => Binary.BigEndian.GetBytes((ushort)Value); + } +} diff --git a/src/cs-multiaddress/src/Multiformats.Address/Protocols/Onion.cs b/src/cs-multiaddress/src/Multiformats.Address/Protocols/Onion.cs new file mode 100644 index 00000000..8acb74c9 --- /dev/null +++ b/src/cs-multiaddress/src/Multiformats.Address/Protocols/Onion.cs @@ -0,0 +1,70 @@ +using System; +using System.Linq; +using BinaryEncoding; +using Multiformats.Base; + +namespace Multiformats.Address.Protocols +{ + public class Onion : MultiaddressProtocol + { + public string Address => Value != null ? (string) Value : string.Empty; + + public Onion() + : base("onion", 444, 96) + { + } + + public Onion(string s) + : this() + { + Value = s; + } + + public override void Decode(string value) + { + var addr = value.Split(':'); + if (addr.Length != 2) + throw new Exception("Failed to parse addr"); + + if (addr[0].Length != 16) + throw new Exception("Failed to parse addr"); + + if (!Multibase.TryDecode(addr[0], out var encoding, out _) || encoding != MultibaseEncoding.Base32Lower) + throw new InvalidOperationException($"{value} is not a valid onion address."); + + var i = ushort.Parse(addr[1]); + if (i < 1) + throw new Exception("Failed to parse addr"); + + Value = value; + } + + public override void Decode(byte[] bytes) + { + var addr = Multibase.Base32.Encode(bytes.Slice(0, 10)); + var port = Binary.BigEndian.GetUInt16(bytes, 10); + + Value = $"{addr}:{port}"; + } + + public override byte[] ToBytes() + { + var s = (string) Value; + var addr = s.Split(':'); + if (addr.Length != 2) + throw new Exception("Failed to parse addr"); + + if (addr[0].Length != 16) + throw new Exception("Failed to parse addr"); + + if (!Multibase.TryDecode(addr[0], out var encoding, out var onionHostBytes) || encoding != MultibaseEncoding.Base32Lower) + throw new InvalidOperationException($"{s} is not a valid onion address."); + + var i = ushort.Parse(addr[1]); + if (i < 1) + throw new Exception("Failed to parse addr"); + + return onionHostBytes.Concat(Binary.BigEndian.GetBytes(i)).ToArray(); + } + } +} diff --git a/src/cs-multiaddress/src/Multiformats.Address/Protocols/P2P.Circuit.cs b/src/cs-multiaddress/src/Multiformats.Address/Protocols/P2P.Circuit.cs new file mode 100644 index 00000000..bb04db0d --- /dev/null +++ b/src/cs-multiaddress/src/Multiformats.Address/Protocols/P2P.Circuit.cs @@ -0,0 +1,20 @@ +namespace Multiformats.Address.Protocols +{ + public class P2PCircuit : MultiaddressProtocol + { + public P2PCircuit() + : base("p2p-circuit", 290, 0) + { + } + + public override void Decode(string value) + { + } + + public override void Decode(byte[] bytes) + { + } + + public override byte[] ToBytes() => EmptyBuffer; + } +} diff --git a/src/cs-multiaddress/src/Multiformats.Address/Protocols/P2P.Web.RTC.Star.cs b/src/cs-multiaddress/src/Multiformats.Address/Protocols/P2P.Web.RTC.Star.cs new file mode 100644 index 00000000..9b2d4511 --- /dev/null +++ b/src/cs-multiaddress/src/Multiformats.Address/Protocols/P2P.Web.RTC.Star.cs @@ -0,0 +1,20 @@ +namespace Multiformats.Address.Protocols +{ + public class P2PWebRTCStar : MultiaddressProtocol + { + public P2PWebRTCStar() + : base("p2p-webrtc-star", 275, 0) + { + } + + public override void Decode(string value) + { + } + + public override void Decode(byte[] bytes) + { + } + + public override byte[] ToBytes() => EmptyBuffer; + } +} diff --git a/src/cs-multiaddress/src/Multiformats.Address/Protocols/P2P.WebRTC.Direct.cs b/src/cs-multiaddress/src/Multiformats.Address/Protocols/P2P.WebRTC.Direct.cs new file mode 100644 index 00000000..a3e00bec --- /dev/null +++ b/src/cs-multiaddress/src/Multiformats.Address/Protocols/P2P.WebRTC.Direct.cs @@ -0,0 +1,20 @@ +namespace Multiformats.Address.Protocols +{ + public class P2PWebRTCDirect : MultiaddressProtocol + { + public P2PWebRTCDirect() + : base("p2p-webrtc-direct", 276, 0) + { + } + + public override void Decode(string value) + { + } + + public override void Decode(byte[] bytes) + { + } + + public override byte[] ToBytes() => EmptyBuffer; + } +} diff --git a/src/cs-multiaddress/src/Multiformats.Address/Protocols/P2P.WebSocket.Star.cs b/src/cs-multiaddress/src/Multiformats.Address/Protocols/P2P.WebSocket.Star.cs new file mode 100644 index 00000000..cd497eca --- /dev/null +++ b/src/cs-multiaddress/src/Multiformats.Address/Protocols/P2P.WebSocket.Star.cs @@ -0,0 +1,20 @@ +namespace Multiformats.Address.Protocols +{ + public class P2PWebSocketStar : MultiaddressProtocol + { + public P2PWebSocketStar() + : base("p2p-websocket-star", 479, 0) + { + } + + public override void Decode(string value) + { + } + + public override void Decode(byte[] bytes) + { + } + + public override byte[] ToBytes() => EmptyBuffer; + } +} diff --git a/src/cs-multiaddress/src/Multiformats.Address/Protocols/P2P.cs b/src/cs-multiaddress/src/Multiformats.Address/Protocols/P2P.cs new file mode 100644 index 00000000..a007e9ea --- /dev/null +++ b/src/cs-multiaddress/src/Multiformats.Address/Protocols/P2P.cs @@ -0,0 +1,28 @@ +using Multiformats.Hash; + +namespace Multiformats.Address.Protocols +{ + public class P2P : MultiaddressProtocol + { + public P2P() + : base("p2p", 420, -1) + { + } + + public P2P(string address) + : this(Multihash.FromB58String(address)) + { + } + + public P2P(Multihash address) + : this() + { + Value = address; + } + + public override void Decode(string value) => Value = Multihash.FromB58String(value); + public override void Decode(byte[] bytes) => Value = Multihash.Decode(bytes); + public override byte[] ToBytes() => (Multihash)Value; + public override string ToString() => ((Multihash)Value)?.B58String() ?? string.Empty; + } +} diff --git a/src/cs-multiaddress/src/Multiformats.Address/Protocols/QUIC.cs b/src/cs-multiaddress/src/Multiformats.Address/Protocols/QUIC.cs new file mode 100644 index 00000000..3aa4adf7 --- /dev/null +++ b/src/cs-multiaddress/src/Multiformats.Address/Protocols/QUIC.cs @@ -0,0 +1,20 @@ +namespace Multiformats.Address.Protocols +{ + public class QUIC : MultiaddressProtocol + { + public QUIC() + : base("quic", 460, 0) + { + } + + public override void Decode(string value) + { + } + + public override void Decode(byte[] bytes) + { + } + + public override byte[] ToBytes() => EmptyBuffer; + } +} diff --git a/src/cs-multiaddress/src/Multiformats.Address/Protocols/SCTP.cs b/src/cs-multiaddress/src/Multiformats.Address/Protocols/SCTP.cs new file mode 100644 index 00000000..c1440f09 --- /dev/null +++ b/src/cs-multiaddress/src/Multiformats.Address/Protocols/SCTP.cs @@ -0,0 +1,16 @@ +namespace Multiformats.Address.Protocols +{ + public class SCTP : Number + { + public SCTP() + : base("sctp", 132) + { + } + + public SCTP(int port) + : this() + { + Value = port; + } + } +} \ No newline at end of file diff --git a/src/cs-multiaddress/src/Multiformats.Address/Protocols/TCP.cs b/src/cs-multiaddress/src/Multiformats.Address/Protocols/TCP.cs new file mode 100644 index 00000000..c30664c1 --- /dev/null +++ b/src/cs-multiaddress/src/Multiformats.Address/Protocols/TCP.cs @@ -0,0 +1,16 @@ +namespace Multiformats.Address.Protocols +{ + public class TCP : Number + { + public TCP() + : base("tcp", 6) + { + } + + public TCP(ushort port) + : this() + { + Value = port; + } + } +} diff --git a/src/cs-multiaddress/src/Multiformats.Address/Protocols/UDP.cs b/src/cs-multiaddress/src/Multiformats.Address/Protocols/UDP.cs new file mode 100644 index 00000000..620df4cb --- /dev/null +++ b/src/cs-multiaddress/src/Multiformats.Address/Protocols/UDP.cs @@ -0,0 +1,16 @@ +namespace Multiformats.Address.Protocols +{ + public class UDP : Number + { + public UDP() + : base("udp", 17) + { + } + + public UDP(ushort port) + : this() + { + Value = port; + } + } +} diff --git a/src/cs-multiaddress/src/Multiformats.Address/Protocols/UDT.cs b/src/cs-multiaddress/src/Multiformats.Address/Protocols/UDT.cs new file mode 100644 index 00000000..b1c9c41b --- /dev/null +++ b/src/cs-multiaddress/src/Multiformats.Address/Protocols/UDT.cs @@ -0,0 +1,22 @@ +using System; + +namespace Multiformats.Address.Protocols +{ + public class UDT : MultiaddressProtocol + { + public UDT() + : base("udt", 302, 0) + { + } + + public override void Decode(string value) + { + } + + public override void Decode(byte[] bytes) + { + } + + public override byte[] ToBytes() => EmptyBuffer; + } +} \ No newline at end of file diff --git a/src/cs-multiaddress/src/Multiformats.Address/Protocols/UTP.cs b/src/cs-multiaddress/src/Multiformats.Address/Protocols/UTP.cs new file mode 100644 index 00000000..3358b10d --- /dev/null +++ b/src/cs-multiaddress/src/Multiformats.Address/Protocols/UTP.cs @@ -0,0 +1,22 @@ +using System; + +namespace Multiformats.Address.Protocols +{ + public class UTP : MultiaddressProtocol + { + public UTP() + : base("utp", 301, 0) + { + } + + public override void Decode(string value) + { + } + + public override void Decode(byte[] bytes) + { + } + + public override byte[] ToBytes() => EmptyBuffer; + } +} \ No newline at end of file diff --git a/src/cs-multiaddress/src/Multiformats.Address/Protocols/Unix.cs b/src/cs-multiaddress/src/Multiformats.Address/Protocols/Unix.cs new file mode 100644 index 00000000..0dd4f33e --- /dev/null +++ b/src/cs-multiaddress/src/Multiformats.Address/Protocols/Unix.cs @@ -0,0 +1,50 @@ +using System; +using System.Linq; +using System.Text; +using BinaryEncoding; + +namespace Multiformats.Address.Protocols +{ + public class Unix : MultiaddressProtocol + { + public string Path => Value != null ? (string) Value : string.Empty; + + public Unix() + : base("unix", 400, -1) + { + } + + public Unix(string address) + : this() + { + Value = address; + } + + public override void Decode(string value) + { + Value = value; + } + + public override void Decode(byte[] bytes) + { + uint size = 0; + var n = Binary.Varint.Read(bytes, 0, out size); + + if (bytes.Length - n != size) + throw new Exception("Inconsitent lengths"); + + if (size == 0) + throw new Exception("Invalid length"); + + var s = Encoding.UTF8.GetString(bytes, n, bytes.Length - n); + + Value = s.Substring(1); + } + + public override byte[] ToBytes() + { + return Binary.Varint.GetBytes((uint) Encoding.UTF8.GetByteCount((string) Value)) + .Concat(Encoding.UTF8.GetBytes((string) Value)).ToArray(); + } + } +} diff --git a/src/cs-multiaddress/src/Multiformats.Address/Protocols/WebSocket.cs b/src/cs-multiaddress/src/Multiformats.Address/Protocols/WebSocket.cs new file mode 100644 index 00000000..bb0ea594 --- /dev/null +++ b/src/cs-multiaddress/src/Multiformats.Address/Protocols/WebSocket.cs @@ -0,0 +1,22 @@ +using System; + +namespace Multiformats.Address.Protocols +{ + public class WebSocket : MultiaddressProtocol + { + public WebSocket() + : base("ws", 477, 0) + { + } + + public override void Decode(byte[] bytes) + { + } + + public override void Decode(string value) + { + } + + public override byte[] ToBytes() => EmptyBuffer; + } +} diff --git a/src/cs-multiaddress/src/Multiformats.Address/Protocols/WebSocketSecure.cs b/src/cs-multiaddress/src/Multiformats.Address/Protocols/WebSocketSecure.cs new file mode 100644 index 00000000..a2ade955 --- /dev/null +++ b/src/cs-multiaddress/src/Multiformats.Address/Protocols/WebSocketSecure.cs @@ -0,0 +1,22 @@ +using System; + +namespace Multiformats.Address.Protocols +{ + public class WebSocketSecure : MultiaddressProtocol + { + public WebSocketSecure() + : base("wss", 478, 0) + { + } + + public override void Decode(byte[] bytes) + { + } + + public override void Decode(string value) + { + } + + public override byte[] ToBytes() => EmptyBuffer; + } +} diff --git a/src/cs-multiaddress/test/Multiformats.Address.Tests/ConvertTests.cs b/src/cs-multiaddress/test/Multiformats.Address.Tests/ConvertTests.cs new file mode 100644 index 00000000..8190fa4d --- /dev/null +++ b/src/cs-multiaddress/test/Multiformats.Address.Tests/ConvertTests.cs @@ -0,0 +1,225 @@ +using System.Linq; +using System.Net; +using System.Net.Sockets; +using System.Threading.Tasks; +using Multiformats.Address.Net; +using Xunit; + +namespace Multiformats.Address.Tests +{ + public class ConvertTests + { + [Fact] + public void IPEndPoint_GivenIPv4Tcp_ReturnsValid() + { + var ep = new IPEndPoint(IPAddress.Loopback, 1337); + var ma = ep.ToMultiaddress(ProtocolType.Tcp); + var result = ma.ToString(); + + Assert.Equal("/ip4/127.0.0.1/tcp/1337", result); + } + + [Fact] + public void IPEndPoint_GivenIPv6Tcp_ReturnsValid() + { + var ep = new IPEndPoint(IPAddress.IPv6Loopback, 1337); + var ma = ep.ToMultiaddress(ProtocolType.Tcp); + var result = ma.ToString(); + + Assert.Equal("/ip6/::1/tcp/1337", result); + } + + [Fact] + public void IPEndPoint_GivenIPv4Udp_ReturnsValid() + { + var ep = new IPEndPoint(IPAddress.Loopback, 1337); + var ma = ep.ToMultiaddress(ProtocolType.Udp); + var result = ma.ToString(); + + Assert.Equal("/ip4/127.0.0.1/udp/1337", result); + } + + [Fact] + public void IPEndPoint_GivenIPv6Udp_ReturnsValid() + { + var ep = new IPEndPoint(IPAddress.IPv6Loopback, 1337); + var ma = ep.ToMultiaddress(ProtocolType.Udp); + var result = ma.ToString(); + + Assert.Equal("/ip6/::1/udp/1337", result); + } + + [Fact] + public void Multiaddress_GivenIPv4Tcp_ReturnsValidEndPoint() + { + var ma = Multiaddress.Decode("/ip4/127.0.0.1/tcp/1337"); + ProtocolType p; + var ep = ma.ToEndPoint(out p); + + Assert.Equal(AddressFamily.InterNetwork, ep.AddressFamily); + Assert.Equal(IPAddress.Loopback, ep.Address); + Assert.Equal(1337, ep.Port); + Assert.Equal(ProtocolType.Tcp, p); + } + + [Fact] + public void Multiaddress_GivenIPv4Udp_ReturnsValidEndPoint() + { + var ma = Multiaddress.Decode("/ip4/127.0.0.1/udp/1337"); + ProtocolType p; + var ep = ma.ToEndPoint(out p); + + Assert.Equal(AddressFamily.InterNetwork, ep.AddressFamily); + Assert.Equal(IPAddress.Loopback, ep.Address); + Assert.Equal(1337, ep.Port); + Assert.Equal(ProtocolType.Udp, p); + } + + [Fact] + public void Multiaddress_GivenIPv6Tcp_ReturnsValidEndPoint() + { + var ma = Multiaddress.Decode("/ip6/::1/tcp/1337"); + ProtocolType p; + var ep = ma.ToEndPoint(out p); + + Assert.Equal(AddressFamily.InterNetworkV6, ep.AddressFamily); + Assert.Equal(IPAddress.IPv6Loopback, ep.Address); + Assert.Equal(1337, ep.Port); + Assert.Equal(ProtocolType.Tcp, p); + } + + [Fact] + public void Multiaddress_GivenIPv6Udp_ReturnsValidEndPoint() + { + var ma = Multiaddress.Decode("/ip6/::1/udp/1337"); + ProtocolType p; + var ep = ma.ToEndPoint(out p); + + Assert.Equal(AddressFamily.InterNetworkV6, ep.AddressFamily); + Assert.Equal(IPAddress.IPv6Loopback, ep.Address); + Assert.Equal(1337, ep.Port); + Assert.Equal(ProtocolType.Udp, p); + } + + [Fact] + public void Socket_GivenMultiaddress_CreatesSocket() + { + var ma = Multiaddress.Decode("/ip4/127.0.0.1/tcp/1337"); + using (var socket = ma.CreateSocket()) + { + Assert.Equal(AddressFamily.InterNetwork, socket.AddressFamily); + Assert.Equal(ProtocolType.Tcp, socket.ProtocolType); + Assert.Equal(SocketType.Stream, socket.SocketType); + } + } + + [Theory] + [InlineData("/ip4/127.0.0.1/udp/1234", true)] + [InlineData("/ip4/127.0.0.1/tcp/1234", true)] + [InlineData("/ip4/127.0.0.1/udp/1234/tcp/1234", true)] + [InlineData("/ip4/127.0.0.1/tcp/12345/ip4/1.2.3.4", true)] + [InlineData("/ip6/::1/tcp/80", true)] + [InlineData("/ip6/::1/udp/80", true)] + [InlineData("/ip6/::1", true)] + [InlineData("/tcp/1234/ip4/1.2.3.4", false)] + [InlineData("/tcp/1234", false)] + [InlineData("/tcp/1234/udp/1234", false)] + [InlineData("/ip4/1.2.3.4/ip4/2.3.4.5", true)] + [InlineData("/ip6/::1/ip4/2.3.4.5", true)] + public void TestThinWaist(string addr, bool expected) + { + var m = Multiaddress.Decode(addr); + + Assert.Equal(expected, m.IsThinWaist()); + } + + [Fact] + public void CanGetInterfaceAddresses() + { +#if !__MonoCS__ + var addrs = MultiaddressTools.GetInterfaceMultiaddresses(); + + Assert.True(addrs.Count() > 1); +#endif + } + + private void TestAddr(Multiaddress m, Multiaddress[] input, Multiaddress[] expect) + { + var actual = m.Match(input); + + Assert.Equal(expect, actual); + } + + [Fact] + public void TestAddrMatch() + { + var a = new[] + { + Multiaddress.Decode("/ip4/1.2.3.4/tcp/1234"), + Multiaddress.Decode("/ip4/1.2.3.4/tcp/2345"), + Multiaddress.Decode("/ip4/1.2.3.4/tcp/1234/tcp/2345"), + Multiaddress.Decode("/ip4/1.2.3.4/tcp/1234/tcp/2345"), + Multiaddress.Decode("/ip4/1.2.3.4/tcp/1234/udp/1234"), + Multiaddress.Decode("/ip4/1.2.3.4/tcp/1234/udp/1234"), + Multiaddress.Decode("/ip4/1.2.3.4/tcp/1234/ip6/::1"), + Multiaddress.Decode("/ip4/1.2.3.4/tcp/1234/ip6/::1"), + Multiaddress.Decode("/ip6/::1/tcp/1234"), + Multiaddress.Decode("/ip6/::1/tcp/2345"), + Multiaddress.Decode("/ip6/::1/tcp/1234/tcp/2345"), + Multiaddress.Decode("/ip6/::1/tcp/1234/tcp/2345"), + Multiaddress.Decode("/ip6/::1/tcp/1234/udp/1234"), + Multiaddress.Decode("/ip6/::1/tcp/1234/udp/1234"), + Multiaddress.Decode("/ip6/::1/tcp/1234/ip6/::1"), + Multiaddress.Decode("/ip6/::1/tcp/1234/ip6/::1"), + }; + + TestAddr(a[0], a, new [] + { + Multiaddress.Decode("/ip4/1.2.3.4/tcp/1234"), + Multiaddress.Decode("/ip4/1.2.3.4/tcp/2345"), + }); + + TestAddr(a[2], a, new[] + { + Multiaddress.Decode("/ip4/1.2.3.4/tcp/1234/tcp/2345"), + Multiaddress.Decode("/ip4/1.2.3.4/tcp/1234/tcp/2345"), + }); + + TestAddr(a[4], a, new[] + { + Multiaddress.Decode("/ip4/1.2.3.4/tcp/1234/udp/1234"), + Multiaddress.Decode("/ip4/1.2.3.4/tcp/1234/udp/1234"), + }); + + TestAddr(a[6], a, new[] + { + Multiaddress.Decode("/ip4/1.2.3.4/tcp/1234/ip6/::1"), + Multiaddress.Decode("/ip4/1.2.3.4/tcp/1234/ip6/::1"), + }); + + TestAddr(a[8], a, new[] + { + Multiaddress.Decode("/ip6/::1/tcp/1234"), + Multiaddress.Decode("/ip6/::1/tcp/2345"), + }); + + TestAddr(a[10], a, new[] + { + Multiaddress.Decode("/ip6/::1/tcp/1234/tcp/2345"), + Multiaddress.Decode("/ip6/::1/tcp/1234/tcp/2345"), + }); + + TestAddr(a[12], a, new[] + { + Multiaddress.Decode("/ip6/::1/tcp/1234/udp/1234"), + Multiaddress.Decode("/ip6/::1/tcp/1234/udp/1234"), + }); + + TestAddr(a[14], a, new[] + { + Multiaddress.Decode("/ip6/::1/tcp/1234/ip6/::1"), + Multiaddress.Decode("/ip6/::1/tcp/1234/ip6/::1"), + }); + } + } +} diff --git a/src/cs-multiaddress/test/Multiformats.Address.Tests/MultiaddressTests.cs b/src/cs-multiaddress/test/Multiformats.Address.Tests/MultiaddressTests.cs new file mode 100644 index 00000000..e610d9f6 --- /dev/null +++ b/src/cs-multiaddress/test/Multiformats.Address.Tests/MultiaddressTests.cs @@ -0,0 +1,198 @@ +using System; +using System.Linq; +using Multiformats.Address.Protocols; +using Org.BouncyCastle.Utilities.Encoders; +using Xunit; + +namespace Multiformats.Address.Tests +{ + public class MultiaddressTests + { + [Theory] + [InlineData("/ip4")] + [InlineData("/ip4/::1")] + [InlineData("/ip4/fdpsofodsajfdoisa")] + [InlineData("/ip6")] + [InlineData("/udp")] + [InlineData("/tcp")] + [InlineData("/sctp")] + [InlineData("/udp/65536")] + [InlineData("/tcp/65536")] + [InlineData("/onion/9imaq4ygg2iegci7:80")] + [InlineData("/onion/aaimaq4ygg2iegci7:80")] + [InlineData("/onion/timaq4ygg2iegci7:0")] + [InlineData("/onion/timaq4ygg2iegci7:-1")] + [InlineData("/onion/timaq4ygg2iegci7")] + [InlineData("/onion/timaq4ygg2iegci@:666")] + [InlineData("/udp/1234/sctp")] + [InlineData("/udp/1234/udt/1234")] + [InlineData("/udp/1234/utp/1234")] + [InlineData("/ip4/127.0.0.1/udp/jfodsajfidosajfoidsa")] + [InlineData("/ip4/127.0.0.1/udp")] + [InlineData("/ip4/127.0.0.1/tcp/jfodsajfidosajfoidsa")] + [InlineData("/ip4/127.0.0.1/tcp")] + [InlineData("/ip4/127.0.0.1/ipfs")] + [InlineData("/ip4/127.0.0.1/ipfs/tcp")] + [InlineData("/unix")] + [InlineData("/ip4/1.2.3.4/tcp/80/unix")] + [InlineData("/dns")] + [InlineData("/dns4")] + [InlineData("/dns6")] + [InlineData("/libp2p-circuit-relay")] + [InlineData("/libp2p-webrtc-star/4")] + [InlineData("/libp2p-webrtc-direct/4")] + public void TestConstructFails(string addr) + { + Assert.ThrowsAny(() => Multiaddress.Decode(addr)); + } + + [Theory] + [InlineData("/ip4/1.2.3.4")] + [InlineData("/ip4/0.0.0.0")] + [InlineData("/ip6/::1")] + [InlineData("/ip6/2601:9:4f81:9700:803e:ca65:66e8:c21")] + [InlineData("/onion/timaq4ygg2iegci7:1234")] + [InlineData("/onion/timaq4ygg2iegci7:80/http")] + [InlineData("/udp/0")] + [InlineData("/tcp/0")] + [InlineData("/sctp/0")] + [InlineData("/udp/1234")] + [InlineData("/tcp/1234")] + [InlineData("/sctp/1234")] + [InlineData("/udp/65535")] + [InlineData("/tcp/65535")] + [InlineData("/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC")] + [InlineData("/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC")] + [InlineData("/udp/1234/sctp/1234")] + [InlineData("/udp/1234/udt")] + [InlineData("/udp/1234/utp")] + [InlineData("/tcp/1234/http")] + [InlineData("/tcp/1234/https")] + [InlineData("/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC/tcp/1234")] + [InlineData("/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC/tcp/1234")] + [InlineData("/ip4/127.0.0.1/udp/1234")] + [InlineData("/ip4/127.0.0.1/udp/0")] + [InlineData("/ip4/127.0.0.1/tcp/1234")] + [InlineData("/ip4/127.0.0.1/tcp/1234/")] + [InlineData("/ip4/127.0.0.1/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC")] + [InlineData("/ip4/127.0.0.1/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC/tcp/1234")] + [InlineData("/unix/a/b/c/d/e")] + [InlineData("/unix/stdio")] + [InlineData("/ip4/1.2.3.4/tcp/80/unix/a/b/c/d/e/f")] + [InlineData("/ip4/127.0.0.1/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC/tcp/1234/unix/stdio")] + [InlineData("/dns/www.google.com")] + [InlineData("/dns4/www.google.com")] + [InlineData("/dns6/www.google.com")] + [InlineData("/p2p-circuit/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC")] + [InlineData("/p2p-webrtc-star/dns/www.google.com")] + [InlineData("/p2p-webrtc-direct/dns/www.google.com")] + [InlineData("/p2p-websocket-star/dns/www.google.com")] + [InlineData("/quic/dns/www.google.com")] + [InlineData("/ws/dns/www.google.com")] + [InlineData("/wss/dns/www.google.com")] + [InlineData("/http/dns/www.google.com")] + [InlineData("/https/dns/www.google.com")] + public void TestConstructSucceeds(string addr) + { + Multiaddress.Decode(addr); + } + + [Fact] + public void TestEqual() + { + var m1 = Multiaddress.Decode("/ip4/127.0.0.1/udp/1234"); + var m2 = Multiaddress.Decode("/ip4/127.0.0.1/tcp/1234"); + var m3 = Multiaddress.Decode("/ip4/127.0.0.1/tcp/1234"); + var m4 = Multiaddress.Decode("/ip4/127.0.0.1/tcp/1234"); + + Assert.NotEqual(m1, m2); + Assert.NotEqual(m2, m1); + Assert.Equal(m2, m3); + Assert.Equal(m3, m2); + Assert.Equal(m1, m1); + Assert.Equal(m2, m4); + Assert.Equal(m4, m3); + } + + [Theory] + [InlineData("/ip4/127.0.0.1/udp/1234", "047f0000011104d2")] + [InlineData("/ip4/127.0.0.1/tcp/4321", "047f0000010610e1")] + [InlineData("/ip4/127.0.0.1/udp/1234/ip4/127.0.0.1/tcp/4321", "047f0000011104d2047f0000010610e1")] + public void TestStringToBytes(string s, string h) + { + var b1 = Hex.Decode(h); + var b2 = Multiaddress.Decode(s).ToBytes(); + + Assert.Equal(b1, b2); + } + + [Theory] + [InlineData("/ip4/127.0.0.1/udp/1234", "047f0000011104d2")] + [InlineData("/ip4/127.0.0.1/tcp/4321", "047f0000010610e1")] + [InlineData("/ip4/127.0.0.1/udp/1234/ip4/127.0.0.1/tcp/4321", "047f0000011104d2047f0000010610e1")] + [InlineData("/onion/aaimaq4ygg2iegci:80", "bc030010c0439831b48218480050")] + public void TestBytesToString(string s1, string h) + { + var b = Hex.Decode(h); + var s2 = Multiaddress.Decode(s1).ToString(); + + Assert.Equal(s1, s2); + } + + [Theory] + [InlineData("/ip4/1.2.3.4/udp/1234", "/ip4/1.2.3.4", "/udp/1234")] + [InlineData("/ip4/1.2.3.4/tcp/1/ip4/2.3.4.5/udp/2", "/ip4/1.2.3.4", "/tcp/1", "/ip4/2.3.4.5", "/udp/2")] + [InlineData("/ip4/1.2.3.4/utp/ip4/2.3.4.5/udp/2/udt", "/ip4/1.2.3.4", "/utp", "/ip4/2.3.4.5", "/udp/2", "/udt")] + public void TestBytesSplitAndJoin(string s, params string[] res) + { + var m = Multiaddress.Decode(s); + var split = m.Split().ToArray(); + + Assert.Equal(split.Length, res.Length); + + for (var i = 0; i < split.Length; i++) + { + Assert.Equal(split[i].ToString(), res[i]); + } + + var joined = Multiaddress.Join(split); + Assert.Equal(m, joined); + } + + [Fact] + public void TestEncapsulate() + { + var m = Multiaddress.Decode("/ip4/127.0.0.1/udp/1234"); + var m2 = Multiaddress.Decode("/udp/5678"); + + var b = m.Encapsulate(m2); + Assert.Equal("/ip4/127.0.0.1/udp/1234/udp/5678", b.ToString()); + + var m3 = Multiaddress.Decode("/udp/5678"); + var c = b.Decapsulate(m3); + Assert.Equal("/ip4/127.0.0.1/udp/1234", c.ToString()); + + var m4 = Multiaddress.Decode("/ip4/127.0.0.1"); + var d = c.Decapsulate(m4); + Assert.Equal("", d.ToString()); + } + + [Fact] + public void TestGetValue() + { + var a = + Multiaddress.Decode( + "/ip4/127.0.0.1/utp/tcp/5555/udp/1234/utp/ipfs/QmbHVEEepCi7rn7VL7Exxpd2Ci9NNB6ifvqwhsrbRMgQFP"); + + Assert.Equal("127.0.0.1", a.Protocols.OfType().FirstOrDefault()?.ToString()); + Assert.Equal("", a.Protocols.OfType().FirstOrDefault()?.ToString()); + Assert.Equal("5555", a.Protocols.OfType().FirstOrDefault()?.ToString()); + Assert.Equal("1234", a.Protocols.OfType().FirstOrDefault()?.ToString()); + Assert.Equal("QmbHVEEepCi7rn7VL7Exxpd2Ci9NNB6ifvqwhsrbRMgQFP", a.Protocols.OfType().FirstOrDefault()?.ToString()); + + a = Multiaddress.Decode("/ip4/0.0.0.0/unix/a/b/c/d"); + Assert.Equal("0.0.0.0", a.Protocols.OfType().FirstOrDefault()?.ToString()); + Assert.Equal("a/b/c/d", a.Protocols.OfType().FirstOrDefault()?.ToString()); + } + } +} diff --git a/src/cs-multiaddress/test/Multiformats.Address.Tests/Multiformats.Address.Tests.csproj b/src/cs-multiaddress/test/Multiformats.Address.Tests/Multiformats.Address.Tests.csproj new file mode 100644 index 00000000..a9bbcc00 --- /dev/null +++ b/src/cs-multiaddress/test/Multiformats.Address.Tests/Multiformats.Address.Tests.csproj @@ -0,0 +1,45 @@ + + + + netcoreapp1.1;net461 + win10-x64;osx-x64;ubuntu-x64 + true + Multiformats.Address.Tests + Multiformats.Address.Tests + true + $(PackageTargetFallback);netstandard;portable-net461+win8 + + + + true + full + false + $(DefineConstants);DEBUG + + + + pdbonly + true + $(DefineConstants) + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/libp2p/Libp2p.Core/Discovery/IDiscoveryProtocol.cs b/src/libp2p/Libp2p.Core/Discovery/IDiscoveryProtocol.cs index 12c2b755..e883d11a 100644 --- a/src/libp2p/Libp2p.Core/Discovery/IDiscoveryProtocol.cs +++ b/src/libp2p/Libp2p.Core/Discovery/IDiscoveryProtocol.cs @@ -1,11 +1,13 @@ // SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited // SPDX-License-Identifier: MIT +using Multiformats.Address; + namespace Nethermind.Libp2p.Core.Discovery; public interface IDiscoveryProtocol { - Task DiscoverAsync(Multiaddr localPeerAddr, CancellationToken token = default); - Func? OnAddPeer { set; } - Func? OnRemovePeer { set; } + Task DiscoverAsync(Multiaddress localPeerAddr, CancellationToken token = default); + Func? OnAddPeer { set; } + Func? OnRemovePeer { set; } } diff --git a/src/libp2p/Libp2p.Core/IListener.cs b/src/libp2p/Libp2p.Core/IListener.cs index 90bcd8a8..1e19c470 100644 --- a/src/libp2p/Libp2p.Core/IListener.cs +++ b/src/libp2p/Libp2p.Core/IListener.cs @@ -1,13 +1,14 @@ // SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited // SPDX-License-Identifier: MIT +using Multiformats.Address; using System.Runtime.CompilerServices; namespace Nethermind.Libp2p.Core; public interface IListener { - Multiaddr Address { get; } + Multiaddress Address { get; } event OnConnection OnConnection; Task DisconnectAsync(); diff --git a/src/libp2p/Libp2p.Core/ILocalPeer.cs b/src/libp2p/Libp2p.Core/ILocalPeer.cs index 81380178..64c7e1eb 100644 --- a/src/libp2p/Libp2p.Core/ILocalPeer.cs +++ b/src/libp2p/Libp2p.Core/ILocalPeer.cs @@ -1,10 +1,12 @@ // SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited // SPDX-License-Identifier: MIT +using Multiformats.Address; + namespace Nethermind.Libp2p.Core; public interface ILocalPeer : IPeer { - Task DialAsync(Multiaddr addr, CancellationToken token = default); - Task ListenAsync(Multiaddr addr, CancellationToken token = default); + Task DialAsync(Multiaddress addr, CancellationToken token = default); + Task ListenAsync(Multiaddress addr, CancellationToken token = default); } diff --git a/src/libp2p/Libp2p.Core/IPeer.cs b/src/libp2p/Libp2p.Core/IPeer.cs index 42347144..148e9885 100644 --- a/src/libp2p/Libp2p.Core/IPeer.cs +++ b/src/libp2p/Libp2p.Core/IPeer.cs @@ -1,10 +1,12 @@ // SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited // SPDX-License-Identifier: MIT +using Multiformats.Address; + namespace Nethermind.Libp2p.Core; public interface IPeer { Identity Identity { get; set; } - Multiaddr Address { get; set; } + Multiaddress Address { get; set; } } diff --git a/src/libp2p/Libp2p.Core/IPeerContext.cs b/src/libp2p/Libp2p.Core/IPeerContext.cs index ce535f54..e9fe0425 100644 --- a/src/libp2p/Libp2p.Core/IPeerContext.cs +++ b/src/libp2p/Libp2p.Core/IPeerContext.cs @@ -1,6 +1,7 @@ // SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited // SPDX-License-Identifier: MIT +using Multiformats.Address; using System.Collections.Concurrent; namespace Nethermind.Libp2p.Core; @@ -11,8 +12,8 @@ public interface IPeerContext IPeer LocalPeer { get; } IPeer RemotePeer { get; } - Multiaddr RemoteEndpoint { get; set; } - Multiaddr LocalEndpoint { get; set; } + Multiaddress RemoteEndpoint { get; set; } + Multiaddress LocalEndpoint { get; set; } // TODO: Get rid of this: IPeerContext Fork(); diff --git a/src/libp2p/Libp2p.Core/IPeerFactory.cs b/src/libp2p/Libp2p.Core/IPeerFactory.cs index 99874efa..c48bbba1 100644 --- a/src/libp2p/Libp2p.Core/IPeerFactory.cs +++ b/src/libp2p/Libp2p.Core/IPeerFactory.cs @@ -1,9 +1,11 @@ // SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited // SPDX-License-Identifier: MIT +using Multiformats.Address; + namespace Nethermind.Libp2p.Core; public interface IPeerFactory { - ILocalPeer Create(Identity? identity = default, Multiaddr? localAddr = default); + ILocalPeer Create(Identity? identity = default, Multiaddress? localAddr = default); } diff --git a/src/libp2p/Libp2p.Core/Libp2p.Core.csproj b/src/libp2p/Libp2p.Core/Libp2p.Core.csproj index d6f32ebe..a5ea4e64 100644 --- a/src/libp2p/Libp2p.Core/Libp2p.Core.csproj +++ b/src/libp2p/Libp2p.Core/Libp2p.Core.csproj @@ -19,6 +19,7 @@ + diff --git a/src/libp2p/Libp2p.Core/PeerContext.cs b/src/libp2p/Libp2p.Core/PeerContext.cs index 80311d0b..19abb63c 100644 --- a/src/libp2p/Libp2p.Core/PeerContext.cs +++ b/src/libp2p/Libp2p.Core/PeerContext.cs @@ -1,6 +1,7 @@ // SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited // SPDX-License-Identifier: MIT +using Multiformats.Address; using System.Collections.Concurrent; namespace Nethermind.Libp2p.Core; @@ -10,8 +11,8 @@ public class PeerContext : IPeerContext public string Id { get; set; } public IPeer LocalPeer { get; set; } public IPeer RemotePeer { get; set; } - public Multiaddr RemoteEndpoint { get; set; } - public Multiaddr LocalEndpoint { get; set; } + public Multiaddress RemoteEndpoint { get; set; } + public Multiaddress LocalEndpoint { get; set; } public BlockingCollection SubDialRequests { get; set; } = new(); public IChannelRequest? SpecificProtocolRequest { get; set; } diff --git a/src/libp2p/Libp2p.Core/PeerFactory.cs b/src/libp2p/Libp2p.Core/PeerFactory.cs index b841fba5..b1e249ab 100644 --- a/src/libp2p/Libp2p.Core/PeerFactory.cs +++ b/src/libp2p/Libp2p.Core/PeerFactory.cs @@ -1,6 +1,8 @@ // SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited // SPDX-License-Identifier: MIT +using Multiformats.Address; +using Multiformats.Address.Protocols; using System.Runtime.CompilerServices; namespace Nethermind.Libp2p.Core; @@ -18,7 +20,7 @@ public PeerFactory(IServiceProvider serviceProvider) _serviceProvider = serviceProvider; } - public virtual ILocalPeer Create(Identity? identity = default, Multiaddr? localAddr = default) + public virtual ILocalPeer Create(Identity? identity = default, Multiaddress? localAddr = default) { identity ??= new Identity(); return new LocalPeer(this) { Identity = identity, Address = localAddr ?? $"/ip4/127.0.0.1/tcp/0/p2p/{identity.PeerId}" }; @@ -37,12 +39,12 @@ public void Setup(IProtocol protocol, IChannelFactory upChannelFactory) _upChannelFactory = upChannelFactory; } - private async Task ListenAsync(LocalPeer peer, Multiaddr addr, CancellationToken token) + private async Task ListenAsync(LocalPeer peer, Multiaddress addr, CancellationToken token) { peer.Address = addr; - if (!peer.Address.Has(Enums.Multiaddr.P2p)) + if (!peer.Address.Has()) { - peer.Address = peer.Address.Append(Enums.Multiaddr.P2p, peer.Identity.PeerId.ToString()); + peer.Address = peer.Address.Add(peer.Identity.PeerId.ToString()); } Channel chan = new(); @@ -101,7 +103,7 @@ private Task DialAsync(IPeerContext peerContext, CancellationToken to return cts.Task; } - protected virtual async Task DialAsync(LocalPeer peer, Multiaddr addr, CancellationToken token) + protected virtual async Task DialAsync(LocalPeer peer, Multiaddress addr, CancellationToken token) { try { @@ -150,7 +152,7 @@ public PeerListener(Channel chan, LocalPeer localPeer) } public event OnConnection? OnConnection; - public Multiaddr Address => _localPeer.Address; + public Multiaddress Address => _localPeer.Address; public Task DisconnectAsync() { @@ -179,14 +181,14 @@ public LocalPeer(PeerFactory factory) } public Identity? Identity { get; set; } - public Multiaddr Address { get; set; } + public Multiaddress Address { get; set; } - public Task DialAsync(Multiaddr addr, CancellationToken token = default) + public Task DialAsync(Multiaddress addr, CancellationToken token = default) { return _factory.DialAsync(this, addr, token); } - public Task ListenAsync(Multiaddr addr, CancellationToken token = default) + public Task ListenAsync(Multiaddress addr, CancellationToken token = default) { return _factory.ListenAsync(this, addr, token); } @@ -207,7 +209,7 @@ public RemotePeer(PeerFactory factory, ILocalPeer localPeer, IPeerContext peerCo public Channel Channel { get; set; } public Identity Identity { get; set; } - public Multiaddr Address { get; set; } + public Multiaddress Address { get; set; } internal ILocalPeer LocalPeer { get; } public Task DialAsync(CancellationToken token = default) where TProtocol : IProtocol diff --git a/src/libp2p/Libp2p.Protocols.IpTcp/IpTcpProtocol.cs b/src/libp2p/Libp2p.Protocols.IpTcp/IpTcpProtocol.cs index a40b58ec..24da4f30 100644 --- a/src/libp2p/Libp2p.Protocols.IpTcp/IpTcpProtocol.cs +++ b/src/libp2p/Libp2p.Protocols.IpTcp/IpTcpProtocol.cs @@ -7,6 +7,8 @@ using Nethermind.Libp2p.Core; using Microsoft.Extensions.Logging; using MultiaddrEnum = Nethermind.Libp2p.Core.Enums.Multiaddr; +using Multiformats.Address; +using Multiformats.Address.Protocols; namespace Nethermind.Libp2p.Protocols; @@ -26,8 +28,8 @@ public async Task ListenAsync(IChannel channel, IChannelFactory? channelFactory, { _logger?.LogInformation("ListenAsync({contextId})", context.Id); - Multiaddr addr = context.LocalPeer.Address; - MultiaddrEnum ipProtocol = addr.Has(MultiaddrEnum.Ip4) ? MultiaddrEnum.Ip4 : MultiaddrEnum.Ip6; + Multiaddress addr = context.LocalPeer.Address; + MultiaddrEnum ipProtocol = addr.Has() ? MultiaddrEnum.Ip4 : MultiaddrEnum.Ip6; IPAddress ipAddress = IPAddress.Parse(addr.At(ipProtocol)!); int tcpPort = int.Parse(addr.At(MultiaddrEnum.Tcp)!); @@ -42,7 +44,7 @@ public async Task ListenAsync(IChannel channel, IChannelFactory? channelFactory, return Task.CompletedTask; }); - context.LocalEndpoint = Multiaddr.From( + context.LocalEndpoint = Multiaddress.From( ipProtocol, ipProtocol == MultiaddrEnum.Ip4 ? localIpEndpoint.Address.MapToIPv4().ToString() : localIpEndpoint.Address.MapToIPv6().ToString(), @@ -65,7 +67,7 @@ await Task.Run(async () => IPeerContext clientContext = context.Fork(); IPEndPoint remoteIpEndpoint = (IPEndPoint)client.RemoteEndPoint!; - clientContext.RemoteEndpoint = clientContext.RemotePeer.Address = Multiaddr.From( + clientContext.RemoteEndpoint = clientContext.RemotePeer.Address = Multiaddress.From( ipProtocol, remoteIpEndpoint.Address.ToString(), MultiaddrEnum.Tcp, remoteIpEndpoint.Port); @@ -120,10 +122,10 @@ public async Task DialAsync(IChannel channel, IChannelFactory channelFactory, IP TaskCompletionSource waitForStop = new(TaskCreationOptions.RunContinuationsAsynchronously); Socket client = new(SocketType.Stream, ProtocolType.Tcp); - Multiaddr addr = context.RemotePeer.Address; - MultiaddrEnum ipProtocol = addr.Has(MultiaddrEnum.Ip4) ? MultiaddrEnum.Ip4 : MultiaddrEnum.Ip6; - IPAddress ipAddress = IPAddress.Parse(addr.At(ipProtocol)!); - int tcpPort = int.Parse(addr.At(MultiaddrEnum.Tcp)!); + Multiaddress addr = context.RemotePeer.Address; + MultiaddrEnum ipProtocol = addr.Has() ? MultiaddrEnum.Ip4 : MultiaddrEnum.Ip6; + IPAddress ipAddress = IPAddress.Parse(addr.Get(ipProtocol)!); + int tcpPort = addr.Get().Port; try { await client.ConnectAsync(new IPEndPoint(ipAddress, tcpPort), channel.Token); @@ -138,7 +140,7 @@ public async Task DialAsync(IChannel channel, IChannelFactory channelFactory, IP IPEndPoint localEndpoint = (IPEndPoint)client.LocalEndPoint!; IPEndPoint remoteEndpoint = (IPEndPoint)client.RemoteEndPoint!; - context.RemoteEndpoint = Multiaddr.From( + context.RemoteEndpoint = Multiaddress.From( ipProtocol, ipProtocol == MultiaddrEnum.Ip4 ? remoteEndpoint.Address.MapToIPv4() : remoteEndpoint.Address.MapToIPv6(), MultiaddrEnum.Tcp, remoteEndpoint.Port); diff --git a/src/libp2p/Libp2p.sln b/src/libp2p/Libp2p.sln index 7ca6e42f..81999895 100644 --- a/src/libp2p/Libp2p.sln +++ b/src/libp2p/Libp2p.sln @@ -57,6 +57,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Multiformats.Hash", "..\cs- EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Libp2p.Protocols.Quic.Tests", "Libp2p.Protocols.Quic.Tests\Libp2p.Protocols.Quic.Tests.csproj", "{EEECB761-A3C3-4598-AD03-EFABBF6CAA77}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Multiformats.Address", "..\cs-multiaddress\src\Multiformats.Address\Multiformats.Address.csproj", "{1C7EF4B1-E314-46C7-99EC-16C7B20A1618}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -163,6 +165,10 @@ Global {EEECB761-A3C3-4598-AD03-EFABBF6CAA77}.Debug|Any CPU.Build.0 = Debug|Any CPU {EEECB761-A3C3-4598-AD03-EFABBF6CAA77}.Release|Any CPU.ActiveCfg = Release|Any CPU {EEECB761-A3C3-4598-AD03-EFABBF6CAA77}.Release|Any CPU.Build.0 = Release|Any CPU + {1C7EF4B1-E314-46C7-99EC-16C7B20A1618}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1C7EF4B1-E314-46C7-99EC-16C7B20A1618}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1C7EF4B1-E314-46C7-99EC-16C7B20A1618}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1C7EF4B1-E314-46C7-99EC-16C7B20A1618}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From de646e8c23f578cf7db55ff25fa188c6dcd1ccb6 Mon Sep 17 00:00:00 2001 From: Juanu Date: Thu, 30 Nov 2023 20:09:16 -0300 Subject: [PATCH 02/14] All tests passing --- .../src/Multiformats.Address/Multiaddress.cs | 12 ++- .../src/Multiformats.Address/Protocols/TCP.cs | 18 ++++ .../src/Multiformats.Address/Protocols/UDP.cs | 18 ++++ .../TestDiscoveryProtocol.cs | 7 +- .../Libp2p.Core.TestsBase/TestLocalPeer.cs | 12 +-- src/libp2p/Libp2p.Core.TestsBase/TestPeers.cs | 15 ++-- src/libp2p/Libp2p.Core/Enums/Multiaddr.cs | 1 + .../IdentifyProtocol.cs | 4 +- .../Libp2p.Protocols.IpTcp/IpTcpProtocol.cs | 53 ++++++----- .../MDnsDiscoveryProtocol.cs | 22 ++--- .../Libp2p.Protocols.Ping/LogMessages.cs | 19 ++-- .../FloodsubProtocolTests.cs | 5 +- .../GossipsubProtocolTests.cs | 3 +- .../PubsubProtocolTests.cs | 6 +- .../Libp2p.Protocols.Pubsub/PubsubProtocol.cs | 5 +- .../Libp2p.Protocols.Pubsub/PubsubRouter.cs | 14 +-- .../Libp2p.Protocols.Quic/QuicProtocol.cs | 87 ++++++++++--------- .../Libp2p/MultiaddrBasedSelectorProtocol.cs | 7 +- src/samples/chat/Program.cs | 6 +- src/samples/perf-benchmarks/Program.cs | 5 +- src/samples/pubsub-chat/Program.cs | 6 +- 21 files changed, 201 insertions(+), 124 deletions(-) diff --git a/src/cs-multiaddress/src/Multiformats.Address/Multiaddress.cs b/src/cs-multiaddress/src/Multiformats.Address/Multiaddress.cs index b38e8d10..b62d7757 100644 --- a/src/cs-multiaddress/src/Multiformats.Address/Multiaddress.cs +++ b/src/cs-multiaddress/src/Multiformats.Address/Multiaddress.cs @@ -14,8 +14,8 @@ static Multiaddress() { Setup("ip4", 4, 32, false, ip => ip != null ? new IP4((IPAddress)ip) : new IP4()); Setup("ip6", 41, 128, false, ip => ip != null ? new IP6((IPAddress)ip) : new IP6()); - Setup("tcp", 6, 16, false, port => port != null ? new TCP((ushort)port) : new TCP()); - Setup("udp", 17, 16, false, port => port != null ? new UDP((ushort)port) : new UDP()); + Setup("tcp", 6, 16, false, port => port != null ? new TCP((int)port) : new TCP()); + Setup("udp", 17, 16, false, port => port != null ? new UDP((int)port) : new UDP()); Setup("p2p", 420, -1, false, address => address != null ? address is Multihash ? new P2P((Multihash)address) : new P2P((string)address) : new P2P()); Setup("ipfs", 421, -1, false, address => address != null ? address is Multihash ? new IPFS((Multihash)address) : new IPFS((string)address) : new IPFS()); Setup("ws", 477, 0, false, _ => new WebSocket()); @@ -90,6 +90,7 @@ public Multiaddress Add(params MultiaddressProtocol[] protocols) } public TProtocol Get() where TProtocol : MultiaddressProtocol => Protocols.OfType().SingleOrDefault(); + public MultiaddressProtocol Get(Type multiprotocolType) => Protocols.Where(p => p.GetType() == multiprotocolType).SingleOrDefault(); public void Remove() where TProtocol : MultiaddressProtocol { @@ -252,5 +253,12 @@ public static implicit operator Multiaddress(string value) public bool Has() where T : MultiaddressProtocol => Protocols.OfType().Any(); + + public Multiaddress Replace(object v) where T : MultiaddressProtocol + { + Remove(); + var protocolDef = _protocols.SingleOrDefault(p => p.Type == typeof(T)); + return Add(protocolDef.Factory(v)); + } } } diff --git a/src/cs-multiaddress/src/Multiformats.Address/Protocols/TCP.cs b/src/cs-multiaddress/src/Multiformats.Address/Protocols/TCP.cs index c30664c1..202b6d38 100644 --- a/src/cs-multiaddress/src/Multiformats.Address/Protocols/TCP.cs +++ b/src/cs-multiaddress/src/Multiformats.Address/Protocols/TCP.cs @@ -7,6 +7,24 @@ public TCP() { } + public TCP(int port) + : this() + { + Value = port; + } + + public TCP(uint port) + : this() + { + Value = port; + } + + public TCP(short port) + : this() + { + Value = port; + } + public TCP(ushort port) : this() { diff --git a/src/cs-multiaddress/src/Multiformats.Address/Protocols/UDP.cs b/src/cs-multiaddress/src/Multiformats.Address/Protocols/UDP.cs index 620df4cb..5fa22c42 100644 --- a/src/cs-multiaddress/src/Multiformats.Address/Protocols/UDP.cs +++ b/src/cs-multiaddress/src/Multiformats.Address/Protocols/UDP.cs @@ -7,6 +7,24 @@ public UDP() { } + public UDP(int port) + : this() + { + Value = port; + } + + public UDP(uint port) + : this() + { + Value = port; + } + + public UDP(short port) + : this() + { + Value = port; + } + public UDP(ushort port) : this() { diff --git a/src/libp2p/Libp2p.Core.TestsBase/TestDiscoveryProtocol.cs b/src/libp2p/Libp2p.Core.TestsBase/TestDiscoveryProtocol.cs index 147f5e82..197bd3b3 100644 --- a/src/libp2p/Libp2p.Core.TestsBase/TestDiscoveryProtocol.cs +++ b/src/libp2p/Libp2p.Core.TestsBase/TestDiscoveryProtocol.cs @@ -1,16 +1,17 @@ // SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited // SPDX-License-Identifier: MIT +using Multiformats.Address; using Nethermind.Libp2p.Core.Discovery; namespace Nethermind.Libp2p.Core.TestsBase; public class TestDiscoveryProtocol : IDiscoveryProtocol { - public Func? OnAddPeer { get; set; } - public Func? OnRemovePeer { get; set; } + public Func? OnAddPeer { get; set; } + public Func? OnRemovePeer { get; set; } - public Task DiscoverAsync(Multiaddr localPeerAddr, CancellationToken token = default) + public Task DiscoverAsync(Multiaddress localPeerAddr, CancellationToken token = default) { TaskCompletionSource task = new(); token.Register(task.SetResult); diff --git a/src/libp2p/Libp2p.Core.TestsBase/TestLocalPeer.cs b/src/libp2p/Libp2p.Core.TestsBase/TestLocalPeer.cs index 7fd788de..5165f78e 100644 --- a/src/libp2p/Libp2p.Core.TestsBase/TestLocalPeer.cs +++ b/src/libp2p/Libp2p.Core.TestsBase/TestLocalPeer.cs @@ -1,6 +1,8 @@ // SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited // SPDX-License-Identifier: MIT +using Multiformats.Address; + namespace Nethermind.Libp2p.Core.TestsBase; public class TestLocalPeer : ILocalPeer @@ -12,14 +14,14 @@ public TestLocalPeer() } public Identity Identity { get; set; } - public Multiaddr Address { get; set; } + public Multiaddress Address { get; set; } - public Task DialAsync(Multiaddr addr, CancellationToken token = default) + public Task DialAsync(Multiaddress addr, CancellationToken token = default) { return Task.FromResult(new TestRemotePeer(addr)); } - public Task ListenAsync(Multiaddr addr, CancellationToken token = default) + public Task ListenAsync(Multiaddress addr, CancellationToken token = default) { return Task.FromResult(null); } @@ -27,14 +29,14 @@ public Task ListenAsync(Multiaddr addr, CancellationToken token = def public class TestRemotePeer : IRemotePeer { - public TestRemotePeer(Multiaddr addr) + public TestRemotePeer(Multiaddress addr) { Identity = TestPeers.Identity(addr); Address = addr; } public Identity Identity { get; set; } - public Multiaddr Address { get; set; } + public Multiaddress Address { get; set; } public Task DialAsync(CancellationToken token = default) where TProtocol : IProtocol { diff --git a/src/libp2p/Libp2p.Core.TestsBase/TestPeers.cs b/src/libp2p/Libp2p.Core.TestsBase/TestPeers.cs index 4bb9d81f..5dc8ab94 100644 --- a/src/libp2p/Libp2p.Core.TestsBase/TestPeers.cs +++ b/src/libp2p/Libp2p.Core.TestsBase/TestPeers.cs @@ -1,6 +1,9 @@ // SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited // SPDX-License-Identifier: MIT +using Multiformats.Address; +using Multiformats.Address.Protocols; +using Nethermind.Libp2p.Core.Dto; using System.Buffers.Binary; using System.Collections.Concurrent; @@ -8,20 +11,20 @@ namespace Nethermind.Libp2p.Core.TestsBase; public class TestPeers { - private static readonly ConcurrentDictionary testPeerAddrs = new(); + private static readonly ConcurrentDictionary testPeerAddrs = new(); private static readonly ConcurrentDictionary testPeerIds = new(); - public static Multiaddr Multiaddr(int i) => testPeerAddrs.GetOrAdd(i, i => + public static Multiaddress Multiaddr(int i) => testPeerAddrs.GetOrAdd(i, i => { byte[] key = new byte[32]; BinaryPrimitives.WriteInt32BigEndian(key.AsSpan(32 - 4, 4), i); - return new Multiaddr($"/p2p/{new Identity(key).PeerId}"); + return Multiaddress.Decode($"/p2p/{new Identity(key).PeerId}"); }); - public static PeerId PeerId(int i) => testPeerIds.GetOrAdd(i, i => new PeerId(testPeerAddrs[i].At(Enums.Multiaddr.P2p)!)); + public static PeerId PeerId(int i) => testPeerIds.GetOrAdd(i, i => new PeerId(testPeerAddrs[i].Get().ToString())); - public static PeerId PeerId(Multiaddr addr) => new(addr.At(Enums.Multiaddr.P2p)!); + public static PeerId PeerId(Multiaddress addr) => new PeerId(addr.Get().ToString()); - public static Identity Identity(Multiaddr addr) => new(Core.PeerId.ExtractPublicKey(PeerId(addr).Bytes)); + public static Identity Identity(Multiaddress addr) => new(Core.PeerId.ExtractPublicKey(PeerId(addr).Bytes)); } diff --git a/src/libp2p/Libp2p.Core/Enums/Multiaddr.cs b/src/libp2p/Libp2p.Core/Enums/Multiaddr.cs index e11cd3ae..fbc98c90 100644 --- a/src/libp2p/Libp2p.Core/Enums/Multiaddr.cs +++ b/src/libp2p/Libp2p.Core/Enums/Multiaddr.cs @@ -1,4 +1,5 @@ namespace Nethermind.Libp2p.Core.Enums; +[Obsolete("Use Multiaddress library")] public enum Multiaddr { Ip4 = 0x04, diff --git a/src/libp2p/Libp2p.Protocols.Identify/IdentifyProtocol.cs b/src/libp2p/Libp2p.Protocols.Identify/IdentifyProtocol.cs index afa9bbb4..af1f3de9 100644 --- a/src/libp2p/Libp2p.Protocols.Identify/IdentifyProtocol.cs +++ b/src/libp2p/Libp2p.Protocols.Identify/IdentifyProtocol.cs @@ -60,8 +60,8 @@ public async Task ListenAsync(IChannel channel, IChannelFactory channelFactory, { AgentVersion = "github.com/Nethermind/dotnet-libp2p/samples@1.0.0", ProtocolVersion = SubProtocolId, - ListenAddrs = { ByteString.CopyFrom(context.LocalEndpoint.ToByteArray()) }, - ObservedAddr = ByteString.CopyFrom(context.RemoteEndpoint.ToByteArray()), + ListenAddrs = { ByteString.CopyFrom(context.LocalEndpoint.ToBytes()) }, + ObservedAddr = ByteString.CopyFrom(context.RemoteEndpoint.ToBytes()), PublicKey = context.LocalPeer.Identity.PublicKey.ToByteString(), Protocols = { peerFactoryBuilder.AppLayerProtocols.Select(p => p.Id) } }; diff --git a/src/libp2p/Libp2p.Protocols.IpTcp/IpTcpProtocol.cs b/src/libp2p/Libp2p.Protocols.IpTcp/IpTcpProtocol.cs index 24da4f30..0e442f93 100644 --- a/src/libp2p/Libp2p.Protocols.IpTcp/IpTcpProtocol.cs +++ b/src/libp2p/Libp2p.Protocols.IpTcp/IpTcpProtocol.cs @@ -29,9 +29,10 @@ public async Task ListenAsync(IChannel channel, IChannelFactory? channelFactory, _logger?.LogInformation("ListenAsync({contextId})", context.Id); Multiaddress addr = context.LocalPeer.Address; - MultiaddrEnum ipProtocol = addr.Has() ? MultiaddrEnum.Ip4 : MultiaddrEnum.Ip6; - IPAddress ipAddress = IPAddress.Parse(addr.At(ipProtocol)!); - int tcpPort = int.Parse(addr.At(MultiaddrEnum.Tcp)!); + bool isIP4 = addr.Has(); + MultiaddressProtocol ipProtocol = isIP4 ? addr.Get() : addr.Get(); + IPAddress ipAddress = IPAddress.Parse(ipProtocol.ToString()); + int tcpPort = int.Parse(addr.Get().ToString()); Socket srv = new(SocketType.Stream, ProtocolType.Tcp); srv.Bind(new IPEndPoint(ipAddress, tcpPort)); @@ -44,16 +45,15 @@ public async Task ListenAsync(IChannel channel, IChannelFactory? channelFactory, return Task.CompletedTask; }); - context.LocalEndpoint = Multiaddress.From( - ipProtocol, ipProtocol == MultiaddrEnum.Ip4 ? - localIpEndpoint.Address.MapToIPv4().ToString() : - localIpEndpoint.Address.MapToIPv6().ToString(), - MultiaddrEnum.Tcp, localIpEndpoint.Port); + Multiaddress localMultiaddress = new(); + localMultiaddress = isIP4 ? localMultiaddress.Add(localIpEndpoint.Address.MapToIPv4()) : localMultiaddress.Add(localIpEndpoint.Address.MapToIPv6()); + localMultiaddress = localMultiaddress.Add(localIpEndpoint.Port); + context.LocalEndpoint = localMultiaddress; if (tcpPort == 0) { context.LocalPeer.Address = context.LocalPeer.Address - .Replace(MultiaddrEnum.Tcp, localIpEndpoint.Port.ToString()); + .Replace(localIpEndpoint.Port); } _logger?.LogDebug("Ready to handle connections"); @@ -67,9 +67,11 @@ await Task.Run(async () => IPeerContext clientContext = context.Fork(); IPEndPoint remoteIpEndpoint = (IPEndPoint)client.RemoteEndPoint!; - clientContext.RemoteEndpoint = clientContext.RemotePeer.Address = Multiaddress.From( - ipProtocol, remoteIpEndpoint.Address.ToString(), - MultiaddrEnum.Tcp, remoteIpEndpoint.Port); + Multiaddress remoteMultiaddress = new(); + remoteMultiaddress = isIP4 ? remoteMultiaddress.Add(remoteIpEndpoint.Address.MapToIPv4()) : remoteMultiaddress.Add(remoteIpEndpoint.Address.MapToIPv6()); + remoteMultiaddress = remoteMultiaddress.Add(remoteIpEndpoint.Port); + + clientContext.RemoteEndpoint = clientContext.RemotePeer.Address = remoteMultiaddress; IChannel chan = channelFactory.SubListen(clientContext); @@ -123,8 +125,8 @@ public async Task DialAsync(IChannel channel, IChannelFactory channelFactory, IP TaskCompletionSource waitForStop = new(TaskCreationOptions.RunContinuationsAsynchronously); Socket client = new(SocketType.Stream, ProtocolType.Tcp); Multiaddress addr = context.RemotePeer.Address; - MultiaddrEnum ipProtocol = addr.Has() ? MultiaddrEnum.Ip4 : MultiaddrEnum.Ip6; - IPAddress ipAddress = IPAddress.Parse(addr.Get(ipProtocol)!); + MultiaddressProtocol ipProtocol = addr.Has() ? addr.Get() : addr.Get(); + IPAddress ipAddress = IPAddress.Parse(ipProtocol.ToString()); int tcpPort = addr.Get().Port; try { @@ -140,15 +142,20 @@ public async Task DialAsync(IChannel channel, IChannelFactory channelFactory, IP IPEndPoint localEndpoint = (IPEndPoint)client.LocalEndPoint!; IPEndPoint remoteEndpoint = (IPEndPoint)client.RemoteEndPoint!; - context.RemoteEndpoint = Multiaddress.From( - ipProtocol, - ipProtocol == MultiaddrEnum.Ip4 ? remoteEndpoint.Address.MapToIPv4() : remoteEndpoint.Address.MapToIPv6(), - MultiaddrEnum.Tcp, remoteEndpoint.Port); - context.LocalEndpoint = Multiaddr.From( - ipProtocol, - ipProtocol == MultiaddrEnum.Ip4 ? localEndpoint.Address.MapToIPv4() : localEndpoint.Address.MapToIPv6(), - MultiaddrEnum.Tcp, localEndpoint.Port); - context.LocalPeer.Address = context.LocalEndpoint.Append(MultiaddrEnum.P2p, context.LocalPeer.Identity.PeerId.ToString()); + var isIP4 = addr.Has(); + + var remoteMultiaddress = new Multiaddress(); + var remoteIpAddress = isIP4 ? remoteEndpoint.Address.MapToIPv4() : remoteEndpoint.Address.MapToIPv6(); + remoteMultiaddress = isIP4? remoteMultiaddress.Add(remoteIpAddress) : remoteMultiaddress.Add(remoteIpAddress); + context.RemoteEndpoint = remoteMultiaddress.Add(remoteEndpoint.Port); + + + var localMultiaddress = new Multiaddress(); + var localIpAddress = isIP4 ? localEndpoint.Address.MapToIPv4() : localEndpoint.Address.MapToIPv6(); + localMultiaddress = isIP4 ? localMultiaddress.Add(localIpAddress) : localMultiaddress.Add(localIpAddress); + context.LocalEndpoint = localMultiaddress.Add(localEndpoint.Port); + + context.LocalPeer.Address = context.LocalEndpoint.Add(context.LocalPeer.Identity.PeerId.ToString()); IChannel upChannel = channelFactory.SubDial(context); channel.Token.Register(() => upChannel.CloseAsync()); diff --git a/src/libp2p/Libp2p.Protocols.MDns/MDnsDiscoveryProtocol.cs b/src/libp2p/Libp2p.Protocols.MDns/MDnsDiscoveryProtocol.cs index 0b011ba9..529fd099 100644 --- a/src/libp2p/Libp2p.Protocols.MDns/MDnsDiscoveryProtocol.cs +++ b/src/libp2p/Libp2p.Protocols.MDns/MDnsDiscoveryProtocol.cs @@ -7,6 +7,8 @@ using System.Collections.ObjectModel; using Nethermind.Libp2p.Core.Discovery; using Makaretu.Dns; +using Multiformats.Address; +using Multiformats.Address.Protocols; namespace Nethermind.Libp2p.Protocols; @@ -25,28 +27,28 @@ public MDnsDiscoveryProtocol(ILoggerFactory? loggerFactory = null) private string? ServiceNameOverride = "pubsub-chat-example"; - public Func? OnAddPeer { get; set; } - public Func? OnRemovePeer { get; set; } + public Func? OnAddPeer { get; set; } + public Func? OnRemovePeer { get; set; } private string PeerName = null!; - public async Task DiscoverAsync(Core.Multiaddr localPeerAddr, CancellationToken token = default) + public async Task DiscoverAsync(Multiaddress localPeerAddr, CancellationToken token = default) { - ObservableCollection peers = new(); + ObservableCollection peers = new(); try { PeerName = RandomString(32); ServiceProfile service = new(PeerName, ServiceNameOverride ?? ServiceName, 0); - if (localPeerAddr.At(Core.Enums.Multiaddr.Ip4) == "0.0.0.0") + if (localPeerAddr.Get().ToString() == "0.0.0.0") { service.Resources.Add(new TXTRecord() { Name = service.FullyQualifiedName, Strings = new List(MulticastService.GetLinkLocalAddresses() .Where(x => x.AddressFamily == AddressFamily.InterNetwork) - .Select(item => $"dnsaddr={localPeerAddr.Replace(Core.Enums.Multiaddr.Ip4, item.ToString())}")) + .Select(item => $"dnsaddr={localPeerAddr.Replace(item.ToString())}")) }); } else @@ -71,14 +73,14 @@ public async Task DiscoverAsync(Core.Multiaddr localPeerAddr, CancellationToken }; sd.ServiceInstanceDiscovered += (s, e) => { - Core.Multiaddr[] records = e.Message.AdditionalRecords.OfType() + Multiaddress[] records = e.Message.AdditionalRecords.OfType() .Select(x => x.Strings.Where(x => x.StartsWith("dnsaddr"))) - .SelectMany(x => x).Select(x => new Core.Multiaddr(x.Replace("dnsaddr=", ""))).ToArray(); + .SelectMany(x => x).Select(x => Multiaddress.Decode(x.Replace("dnsaddr=", ""))).ToArray(); _logger?.LogTrace("Inst disc {0}, nmsg: {1}", e.ServiceInstanceName, e.Message); - if (Enumerable.Any(records) && !peers.Contains(Enumerable.First(records)) && localPeerAddr.At(Core.Enums.Multiaddr.P2p) != Enumerable.First(records).At(Core.Enums.Multiaddr.P2p)) + if (Enumerable.Any(records) && !peers.Contains(Enumerable.First(records)) && localPeerAddr.Get().ToString() != Enumerable.First(records).Get().ToString()) { List peerAddresses = new(); - foreach (Core.Multiaddr peer in records) + foreach (Multiaddress peer in records) { peers.Add(peer); } diff --git a/src/libp2p/Libp2p.Protocols.Ping/LogMessages.cs b/src/libp2p/Libp2p.Protocols.Ping/LogMessages.cs index 31643ba4..0f93028e 100644 --- a/src/libp2p/Libp2p.Protocols.Ping/LogMessages.cs +++ b/src/libp2p/Libp2p.Protocols.Ping/LogMessages.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: MIT using Microsoft.Extensions.Logging; +using Multiformats.Address; using Nethermind.Libp2p.Core; namespace Nethermind.Libp2p.Protocols.Ping; @@ -17,7 +18,7 @@ internal static partial class LogMessages Level = LogLevel.Trace)] internal static partial void ReadingPong( this ILogger logger, - Multiaddr remotePeer); + Multiaddress remotePeer); [LoggerMessage( EventId = EventId + 2, @@ -26,7 +27,7 @@ internal static partial void ReadingPong( Level = LogLevel.Trace)] internal static partial void VerifyingPong( this ILogger logger, - Multiaddr remotePeer); + Multiaddress remotePeer); [LoggerMessage( EventId = EventId + 3, @@ -35,7 +36,7 @@ internal static partial void VerifyingPong( Level = LogLevel.Trace)] internal static partial void ReadingPing( this ILogger logger, - Multiaddr remotePeer); + Multiaddress remotePeer); [LoggerMessage( EventId = EventId + 4, @@ -44,7 +45,7 @@ internal static partial void ReadingPing( Level = LogLevel.Trace)] internal static partial void ReturningPong( this ILogger logger, - Multiaddr remotePeer); + Multiaddress remotePeer); [LoggerMessage( EventId = EventId + 5, @@ -53,7 +54,7 @@ internal static partial void ReturningPong( Level = LogLevel.Debug)] internal static partial void LogPing( this ILogger logger, - Multiaddr remotePeer); + Multiaddress remotePeer); [LoggerMessage( EventId = EventId + 6, @@ -62,7 +63,7 @@ internal static partial void LogPing( Level = LogLevel.Debug)] internal static partial void LogPinged( this ILogger logger, - Multiaddr remotePeer); + Multiaddress remotePeer); [LoggerMessage( EventId = EventId + 7, @@ -71,7 +72,7 @@ internal static partial void LogPinged( Level = LogLevel.Debug)] internal static partial void PingListenStarted( this ILogger logger, - Multiaddr remotePeer); + Multiaddress remotePeer); [LoggerMessage( EventId = EventId + 8, @@ -80,7 +81,7 @@ internal static partial void PingListenStarted( Level = LogLevel.Debug)] internal static partial void PingFinished( this ILogger logger, - Multiaddr remotePeer); + Multiaddress remotePeer); [LoggerMessage( EventId = EventId + 9, @@ -89,5 +90,5 @@ internal static partial void PingFinished( Level = LogLevel.Warning)] internal static partial void PingFailed( this ILogger logger, - Multiaddr remotePeer); + Multiaddress remotePeer); } diff --git a/src/libp2p/Libp2p.Protocols.Pubsub.Tests/FloodsubProtocolTests.cs b/src/libp2p/Libp2p.Protocols.Pubsub.Tests/FloodsubProtocolTests.cs index 732f1063..d61215fd 100644 --- a/src/libp2p/Libp2p.Protocols.Pubsub.Tests/FloodsubProtocolTests.cs +++ b/src/libp2p/Libp2p.Protocols.Pubsub.Tests/FloodsubProtocolTests.cs @@ -1,6 +1,7 @@ // SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited // SPDX-License-Identifier: MIT +using Multiformats.Address; using Nethermind.Libp2p.Protocols.Pubsub; using Nethermind.Libp2p.Protocols.Pubsub.Dto; @@ -14,9 +15,9 @@ public async Task Test_Peer_is_in_fpeers() { PubsubRouter router = new(); IRoutingStateContainer state = router; - Multiaddr discoveredPeer = TestPeers.Multiaddr(1); + Multiaddress discoveredPeer = TestPeers.Multiaddr(1); PeerId peerId = TestPeers.PeerId(1); - Multiaddr localPeerAddr = TestPeers.Multiaddr(2); + Multiaddress localPeerAddr = TestPeers.Multiaddr(2); const string commonTopic = "topic1"; ILocalPeer peer = Substitute.For(); diff --git a/src/libp2p/Libp2p.Protocols.Pubsub.Tests/GossipsubProtocolTests.cs b/src/libp2p/Libp2p.Protocols.Pubsub.Tests/GossipsubProtocolTests.cs index d137bccf..c79a1e8a 100644 --- a/src/libp2p/Libp2p.Protocols.Pubsub.Tests/GossipsubProtocolTests.cs +++ b/src/libp2p/Libp2p.Protocols.Pubsub.Tests/GossipsubProtocolTests.cs @@ -1,6 +1,7 @@ // SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited // SPDX-License-Identifier: MIT +using Multiformats.Address; using Nethermind.Libp2p.Protocols.Pubsub; using Nethermind.Libp2p.Protocols.Pubsub.Dto; @@ -30,7 +31,7 @@ public async Task Test_New_messages_are_sent_to_mesh_only() foreach (int index in Enumerable.Range(1, peerCount)) { - Multiaddr discoveredPeer = TestPeers.Multiaddr(index); + Multiaddress discoveredPeer = TestPeers.Multiaddr(index); PeerId peerId = TestPeers.PeerId(index); discovery.OnAddPeer!(new[] { discoveredPeer }); diff --git a/src/libp2p/Libp2p.Protocols.Pubsub.Tests/PubsubProtocolTests.cs b/src/libp2p/Libp2p.Protocols.Pubsub.Tests/PubsubProtocolTests.cs index 72ea411e..8b719719 100644 --- a/src/libp2p/Libp2p.Protocols.Pubsub.Tests/PubsubProtocolTests.cs +++ b/src/libp2p/Libp2p.Protocols.Pubsub.Tests/PubsubProtocolTests.cs @@ -1,6 +1,8 @@ // SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited // SPDX-License-Identifier: MIT +using Multiformats.Address; + namespace Nethermind.Libp2p.Protocols.Pubsub.Tests; [TestFixture] @@ -11,9 +13,9 @@ public async Task Test_Peer_is_dialed_when_added_by_discovery() { PubsubRouter router = new(); IRoutingStateContainer state = router; - Multiaddr discoveredPeer = TestPeers.Multiaddr(1); + Multiaddress discoveredPeer = TestPeers.Multiaddr(1); PeerId peerId = TestPeers.PeerId(1); - Multiaddr localPeer = TestPeers.Multiaddr(2); + Multiaddress localPeer = TestPeers.Multiaddr(2); ILocalPeer peer = Substitute.For(); peer.Address.Returns(localPeer); diff --git a/src/libp2p/Libp2p.Protocols.Pubsub/PubsubProtocol.cs b/src/libp2p/Libp2p.Protocols.Pubsub/PubsubProtocol.cs index 1ad684bb..2fc303e8 100644 --- a/src/libp2p/Libp2p.Protocols.Pubsub/PubsubProtocol.cs +++ b/src/libp2p/Libp2p.Protocols.Pubsub/PubsubProtocol.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: MIT using Microsoft.Extensions.Logging; +using Multiformats.Address.Protocols; using Nethermind.Libp2p.Core; using Nethermind.Libp2p.Protocols.Pubsub.Dto; @@ -27,7 +28,7 @@ public PubsubProtocol(string protocolId, PubsubRouter router, ILoggerFactory? lo public async Task DialAsync(IChannel channel, IChannelFactory? channelFactory, IPeerContext context) { - string peerId = context.RemotePeer.Address.At(MultiaddrEnum.P2p)!; + string peerId = context.RemotePeer.Address.Get().ToString()!; _logger?.LogDebug($"Dialed({context.Id}) {context.RemotePeer.Address}"); CancellationToken token = router.OutboundConnection(peerId, Id, (rpc) => @@ -50,7 +51,7 @@ public async Task DialAsync(IChannel channel, IChannelFactory? channelFactory, public async Task ListenAsync(IChannel channel, IChannelFactory? channelFactory, IPeerContext context) { - string peerId = context.RemotePeer.Address.At(MultiaddrEnum.P2p)!; + string peerId = context.RemotePeer.Address.Get().ToString()!; _logger?.LogDebug($"Listen({context.Id}) to {context.RemotePeer.Address}"); CancellationToken token = router.InboundConnection(peerId, Id, () => diff --git a/src/libp2p/Libp2p.Protocols.Pubsub/PubsubRouter.cs b/src/libp2p/Libp2p.Protocols.Pubsub/PubsubRouter.cs index 530b4548..19568cae 100644 --- a/src/libp2p/Libp2p.Protocols.Pubsub/PubsubRouter.cs +++ b/src/libp2p/Libp2p.Protocols.Pubsub/PubsubRouter.cs @@ -3,6 +3,8 @@ using Google.Protobuf; using Microsoft.Extensions.Logging; +using Multiformats.Address; +using Multiformats.Address.Protocols; using Nethermind.Libp2p.Core; using Nethermind.Libp2p.Core.Discovery; using Nethermind.Libp2p.Protocols.Pubsub.Dto; @@ -114,7 +116,7 @@ public async Task RunAsync(ILocalPeer localPeer, IDiscoveryProtocol discoveryPro throw new InvalidOperationException("Router has been already started"); } this.localPeer = localPeer; - LocalPeerId = new PeerId(localPeer.Address.At(MultiaddrEnum.P2p)!); + LocalPeerId = new PeerId(localPeer.Address.Get().ToString()!); _ = localPeer.ListenAsync(localPeer.Address, token); _ = StartDiscoveryAsync(discoveryProtocol, token); @@ -131,12 +133,12 @@ private async Task StartDiscoveryAsync(IDiscoveryProtocol discoveryProtocol, Can { throw new ArgumentNullException(nameof(localPeer)); } - ObservableCollection col = new(); + ObservableCollection col = new(); discoveryProtocol.OnAddPeer = (addrs) => { //addrs = addrs.Where(x => x.ToString().Contains("127.0.0.1")).ToArray(); - Dictionary cancellations = new(); - foreach (Multiaddr addr in addrs) + Dictionary cancellations = new(); + foreach (Multiaddress addr in addrs) { cancellations[addr] = CancellationTokenSource.CreateLinkedTokenSource(token); } @@ -145,7 +147,7 @@ private async Task StartDiscoveryAsync(IDiscoveryProtocol discoveryProtocol, Can { IRemotePeer firstConnected = (await Task.WhenAny(addrs .Select(addr => localPeer.DialAsync(addr, cancellations[addr].Token)))).Result; - foreach (KeyValuePair c in cancellations) + foreach (KeyValuePair c in cancellations) { if (c.Key != firstConnected.Address) { @@ -153,7 +155,7 @@ private async Task StartDiscoveryAsync(IDiscoveryProtocol discoveryProtocol, Can } } logger?.LogDebug("Dialing {0}", firstConnected.Address); - PeerId peerId = firstConnected.Address.At(MultiaddrEnum.P2p)!; + PeerId peerId = firstConnected.Address.Get().ToString()!; if (!peerState.ContainsKey(peerId)) { await firstConnected.DialAsync(token); diff --git a/src/libp2p/Libp2p.Protocols.Quic/QuicProtocol.cs b/src/libp2p/Libp2p.Protocols.Quic/QuicProtocol.cs index 02df0910..a52abd56 100644 --- a/src/libp2p/Libp2p.Protocols.Quic/QuicProtocol.cs +++ b/src/libp2p/Libp2p.Protocols.Quic/QuicProtocol.cs @@ -5,13 +5,14 @@ using Microsoft.Extensions.Logging; using System.Buffers; using System.Net.Sockets; -using MultiaddrEnum = Nethermind.Libp2p.Core.Enums.Multiaddr; using System.Net; using System.Net.Quic; using System.Net.Security; using System.Security.Cryptography.X509Certificates; using Nethermind.Libp2p.Protocols.Quic; using System.Security.Cryptography; +using Multiformats.Address; +using Multiformats.Address.Protocols; namespace Nethermind.Libp2p.Protocols; @@ -48,10 +49,10 @@ public async Task ListenAsync(IChannel channel, IChannelFactory? channelFactory, throw new NotSupportedException("QUIC is not supported, check for presence of libmsquic and support of TLS 1.3."); } - Multiaddr addr = context.LocalPeer.Address; - MultiaddrEnum ipProtocol = addr.Has(MultiaddrEnum.Ip4) ? MultiaddrEnum.Ip4 : MultiaddrEnum.Ip6; - IPAddress ipAddress = IPAddress.Parse(addr.At(ipProtocol)!); - int udpPort = int.Parse(addr.At(MultiaddrEnum.Udp)!); + Multiaddress addr = context.LocalPeer.Address; + MultiaddressProtocol ipProtocol = addr.Has() ? addr.Get() : addr.Get(); + IPAddress ipAddress = IPAddress.Parse(ipProtocol.ToString()); + int udpPort = int.Parse(addr.Get().ToString()); IPEndPoint localEndpoint = new(ipAddress, udpPort); @@ -75,14 +76,21 @@ public async Task ListenAsync(IChannel channel, IChannelFactory? channelFactory, ConnectionOptionsCallback = (_, _, _) => ValueTask.FromResult(serverConnectionOptions) }); - context.LocalEndpoint = Multiaddr.From( - ipProtocol, listener.LocalEndPoint.Address.ToString(), - MultiaddrEnum.Udp, listener.LocalEndPoint.Port); + var localEndPoint = new Multiaddress(); + // IP (4 or 6 is based on source address). + var strLocalEndpoint = listener.LocalEndPoint.Address.ToString(); + localEndPoint = addr.Has() ? localEndPoint.Add(strLocalEndpoint) : localEndPoint.Add(strLocalEndpoint); + + // UDP + localEndPoint = localEndPoint.Add(listener.LocalEndPoint.Port); + + // Set on context + context.LocalEndpoint = localEndPoint; if (udpPort == 0) { context.LocalPeer.Address = context.LocalPeer.Address - .Replace(MultiaddrEnum.Udp, listener.LocalEndPoint.Port.ToString()); + .Replace(listener.LocalEndPoint.Port.ToString()); } channel.OnClose(async () => @@ -112,18 +120,20 @@ public async Task DialAsync(IChannel channel, IChannelFactory? channelFactory, I throw new NotSupportedException("QUIC is not supported, check for presence of libmsquic and support of TLS 1.3."); } - Multiaddr addr = context.LocalPeer.Address; - MultiaddrEnum ipProtocol = addr.Has(MultiaddrEnum.Ip4) ? MultiaddrEnum.Ip4 : MultiaddrEnum.Ip6; - IPAddress ipAddress = IPAddress.Parse(addr.At(ipProtocol)!); - int udpPort = int.Parse(addr.At(MultiaddrEnum.Udp)!); + Multiaddress addr = context.LocalPeer.Address; + bool isIp4 = addr.Has(); + MultiaddressProtocol protocol = isIp4 ? addr.Get() : addr.Get(); + IPAddress ipAddress = IPAddress.Parse(protocol.ToString()); + int udpPort = int.Parse(addr.Get().ToString()); IPEndPoint localEndpoint = new(ipAddress, udpPort); addr = context.RemotePeer.Address; - ipProtocol = addr.Has(MultiaddrEnum.Ip4) ? MultiaddrEnum.Ip4 : MultiaddrEnum.Ip6; - ipAddress = IPAddress.Parse(addr.At(ipProtocol)!); - udpPort = int.Parse(addr.At(MultiaddrEnum.Udp)!); + isIp4 = addr.Has(); + protocol = isIp4 ? addr.Get() : addr.Get(); + ipAddress = IPAddress.Parse(protocol.ToString()!); + udpPort = int.Parse(addr.Get().ToString()!); IPEndPoint remoteEndpoint = new(ipAddress, udpPort); @@ -158,37 +168,30 @@ public async Task DialAsync(IChannel channel, IChannelFactory? channelFactory, I } private static bool VerifyRemoteCertificate(IPeer? remotePeer, X509Certificate certificate) => - CertificateHelper.ValidateCertificate(certificate as X509Certificate2, remotePeer?.Address.At(MultiaddrEnum.P2p)); + CertificateHelper.ValidateCertificate(certificate as X509Certificate2, remotePeer?.Address.Get().ToString()); private async Task ProcessStreams(QuicConnection connection, IPeerContext context, IChannelFactory channelFactory, CancellationToken token) { - MultiaddrEnum newIpProtocol = connection.LocalEndPoint.AddressFamily == AddressFamily.InterNetwork - ? MultiaddrEnum.Ip4 - : MultiaddrEnum.Ip6; - - context.LocalEndpoint = Multiaddr.From( - newIpProtocol, - connection.LocalEndPoint.Address.ToString(), - MultiaddrEnum.Udp, - connection.LocalEndPoint.Port); - - context.LocalPeer.Address = context.LocalPeer.Address.Replace( - context.LocalEndpoint.Has(MultiaddrEnum.Ip4) ? - MultiaddrEnum.Ip4 : - MultiaddrEnum.Ip6, - newIpProtocol, - connection.LocalEndPoint.Address.ToString()); + bool isIP4 = connection.LocalEndPoint.AddressFamily == AddressFamily.InterNetwork; + + Multiaddress localEndPointMultiaddress = new Multiaddress(); + string strLocalEndpointAddress = connection.LocalEndPoint.Address.ToString(); + localEndPointMultiaddress = isIP4 ? localEndPointMultiaddress.Add(strLocalEndpointAddress) : localEndPointMultiaddress.Add(strLocalEndpointAddress); + localEndPointMultiaddress = localEndPointMultiaddress.Add(connection.LocalEndPoint.Port); + + context.LocalEndpoint = localEndPointMultiaddress; + + context.LocalPeer.Address = isIP4 ? context.LocalPeer.Address.Replace(strLocalEndpointAddress) : context.LocalPeer.Address.Replace(strLocalEndpointAddress); IPEndPoint remoteIpEndpoint = connection.RemoteEndPoint!; - newIpProtocol = remoteIpEndpoint.AddressFamily == AddressFamily.InterNetwork - ? MultiaddrEnum.Ip4 - : MultiaddrEnum.Ip6; - - context.RemoteEndpoint = Multiaddr.From( - newIpProtocol, - remoteIpEndpoint.Address.ToString(), - MultiaddrEnum.Udp, - remoteIpEndpoint.Port); + isIP4 = remoteIpEndpoint.AddressFamily == AddressFamily.InterNetwork; + + Multiaddress remoteEndPointMultiaddress = new Multiaddress(); + string strRemoteEndpointAddress = remoteIpEndpoint.Address.ToString(); + remoteEndPointMultiaddress = isIP4 ? remoteEndPointMultiaddress.Add(strRemoteEndpointAddress) : remoteEndPointMultiaddress.Add(strRemoteEndpointAddress); + remoteEndPointMultiaddress = remoteEndPointMultiaddress.Add(remoteIpEndpoint.Port); + + context.RemoteEndpoint = remoteEndPointMultiaddress; context.Connected(context.RemotePeer); diff --git a/src/libp2p/Libp2p/MultiaddrBasedSelectorProtocol.cs b/src/libp2p/Libp2p/MultiaddrBasedSelectorProtocol.cs index 6e993342..b2ac4466 100644 --- a/src/libp2p/Libp2p/MultiaddrBasedSelectorProtocol.cs +++ b/src/libp2p/Libp2p/MultiaddrBasedSelectorProtocol.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: MIT using Microsoft.Extensions.Logging; +using Multiformats.Address.Protocols; using Nethermind.Libp2p.Core; using Nethermind.Libp2p.Stack; @@ -19,15 +20,15 @@ public class MultiaddrBasedSelectorProtocol(ILoggerFactory? loggerFactory = null protected override async Task ConnectAsync(IChannel _, IChannelFactory? channelFactory, IPeerContext context, bool isListener) { IProtocol protocol = null!; - if (context.LocalPeer.Address.Has(Core.Enums.Multiaddr.QuicV1)) + if (context.LocalPeer.Address.Has()) { protocol = channelFactory!.SubProtocols.FirstOrDefault(proto => proto.Id.Contains("quic")) ?? throw new ApplicationException("QUIC is not supported"); } - else if (context.LocalPeer.Address.Has(Core.Enums.Multiaddr.Quic)) + else if (context.LocalPeer.Address.Has()) { throw new ApplicationException("QUIC version draft-29 is not supported."); } - else if (context.LocalPeer.Address.Has(Core.Enums.Multiaddr.Tcp)) + else if (context.LocalPeer.Address.Has()) { protocol = channelFactory!.SubProtocols.FirstOrDefault(proto => proto.Id.Contains("tcp")) ?? throw new ApplicationException("TCP is not supported"); } diff --git a/src/samples/chat/Program.cs b/src/samples/chat/Program.cs index b64f2584..45c04388 100644 --- a/src/samples/chat/Program.cs +++ b/src/samples/chat/Program.cs @@ -5,6 +5,8 @@ using Microsoft.Extensions.Logging; using Nethermind.Libp2p.Stack; using Nethermind.Libp2p.Core; +using Multiformats.Address; +using Multiformats.Address.Protocols; ServiceProvider serviceProvider = new ServiceCollection() .AddLibp2p(builder => builder.AddAppLayerProtocol()) @@ -24,9 +26,9 @@ if (args.Length > 0 && args[0] == "-d") { - Multiaddr remoteAddr = args[1]; + Multiaddress remoteAddr = args[1]; - string addrTemplate = remoteAddr.Has(Nethermind.Libp2p.Core.Enums.Multiaddr.QuicV1) ? + string addrTemplate = remoteAddr.Has() ? "/ip4/0.0.0.0/udp/0/quic-v1" : "/ip4/0.0.0.0/tcp/0"; diff --git a/src/samples/perf-benchmarks/Program.cs b/src/samples/perf-benchmarks/Program.cs index a145127e..5ff5cc51 100644 --- a/src/samples/perf-benchmarks/Program.cs +++ b/src/samples/perf-benchmarks/Program.cs @@ -6,6 +6,7 @@ using Microsoft.Extensions.DependencyInjection; using Nethermind.Libp2p.Stack; using Nethermind.Libp2p.Core; +using Multiformats.Address; await Task.Delay(1000); { @@ -21,7 +22,7 @@ IListener listener = await peer.ListenAsync($"/ip4/0.0.0.0/tcp/0/p2p/{peer.Identity.PeerId}"); - Multiaddr remoteAddr = listener.Address; + Multiaddress remoteAddr = listener.Address; ILocalPeer localPeer = peerFactory.Create(); IRemotePeer remotePeer = await localPeer.DialAsync(remoteAddr); @@ -43,7 +44,7 @@ ILocalPeer peer = peerFactory.Create(); IListener listener = await peer.ListenAsync($"/ip4/0.0.0.0/tcp/0"); - Multiaddr remoteAddr = listener.Address; + Multiaddress remoteAddr = listener.Address; ILocalPeer localPeer = peerFactory.Create(); IRemotePeer remotePeer = await localPeer.DialAsync(remoteAddr); diff --git a/src/samples/pubsub-chat/Program.cs b/src/samples/pubsub-chat/Program.cs index c68b5501..c168e59a 100644 --- a/src/samples/pubsub-chat/Program.cs +++ b/src/samples/pubsub-chat/Program.cs @@ -8,6 +8,8 @@ using System.Text; using System.Text.Json; using Nethermind.Libp2p.Protocols.Pubsub; +using Multiformats.Address.Protocols; +using Multiformats.Address; ServiceProvider serviceProvider = new ServiceCollection() .AddLibp2p(builder => builder @@ -30,7 +32,7 @@ Identity localPeerIdentity = new(); string addr = $"/ip4/0.0.0.0/udp/0/quic-v1/p2p/{localPeerIdentity.PeerId}"; -ILocalPeer peer = peerFactory.Create(localPeerIdentity, addr); +ILocalPeer peer = peerFactory.Create(localPeerIdentity, Multiaddress.Decode(addr)); PubsubRouter router = serviceProvider.GetService()!; ITopic topic = router.Subscribe("chat-room:awesome-chat-room"); @@ -47,7 +49,7 @@ -string peerId = peer.Address.At(Nethermind.Libp2p.Core.Enums.Multiaddr.P2p)!; +string peerId = peer.Address.Get().ToString(); string nickName = "libp2p-dotnet"; From 464a1d2b10e37e3600d4b206570bdb1b20a39500 Mon Sep 17 00:00:00 2001 From: Juanu Date: Fri, 1 Dec 2023 19:50:57 -0300 Subject: [PATCH 03/14] Added QUICv1 protocol QUIC marked as obsolete Renamed MultiaddressBasedProtocolSelector --- .../src/Multiformats.Address/Multiaddress.cs | 1 + .../Multiformats.Address/Protocols/QUIC.cs | 3 +++ .../Multiformats.Address/Protocols/QUICv1.cs | 24 +++++++++++++++++++ src/libp2p/Libp2p/Libp2pPeerFactoryBuilder.cs | 2 +- ...s => MultiaddressBasedSelectorProtocol.cs} | 8 +++---- src/samples/chat/Program.cs | 4 ++-- 6 files changed, 35 insertions(+), 7 deletions(-) create mode 100644 src/cs-multiaddress/src/Multiformats.Address/Protocols/QUICv1.cs rename src/libp2p/Libp2p/{MultiaddrBasedSelectorProtocol.cs => MultiaddressBasedSelectorProtocol.cs} (79%) diff --git a/src/cs-multiaddress/src/Multiformats.Address/Multiaddress.cs b/src/cs-multiaddress/src/Multiformats.Address/Multiaddress.cs index b62d7757..3bc1bf69 100644 --- a/src/cs-multiaddress/src/Multiformats.Address/Multiaddress.cs +++ b/src/cs-multiaddress/src/Multiformats.Address/Multiaddress.cs @@ -25,6 +25,7 @@ static Multiaddress() Setup("unix", 400, -1, true, address => address != null ? new Unix((string)address) : new Unix()); Setup("onion", 444, 96, false, address => address != null ? new Onion((string)address) : new Onion()); Setup("quic", 460, 0, false, _ => new QUIC()); + Setup("quic-v1", 145, 0, false, _ => new QUICv1()); Setup("http", 480, 0, false, _ => new HTTP()); Setup("https", 443, 0, false, _ => new HTTPS()); Setup("utp", 301, 0, false, _ => new UTP()); diff --git a/src/cs-multiaddress/src/Multiformats.Address/Protocols/QUIC.cs b/src/cs-multiaddress/src/Multiformats.Address/Protocols/QUIC.cs index 3aa4adf7..42feae78 100644 --- a/src/cs-multiaddress/src/Multiformats.Address/Protocols/QUIC.cs +++ b/src/cs-multiaddress/src/Multiformats.Address/Protocols/QUIC.cs @@ -1,5 +1,8 @@ +using System; + namespace Multiformats.Address.Protocols { + [Obsolete("Use QUICv1 instead")] public class QUIC : MultiaddressProtocol { public QUIC() diff --git a/src/cs-multiaddress/src/Multiformats.Address/Protocols/QUICv1.cs b/src/cs-multiaddress/src/Multiformats.Address/Protocols/QUICv1.cs new file mode 100644 index 00000000..87f32b3b --- /dev/null +++ b/src/cs-multiaddress/src/Multiformats.Address/Protocols/QUICv1.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Multiformats.Address.Protocols +{ + public class QUICv1 : MultiaddressProtocol + { + public QUICv1() + : base("quic-v1", 0x91, 0) + { + } + + public override void Decode(string value) + { + } + + public override void Decode(byte[] bytes) + { + } + + public override byte[] ToBytes() => EmptyBuffer; + } +} diff --git a/src/libp2p/Libp2p/Libp2pPeerFactoryBuilder.cs b/src/libp2p/Libp2p/Libp2pPeerFactoryBuilder.cs index 76048572..84946754 100644 --- a/src/libp2p/Libp2p/Libp2pPeerFactoryBuilder.cs +++ b/src/libp2p/Libp2p/Libp2pPeerFactoryBuilder.cs @@ -36,7 +36,7 @@ protected override ProtocolStack BuildStack() .Over(); return - Over() + Over() .Over().Or(tcpStack) .Over() .AddAppLayerProtocol() diff --git a/src/libp2p/Libp2p/MultiaddrBasedSelectorProtocol.cs b/src/libp2p/Libp2p/MultiaddressBasedSelectorProtocol.cs similarity index 79% rename from src/libp2p/Libp2p/MultiaddrBasedSelectorProtocol.cs rename to src/libp2p/Libp2p/MultiaddressBasedSelectorProtocol.cs index b2ac4466..27625272 100644 --- a/src/libp2p/Libp2p/MultiaddrBasedSelectorProtocol.cs +++ b/src/libp2p/Libp2p/MultiaddressBasedSelectorProtocol.cs @@ -11,9 +11,9 @@ namespace Nethermind.Libp2p.Protocols; /// /// Select protocol based on multiaddr /// -public class MultiaddrBasedSelectorProtocol(ILoggerFactory? loggerFactory = null) : SymmetricProtocol, IProtocol +public class MultiaddressBasedSelectorProtocol(ILoggerFactory? loggerFactory = null) : SymmetricProtocol, IProtocol { - private readonly ILogger? _logger = loggerFactory?.CreateLogger(); + private readonly ILogger? _logger = loggerFactory?.CreateLogger(); public string Id => "multiaddr-select"; @@ -24,9 +24,9 @@ protected override async Task ConnectAsync(IChannel _, IChannelFactory? channelF { protocol = channelFactory!.SubProtocols.FirstOrDefault(proto => proto.Id.Contains("quic")) ?? throw new ApplicationException("QUIC is not supported"); } - else if (context.LocalPeer.Address.Has()) + else if (context.LocalPeer.Address.Has()) { - throw new ApplicationException("QUIC version draft-29 is not supported."); + protocol = channelFactory!.SubProtocols.FirstOrDefault(proto => proto.Id.Contains("quic-v1")) ?? throw new ApplicationException("QUIC-v1 is not supported"); } else if (context.LocalPeer.Address.Has()) { diff --git a/src/samples/chat/Program.cs b/src/samples/chat/Program.cs index 45c04388..200baac9 100644 --- a/src/samples/chat/Program.cs +++ b/src/samples/chat/Program.cs @@ -28,13 +28,13 @@ { Multiaddress remoteAddr = args[1]; - string addrTemplate = remoteAddr.Has() ? + string addrTemplate = remoteAddr.Has() ? "/ip4/0.0.0.0/udp/0/quic-v1" : "/ip4/0.0.0.0/tcp/0"; ILocalPeer localPeer = peerFactory.Create(localAddr: addrTemplate); - logger.LogInformation("Dialing {0}", remoteAddr); + logger.LogInformation("Dialing {0}", remoteAddr);` IRemotePeer remotePeer = await localPeer.DialAsync(remoteAddr, ts.Token); await remotePeer.DialAsync(ts.Token); From e1329dcb997565ec1c34d979cf85719ed27ffb48 Mon Sep 17 00:00:00 2001 From: Juanu Date: Fri, 1 Dec 2023 19:52:43 -0300 Subject: [PATCH 04/14] Fixed tipo --- src/samples/chat/Program.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/samples/chat/Program.cs b/src/samples/chat/Program.cs index 200baac9..1f6d3152 100644 --- a/src/samples/chat/Program.cs +++ b/src/samples/chat/Program.cs @@ -34,7 +34,7 @@ ILocalPeer localPeer = peerFactory.Create(localAddr: addrTemplate); - logger.LogInformation("Dialing {0}", remoteAddr);` + logger.LogInformation("Dialing {0}", remoteAddr); IRemotePeer remotePeer = await localPeer.DialAsync(remoteAddr, ts.Token); await remotePeer.DialAsync(ts.Token); From f97b5c33874d50c43c7de45de5f9ff5b8cdecaf6 Mon Sep 17 00:00:00 2001 From: Juanu Date: Sat, 2 Dec 2023 12:16:18 -0300 Subject: [PATCH 05/14] Changed Multiaddress target Framework to .NET 7.0 --- .../src/Multiformats.Address/Multiformats.Address.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cs-multiaddress/src/Multiformats.Address/Multiformats.Address.csproj b/src/cs-multiaddress/src/Multiformats.Address/Multiformats.Address.csproj index 8fb0f999..ad40b2b3 100644 --- a/src/cs-multiaddress/src/Multiformats.Address/Multiformats.Address.csproj +++ b/src/cs-multiaddress/src/Multiformats.Address/Multiformats.Address.csproj @@ -1,6 +1,6 @@ - + - netstandard1.6;net461 + net70 win10-x64;osx-x64;ubuntu-x64 Multiformat addresses Copyright © tabrath 2017 From fbeafc5cb060f8f36e71c88d2ee844ad4f1370e1 Mon Sep 17 00:00:00 2001 From: Juanu Date: Sat, 2 Dec 2023 16:27:21 -0300 Subject: [PATCH 06/14] Fixed QUICv1 code --- src/cs-multiaddress/src/Multiformats.Address/Multiaddress.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cs-multiaddress/src/Multiformats.Address/Multiaddress.cs b/src/cs-multiaddress/src/Multiformats.Address/Multiaddress.cs index 3bc1bf69..b4ba1a96 100644 --- a/src/cs-multiaddress/src/Multiformats.Address/Multiaddress.cs +++ b/src/cs-multiaddress/src/Multiformats.Address/Multiaddress.cs @@ -25,7 +25,7 @@ static Multiaddress() Setup("unix", 400, -1, true, address => address != null ? new Unix((string)address) : new Unix()); Setup("onion", 444, 96, false, address => address != null ? new Onion((string)address) : new Onion()); Setup("quic", 460, 0, false, _ => new QUIC()); - Setup("quic-v1", 145, 0, false, _ => new QUICv1()); + Setup("quic-v1", 461, 0, false, _ => new QUICv1()); Setup("http", 480, 0, false, _ => new HTTP()); Setup("https", 443, 0, false, _ => new HTTPS()); Setup("utp", 301, 0, false, _ => new UTP()); From fc7a48d82ac9a81a1eb4a95d56470765475df595 Mon Sep 17 00:00:00 2001 From: Juanu Date: Sun, 3 Dec 2023 18:29:59 -0300 Subject: [PATCH 07/14] Fix format --- src/libp2p/Libp2p.Protocols.IpTcp/IpTcpProtocol.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libp2p/Libp2p.Protocols.IpTcp/IpTcpProtocol.cs b/src/libp2p/Libp2p.Protocols.IpTcp/IpTcpProtocol.cs index 0e442f93..003a4db5 100644 --- a/src/libp2p/Libp2p.Protocols.IpTcp/IpTcpProtocol.cs +++ b/src/libp2p/Libp2p.Protocols.IpTcp/IpTcpProtocol.cs @@ -146,7 +146,7 @@ public async Task DialAsync(IChannel channel, IChannelFactory channelFactory, IP var remoteMultiaddress = new Multiaddress(); var remoteIpAddress = isIP4 ? remoteEndpoint.Address.MapToIPv4() : remoteEndpoint.Address.MapToIPv6(); - remoteMultiaddress = isIP4? remoteMultiaddress.Add(remoteIpAddress) : remoteMultiaddress.Add(remoteIpAddress); + remoteMultiaddress = isIP4 ? remoteMultiaddress.Add(remoteIpAddress) : remoteMultiaddress.Add(remoteIpAddress); context.RemoteEndpoint = remoteMultiaddress.Add(remoteEndpoint.Port); From 7151d0ae29f9766c9d1a75bb48193e53a29d0d84 Mon Sep 17 00:00:00 2001 From: juanu Date: Mon, 4 Dec 2023 17:44:11 -0300 Subject: [PATCH 08/14] Removed Multiaddr file --- src/libp2p/Libp2p.Core/Multiaddr.cs | 194 ---------------------------- 1 file changed, 194 deletions(-) delete mode 100644 src/libp2p/Libp2p.Core/Multiaddr.cs diff --git a/src/libp2p/Libp2p.Core/Multiaddr.cs b/src/libp2p/Libp2p.Core/Multiaddr.cs deleted file mode 100644 index f6d6ac79..00000000 --- a/src/libp2p/Libp2p.Core/Multiaddr.cs +++ /dev/null @@ -1,194 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited -// SPDX-License-Identifier: MIT - -using System.Text; - -namespace Nethermind.Libp2p.Core; - -/// -/// https://github.com/libp2p/specs/blob/master/addressing/README.md -/// -public struct Multiaddr -{ - // override object.Equals - public override bool Equals(object obj) => - (obj is Multiaddr dst) && ((dst._segments is null && _segments is null) || (dst._segments is not null && _segments is not null && dst._segments.SequenceEqual(_segments))); - - // override object.GetHashCode - public override int GetHashCode() => ToString().GetHashCode(); - - private struct Segment - { - public Segment(Enums.Multiaddr type, string? parameter) - { - Type = type; - Parameter = parameter; - } - - public Enums.Multiaddr Type { get; init; } - public string? Parameter { get; init; } - } - - private Segment[]? _segments = null; - - public Multiaddr() - { - } - - public static bool operator ==(Multiaddr lhs, Multiaddr rhs) - { - return lhs.Equals(rhs); - } - - public static bool operator !=(Multiaddr lhs, Multiaddr rhs) => !(lhs == rhs); - - public override string ToString() - { - return string.Join("", _segments - .Select(s => - s.Parameter is null - ? new object[] { $"/{ToString(s.Type)}" } - : new object[] { $"/{ToString(s.Type)}", $"/{s.Parameter}" }) - .SelectMany(s => s)); - } - - public static Multiaddr From(params object[] segments) - { - List segs = new(); - for (int i = 0; i < segments.Length; i++) - { - if (segments[i] is not Enums.Multiaddr addr) - { - throw new ArgumentException($"{segments[i]} is expected to be a multiaddress segment id"); - } - - if (ToProto(addr).isParametrized) - { - segs.Add(new Segment(addr, segments[++i].ToString())); - } - } - - return new Multiaddr { _segments = segs.ToArray() }; - } - - public static implicit operator Multiaddr(string value) - { - return From(value); - } - public Multiaddr(string value) - { - this = From(value); - } - - public string? At(Enums.Multiaddr section) - { - return _segments?.FirstOrDefault(x => x.Type == section).Parameter; - } - - public bool Has(Enums.Multiaddr section) - { - return _segments?.Any(x => x.Type == section) ?? false; - } - - public Multiaddr Append(Enums.Multiaddr at, string? value) - { - Segment[] newSegments = { new(at, value) }; - return new Multiaddr { _segments = _segments is not null ? _segments.Concat(newSegments).ToArray() : newSegments }; - } - - public Multiaddr Replace(Enums.Multiaddr at, Enums.Multiaddr newAt, string? value = null) - { - Segment[] newSegments = _segments.ToArray(); - for (int i = 0; i < _segments.Length; i++) - { - if (newSegments[i].Type == at) - { - newSegments[i] = new Segment(newAt, value); - break; - } - } - - return new Multiaddr { _segments = newSegments }; - } - - public Multiaddr Replace(Enums.Multiaddr at, string? value = null) - { - Segment[] newSegments = _segments.ToArray(); - for (int i = 0; i < _segments.Length; i++) - { - if (newSegments[i].Type == at) - { - newSegments[i] = new Segment(at, value); - break; - } - } - - return new Multiaddr { _segments = newSegments }; - } - - private static Multiaddr From(string multiAddr) - { - string[] vals = multiAddr.Split('/', StringSplitOptions.RemoveEmptyEntries); - List segments = new(); - for (int i = 0; i < vals.Length; i++) - { - (Enums.Multiaddr type, bool isParametrized) segment = ToProto(vals[i]); - segments.Add(new Segment { Type = segment.type, Parameter = segment.isParametrized ? vals[++i] : null }); - } - - return new Multiaddr { _segments = segments.ToArray() }; - } - - private static (Enums.Multiaddr type, bool isParametrized) ToProto(string val) - { - return val.ToLower() switch - { - "ip4" => ToProto(Enums.Multiaddr.Ip4), - "ip6" => ToProto(Enums.Multiaddr.Ip6), - "tcp" => ToProto(Enums.Multiaddr.Tcp), - "udp" => ToProto(Enums.Multiaddr.Udp), - "p2p" => ToProto(Enums.Multiaddr.P2p), - "ws" => ToProto(Enums.Multiaddr.Ws), - "quic" => ToProto(Enums.Multiaddr.Quic), - "quic-v1" => ToProto(Enums.Multiaddr.QuicV1), - _ => ToProto(Enums.Multiaddr.Unknown) - }; - } - - private static (Enums.Multiaddr type, bool isParametrized) ToProto(Enums.Multiaddr val) - { - return val switch - { - Enums.Multiaddr.Quic => (val, false), - Enums.Multiaddr.QuicV1 => (val, false), - Enums.Multiaddr.Ws => (val, false), - Enums.Multiaddr.Unknown => (val, false), - _ => (val, true) - }; - } - - private static string ToString(Enums.Multiaddr type) - { - return type switch - { - Enums.Multiaddr.QuicV1 => "quic-v1", - _ => type.ToString().ToLower(), - }; - } - - public byte[] ToByteArray() - { - Span result = stackalloc byte[256]; - int ptr = 0; - for (int i = 0; i < _segments.Length; i++) - { - VarInt.Encode((int)_segments[i].Type, result, ref ptr); - if (ToProto(_segments[i].Type).isParametrized) - { - ptr += Encoding.UTF8.GetBytes(_segments[++i].Parameter, result[ptr..]); - } - } - - return result[..ptr].ToArray(); - } -} From 7f894945e053f92a26edfdb825fc73527e1bbc92 Mon Sep 17 00:00:00 2001 From: juanu Date: Mon, 4 Dec 2023 17:49:38 -0300 Subject: [PATCH 09/14] Remove more Multiaddr --- src/libp2p/Libp2p.Core/Enums/Multiaddr.cs | 85 ------------------- .../Libp2p.Protocols.IpTcp/IpTcpProtocol.cs | 1 - src/libp2p/Libp2p.Protocols.Pubsub/Usings.cs | 3 +- 3 files changed, 1 insertion(+), 88 deletions(-) delete mode 100644 src/libp2p/Libp2p.Core/Enums/Multiaddr.cs diff --git a/src/libp2p/Libp2p.Core/Enums/Multiaddr.cs b/src/libp2p/Libp2p.Core/Enums/Multiaddr.cs deleted file mode 100644 index fbc98c90..00000000 --- a/src/libp2p/Libp2p.Core/Enums/Multiaddr.cs +++ /dev/null @@ -1,85 +0,0 @@ -namespace Nethermind.Libp2p.Core.Enums; -[Obsolete("Use Multiaddress library")] -public enum Multiaddr -{ - Ip4 = 0x04, - Tcp = 0x06, - // draft - Dccp = 0x21, - Ip6 = 0x29, - // draft - Ip6zone = 0x2a, - // CIDR mask for IP addresses - // draft - Ipcidr = 0x2b, - Dns = 0x35, - Dns4 = 0x36, - Dns6 = 0x37, - Dnsaddr = 0x38, - // draft - Sctp = 0x84, - // draft - Udp = 0x0111, - // Use webrtc or webrtc-direct instead - // deprecated - P2pWebrtcStar = 0x0113, - // Use webrtc or webrtc-direct instead - // deprecated - P2pWebrtcDirect = 0x0114, - // deprecated - P2pStardust = 0x0115, - // ICE-lite webrtc transport with SDP munging during connection establishment and without use of a STUN server - // draft - WebrtcDirect = 0x0118, - // webrtc transport where connection establishment is according to w3c spec - // draft - Webrtc = 0x0119, - P2pCircuit = 0x0122, - // draft - Udt = 0x012d, - // draft - Utp = 0x012e, - Unix = 0x0190, - // Textile Thread - // draft - Thread = 0x0196, - // libp2p - P2p = 0x01a5, - // draft - Https = 0x01bb, - // draft - Onion = 0x01bc, - // draft - Onion3 = 0x01bd, - // I2P base64 (raw public key) - // draft - Garlic64 = 0x01be, - // I2P base32 (hashed public key or encoded public key/checksum+optional secret) - // draft - Garlic32 = 0x01bf, - // draft - Tls = 0x01c0, - // Server Name Indication RFC 6066 § 3 - // draft - Sni = 0x01c1, - // draft - Noise = 0x01c6, - Quic = 0x01cc, - QuicV1 = 0x01cd, - // draft - Webtransport = 0x01d1, - // TLS certificate's fingerprint as a multihash - // draft - Certhash = 0x01d2, - Ws = 0x01dd, - Wss = 0x01de, - P2pWebsocketStar = 0x01df, - // draft - Http = 0x01e0, - // Experimental QUIC over yggdrasil and ironwood routing protocol - // draft - Silverpine = 0x3f42, - // draft - Plaintextv2 = 0x706c61, - Unknown, -} diff --git a/src/libp2p/Libp2p.Protocols.IpTcp/IpTcpProtocol.cs b/src/libp2p/Libp2p.Protocols.IpTcp/IpTcpProtocol.cs index 003a4db5..8f95b420 100644 --- a/src/libp2p/Libp2p.Protocols.IpTcp/IpTcpProtocol.cs +++ b/src/libp2p/Libp2p.Protocols.IpTcp/IpTcpProtocol.cs @@ -6,7 +6,6 @@ using System.Net.Sockets; using Nethermind.Libp2p.Core; using Microsoft.Extensions.Logging; -using MultiaddrEnum = Nethermind.Libp2p.Core.Enums.Multiaddr; using Multiformats.Address; using Multiformats.Address.Protocols; diff --git a/src/libp2p/Libp2p.Protocols.Pubsub/Usings.cs b/src/libp2p/Libp2p.Protocols.Pubsub/Usings.cs index f545c927..32a118f8 100644 --- a/src/libp2p/Libp2p.Protocols.Pubsub/Usings.cs +++ b/src/libp2p/Libp2p.Protocols.Pubsub/Usings.cs @@ -1,8 +1,7 @@ // SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited // SPDX-License-Identifier: MIT -global using Multiaddr = Nethermind.Libp2p.Core.Multiaddr; -global using MultiaddrEnum = Nethermind.Libp2p.Core.Enums.Multiaddr; +global using Multiaddress = Multiformats.Address.Multiaddress; using System.Runtime.CompilerServices; [assembly: InternalsVisibleTo("Libp2p.Protocols.Pubsub.Tests")] From d0d9c49ed2e980af94f9a1d38dcd7ec2f5ac85b3 Mon Sep 17 00:00:00 2001 From: Juanu Date: Mon, 4 Dec 2023 21:52:28 -0300 Subject: [PATCH 10/14] QUICv1 fix --- .../src/Multiformats.Address/Multiaddress.cs | 15 ++++++++++++++- .../src/Multiformats.Address/Protocols/IP4.cs | 3 +++ src/libp2p/Libp2p.Protocols.Quic/QuicProtocol.cs | 14 +++++++------- .../Libp2p/MultiaddressBasedSelectorProtocol.cs | 2 +- 4 files changed, 25 insertions(+), 9 deletions(-) diff --git a/src/cs-multiaddress/src/Multiformats.Address/Multiaddress.cs b/src/cs-multiaddress/src/Multiformats.Address/Multiaddress.cs index b4ba1a96..0470a6b8 100644 --- a/src/cs-multiaddress/src/Multiformats.Address/Multiaddress.cs +++ b/src/cs-multiaddress/src/Multiformats.Address/Multiaddress.cs @@ -5,6 +5,7 @@ using BinaryEncoding; using Multiformats.Address.Protocols; using Multiformats.Hash; +using Org.BouncyCastle.Bcpg; namespace Multiformats.Address { @@ -12,7 +13,19 @@ public class Multiaddress : IEquatable { static Multiaddress() { - Setup("ip4", 4, 32, false, ip => ip != null ? new IP4((IPAddress)ip) : new IP4()); + Setup("ip4", 4, 32, false, ip => { + if (ip != null) + { + if (ip is IPAddress) + return new IP4((IPAddress)ip); + else if (ip is string) + return new IP4((string)ip); + else + throw new Exception($"Invalid IP4 address {ip}"); + } + + return new IP4(); + }); Setup("ip6", 41, 128, false, ip => ip != null ? new IP6((IPAddress)ip) : new IP6()); Setup("tcp", 6, 16, false, port => port != null ? new TCP((int)port) : new TCP()); Setup("udp", 17, 16, false, port => port != null ? new UDP((int)port) : new UDP()); diff --git a/src/cs-multiaddress/src/Multiformats.Address/Protocols/IP4.cs b/src/cs-multiaddress/src/Multiformats.Address/Protocols/IP4.cs index 1ae278c6..06baa328 100644 --- a/src/cs-multiaddress/src/Multiformats.Address/Protocols/IP4.cs +++ b/src/cs-multiaddress/src/Multiformats.Address/Protocols/IP4.cs @@ -20,6 +20,9 @@ public IP4(IPAddress address) Value = address; } + public IP4(string address) + : this(IPAddress.Parse(address)) { } + public override void Decode(string value) { base.Decode(value); diff --git a/src/libp2p/Libp2p.Protocols.Quic/QuicProtocol.cs b/src/libp2p/Libp2p.Protocols.Quic/QuicProtocol.cs index 6f9c6a3f..714f773b 100644 --- a/src/libp2p/Libp2p.Protocols.Quic/QuicProtocol.cs +++ b/src/libp2p/Libp2p.Protocols.Quic/QuicProtocol.cs @@ -1,18 +1,18 @@ // SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited // SPDX-License-Identifier: MIT +using Microsoft.Extensions.Logging; +using Multiformats.Address; +using Multiformats.Address.Protocols; +using Nethermind.Libp2p.Core; +using Nethermind.Libp2p.Protocols.Quic; using System.Buffers; -using System.Net.Sockets; using System.Net; using System.Net.Quic; using System.Net.Security; +using System.Net.Sockets; using System.Security.Cryptography; -using Multiformats.Address; -using Multiformats.Address.Protocols; using System.Security.Cryptography.X509Certificates; -using Microsoft.Extensions.Logging; -using Nethermind.Libp2p.Core; -using Nethermind.Libp2p.Protocols.Quic; //using Nethermind.Libp2p.Protocols.Quic; namespace Nethermind.Libp2p.Protocols; @@ -94,7 +94,7 @@ public async Task ListenAsync(IChannel channel, IChannelFactory? channelFactory, if (udpPort == 0) { context.LocalPeer.Address = context.LocalPeer.Address - .Replace(listener.LocalEndPoint.Port.ToString()); + .Replace(listener.LocalEndPoint.Port); } channel.OnClose(async () => diff --git a/src/libp2p/Libp2p/MultiaddressBasedSelectorProtocol.cs b/src/libp2p/Libp2p/MultiaddressBasedSelectorProtocol.cs index 27625272..8e2f6a15 100644 --- a/src/libp2p/Libp2p/MultiaddressBasedSelectorProtocol.cs +++ b/src/libp2p/Libp2p/MultiaddressBasedSelectorProtocol.cs @@ -20,7 +20,7 @@ public class MultiaddressBasedSelectorProtocol(ILoggerFactory? loggerFactory = n protected override async Task ConnectAsync(IChannel _, IChannelFactory? channelFactory, IPeerContext context, bool isListener) { IProtocol protocol = null!; - if (context.LocalPeer.Address.Has()) + if (context.LocalPeer.Address.Has()) { protocol = channelFactory!.SubProtocols.FirstOrDefault(proto => proto.Id.Contains("quic")) ?? throw new ApplicationException("QUIC is not supported"); } From 01e65b9102277e4ae62a0f3480a9a61257404dfc Mon Sep 17 00:00:00 2001 From: Juanu Date: Tue, 5 Dec 2023 08:39:33 -0300 Subject: [PATCH 11/14] QUIC fix --- src/libp2p/Libp2p/MultiaddressBasedSelectorProtocol.cs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/libp2p/Libp2p/MultiaddressBasedSelectorProtocol.cs b/src/libp2p/Libp2p/MultiaddressBasedSelectorProtocol.cs index 8e2f6a15..a92c7389 100644 --- a/src/libp2p/Libp2p/MultiaddressBasedSelectorProtocol.cs +++ b/src/libp2p/Libp2p/MultiaddressBasedSelectorProtocol.cs @@ -20,14 +20,11 @@ public class MultiaddressBasedSelectorProtocol(ILoggerFactory? loggerFactory = n protected override async Task ConnectAsync(IChannel _, IChannelFactory? channelFactory, IPeerContext context, bool isListener) { IProtocol protocol = null!; - if (context.LocalPeer.Address.Has()) + // TODO: Validate support for BOTH or just quicv1 and deprecate quic + if (context.LocalPeer.Address.Has()|| context.LocalPeer.Address.Has()) { protocol = channelFactory!.SubProtocols.FirstOrDefault(proto => proto.Id.Contains("quic")) ?? throw new ApplicationException("QUIC is not supported"); } - else if (context.LocalPeer.Address.Has()) - { - protocol = channelFactory!.SubProtocols.FirstOrDefault(proto => proto.Id.Contains("quic-v1")) ?? throw new ApplicationException("QUIC-v1 is not supported"); - } else if (context.LocalPeer.Address.Has()) { protocol = channelFactory!.SubProtocols.FirstOrDefault(proto => proto.Id.Contains("tcp")) ?? throw new ApplicationException("TCP is not supported"); From 8bee765b2570edce4dd77d171a4d8b2dd5a58d78 Mon Sep 17 00:00:00 2001 From: Juanu Date: Tue, 5 Dec 2023 09:05:29 -0300 Subject: [PATCH 12/14] QUICv1 on Multiaddress selector --- src/libp2p/Libp2p/MultiaddressBasedSelectorProtocol.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/libp2p/Libp2p/MultiaddressBasedSelectorProtocol.cs b/src/libp2p/Libp2p/MultiaddressBasedSelectorProtocol.cs index a92c7389..fbd9fe36 100644 --- a/src/libp2p/Libp2p/MultiaddressBasedSelectorProtocol.cs +++ b/src/libp2p/Libp2p/MultiaddressBasedSelectorProtocol.cs @@ -20,11 +20,15 @@ public class MultiaddressBasedSelectorProtocol(ILoggerFactory? loggerFactory = n protected override async Task ConnectAsync(IChannel _, IChannelFactory? channelFactory, IPeerContext context, bool isListener) { IProtocol protocol = null!; - // TODO: Validate support for BOTH or just quicv1 and deprecate quic - if (context.LocalPeer.Address.Has()|| context.LocalPeer.Address.Has()) + // TODO: deprecate quic + if (context.LocalPeer.Address.Has()) { protocol = channelFactory!.SubProtocols.FirstOrDefault(proto => proto.Id.Contains("quic")) ?? throw new ApplicationException("QUIC is not supported"); } + else if (context.LocalPeer.Address.Has()) + { + protocol = channelFactory!.SubProtocols.FirstOrDefault(proto => proto.Id.Contains("quic-v1")) ?? throw new ApplicationException("QUICv1 is not supported"); + } else if (context.LocalPeer.Address.Has()) { protocol = channelFactory!.SubProtocols.FirstOrDefault(proto => proto.Id.Contains("tcp")) ?? throw new ApplicationException("TCP is not supported"); From c247430a377639aa18a55bdadb17219119bafa0b Mon Sep 17 00:00:00 2001 From: Juanu Date: Tue, 5 Dec 2023 11:19:10 -0300 Subject: [PATCH 13/14] Fixed QUICv1 code --- .../src/Multiformats.Address/Protocols/QUICv1.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cs-multiaddress/src/Multiformats.Address/Protocols/QUICv1.cs b/src/cs-multiaddress/src/Multiformats.Address/Protocols/QUICv1.cs index 87f32b3b..2a850262 100644 --- a/src/cs-multiaddress/src/Multiformats.Address/Protocols/QUICv1.cs +++ b/src/cs-multiaddress/src/Multiformats.Address/Protocols/QUICv1.cs @@ -7,7 +7,7 @@ namespace Multiformats.Address.Protocols public class QUICv1 : MultiaddressProtocol { public QUICv1() - : base("quic-v1", 0x91, 0) + : base("quic-v1", 461, 0) { } From e342377719c56946da1a1323dd6267b81ed00e3e Mon Sep 17 00:00:00 2001 From: Juanu Date: Tue, 5 Dec 2023 11:19:42 -0300 Subject: [PATCH 14/14] Support QUICv1 only --- src/libp2p/Libp2p/MultiaddressBasedSelectorProtocol.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libp2p/Libp2p/MultiaddressBasedSelectorProtocol.cs b/src/libp2p/Libp2p/MultiaddressBasedSelectorProtocol.cs index fbd9fe36..00f1482e 100644 --- a/src/libp2p/Libp2p/MultiaddressBasedSelectorProtocol.cs +++ b/src/libp2p/Libp2p/MultiaddressBasedSelectorProtocol.cs @@ -23,11 +23,11 @@ protected override async Task ConnectAsync(IChannel _, IChannelFactory? channelF // TODO: deprecate quic if (context.LocalPeer.Address.Has()) { - protocol = channelFactory!.SubProtocols.FirstOrDefault(proto => proto.Id.Contains("quic")) ?? throw new ApplicationException("QUIC is not supported"); + throw new ApplicationException("QUIC is not supported. Use QUICv1 instead."); } else if (context.LocalPeer.Address.Has()) { - protocol = channelFactory!.SubProtocols.FirstOrDefault(proto => proto.Id.Contains("quic-v1")) ?? throw new ApplicationException("QUICv1 is not supported"); + protocol = channelFactory!.SubProtocols.FirstOrDefault(proto => proto.Id.Contains("quic")) ?? throw new ApplicationException("QUICv1 is not supported"); } else if (context.LocalPeer.Address.Has()) {