├── .gitattributes
├── .gitignore
├── DHT.Network.NodeRunner
├── App.config
├── DHT.Network.NodeRunner.csproj
├── Program.cs
├── Properties
│ └── AssemblyInfo.cs
└── routingTable.txt
├── DHT.ProtocolBuffers
├── DHT.ProtocolBuffers.csproj
├── DhtProto
│ ├── Dht.cs
│ └── DhtGrpc.cs
├── Properties
│ └── AssemblyInfo.cs
├── generate_protos.bat
├── packages.config
└── protos
│ └── dht.proto
├── DHT.Runner
├── App.config
├── DHT.Runner.csproj
├── Program.cs
├── Properties
│ └── AssemblyInfo.cs
├── packages.config
└── routingTable.txt
├── DHT.Tests
├── DHT.Tests.csproj
├── Nodes
│ └── NodeStoreTests.cs
├── NodesProtocol
│ ├── LocalNodeServerClientTests.cs
│ └── NodeServerClientFactoryTests.cs
├── Properties
│ └── AssemblyInfo.cs
├── Routing
│ ├── RoutingTableTests.cs
│ └── Sha256HashGeneratorTests.cs
└── packages.config
├── DHT.sln
├── DHT
├── DHT.csproj
├── Nodes
│ ├── INodeStore.cs
│ ├── NodeInfo.cs
│ └── NodeStore.cs
├── NodesProtocol
│ ├── INodeServerClientFactory.cs
│ ├── LocalNodeServerClient.cs
│ ├── NodeServer.cs
│ └── NodeServerClientFactory.cs
├── Properties
│ └── AssemblyInfo.cs
├── Routing
│ ├── IConsistentHashGenerator.cs
│ ├── IRoutingTable.cs
│ ├── RoutingTable.cs
│ ├── RoutingTableFactory.cs
│ └── Sha256HashGenerator.cs
├── Utils
│ └── Logger.cs
└── packages.config
├── README.md
└── routingTable.txt
/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to automatically normalize line endings.
3 | ###############################################################################
4 | * text=auto
5 |
6 | ###############################################################################
7 | # Set default behavior for command prompt diff.
8 | #
9 | # This is need for earlier builds of msysgit that does not have it on by
10 | # default for csharp files.
11 | # Note: This is only used by command line
12 | ###############################################################################
13 | #*.cs diff=csharp
14 |
15 | ###############################################################################
16 | # Set the merge driver for project and solution files
17 | #
18 | # Merging from the command prompt will add diff markers to the files if there
19 | # are conflicts (Merging from VS is not affected by the settings below, in VS
20 | # the diff markers are never inserted). Diff markers may cause the following
21 | # file extensions to fail to load in VS. An alternative would be to treat
22 | # these files as binary and thus will always conflict and require user
23 | # intervention with every merge. To do so, just uncomment the entries below
24 | ###############################################################################
25 | #*.sln merge=binary
26 | #*.csproj merge=binary
27 | #*.vbproj merge=binary
28 | #*.vcxproj merge=binary
29 | #*.vcproj merge=binary
30 | #*.dbproj merge=binary
31 | #*.fsproj merge=binary
32 | #*.lsproj merge=binary
33 | #*.wixproj merge=binary
34 | #*.modelproj merge=binary
35 | #*.sqlproj merge=binary
36 | #*.wwaproj merge=binary
37 |
38 | ###############################################################################
39 | # behavior for image files
40 | #
41 | # image files are treated as binary by default.
42 | ###############################################################################
43 | #*.jpg binary
44 | #*.png binary
45 | #*.gif binary
46 |
47 | ###############################################################################
48 | # diff behavior for common document formats
49 | #
50 | # Convert binary document formats to text before diffing them. This feature
51 | # is only available from the command line. Turn it on by uncommenting the
52 | # entries below.
53 | ###############################################################################
54 | #*.doc diff=astextplain
55 | #*.DOC diff=astextplain
56 | #*.docx diff=astextplain
57 | #*.DOCX diff=astextplain
58 | #*.dot diff=astextplain
59 | #*.DOT diff=astextplain
60 | #*.pdf diff=astextplain
61 | #*.PDF diff=astextplain
62 | #*.rtf diff=astextplain
63 | #*.RTF diff=astextplain
64 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.userosscache
8 | *.sln.docstates
9 |
10 | # User-specific files (MonoDevelop/Xamarin Studio)
11 | *.userprefs
12 |
13 | # Build results
14 | [Dd]ebug/
15 | [Dd]ebugPublic/
16 | [Rr]elease/
17 | [Rr]eleases/
18 | x64/
19 | x86/
20 | bld/
21 | [Bb]in/
22 | [Oo]bj/
23 | [Ll]og/
24 |
25 | # Visual Studio 2015 cache/options directory
26 | .vs/
27 | # Uncomment if you have tasks that create the project's static files in wwwroot
28 | #wwwroot/
29 |
30 | # MSTest test Results
31 | [Tt]est[Rr]esult*/
32 | [Bb]uild[Ll]og.*
33 |
34 | # NUNIT
35 | *.VisualState.xml
36 | TestResult.xml
37 |
38 | # Build Results of an ATL Project
39 | [Dd]ebugPS/
40 | [Rr]eleasePS/
41 | dlldata.c
42 |
43 | # DNX
44 | project.lock.json
45 | artifacts/
46 |
47 | *_i.c
48 | *_p.c
49 | *_i.h
50 | *.ilk
51 | *.meta
52 | *.obj
53 | *.pch
54 | *.pdb
55 | *.pgc
56 | *.pgd
57 | *.rsp
58 | *.sbr
59 | *.tlb
60 | *.tli
61 | *.tlh
62 | *.tmp
63 | *.tmp_proj
64 | *.log
65 | *.vspscc
66 | *.vssscc
67 | .builds
68 | *.pidb
69 | *.svclog
70 | *.scc
71 |
72 | # Chutzpah Test files
73 | _Chutzpah*
74 |
75 | # Visual C++ cache files
76 | ipch/
77 | *.aps
78 | *.ncb
79 | *.opendb
80 | *.opensdf
81 | *.sdf
82 | *.cachefile
83 | *.VC.db
84 | *.VC.VC.opendb
85 |
86 | # Visual Studio profiler
87 | *.psess
88 | *.vsp
89 | *.vspx
90 | *.sap
91 |
92 | # TFS 2012 Local Workspace
93 | $tf/
94 |
95 | # Guidance Automation Toolkit
96 | *.gpState
97 |
98 | # ReSharper is a .NET coding add-in
99 | _ReSharper*/
100 | *.[Rr]e[Ss]harper
101 | *.DotSettings.user
102 |
103 | # JustCode is a .NET coding add-in
104 | .JustCode
105 |
106 | # TeamCity is a build add-in
107 | _TeamCity*
108 |
109 | # DotCover is a Code Coverage Tool
110 | *.dotCover
111 |
112 | # NCrunch
113 | _NCrunch_*
114 | .*crunch*.local.xml
115 | nCrunchTemp_*
116 |
117 | # MightyMoose
118 | *.mm.*
119 | AutoTest.Net/
120 |
121 | # Web workbench (sass)
122 | .sass-cache/
123 |
124 | # Installshield output folder
125 | [Ee]xpress/
126 |
127 | # DocProject is a documentation generator add-in
128 | DocProject/buildhelp/
129 | DocProject/Help/*.HxT
130 | DocProject/Help/*.HxC
131 | DocProject/Help/*.hhc
132 | DocProject/Help/*.hhk
133 | DocProject/Help/*.hhp
134 | DocProject/Help/Html2
135 | DocProject/Help/html
136 |
137 | # Click-Once directory
138 | publish/
139 |
140 | # Publish Web Output
141 | *.[Pp]ublish.xml
142 | *.azurePubxml
143 | # TODO: Comment the next line if you want to checkin your web deploy settings
144 | # but database connection strings (with potential passwords) will be unencrypted
145 | *.pubxml
146 | *.publishproj
147 |
148 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
149 | # checkin your Azure Web App publish settings, but sensitive information contained
150 | # in these scripts will be unencrypted
151 | PublishScripts/
152 |
153 | # NuGet Packages
154 | *.nupkg
155 | # The packages folder can be ignored because of Package Restore
156 | **/packages/*
157 | # except build/, which is used as an MSBuild target.
158 | !**/packages/build/
159 | # Uncomment if necessary however generally it will be regenerated when needed
160 | #!**/packages/repositories.config
161 | # NuGet v3's project.json files produces more ignoreable files
162 | *.nuget.props
163 | *.nuget.targets
164 |
165 | # Microsoft Azure Build Output
166 | csx/
167 | *.build.csdef
168 |
169 | # Microsoft Azure Emulator
170 | ecf/
171 | rcf/
172 |
173 | # Windows Store app package directories and files
174 | AppPackages/
175 | BundleArtifacts/
176 | Package.StoreAssociation.xml
177 | _pkginfo.txt
178 |
179 | # Visual Studio cache files
180 | # files ending in .cache can be ignored
181 | *.[Cc]ache
182 | # but keep track of directories ending in .cache
183 | !*.[Cc]ache/
184 |
185 | # Others
186 | ClientBin/
187 | ~$*
188 | *~
189 | *.dbmdl
190 | *.dbproj.schemaview
191 | *.pfx
192 | *.publishsettings
193 | node_modules/
194 | orleans.codegen.cs
195 |
196 | # Since there are multiple workflows, uncomment next line to ignore bower_components
197 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
198 | #bower_components/
199 |
200 | # RIA/Silverlight projects
201 | Generated_Code/
202 |
203 | # Backup & report files from converting an old project file
204 | # to a newer Visual Studio version. Backup files are not needed,
205 | # because we have git ;-)
206 | _UpgradeReport_Files/
207 | Backup*/
208 | UpgradeLog*.XML
209 | UpgradeLog*.htm
210 |
211 | # SQL Server files
212 | *.mdf
213 | *.ldf
214 |
215 | # Business Intelligence projects
216 | *.rdl.data
217 | *.bim.layout
218 | *.bim_*.settings
219 |
220 | # Microsoft Fakes
221 | FakesAssemblies/
222 |
223 | # GhostDoc plugin setting file
224 | *.GhostDoc.xml
225 |
226 | # Node.js Tools for Visual Studio
227 | .ntvs_analysis.dat
228 |
229 | # Visual Studio 6 build log
230 | *.plg
231 |
232 | # Visual Studio 6 workspace options file
233 | *.opt
234 |
235 | # Visual Studio LightSwitch build output
236 | **/*.HTMLClient/GeneratedArtifacts
237 | **/*.DesktopClient/GeneratedArtifacts
238 | **/*.DesktopClient/ModelManifest.xml
239 | **/*.Server/GeneratedArtifacts
240 | **/*.Server/ModelManifest.xml
241 | _Pvt_Extensions
242 |
243 | # Paket dependency manager
244 | .paket/paket.exe
245 | paket-files/
246 |
247 | # FAKE - F# Make
248 | .fake/
249 |
250 | # JetBrains Rider
251 | .idea/
252 | *.sln.iml
253 |
--------------------------------------------------------------------------------
/DHT.Network.NodeRunner/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/DHT.Network.NodeRunner/DHT.Network.NodeRunner.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {07E4BBDF-A699-417A-AE38-CE60D953680E}
8 | Exe
9 | Properties
10 | DHT.Network.NodeRunner
11 | DHT.Network.NodeRunner
12 | v4.5.2
13 | 512
14 | true
15 |
16 |
17 | AnyCPU
18 | true
19 | full
20 | false
21 | bin\Debug\
22 | DEBUG;TRACE
23 | prompt
24 | 4
25 |
26 |
27 | AnyCPU
28 | pdbonly
29 | true
30 | bin\Release\
31 | TRACE
32 | prompt
33 | 4
34 |
35 |
36 |
37 | False
38 | ..\packages\System.Interactive.Async.3.0.0\lib\net45\System.Interactive.Async.dll
39 |
40 |
41 | False
42 | ..\packages\Google.Protobuf.3.0.0\lib\net45\Google.Protobuf.dll
43 |
44 |
45 | False
46 | ..\packages\Grpc.Core.1.0.1\lib\net45\Grpc.Core.dll
47 |
48 |
49 | False
50 | ..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 | {76baf981-f995-4cb9-b9d5-229a822bd8ff}
71 | DHT.ProtocolBuffers
72 |
73 |
74 | {cf2d500f-1ebf-43ee-b8c4-4096da5cfba4}
75 | DHT
76 |
77 |
78 |
79 |
80 | Always
81 |
82 |
83 |
84 |
91 |
--------------------------------------------------------------------------------
/DHT.Network.NodeRunner/Program.cs:
--------------------------------------------------------------------------------
1 | namespace DHT.Network.NodeRunner
2 | {
3 | using System;
4 | using System.Linq;
5 | using DHT.Nodes;
6 | using DHT.Routing;
7 | using Grpc.Core;
8 | using NodesProtocol;
9 |
10 | public class Program
11 | {
12 | static void Main(string[] args)
13 | {
14 | // Create routing table
15 | var routingTable = RoutingTableFactory.FromFile("routingTable.txt");
16 |
17 | // Get node to run
18 | var nodeId = UInt32.Parse(args[0]);
19 | var nodeInfo = routingTable.Nodes.FirstOrDefault(n => n.NodeId == nodeId);
20 |
21 | // Start that node
22 | var server = StartNodeServer(nodeInfo, routingTable);
23 |
24 | // Wait for input before killing it
25 | Console.ReadKey();
26 |
27 | KillNodeServer(server);
28 | }
29 |
30 | private static Server StartNodeServer(NodeInfo node, IRoutingTable routingTable)
31 | {
32 | var nodeServer = new NodeServer(node, routingTable, new NodeServerClientFactory());
33 |
34 | var server = new Server
35 | {
36 | Services = { Dhtproto.DhtProtoService.BindService(nodeServer) },
37 | Ports = { new ServerPort(node.HostName, node.Port, ServerCredentials.Insecure) }
38 | };
39 |
40 | server.Start();
41 |
42 | Console.WriteLine("NodeServer server listening on {0}:{1} ", node.HostName, node.Port);
43 | Console.WriteLine();
44 |
45 | return server;
46 | }
47 |
48 | private static void KillNodeServer(Server nodeServer)
49 | {
50 | nodeServer.ShutdownAsync().Wait();
51 |
52 | Console.WriteLine("NodeServer server killed");
53 | Console.WriteLine();
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/DHT.Network.NodeRunner/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("DHT.Network.NodeRunner")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("DHT.Network.NodeRunner")]
13 | [assembly: AssemblyCopyright("Copyright © 2017")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("07e4bbdf-a699-417a-ae38-ce60d953680e")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/DHT.Network.NodeRunner/routingTable.txt:
--------------------------------------------------------------------------------
1 | 90037898 localhost 11000
2 | 270845369 localhost 11001
3 | 379604884 localhost 11002
4 | 488206434 localhost 11003
5 | 537028870 localhost 11004
6 | 694202208 localhost 11005
7 | 886653498 localhost 11006
8 | 975552819 localhost 11007
9 | 1079815039 localhost 11008
10 | 2090213630 localhost 11009
--------------------------------------------------------------------------------
/DHT.ProtocolBuffers/DHT.ProtocolBuffers.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {76BAF981-F995-4CB9-B9D5-229A822BD8FF}
8 | Library
9 | Properties
10 | DHT.ProtocolBuffers
11 | DHT.ProtocolBuffers
12 | v4.5.2
13 | 512
14 |
15 |
16 | true
17 | full
18 | false
19 | bin\Debug\
20 | DEBUG;TRACE
21 | prompt
22 | 4
23 |
24 |
25 | pdbonly
26 | true
27 | bin\Release\
28 | TRACE
29 | prompt
30 | 4
31 |
32 |
33 |
34 | False
35 | ..\packages\System.Interactive.Async.3.0.0\lib\net45\System.Interactive.Async.dll
36 |
37 |
38 | False
39 | ..\packages\Google.Protobuf.3.0.0\lib\net45\Google.Protobuf.dll
40 |
41 |
42 | False
43 | ..\packages\Grpc.Core.1.0.1\lib\net45\Grpc.Core.dll
44 |
45 |
46 | False
47 | ..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 | This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
74 |
75 |
76 |
77 |
84 |
--------------------------------------------------------------------------------
/DHT.ProtocolBuffers/DhtProto/Dht.cs:
--------------------------------------------------------------------------------
1 | // Generated by the protocol buffer compiler. DO NOT EDIT!
2 | // source: dht.proto
3 | #pragma warning disable 1591, 0612, 3021
4 | #region Designer generated code
5 |
6 | using pb = global::Google.Protobuf;
7 | using pbc = global::Google.Protobuf.Collections;
8 | using pbr = global::Google.Protobuf.Reflection;
9 | using scg = global::System.Collections.Generic;
10 | namespace Dhtproto {
11 |
12 | /// Holder for reflection information generated from dht.proto
13 | public static partial class DhtReflection {
14 |
15 | #region Descriptor
16 | /// File descriptor for dht.proto
17 | public static pbr::FileDescriptor Descriptor {
18 | get { return descriptor; }
19 | }
20 | private static pbr::FileDescriptor descriptor;
21 |
22 | static DhtReflection() {
23 | byte[] descriptorData = global::System.Convert.FromBase64String(
24 | string.Concat(
25 | "CglkaHQucHJvdG8SCGRodHByb3RvIhkKCktleU1lc3NhZ2USCwoDa2V5GAEg",
26 | "ASgJIi0KD0tleVZhbHVlTWVzc2FnZRILCgNrZXkYASABKAkSDQoFdmFsdWUY",
27 | "AiABKAky0wEKD0RodFByb3RvU2VydmljZRI9CghHZXRWYWx1ZRIULmRodHBy",
28 | "b3RvLktleU1lc3NhZ2UaGS5kaHRwcm90by5LZXlWYWx1ZU1lc3NhZ2UiABJE",
29 | "CgpTdG9yZVZhbHVlEhkuZGh0cHJvdG8uS2V5VmFsdWVNZXNzYWdlGhkuZGh0",
30 | "cHJvdG8uS2V5VmFsdWVNZXNzYWdlIgASOwoLUmVtb3ZlVmFsdWUSFC5kaHRw",
31 | "cm90by5LZXlNZXNzYWdlGhQuZGh0cHJvdG8uS2V5TWVzc2FnZSIAQjgKG2lv",
32 | "LmdycGMuZXhhbXBsZXMucm91dGVndWlkZUIRSGVsbG9TZXJ2aWNlUHJvdG9Q",
33 | "AaICA1JUR2IGcHJvdG8z"));
34 | descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
35 | new pbr::FileDescriptor[] { },
36 | new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {
37 | new pbr::GeneratedClrTypeInfo(typeof(global::Dhtproto.KeyMessage), global::Dhtproto.KeyMessage.Parser, new[]{ "Key" }, null, null, null),
38 | new pbr::GeneratedClrTypeInfo(typeof(global::Dhtproto.KeyValueMessage), global::Dhtproto.KeyValueMessage.Parser, new[]{ "Key", "Value" }, null, null, null)
39 | }));
40 | }
41 | #endregion
42 |
43 | }
44 | #region Messages
45 | public sealed partial class KeyMessage : pb::IMessage {
46 | private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new KeyMessage());
47 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
48 | public static pb::MessageParser Parser { get { return _parser; } }
49 |
50 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
51 | public static pbr::MessageDescriptor Descriptor {
52 | get { return global::Dhtproto.DhtReflection.Descriptor.MessageTypes[0]; }
53 | }
54 |
55 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
56 | pbr::MessageDescriptor pb::IMessage.Descriptor {
57 | get { return Descriptor; }
58 | }
59 |
60 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
61 | public KeyMessage() {
62 | OnConstruction();
63 | }
64 |
65 | partial void OnConstruction();
66 |
67 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
68 | public KeyMessage(KeyMessage other) : this() {
69 | key_ = other.key_;
70 | }
71 |
72 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
73 | public KeyMessage Clone() {
74 | return new KeyMessage(this);
75 | }
76 |
77 | /// Field number for the "key" field.
78 | public const int KeyFieldNumber = 1;
79 | private string key_ = "";
80 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
81 | public string Key {
82 | get { return key_; }
83 | set {
84 | key_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
85 | }
86 | }
87 |
88 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
89 | public override bool Equals(object other) {
90 | return Equals(other as KeyMessage);
91 | }
92 |
93 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
94 | public bool Equals(KeyMessage other) {
95 | if (ReferenceEquals(other, null)) {
96 | return false;
97 | }
98 | if (ReferenceEquals(other, this)) {
99 | return true;
100 | }
101 | if (Key != other.Key) return false;
102 | return true;
103 | }
104 |
105 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
106 | public override int GetHashCode() {
107 | int hash = 1;
108 | if (Key.Length != 0) hash ^= Key.GetHashCode();
109 | return hash;
110 | }
111 |
112 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
113 | public override string ToString() {
114 | return pb::JsonFormatter.ToDiagnosticString(this);
115 | }
116 |
117 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
118 | public void WriteTo(pb::CodedOutputStream output) {
119 | if (Key.Length != 0) {
120 | output.WriteRawTag(10);
121 | output.WriteString(Key);
122 | }
123 | }
124 |
125 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
126 | public int CalculateSize() {
127 | int size = 0;
128 | if (Key.Length != 0) {
129 | size += 1 + pb::CodedOutputStream.ComputeStringSize(Key);
130 | }
131 | return size;
132 | }
133 |
134 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
135 | public void MergeFrom(KeyMessage other) {
136 | if (other == null) {
137 | return;
138 | }
139 | if (other.Key.Length != 0) {
140 | Key = other.Key;
141 | }
142 | }
143 |
144 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
145 | public void MergeFrom(pb::CodedInputStream input) {
146 | uint tag;
147 | while ((tag = input.ReadTag()) != 0) {
148 | switch(tag) {
149 | default:
150 | input.SkipLastField();
151 | break;
152 | case 10: {
153 | Key = input.ReadString();
154 | break;
155 | }
156 | }
157 | }
158 | }
159 |
160 | }
161 |
162 | public sealed partial class KeyValueMessage : pb::IMessage {
163 | private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new KeyValueMessage());
164 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
165 | public static pb::MessageParser Parser { get { return _parser; } }
166 |
167 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
168 | public static pbr::MessageDescriptor Descriptor {
169 | get { return global::Dhtproto.DhtReflection.Descriptor.MessageTypes[1]; }
170 | }
171 |
172 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
173 | pbr::MessageDescriptor pb::IMessage.Descriptor {
174 | get { return Descriptor; }
175 | }
176 |
177 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
178 | public KeyValueMessage() {
179 | OnConstruction();
180 | }
181 |
182 | partial void OnConstruction();
183 |
184 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
185 | public KeyValueMessage(KeyValueMessage other) : this() {
186 | key_ = other.key_;
187 | value_ = other.value_;
188 | }
189 |
190 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
191 | public KeyValueMessage Clone() {
192 | return new KeyValueMessage(this);
193 | }
194 |
195 | /// Field number for the "key" field.
196 | public const int KeyFieldNumber = 1;
197 | private string key_ = "";
198 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
199 | public string Key {
200 | get { return key_; }
201 | set {
202 | key_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
203 | }
204 | }
205 |
206 | /// Field number for the "value" field.
207 | public const int ValueFieldNumber = 2;
208 | private string value_ = "";
209 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
210 | public string Value {
211 | get { return value_; }
212 | set {
213 | value_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
214 | }
215 | }
216 |
217 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
218 | public override bool Equals(object other) {
219 | return Equals(other as KeyValueMessage);
220 | }
221 |
222 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
223 | public bool Equals(KeyValueMessage other) {
224 | if (ReferenceEquals(other, null)) {
225 | return false;
226 | }
227 | if (ReferenceEquals(other, this)) {
228 | return true;
229 | }
230 | if (Key != other.Key) return false;
231 | if (Value != other.Value) return false;
232 | return true;
233 | }
234 |
235 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
236 | public override int GetHashCode() {
237 | int hash = 1;
238 | if (Key.Length != 0) hash ^= Key.GetHashCode();
239 | if (Value.Length != 0) hash ^= Value.GetHashCode();
240 | return hash;
241 | }
242 |
243 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
244 | public override string ToString() {
245 | return pb::JsonFormatter.ToDiagnosticString(this);
246 | }
247 |
248 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
249 | public void WriteTo(pb::CodedOutputStream output) {
250 | if (Key.Length != 0) {
251 | output.WriteRawTag(10);
252 | output.WriteString(Key);
253 | }
254 | if (Value.Length != 0) {
255 | output.WriteRawTag(18);
256 | output.WriteString(Value);
257 | }
258 | }
259 |
260 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
261 | public int CalculateSize() {
262 | int size = 0;
263 | if (Key.Length != 0) {
264 | size += 1 + pb::CodedOutputStream.ComputeStringSize(Key);
265 | }
266 | if (Value.Length != 0) {
267 | size += 1 + pb::CodedOutputStream.ComputeStringSize(Value);
268 | }
269 | return size;
270 | }
271 |
272 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
273 | public void MergeFrom(KeyValueMessage other) {
274 | if (other == null) {
275 | return;
276 | }
277 | if (other.Key.Length != 0) {
278 | Key = other.Key;
279 | }
280 | if (other.Value.Length != 0) {
281 | Value = other.Value;
282 | }
283 | }
284 |
285 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
286 | public void MergeFrom(pb::CodedInputStream input) {
287 | uint tag;
288 | while ((tag = input.ReadTag()) != 0) {
289 | switch(tag) {
290 | default:
291 | input.SkipLastField();
292 | break;
293 | case 10: {
294 | Key = input.ReadString();
295 | break;
296 | }
297 | case 18: {
298 | Value = input.ReadString();
299 | break;
300 | }
301 | }
302 | }
303 | }
304 |
305 | }
306 |
307 | #endregion
308 |
309 | }
310 |
311 | #endregion Designer generated code
312 |
--------------------------------------------------------------------------------
/DHT.ProtocolBuffers/DhtProto/DhtGrpc.cs:
--------------------------------------------------------------------------------
1 | // Generated by the protocol buffer compiler. DO NOT EDIT!
2 | // source: dht.proto
3 | #region Designer generated code
4 |
5 | using System;
6 | using System.Threading;
7 | using System.Threading.Tasks;
8 | using grpc = global::Grpc.Core;
9 |
10 | namespace Dhtproto {
11 | ///
12 | /// Interface exported by the server.
13 | ///
14 | public static partial class DhtProtoService
15 | {
16 | static readonly string __ServiceName = "dhtproto.DhtProtoService";
17 |
18 | static readonly grpc::Marshaller __Marshaller_KeyMessage = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Dhtproto.KeyMessage.Parser.ParseFrom);
19 | static readonly grpc::Marshaller __Marshaller_KeyValueMessage = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Dhtproto.KeyValueMessage.Parser.ParseFrom);
20 |
21 | static readonly grpc::Method __Method_GetValue = new grpc::Method(
22 | grpc::MethodType.Unary,
23 | __ServiceName,
24 | "GetValue",
25 | __Marshaller_KeyMessage,
26 | __Marshaller_KeyValueMessage);
27 |
28 | static readonly grpc::Method __Method_StoreValue = new grpc::Method(
29 | grpc::MethodType.Unary,
30 | __ServiceName,
31 | "StoreValue",
32 | __Marshaller_KeyValueMessage,
33 | __Marshaller_KeyValueMessage);
34 |
35 | static readonly grpc::Method __Method_RemoveValue = new grpc::Method(
36 | grpc::MethodType.Unary,
37 | __ServiceName,
38 | "RemoveValue",
39 | __Marshaller_KeyMessage,
40 | __Marshaller_KeyMessage);
41 |
42 | /// Service descriptor
43 | public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
44 | {
45 | get { return global::Dhtproto.DhtReflection.Descriptor.Services[0]; }
46 | }
47 |
48 | /// Base class for server-side implementations of DhtProtoService
49 | public abstract partial class DhtProtoServiceBase
50 | {
51 | public virtual global::System.Threading.Tasks.Task GetValue(global::Dhtproto.KeyMessage request, grpc::ServerCallContext context)
52 | {
53 | throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, ""));
54 | }
55 |
56 | public virtual global::System.Threading.Tasks.Task StoreValue(global::Dhtproto.KeyValueMessage request, grpc::ServerCallContext context)
57 | {
58 | throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, ""));
59 | }
60 |
61 | public virtual global::System.Threading.Tasks.Task RemoveValue(global::Dhtproto.KeyMessage request, grpc::ServerCallContext context)
62 | {
63 | throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, ""));
64 | }
65 |
66 | }
67 |
68 | /// Client for DhtProtoService
69 | public partial class DhtProtoServiceClient : grpc::ClientBase
70 | {
71 | /// Creates a new client for DhtProtoService
72 | /// The channel to use to make remote calls.
73 | public DhtProtoServiceClient(grpc::Channel channel) : base(channel)
74 | {
75 | }
76 | /// Creates a new client for DhtProtoService that uses a custom CallInvoker.
77 | /// The callInvoker to use to make remote calls.
78 | public DhtProtoServiceClient(grpc::CallInvoker callInvoker) : base(callInvoker)
79 | {
80 | }
81 | /// Protected parameterless constructor to allow creation of test doubles.
82 | protected DhtProtoServiceClient() : base()
83 | {
84 | }
85 | /// Protected constructor to allow creation of configured clients.
86 | /// The client configuration.
87 | protected DhtProtoServiceClient(ClientBaseConfiguration configuration) : base(configuration)
88 | {
89 | }
90 |
91 | public virtual global::Dhtproto.KeyValueMessage GetValue(global::Dhtproto.KeyMessage request, grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
92 | {
93 | return GetValue(request, new grpc::CallOptions(headers, deadline, cancellationToken));
94 | }
95 | public virtual global::Dhtproto.KeyValueMessage GetValue(global::Dhtproto.KeyMessage request, grpc::CallOptions options)
96 | {
97 | return CallInvoker.BlockingUnaryCall(__Method_GetValue, null, options, request);
98 | }
99 | public virtual grpc::AsyncUnaryCall GetValueAsync(global::Dhtproto.KeyMessage request, grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
100 | {
101 | return GetValueAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken));
102 | }
103 | public virtual grpc::AsyncUnaryCall GetValueAsync(global::Dhtproto.KeyMessage request, grpc::CallOptions options)
104 | {
105 | return CallInvoker.AsyncUnaryCall(__Method_GetValue, null, options, request);
106 | }
107 | public virtual global::Dhtproto.KeyValueMessage StoreValue(global::Dhtproto.KeyValueMessage request, grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
108 | {
109 | return StoreValue(request, new grpc::CallOptions(headers, deadline, cancellationToken));
110 | }
111 | public virtual global::Dhtproto.KeyValueMessage StoreValue(global::Dhtproto.KeyValueMessage request, grpc::CallOptions options)
112 | {
113 | return CallInvoker.BlockingUnaryCall(__Method_StoreValue, null, options, request);
114 | }
115 | public virtual grpc::AsyncUnaryCall StoreValueAsync(global::Dhtproto.KeyValueMessage request, grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
116 | {
117 | return StoreValueAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken));
118 | }
119 | public virtual grpc::AsyncUnaryCall StoreValueAsync(global::Dhtproto.KeyValueMessage request, grpc::CallOptions options)
120 | {
121 | return CallInvoker.AsyncUnaryCall(__Method_StoreValue, null, options, request);
122 | }
123 | public virtual global::Dhtproto.KeyMessage RemoveValue(global::Dhtproto.KeyMessage request, grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
124 | {
125 | return RemoveValue(request, new grpc::CallOptions(headers, deadline, cancellationToken));
126 | }
127 | public virtual global::Dhtproto.KeyMessage RemoveValue(global::Dhtproto.KeyMessage request, grpc::CallOptions options)
128 | {
129 | return CallInvoker.BlockingUnaryCall(__Method_RemoveValue, null, options, request);
130 | }
131 | public virtual grpc::AsyncUnaryCall RemoveValueAsync(global::Dhtproto.KeyMessage request, grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
132 | {
133 | return RemoveValueAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken));
134 | }
135 | public virtual grpc::AsyncUnaryCall RemoveValueAsync(global::Dhtproto.KeyMessage request, grpc::CallOptions options)
136 | {
137 | return CallInvoker.AsyncUnaryCall(__Method_RemoveValue, null, options, request);
138 | }
139 | /// Creates a new instance of client from given ClientBaseConfiguration.
140 | protected override DhtProtoServiceClient NewInstance(ClientBaseConfiguration configuration)
141 | {
142 | return new DhtProtoServiceClient(configuration);
143 | }
144 | }
145 |
146 | /// Creates service definition that can be registered with a server
147 | /// An object implementing the server-side handling logic.
148 | public static grpc::ServerServiceDefinition BindService(DhtProtoServiceBase serviceImpl)
149 | {
150 | return grpc::ServerServiceDefinition.CreateBuilder()
151 | .AddMethod(__Method_GetValue, serviceImpl.GetValue)
152 | .AddMethod(__Method_StoreValue, serviceImpl.StoreValue)
153 | .AddMethod(__Method_RemoveValue, serviceImpl.RemoveValue).Build();
154 | }
155 |
156 | }
157 | }
158 | #endregion
159 |
--------------------------------------------------------------------------------
/DHT.ProtocolBuffers/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("DHT.ProtocolBuffers")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("DHT.ProtocolBuffers")]
13 | [assembly: AssemblyCopyright("Copyright © 2017")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("76baf981-f995-4cb9-b9d5-229a822bd8ff")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/DHT.ProtocolBuffers/generate_protos.bat:
--------------------------------------------------------------------------------
1 | @rem Copyright 2016, Google Inc.
2 | @rem All rights reserved.
3 | @rem
4 | @rem Redistribution and use in source and binary forms, with or without
5 | @rem modification, are permitted provided that the following conditions are
6 | @rem met:
7 | @rem
8 | @rem * Redistributions of source code must retain the above copyright
9 | @rem notice, this list of conditions and the following disclaimer.
10 | @rem * Redistributions in binary form must reproduce the above
11 | @rem copyright notice, this list of conditions and the following disclaimer
12 | @rem in the documentation and/or other materials provided with the
13 | @rem distribution.
14 | @rem * Neither the name of Google Inc. nor the names of its
15 | @rem contributors may be used to endorse or promote products derived from
16 | @rem this software without specific prior written permission.
17 | @rem
18 | @rem THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 | @rem "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 | @rem LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 | @rem A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 | @rem OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 | @rem SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 | @rem LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 | @rem DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 | @rem THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 | @rem (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 | @rem OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 |
30 | @rem Generate the C# code for .proto files
31 |
32 | setlocal
33 |
34 | @rem enter this directory
35 | cd /d %~dp0
36 |
37 | set TOOLS_PATH=..\packages\Grpc.Tools.1.2.2\tools\windows_x86
38 |
39 | %TOOLS_PATH%\protoc.exe -I protos --csharp_out DhtProto protos/dht.proto --grpc_out DhtProto --plugin=protoc-gen-grpc=%TOOLS_PATH%\grpc_csharp_plugin.exe
40 |
41 | endlocal
42 |
--------------------------------------------------------------------------------
/DHT.ProtocolBuffers/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/DHT.ProtocolBuffers/protos/dht.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | option java_multiple_files = true;
4 | option java_package = "io.grpc.examples.routeguide";
5 | option java_outer_classname = "HelloServiceProto";
6 | option objc_class_prefix = "RTG";
7 |
8 | package dhtproto;
9 |
10 | // Interface exported by the server.
11 | service DhtProtoService {
12 |
13 | rpc GetValue(KeyMessage) returns (KeyValueMessage) {}
14 |
15 | rpc StoreValue(KeyValueMessage) returns (KeyValueMessage) {}
16 |
17 | rpc RemoveValue(KeyMessage) returns (KeyMessage) {}
18 | }
19 |
20 | message KeyMessage {
21 | string key = 1;
22 | }
23 |
24 | message KeyValueMessage {
25 | string key = 1;
26 | string value = 2;
27 | }
--------------------------------------------------------------------------------
/DHT.Runner/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/DHT.Runner/DHT.Runner.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {40FABD93-3D5C-4DDD-99B5-288378F41FC2}
8 | Exe
9 | Properties
10 | DHT.Runner
11 | DHT.Runner
12 | v4.5.2
13 | 512
14 | true
15 |
16 |
17 | AnyCPU
18 | true
19 | full
20 | false
21 | bin\Debug\
22 | DEBUG;TRACE
23 | prompt
24 | 4
25 |
26 |
27 | AnyCPU
28 | pdbonly
29 | true
30 | bin\Release\
31 | TRACE
32 | prompt
33 | 4
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 | False
56 | ..\packages\System.Interactive.Async.3.0.0\lib\net45\System.Interactive.Async.dll
57 |
58 |
59 | False
60 | ..\packages\Google.Protobuf.3.0.0\lib\net45\Google.Protobuf.dll
61 |
62 |
63 | False
64 | ..\packages\Grpc.Core.1.0.1\lib\net45\Grpc.Core.dll
65 |
66 |
67 | False
68 | ..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll
69 |
70 |
71 | {07e4bbdf-a699-417a-ae38-ce60d953680e}
72 | DHT.Network.NodeRunner
73 |
74 |
75 | {76baf981-f995-4cb9-b9d5-229a822bd8ff}
76 | DHT.ProtocolBuffers
77 |
78 |
79 | {cf2d500f-1ebf-43ee-b8c4-4096da5cfba4}
80 | DHT
81 |
82 |
83 |
84 |
85 | Always
86 |
87 |
88 |
89 |
96 |
--------------------------------------------------------------------------------
/DHT.Runner/Program.cs:
--------------------------------------------------------------------------------
1 | namespace DHT.Runner
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Diagnostics;
6 | using System.Linq;
7 | using Dhtproto;
8 | using Grpc.Core;
9 | using Nodes;
10 | using Routing;
11 | using static Dhtproto.DhtProtoService;
12 |
13 | class Program
14 | {
15 | private static Random random = new Random();
16 |
17 | private static IRoutingTable routingTable = RoutingTableFactory.FromFile("routingTable.txt");
18 |
19 | private static IList processes = new List();
20 |
21 | static void Main(string[] args)
22 | {
23 | var commands = new Dictionary>>()
24 | {
25 | { "help", Help },
26 | { "start", Start },
27 | { "stop", Stop },
28 | { "getValue", GetValue },
29 | { "storeValue", StoreValue },
30 | { "removeValue", RemoveValue },
31 | };
32 |
33 | // Main networking management loop
34 | while (true)
35 | {
36 | var line = Console.ReadLine();
37 | var lineArgs = line.Split(' ').ToList();
38 | var command = lineArgs[0];
39 |
40 | lineArgs.RemoveAt(0);
41 |
42 | if (commands.ContainsKey(command))
43 | {
44 | var commandFunc = commands[command];
45 | commandFunc(command, lineArgs);
46 | }
47 | else
48 | {
49 | Console.WriteLine("Unknown command");
50 | }
51 | }
52 | }
53 |
54 | private static void StartNodeServerProcess(NodeInfo nodeInfo)
55 | {
56 | Process p = new Process();
57 | p.StartInfo.FileName = "DHT.Network.NodeRunner.exe";
58 | p.StartInfo.Arguments = nodeInfo.NodeId.ToString();
59 |
60 | p.Start();
61 |
62 | processes.Add(p);
63 | }
64 |
65 | private static void Help(string command, IList args)
66 | {
67 | Console.WriteLine("Help command run");
68 | }
69 |
70 | private static void Start(string command, IList args)
71 | {
72 | // Start node servers
73 | var servers = new List();
74 |
75 | foreach (var node in routingTable.Nodes)
76 | {
77 | StartNodeServerProcess(node);
78 | }
79 | }
80 |
81 | private static void Stop(string command, IList args)
82 | {
83 | // Start node servers
84 | var servers = new List();
85 |
86 | foreach (var process in processes)
87 | {
88 | process.Kill();
89 | }
90 |
91 | processes.Clear();
92 | }
93 |
94 | private static void GetValue(string command, IList args)
95 | {
96 | var client = GetRandomClient();
97 | var request = new KeyMessage()
98 | {
99 | Key = args[0]
100 | };
101 |
102 | try
103 | {
104 | var response = client.GetValue(request);
105 | Console.WriteLine("Success: Got key value = {0} {1}", response.Key, response.Value);
106 | }
107 | catch (RpcException e)
108 | {
109 | Console.WriteLine("Error: {0} {1} ", e.Status.StatusCode, e.Status.Detail);
110 | }
111 | }
112 |
113 | private static void StoreValue(string command, IList args)
114 | {
115 | var client = GetRandomClient();
116 | var request = new KeyValueMessage()
117 | {
118 | Key = args[0],
119 | Value = args[1]
120 | };
121 |
122 | try
123 | {
124 | var response = client.StoreValue(request);
125 | Console.WriteLine("Success: Got key value = {0} {1}", response.Key, response.Value);
126 | }
127 | catch (RpcException e)
128 | {
129 | Console.WriteLine("Error: {0} {1} ", e.Status.StatusCode, e.Status.Detail);
130 | }
131 | }
132 |
133 | private static void RemoveValue(string command, IList args)
134 | {
135 | var client = GetRandomClient();
136 | var request = new KeyMessage()
137 | {
138 | Key = args[0]
139 | };
140 |
141 | try
142 | {
143 | var response = client.RemoveValue(request);
144 | Console.WriteLine("Success: Got key value = {0}", response.Key);
145 | }
146 | catch (RpcException e)
147 | {
148 | Console.WriteLine("Error: {0} {1} ", e.Status.StatusCode, e.Status.Detail);
149 | }
150 | }
151 |
152 | private static NodeInfo GetRandomNode()
153 | {
154 | var randomNodeIdx = random.Next(0, routingTable.Nodes.Count);
155 | var randomNode = routingTable.Nodes[randomNodeIdx];
156 |
157 | return randomNode;
158 | }
159 |
160 | private static DhtProtoServiceClient GetRandomClient()
161 | {
162 | var node = GetRandomNode();
163 |
164 | var target = string.Format("{0}:{1}", node.HostName, node.Port);
165 | var channel = new Channel(target, ChannelCredentials.Insecure);
166 | var client = new DhtProtoServiceClient(channel);
167 |
168 | return client;
169 | }
170 | }
171 | }
172 |
--------------------------------------------------------------------------------
/DHT.Runner/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("DHT.Runner")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("DHT.Runner")]
13 | [assembly: AssemblyCopyright("Copyright © 2017")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("40fabd93-3d5c-4ddd-99b5-288378f41fc2")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/DHT.Runner/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/DHT.Runner/routingTable.txt:
--------------------------------------------------------------------------------
1 | 90037898 localhost 11000
2 | 270845369 localhost 11001
3 | 379604884 localhost 11002
4 | 488206434 localhost 11003
5 | 537028870 localhost 11004
6 | 694202208 localhost 11005
7 | 886653498 localhost 11006
8 | 975552819 localhost 11007
9 | 1079815039 localhost 11008
10 | 2090213630 localhost 11009
--------------------------------------------------------------------------------
/DHT.Tests/DHT.Tests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Debug
5 | AnyCPU
6 | {2B4BDB45-4547-41B4-89BD-453B0D6F7EF4}
7 | Library
8 | Properties
9 | DHT.Tests
10 | DHT.Tests
11 | v4.5.2
12 | 512
13 | {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
14 | 10.0
15 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
16 | $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages
17 | False
18 | UnitTest
19 |
20 |
21 | true
22 | full
23 | false
24 | bin\Debug\
25 | DEBUG;TRACE
26 | prompt
27 | 4
28 |
29 |
30 | pdbonly
31 | true
32 | bin\Release\
33 | TRACE
34 | prompt
35 | 4
36 |
37 |
38 |
39 | ..\packages\Castle.Core.4.0.0\lib\net45\Castle.Core.dll
40 | True
41 |
42 |
43 |
44 | ..\packages\Moq.4.7.8\lib\net45\Moq.dll
45 | True
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 | False
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 | {76BAF981-F995-4CB9-B9D5-229A822BD8FF}
75 | DHT.ProtocolBuffers
76 |
77 |
78 | {cf2d500f-1ebf-43ee-b8c4-4096da5cfba4}
79 | DHT
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 | False
91 |
92 |
93 | False
94 |
95 |
96 | False
97 |
98 |
99 | False
100 |
101 |
102 |
103 |
104 |
105 |
106 |
113 |
--------------------------------------------------------------------------------
/DHT.Tests/Nodes/NodeStoreTests.cs:
--------------------------------------------------------------------------------
1 | namespace DHT.Tests.Nodes
2 | {
3 | using System.Data.Linq;
4 | using DHT.Nodes;
5 | using Microsoft.VisualStudio.TestTools.UnitTesting;
6 |
7 | [TestClass]
8 | public class NodeStoreTests
9 | {
10 | [TestMethod]
11 | public void NodeStore_ContainsKey_False()
12 | {
13 | // Arrange
14 | var store = new NodeStore();
15 | var key = "key";
16 |
17 | // Act
18 | var containsKey = store.ContainsKey(key);
19 |
20 | // Assert
21 | Assert.IsFalse(containsKey);
22 | }
23 |
24 | [TestMethod]
25 | public void NodeStore_ContainsKey_True()
26 | {
27 | // Arrange
28 | var store = new NodeStore();
29 | var key = "key";
30 | var value = "value";
31 | store.AddValue(key, value);
32 |
33 | // Act
34 | var containsKey = store.ContainsKey(key);
35 |
36 | // Assert
37 | Assert.IsTrue(containsKey);
38 | }
39 |
40 | [TestMethod]
41 | public void NodeStore_GetValue_Null()
42 | {
43 | // Arrange
44 | var store = new NodeStore();
45 | var key = "key";
46 |
47 | // Act
48 | var storeValue = store.GetValue(key);
49 |
50 | // Assert
51 | Assert.IsNull(storeValue);
52 | }
53 |
54 | [TestMethod]
55 | public void NodeStore_GetValue_NotNull()
56 | {
57 | // Arrange
58 | var store = new NodeStore();
59 | var key = "key";
60 | var value = "value";
61 | store.AddValue(key, value);
62 |
63 | // Act
64 | var storeValue = store.GetValue(key);
65 |
66 | // Assert
67 | Assert.AreEqual(value, storeValue);
68 | }
69 |
70 | [TestMethod]
71 | public void NodeStore_AddValue_True()
72 | {
73 | // Arrange
74 | var store = new NodeStore();
75 | var key = "key";
76 | var value = "value";
77 |
78 | // Act
79 | var added = store.AddValue(key, value);
80 |
81 | // Assert
82 | Assert.IsTrue(added);
83 | }
84 |
85 | [TestMethod]
86 | [ExpectedException(typeof(DuplicateKeyException))]
87 | public void NodeStore_AddValue_ThrowsIfAlreadyThere()
88 | {
89 | // Arrange
90 | var store = new NodeStore();
91 | var key = "key";
92 | var value = "value";
93 | store.AddValue(key, value);
94 |
95 | // Act
96 | store.AddValue(key, value);
97 | }
98 |
99 | [TestMethod]
100 | public void NodeStore_RemoveValue_False()
101 | {
102 | // Arrange
103 | var store = new NodeStore();
104 | var key = "key";
105 |
106 | // Act
107 | var removed = store.RemoveValue(key);
108 |
109 | // Assert
110 | Assert.IsFalse(removed);
111 | }
112 |
113 | [TestMethod]
114 | public void NodeStore_RemoveValue_True()
115 | {
116 | // Arrange
117 | var store = new NodeStore();
118 | var key = "key";
119 | var value = "value";
120 | var added = store.AddValue(key, value);
121 |
122 | // Act
123 | var removed = store.RemoveValue(key);
124 |
125 | // Assert
126 | Assert.IsTrue(removed);
127 | }
128 | }
129 | }
130 |
--------------------------------------------------------------------------------
/DHT.Tests/NodesProtocol/LocalNodeServerClientTests.cs:
--------------------------------------------------------------------------------
1 | namespace DHT.Tests.NodesProtocol
2 | {
3 | using System.Data.Linq;
4 | using DHT.Nodes;
5 | using DHT.NodesProtocol;
6 | using Dhtproto;
7 | using Grpc.Core;
8 | using Microsoft.VisualStudio.TestTools.UnitTesting;
9 | using Moq;
10 |
11 | [TestClass]
12 | public class LocalNodeServerClientTests
13 | {
14 | private Mock nodeStoreMock;
15 |
16 | private LocalNodeServerClient client;
17 |
18 | [TestInitialize]
19 | public void TestInit()
20 | {
21 | this.nodeStoreMock = new Mock();
22 | this.client = new LocalNodeServerClient(this.nodeStoreMock.Object);
23 | }
24 |
25 | [TestMethod]
26 | [ExpectedException(typeof(RpcException))]
27 | public void LocalNodeServerClient_GetValue_ThrowsOnKeyNotFound()
28 | {
29 | // Arrange
30 | var key = "a";
31 | var request = new KeyMessage()
32 | {
33 | Key = key
34 | };
35 |
36 | // Act
37 | this.client.GetValue(request);
38 | }
39 |
40 | [TestMethod]
41 | public void LocalNodeServerClient_GetValue_GetsValue()
42 | {
43 | // Arrange
44 | var key = "a";
45 | var value = "aValue";
46 | var request = new KeyMessage()
47 | {
48 | Key = key
49 | };
50 | this.nodeStoreMock
51 | .Setup(x => x.ContainsKey(key))
52 | .Returns(true);
53 | this.nodeStoreMock
54 | .Setup(x => x.GetValue(key))
55 | .Returns(value);
56 |
57 | // Act
58 | var response = this.client.GetValue(request);
59 |
60 | // Assert
61 | Assert.AreEqual(key, response.Key);
62 | Assert.AreEqual(value, response.Value);
63 | }
64 |
65 | [TestMethod]
66 | [ExpectedException(typeof(RpcException))]
67 | public void LocalNodeServerClient_RemoveValue_ThrowsOnFailure()
68 | {
69 | // Arrange
70 | var key = "a";
71 | var request = new KeyMessage()
72 | {
73 | Key = key
74 | };
75 | this.nodeStoreMock
76 | .Setup(x => x.RemoveValue(key))
77 | .Returns(false);
78 |
79 | // Act
80 | var response = this.client.RemoveValue(request);
81 | }
82 |
83 | [TestMethod]
84 | public void LocalNodeServerClient_RemoveValue_RemovesValue()
85 | {
86 | // Arrange
87 | var key = "a";
88 | var request = new KeyMessage()
89 | {
90 | Key = key
91 | };
92 | this.nodeStoreMock
93 | .Setup(x => x.RemoveValue(key))
94 | .Returns(true);
95 |
96 | // Act
97 | var response = this.client.RemoveValue(request);
98 |
99 | // Assert
100 | Assert.AreEqual(key, response.Key);
101 | }
102 |
103 | [TestMethod]
104 | [ExpectedException(typeof(RpcException))]
105 | public void LocalNodeServerClient_StoreValue_ThrowsOnFailure()
106 | {
107 | // Arrange
108 | var key = "a";
109 | var value = "aValue";
110 | var request = new KeyValueMessage()
111 | {
112 | Key = key,
113 | Value = value
114 | };
115 | this.nodeStoreMock
116 | .Setup(x => x.AddValue(key, value))
117 | .Returns(false);
118 |
119 | // Act
120 | var response = this.client.StoreValue(request);
121 | }
122 |
123 | [TestMethod]
124 | [ExpectedException(typeof(RpcException))]
125 | public void LocalNodeServerClient_StoreValue_ThrowsOnDuplicateKey()
126 | {
127 | // Arrange
128 | var key = "a";
129 | var value = "aValue";
130 | var request = new KeyValueMessage()
131 | {
132 | Key = key,
133 | Value = value
134 | };
135 | this.nodeStoreMock
136 | .Setup(x => x.AddValue(key, value))
137 | .Throws(new DuplicateKeyException(key));
138 |
139 | // Act
140 | var response = this.client.StoreValue(request);
141 | }
142 |
143 | [TestMethod]
144 | public void LocalNodeServerClient_StoreValue_StoresValue()
145 | {
146 | // Arrange
147 | var key = "a";
148 | var value = "aValue";
149 | var request = new KeyValueMessage()
150 | {
151 | Key = key,
152 | Value = value
153 | };
154 | this.nodeStoreMock
155 | .Setup(x => x.AddValue(key, value))
156 | .Returns(true);
157 |
158 | // Act
159 | var response = this.client.StoreValue(request);
160 |
161 | // Assert
162 | Assert.AreEqual(key, response.Key);
163 | Assert.AreEqual(value, response.Value);
164 | }
165 | }
166 | }
167 |
--------------------------------------------------------------------------------
/DHT.Tests/NodesProtocol/NodeServerClientFactoryTests.cs:
--------------------------------------------------------------------------------
1 | namespace DHT.Tests.NodesProtocol
2 | {
3 | using DHT.Nodes;
4 | using DHT.NodesProtocol;
5 | using Microsoft.VisualStudio.TestTools.UnitTesting;
6 |
7 | [TestClass]
8 | public class NodeServerClientFactoryTests
9 | {
10 | [TestMethod]
11 | public void NodeServerClientFactory_CreateLocalClient()
12 | {
13 | // Arrange
14 | var factory = new NodeServerClientFactory();
15 |
16 | // Act
17 | var client = factory.CreateLocalClient();
18 |
19 | // Assert
20 | Assert.IsInstanceOfType(client, typeof(LocalNodeServerClient));
21 | }
22 |
23 | [TestMethod]
24 | public void NodeServerClientFactory_CreateRemoteClient()
25 | {
26 | // Arrange
27 | var factory = new NodeServerClientFactory();
28 | var nodeInfo = new NodeInfo();
29 |
30 | // Act
31 | var client = factory.CreateRemoteClient(nodeInfo);
32 |
33 | // Assert
34 | Assert.IsNotInstanceOfType(client, typeof(LocalNodeServerClient));
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/DHT.Tests/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("DHT.Tests")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("DHT.Tests")]
13 | [assembly: AssemblyCopyright("Copyright © 2017")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("2b4bdb45-4547-41b4-89bd-453b0d6f7ef4")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/DHT.Tests/Routing/RoutingTableTests.cs:
--------------------------------------------------------------------------------
1 | namespace DHT.Tests.Routing
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Diagnostics;
6 | using System.Linq;
7 | using DHT.Nodes;
8 | using DHT.Routing;
9 | using Microsoft.VisualStudio.TestTools.UnitTesting;
10 | using Moq;
11 | using Nodes;
12 |
13 | [TestClass]
14 | public class RoutingTableTests
15 | {
16 | private static Random random = new Random();
17 |
18 | private IRoutingTable routingTableMockHash;
19 |
20 | private IRoutingTable routingTableRealHash;
21 |
22 | [TestInitialize]
23 | public void TestInit()
24 | {
25 | // Setup routingTableMockHash
26 | var hashGenerator = new Mock();
27 | hashGenerator
28 | .Setup(x => x.Hash(It.IsAny()))
29 | .Returns(() => { return (UInt32)random.Next(); });
30 |
31 | this.routingTableMockHash = new RoutingTable(hashGenerator.Object);
32 |
33 | // Setup routingTableRealHash
34 | var realHashGenerator = new Sha256HashGenerator();
35 | this.routingTableRealHash = new RoutingTable(realHashGenerator);
36 | }
37 |
38 | [TestMethod]
39 | public void RoutingTable_FindNode_FakeHash()
40 | {
41 | // Act Assert
42 | this.AssertFindNode(this.routingTableMockHash, 10, 100);
43 | }
44 |
45 | [TestMethod]
46 | public void RoutingTable_FindNode_RealHash()
47 | {
48 | // Act Assert
49 | this.AssertFindNode(this.routingTableRealHash, 10, 100);
50 | }
51 |
52 | private void AssertFindNode(IRoutingTable routingTable, int randomNodes, int randomKeys)
53 | {
54 | Debug.WriteLine("--------");
55 | Debug.WriteLine("Test starting with {0} nodes and {1} keys", randomNodes, randomKeys);
56 | Debug.WriteLine("--------");
57 | Debug.WriteLine(string.Empty);
58 |
59 | // Arrange
60 | var nodes = this.GetRandomNodes(randomNodes);
61 | var freq = new Dictionary();
62 | routingTable.Nodes = nodes;
63 |
64 | foreach(var node in nodes)
65 | {
66 | freq.Add(node, 0);
67 | }
68 |
69 | var keys = this.GetRandomKeys(randomKeys);
70 |
71 | foreach (var key in keys)
72 | {
73 | // Act
74 | var partitionNode = routingTable.FindNode(key);
75 |
76 | // Assert
77 | Assert.IsNotNull(partitionNode);
78 |
79 | freq[partitionNode]++;
80 | }
81 |
82 | // Print frequency
83 | foreach (var freqKV in freq.OrderBy(n => n.Key.NodeId))
84 | {
85 | Debug.WriteLine("Node {0} selected {1}", freqKV.Key.NodeId, freqKV.Value);
86 | }
87 |
88 | Debug.WriteLine(string.Empty);
89 | Debug.WriteLine(string.Empty);
90 | }
91 |
92 | private IList GetRandomKeys(int numberOfKeys)
93 | {
94 | var keys = new List();
95 |
96 | for (int keyIdx = 0; keyIdx < numberOfKeys; keyIdx++)
97 | {
98 | var keyLength = random.Next(1, 10);
99 | var key = this.GetRandomString(keyLength);
100 |
101 | keys.Add(key);
102 | }
103 |
104 | return keys;
105 | }
106 |
107 | private string GetRandomString(int length)
108 | {
109 | const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
110 |
111 | var randomChars = Enumerable
112 | .Repeat(chars, length)
113 | .Select(s => s[random.Next(s.Length)])
114 | .ToArray();
115 |
116 | return new string(randomChars);
117 | }
118 |
119 | private IList GetRandomNodes(int numberOfNodes)
120 | {
121 | var nodes = new List();
122 |
123 | for (int nodeIdx = 0; nodeIdx < numberOfNodes; nodeIdx++)
124 | {
125 | var randomNodeId = (UInt32)random.Next(0, Int32.MaxValue);
126 | var nodeInfo = new NodeInfo()
127 | {
128 | NodeId = randomNodeId
129 | };
130 |
131 | nodes.Add(nodeInfo);
132 | }
133 |
134 | return nodes;
135 | }
136 | }
137 | }
138 |
--------------------------------------------------------------------------------
/DHT.Tests/Routing/Sha256HashGeneratorTests.cs:
--------------------------------------------------------------------------------
1 | namespace DHT.Tests.Routing
2 | {
3 | using System;
4 | using DHT.Routing;
5 | using Microsoft.VisualStudio.TestTools.UnitTesting;
6 |
7 | [TestClass]
8 | public class Sha256HashGeneratorTests
9 | {
10 | [TestMethod]
11 | public void Sha256HashGenerator_Hash_IsConsistent()
12 | {
13 | // Arrange
14 | var value = "value";
15 | var hashGenerator = new Sha256HashGenerator();
16 |
17 | // Act
18 | var valueHash1 = hashGenerator.Hash(value);
19 | var valueHash2 = hashGenerator.Hash(value);
20 |
21 | // Assert
22 | Assert.AreEqual(valueHash1, valueHash2);
23 | }
24 |
25 | [TestMethod]
26 | public void Sha256HashGenerator_Hash_IsDifferent()
27 | {
28 | // Arrange
29 | var value1 = "value1";
30 | var value2 = "value2";
31 | var hashGenerator = new Sha256HashGenerator();
32 |
33 | // Act
34 | var valueHash1 = hashGenerator.Hash(value1);
35 | var valueHash2 = hashGenerator.Hash(value2);
36 |
37 | // Assert
38 | Assert.AreNotEqual(valueHash1, valueHash2);
39 | }
40 |
41 | [TestMethod]
42 | [ExpectedException(typeof(ArgumentNullException))]
43 | public void Sha256HashGenerator_Hash_ThrowsForNullString()
44 | {
45 | // Arrange
46 | string value = null;
47 | var hashGenerator = new Sha256HashGenerator();
48 |
49 | // Act
50 | var valueHash = hashGenerator.Hash(value);
51 | }
52 |
53 | [TestMethod]
54 | [ExpectedException(typeof(ArgumentException))]
55 | public void Sha256HashGenerator_Hash_ThrowsForEmptyString()
56 | {
57 | // Arrange
58 | string value = string.Empty;
59 | var hashGenerator = new Sha256HashGenerator();
60 |
61 | // Act
62 | var valueHash = hashGenerator.Hash(value);
63 | }
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/DHT.Tests/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/DHT.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 14
4 | VisualStudioVersion = 14.0.25420.1
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DHT", "DHT\DHT.csproj", "{CF2D500F-1EBF-43EE-B8C4-4096DA5CFBA4}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DHT.Tests", "DHT.Tests\DHT.Tests.csproj", "{2B4BDB45-4547-41B4-89BD-453B0D6F7EF4}"
9 | EndProject
10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DHT.ProtocolBuffers", "DHT.ProtocolBuffers\DHT.ProtocolBuffers.csproj", "{76BAF981-F995-4CB9-B9D5-229A822BD8FF}"
11 | EndProject
12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DHT.Runner", "DHT.Runner\DHT.Runner.csproj", "{40FABD93-3D5C-4DDD-99B5-288378F41FC2}"
13 | EndProject
14 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DHT.Network.NodeRunner", "DHT.Network.NodeRunner\DHT.Network.NodeRunner.csproj", "{07E4BBDF-A699-417A-AE38-CE60D953680E}"
15 | EndProject
16 | Global
17 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
18 | Debug|Any CPU = Debug|Any CPU
19 | Release|Any CPU = Release|Any CPU
20 | EndGlobalSection
21 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
22 | {CF2D500F-1EBF-43EE-B8C4-4096DA5CFBA4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
23 | {CF2D500F-1EBF-43EE-B8C4-4096DA5CFBA4}.Debug|Any CPU.Build.0 = Debug|Any CPU
24 | {CF2D500F-1EBF-43EE-B8C4-4096DA5CFBA4}.Release|Any CPU.ActiveCfg = Release|Any CPU
25 | {CF2D500F-1EBF-43EE-B8C4-4096DA5CFBA4}.Release|Any CPU.Build.0 = Release|Any CPU
26 | {2B4BDB45-4547-41B4-89BD-453B0D6F7EF4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
27 | {2B4BDB45-4547-41B4-89BD-453B0D6F7EF4}.Debug|Any CPU.Build.0 = Debug|Any CPU
28 | {2B4BDB45-4547-41B4-89BD-453B0D6F7EF4}.Release|Any CPU.ActiveCfg = Release|Any CPU
29 | {2B4BDB45-4547-41B4-89BD-453B0D6F7EF4}.Release|Any CPU.Build.0 = Release|Any CPU
30 | {76BAF981-F995-4CB9-B9D5-229A822BD8FF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
31 | {76BAF981-F995-4CB9-B9D5-229A822BD8FF}.Debug|Any CPU.Build.0 = Debug|Any CPU
32 | {76BAF981-F995-4CB9-B9D5-229A822BD8FF}.Release|Any CPU.ActiveCfg = Release|Any CPU
33 | {76BAF981-F995-4CB9-B9D5-229A822BD8FF}.Release|Any CPU.Build.0 = Release|Any CPU
34 | {40FABD93-3D5C-4DDD-99B5-288378F41FC2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
35 | {40FABD93-3D5C-4DDD-99B5-288378F41FC2}.Debug|Any CPU.Build.0 = Debug|Any CPU
36 | {40FABD93-3D5C-4DDD-99B5-288378F41FC2}.Release|Any CPU.ActiveCfg = Release|Any CPU
37 | {40FABD93-3D5C-4DDD-99B5-288378F41FC2}.Release|Any CPU.Build.0 = Release|Any CPU
38 | {07E4BBDF-A699-417A-AE38-CE60D953680E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
39 | {07E4BBDF-A699-417A-AE38-CE60D953680E}.Debug|Any CPU.Build.0 = Debug|Any CPU
40 | {07E4BBDF-A699-417A-AE38-CE60D953680E}.Release|Any CPU.ActiveCfg = Release|Any CPU
41 | {07E4BBDF-A699-417A-AE38-CE60D953680E}.Release|Any CPU.Build.0 = Release|Any CPU
42 | EndGlobalSection
43 | GlobalSection(SolutionProperties) = preSolution
44 | HideSolutionNode = FALSE
45 | EndGlobalSection
46 | EndGlobal
47 |
--------------------------------------------------------------------------------
/DHT/DHT.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {CF2D500F-1EBF-43EE-B8C4-4096DA5CFBA4}
8 | Library
9 | Properties
10 | DHT
11 | DHT
12 | v4.5.2
13 | 512
14 |
15 |
16 | true
17 | full
18 | false
19 | bin\Debug\
20 | DEBUG;TRACE
21 | prompt
22 | 4
23 |
24 |
25 | pdbonly
26 | true
27 | bin\Release\
28 | TRACE
29 | prompt
30 | 4
31 |
32 |
33 |
34 | ..\packages\Argument.Validator.1.0.2\lib\ArgumentValidator.dll
35 | True
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 | False
66 | ..\packages\Grpc.Core.1.0.1\lib\net45\Grpc.Core.dll
67 |
68 |
69 | {76baf981-f995-4cb9-b9d5-229a822bd8ff}
70 | DHT.ProtocolBuffers
71 |
72 |
73 |
74 |
75 |
76 |
77 |
84 |
--------------------------------------------------------------------------------
/DHT/Nodes/INodeStore.cs:
--------------------------------------------------------------------------------
1 | namespace DHT.Nodes
2 | {
3 | ///
4 | /// Interface for node storage
5 | ///
6 | public interface INodeStore
7 | {
8 | ///
9 | /// Does this store contain this key
10 | ///
11 | bool ContainsKey(string key);
12 |
13 | ///
14 | /// Gets a value (if there). Null if not.
15 | ///
16 | string GetValue(string key);
17 |
18 | ///
19 | /// Adds a key, value
20 | ///
21 | bool AddValue(string key, string value);
22 |
23 | ///
24 | /// Removes a key, value
25 | ///
26 | bool RemoveValue(string key);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/DHT/Nodes/NodeInfo.cs:
--------------------------------------------------------------------------------
1 | namespace DHT.Nodes
2 | {
3 | using System;
4 |
5 | ///
6 | /// Stores info about a node in the DHT network
7 | ///
8 | public class NodeInfo
9 | {
10 | ///
11 | /// 32 bit node id
12 | ///
13 | ///
14 | /// Being explicit about the 32 bit declaration
15 | /// since it's crucial to how routing will work between DHT nodes.
16 | ///
17 | public UInt32 NodeId { get; set; }
18 |
19 | ///
20 | /// Host name (or IP)
21 | ///
22 | public string HostName { get; set; }
23 |
24 | ///
25 | /// Port running on
26 | ///
27 | public int Port { get; set; }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/DHT/Nodes/NodeStore.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Concurrent;
3 | using System.Collections.Generic;
4 | using System.Data.Linq;
5 |
6 | namespace DHT.Nodes
7 | {
8 | public class NodeStore : INodeStore
9 | {
10 | private readonly IDictionary store;
11 |
12 | public NodeStore()
13 | {
14 | this.store = new ConcurrentDictionary();
15 | }
16 |
17 | public bool AddValue(string key, string value)
18 | {
19 | if (this.store.ContainsKey(key))
20 | {
21 | throw new DuplicateKeyException(key);
22 | }
23 |
24 | this.store.Add(key, value);
25 |
26 | // We should also return false if the store is full
27 | return true;
28 | }
29 |
30 | public bool ContainsKey(string key)
31 | {
32 | return this.store.ContainsKey(key);
33 | }
34 |
35 | public string GetValue(string key)
36 | {
37 | string value = null;
38 |
39 | this.store.TryGetValue(key, out value);
40 |
41 | return value;
42 | }
43 |
44 | public bool RemoveValue(string key)
45 | {
46 | return this.store.Remove(key);
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/DHT/NodesProtocol/INodeServerClientFactory.cs:
--------------------------------------------------------------------------------
1 | namespace DHT.NodesProtocol
2 | {
3 | using DHT.Nodes;
4 | using static Dhtproto.DhtProtoService;
5 |
6 | public interface INodeServerClientFactory
7 | {
8 | DhtProtoServiceClient CreateRemoteClient(NodeInfo nodeInfo);
9 |
10 | DhtProtoServiceClient CreateLocalClient();
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/DHT/NodesProtocol/LocalNodeServerClient.cs:
--------------------------------------------------------------------------------
1 | namespace DHT.NodesProtocol
2 | {
3 | using System.Data.Linq;
4 | using ArgumentValidator;
5 | using Dhtproto;
6 | using Grpc.Core;
7 | using Nodes;
8 |
9 | public class LocalNodeServerClient : DhtProtoService.DhtProtoServiceClient
10 | {
11 | private readonly INodeStore nodeStore;
12 |
13 | public LocalNodeServerClient(INodeStore nodeStore)
14 | {
15 | Throw.IfNull(nodeStore, nameof(nodeStore));
16 |
17 | this.nodeStore = nodeStore;
18 | }
19 |
20 | public LocalNodeServerClient()
21 | : this(new NodeStore())
22 | {
23 | }
24 |
25 | public override KeyValueMessage GetValue(KeyMessage request, CallOptions options)
26 | {
27 | if (!this.nodeStore.ContainsKey(request.Key))
28 | {
29 | ThrowRpcException(StatusCode.NotFound, "Key not found");
30 | }
31 |
32 | var value = this.nodeStore.GetValue(request.Key);
33 | var response = new KeyValueMessage()
34 | {
35 | Key = request.Key,
36 | Value = value
37 | };
38 |
39 | return response;
40 | }
41 |
42 | public override KeyMessage RemoveValue(KeyMessage request, CallOptions options)
43 | {
44 | var removed = this.nodeStore.RemoveValue(request.Key);
45 |
46 | if (!removed)
47 | {
48 | ThrowRpcException(StatusCode.NotFound, "Key not found, can't remove.");
49 | }
50 |
51 | var response = new KeyMessage()
52 | {
53 | Key = request.Key
54 | };
55 |
56 | return response;
57 | }
58 |
59 | public override KeyValueMessage StoreValue(KeyValueMessage request, CallOptions options)
60 | {
61 | try
62 | {
63 | var added = this.nodeStore.AddValue(request.Key, request.Value);
64 |
65 | if (!added)
66 | {
67 | ThrowRpcException(StatusCode.Internal, "Couldn't store value.");
68 | }
69 | }
70 | catch (DuplicateKeyException)
71 | {
72 | ThrowRpcException(StatusCode.AlreadyExists, "Duplicate key found.");
73 | }
74 |
75 | return request;
76 | }
77 |
78 | private void ThrowRpcException(StatusCode statusCode, string message)
79 | {
80 | var status = new Status(statusCode, message);
81 | throw new RpcException(status);
82 | }
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/DHT/NodesProtocol/NodeServer.cs:
--------------------------------------------------------------------------------
1 | namespace DHT.NodesProtocol
2 | {
3 | using System.Threading.Tasks;
4 | using ArgumentValidator;
5 | using Dhtproto;
6 | using Grpc.Core;
7 | using Nodes;
8 | using Routing;
9 | using static Dhtproto.DhtProtoService;
10 | using grpc = global::Grpc.Core;
11 |
12 | public class NodeServer : DhtProtoServiceBase
13 | {
14 | private readonly NodeInfo nodeInfo;
15 |
16 | private readonly IRoutingTable routingTable;
17 |
18 | private readonly INodeServerClientFactory clientFactory;
19 |
20 | private readonly DhtProtoServiceClient localClient;
21 |
22 | public NodeServer(NodeInfo nodeInfo, IRoutingTable routingTable, INodeServerClientFactory clientFactory)
23 | {
24 | Throw.IfNull(nodeInfo, nameof(nodeInfo));
25 | Throw.IfNull(routingTable, nameof(routingTable));
26 | Throw.IfNull(clientFactory, nameof(clientFactory));
27 |
28 | this.nodeInfo = nodeInfo;
29 | this.routingTable = routingTable;
30 | this.clientFactory = clientFactory;
31 | this.localClient = clientFactory.CreateLocalClient();
32 | }
33 |
34 | public override Task GetValue(KeyMessage request, ServerCallContext context)
35 | {
36 | var client = this.GetClient(request.Key);
37 | var response = client.GetValue(request);
38 |
39 | return Task.FromResult(response);
40 | }
41 |
42 | public override Task RemoveValue(KeyMessage request, ServerCallContext context)
43 | {
44 | var client = this.GetClient(request.Key);
45 | var response = client.RemoveValue(request);
46 |
47 | return Task.FromResult(response);
48 | }
49 |
50 | public override Task StoreValue(KeyValueMessage request, grpc.ServerCallContext context)
51 | {
52 | var client = this.GetClient(request.Key);
53 | var response = client.StoreValue(request);
54 |
55 | return Task.FromResult(response);
56 | }
57 |
58 | private DhtProtoServiceClient GetClient(string key)
59 | {
60 | // Find the node which should have this key
61 | var remoteNode = this.routingTable.FindNode(key);
62 |
63 | // Return true if it's the local node
64 | var isLocal = remoteNode.NodeId == this.nodeInfo.NodeId;
65 |
66 | if (isLocal)
67 | {
68 | return this.localClient;
69 | }
70 |
71 | return this.clientFactory.CreateRemoteClient(remoteNode);
72 | }
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/DHT/NodesProtocol/NodeServerClientFactory.cs:
--------------------------------------------------------------------------------
1 | namespace DHT.NodesProtocol
2 | {
3 | using System;
4 | using DHT.Nodes;
5 | using Dhtproto;
6 | using Grpc.Core;
7 |
8 | public class NodeServerClientFactory : INodeServerClientFactory
9 | {
10 | public DhtProtoService.DhtProtoServiceClient CreateLocalClient()
11 | {
12 | var client = new LocalNodeServerClient();
13 |
14 | return client;
15 | }
16 |
17 | public DhtProtoService.DhtProtoServiceClient CreateRemoteClient(NodeInfo nodeInfo)
18 | {
19 | var target = string.Format("{0}:{1}", nodeInfo.HostName, nodeInfo.Port);
20 | var channel = new Channel(target, ChannelCredentials.Insecure);
21 | var client = new DhtProtoService.DhtProtoServiceClient(channel);
22 |
23 | return client;
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/DHT/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("DHT")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("DHT")]
13 | [assembly: AssemblyCopyright("Copyright © 2017")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("cf2d500f-1ebf-43ee-b8c4-4096da5cfba4")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/DHT/Routing/IConsistentHashGenerator.cs:
--------------------------------------------------------------------------------
1 | namespace DHT.Routing
2 | {
3 | using System;
4 |
5 | public interface IConsistentHashGenerator
6 | {
7 | UInt32 Hash(string value);
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/DHT/Routing/IRoutingTable.cs:
--------------------------------------------------------------------------------
1 | namespace DHT.Routing
2 | {
3 | using System.Collections.Generic;
4 | using DHT.Nodes;
5 |
6 | ///
7 | /// Routing interface
8 | ///
9 | public interface IRoutingTable
10 | {
11 | ///
12 | /// List of node info in the network
13 | ///
14 | IList Nodes { get; set; }
15 |
16 | ///
17 | /// Find the node which should store this key
18 | ///
19 | NodeInfo FindNode(string key);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/DHT/Routing/RoutingTable.cs:
--------------------------------------------------------------------------------
1 | namespace DHT.Routing
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using ArgumentValidator;
7 | using DHT.Nodes;
8 | using Utils;
9 |
10 | ///
11 | /// Routing table implementation
12 | ///
13 | public class RoutingTable : IRoutingTable
14 | {
15 | private IList nodes;
16 |
17 | private readonly IConsistentHashGenerator hashGenerator;
18 |
19 | public RoutingTable(IConsistentHashGenerator hashGenerator)
20 | : this(hashGenerator, new List())
21 | {
22 | }
23 |
24 | public RoutingTable(IConsistentHashGenerator hashGenerator, IList nodes)
25 | {
26 | Throw.IfNull(nodes, nameof(nodes));
27 | Throw.IfNull(hashGenerator, nameof(hashGenerator));
28 |
29 | this.nodes = nodes;
30 | this.hashGenerator = hashGenerator;
31 | }
32 |
33 | private IList SortedNodes
34 | {
35 | get
36 | {
37 | return this.Nodes.OrderBy(node => node.NodeId).ToList();
38 | }
39 | }
40 |
41 | public IList Nodes
42 | {
43 | get
44 | {
45 | return this.nodes;
46 | }
47 | set
48 | {
49 | this.nodes = value;
50 | }
51 | }
52 |
53 | public NodeInfo FindNode(string key)
54 | {
55 | NodeInfo partitionNode;
56 |
57 | // Hash the key to get the "partition" key
58 | var partitionKey = this.hashGenerator.Hash(key);
59 |
60 | Logger.Log("RoutingTable - FindNode", "key = " + key);
61 | Logger.Log("RoutingTable - FindNode", "partitionKey = " + partitionKey);
62 |
63 | // Now find the last node which has an id smaller than the
64 | // partition key. We also make sure that the nodes are sorted,
65 | // this might be overkill but unless we have millions of nodes
66 | // it should be OK performance wise.
67 | partitionNode = this.SortedNodes.LastOrDefault(n => n.NodeId <= partitionKey);
68 |
69 | // If we haven't found any node, we'll give the load to the last node.
70 | // If the node ids aren't evenly distributed we could be in trouble
71 | // since the last node might get overloaded.
72 | if (partitionNode == null)
73 | {
74 | Logger.Log("RoutingTable - FindNode", "Didn't find node, reverting to last");
75 | partitionNode = this.SortedNodes.Last();
76 | }
77 |
78 | Logger.Log("RoutingTable - FindNode", "FoundNode = " + partitionNode.NodeId);
79 |
80 | return partitionNode;
81 | }
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/DHT/Routing/RoutingTableFactory.cs:
--------------------------------------------------------------------------------
1 | namespace DHT.Routing
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using System.IO;
6 | using Nodes;
7 |
8 | ///
9 | /// Factory for constructing the routing table
10 | ///
11 | public class RoutingTableFactory
12 | {
13 | public static IRoutingTable FromFile(string routingTablePath)
14 | {
15 | var lines = File.ReadAllLines(routingTablePath);
16 | var nodes = new List();
17 |
18 | foreach (var line in lines)
19 | {
20 | var tokens = line.Split(' ');
21 | var nodeId = UInt32.Parse(tokens[0]);
22 | var hostName = tokens[1];
23 | var port = int.Parse(tokens[2]);
24 |
25 | var nodeInfo = new NodeInfo()
26 | {
27 | NodeId = nodeId,
28 | HostName = hostName,
29 | Port = port
30 | };
31 |
32 | nodes.Add(nodeInfo);
33 | }
34 |
35 | var hashGenerator = new Sha256HashGenerator();
36 | var routingTable = new RoutingTable(hashGenerator, nodes);
37 |
38 | return routingTable;
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/DHT/Routing/Sha256HashGenerator.cs:
--------------------------------------------------------------------------------
1 | namespace DHT.Routing
2 | {
3 | using System;
4 | using System.IO;
5 | using System.Security.Cryptography;
6 | using System.Text;
7 | using ArgumentValidator;
8 |
9 | public class Sha256HashGenerator : IConsistentHashGenerator
10 | {
11 | private readonly SHA256 hasher;
12 |
13 | public Sha256HashGenerator()
14 | {
15 | this.hasher = SHA256.Create();
16 | }
17 |
18 | public UInt32 Hash(string value)
19 | {
20 | Throw.IfNullOrEmpty(value, nameof(value));
21 |
22 | using (var stream = this.GenerateStreamFromString(value))
23 | {
24 | var hashBytes = this.hasher.ComputeHash(stream);
25 | var hashInt = BitConverter.ToUInt32(hashBytes, 0);
26 |
27 | return hashInt;
28 | }
29 | }
30 |
31 | private MemoryStream GenerateStreamFromString(string value)
32 | {
33 | return new MemoryStream(Encoding.UTF8.GetBytes(value ?? ""));
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/DHT/Utils/Logger.cs:
--------------------------------------------------------------------------------
1 | namespace DHT.Utils
2 | {
3 | using System;
4 | using DHT.Nodes;
5 |
6 | public static class Logger
7 | {
8 | public static void Log(string method, string message)
9 | {
10 | Console.WriteLine("[{0}] {1} {2}",
11 | DateTime.UtcNow.ToString(),
12 | method,
13 | message);
14 | }
15 |
16 | public static void Log(NodeInfo nodeInfo, string method, string message)
17 | {
18 | Console.WriteLine("[{0}][{1}][{2}:{3}] {4}",
19 | DateTime.UtcNow.ToString(),
20 | nodeInfo.NodeId,
21 | nodeInfo.HostName,
22 | nodeInfo.Port,
23 | message);
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/DHT/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # dht-csharp
2 | DHT implementation of Kademlia in C#
3 |
--------------------------------------------------------------------------------
/routingTable.txt:
--------------------------------------------------------------------------------
1 | 90037898 localhost 11000
2 | 270845369 localhost 11001
3 |
--------------------------------------------------------------------------------