├── .gitattributes ├── .gitignore ├── DHTSpider.sln ├── README.md ├── SimpleClient ├── App.config ├── NLog.config ├── Program.cs ├── Properties │ └── AssemblyInfo.cs └── SimpleClient.csproj ├── Spider ├── Cache │ ├── DefaultCache.cs │ ├── ICache.cs │ └── RedisCache.cs ├── Core │ ├── DHTSpider.cs │ ├── EasyTokenManager.cs │ └── UdpSocketListener.cs ├── Helper │ └── RedisHelper.cs ├── Log │ └── Logger.cs ├── Properties │ └── AssemblyInfo.cs ├── Queue │ ├── DefaultQueue.cs │ ├── IQueue.cs │ └── RedisQueue.cs ├── Spider.csproj ├── SpiderConfiguration.cs ├── SpiderSetting.cs ├── Store │ ├── ElasticSearchStore.cs │ ├── IStore.cs │ └── MongoDBStore.cs └── packages.config ├── Tancoder.Torrent ├── BigInteger.cs ├── ClassDiagram.cd ├── EventArgs │ ├── NodeAddedEventArgs.cs │ ├── NodeFoundEventArgs.cs │ └── StateUpdateEventArgs.cs ├── Exceptions │ ├── ChangeLog │ ├── ConnectionException.cs │ ├── ListenerException.cs │ ├── MessageException.cs │ ├── ProtocolException.cs │ └── TorrentLoadException.cs ├── FindPeersResult.cs ├── GetPeersResult.cs ├── IDhtEngine.cs ├── IMetaDataFilter.cs ├── ISpider.cs ├── InfoHash.cs ├── Listeners │ ├── DhtListener.cs │ ├── Listener.cs │ ├── UdpListener.cs │ └── WireListener.cs ├── MessageException.cs ├── MessageFactory.cs ├── Messages │ ├── DhtMessage.cs │ ├── Errors │ │ └── ErrorMessage.cs │ ├── Queries │ │ ├── AnnouncePeer.cs │ │ ├── FindNode.cs │ │ ├── GetPeers.cs │ │ ├── Ping.cs │ │ └── QueryMessage.cs │ ├── Responses │ │ ├── AnnouncePeerResponse.cs │ │ ├── FindNodeResponse.cs │ │ ├── GetPeersResponse.cs │ │ ├── PingResponse.cs │ │ └── ResponseMessage.cs │ ├── Wire │ │ ├── ExtData.cs │ │ ├── ExtHandShack.cs │ │ ├── ExtQueryPiece.cs │ │ ├── ExtendMessage.cs │ │ └── HandShack.cs │ └── WireMessage.cs ├── Metadata.cs ├── MonoTorrent.BEncoding │ ├── BEncodedDictionary.cs │ ├── BEncodedList.cs │ ├── BEncodedNumber.cs │ ├── BEncodedString.cs │ ├── BEncodingException.cs │ ├── ChangeLog │ ├── IBEncodedValue.cs │ └── RawReader.cs ├── NoTraceMessage.cs ├── Nodes │ ├── ITokenManager.cs │ ├── Node.cs │ ├── NodeId.cs │ └── NodeState.cs ├── Properties │ └── AssemblyInfo.cs ├── Source │ ├── Check.cs │ ├── Enums.cs │ ├── IMessage.cs │ ├── Message.cs │ ├── ToolBox.cs │ ├── TorrentException.cs │ ├── UriHelper.cs │ └── VersionInfo.cs ├── Tancoder.Torrent.csproj ├── TransactionId.cs └── packages.config └── demo.png /.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 | [Xx]64/ 19 | [Xx]86/ 20 | [Bb]uild/ 21 | bld/ 22 | [Bb]in/ 23 | [Oo]bj/ 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 | 85 | # Visual Studio profiler 86 | *.psess 87 | *.vsp 88 | *.vspx 89 | *.sap 90 | 91 | # TFS 2012 Local Workspace 92 | $tf/ 93 | 94 | # Guidance Automation Toolkit 95 | *.gpState 96 | 97 | # ReSharper is a .NET coding add-in 98 | _ReSharper*/ 99 | *.[Rr]e[Ss]harper 100 | *.DotSettings.user 101 | 102 | # JustCode is a .NET coding add-in 103 | .JustCode 104 | 105 | # TeamCity is a build add-in 106 | _TeamCity* 107 | 108 | # DotCover is a Code Coverage Tool 109 | *.dotCover 110 | 111 | # NCrunch 112 | _NCrunch_* 113 | .*crunch*.local.xml 114 | nCrunchTemp_* 115 | 116 | # MightyMoose 117 | *.mm.* 118 | AutoTest.Net/ 119 | 120 | # Web workbench (sass) 121 | .sass-cache/ 122 | 123 | # Installshield output folder 124 | [Ee]xpress/ 125 | 126 | # DocProject is a documentation generator add-in 127 | DocProject/buildhelp/ 128 | DocProject/Help/*.HxT 129 | DocProject/Help/*.HxC 130 | DocProject/Help/*.hhc 131 | DocProject/Help/*.hhk 132 | DocProject/Help/*.hhp 133 | DocProject/Help/Html2 134 | DocProject/Help/html 135 | 136 | # Click-Once directory 137 | publish/ 138 | 139 | # Publish Web Output 140 | *.[Pp]ublish.xml 141 | *.azurePubxml 142 | 143 | # TODO: Un-comment the next line if you do not want to checkin 144 | # your web deploy settings because they may include unencrypted 145 | # passwords 146 | #*.pubxml 147 | *.publishproj 148 | 149 | # NuGet Packages 150 | *.nupkg 151 | # The packages folder can be ignored because of Package Restore 152 | **/packages/* 153 | # except build/, which is used as an MSBuild target. 154 | !**/packages/build/ 155 | # Uncomment if necessary however generally it will be regenerated when needed 156 | #!**/packages/repositories.config 157 | # NuGet v3's project.json files produces more ignoreable files 158 | *.nuget.props 159 | *.nuget.targets 160 | 161 | # Microsoft Azure Build Output 162 | csx/ 163 | *.build.csdef 164 | 165 | # Microsoft Azure Emulator 166 | ecf/ 167 | rcf/ 168 | 169 | # Microsoft Azure ApplicationInsights config file 170 | ApplicationInsights.config 171 | 172 | # Windows Store app package directory 173 | AppPackages/ 174 | BundleArtifacts/ 175 | 176 | # Visual Studio cache files 177 | # files ending in .cache can be ignored 178 | *.[Cc]ache 179 | # but keep track of directories ending in .cache 180 | !*.[Cc]ache/ 181 | 182 | # Others 183 | ClientBin/ 184 | [Ss]tyle[Cc]op.* 185 | ~$* 186 | *~ 187 | *.dbmdl 188 | *.dbproj.schemaview 189 | *.pfx 190 | *.publishsettings 191 | node_modules/ 192 | orleans.codegen.cs 193 | 194 | # RIA/Silverlight projects 195 | Generated_Code/ 196 | 197 | # Backup & report files from converting an old project file 198 | # to a newer Visual Studio version. Backup files are not needed, 199 | # because we have git ;-) 200 | _UpgradeReport_Files/ 201 | Backup*/ 202 | UpgradeLog*.XML 203 | UpgradeLog*.htm 204 | 205 | # SQL Server files 206 | *.mdf 207 | *.ldf 208 | 209 | # Business Intelligence projects 210 | *.rdl.data 211 | *.bim.layout 212 | *.bim_*.settings 213 | 214 | # Microsoft Fakes 215 | FakesAssemblies/ 216 | 217 | # GhostDoc plugin setting file 218 | *.GhostDoc.xml 219 | 220 | # Node.js Tools for Visual Studio 221 | .ntvs_analysis.dat 222 | 223 | # Visual Studio 6 build log 224 | *.plg 225 | 226 | # Visual Studio 6 workspace options file 227 | *.opt 228 | 229 | # Visual Studio LightSwitch build output 230 | **/*.HTMLClient/GeneratedArtifacts 231 | **/*.DesktopClient/GeneratedArtifacts 232 | **/*.DesktopClient/ModelManifest.xml 233 | **/*.Server/GeneratedArtifacts 234 | **/*.Server/ModelManifest.xml 235 | _Pvt_Extensions 236 | 237 | # LightSwitch generated files 238 | GeneratedArtifacts/ 239 | ModelManifest.xml 240 | 241 | # Paket dependency manager 242 | .paket/paket.exe 243 | 244 | # FAKE - F# Make 245 | .fake/ -------------------------------------------------------------------------------- /DHTSpider.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26430.14 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tancoder.Torrent", "Tancoder.Torrent\Tancoder.Torrent.csproj", "{B3FDEA8E-20F3-4BE3-B73A-505B45BA9501}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Spider", "Spider\Spider.csproj", "{E0279EF8-1F47-4CB2-983E-736C375D73C5}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SimpleClient", "SimpleClient\SimpleClient.csproj", "{F2A5753C-3AF2-40F2-9BB8-FD4B3A528ECB}" 11 | EndProject 12 | Global 13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 14 | Debug|Any CPU = Debug|Any CPU 15 | Release|Any CPU = Release|Any CPU 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {B3FDEA8E-20F3-4BE3-B73A-505B45BA9501}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 19 | {B3FDEA8E-20F3-4BE3-B73A-505B45BA9501}.Debug|Any CPU.Build.0 = Debug|Any CPU 20 | {B3FDEA8E-20F3-4BE3-B73A-505B45BA9501}.Release|Any CPU.ActiveCfg = Release|Any CPU 21 | {B3FDEA8E-20F3-4BE3-B73A-505B45BA9501}.Release|Any CPU.Build.0 = Release|Any CPU 22 | {E0279EF8-1F47-4CB2-983E-736C375D73C5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 23 | {E0279EF8-1F47-4CB2-983E-736C375D73C5}.Debug|Any CPU.Build.0 = Debug|Any CPU 24 | {E0279EF8-1F47-4CB2-983E-736C375D73C5}.Release|Any CPU.ActiveCfg = Release|Any CPU 25 | {E0279EF8-1F47-4CB2-983E-736C375D73C5}.Release|Any CPU.Build.0 = Release|Any CPU 26 | {F2A5753C-3AF2-40F2-9BB8-FD4B3A528ECB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 27 | {F2A5753C-3AF2-40F2-9BB8-FD4B3A528ECB}.Debug|Any CPU.Build.0 = Debug|Any CPU 28 | {F2A5753C-3AF2-40F2-9BB8-FD4B3A528ECB}.Release|Any CPU.ActiveCfg = Release|Any CPU 29 | {F2A5753C-3AF2-40F2-9BB8-FD4B3A528ECB}.Release|Any CPU.Build.0 = Release|Any CPU 30 | EndGlobalSection 31 | GlobalSection(SolutionProperties) = preSolution 32 | HideSolutionNode = FALSE 33 | EndGlobalSection 34 | EndGlobal 35 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DHTSpider 2 | >A Very Simple Spider With DHT Crawler, Written by C#. 3 | 4 | * The bittorrent library bases on MonoTorrent. 5 | 6 | ### 介绍 7 | 8 | DHTSpider 是一个由C#编写的 DHT 爬虫, 从全球` DHT ` 网络里"`嗅探`"正在下载的资源, 并把资源`metadata`(种子信息)进行抓取下载. 9 | 10 | 11 | ### 相关 12 | 13 | >Cache 14 | 15 | + 使用 `Memory` > UseDefaultCache ( 默认 ) 16 | + 使用 `Redis` > UseRedisCache ( TODO ) 17 | 18 | >Queue 19 | 20 | + 使用 `Memory` > UseDefaultQueue ( 默认 ) 21 | + 使用 `Redis` > UseRedisQueue ( TODO ) 22 | 23 | >Store 24 | 25 | + 使用 `MongoDB` > UseMongoDBStore ( TODO ) 26 | + 使用 `ElasticSearch` > UseElasticSearchStore ( TODO ) 27 | 28 | >Log > `NLog` 29 | 30 | >Ioc > `Autofac` 31 | 32 | ### 环境 33 | 34 | 1. `.net` 版本 `>=4.5.2` 35 | 36 | 2. 运行的机器需要`独立IP` , 内网机器需要做下`端口映射` 37 | 38 | 39 | ### 使用 40 | 41 | ```c# 42 | 43 | var spider = SpiderConfiguration.Create() //使用默认配置 44 | .UseDefaultCache() //默认使用内存缓存 45 | .UseDefaultQueue() //默认使用内存队列 46 | .Start(); 47 | 48 | ``` 49 | 50 | ### 配置 51 | 52 | ```c# 53 | 54 | var spider = SpiderConfiguration.Create(new SpiderSetting() 55 | { 56 | LocalPort = 6881, //使用端口 57 | IsSaveTorrent = true, //是否保存torrent 58 | TorrentSavePath = "", //torrent保存路径 59 | MaxSpiderThreadCount = 1, //爬虫线程数 60 | MaxDownLoadThreadCount = 20 //下载线程数 61 | }) 62 | .UseRedisCache() //使用redis缓存 63 | .UseRedisQueue() //使用redis队列 64 | .UseMongoDBStore() //使用mongodb存储 65 | .Start(); 66 | 67 | ``` 68 | 69 | 70 | #### demo 71 | ![demo](https://user-images.githubusercontent.com/9568475/44514542-fc4cfb00-a6f2-11e8-8260-6a82242e1aba.png) 72 | 73 | -------------------------------------------------------------------------------- /SimpleClient/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /SimpleClient/NLog.config: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 12 | 13 | 14 | 18 | 19 | 20 | 25 | 26 | 31 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 51 | 52 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /SimpleClient/Program.cs: -------------------------------------------------------------------------------- 1 | using Spider; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace SimpleClient 9 | { 10 | class Program 11 | { 12 | static void Main(string[] args) 13 | { 14 | SpiderConfiguration.Create(new SpiderSetting() 15 | { 16 | LocalPort = 6881,//使用端口 17 | IsSaveTorrent = true,//是否保存torrent 18 | TorrentSavePath = "",//torrent保存路径 19 | MaxSpiderThreadCount = 1,//爬虫线程数 20 | MaxDownLoadThreadCount = 5//下载线程数 21 | }) 22 | .UseDefaultCache() //默认使用内存缓存 23 | .UseDefaultQueue() //默认使用内存队列 24 | .Start(); 25 | 26 | 27 | Console.ReadKey(); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /SimpleClient/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // 有关程序集的一般信息由以下 6 | // 控制。更改这些特性值可修改 7 | // 与程序集关联的信息。 8 | [assembly: AssemblyTitle("SimpleClient")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("Microsoft")] 12 | [assembly: AssemblyProduct("SimpleClient")] 13 | [assembly: AssemblyCopyright("Copyright © Microsoft 2017")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // 将 ComVisible 设置为 false 会使此程序集中的类型 18 | //对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型 19 | //请将此类型的 ComVisible 特性设置为 true。 20 | [assembly: ComVisible(false)] 21 | 22 | // 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID 23 | [assembly: Guid("f2a5753c-3af2-40f2-9bb8-fd4b3a528ecb")] 24 | 25 | // 程序集的版本信息由下列四个值组成: 26 | // 27 | // 主版本 28 | // 次版本 29 | // 生成号 30 | // 修订号 31 | // 32 | // 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号 33 | // 方法是按如下所示使用“*”: : 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /SimpleClient/SimpleClient.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {F2A5753C-3AF2-40F2-9BB8-FD4B3A528ECB} 8 | Exe 9 | SimpleClient 10 | SimpleClient 11 | v4.5.2 12 | 512 13 | true 14 | 15 | 16 | AnyCPU 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | AnyCPU 27 | pdbonly 28 | true 29 | bin\Release\ 30 | TRACE 31 | prompt 32 | 4 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | Always 52 | 53 | 54 | 55 | 56 | {e0279ef8-1f47-4cb2-983e-736c375d73c5} 57 | Spider 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /Spider/Cache/DefaultCache.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Concurrent; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Runtime.Caching; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace Spider.Cache 10 | { 11 | public class DefaultCache : ICache 12 | { 13 | public ConcurrentDictionary _cache = null; 14 | public DefaultCache() 15 | { 16 | _cache = new ConcurrentDictionary(); 17 | } 18 | 19 | public object Get(string key) 20 | { 21 | return MemoryCache.Default.Get(key); 22 | //object val = null; 23 | //_cache.TryGetValue(key, out val); 24 | //return val; 25 | } 26 | 27 | public void Set(string key, object val) 28 | { 29 | MemoryCache.Default.Set(key, val, new CacheItemPolicy()); 30 | //_cache.TryAdd(key, val); 31 | } 32 | 33 | public bool ContainsKey(string key) 34 | { 35 | return MemoryCache.Default.Contains(key); 36 | //return _cache.ContainsKey(key); 37 | } 38 | 39 | public int Count() 40 | { 41 | return MemoryCache.Default.Count(); 42 | //return _cache.Count; 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Spider/Cache/ICache.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Spider.Cache 8 | { 9 | public interface ICache 10 | { 11 | bool ContainsKey(string key); 12 | 13 | object Get(string key); 14 | 15 | void Set(string key, object val); 16 | 17 | int Count(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Spider/Cache/RedisCache.cs: -------------------------------------------------------------------------------- 1 | using Spider.Helper; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Spider.Cache 9 | { 10 | public class RedisCache : ICache 11 | { 12 | //TODO 13 | public RedisCache() 14 | { 15 | } 16 | 17 | public bool ContainsKey(string key) 18 | { 19 | throw new NotImplementedException(); 20 | } 21 | 22 | public int Count() 23 | { 24 | throw new NotImplementedException(); 25 | } 26 | 27 | public object Get(string key) 28 | { 29 | throw new NotImplementedException(); 30 | } 31 | 32 | public void Set(string key, object val) 33 | { 34 | throw new NotImplementedException(); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Spider/Core/EasyTokenManager.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using Tancoder.Torrent.BEncoding; 6 | using Tancoder.Torrent.Dht; 7 | 8 | namespace Spider.Core 9 | { 10 | public class EasyTokenManager : ITokenManager 11 | { 12 | public TimeSpan Timeout { get; set; } 13 | private readonly int tokenLength = 10; 14 | 15 | public BEncodedString GenerateToken(Node node) 16 | { 17 | BEncodedString token = getToken(node); 18 | return token; 19 | } 20 | 21 | private BEncodedString getToken(Node node) 22 | { 23 | byte[] buffer = new byte[tokenLength]; 24 | Array.Copy(node.Id.Bytes, buffer, tokenLength); 25 | var token = new BEncodedString(buffer); 26 | return token; 27 | } 28 | 29 | public bool VerifyToken(Node node, BEncodedString token) 30 | { 31 | return getToken(node).Equals(token); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Spider/Core/UdpSocketListener.cs: -------------------------------------------------------------------------------- 1 | using Spider.Log; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Net; 6 | using System.Net.Sockets; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | 10 | namespace Spider.Core 11 | { 12 | public delegate void MessageReceived(byte[] buffer, IPEndPoint endpoint); 13 | 14 | public class UdpSocketListener 15 | { 16 | private IPEndPoint endpoint; 17 | public IPEndPoint Endpoint 18 | { 19 | get { return endpoint; } 20 | } 21 | 22 | private Socket m_ListenSocket; 23 | 24 | private SocketAsyncEventArgs m_ReceiveSAE; 25 | 26 | public UdpSocketListener(IPEndPoint endpoint) 27 | { 28 | this.endpoint = endpoint; 29 | } 30 | 31 | public void Start() 32 | { 33 | try 34 | { 35 | m_ListenSocket = new Socket(this.endpoint.AddressFamily, SocketType.Dgram, ProtocolType.Udp); 36 | m_ListenSocket.Ttl = 255; 37 | m_ListenSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); 38 | m_ListenSocket.Bind(this.endpoint); 39 | 40 | //Mono 不支持 41 | //if (Platform.SupportSocketIOControlByCodeEnum) 42 | { 43 | uint IOC_IN = 0x80000000; 44 | uint IOC_VENDOR = 0x18000000; 45 | uint SIO_UDP_CONNRESET = IOC_IN | IOC_VENDOR | 12; 46 | 47 | byte[] optionInValue = { Convert.ToByte(false) }; 48 | byte[] optionOutValue = new byte[4]; 49 | m_ListenSocket.IOControl((int)SIO_UDP_CONNRESET, optionInValue, optionOutValue); 50 | } 51 | 52 | var eventArgs = new SocketAsyncEventArgs(); 53 | m_ReceiveSAE = eventArgs; 54 | 55 | eventArgs.Completed += new EventHandler(eventArgs_Completed); 56 | eventArgs.RemoteEndPoint = new IPEndPoint(IPAddress.Any, 0); 57 | 58 | int receiveBufferSize = 2048; 59 | var buffer = new byte[receiveBufferSize]; 60 | eventArgs.SetBuffer(buffer, 0, buffer.Length); 61 | 62 | m_ListenSocket.ReceiveFromAsync(eventArgs); 63 | } 64 | catch (Exception ex) 65 | { 66 | OnError(ex); 67 | 68 | } 69 | } 70 | public event MessageReceived MessageReceived; 71 | private void eventArgs_Completed(object sender, SocketAsyncEventArgs e) 72 | { 73 | if (e.SocketError != SocketError.Success) 74 | { 75 | var errorCode = (int)e.SocketError; 76 | 77 | //The listen socket was closed 78 | //if (errorCode == 995 || errorCode == 10004 || errorCode == 10038) 79 | //return; 80 | //Logger.Fatal($"The listen socket was closed errorCode:{errorCode}"); 81 | Logger.Fatal($"errorCode:{errorCode}"); 82 | } 83 | 84 | if (e.LastOperation == SocketAsyncOperation.ReceiveFrom) 85 | { 86 | try 87 | { 88 | //获取接收到的数据 89 | byte[] ByteArray = new byte[e.BytesTransferred]; 90 | Array.Copy(e.Buffer, 0, ByteArray, 0, ByteArray.Length); 91 | MessageReceived?.Invoke(ByteArray, (IPEndPoint)e.RemoteEndPoint); 92 | } 93 | catch (Exception exc) 94 | { 95 | OnError(exc); 96 | } 97 | 98 | try 99 | { 100 | m_ListenSocket.ReceiveFromAsync(e); 101 | } 102 | catch (Exception exc) 103 | { 104 | OnError(exc); 105 | } 106 | } 107 | } 108 | 109 | 110 | private void OnError(Exception ex) 111 | { 112 | Logger.Fatal(ex.Message + ex.StackTrace); 113 | //throw ex; 114 | } 115 | 116 | public void Stop() 117 | { 118 | if (m_ListenSocket == null) 119 | return; 120 | 121 | lock (this) 122 | { 123 | if (m_ListenSocket == null) 124 | return; 125 | 126 | m_ReceiveSAE.Completed -= new EventHandler(eventArgs_Completed); 127 | m_ReceiveSAE.Dispose(); 128 | m_ReceiveSAE = null; 129 | 130 | //if (!Platform.IsMono) 131 | { 132 | try 133 | { 134 | m_ListenSocket.Shutdown(SocketShutdown.Both); 135 | } 136 | catch { } 137 | } 138 | 139 | try 140 | { 141 | m_ListenSocket.Close(); 142 | } 143 | catch { } 144 | finally 145 | { 146 | m_ListenSocket = null; 147 | } 148 | } 149 | 150 | } 151 | 152 | 153 | public void Send(byte[] buffer, IPEndPoint endpoint) 154 | { 155 | try 156 | { 157 | if (endpoint.Address != IPAddress.Any) 158 | { 159 | var len = m_ListenSocket.SendTo(buffer, endpoint); 160 | //Logger.Warn($"Send :{len} {buffer.Length} {endpoint}"); 161 | } 162 | else 163 | { 164 | Logger.Fatal($"Send Not Work {endpoint.ToString()}"); 165 | } 166 | } 167 | catch (Exception ex) 168 | { 169 | OnError(ex); 170 | } 171 | } 172 | 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /Spider/Log/Logger.cs: -------------------------------------------------------------------------------- 1 | using NLog; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | 7 | namespace Spider.Log 8 | { 9 | public class Logger 10 | { 11 | private static ILogger logger = LogManager.GetCurrentClassLogger(); 12 | 13 | public static void Error(string msg) 14 | { 15 | logger.Error(msg); 16 | } 17 | 18 | public static void Info(string msg) 19 | { 20 | logger.Info(msg); 21 | } 22 | 23 | public static void Fatal(string msg) 24 | { 25 | logger.Fatal(msg); 26 | } 27 | 28 | public static void Debug(string msg) 29 | { 30 | logger.Debug(msg); 31 | } 32 | 33 | public static void Trace(string msg) 34 | { 35 | logger.Trace(msg); 36 | } 37 | 38 | public static void Warn(string msg) 39 | { 40 | logger.Warn(msg); 41 | } 42 | 43 | 44 | 45 | public static void ConsoleWrite(string msg, ConsoleColor consoleColor = ConsoleColor.Green) 46 | { 47 | Console.ForegroundColor = consoleColor; 48 | Console.WriteLine("------------------------------------------------------"); 49 | Console.WriteLine($"[{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}]{msg}"); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Spider/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // 有关程序集的一般信息由以下 6 | // 控制。更改这些特性值可修改 7 | // 与程序集关联的信息。 8 | [assembly: AssemblyTitle("Spider")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("Microsoft")] 12 | [assembly: AssemblyProduct("Spider")] 13 | [assembly: AssemblyCopyright("Copyright © Microsoft 2017")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // 将 ComVisible 设置为 false 会使此程序集中的类型 18 | //对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型 19 | //请将此类型的 ComVisible 特性设置为 true。 20 | [assembly: ComVisible(false)] 21 | 22 | // 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID 23 | [assembly: Guid("e0279ef8-1f47-4cb2-983e-736c375d73c5")] 24 | 25 | // 程序集的版本信息由下列四个值组成: 26 | // 27 | // 主版本 28 | // 次版本 29 | // 生成号 30 | // 修订号 31 | // 32 | // 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号 33 | //通过使用 "*",如下所示: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Spider/Queue/DefaultQueue.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Concurrent; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Net; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | using Tancoder.Torrent; 9 | 10 | namespace Spider.Queue 11 | { 12 | public class DefaultQueue : IQueue 13 | { 14 | public ConcurrentQueue> _queue = null; 15 | public DefaultQueue() 16 | { 17 | _queue = new ConcurrentQueue>(); 18 | } 19 | 20 | public KeyValuePair Dequeue() 21 | { 22 | var item = new KeyValuePair(); 23 | _queue.TryDequeue(out item); 24 | return item; 25 | } 26 | 27 | public void Enqueue(KeyValuePair item) 28 | { 29 | _queue.Enqueue(item); 30 | } 31 | 32 | public int Count() 33 | { 34 | return _queue.Count; 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Spider/Queue/IQueue.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Net; 5 | using System.Text; 6 | using Tancoder.Torrent; 7 | 8 | namespace Spider.Queue 9 | { 10 | public interface IQueue 11 | { 12 | void Enqueue(KeyValuePair item); 13 | 14 | KeyValuePair Dequeue(); 15 | 16 | int Count(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Spider/Queue/RedisQueue.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Net; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using Tancoder.Torrent; 8 | 9 | namespace Spider.Queue 10 | { 11 | public class RedisQueue : IQueue 12 | { 13 | //TODO 14 | public RedisQueue() 15 | { 16 | } 17 | public KeyValuePair Dequeue() 18 | { 19 | throw new NotImplementedException(); 20 | } 21 | 22 | public void Enqueue(KeyValuePair item) 23 | { 24 | throw new NotImplementedException(); 25 | } 26 | 27 | public int Count() 28 | { 29 | return 0; 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Spider/Spider.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {E0279EF8-1F47-4CB2-983E-736C375D73C5} 8 | Library 9 | Properties 10 | Spider 11 | Spider 12 | v4.5.2 13 | 512 14 | 15 | 16 | 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | false 25 | 26 | 27 | pdbonly 28 | true 29 | bin\Release\ 30 | TRACE 31 | prompt 32 | 4 33 | false 34 | 35 | 36 | 37 | ..\packages\Autofac.4.6.0\lib\net45\Autofac.dll 38 | 39 | 40 | ..\packages\NLog.4.4.11\lib\net45\NLog.dll 41 | 42 | 43 | ..\packages\StackExchange.Redis.1.2.4\lib\net45\StackExchange.Redis.dll 44 | 45 | 46 | 47 | 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 | 74 | 75 | 76 | 77 | {b3fdea8e-20f3-4be3-b73a-505b45ba9501} 78 | Tancoder.Torrent 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /Spider/SpiderConfiguration.cs: -------------------------------------------------------------------------------- 1 | using Autofac; 2 | using Spider.Cache; 3 | using Spider.Core; 4 | using Spider.Log; 5 | using Spider.Queue; 6 | using Spider.Store; 7 | using System; 8 | using System.Collections.Generic; 9 | using System.IO; 10 | using System.Linq; 11 | using System.Net; 12 | using System.Text; 13 | using System.Threading; 14 | using System.Threading.Tasks; 15 | using Tancoder.Torrent; 16 | using Tancoder.Torrent.BEncoding; 17 | using Tancoder.Torrent.Client; 18 | 19 | namespace Spider 20 | { 21 | public class SpiderConfiguration 22 | { 23 | private readonly ContainerBuilder _builder; 24 | private IContainer _container; 25 | 26 | private static readonly object obj = new object(); 27 | private static SpiderConfiguration _instance = null; 28 | 29 | public SpiderSetting _option { get; set; } 30 | public ICache _cache { get; set; } 31 | public IQueue _queue { get; set; } 32 | public IStore _store { get; set; } 33 | 34 | private SpiderConfiguration(SpiderSetting option) 35 | { 36 | _option = option; 37 | _builder = new ContainerBuilder(); 38 | 39 | if (_option.IsSaveTorrent) 40 | { 41 | if (string.IsNullOrEmpty(_option.TorrentSavePath) || !Directory.Exists(_option.TorrentSavePath)) 42 | { 43 | _option.TorrentSavePath = Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, "torrent"); 44 | Directory.CreateDirectory(_option.TorrentSavePath); 45 | } 46 | } 47 | } 48 | 49 | public static SpiderConfiguration Create(SpiderSetting option = null) 50 | { 51 | if (_instance == null) 52 | { 53 | lock (obj) 54 | { 55 | if (_instance == null) 56 | { 57 | _instance = new SpiderConfiguration(option ?? new SpiderSetting()); 58 | } 59 | } 60 | } 61 | return _instance; 62 | } 63 | 64 | public SpiderConfiguration UseDefaultCache() 65 | { 66 | _builder.RegisterType().As().Named("Cache").SingleInstance(); 67 | return _instance; 68 | } 69 | 70 | public SpiderConfiguration UseRedisCache() 71 | { 72 | _builder.RegisterType().As().Named("Cache").SingleInstance(); 73 | return _instance; 74 | } 75 | 76 | public SpiderConfiguration UseDefaultQueue() 77 | { 78 | _builder.RegisterType().As().Named("Queue").SingleInstance(); 79 | return _instance; 80 | } 81 | 82 | public SpiderConfiguration UseRedisQueue() 83 | { 84 | _builder.RegisterType().As().Named("Queue").SingleInstance(); 85 | return _instance; 86 | } 87 | 88 | public SpiderConfiguration UseElasticSearchStore() 89 | { 90 | _builder.RegisterType().As().Named("Store").SingleInstance(); 91 | return _instance; 92 | } 93 | 94 | public SpiderConfiguration UseMongoDBStore() 95 | { 96 | _builder.RegisterType().As().Named("Store").SingleInstance(); 97 | return _instance; 98 | } 99 | 100 | public void Stop() 101 | { 102 | //TODO 103 | } 104 | 105 | public SpiderConfiguration Start() 106 | { 107 | _container = _builder.Build(); 108 | if (!_container.IsRegisteredWithName("Cache")) 109 | { 110 | throw new Exception("没有注册Cache"); 111 | } 112 | if (!_container.IsRegisteredWithName("Queue")) 113 | { 114 | throw new Exception("没有注册Queue"); 115 | } 116 | //if (!_container.IsRegisteredWithName("Store")) 117 | //{ 118 | // throw new Exception("没有注册Store"); 119 | //} 120 | 121 | _queue = _container.ResolveNamed("Queue"); 122 | _cache = _container.ResolveNamed("Cache"); 123 | //_store = _container.ResolveNamed("Store"); 124 | 125 | 126 | for (var i = 0; i < _option.MaxSpiderThreadCount; i++) 127 | { 128 | var port = _option.LocalPort + i; 129 | Logger.ConsoleWrite($"线程:{i + 1} 端口:{port} 已启动监听..."); 130 | Task.Run(() => 131 | { 132 | var spider = new DHTSpider(new IPEndPoint(IPAddress.Parse("0.0.0.0"), port), _queue); 133 | spider.NewMetadata += DHTSpider_NewMetadata; 134 | spider.Start(); 135 | }); 136 | Thread.Sleep(1000); 137 | } 138 | 139 | for (var i = 0; i < _option.MaxDownLoadThreadCount; i++) 140 | { 141 | var id = i + 1; 142 | Logger.ConsoleWrite($"线程[{id}]开始下载"); 143 | Task.Run(() => 144 | { 145 | Download(id); 146 | }); 147 | Thread.Sleep(100); 148 | } 149 | 150 | 151 | return _instance; 152 | } 153 | 154 | 155 | 156 | private void DHTSpider_NewMetadata(object sender, NewMetadataEventArgs e) 157 | { 158 | var hash = e.Metadata.ToString(); 159 | lock (obj) 160 | { 161 | if (!_cache.ContainsKey(hash)) 162 | { 163 | _cache.Set(hash, e.Owner); 164 | _queue.Enqueue(new KeyValuePair(e.Metadata, e.Owner)); 165 | Logger.ConsoleWrite($"NewMetadata Hash:{e.Metadata} Address:{e.Owner.ToString()}"); 166 | } 167 | } 168 | 169 | } 170 | 171 | private void Download(int threadId) 172 | { 173 | while (true) 174 | { 175 | try 176 | { 177 | var info = new KeyValuePair(); 178 | lock (this) 179 | { 180 | info = _queue.Dequeue(); 181 | } 182 | if (info.Key == null || info.Value == null) 183 | { 184 | Thread.Sleep(1000); 185 | continue; 186 | } 187 | var hash = BitConverter.ToString(info.Key.Hash).Replace("-", ""); 188 | using (WireClient client = new WireClient(info.Value)) 189 | { 190 | var metadata = client.GetMetaData(info.Key); 191 | if (metadata != null) 192 | { 193 | var name = ((BEncodedString)metadata["name"]).Text; 194 | if (_option.IsSaveTorrent) 195 | { 196 | var filepath = $"{_option.TorrentSavePath}\\{hash}.torrent"; 197 | File.WriteAllBytes(filepath, metadata.Encode()); 198 | } 199 | Logger.ConsoleWrite($"线程[{threadId}]下载完成 Name:{name} ", ConsoleColor.Yellow); 200 | } 201 | 202 | } 203 | 204 | } 205 | catch (Exception ex) 206 | { 207 | //Logger.Error($"Download {ex.Message}"); 208 | } 209 | finally 210 | { 211 | Thread.Sleep(1000); 212 | } 213 | } 214 | } 215 | } 216 | } 217 | -------------------------------------------------------------------------------- /Spider/SpiderSetting.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Spider 9 | { 10 | public class SpiderSetting 11 | { 12 | public int LocalPort { get; set; } 13 | 14 | public bool IsSaveTorrent { get; set; } 15 | 16 | public string TorrentSavePath { get; set; } 17 | 18 | public int MaxDownLoadThreadCount { get; set; } 19 | 20 | public int MaxSpiderThreadCount { get; set; } 21 | 22 | public SpiderSetting(int localPort = 6881, bool isSaveTorrent = false, string torrentSavePath = "", int maxDownLoadThreadCount = 10, int maxSpiderThreadCount = 1) 23 | { 24 | LocalPort = localPort; 25 | IsSaveTorrent = isSaveTorrent; 26 | TorrentSavePath = torrentSavePath; 27 | MaxDownLoadThreadCount = maxDownLoadThreadCount; 28 | MaxSpiderThreadCount = maxSpiderThreadCount; 29 | } 30 | 31 | 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Spider/Store/ElasticSearchStore.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Spider.Store 8 | { 9 | public class ElasticSearchStore : IStore 10 | { 11 | //TODO 12 | public bool Insert(object obj) 13 | { 14 | throw new NotImplementedException(); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Spider/Store/IStore.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace Spider.Store 7 | { 8 | public interface IStore 9 | { 10 | bool Insert(object obj); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Spider/Store/MongoDBStore.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Spider.Store 8 | { 9 | public class MongoDBStore : IStore 10 | { 11 | //TODO 12 | public bool Insert(object obj) 13 | { 14 | throw new NotImplementedException(); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Spider/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Tancoder.Torrent/ClassDiagram.cd: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAA= 7 | ISpider.cs 8 | 9 | 10 | 11 | 12 | 13 | AAAAAAAAAAAAAAAAAAAAAgQAAAAAAAAAAAAAAAAAAAA= 14 | Metadata.cs 15 | 16 | 17 | 18 | 19 | 20 | AAAAAAAAAAAAAAAAACAAAAAAABCAAAAAAAAAAAAAAAA= 21 | ISpider.cs 22 | 23 | 24 | 25 | 26 | 27 | AAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= 28 | IMetaDataFilter.cs 29 | 30 | 31 | 32 | 33 | 34 | AAAAAAAAAAAAAAAAAAAAAAAQAAAAAgAAAAAAAAAAAAA= 35 | ISpider.cs 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /Tancoder.Torrent/EventArgs/NodeAddedEventArgs.cs: -------------------------------------------------------------------------------- 1 | #if !DISABLE_DHT 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | 6 | namespace Tancoder.Torrent.Dht 7 | { 8 | public class NodeAddedEventArgs : EventArgs 9 | { 10 | private Node node; 11 | 12 | public Node Node 13 | { 14 | get { return node; } 15 | } 16 | 17 | public NodeAddedEventArgs(Node node) 18 | { 19 | this.node = node; 20 | } 21 | } 22 | } 23 | #endif -------------------------------------------------------------------------------- /Tancoder.Torrent/EventArgs/NodeFoundEventArgs.cs: -------------------------------------------------------------------------------- 1 | #if !DISABLE_DHT 2 | // NodeFound.cs.cs 3 | // 4 | // Authors: 5 | // Olivier Dufour 6 | // 7 | // Copyright (C) 2008 Olivier Dufour 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining 10 | // a copy of this software and associated documentation files (the 11 | // "Software"), to deal in the Software without restriction, including 12 | // without limitation the rights to use, copy, modify, merge, publish, 13 | // distribute, sublicense, and/or sell copies of the Software, and to 14 | // permit persons to whom the Software is furnished to do so, subject to 15 | // the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be 18 | // included in all copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 24 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 25 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 26 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 27 | // 28 | // 29 | 30 | using System; 31 | using System.IO; 32 | using System.Security.Cryptography; 33 | using System.Collections.Generic; 34 | 35 | using Tancoder.Torrent.BEncoding; 36 | 37 | namespace Tancoder.Torrent.Dht 38 | { 39 | public class NodeFoundEventArgs : EventArgs 40 | { 41 | private Node node; 42 | 43 | public NodeFoundEventArgs(Node node) 44 | { 45 | this.node = node; 46 | } 47 | 48 | public Node Node 49 | { 50 | get { return node; } 51 | } 52 | } 53 | } 54 | #endif -------------------------------------------------------------------------------- /Tancoder.Torrent/EventArgs/StateUpdateEventArgs.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text; 3 | 4 | namespace Tancoder.Torrent.Client 5 | { 6 | public class StatsUpdateEventArgs : EventArgs 7 | { 8 | public StatsUpdateEventArgs() 9 | { 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Tancoder.Torrent/Exceptions/ChangeLog: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhangkong828/DHTSpider/49f0055c78ed718bcda77e0466f25c277af9577a/Tancoder.Torrent/Exceptions/ChangeLog -------------------------------------------------------------------------------- /Tancoder.Torrent/Exceptions/ConnectionException.cs: -------------------------------------------------------------------------------- 1 | // 2 | // ConnectionException.cs 3 | // 4 | // Authors: 5 | // Alan McGovern alan.mcgovern@gmail.com 6 | // 7 | // Copyright (C) 2006 Alan McGovern 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining 10 | // a copy of this software and associated documentation files (the 11 | // "Software"), to deal in the Software without restriction, including 12 | // without limitation the rights to use, copy, modify, merge, publish, 13 | // distribute, sublicense, and/or sell copies of the Software, and to 14 | // permit persons to whom the Software is furnished to do so, subject to 15 | // the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be 18 | // included in all copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 24 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 25 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 26 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 27 | // 28 | 29 | 30 | using System; 31 | using System.Text; 32 | using Tancoder.Torrent.Common; 33 | 34 | namespace Tancoder.Torrent.Client 35 | { 36 | /// 37 | /// 38 | /// 39 | public class ConnectionException : TorrentException 40 | { 41 | /// 42 | /// 43 | /// 44 | public ConnectionException() 45 | : base() 46 | { 47 | } 48 | 49 | 50 | /// 51 | /// 52 | /// 53 | /// 54 | public ConnectionException(string message) 55 | : base(message) 56 | { 57 | } 58 | 59 | 60 | /// 61 | /// 62 | /// 63 | /// 64 | /// 65 | public ConnectionException(string message, Exception innerException) 66 | : base(message, innerException) 67 | { 68 | } 69 | 70 | 71 | /// 72 | /// 73 | /// 74 | /// 75 | /// 76 | public ConnectionException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) 77 | : base(info, context) 78 | { 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /Tancoder.Torrent/Exceptions/ListenerException.cs: -------------------------------------------------------------------------------- 1 | // 2 | // ListenerException.cs 3 | // 4 | // Authors: 5 | // Alan McGovern alan.mcgovern@gmail.com 6 | // 7 | // Copyright (C) 2006 Alan McGovern 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining 10 | // a copy of this software and associated documentation files (the 11 | // "Software"), to deal in the Software without restriction, including 12 | // without limitation the rights to use, copy, modify, merge, publish, 13 | // distribute, sublicense, and/or sell copies of the Software, and to 14 | // permit persons to whom the Software is furnished to do so, subject to 15 | // the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be 18 | // included in all copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 24 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 25 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 26 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 27 | // 28 | 29 | 30 | using System; 31 | using System.Text; 32 | using Tancoder.Torrent.Common; 33 | 34 | namespace Tancoder.Torrent.Client 35 | { 36 | /// 37 | /// 38 | /// 39 | public class ListenerException : TorrentException 40 | { 41 | /// 42 | /// 43 | /// 44 | public ListenerException() 45 | : base() 46 | { 47 | } 48 | 49 | 50 | /// 51 | /// 52 | /// 53 | /// 54 | public ListenerException(string message) 55 | : base(message) 56 | { 57 | } 58 | 59 | 60 | /// 61 | /// 62 | /// 63 | /// 64 | /// 65 | public ListenerException(string message, Exception innerException) 66 | : base(message, innerException) 67 | { 68 | } 69 | 70 | 71 | /// 72 | /// 73 | /// 74 | /// 75 | /// 76 | public ListenerException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) 77 | : base(info, context) 78 | { 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /Tancoder.Torrent/Exceptions/MessageException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text; 3 | using Tancoder.Torrent.Common; 4 | 5 | namespace Tancoder.Torrent.Client 6 | { 7 | public class MessageException : TorrentException 8 | { 9 | public MessageException() 10 | : base() 11 | { 12 | } 13 | 14 | 15 | public MessageException(string message) 16 | : base(message) 17 | { 18 | } 19 | 20 | 21 | public MessageException(string message, Exception innerException) 22 | : base(message, innerException) 23 | { 24 | } 25 | 26 | 27 | public MessageException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) 28 | : base(info, context) 29 | { 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Tancoder.Torrent/Exceptions/ProtocolException.cs: -------------------------------------------------------------------------------- 1 | // 2 | // ProtocolException.cs 3 | // 4 | // Authors: 5 | // Alan McGovern alan.mcgovern@gmail.com 6 | // 7 | // Copyright (C) 2006 Alan McGovern 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining 10 | // a copy of this software and associated documentation files (the 11 | // "Software"), to deal in the Software without restriction, including 12 | // without limitation the rights to use, copy, modify, merge, publish, 13 | // distribute, sublicense, and/or sell copies of the Software, and to 14 | // permit persons to whom the Software is furnished to do so, subject to 15 | // the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be 18 | // included in all copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 24 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 25 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 26 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 27 | // 28 | 29 | 30 | using System; 31 | using System.Text; 32 | using Tancoder.Torrent.Common; 33 | 34 | namespace Tancoder.Torrent.Client 35 | { 36 | public class ProtocolException : TorrentException 37 | { 38 | public ProtocolException() 39 | :base() 40 | { 41 | } 42 | 43 | 44 | public ProtocolException(string message) 45 | : base(message) 46 | { 47 | } 48 | 49 | 50 | public ProtocolException(string message, Exception innerException) 51 | : base(message, innerException) 52 | { 53 | } 54 | 55 | 56 | public ProtocolException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) 57 | : base(info, context) 58 | { 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /Tancoder.Torrent/Exceptions/TorrentLoadException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text; 3 | using Tancoder.Torrent.Common; 4 | 5 | namespace Tancoder.Torrent.Client 6 | { 7 | public class TorrentLoadException : TorrentException 8 | { 9 | 10 | public TorrentLoadException() 11 | : base() 12 | { 13 | } 14 | 15 | 16 | public TorrentLoadException(string message) 17 | : base(message) 18 | { 19 | } 20 | 21 | 22 | public TorrentLoadException(string message, Exception innerException) 23 | : base(message, innerException) 24 | { 25 | } 26 | 27 | 28 | public TorrentLoadException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) 29 | : base(info, context) 30 | { 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /Tancoder.Torrent/FindPeersResult.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Tancoder.Torrent.Dht; 3 | 4 | namespace Tancoder.Torrent 5 | { 6 | public class FindPeersResult 7 | { 8 | public bool Found { get; set; } 9 | public IList Nodes { get; set; } 10 | } 11 | } -------------------------------------------------------------------------------- /Tancoder.Torrent/GetPeersResult.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Tancoder.Torrent.BEncoding; 3 | using Tancoder.Torrent.Dht; 4 | 5 | namespace Tancoder.Torrent 6 | { 7 | public class GetPeersResult 8 | { 9 | public bool HasHash { get; set; } 10 | public IList Values { get; set; } 11 | public IList Nodes { get; set; } 12 | } 13 | } -------------------------------------------------------------------------------- /Tancoder.Torrent/IDhtEngine.cs: -------------------------------------------------------------------------------- 1 | // 2 | // IDhtEngine.cs 3 | // 4 | // Authors: 5 | // Alan McGovern alan.mcgovern@gmail.com 6 | // 7 | // Copyright (C) 2009 Alan McGovern 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining 10 | // a copy of this software and associated documentation files (the 11 | // "Software"), to deal in the Software without restriction, including 12 | // without limitation the rights to use, copy, modify, merge, publish, 13 | // distribute, sublicense, and/or sell copies of the Software, and to 14 | // permit persons to whom the Software is furnished to do so, subject to 15 | // the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be 18 | // included in all copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 24 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 25 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 26 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 27 | // 28 | 29 | 30 | using System; 31 | using System.Collections.Generic; 32 | using System.Net; 33 | using Tancoder.Torrent.BEncoding; 34 | using Tancoder.Torrent.Dht; 35 | using Tancoder.Torrent.Dht.Messages; 36 | 37 | namespace Tancoder.Torrent 38 | { 39 | public enum ErrorCode : int 40 | { 41 | GenericError = 201, 42 | ServerError = 202, 43 | ProtocolError = 203,// malformed packet, invalid arguments, or bad token 44 | MethodUnknown = 204//Method Unknown 45 | } 46 | public interface IDhtEngine : IDisposable 47 | { 48 | //event EventHandler StateChanged; 49 | 50 | bool Disposed { get; } 51 | NodeId LocalId { get; } 52 | //DhtState State { get; } 53 | ITokenManager TokenManager { get; } 54 | 55 | void Add(BEncodedList nodes); 56 | void Add(IEnumerable enumerable); 57 | void Add(Node node); 58 | 59 | //void Announce(InfoHash infohash, int port); 60 | void GetAnnounced(InfoHash infohash, IPEndPoint endpoint); 61 | void GetPeers(InfoHash infohash); 62 | 63 | GetPeersResult QueryGetPeers(NodeId infohash); 64 | FindPeersResult QueryFindNode(NodeId target); 65 | 66 | //byte[] SaveNodes(); 67 | void Send(DhtMessage msg, IPEndPoint endpoint); 68 | 69 | void Start(); 70 | NodeId GetNeighborId(NodeId target); 71 | void Stop(); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /Tancoder.Torrent/IMetaDataFilter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace Tancoder.Torrent 7 | { 8 | public interface IMetaDataFilter 9 | { 10 | bool Ignore(InfoHash metadata); 11 | } 12 | } -------------------------------------------------------------------------------- /Tancoder.Torrent/ISpider.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Net; 5 | using System.Text; 6 | using Tancoder.Torrent.Dht; 7 | 8 | namespace Tancoder.Torrent 9 | { 10 | public interface ISpider 11 | { 12 | event NewMetadataEvent NewMetadata; 13 | IMetaDataFilter Filter { get; set; } 14 | 15 | KeyValuePair Pop(); 16 | } 17 | 18 | public class NewMetadataEventArgs : EventArgs 19 | { 20 | public InfoHash Metadata { get; private set; } 21 | public IPEndPoint Owner { get; private set; } 22 | 23 | public NewMetadataEventArgs(InfoHash metadata, IPEndPoint endpoint) 24 | { 25 | Metadata = metadata; 26 | Owner = endpoint; 27 | } 28 | } 29 | 30 | public delegate void NewMetadataEvent(object sender, NewMetadataEventArgs e); 31 | } -------------------------------------------------------------------------------- /Tancoder.Torrent/InfoHash.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using Tancoder.Torrent.Common; 5 | using System.Web; 6 | 7 | namespace Tancoder.Torrent 8 | { 9 | public class InfoHash : IEquatable 10 | { 11 | static Dictionary base32DecodeTable; 12 | 13 | static InfoHash() 14 | { 15 | base32DecodeTable = new Dictionary(); 16 | string table = "abcdefghijklmnopqrstuvwxyz234567"; 17 | for (int i = 0; i < table.Length; i++) 18 | base32DecodeTable[table[i]] = (byte)i; 19 | } 20 | 21 | byte[] hash; 22 | 23 | public byte[] Hash 24 | { 25 | get { return hash; } 26 | } 27 | 28 | public InfoHash(byte[] infoHash) 29 | { 30 | Check.InfoHash(infoHash); 31 | if (infoHash.Length != 20) 32 | throw new ArgumentException("Infohash must be exactly 20 bytes long"); 33 | hash = (byte[])infoHash.Clone(); 34 | } 35 | 36 | public override bool Equals(object obj) 37 | { 38 | return Equals(obj as InfoHash); 39 | } 40 | 41 | public bool Equals(byte[] other) 42 | { 43 | return other == null || other.Length != 20 ? false : Toolbox.ByteMatch(Hash, other); 44 | } 45 | 46 | public bool Equals(InfoHash other) 47 | { 48 | return this == other; 49 | } 50 | 51 | public override int GetHashCode() 52 | { 53 | // Equality is based generally on checking 20 positions, checking 4 should be enough 54 | // for the hashcode as infohashes are randomly distributed. 55 | return Hash[0] | (Hash[1] << 8) | (Hash[2] << 16) | (Hash[3] << 24); 56 | } 57 | 58 | public byte[] ToArray() 59 | { 60 | return (byte[])hash.Clone(); 61 | } 62 | 63 | public string ToHex() 64 | { 65 | StringBuilder sb = new StringBuilder(40); 66 | for (int i = 0; i < hash.Length; i++) 67 | { 68 | string hex = hash[i].ToString("X"); 69 | if (hex.Length != 2) 70 | sb.Append("0"); 71 | sb.Append(hex); 72 | } 73 | return sb.ToString(); 74 | } 75 | 76 | public override string ToString() 77 | { 78 | return BitConverter.ToString(hash); 79 | } 80 | 81 | public string UrlEncode() 82 | { 83 | return UriHelper.UrlEncode(Hash); 84 | } 85 | 86 | public static bool operator ==(InfoHash left, InfoHash right) 87 | { 88 | if ((object)left == null) 89 | return (object)right == null; 90 | if ((object)right == null) 91 | return false; 92 | return Toolbox.ByteMatch(left.Hash, right.Hash); 93 | } 94 | 95 | public static bool operator !=(InfoHash left, InfoHash right) 96 | { 97 | return !(left == right); 98 | } 99 | 100 | public static InfoHash FromBase32(string infoHash) 101 | { 102 | Check.InfoHash (infoHash); 103 | if (infoHash.Length != 32) 104 | throw new ArgumentException("Infohash must be a base32 encoded 32 character string"); 105 | 106 | infoHash = infoHash.ToLower(); 107 | int infohashOffset =0 ; 108 | byte[] hash = new byte[20]; 109 | var temp = new byte[8]; 110 | for (int i = 0; i < hash.Length; ) { 111 | for (int j=0; j < 8; j++) 112 | if (!base32DecodeTable.TryGetValue(infoHash[infohashOffset++], out temp[j])) 113 | throw new ArgumentException ("infoHash", "Value is not a valid base32 encoded string"); 114 | 115 | //8 * 5bits = 40 bits = 5 bytes 116 | hash[i++] = (byte)((temp[0] << 3) | (temp [1]>> 2)); 117 | hash[i++] = (byte)((temp[1] << 6) | (temp[2] << 1) | (temp[3] >> 4)); 118 | hash[i++] = (byte)((temp[3] << 4) | (temp [4]>> 1)); 119 | hash[i++] = (byte)((temp[4] << 7) | (temp[5] << 2) | (temp [6]>> 3)); 120 | hash[i++] = (byte)((temp[6] << 5) | temp[7]); 121 | } 122 | 123 | return new InfoHash(hash); 124 | } 125 | 126 | public static InfoHash FromHex(string infoHash) 127 | { 128 | Check.InfoHash (infoHash); 129 | if (infoHash.Length != 40) 130 | throw new ArgumentException("Infohash must be 40 characters long"); 131 | 132 | byte[] hash = new byte[20]; 133 | for (int i = 0; i < hash.Length; i++) 134 | hash[i] = byte.Parse(infoHash.Substring(i * 2, 2), System.Globalization.NumberStyles.HexNumber); 135 | 136 | return new InfoHash(hash); 137 | } 138 | 139 | public static InfoHash FromMagnetLink(string magnetLink) 140 | { 141 | Check.MagnetLink(magnetLink); 142 | if (!magnetLink.StartsWith("magnet:?")) 143 | throw new ArgumentException("Invalid magnet link format"); 144 | magnetLink = magnetLink.Substring("magnet:?".Length); 145 | int hashStart = magnetLink.IndexOf("xt=urn:btih:"); 146 | if (hashStart == -1) 147 | throw new ArgumentException("Magnet link does not contain an infohash"); 148 | hashStart += "xt=urn:btih:".Length; 149 | 150 | int hashEnd = magnetLink.IndexOf('&', hashStart); 151 | if (hashEnd == -1) 152 | hashEnd = magnetLink.Length; 153 | 154 | switch (hashEnd - hashStart) 155 | { 156 | case 32: 157 | return FromBase32(magnetLink.Substring(hashStart, 32)); 158 | case 40: 159 | return FromHex(magnetLink.Substring(hashStart, 40)); 160 | default: 161 | throw new ArgumentException("Infohash must be base32 or hex encoded."); 162 | } 163 | } 164 | 165 | public static InfoHash UrlDecode(string infoHash) 166 | { 167 | Check.InfoHash(infoHash); 168 | return new InfoHash(UriHelper.UrlDecode(infoHash)); 169 | } 170 | } 171 | } 172 | -------------------------------------------------------------------------------- /Tancoder.Torrent/Listeners/DhtListener.cs: -------------------------------------------------------------------------------- 1 | #if !DISABLE_DHT 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | using Tancoder.Torrent.Client; 6 | using System.Net; 7 | using Tancoder.Torrent.Common; 8 | 9 | namespace Tancoder.Torrent.Dht.Listeners 10 | { 11 | public delegate void MessageReceived(byte[] buffer, IPEndPoint endpoint); 12 | 13 | public class DhtListener : UdpListener 14 | { 15 | public event MessageReceived MessageReceived; 16 | 17 | public DhtListener(IPEndPoint endpoint) 18 | : base(endpoint) 19 | { 20 | 21 | } 22 | 23 | protected override void OnMessageReceived(byte[] buffer, IPEndPoint endpoint) 24 | { 25 | MessageReceived?.Invoke(buffer, endpoint); 26 | } 27 | } 28 | } 29 | #endif -------------------------------------------------------------------------------- /Tancoder.Torrent/Listeners/Listener.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Listener.cs 3 | // 4 | // Authors: 5 | // Alan McGovern alan.mcgovern@gmail.com 6 | // 7 | // Copyright (C) 2008 Alan McGovern 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining 10 | // a copy of this software and associated documentation files (the 11 | // "Software"), to deal in the Software without restriction, including 12 | // without limitation the rights to use, copy, modify, merge, publish, 13 | // distribute, sublicense, and/or sell copies of the Software, and to 14 | // permit persons to whom the Software is furnished to do so, subject to 15 | // the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be 18 | // included in all copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 24 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 25 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 26 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 27 | // 28 | 29 | using System; 30 | using System.Collections.Generic; 31 | using System.Text; 32 | using System.Net.Sockets; 33 | using System.Net; 34 | using Tancoder.Torrent.Common; 35 | 36 | namespace Tancoder.Torrent.Client 37 | { 38 | public abstract class Listener 39 | { 40 | public event EventHandler StatusChanged; 41 | 42 | private IPEndPoint endpoint; 43 | private ListenerStatus status; 44 | 45 | public IPEndPoint Endpoint 46 | { 47 | get { return endpoint; } 48 | } 49 | 50 | public ListenerStatus Status 51 | { 52 | get { return status; } 53 | } 54 | 55 | 56 | protected Listener(IPEndPoint endpoint) 57 | { 58 | this.status = ListenerStatus.NotListening; 59 | this.endpoint = endpoint; 60 | } 61 | 62 | public void ChangeEndpoint(IPEndPoint endpoint) 63 | { 64 | this.endpoint = endpoint; 65 | if (Status == ListenerStatus.Listening) 66 | { 67 | Stop(); 68 | Start(); 69 | } 70 | } 71 | 72 | protected virtual void RaiseStatusChanged(ListenerStatus status) 73 | { 74 | this.status = status; 75 | if (StatusChanged != null) 76 | Toolbox.RaiseAsyncEvent(StatusChanged, this, EventArgs.Empty); 77 | } 78 | 79 | public abstract void Start(); 80 | 81 | public abstract void Stop(); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /Tancoder.Torrent/Listeners/UdpListener.cs: -------------------------------------------------------------------------------- 1 | #if !DISABLE_DHT 2 | // 3 | // UdpListener.cs 4 | // 5 | // Authors: 6 | // Alan McGovern 7 | // 8 | // Copyright (C) 2008 Alan McGovern 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining 11 | // a copy of this software and associated documentation files (the 12 | // "Software"), to deal in the Software without restriction, including 13 | // without limitation the rights to use, copy, modify, merge, publish, 14 | // distribute, sublicense, and/or sell copies of the Software, and to 15 | // permit persons to whom the Software is furnished to do so, subject to 16 | // the following conditions: 17 | // 18 | // The above copyright notice and this permission notice shall be 19 | // included in all copies or substantial portions of the Software. 20 | // 21 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 22 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 23 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 24 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 25 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 26 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 27 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 28 | // 29 | 30 | 31 | using System; 32 | using System.Collections.Generic; 33 | using System.Text; 34 | using System.Net.Sockets; 35 | using System.Net; 36 | using Tancoder.Torrent.BEncoding; 37 | using Tancoder.Torrent.Client; 38 | using Tancoder.Torrent.Common; 39 | using System.Diagnostics; 40 | 41 | namespace Tancoder.Torrent 42 | { 43 | public abstract class UdpListener : Listener 44 | { 45 | 46 | private UdpClient client; 47 | 48 | protected UdpListener(IPEndPoint endpoint) 49 | : base(endpoint) 50 | { 51 | 52 | } 53 | 54 | private void EndReceive(IAsyncResult result) 55 | { 56 | try 57 | { 58 | IPEndPoint e = new IPEndPoint(IPAddress.Any, Endpoint.Port); 59 | byte[] buffer = client.EndReceive(result, ref e); 60 | 61 | OnMessageReceived(buffer, e); 62 | client.BeginReceive(EndReceive, null); 63 | } 64 | //catch (ObjectDisposedException ex) 65 | //{ 66 | // // Ignore, we're finished! 67 | // throw new Exception($"UdpListener ObjectDisposedException: {ex}"); 68 | //} 69 | catch (SocketException ex) 70 | { 71 | // If the destination computer closes the connection 72 | // we get error code 10054. We need to keep receiving on 73 | // the socket until we clear all the error states 74 | //if (ex.ErrorCode == 10054) 75 | //{ 76 | // while (true) 77 | // { 78 | // try 79 | // { 80 | // client.BeginReceive(EndReceive, null); 81 | // return; 82 | // } 83 | // //catch (ObjectDisposedException oe) 84 | // //{ 85 | // // throw new Exception($"UdpListener ObjectDisposedException: {oe}"); 86 | // //} 87 | // catch (SocketException e) 88 | // { 89 | // throw new Exception($"UdpListener SocketException: {e}"); 90 | // //if (e.ErrorCode != 10054) 91 | // // return; 92 | // } 93 | // } 94 | //} 95 | ////else if (ex.ErrorCode == 10052) 96 | ////{ 97 | 98 | ////} 99 | //else 100 | //{ 101 | // throw new Exception($"UdpListener SocketException: {ex}"); 102 | //} 103 | client.BeginReceive(EndReceive, null); 104 | } 105 | catch (Exception ex) 106 | { 107 | throw new Exception($"UdpListener SocketException: {ex}"); 108 | } 109 | } 110 | 111 | protected abstract void OnMessageReceived(byte[] buffer, IPEndPoint endpoint); 112 | 113 | public virtual void Send(byte[] buffer, IPEndPoint endpoint) 114 | { 115 | try 116 | { 117 | if (endpoint.Address != IPAddress.Any) 118 | client.Send(buffer, buffer.Length, endpoint); 119 | } 120 | catch (Exception ex) 121 | { 122 | throw new Exception($"UdpListener could not send message: {ex}"); 123 | } 124 | } 125 | 126 | public override void Start() 127 | { 128 | try 129 | { 130 | client = new UdpClient(Endpoint); 131 | { 132 | const uint IOC_IN = 0x80000000; 133 | int IOC_VENDOR = 0x18000000; 134 | int SIO_UDP_CONNRESET = (int)(IOC_IN | IOC_VENDOR | 12); 135 | client.Client.IOControl((int)SIO_UDP_CONNRESET, new byte[] { Convert.ToByte(false) }, new byte[4]); 136 | } 137 | client.BeginReceive(EndReceive, null); 138 | RaiseStatusChanged(ListenerStatus.Listening); 139 | } 140 | catch (SocketException) 141 | { 142 | RaiseStatusChanged(ListenerStatus.PortNotFree); 143 | } 144 | catch (ObjectDisposedException) 145 | { 146 | // Do Nothing 147 | } 148 | } 149 | 150 | public override void Stop() 151 | { 152 | try 153 | { 154 | client.Close(); 155 | } 156 | catch 157 | { 158 | // FIXME: Not needed 159 | } 160 | } 161 | } 162 | } 163 | #endif -------------------------------------------------------------------------------- /Tancoder.Torrent/MessageException.cs: -------------------------------------------------------------------------------- 1 | #if !DISABLE_DHT 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | 6 | namespace Tancoder.Torrent.Dht 7 | { 8 | public class MessageException : Exception 9 | { 10 | private ErrorCode errorCode; 11 | 12 | public ErrorCode ErrorCode 13 | { 14 | get { return errorCode; } 15 | } 16 | 17 | public MessageException(ErrorCode errorCode, string message) : base(message) 18 | { 19 | this.errorCode = errorCode; 20 | } 21 | } 22 | } 23 | #endif -------------------------------------------------------------------------------- /Tancoder.Torrent/MessageFactory.cs: -------------------------------------------------------------------------------- 1 | #if !DISABLE_DHT 2 | // 3 | // MessageFactory.cs 4 | // 5 | // Authors: 6 | // Alan McGovern 7 | // 8 | // Copyright (C) 2008 Alan McGovern 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining 11 | // a copy of this software and associated documentation files (the 12 | // "Software"), to deal in the Software without restriction, including 13 | // without limitation the rights to use, copy, modify, merge, publish, 14 | // distribute, sublicense, and/or sell copies of the Software, and to 15 | // permit persons to whom the Software is furnished to do so, subject to 16 | // the following conditions: 17 | // 18 | // The above copyright notice and this permission notice shall be 19 | // included in all copies or substantial portions of the Software. 20 | // 21 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 22 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 23 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 24 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 25 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 26 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 27 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 28 | // 29 | 30 | 31 | using System; 32 | using System.Collections.Generic; 33 | using System.Text; 34 | 35 | using Tancoder.Torrent.BEncoding; 36 | 37 | namespace Tancoder.Torrent.Dht.Messages 38 | { 39 | public delegate DhtMessage Creator(BEncodedDictionary dictionary); 40 | public delegate DhtMessage ResponseCreator(BEncodedDictionary dictionary, QueryMessage message); 41 | 42 | public static class MessageFactory 43 | { 44 | private static readonly string QueryNameKey = "q"; 45 | private static BEncodedString MessageTypeKey = "y"; 46 | private static BEncodedString TransactionIdKey = "t"; 47 | 48 | public static int RegisteredMessages 49 | { 50 | get { return messages.Count; } 51 | } 52 | 53 | static MessageFactory() 54 | { 55 | queryDecoders.Add("announce_peer", delegate(BEncodedDictionary d) { return new AnnouncePeer(d); }); 56 | queryDecoders.Add("find_node", delegate(BEncodedDictionary d) { return new FindNode(d); }); 57 | queryDecoders.Add("get_peers", delegate(BEncodedDictionary d) { return new GetPeers(d); }); 58 | queryDecoders.Add("ping", delegate(BEncodedDictionary d) { return new Ping(d); }); 59 | } 60 | 61 | private static Dictionary messages = new Dictionary(); 62 | private static Dictionary queryDecoders = new Dictionary(); 63 | 64 | public static bool IsRegistered(BEncodedValue transactionId) 65 | { 66 | lock (messages) 67 | { 68 | return messages.ContainsKey(transactionId); 69 | } 70 | } 71 | 72 | public static void RegisterSend(QueryMessage message) 73 | { 74 | lock(messages) 75 | { 76 | messages.Add(message.TransactionId, message); 77 | } 78 | } 79 | 80 | public static bool UnregisterSend(QueryMessage message) 81 | { 82 | lock (messages) 83 | { 84 | return messages.Remove(message.TransactionId); 85 | } 86 | } 87 | 88 | public static DhtMessage DecodeMessage(BEncodedDictionary dictionary) 89 | { 90 | DhtMessage message; 91 | string error; 92 | 93 | if (!TryDecodeMessage(dictionary, out message, out error)) 94 | throw new MessageException(ErrorCode.GenericError, error); 95 | 96 | return message; 97 | } 98 | 99 | public static bool TryDecodeMessage(BEncodedDictionary dictionary, out DhtMessage message) 100 | { 101 | string error; 102 | return TryDecodeMessage(dictionary, out message, out error); 103 | } 104 | 105 | public static bool TryDecodeMessage(BEncodedDictionary dictionary, out DhtMessage message, out string error) 106 | { 107 | message = null; 108 | error = null; 109 | 110 | if (dictionary[MessageTypeKey].Equals(QueryMessage.QueryType)) 111 | { 112 | if (!queryDecoders.ContainsKey((BEncodedString)dictionary[QueryNameKey])) 113 | { 114 | error = ((BEncodedString)dictionary[QueryNameKey]).Text; 115 | return false; 116 | } 117 | message = queryDecoders[(BEncodedString)dictionary[QueryNameKey]](dictionary); 118 | } 119 | else if (dictionary[MessageTypeKey].Equals(ErrorMessage.ErrorType)) 120 | { 121 | message = new ErrorMessage(dictionary); 122 | } 123 | else 124 | { 125 | QueryMessage query; 126 | BEncodedString key = (BEncodedString)dictionary[TransactionIdKey]; 127 | if (messages.TryGetValue(key, out query)) 128 | { 129 | messages.Remove(key); 130 | try 131 | { 132 | message = query.ResponseCreator(dictionary, query); 133 | } 134 | catch 135 | { 136 | error = "Response dictionary was invalid"; 137 | } 138 | } 139 | else 140 | { 141 | error = "Response had bad transaction ID"; 142 | } 143 | } 144 | 145 | return error == null && message != null; 146 | } 147 | public static bool TryNoTraceDecodeMessage(BEncodedDictionary dictionary, out DhtMessage message, out string error) 148 | { 149 | message = null; 150 | error = null; 151 | 152 | if (dictionary[MessageTypeKey].Equals(QueryMessage.QueryType)) 153 | { 154 | if (!queryDecoders.ContainsKey((BEncodedString)dictionary[QueryNameKey])) 155 | { 156 | error = ((BEncodedString)dictionary[QueryNameKey]).Text; 157 | return false; 158 | } 159 | message = queryDecoders[(BEncodedString)dictionary[QueryNameKey]](dictionary); 160 | } 161 | else if (dictionary[MessageTypeKey].Equals(ErrorMessage.ErrorType)) 162 | { 163 | message = new ErrorMessage(dictionary); 164 | } 165 | else 166 | { 167 | QueryMessage query = new NoTraceMessage(); 168 | BEncodedString key = (BEncodedString)dictionary[TransactionIdKey]; 169 | try 170 | { 171 | message = query.ResponseCreator(dictionary, query); 172 | 173 | //BEncodedValue q; 174 | //if (message == null && dictionary.TryGetValue("q", out q)) 175 | //{ 176 | // error = q.ToString(); 177 | //} 178 | if (message == null && dictionary.ContainsKey("q")) 179 | { 180 | dictionary[MessageTypeKey] = QueryMessage.QueryType; 181 | TryNoTraceDecodeMessage(dictionary, out message, out error); 182 | } 183 | } 184 | catch(Exception ex) 185 | { 186 | error = ex.ToString(); 187 | } 188 | } 189 | 190 | return error == null && message != null; 191 | } 192 | public static bool TryNoTraceDecodeMessage(BEncodedDictionary dictionary, out DhtMessage message) 193 | { 194 | string error; 195 | return TryNoTraceDecodeMessage(dictionary, out message, out error); 196 | } 197 | } 198 | } 199 | #endif -------------------------------------------------------------------------------- /Tancoder.Torrent/Messages/DhtMessage.cs: -------------------------------------------------------------------------------- 1 | #if !DISABLE_DHT 2 | // 3 | // Message.cs 4 | // 5 | // Authors: 6 | // Alan McGovern 7 | // 8 | // Copyright (C) 2008 Alan McGovern 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining 11 | // a copy of this software and associated documentation files (the 12 | // "Software"), to deal in the Software without restriction, including 13 | // without limitation the rights to use, copy, modify, merge, publish, 14 | // distribute, sublicense, and/or sell copies of the Software, and to 15 | // permit persons to whom the Software is furnished to do so, subject to 16 | // the following conditions: 17 | // 18 | // The above copyright notice and this permission notice shall be 19 | // included in all copies or substantial portions of the Software. 20 | // 21 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 22 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 23 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 24 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 25 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 26 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 27 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 28 | // 29 | 30 | 31 | using System; 32 | using System.Collections.Generic; 33 | 34 | using Tancoder.Torrent.BEncoding; 35 | using System.Net; 36 | using Tancoder.Torrent.Common; 37 | 38 | namespace Tancoder.Torrent.Dht.Messages 39 | { 40 | public abstract class DhtMessage : Tancoder.Torrent.Client.Messages.Message 41 | { 42 | public static bool UseVersionKey = true; 43 | 44 | private static BEncodedString EmptyString = ""; 45 | protected static readonly BEncodedString IdKey = "id"; 46 | private static BEncodedString TransactionIdKey = "t"; 47 | private static BEncodedString VersionKey = "v"; 48 | private static BEncodedString MessageTypeKey = "y"; 49 | private static BEncodedString DhtVersion = VersionInfo.DhtClientVersion; 50 | 51 | protected BEncodedDictionary properties = new BEncodedDictionary(); 52 | 53 | public BEncodedString ClientVersion 54 | { 55 | get 56 | { 57 | BEncodedValue val; 58 | if (properties.TryGetValue(VersionKey, out val)) 59 | return (BEncodedString)val; 60 | return EmptyString; 61 | } 62 | } 63 | 64 | public abstract NodeId Id 65 | { 66 | get; 67 | } 68 | 69 | public BEncodedString MessageType 70 | { 71 | get { return (BEncodedString)properties[MessageTypeKey]; } 72 | } 73 | 74 | public BEncodedValue TransactionId 75 | { 76 | get { return properties[TransactionIdKey]; } 77 | set { properties[TransactionIdKey] = value; } 78 | } 79 | 80 | 81 | protected DhtMessage(BEncodedString messageType) 82 | { 83 | properties.Add(TransactionIdKey, null); 84 | properties.Add(MessageTypeKey, messageType); 85 | if (UseVersionKey) 86 | properties.Add(VersionKey, DhtVersion); 87 | } 88 | 89 | protected DhtMessage(BEncodedDictionary dictionary) 90 | { 91 | properties = dictionary; 92 | } 93 | 94 | public override int ByteLength 95 | { 96 | get { return properties.LengthInBytes(); } 97 | } 98 | 99 | public override void Decode(byte[] buffer, int offset, int length) 100 | { 101 | properties = BEncodedValue.Decode(buffer, offset, length, false); 102 | } 103 | 104 | public override int Encode(byte[] buffer, int offset) 105 | { 106 | return properties.Encode(buffer, offset); 107 | } 108 | 109 | public virtual void Handle(IDhtEngine engine, Node node) 110 | { 111 | node.Seen(); 112 | } 113 | } 114 | } 115 | #endif -------------------------------------------------------------------------------- /Tancoder.Torrent/Messages/Errors/ErrorMessage.cs: -------------------------------------------------------------------------------- 1 | #if !DISABLE_DHT 2 | // 3 | // ErrorMessage.cs 4 | // 5 | // Authors: 6 | // Alan McGovern 7 | // 8 | // Copyright (C) 2008 Alan McGovern 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining 11 | // a copy of this software and associated documentation files (the 12 | // "Software"), to deal in the Software without restriction, including 13 | // without limitation the rights to use, copy, modify, merge, publish, 14 | // distribute, sublicense, and/or sell copies of the Software, and to 15 | // permit persons to whom the Software is furnished to do so, subject to 16 | // the following conditions: 17 | // 18 | // The above copyright notice and this permission notice shall be 19 | // included in all copies or substantial portions of the Software. 20 | // 21 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 22 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 23 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 24 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 25 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 26 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 27 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 28 | // 29 | 30 | 31 | using System; 32 | using System.Collections.Generic; 33 | using System.Text; 34 | using System.Net; 35 | 36 | using Tancoder.Torrent.BEncoding; 37 | using Tancoder.Torrent.Dht; 38 | 39 | 40 | namespace Tancoder.Torrent.Dht.Messages 41 | { 42 | public class ErrorMessage : DhtMessage 43 | { 44 | private static readonly BEncodedString ErrorListKey = "e"; 45 | public static readonly BEncodedString ErrorType = "e"; 46 | 47 | public override NodeId Id 48 | { 49 | get { return new NodeId((BEncodedString)""); } 50 | } 51 | public BEncodedList ErrorList 52 | { 53 | get { return (BEncodedList)properties[ErrorListKey]; } 54 | } 55 | 56 | private ErrorCode ErrorCode 57 | { 58 | get { return ((ErrorCode)((BEncodedNumber)ErrorList[0]).Number); } 59 | } 60 | 61 | private string Message 62 | { 63 | get { return ((BEncodedString)ErrorList[1]).Text; } 64 | } 65 | 66 | public ErrorMessage(ErrorCode error, string message) 67 | : base(ErrorType) 68 | { 69 | BEncodedList l = new BEncodedList(); 70 | l.Add(new BEncodedNumber((int)error)); 71 | l.Add(new BEncodedString(message)); 72 | properties.Add(ErrorListKey, l); 73 | } 74 | 75 | public ErrorMessage(BEncodedDictionary d) 76 | : base(d) 77 | { 78 | 79 | } 80 | 81 | public override void Handle(IDhtEngine engine, Node node) 82 | { 83 | base.Handle(engine, node); 84 | 85 | throw new MessageException(ErrorCode, Message); 86 | } 87 | } 88 | } 89 | #endif -------------------------------------------------------------------------------- /Tancoder.Torrent/Messages/Queries/AnnouncePeer.cs: -------------------------------------------------------------------------------- 1 | #if !DISABLE_DHT 2 | // 3 | // AnnouncePeer.cs 4 | // 5 | // Authors: 6 | // Alan McGovern 7 | // 8 | // Copyright (C) 2008 Alan McGovern 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining 11 | // a copy of this software and associated documentation files (the 12 | // "Software"), to deal in the Software without restriction, including 13 | // without limitation the rights to use, copy, modify, merge, publish, 14 | // distribute, sublicense, and/or sell copies of the Software, and to 15 | // permit persons to whom the Software is furnished to do so, subject to 16 | // the following conditions: 17 | // 18 | // The above copyright notice and this permission notice shall be 19 | // included in all copies or substantial portions of the Software. 20 | // 21 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 22 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 23 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 24 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 25 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 26 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 27 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 28 | // 29 | 30 | 31 | using System; 32 | using System.Collections.Generic; 33 | using System.Text; 34 | 35 | using Tancoder.Torrent.BEncoding; 36 | using System.Net; 37 | 38 | namespace Tancoder.Torrent.Dht.Messages 39 | { 40 | public class AnnouncePeer : QueryMessage 41 | { 42 | private static BEncodedString InfoHashKey = "info_hash"; 43 | private static BEncodedString QueryName = "announce_peer"; 44 | private static BEncodedString PortKey = "port"; 45 | private static BEncodedString TokenKey = "token"; 46 | private static ResponseCreator responseCreator = delegate(BEncodedDictionary d, QueryMessage m) { return new AnnouncePeerResponse(d, m); }; 47 | 48 | public NodeId InfoHash 49 | { 50 | get { return new NodeId((BEncodedString)Parameters[InfoHashKey]); } 51 | } 52 | 53 | public BEncodedNumber Port 54 | { 55 | get { return (BEncodedNumber)Parameters[PortKey]; } 56 | } 57 | 58 | public BEncodedString Token 59 | { 60 | get { return (BEncodedString)Parameters[TokenKey]; } 61 | } 62 | 63 | public AnnouncePeer(NodeId id, NodeId infoHash, BEncodedNumber port, BEncodedString token) 64 | : base(id, QueryName, responseCreator) 65 | { 66 | Parameters.Add(InfoHashKey, infoHash.BencodedString()); 67 | Parameters.Add(PortKey, port); 68 | Parameters.Add(TokenKey, token); 69 | } 70 | 71 | public AnnouncePeer(BEncodedDictionary d) 72 | : base(d, responseCreator) 73 | { 74 | 75 | } 76 | 77 | public override void Handle(IDhtEngine engine, Node node) 78 | { 79 | base.Handle(engine, node); 80 | 81 | DhtMessage response; 82 | if (engine.TokenManager.VerifyToken(node, Token)) 83 | { 84 | engine.GetAnnounced(new InfoHash(InfoHash.Bytes), 85 | new IPEndPoint(node.EndPoint.Address, (int)Port.Number)); 86 | response = new AnnouncePeerResponse(engine.GetNeighborId(Id), TransactionId); 87 | } 88 | else 89 | response = new ErrorMessage(ErrorCode.ProtocolError, "Invalid or expired token received"); 90 | 91 | engine.Send(response, node.EndPoint); 92 | } 93 | } 94 | } 95 | #endif -------------------------------------------------------------------------------- /Tancoder.Torrent/Messages/Queries/FindNode.cs: -------------------------------------------------------------------------------- 1 | #if !DISABLE_DHT 2 | // 3 | // FindNode.cs 4 | // 5 | // Authors: 6 | // Alan McGovern 7 | // 8 | // Copyright (C) 2008 Alan McGovern 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining 11 | // a copy of this software and associated documentation files (the 12 | // "Software"), to deal in the Software without restriction, including 13 | // without limitation the rights to use, copy, modify, merge, publish, 14 | // distribute, sublicense, and/or sell copies of the Software, and to 15 | // permit persons to whom the Software is furnished to do so, subject to 16 | // the following conditions: 17 | // 18 | // The above copyright notice and this permission notice shall be 19 | // included in all copies or substantial portions of the Software. 20 | // 21 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 22 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 23 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 24 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 25 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 26 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 27 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 28 | // 29 | 30 | 31 | using System; 32 | using System.Collections.Generic; 33 | using System.Text; 34 | 35 | using Tancoder.Torrent.BEncoding; 36 | using System.Net; 37 | 38 | namespace Tancoder.Torrent.Dht.Messages 39 | { 40 | public class FindNode : QueryMessage 41 | { 42 | private static BEncodedString TargetKey = "target"; 43 | private static BEncodedString QueryName = "find_node"; 44 | private static ResponseCreator responseCreator = delegate (BEncodedDictionary d, QueryMessage m) { return new FindNodeResponse(d, m); }; 45 | 46 | public NodeId Target 47 | { 48 | get { return new NodeId((BEncodedString)Parameters[TargetKey]); } 49 | } 50 | 51 | public FindNode(NodeId id, NodeId target) 52 | : base(id, QueryName, responseCreator) 53 | { 54 | Parameters.Add(TargetKey, target.BencodedString()); 55 | } 56 | 57 | public FindNode(BEncodedDictionary d) 58 | : base(d, responseCreator) 59 | { 60 | } 61 | 62 | public override void Handle(IDhtEngine engine, Node node) 63 | { 64 | base.Handle(engine, node); 65 | FindNodeResponse response = new FindNodeResponse(engine.LocalId, TransactionId); 66 | var result = engine.QueryFindNode(Target); 67 | response.Nodes = Node.CompactNode(result.Nodes); 68 | 69 | engine.Send(response, node.EndPoint); 70 | } 71 | } 72 | } 73 | #endif -------------------------------------------------------------------------------- /Tancoder.Torrent/Messages/Queries/GetPeers.cs: -------------------------------------------------------------------------------- 1 | #if !DISABLE_DHT 2 | // 3 | // GetPeers.cs 4 | // 5 | // Authors: 6 | // Alan McGovern 7 | // 8 | // Copyright (C) 2008 Alan McGovern 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining 11 | // a copy of this software and associated documentation files (the 12 | // "Software"), to deal in the Software without restriction, including 13 | // without limitation the rights to use, copy, modify, merge, publish, 14 | // distribute, sublicense, and/or sell copies of the Software, and to 15 | // permit persons to whom the Software is furnished to do so, subject to 16 | // the following conditions: 17 | // 18 | // The above copyright notice and this permission notice shall be 19 | // included in all copies or substantial portions of the Software. 20 | // 21 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 22 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 23 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 24 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 25 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 26 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 27 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 28 | // 29 | 30 | 31 | using System; 32 | using System.Collections.Generic; 33 | using System.Text; 34 | 35 | using Tancoder.Torrent.BEncoding; 36 | using System.Net; 37 | 38 | namespace Tancoder.Torrent.Dht.Messages 39 | { 40 | public class GetPeers : QueryMessage 41 | { 42 | private static BEncodedString InfoHashKey = "info_hash"; 43 | private static BEncodedString QueryName = "get_peers"; 44 | private static ResponseCreator responseCreator = delegate(BEncodedDictionary d, QueryMessage m) { return new GetPeersResponse(d, m); }; 45 | 46 | public static Func Hook { get; set; } 47 | 48 | public NodeId InfoHash 49 | { 50 | get { return new NodeId((BEncodedString)Parameters[InfoHashKey]); } 51 | } 52 | 53 | public GetPeers(NodeId id, NodeId infohash) 54 | : base(id, QueryName, responseCreator) 55 | { 56 | Parameters.Add(InfoHashKey, infohash.BencodedString()); 57 | } 58 | 59 | public GetPeers(BEncodedDictionary d) 60 | : base(d, responseCreator) 61 | { 62 | 63 | } 64 | 65 | public override void Handle(IDhtEngine engine, Node node) 66 | { 67 | base.Handle(engine, node); 68 | 69 | BEncodedString token = engine.TokenManager.GenerateToken(node); 70 | GetPeersResponse response = new GetPeersResponse(engine.LocalId, TransactionId, token); 71 | 72 | var result = engine.QueryGetPeers(InfoHash); 73 | if (result.HasHash) 74 | { 75 | BEncodedList list = new BEncodedList(); 76 | foreach (Node n in result.Values) 77 | list.Add(n.CompactPort()); 78 | response.Values = list; 79 | } 80 | else 81 | { 82 | // Is this right? 83 | response.Nodes = Node.CompactNode(result.Nodes); 84 | } 85 | 86 | if (Hook == null || Hook(response)) 87 | engine.Send(response, node.EndPoint); 88 | } 89 | } 90 | } 91 | #endif -------------------------------------------------------------------------------- /Tancoder.Torrent/Messages/Queries/Ping.cs: -------------------------------------------------------------------------------- 1 | #if !DISABLE_DHT 2 | // 3 | // Ping.cs 4 | // 5 | // Authors: 6 | // Alan McGovern 7 | // 8 | // Copyright (C) 2008 Alan McGovern 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining 11 | // a copy of this software and associated documentation files (the 12 | // "Software"), to deal in the Software without restriction, including 13 | // without limitation the rights to use, copy, modify, merge, publish, 14 | // distribute, sublicense, and/or sell copies of the Software, and to 15 | // permit persons to whom the Software is furnished to do so, subject to 16 | // the following conditions: 17 | // 18 | // The above copyright notice and this permission notice shall be 19 | // included in all copies or substantial portions of the Software. 20 | // 21 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 22 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 23 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 24 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 25 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 26 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 27 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 28 | // 29 | 30 | 31 | using System; 32 | using System.Collections.Generic; 33 | using System.Text; 34 | 35 | using Tancoder.Torrent.BEncoding; 36 | using System.Net; 37 | 38 | namespace Tancoder.Torrent.Dht.Messages 39 | { 40 | public class Ping : QueryMessage 41 | { 42 | private static readonly BEncodedString QueryName = "ping"; 43 | private static readonly ResponseCreator responseCreator = delegate (BEncodedDictionary d, QueryMessage m) { return new PingResponse(d, m); }; 44 | 45 | public Ping(NodeId id) 46 | : base(id, QueryName, responseCreator) 47 | { 48 | 49 | } 50 | 51 | public Ping(BEncodedDictionary d) 52 | : base(d, responseCreator) 53 | { 54 | 55 | } 56 | 57 | public override void Handle(IDhtEngine engine, Node node) 58 | { 59 | base.Handle(engine, node); 60 | 61 | //PingResponse m = new PingResponse(engine.GetNeighborId(Id), TransactionId); 62 | PingResponse m = new PingResponse(engine.LocalId, TransactionId); 63 | engine.Send(m, node.EndPoint); 64 | } 65 | } 66 | } 67 | #endif -------------------------------------------------------------------------------- /Tancoder.Torrent/Messages/Queries/QueryMessage.cs: -------------------------------------------------------------------------------- 1 | #if !DISABLE_DHT 2 | // 3 | // QueryMessage.cs 4 | // 5 | // Authors: 6 | // Alan McGovern 7 | // 8 | // Copyright (C) 2008 Alan McGovern 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining 11 | // a copy of this software and associated documentation files (the 12 | // "Software"), to deal in the Software without restriction, including 13 | // without limitation the rights to use, copy, modify, merge, publish, 14 | // distribute, sublicense, and/or sell copies of the Software, and to 15 | // permit persons to whom the Software is furnished to do so, subject to 16 | // the following conditions: 17 | // 18 | // The above copyright notice and this permission notice shall be 19 | // included in all copies or substantial portions of the Software. 20 | // 21 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 22 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 23 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 24 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 25 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 26 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 27 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 28 | // 29 | 30 | 31 | using System; 32 | using System.Collections.Generic; 33 | 34 | using Tancoder.Torrent.BEncoding; 35 | using System.Net; 36 | 37 | namespace Tancoder.Torrent.Dht.Messages 38 | { 39 | public abstract class QueryMessage : DhtMessage 40 | { 41 | private static readonly BEncodedString QueryArgumentsKey = "a"; 42 | private static readonly BEncodedString QueryNameKey = "q"; 43 | public static readonly BEncodedString QueryType = "q"; 44 | private ResponseCreator responseCreator; 45 | 46 | public override NodeId Id 47 | { 48 | get { return new NodeId((BEncodedString)Parameters[IdKey]); } 49 | } 50 | 51 | public ResponseCreator ResponseCreator 52 | { 53 | get { return responseCreator; } 54 | private set { responseCreator = value; } 55 | } 56 | 57 | public BEncodedDictionary Parameters 58 | { 59 | get { return (BEncodedDictionary)properties[QueryArgumentsKey]; } 60 | } 61 | 62 | protected QueryMessage(NodeId id, BEncodedString queryName, ResponseCreator responseCreator) 63 | : this(id, queryName, new BEncodedDictionary(), responseCreator) 64 | { 65 | 66 | } 67 | 68 | protected QueryMessage(NodeId id, BEncodedString queryName, BEncodedDictionary queryArguments, ResponseCreator responseCreator) 69 | : base(QueryType) 70 | { 71 | properties.Add(QueryNameKey, queryName); 72 | properties.Add(QueryArgumentsKey, queryArguments); 73 | 74 | Parameters.Add(IdKey, id.BencodedString()); 75 | ResponseCreator = responseCreator; 76 | } 77 | 78 | protected QueryMessage(BEncodedDictionary d, ResponseCreator responseCreator) 79 | : base(d) 80 | { 81 | ResponseCreator = responseCreator; 82 | } 83 | } 84 | } 85 | #endif -------------------------------------------------------------------------------- /Tancoder.Torrent/Messages/Responses/AnnouncePeerResponse.cs: -------------------------------------------------------------------------------- 1 | #if !DISABLE_DHT 2 | // 3 | // AnnouncePeerResponse.cs 4 | // 5 | // Authors: 6 | // Alan McGovern 7 | // 8 | // Copyright (C) 2008 Alan McGovern 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining 11 | // a copy of this software and associated documentation files (the 12 | // "Software"), to deal in the Software without restriction, including 13 | // without limitation the rights to use, copy, modify, merge, publish, 14 | // distribute, sublicense, and/or sell copies of the Software, and to 15 | // permit persons to whom the Software is furnished to do so, subject to 16 | // the following conditions: 17 | // 18 | // The above copyright notice and this permission notice shall be 19 | // included in all copies or substantial portions of the Software. 20 | // 21 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 22 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 23 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 24 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 25 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 26 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 27 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 28 | // 29 | 30 | 31 | using System; 32 | using System.Collections.Generic; 33 | using System.Text; 34 | 35 | using Tancoder.Torrent.BEncoding; 36 | using System.Net; 37 | 38 | namespace Tancoder.Torrent.Dht.Messages 39 | { 40 | public class AnnouncePeerResponse : ResponseMessage 41 | { 42 | public AnnouncePeerResponse(NodeId id, BEncodedValue transactionId) 43 | : base(id, transactionId) 44 | { 45 | 46 | } 47 | 48 | public AnnouncePeerResponse(BEncodedDictionary d, QueryMessage m) 49 | : base(d, m) 50 | { 51 | 52 | } 53 | } 54 | } 55 | #endif -------------------------------------------------------------------------------- /Tancoder.Torrent/Messages/Responses/FindNodeResponse.cs: -------------------------------------------------------------------------------- 1 | #if !DISABLE_DHT 2 | // 3 | // FindNodeResponse.cs 4 | // 5 | // Authors: 6 | // Alan McGovern 7 | // 8 | // Copyright (C) 2008 Alan McGovern 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining 11 | // a copy of this software and associated documentation files (the 12 | // "Software"), to deal in the Software without restriction, including 13 | // without limitation the rights to use, copy, modify, merge, publish, 14 | // distribute, sublicense, and/or sell copies of the Software, and to 15 | // permit persons to whom the Software is furnished to do so, subject to 16 | // the following conditions: 17 | // 18 | // The above copyright notice and this permission notice shall be 19 | // included in all copies or substantial portions of the Software. 20 | // 21 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 22 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 23 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 24 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 25 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 26 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 27 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 28 | // 29 | 30 | 31 | using System; 32 | using System.Collections.Generic; 33 | using System.Text; 34 | 35 | using Tancoder.Torrent.BEncoding; 36 | using System.Net; 37 | 38 | namespace Tancoder.Torrent.Dht.Messages 39 | { 40 | public class FindNodeResponse : ResponseMessage 41 | { 42 | private static readonly BEncodedString NodesKey = "nodes"; 43 | private static readonly BEncodedString NodesKey2 = "nodes\0v"; 44 | 45 | public BEncodedString Nodes 46 | { 47 | get 48 | { 49 | if (Parameters.ContainsKey(NodesKey)) 50 | return (BEncodedString)Parameters[NodesKey]; 51 | else 52 | return (BEncodedString)Parameters[NodesKey2]; 53 | } 54 | set { Parameters[NodesKey] = value; } 55 | } 56 | 57 | public FindNodeResponse(NodeId id, BEncodedValue transactionId) 58 | : base(id, transactionId) 59 | { 60 | Parameters.Add(NodesKey, new BEncodedString()); 61 | } 62 | 63 | public FindNodeResponse(BEncodedDictionary d, QueryMessage m) 64 | : base(d, m) 65 | { 66 | } 67 | 68 | public override void Handle(IDhtEngine engine, Node node) 69 | { 70 | base.Handle(engine, node); 71 | engine.Add(Node.FromCompactNode(Nodes.TextBytes)); 72 | } 73 | } 74 | } 75 | #endif -------------------------------------------------------------------------------- /Tancoder.Torrent/Messages/Responses/GetPeersResponse.cs: -------------------------------------------------------------------------------- 1 | #if !DISABLE_DHT 2 | // 3 | // GetPeersResponse.cs 4 | // 5 | // Authors: 6 | // Alan McGovern 7 | // 8 | // Copyright (C) 2008 Alan McGovern 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining 11 | // a copy of this software and associated documentation files (the 12 | // "Software"), to deal in the Software without restriction, including 13 | // without limitation the rights to use, copy, modify, merge, publish, 14 | // distribute, sublicense, and/or sell copies of the Software, and to 15 | // permit persons to whom the Software is furnished to do so, subject to 16 | // the following conditions: 17 | // 18 | // The above copyright notice and this permission notice shall be 19 | // included in all copies or substantial portions of the Software. 20 | // 21 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 22 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 23 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 24 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 25 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 26 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 27 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 28 | // 29 | 30 | 31 | using System; 32 | using System.Collections.Generic; 33 | using System.Text; 34 | 35 | using Tancoder.Torrent.BEncoding; 36 | using System.Net; 37 | 38 | namespace Tancoder.Torrent.Dht.Messages 39 | { 40 | public class GetPeersResponse : ResponseMessage 41 | { 42 | public static readonly BEncodedString NodesKey = "nodes"; 43 | private static readonly BEncodedString TokenKey = "token"; 44 | public static readonly BEncodedString ValuesKey = "values"; 45 | 46 | public BEncodedString Token 47 | { 48 | get { return (BEncodedString)Parameters[TokenKey]; } 49 | set { Parameters[TokenKey] = value; } 50 | } 51 | 52 | public BEncodedString Nodes 53 | { 54 | get 55 | { 56 | if (Parameters.ContainsKey(ValuesKey) || !Parameters.ContainsKey(NodesKey)) 57 | return null; 58 | return (BEncodedString)Parameters[NodesKey]; 59 | } 60 | set 61 | { 62 | if (Parameters.ContainsKey(ValuesKey)) 63 | throw new InvalidOperationException("Already contains the values key"); 64 | if (!Parameters.ContainsKey(NodesKey)) 65 | Parameters.Add(NodesKey, null); 66 | Parameters[NodesKey] = value; 67 | } 68 | } 69 | 70 | public BEncodedList Values 71 | { 72 | get 73 | { 74 | if (Parameters.ContainsKey(NodesKey) || !Parameters.ContainsKey(ValuesKey)) 75 | return null; 76 | return (BEncodedList)Parameters[ValuesKey]; 77 | } 78 | set 79 | { 80 | if (Parameters.ContainsKey(NodesKey)) 81 | throw new InvalidOperationException("Already contains the nodes key"); 82 | if (!Parameters.ContainsKey(ValuesKey)) 83 | Parameters.Add(ValuesKey, value); 84 | else 85 | Parameters[ValuesKey] = value; 86 | } 87 | } 88 | 89 | public GetPeersResponse(NodeId id, BEncodedValue transactionId, BEncodedString token) 90 | : base(id, transactionId) 91 | { 92 | Parameters.Add(TokenKey, token); 93 | } 94 | 95 | public GetPeersResponse(BEncodedDictionary d, QueryMessage m) 96 | : base(d, m) 97 | { 98 | 99 | } 100 | 101 | public override void Handle(IDhtEngine engine, Node node) 102 | { 103 | base.Handle(engine, node); 104 | node.Token = Token; 105 | if (Nodes != null) 106 | engine.Add(Node.FromCompactNode(Nodes)); 107 | } 108 | } 109 | } 110 | #endif -------------------------------------------------------------------------------- /Tancoder.Torrent/Messages/Responses/PingResponse.cs: -------------------------------------------------------------------------------- 1 | #if !DISABLE_DHT 2 | // 3 | // PingResponse.cs 4 | // 5 | // Authors: 6 | // Alan McGovern 7 | // 8 | // Copyright (C) 2008 Alan McGovern 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining 11 | // a copy of this software and associated documentation files (the 12 | // "Software"), to deal in the Software without restriction, including 13 | // without limitation the rights to use, copy, modify, merge, publish, 14 | // distribute, sublicense, and/or sell copies of the Software, and to 15 | // permit persons to whom the Software is furnished to do so, subject to 16 | // the following conditions: 17 | // 18 | // The above copyright notice and this permission notice shall be 19 | // included in all copies or substantial portions of the Software. 20 | // 21 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 22 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 23 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 24 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 25 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 26 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 27 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 28 | // 29 | 30 | 31 | using System; 32 | using System.Collections.Generic; 33 | using System.Text; 34 | using Tancoder.Torrent.BEncoding; 35 | using System.Net; 36 | 37 | namespace Tancoder.Torrent.Dht.Messages 38 | { 39 | class PingResponse : ResponseMessage 40 | { 41 | public PingResponse(NodeId id, BEncodedValue transactionId) 42 | : base(id, transactionId) 43 | { 44 | } 45 | 46 | public PingResponse(BEncodedDictionary d, QueryMessage m) 47 | :base(d, m) 48 | { 49 | } 50 | } 51 | } 52 | #endif -------------------------------------------------------------------------------- /Tancoder.Torrent/Messages/Responses/ResponseMessage.cs: -------------------------------------------------------------------------------- 1 | #if !DISABLE_DHT 2 | // 3 | // ResponseMessage.cs 4 | // 5 | // Authors: 6 | // Alan McGovern 7 | // 8 | // Copyright (C) 2008 Alan McGovern 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining 11 | // a copy of this software and associated documentation files (the 12 | // "Software"), to deal in the Software without restriction, including 13 | // without limitation the rights to use, copy, modify, merge, publish, 14 | // distribute, sublicense, and/or sell copies of the Software, and to 15 | // permit persons to whom the Software is furnished to do so, subject to 16 | // the following conditions: 17 | // 18 | // The above copyright notice and this permission notice shall be 19 | // included in all copies or substantial portions of the Software. 20 | // 21 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 22 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 23 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 24 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 25 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 26 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 27 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 28 | // 29 | 30 | 31 | using System; 32 | using System.Collections.Generic; 33 | using System.Text; 34 | using Tancoder.Torrent.BEncoding; 35 | 36 | namespace Tancoder.Torrent.Dht.Messages 37 | { 38 | public abstract class ResponseMessage : DhtMessage 39 | { 40 | private static readonly BEncodedString ReturnValuesKey = "r"; 41 | public static readonly BEncodedString ResponseType = "r"; 42 | protected QueryMessage queryMessage; 43 | 44 | public override NodeId Id 45 | { 46 | get { return new NodeId((BEncodedString)Parameters[IdKey]); } 47 | } 48 | public BEncodedDictionary Parameters 49 | { 50 | get { return (BEncodedDictionary)properties[ReturnValuesKey]; } 51 | } 52 | 53 | public QueryMessage Query 54 | { 55 | get { return queryMessage; } 56 | } 57 | 58 | protected ResponseMessage(NodeId id, BEncodedValue transactionId) 59 | : base(ResponseType) 60 | { 61 | properties.Add(ReturnValuesKey, new BEncodedDictionary()); 62 | Parameters.Add(IdKey, id.BencodedString()); 63 | TransactionId = transactionId; 64 | } 65 | 66 | protected ResponseMessage(BEncodedDictionary d, QueryMessage m) 67 | : base(d) 68 | { 69 | queryMessage = m; 70 | } 71 | } 72 | } 73 | #endif -------------------------------------------------------------------------------- /Tancoder.Torrent/Messages/Wire/ExtData.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using Tancoder.Torrent.BEncoding; 7 | 8 | namespace Tancoder.Torrent.Messages.Wire 9 | { 10 | public class ExtData : ExtendMessage 11 | { 12 | static readonly BEncodedString MsgTypeKey = "msg_type"; 13 | static readonly BEncodedString PieceKey = "piece"; 14 | static readonly BEncodedNumber MsgType = 1; 15 | public byte[] Data { get; set; } 16 | public int PieceID 17 | { 18 | get { return (int)((BEncodedNumber)Parameters[PieceKey]).Number; } 19 | set { Parameters[PieceKey] = new BEncodedNumber(value); } 20 | } 21 | 22 | public ExtData() 23 | { 24 | Parameters[MsgTypeKey] = MsgType; 25 | } 26 | 27 | public override void Decode(byte[] buffer, int offset, int length) 28 | { 29 | int head = 0; 30 | for (int i = 0; i < length - 1; i++) 31 | { 32 | if (buffer[offset + i] == 'e' && buffer[offset + i + 1] == 'e') 33 | { 34 | head = i + 2; 35 | break; 36 | } 37 | } 38 | if (head == 0) 39 | return; 40 | base.Decode(buffer, offset, head); 41 | if (!Legal || !Parameters[MsgTypeKey].Equals(MsgType)) 42 | { 43 | Legal = false; 44 | return; 45 | } 46 | Data = new byte[length - head]; 47 | Array.Copy(buffer, offset + head, Data, 0, Data.Length); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Tancoder.Torrent/Messages/Wire/ExtHandShack.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using Tancoder.Torrent.BEncoding; 7 | 8 | namespace Tancoder.Torrent.Messages.Wire 9 | { 10 | public class ExtHandShack : ExtendMessage 11 | { 12 | static readonly byte ExtHandShackID = 0; 13 | static readonly string UtMetadataKey = "ut_metadata"; 14 | static readonly string MethodKey = "m"; 15 | static readonly string MetadataSizeKey = "metadata_size"; 16 | 17 | public bool SupportUtMetadata 18 | { 19 | get 20 | { 21 | return ((BEncodedDictionary)Parameters[MethodKey]).Keys.Contains(UtMetadataKey); 22 | } 23 | set 24 | { 25 | if (value) 26 | ((BEncodedDictionary)Parameters[MethodKey])[UtMetadataKey] = new BEncodedNumber(1); 27 | else 28 | ((BEncodedDictionary)Parameters[MethodKey]).Remove(UtMetadataKey); 29 | } 30 | } 31 | public byte UtMetadata 32 | { 33 | get 34 | { 35 | return (byte)((BEncodedNumber)((BEncodedDictionary)Parameters[MethodKey])[UtMetadataKey]).Number; 36 | } 37 | set 38 | { 39 | ((BEncodedDictionary)Parameters[MethodKey])[UtMetadataKey] = new BEncodedNumber(value); 40 | } 41 | } 42 | public long MetadataSize 43 | { 44 | get 45 | { 46 | return ((BEncodedNumber)Parameters[MetadataSizeKey]).Number; 47 | } 48 | set 49 | { 50 | Parameters[MetadataSizeKey] = new BEncodedNumber(value); 51 | } 52 | } 53 | 54 | public bool CanGetMetadate 55 | { 56 | get 57 | { 58 | return Parameters.Keys.Contains(MetadataSizeKey) && SupportUtMetadata; 59 | } 60 | } 61 | 62 | public ExtHandShack() 63 | : base() 64 | { 65 | ExtTypeID = ExtHandShackID; 66 | Parameters[MethodKey] = new BEncodedDictionary(); 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /Tancoder.Torrent/Messages/Wire/ExtQueryPiece.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using Tancoder.Torrent.BEncoding; 7 | 8 | namespace Tancoder.Torrent.Messages.Wire 9 | { 10 | public class ExtQueryPiece : ExtendMessage 11 | { 12 | static readonly BEncodedString MsgTypeKey = "msg_type"; 13 | static readonly BEncodedString PieceKey = "piece"; 14 | static readonly byte MsgType = 0; 15 | public int PieceID 16 | { 17 | get { return (int)((BEncodedNumber)Parameters[PieceKey]).Number; } 18 | set { Parameters[PieceKey] = new BEncodedNumber(value); } 19 | } 20 | 21 | public ExtQueryPiece() 22 | { 23 | Parameters[MsgTypeKey] = new BEncodedNumber(MsgType); 24 | } 25 | public ExtQueryPiece(byte ut_metadata, int piece) 26 | : this() 27 | { 28 | PieceID = piece; 29 | ExtTypeID = ut_metadata; 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Tancoder.Torrent/Messages/Wire/ExtendMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using Tancoder.Torrent.BEncoding; 8 | 9 | namespace Tancoder.Torrent.Messages.Wire 10 | { 11 | public abstract class ExtendMessage : WireMessage 12 | { 13 | static readonly byte ExtendID = 20; 14 | public BEncodedDictionary Parameters { get; protected set; } 15 | public byte ExtTypeID { get; protected set; } 16 | public ExtendMessage() 17 | { 18 | MessageID = ExtendID; 19 | Parameters = new BEncodedDictionary(); 20 | } 21 | public override int ByteLength 22 | { 23 | get 24 | { 25 | return Parameters.LengthInBytes() + sizeof(byte) + sizeof(byte) + sizeof(int); 26 | } 27 | } 28 | public override void Decode(byte[] buffer, int offset, int length) 29 | { 30 | base.Decode(buffer, offset, length); 31 | 32 | if (!Legal || MessageID != ExtendID) 33 | { 34 | Legal = false; 35 | return; 36 | } 37 | try 38 | { 39 | offset += 1; 40 | ExtTypeID = ReadByte(buffer, ref offset); 41 | Parameters = BEncodedValue.Decode(buffer, offset, length - 2, false); 42 | Legal = true; 43 | } 44 | catch (Exception ex) 45 | { 46 | Legal = false; 47 | Debug.WriteLine(ex); 48 | } 49 | } 50 | 51 | public override int Encode(byte[] buffer, int offset) 52 | { 53 | int off = offset; 54 | Length = ByteLength - sizeof(int); 55 | off += base.Encode(buffer, off); 56 | off += Write(buffer, off, ExtTypeID); 57 | off += Parameters.Encode(buffer, off); 58 | 59 | return off - offset; 60 | } 61 | 62 | public override bool CheackHead(byte[] buffer, int offset) 63 | { 64 | return buffer[offset] == ExtendID; 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /Tancoder.Torrent/Messages/Wire/HandShack.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using Tancoder.Torrent.Dht; 7 | using Tancoder.Torrent.Messages; 8 | 9 | namespace Tancoder.Torrent.Messages.Wire 10 | { 11 | public class HandShack : WireMessage 12 | { 13 | static readonly string Protocol = "BitTorrent protocol"; 14 | static readonly byte[] Reserved = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01 }; 15 | 16 | public bool SupportExtend { get; set; } 17 | public NodeId PeerId { get; set; } 18 | public InfoHash InfoHash { get; set; } 19 | public override int ByteLength 20 | { 21 | get 22 | { 23 | return 1 + Length + Reserved.Length + 20 + 20; 24 | } 25 | } 26 | 27 | public override int OnMessageLength(byte[] pstrlen) 28 | { 29 | Length = ReadByte(pstrlen, 0); 30 | return ByteLength - 1; 31 | } 32 | 33 | public override void Decode(byte[] buffer, int offset, int length) 34 | { 35 | if (length != ByteLength - 1) 36 | return; 37 | 38 | string protocol = ReadString(buffer, ref offset, Length); 39 | if (protocol != Protocol) 40 | return; 41 | 42 | byte[] res = ReadBytes(buffer, ref offset, 8); 43 | SupportExtend = (res[5] & 0x10) > 0; 44 | InfoHash = new InfoHash(ReadBytes(buffer, ref offset, 20)); 45 | PeerId = new NodeId(ReadBytes(buffer, ref offset, 20)); 46 | Legal = true; 47 | } 48 | 49 | public override int Encode(byte[] buffer, int offset) 50 | { 51 | var off = offset; 52 | off += Write(buffer, off, (byte)Protocol.Length); 53 | off += WriteAscii(buffer, off, Protocol); 54 | off += Write(buffer, off, Reserved); 55 | off += Write(buffer, off, InfoHash.Hash); 56 | off += Write(buffer, off, PeerId.Bytes); 57 | 58 | return off - offset; 59 | } 60 | 61 | public override bool CheackHead(byte[] buffer, int offset) 62 | { 63 | if (Length != Protocol.Length) 64 | return false; 65 | string protocol = ReadString(buffer, ref offset, Length); 66 | return protocol == Protocol; 67 | } 68 | 69 | public HandShack(InfoHash infohash, NodeId id) 70 | { 71 | InfoHash = infohash; 72 | PeerId = id; 73 | Length = (byte)Protocol.Length; 74 | Legal = true; 75 | SupportExtend = true; 76 | } 77 | 78 | public HandShack(InfoHash infohash) 79 | : this(infohash, NodeId.Create()) 80 | { 81 | } 82 | 83 | public HandShack() 84 | { 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /Tancoder.Torrent/Messages/WireMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using Tancoder.Torrent.Client.Messages; 7 | 8 | namespace Tancoder.Torrent.Messages 9 | { 10 | public abstract class WireMessage : Message 11 | { 12 | public int Length { get; set; } 13 | public bool Legal { get; protected set; } = false; 14 | public byte MessageID { get; protected set; } = 0; 15 | public virtual int OnMessageLength(byte[] pstrlen) 16 | { 17 | return Length = ReadInt(pstrlen, 0); 18 | } 19 | 20 | public abstract bool CheackHead(byte[] buffer, int offset); 21 | 22 | public override void Decode(byte[] buffer, int offset, int length) 23 | { 24 | MessageID = ReadByte(buffer, ref offset); 25 | 26 | Legal = true; 27 | } 28 | 29 | public override int Encode(byte[] buffer, int offset) 30 | { 31 | int off = offset; 32 | off += Write(buffer, off, Length); 33 | off += Write(buffer, off, MessageID); 34 | return off - offset; 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Tancoder.Torrent/Metadata.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace Tancoder.Torrent 7 | { 8 | public class Metadata 9 | { 10 | public string Name { get; set; } 11 | public string InfoHash { get; set; } 12 | } 13 | } -------------------------------------------------------------------------------- /Tancoder.Torrent/MonoTorrent.BEncoding/BEncodedList.cs: -------------------------------------------------------------------------------- 1 | // 2 | // BEncodedList.cs 3 | // 4 | // Authors: 5 | // Alan McGovern alan.mcgovern@gmail.com 6 | // 7 | // Copyright (C) 2006 Alan McGovern 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining 10 | // a copy of this software and associated documentation files (the 11 | // "Software"), to deal in the Software without restriction, including 12 | // without limitation the rights to use, copy, modify, merge, publish, 13 | // distribute, sublicense, and/or sell copies of the Software, and to 14 | // permit persons to whom the Software is furnished to do so, subject to 15 | // the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be 18 | // included in all copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 24 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 25 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 26 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 27 | // 28 | 29 | 30 | 31 | using System; 32 | using System.Collections.Generic; 33 | using System.Text; 34 | using System.IO; 35 | 36 | namespace Tancoder.Torrent.BEncoding 37 | { 38 | /// 39 | /// Class representing a BEncoded list 40 | /// 41 | public class BEncodedList : BEncodedValue, IList 42 | { 43 | #region Member Variables 44 | 45 | private List list; 46 | 47 | #endregion 48 | 49 | 50 | #region Constructors 51 | /// 52 | /// Create a new BEncoded List with default capacity 53 | /// 54 | public BEncodedList() 55 | : this(new List()) 56 | { 57 | } 58 | 59 | /// 60 | /// Create a new BEncoded List with the supplied capacity 61 | /// 62 | /// The initial capacity 63 | public BEncodedList(int capacity) 64 | : this(new List(capacity)) 65 | { 66 | 67 | } 68 | 69 | public BEncodedList(IEnumerable list) 70 | { 71 | if (list == null) 72 | throw new ArgumentNullException("list"); 73 | 74 | this.list = new List(list); 75 | } 76 | 77 | private BEncodedList(List value) 78 | { 79 | this.list = value; 80 | } 81 | 82 | #endregion 83 | 84 | 85 | #region Encode/Decode Methods 86 | 87 | 88 | /// 89 | /// Encodes the list to a byte[] 90 | /// 91 | /// The buffer to encode the list to 92 | /// The offset to start writing the data at 93 | /// 94 | public override int Encode(byte[] buffer, int offset) 95 | { 96 | int written = 0; 97 | buffer[offset] = (byte)'l'; 98 | written++; 99 | for (int i = 0; i < this.list.Count; i++) 100 | written += this.list[i].Encode(buffer, offset + written); 101 | buffer[offset + written] = (byte)'e'; 102 | written++; 103 | return written; 104 | } 105 | 106 | /// 107 | /// Decodes a BEncodedList from the given StreamReader 108 | /// 109 | /// 110 | internal override void DecodeInternal(RawReader reader) 111 | { 112 | if (reader.ReadByte() != 'l') // Remove the leading 'l' 113 | throw new BEncodingException("Invalid data found. Aborting"); 114 | 115 | while ((reader.PeekByte() != -1) && (reader.PeekByte() != 'e')) 116 | list.Add(BEncodedValue.Decode(reader)); 117 | 118 | if (reader.ReadByte() != 'e') // Remove the trailing 'e' 119 | throw new BEncodingException("Invalid data found. Aborting"); 120 | } 121 | #endregion 122 | 123 | 124 | #region Helper Methods 125 | /// 126 | /// Returns the size of the list in bytes 127 | /// 128 | /// 129 | public override int LengthInBytes() 130 | { 131 | int length = 0; 132 | 133 | length += 1; // Lists start with 'l' 134 | for (int i=0; i < this.list.Count; i++) 135 | length += this.list[i].LengthInBytes(); 136 | 137 | length += 1; // Lists end with 'e' 138 | return length; 139 | } 140 | #endregion 141 | 142 | 143 | #region Overridden Methods 144 | public override bool Equals(object obj) 145 | { 146 | BEncodedList other = obj as BEncodedList; 147 | 148 | if (other == null) 149 | return false; 150 | 151 | for (int i = 0; i < this.list.Count; i++) 152 | if (!this.list[i].Equals(other.list[i])) 153 | return false; 154 | 155 | return true; 156 | } 157 | 158 | 159 | public override int GetHashCode() 160 | { 161 | int result = 0; 162 | for (int i = 0; i < list.Count; i++) 163 | result ^= list[i].GetHashCode(); 164 | 165 | return result; 166 | } 167 | 168 | 169 | public override string ToString() 170 | { 171 | return System.Text.Encoding.UTF8.GetString(Encode()); 172 | } 173 | #endregion 174 | 175 | 176 | #region IList methods 177 | public void Add(BEncodedValue item) 178 | { 179 | this.list.Add(item); 180 | } 181 | 182 | public void AddRange (IEnumerable collection) 183 | { 184 | list.AddRange (collection); 185 | } 186 | 187 | public void Clear() 188 | { 189 | this.list.Clear(); 190 | } 191 | 192 | public bool Contains(BEncodedValue item) 193 | { 194 | return this.list.Contains(item); 195 | } 196 | 197 | public void CopyTo(BEncodedValue[] array, int arrayIndex) 198 | { 199 | this.list.CopyTo(array, arrayIndex); 200 | } 201 | 202 | public int Count 203 | { 204 | get { return this.list.Count; } 205 | } 206 | 207 | public int IndexOf(BEncodedValue item) 208 | { 209 | return this.list.IndexOf(item); 210 | } 211 | 212 | public void Insert(int index, BEncodedValue item) 213 | { 214 | this.list.Insert(index, item); 215 | } 216 | 217 | public bool IsReadOnly 218 | { 219 | get { return false; } 220 | } 221 | 222 | public bool Remove(BEncodedValue item) 223 | { 224 | return this.list.Remove(item); 225 | } 226 | 227 | public void RemoveAt(int index) 228 | { 229 | this.list.RemoveAt(index); 230 | } 231 | 232 | public BEncodedValue this[int index] 233 | { 234 | get { return this.list[index]; } 235 | set { this.list[index] = value; } 236 | } 237 | 238 | public IEnumerator GetEnumerator() 239 | { 240 | return this.list.GetEnumerator(); 241 | } 242 | 243 | System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() 244 | { 245 | return this.GetEnumerator(); 246 | } 247 | #endregion 248 | } 249 | } -------------------------------------------------------------------------------- /Tancoder.Torrent/MonoTorrent.BEncoding/BEncodedNumber.cs: -------------------------------------------------------------------------------- 1 | // 2 | // BEncodedNumber.cs 3 | // 4 | // Authors: 5 | // Alan McGovern alan.mcgovern@gmail.com 6 | // 7 | // Copyright (C) 2006 Alan McGovern 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining 10 | // a copy of this software and associated documentation files (the 11 | // "Software"), to deal in the Software without restriction, including 12 | // without limitation the rights to use, copy, modify, merge, publish, 13 | // distribute, sublicense, and/or sell copies of the Software, and to 14 | // permit persons to whom the Software is furnished to do so, subject to 15 | // the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be 18 | // included in all copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 24 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 25 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 26 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 27 | // 28 | 29 | 30 | 31 | using System; 32 | using System.IO; 33 | using System.Text; 34 | using System.Collections.Generic; 35 | 36 | namespace Tancoder.Torrent.BEncoding 37 | { 38 | /// 39 | /// Class representing a BEncoded number 40 | /// 41 | public class BEncodedNumber : BEncodedValue, IComparable 42 | { 43 | #region Member Variables 44 | /// 45 | /// The value of the BEncodedNumber 46 | /// 47 | public long Number 48 | { 49 | get { return number; } 50 | set { number = value; } 51 | } 52 | internal long number; 53 | #endregion 54 | 55 | 56 | #region Constructors 57 | public BEncodedNumber() 58 | : this(0) 59 | { 60 | } 61 | 62 | /// 63 | /// Create a new BEncoded number with the given value 64 | /// 65 | /// The inital value of the BEncodedNumber 66 | public BEncodedNumber(long value) 67 | { 68 | this.number = value; 69 | } 70 | 71 | public static implicit operator BEncodedNumber(long value) 72 | { 73 | return new BEncodedNumber(value); 74 | } 75 | #endregion 76 | 77 | 78 | #region Encode/Decode Methods 79 | 80 | /// 81 | /// Encodes this number to the supplied byte[] starting at the supplied offset 82 | /// 83 | /// The buffer to write the data to 84 | /// The offset to start writing the data at 85 | /// 86 | public override int Encode(byte[] buffer, int offset) 87 | { 88 | long number = this.number; 89 | 90 | int written = offset; 91 | buffer[written++] = (byte)'i'; 92 | 93 | if (number < 0) 94 | { 95 | buffer[written++] = (byte)'-'; 96 | number = -number; 97 | } 98 | // Reverse the number '12345' to get '54321' 99 | long reversed = 0; 100 | for (long i = number; i != 0; i /= 10) 101 | reversed = reversed * 10 + i % 10; 102 | 103 | // Write each digit of the reversed number to the array. We write '1' 104 | // first, then '2', etc 105 | for (long i = reversed; i != 0; i /= 10) 106 | buffer[written++] = (byte)(i % 10 + '0'); 107 | 108 | if (number == 0) 109 | buffer[written++] = (byte)'0'; 110 | 111 | // If the original number ends in one or more zeros, they are lost 112 | // when we reverse the number. We add them back in here. 113 | for (long i = number; i % 10 == 0 && number != 0; i /= 10) 114 | buffer[written++] = (byte)'0'; 115 | 116 | buffer[written++] = (byte)'e'; 117 | return written - offset; 118 | } 119 | 120 | 121 | /// 122 | /// Decodes a BEncoded number from the supplied RawReader 123 | /// 124 | /// RawReader containing a BEncoded Number 125 | internal override void DecodeInternal(RawReader reader) 126 | { 127 | int sign = 1; 128 | if (reader == null) 129 | throw new ArgumentNullException("reader"); 130 | 131 | if (reader.ReadByte() != 'i') // remove the leading 'i' 132 | throw new BEncodingException("Invalid data found. Aborting."); 133 | 134 | if (reader.PeekByte() == '-') 135 | { 136 | sign = -1; 137 | reader.ReadByte (); 138 | } 139 | 140 | int letter; 141 | while (((letter = reader.PeekByte()) != -1) && letter != 'e') 142 | { 143 | if(letter < '0' || letter > '9') 144 | throw new BEncodingException("Invalid number found."); 145 | number = number * 10 + (letter - '0'); 146 | reader.ReadByte (); 147 | } 148 | if (reader.ReadByte() != 'e') //remove the trailing 'e' 149 | throw new BEncodingException("Invalid data found. Aborting."); 150 | 151 | number *= sign; 152 | } 153 | #endregion 154 | 155 | 156 | #region Helper Methods 157 | /// 158 | /// Returns the length of the encoded string in bytes 159 | /// 160 | /// 161 | public override int LengthInBytes() 162 | { 163 | long number = this.number; 164 | int count = 2; // account for the 'i' and 'e' 165 | 166 | if (number == 0) 167 | return count + 1; 168 | 169 | if (number < 0) 170 | { 171 | number = -number; 172 | count++; 173 | } 174 | for (long i = number; i != 0; i /= 10) 175 | count++; 176 | 177 | return count; 178 | } 179 | 180 | 181 | public int CompareTo(object other) 182 | { 183 | if (other is BEncodedNumber || other is long || other is int) 184 | return CompareTo((BEncodedNumber)other); 185 | 186 | return -1; 187 | } 188 | 189 | public int CompareTo(BEncodedNumber other) 190 | { 191 | if (other == null) 192 | throw new ArgumentNullException("other"); 193 | 194 | return this.number.CompareTo(other.number); 195 | } 196 | 197 | 198 | public int CompareTo(long other) 199 | { 200 | return this.number.CompareTo(other); 201 | } 202 | #endregion 203 | 204 | 205 | #region Overridden Methods 206 | /// 207 | /// 208 | /// 209 | /// 210 | /// 211 | public override bool Equals(object obj) 212 | { 213 | BEncodedNumber obj2 = obj as BEncodedNumber; 214 | if (obj2 == null) 215 | return false; 216 | 217 | return (this.number == obj2.number); 218 | } 219 | 220 | /// 221 | /// 222 | /// 223 | /// 224 | public override int GetHashCode() 225 | { 226 | return this.number.GetHashCode(); 227 | } 228 | 229 | /// 230 | /// 231 | /// 232 | /// 233 | public override string ToString() 234 | { 235 | return (this.number.ToString()); 236 | } 237 | #endregion 238 | } 239 | } 240 | -------------------------------------------------------------------------------- /Tancoder.Torrent/MonoTorrent.BEncoding/BEncodedString.cs: -------------------------------------------------------------------------------- 1 | // 2 | // BEncodedString.cs 3 | // 4 | // Authors: 5 | // Alan McGovern alan.mcgovern@gmail.com 6 | // 7 | // Copyright (C) 2006 Alan McGovern 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining 10 | // a copy of this software and associated documentation files (the 11 | // "Software"), to deal in the Software without restriction, including 12 | // without limitation the rights to use, copy, modify, merge, publish, 13 | // distribute, sublicense, and/or sell copies of the Software, and to 14 | // permit persons to whom the Software is furnished to do so, subject to 15 | // the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be 18 | // included in all copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 24 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 25 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 26 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 27 | // 28 | 29 | 30 | 31 | using System; 32 | using System.IO; 33 | using System.Collections; 34 | using System.Text; 35 | using Tancoder.Torrent.Common; 36 | using Tancoder.Torrent.Client.Messages; 37 | 38 | namespace Tancoder.Torrent.BEncoding 39 | { 40 | /// 41 | /// Class representing a BEncoded string 42 | /// 43 | public class BEncodedString : BEncodedValue, IComparable 44 | { 45 | #region Member Variables 46 | 47 | /// 48 | /// The value of the BEncodedString 49 | /// 50 | public string Text 51 | { 52 | get { return Encoding.UTF8.GetString(textBytes); } 53 | set { textBytes = Encoding.UTF8.GetBytes(value); } 54 | } 55 | 56 | /// 57 | /// The underlying byte[] associated with this BEncodedString 58 | /// 59 | public byte[] TextBytes 60 | { 61 | get { return this.textBytes; } 62 | } 63 | private byte[] textBytes; 64 | #endregion 65 | 66 | 67 | #region Constructors 68 | /// 69 | /// Create a new BEncodedString using UTF8 encoding 70 | /// 71 | public BEncodedString() 72 | : this(new byte[0]) 73 | { 74 | } 75 | 76 | /// 77 | /// Create a new BEncodedString using UTF8 encoding 78 | /// 79 | /// 80 | public BEncodedString(char[] value) 81 | : this(System.Text.Encoding.UTF8.GetBytes(value)) 82 | { 83 | } 84 | 85 | /// 86 | /// Create a new BEncodedString using UTF8 encoding 87 | /// 88 | /// Initial value for the string 89 | public BEncodedString(string value) 90 | : this(System.Text.Encoding.UTF8.GetBytes(value)) 91 | { 92 | } 93 | 94 | 95 | /// 96 | /// Create a new BEncodedString using UTF8 encoding 97 | /// 98 | /// 99 | public BEncodedString(byte[] value) 100 | { 101 | this.textBytes = value; 102 | } 103 | 104 | 105 | public static implicit operator BEncodedString(string value) 106 | { 107 | return new BEncodedString(value); 108 | } 109 | public static implicit operator BEncodedString(char[] value) 110 | { 111 | return new BEncodedString(value); 112 | } 113 | public static implicit operator BEncodedString(byte[] value) 114 | { 115 | return new BEncodedString(value); 116 | } 117 | #endregion 118 | 119 | 120 | #region Encode/Decode Methods 121 | 122 | 123 | /// 124 | /// Encodes the BEncodedString to a byte[] using the supplied Encoding 125 | /// 126 | /// The buffer to encode the string to 127 | /// The offset at which to save the data to 128 | /// The encoding to use 129 | /// The number of bytes encoded 130 | public override int Encode(byte[] buffer, int offset) 131 | { 132 | int written = offset; 133 | written += Message.WriteAscii(buffer, written, textBytes.Length.ToString ()); 134 | written += Message.WriteAscii(buffer, written, ":"); 135 | written += Message.Write(buffer, written, textBytes); 136 | return written - offset; 137 | } 138 | 139 | 140 | /// 141 | /// Decodes a BEncodedString from the supplied StreamReader 142 | /// 143 | /// The StreamReader containing the BEncodedString 144 | internal override void DecodeInternal(RawReader reader) 145 | { 146 | if (reader == null) 147 | throw new ArgumentNullException("reader"); 148 | 149 | int letterCount; 150 | string length = string.Empty; 151 | 152 | while ((reader.PeekByte() != -1) && (reader.PeekByte() != ':')) // read in how many characters 153 | length += (char)reader.ReadByte(); // the string is 154 | 155 | if (reader.ReadByte() != ':') // remove the ':' 156 | throw new BEncodingException(string.Format("Invalid data found at {0}. Aborting", reader.Position)); 157 | 158 | if (!int.TryParse(length, out letterCount)) 159 | throw new BEncodingException(string.Format("Invalid BEncodedString. Length was '{0}' instead of a number", length)); 160 | 161 | this.textBytes = new byte[letterCount]; 162 | if (reader.Read(textBytes, 0, letterCount) != letterCount) 163 | throw new BEncodingException("Couldn't decode string"); 164 | } 165 | #endregion 166 | 167 | 168 | #region Helper Methods 169 | public string Hex 170 | { 171 | get { return BitConverter.ToString(TextBytes); } 172 | } 173 | 174 | public override int LengthInBytes() 175 | { 176 | // The length is equal to the length-prefix + ':' + length of data 177 | int prefix = 1; // Account for ':' 178 | 179 | // Count the number of characters needed for the length prefix 180 | for (int i = textBytes.Length; i != 0; i = i/10) 181 | prefix += 1; 182 | 183 | if (textBytes.Length == 0) 184 | prefix++; 185 | 186 | return prefix + textBytes.Length; 187 | } 188 | 189 | public int CompareTo(object other) 190 | { 191 | return CompareTo(other as BEncodedString); 192 | } 193 | 194 | 195 | public int CompareTo(BEncodedString other) 196 | { 197 | if (other == null) 198 | return 1; 199 | 200 | int difference=0; 201 | int length = this.textBytes.Length > other.textBytes.Length ? other.textBytes.Length : this.textBytes.Length; 202 | 203 | for (int i = 0; i < length; i++) 204 | if ((difference = this.textBytes[i].CompareTo(other.textBytes[i])) != 0) 205 | return difference; 206 | 207 | if (this.textBytes.Length == other.textBytes.Length) 208 | return 0; 209 | 210 | return this.textBytes.Length > other.textBytes.Length ? 1 : -1; 211 | } 212 | 213 | #endregion 214 | 215 | 216 | #region Overridden Methods 217 | 218 | public override bool Equals(object obj) 219 | { 220 | if (obj == null) 221 | return false; 222 | 223 | BEncodedString other; 224 | if (obj is string) 225 | other = new BEncodedString((string)obj); 226 | else if (obj is BEncodedString) 227 | other = (BEncodedString)obj; 228 | else 229 | return false; 230 | 231 | return Toolbox.ByteMatch(this.textBytes, other.textBytes); 232 | } 233 | 234 | public override int GetHashCode() 235 | { 236 | int hash = 0; 237 | for (int i = 0; i < this.textBytes.Length; i++) 238 | hash += this.textBytes[i]; 239 | 240 | return hash; 241 | } 242 | 243 | public override string ToString() 244 | { 245 | return System.Text.Encoding.UTF8.GetString(textBytes); 246 | } 247 | 248 | #endregion 249 | } 250 | } 251 | -------------------------------------------------------------------------------- /Tancoder.Torrent/MonoTorrent.BEncoding/BEncodingException.cs: -------------------------------------------------------------------------------- 1 | // 2 | // BEncodingException.cs 3 | // 4 | // Authors: 5 | // Alan McGovern alan.mcgovern@gmail.com 6 | // 7 | // Copyright (C) 2006 Alan McGovern 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining 10 | // a copy of this software and associated documentation files (the 11 | // "Software"), to deal in the Software without restriction, including 12 | // without limitation the rights to use, copy, modify, merge, publish, 13 | // distribute, sublicense, and/or sell copies of the Software, and to 14 | // permit persons to whom the Software is furnished to do so, subject to 15 | // the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be 18 | // included in all copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 24 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 25 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 26 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 27 | // 28 | 29 | 30 | 31 | using System; 32 | using System.Text; 33 | using System.Runtime.Serialization; 34 | 35 | namespace Tancoder.Torrent.BEncoding 36 | { 37 | [Serializable] 38 | public class BEncodingException : Exception 39 | { 40 | public BEncodingException() 41 | : base() 42 | { 43 | } 44 | 45 | public BEncodingException(string message) 46 | : base(message) 47 | { 48 | } 49 | 50 | public BEncodingException(string message, Exception innerException) 51 | : base(message, innerException) 52 | { 53 | } 54 | 55 | protected BEncodingException(SerializationInfo info, StreamingContext context) 56 | : base(info, context) 57 | { 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /Tancoder.Torrent/MonoTorrent.BEncoding/ChangeLog: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhangkong828/DHTSpider/49f0055c78ed718bcda77e0466f25c277af9577a/Tancoder.Torrent/MonoTorrent.BEncoding/ChangeLog -------------------------------------------------------------------------------- /Tancoder.Torrent/MonoTorrent.BEncoding/RawReader.cs: -------------------------------------------------------------------------------- 1 | // 2 | // RawReader.cs 3 | // 4 | // Authors: 5 | // Alan McGovern alan.mcgovern@gmail.com 6 | // 7 | // Copyright (C) 2008 Alan McGovern 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining 10 | // a copy of this software and associated documentation files (the 11 | // "Software"), to deal in the Software without restriction, including 12 | // without limitation the rights to use, copy, modify, merge, publish, 13 | // distribute, sublicense, and/or sell copies of the Software, and to 14 | // permit persons to whom the Software is furnished to do so, subject to 15 | // the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be 18 | // included in all copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 24 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 25 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 26 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 27 | // 28 | 29 | using System; 30 | using System.Collections.Generic; 31 | using System.Text; 32 | using System.IO; 33 | 34 | namespace Tancoder.Torrent.BEncoding 35 | { 36 | public class RawReader : Stream 37 | { 38 | bool hasPeek; 39 | Stream input; 40 | byte[] peeked; 41 | bool strictDecoding; 42 | 43 | public bool StrictDecoding 44 | { 45 | get { return strictDecoding; } 46 | } 47 | 48 | public RawReader(Stream input) 49 | : this(input, true) 50 | { 51 | 52 | } 53 | 54 | public RawReader(Stream input, bool strictDecoding) 55 | { 56 | this.input = input; 57 | this.peeked = new byte[1]; 58 | this.strictDecoding = strictDecoding; 59 | } 60 | 61 | public override bool CanRead 62 | { 63 | get { return input.CanRead; } 64 | } 65 | 66 | public override bool CanSeek 67 | { 68 | get { return input.CanSeek; } 69 | } 70 | 71 | public override bool CanWrite 72 | { 73 | get { return false; } 74 | } 75 | 76 | public override void Flush() 77 | { 78 | throw new NotSupportedException(); 79 | } 80 | 81 | public override long Length 82 | { 83 | get { return input.Length; } 84 | } 85 | 86 | public int PeekByte() 87 | { 88 | if (!hasPeek) 89 | hasPeek = Read(peeked, 0, 1) == 1; 90 | return hasPeek ? peeked[0] : -1; 91 | } 92 | 93 | public override int ReadByte() 94 | { 95 | if (hasPeek) 96 | { 97 | hasPeek = false; 98 | return peeked[0]; 99 | } 100 | return base.ReadByte(); 101 | } 102 | 103 | public override long Position 104 | { 105 | get 106 | { 107 | if (hasPeek) 108 | return input.Position - 1; 109 | return input.Position; 110 | } 111 | set 112 | { 113 | if (value != Position) 114 | { 115 | hasPeek = false; 116 | input.Position = value; 117 | } 118 | } 119 | } 120 | 121 | public override int Read(byte[] buffer, int offset, int count) 122 | { 123 | int read = 0; 124 | if (hasPeek && count > 0) 125 | { 126 | hasPeek = false; 127 | buffer[offset] = peeked[0]; 128 | offset++; 129 | count--; 130 | read++; 131 | } 132 | read += input.Read(buffer, offset, count); 133 | return read; 134 | } 135 | 136 | public override long Seek(long offset, SeekOrigin origin) 137 | { 138 | long val; 139 | if (hasPeek && origin == SeekOrigin.Current) 140 | val = input.Seek(offset - 1, origin); 141 | else 142 | val = input.Seek(offset, origin); 143 | hasPeek = false; 144 | return val; 145 | } 146 | 147 | public override void SetLength(long value) 148 | { 149 | throw new NotSupportedException(); 150 | } 151 | 152 | public override void Write(byte[] buffer, int offset, int count) 153 | { 154 | throw new NotSupportedException(); 155 | } 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /Tancoder.Torrent/NoTraceMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Tancoder.Torrent.BEncoding; 3 | 4 | namespace Tancoder.Torrent.Dht.Messages 5 | { 6 | internal class NoTraceMessage : QueryMessage 7 | { 8 | private static ResponseCreator creater = crateByType; 9 | 10 | private static DhtMessage crateByType(BEncodedDictionary dictionary, QueryMessage message) 11 | { 12 | var nodes = ((BEncodedDictionary)dictionary["r"]).Keys.Contains("nodes"); 13 | if (nodes) 14 | return new FindNodeResponse(dictionary, message); 15 | else 16 | return null; 17 | } 18 | 19 | public NoTraceMessage() 20 | : base(new BEncodedDictionary(), creater) 21 | { 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /Tancoder.Torrent/Nodes/ITokenManager.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Tancoder.Torrent.BEncoding; 3 | 4 | namespace Tancoder.Torrent.Dht 5 | { 6 | public interface ITokenManager 7 | { 8 | TimeSpan Timeout { get; set; } 9 | 10 | BEncodedString GenerateToken(Node node); 11 | bool VerifyToken(Node node, BEncodedString token); 12 | } 13 | } -------------------------------------------------------------------------------- /Tancoder.Torrent/Nodes/NodeId.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhangkong828/DHTSpider/49f0055c78ed718bcda77e0466f25c277af9577a/Tancoder.Torrent/Nodes/NodeId.cs -------------------------------------------------------------------------------- /Tancoder.Torrent/Nodes/NodeState.cs: -------------------------------------------------------------------------------- 1 | #if !DISABLE_DHT 2 | // 3 | // NodeState.cs 4 | // 5 | // Authors: 6 | // Jérémie Laval 7 | // 8 | // Copyright (C) 2008 Jérémie Laval 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining 11 | // a copy of this software and associated documentation files (the 12 | // "Software"), to deal in the Software without restriction, including 13 | // without limitation the rights to use, copy, modify, merge, publish, 14 | // distribute, sublicense, and/or sell copies of the Software, and to 15 | // permit persons to whom the Software is furnished to do so, subject to 16 | // the following conditions: 17 | // 18 | // The above copyright notice and this permission notice shall be 19 | // included in all copies or substantial portions of the Software. 20 | // 21 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 22 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 23 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 24 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 25 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 26 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 27 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 28 | // 29 | 30 | 31 | using System; 32 | 33 | namespace Tancoder.Torrent.Dht 34 | { 35 | public enum NodeState 36 | { 37 | Unknown, 38 | Good, 39 | Questionable, 40 | Bad 41 | } 42 | } 43 | #endif -------------------------------------------------------------------------------- /Tancoder.Torrent/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // 有关程序集的一般信息由以下 6 | // 控制。更改这些特性值可修改 7 | // 与程序集关联的信息。 8 | [assembly: AssemblyTitle("Tancoder.Torrent")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Tancoder.Torrent")] 13 | [assembly: AssemblyCopyright("Copyright © 2016")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | //将 ComVisible 设置为 false 将使此程序集中的类型 18 | //对 COM 组件不可见。 如果需要从 COM 访问此程序集中的类型, 19 | //请将此类型的 ComVisible 特性设置为 true。 20 | [assembly: ComVisible(false)] 21 | 22 | // 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID 23 | [assembly: Guid("b3fdea8e-20f3-4be3-b73a-505b45ba9501")] 24 | 25 | // 程序集的版本信息由下列四个值组成: 26 | // 27 | // 主版本 28 | // 次版本 29 | // 生成号 30 | // 修订号 31 | // 32 | //可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值, 33 | // 方法是按如下所示使用“*”: : 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Tancoder.Torrent/Source/Check.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Tancoder.Torrent 4 | { 5 | public static class Check 6 | { 7 | static void DoCheck(object toCheck, string name) 8 | { 9 | if (toCheck == null) 10 | throw new ArgumentNullException(name); 11 | } 12 | 13 | static void IsNullOrEmpty(string toCheck, string name) 14 | { 15 | DoCheck(toCheck, name); 16 | if (toCheck.Length == 0) 17 | throw new ArgumentException("Cannot be empty", name); 18 | } 19 | 20 | public static void Address(object address) 21 | { 22 | DoCheck(address, "address"); 23 | } 24 | 25 | public static void AddressRange(object addressRange) 26 | { 27 | DoCheck(addressRange, "addressRange"); 28 | } 29 | 30 | public static void AddressRanges(object addressRanges) 31 | { 32 | DoCheck(addressRanges, "addressRanges"); 33 | } 34 | 35 | public static void Announces(object announces) 36 | { 37 | DoCheck(announces, "announces"); 38 | } 39 | 40 | public static void BaseDirectory(object baseDirectory) 41 | { 42 | DoCheck(baseDirectory, "baseDirectory"); 43 | } 44 | 45 | internal static void BaseType(Type baseType) 46 | { 47 | DoCheck(baseType, "baseType"); 48 | } 49 | 50 | internal static void Buffer(object buffer) 51 | { 52 | DoCheck(buffer, "buffer"); 53 | } 54 | 55 | internal static void Cache(object cache) 56 | { 57 | DoCheck(cache, "cache"); 58 | } 59 | 60 | public static void Data(object data) 61 | { 62 | DoCheck(data, "data"); 63 | } 64 | 65 | public static void Destination (object destination) 66 | { 67 | DoCheck (destination, "destination"); 68 | } 69 | 70 | public static void Endpoint(object endpoint) 71 | { 72 | DoCheck(endpoint, "endpoint"); 73 | } 74 | 75 | public static void File(object file) 76 | { 77 | DoCheck(file, "file"); 78 | } 79 | 80 | public static void Files(object files) 81 | { 82 | DoCheck(files, "files"); 83 | } 84 | 85 | public static void FileSource(object fileSource) 86 | { 87 | DoCheck(fileSource, "fileSource"); 88 | } 89 | 90 | public static void InfoHash(object infoHash) 91 | { 92 | DoCheck(infoHash, "infoHash"); 93 | } 94 | 95 | public static void Key (object key) 96 | { 97 | DoCheck (key, "key"); 98 | } 99 | 100 | public static void Limiter(object limiter) 101 | { 102 | DoCheck(limiter, "limiter"); 103 | } 104 | 105 | public static void Listener(object listener) 106 | { 107 | DoCheck(listener, "listener"); 108 | } 109 | 110 | public static void Location(object location) 111 | { 112 | DoCheck(location, "location"); 113 | } 114 | 115 | public static void MagnetLink(object magnetLink) 116 | { 117 | DoCheck(magnetLink, "magnetLink"); 118 | } 119 | 120 | public static void Manager(object manager) 121 | { 122 | DoCheck(manager, "manager"); 123 | } 124 | 125 | public static void Mappings (object mappings) 126 | { 127 | DoCheck (mappings, "mappings"); 128 | } 129 | 130 | public static void Metadata(object metadata) 131 | { 132 | DoCheck(metadata, "metadata"); 133 | } 134 | 135 | public static void Name (object name) 136 | { 137 | DoCheck (name, "name"); 138 | } 139 | 140 | public static void Path(object path) 141 | { 142 | DoCheck(path, "path"); 143 | } 144 | 145 | public static void Paths (object paths) 146 | { 147 | DoCheck (paths, "paths"); 148 | } 149 | 150 | public static void PathNotEmpty(string path) 151 | { 152 | IsNullOrEmpty(path, "path"); 153 | } 154 | 155 | public static void Peer (object peer) 156 | { 157 | DoCheck (peer, "peer"); 158 | } 159 | 160 | public static void Peers (object peers) 161 | { 162 | DoCheck (peers, "peers"); 163 | } 164 | 165 | public static void Picker(object picker) 166 | { 167 | DoCheck(picker, "picker"); 168 | } 169 | 170 | public static void Result(object result) 171 | { 172 | DoCheck(result, "result"); 173 | } 174 | 175 | public static void SavePath(object savePath) 176 | { 177 | DoCheck(savePath, "savePath"); 178 | } 179 | 180 | public static void Settings(object settings) 181 | { 182 | DoCheck(settings, "settings"); 183 | } 184 | 185 | internal static void SpecificType(Type specificType) 186 | { 187 | DoCheck(specificType, "specificType"); 188 | } 189 | 190 | public static void Stream(object stream) 191 | { 192 | DoCheck(stream, "stream"); 193 | } 194 | 195 | public static void Torrent(object torrent) 196 | { 197 | DoCheck(torrent, "torrent"); 198 | } 199 | 200 | public static void TorrentInformation(object torrentInformation) 201 | { 202 | DoCheck(torrentInformation, "torrentInformation"); 203 | } 204 | 205 | public static void TorrentSave(object torrentSave) 206 | { 207 | DoCheck(torrentSave, "torrentSave"); 208 | } 209 | 210 | public static void Tracker(object tracker) 211 | { 212 | DoCheck(tracker, "tracker"); 213 | } 214 | 215 | public static void Url(object url) 216 | { 217 | DoCheck(url, "url"); 218 | } 219 | 220 | public static void Uri(Uri uri) 221 | { 222 | DoCheck(uri, "uri"); 223 | } 224 | 225 | public static void Value(object value) 226 | { 227 | DoCheck(value, "value"); 228 | } 229 | 230 | public static void Writer(object writer) 231 | { 232 | DoCheck(writer, "writer"); 233 | } 234 | } 235 | } -------------------------------------------------------------------------------- /Tancoder.Torrent/Source/Enums.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Enums.cs 3 | // 4 | // Authors: 5 | // Alan McGovern alan.mcgovern@gmail.com 6 | // 7 | // Copyright (C) 2006 Alan McGovern 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining 10 | // a copy of this software and associated documentation files (the 11 | // "Software"), to deal in the Software without restriction, including 12 | // without limitation the rights to use, copy, modify, merge, publish, 13 | // distribute, sublicense, and/or sell copies of the Software, and to 14 | // permit persons to whom the Software is furnished to do so, subject to 15 | // the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be 18 | // included in all copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 24 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 25 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 26 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 27 | // 28 | 29 | 30 | 31 | using System; 32 | 33 | namespace Tancoder.Torrent 34 | { 35 | public enum DhtState 36 | { 37 | NotReady, 38 | Initialising, 39 | Ready 40 | } 41 | } 42 | 43 | namespace Tancoder.Torrent.Common 44 | { 45 | public enum ListenerStatus 46 | { 47 | Listening, 48 | PortNotFree, 49 | NotListening 50 | } 51 | 52 | public enum PeerStatus 53 | { 54 | Available, 55 | Connecting, 56 | Connected 57 | } 58 | 59 | public enum Direction 60 | { 61 | None, 62 | Incoming, 63 | Outgoing 64 | } 65 | 66 | public enum TorrentState 67 | { 68 | Stopped, 69 | Paused, 70 | Downloading, 71 | Seeding, 72 | Hashing, 73 | Stopping, 74 | Error, 75 | Metadata 76 | } 77 | 78 | public enum Priority 79 | { 80 | DoNotDownload = 0, 81 | Lowest = 1, 82 | Low = 2, 83 | Normal = 4, 84 | High = 8, 85 | Highest = 16, 86 | Immediate = 32 87 | } 88 | 89 | public enum TrackerState 90 | { 91 | Ok, 92 | Offline, 93 | InvalidResponse 94 | } 95 | 96 | public enum TorrentEvent 97 | { 98 | None, 99 | Started, 100 | Stopped, 101 | Completed 102 | } 103 | 104 | public enum PeerConnectionEvent 105 | { 106 | IncomingConnectionReceived, 107 | OutgoingConnectionCreated, 108 | Disconnected 109 | } 110 | 111 | public enum PieceEvent 112 | { 113 | BlockWriteQueued, 114 | BlockNotRequested, 115 | BlockWrittenToDisk, 116 | HashPassed, 117 | HashFailed 118 | } 119 | 120 | public enum PeerListType 121 | { 122 | NascentPeers, 123 | CandidatePeers, 124 | OptimisticUnchokeCandidatePeers 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /Tancoder.Torrent/Source/IMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Tancoder.Torrent.Client.Messages 6 | { 7 | interface IMessage 8 | { 9 | int ByteLength { get;} 10 | 11 | byte[] Encode(); 12 | int Encode(byte[] buffer, int offset); 13 | 14 | void Decode(byte[] buffer, int offset, int length); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Tancoder.Torrent/Source/Message.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Message.cs 3 | // 4 | // Authors: 5 | // Alan McGovern alan.mcgovern@gmail.com 6 | // 7 | // Copyright (C) 2008 Alan McGovern 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining 10 | // a copy of this software and associated documentation files (the 11 | // "Software"), to deal in the Software without restriction, including 12 | // without limitation the rights to use, copy, modify, merge, publish, 13 | // distribute, sublicense, and/or sell copies of the Software, and to 14 | // permit persons to whom the Software is furnished to do so, subject to 15 | // the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be 18 | // included in all copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 24 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 25 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 26 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 27 | // 28 | 29 | 30 | 31 | using System; 32 | using System.Collections.Generic; 33 | using System.Text; 34 | using System.Net; 35 | 36 | namespace Tancoder.Torrent.Client.Messages 37 | { 38 | public abstract class Message : IMessage 39 | { 40 | public abstract int ByteLength { get; } 41 | 42 | protected int CheckWritten(int written) 43 | { 44 | if (written != ByteLength) 45 | throw new MessageException("Message encoded incorrectly. Incorrect number of bytes written"); 46 | return written; 47 | } 48 | 49 | public abstract void Decode(byte[] buffer, int offset, int length); 50 | 51 | public byte[] Encode() 52 | { 53 | byte[] buffer = new byte[ByteLength]; 54 | Encode(buffer, 0); 55 | return buffer; 56 | } 57 | 58 | public abstract int Encode(byte[] buffer, int offset); 59 | 60 | static public byte ReadByte(byte[] buffer, int offset) 61 | { 62 | return buffer[offset]; 63 | } 64 | 65 | static public byte ReadByte(byte[] buffer, ref int offset) 66 | { 67 | byte b = buffer[offset]; 68 | offset++; 69 | return b; 70 | } 71 | 72 | static public byte[] ReadBytes(byte[] buffer, int offset, int count) 73 | { 74 | return ReadBytes(buffer, ref offset, count); 75 | } 76 | 77 | static public byte[] ReadBytes(byte[] buffer, ref int offset, int count) 78 | { 79 | byte[] result = new byte[count]; 80 | Buffer.BlockCopy(buffer, offset, result, 0, count); 81 | offset += count; 82 | return result; 83 | } 84 | 85 | static public short ReadShort(byte[] buffer, int offset) 86 | { 87 | return ReadShort(buffer, ref offset); 88 | } 89 | 90 | static public short ReadShort(byte[] buffer, ref int offset) 91 | { 92 | short ret = IPAddress.NetworkToHostOrder(BitConverter.ToInt16(buffer, offset)); 93 | offset += 2; 94 | return ret; 95 | } 96 | 97 | static public string ReadString(byte[] buffer, int offset, int count) 98 | { 99 | return ReadString(buffer, ref offset, count); 100 | } 101 | 102 | static public string ReadString(byte[] buffer, ref int offset, int count) 103 | { 104 | string s = System.Text.Encoding.ASCII.GetString(buffer, offset, count); 105 | offset += count; 106 | return s; 107 | } 108 | 109 | static public int ReadInt(byte[] buffer, int offset) 110 | { 111 | return ReadInt(buffer, ref offset); 112 | } 113 | 114 | static public int ReadInt(byte[] buffer, ref int offset) 115 | { 116 | int ret = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(buffer, offset)); 117 | offset += 4; 118 | return ret; 119 | } 120 | 121 | static public long ReadLong(byte[] buffer, int offset) 122 | { 123 | return ReadLong(buffer, ref offset); 124 | } 125 | 126 | static public long ReadLong(byte[] buffer, ref int offset) 127 | { 128 | long ret = IPAddress.NetworkToHostOrder(BitConverter.ToInt64(buffer, offset)); 129 | offset += 8; 130 | return ret; 131 | } 132 | 133 | static public int Write(byte[] buffer, int offset, byte value) 134 | { 135 | buffer[offset] = value; 136 | return 1; 137 | } 138 | 139 | static public int Write(byte[] dest, int destOffset, byte[] src, int srcOffset, int count) 140 | { 141 | Buffer.BlockCopy(src, srcOffset, dest, destOffset, count); 142 | return count; 143 | } 144 | 145 | static public int Write(byte[] buffer, int offset, ushort value) 146 | { 147 | return Write(buffer, offset, (short)value); 148 | } 149 | 150 | static public int Write(byte[] buffer, int offset, short value) 151 | { 152 | offset += Write(buffer, offset, (byte)(value >> 8)); 153 | offset += Write(buffer, offset, (byte)value); 154 | return 2; 155 | } 156 | 157 | static public int Write(byte[] buffer, int offset, int value) 158 | { 159 | offset += Write(buffer, offset, (byte)(value >> 24)); 160 | offset += Write(buffer, offset, (byte)(value >> 16)); 161 | offset += Write(buffer, offset, (byte)(value >> 8)); 162 | offset += Write(buffer, offset, (byte)(value)); 163 | return 4; 164 | } 165 | 166 | static public int Write(byte[] buffer, int offset, uint value) 167 | { 168 | return Write(buffer, offset, (int)value); 169 | } 170 | 171 | static public int Write(byte[] buffer, int offset, long value) 172 | { 173 | offset += Write(buffer, offset, (int)(value >> 32)); 174 | offset += Write(buffer, offset, (int)value); 175 | return 8; 176 | } 177 | 178 | static public int Write(byte[] buffer, int offset, ulong value) 179 | { 180 | return Write(buffer, offset, (long)value); 181 | } 182 | 183 | static public int Write(byte[] buffer, int offset, byte[] value) 184 | { 185 | return Write(buffer, offset, value, 0, value.Length); 186 | } 187 | 188 | static public int WriteAscii(byte[] buffer, int offset, string text) 189 | { 190 | for (int i = 0; i < text.Length; i++) 191 | Write(buffer, offset + i, (byte)text[i]); 192 | return text.Length; 193 | } 194 | } 195 | } -------------------------------------------------------------------------------- /Tancoder.Torrent/Source/ToolBox.cs: -------------------------------------------------------------------------------- 1 | // 2 | // ToolBox.cs 3 | // 4 | // Authors: 5 | // Alan McGovern alan.mcgovern@gmail.com 6 | // 7 | // Copyright (C) 2006 Alan McGovern 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining 10 | // a copy of this software and associated documentation files (the 11 | // "Software"), to deal in the Software without restriction, including 12 | // without limitation the rights to use, copy, modify, merge, publish, 13 | // distribute, sublicense, and/or sell copies of the Software, and to 14 | // permit persons to whom the Software is furnished to do so, subject to 15 | // the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be 18 | // included in all copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 24 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 25 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 26 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 27 | // 28 | 29 | 30 | 31 | using System; 32 | using System.Collections; 33 | using System.Text; 34 | using System.Collections.Generic; 35 | using System.Threading; 36 | //using Tancoder.Torrent.Client.Encryption; 37 | 38 | namespace Tancoder.Torrent.Common 39 | { 40 | public delegate long Operation(T target); 41 | 42 | public static class Toolbox 43 | { 44 | private static Random r = new Random(); 45 | public static int Count(IEnumerable enumerable, Predicate predicate) 46 | { 47 | int count = 0; 48 | 49 | foreach (T t in enumerable) 50 | if (predicate(t)) 51 | count++; 52 | 53 | return count; 54 | } 55 | 56 | public static long Accumulate(IEnumerable enumerable, Operation action) 57 | { 58 | long count = 0; 59 | 60 | foreach (T t in enumerable) 61 | count += action(t); 62 | 63 | return count; 64 | } 65 | 66 | public static void RaiseAsyncEvent(EventHandler e, object o, T args) 67 | where T : EventArgs 68 | { 69 | if (e == null) 70 | return; 71 | 72 | ThreadPool.QueueUserWorkItem(delegate { 73 | if (e != null) 74 | e(o, args); 75 | }); 76 | } 77 | /// 78 | /// Randomizes the contents of the array 79 | /// 80 | /// 81 | /// 82 | public static void Randomize(List array) 83 | { 84 | List clone = new List(array); 85 | array.Clear(); 86 | 87 | while (clone.Count > 0) 88 | { 89 | int index = r.Next(0, clone.Count); 90 | array.Add(clone[index]); 91 | clone.RemoveAt(index); 92 | } 93 | } 94 | 95 | /// 96 | /// Switches the positions of two elements in an array 97 | /// 98 | /// 99 | /// 100 | /// 101 | /// 102 | public static void Switch(IList array, int first, int second) 103 | { 104 | T obj = array[first]; 105 | array[first] = array[second]; 106 | array[second] = obj; 107 | } 108 | 109 | /// 110 | /// Checks to see if the contents of two byte arrays are equal 111 | /// 112 | /// The first array 113 | /// The second array 114 | /// True if the arrays are equal, false if they aren't 115 | public static bool ByteMatch(byte[] array1, byte[] array2) 116 | { 117 | if (array1 == null) 118 | throw new ArgumentNullException("array1"); 119 | if (array2 == null) 120 | throw new ArgumentNullException("array2"); 121 | 122 | if (array1.Length != array2.Length) 123 | return false; 124 | 125 | return ByteMatch(array1, 0, array2, 0, array1.Length); 126 | } 127 | 128 | /// 129 | /// Checks to see if the contents of two byte arrays are equal 130 | /// 131 | /// The first array 132 | /// The second array 133 | /// The starting index for the first array 134 | /// The starting index for the second array 135 | /// The number of bytes to check 136 | /// 137 | public static bool ByteMatch(byte[] array1, int offset1, byte[] array2, int offset2, int count) 138 | { 139 | if (array1 == null) 140 | throw new ArgumentNullException("array1"); 141 | if (array2 == null) 142 | throw new ArgumentNullException("array2"); 143 | 144 | // If either of the arrays is too small, they're not equal 145 | if ((array1.Length - offset1) < count || (array2.Length - offset2) < count) 146 | return false; 147 | 148 | // Check if any elements are unequal 149 | for (int i = 0; i < count; i++) 150 | if (array1[offset1 + i] != array2[offset2 + i]) 151 | return false; 152 | 153 | return true; 154 | } 155 | 156 | //internal static bool HasEncryption(EncryptionTypes available, EncryptionTypes check) 157 | //{ 158 | // return (available & check) == check; 159 | //} 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /Tancoder.Torrent/Source/TorrentException.cs: -------------------------------------------------------------------------------- 1 | // 2 | // TorrentException.cs 3 | // 4 | // Authors: 5 | // Alan McGovern alan.mcgovern@gmail.com 6 | // 7 | // Copyright (C) 2006 Alan McGovern 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining 10 | // a copy of this software and associated documentation files (the 11 | // "Software"), to deal in the Software without restriction, including 12 | // without limitation the rights to use, copy, modify, merge, publish, 13 | // distribute, sublicense, and/or sell copies of the Software, and to 14 | // permit persons to whom the Software is furnished to do so, subject to 15 | // the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be 18 | // included in all copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 24 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 25 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 26 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 27 | // 28 | 29 | 30 | 31 | using System; 32 | using System.Collections.Generic; 33 | using System.Text; 34 | 35 | namespace Tancoder.Torrent.Common 36 | { 37 | [Serializable] 38 | public class TorrentException : Exception 39 | { 40 | public TorrentException() 41 | : base() 42 | { 43 | } 44 | 45 | public TorrentException(string message) 46 | : base(message) 47 | { 48 | } 49 | 50 | public TorrentException(string message, Exception innerException) 51 | : base(message, innerException) 52 | { 53 | } 54 | 55 | public TorrentException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) 56 | : base(info, context) 57 | { 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /Tancoder.Torrent/Source/UriHelper.cs: -------------------------------------------------------------------------------- 1 | // 2 | // System.Web.HttpUtility/HttpEncoder 3 | // 4 | // Authors: 5 | // Patrik Torstensson (Patrik.Torstensson@labs2.com) 6 | // Wictor Wilén (decode/encode functions) (wictor@ibizkit.se) 7 | // Tim Coleman (tim@timcoleman.com) 8 | // Gonzalo Paniagua Javier (gonzalo@ximian.com) 9 | // Marek Habersack 10 | // 11 | // Copyright (C) 2005-2010 Novell, Inc (http://www.novell.com) 12 | // 13 | // Permission is hereby granted, free of charge, to any person obtaining 14 | // a copy of this software and associated documentation files (the 15 | // "Software"), to deal in the Software without restriction, including 16 | // without limitation the rights to use, copy, modify, merge, publish, 17 | // distribute, sublicense, and/or sell copies of the Software, and to 18 | // permit persons to whom the Software is furnished to do so, subject to 19 | // the following conditions: 20 | // 21 | // The above copyright notice and this permission notice shall be 22 | // included in all copies or substantial portions of the Software. 23 | // 24 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 25 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 26 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 27 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 28 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 29 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 30 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 31 | // 32 | 33 | // THIS FILE IS COPIED/PASTED FROM THE MONO SOURCE TREE TO AVOID 34 | // A DEPENDENCY ON SYSTEM.WEB WHICH IS NOT ALWAYS AVAILABLE. 35 | 36 | using System; 37 | using System.Text; 38 | using System.IO; 39 | using System.Collections.Generic; 40 | 41 | namespace Tancoder.Torrent 42 | { 43 | static class UriHelper 44 | { 45 | static readonly char [] hexChars = "0123456789abcdef".ToCharArray (); 46 | 47 | public static string UrlEncode (byte[] bytes) 48 | { 49 | if (bytes == null) 50 | throw new ArgumentNullException ("bytes"); 51 | 52 | var result = new MemoryStream (bytes.Length); 53 | for (int i = 0; i < bytes.Length; i++) 54 | UrlEncodeChar ((char)bytes [i], result, false); 55 | 56 | return Encoding.ASCII.GetString (result.ToArray()); 57 | } 58 | 59 | public static byte [] UrlDecode (string s) 60 | { 61 | if (null == s) 62 | return null; 63 | 64 | var e = Encoding.UTF8; 65 | if (s.IndexOf ('%') == -1 && s.IndexOf ('+') == -1) 66 | return e.GetBytes (s); 67 | 68 | long len = s.Length; 69 | var bytes = new List (); 70 | int xchar; 71 | char ch; 72 | 73 | for (int i = 0; i < len; i++) { 74 | ch = s [i]; 75 | if (ch == '%' && i + 2 < len && s [i + 1] != '%') { 76 | if (s [i + 1] == 'u' && i + 5 < len) { 77 | // unicode hex sequence 78 | xchar = GetChar (s, i + 2, 4); 79 | if (xchar != -1) { 80 | WriteCharBytes (bytes, (char)xchar, e); 81 | i += 5; 82 | } else 83 | WriteCharBytes (bytes, '%', e); 84 | } else if ((xchar = GetChar (s, i + 1, 2)) != -1) { 85 | WriteCharBytes (bytes, (char)xchar, e); 86 | i += 2; 87 | } else { 88 | WriteCharBytes (bytes, '%', e); 89 | } 90 | continue; 91 | } 92 | 93 | if (ch == '+') 94 | WriteCharBytes (bytes, ' ', e); 95 | else 96 | WriteCharBytes (bytes, ch, e); 97 | } 98 | 99 | return bytes.ToArray (); 100 | } 101 | 102 | static void UrlEncodeChar (char c, Stream result, bool isUnicode) { 103 | if (c > ' ' && NotEncoded (c)) { 104 | result.WriteByte ((byte)c); 105 | return; 106 | } 107 | if (c==' ') { 108 | result.WriteByte ((byte)'+'); 109 | return; 110 | } 111 | if ( (c < '0') || 112 | (c < 'A' && c > '9') || 113 | (c > 'Z' && c < 'a') || 114 | (c > 'z')) { 115 | if (isUnicode && c > 127) { 116 | result.WriteByte ((byte)'%'); 117 | result.WriteByte ((byte)'u'); 118 | result.WriteByte ((byte)'0'); 119 | result.WriteByte ((byte)'0'); 120 | } 121 | else 122 | result.WriteByte ((byte)'%'); 123 | 124 | int idx = ((int) c) >> 4; 125 | result.WriteByte ((byte)hexChars [idx]); 126 | idx = ((int) c) & 0x0F; 127 | result.WriteByte ((byte)hexChars [idx]); 128 | } 129 | else { 130 | result.WriteByte ((byte)c); 131 | } 132 | } 133 | 134 | static int GetChar (string str, int offset, int length) 135 | { 136 | int val = 0; 137 | int end = length + offset; 138 | for (int i = offset; i < end; i++) { 139 | char c = str [i]; 140 | if (c > 127) 141 | return -1; 142 | 143 | int current = GetInt ((byte) c); 144 | if (current == -1) 145 | return -1; 146 | val = (val << 4) + current; 147 | } 148 | 149 | return val; 150 | } 151 | 152 | static int GetInt (byte b) 153 | { 154 | char c = (char) b; 155 | if (c >= '0' && c <= '9') 156 | return c - '0'; 157 | 158 | if (c >= 'a' && c <= 'f') 159 | return c - 'a' + 10; 160 | 161 | if (c >= 'A' && c <= 'F') 162 | return c - 'A' + 10; 163 | 164 | return -1; 165 | } 166 | 167 | static bool NotEncoded (char c) 168 | { 169 | return c == '!' || c == '(' || c == ')' || c == '*' || c == '-' || c == '.' || c == '_' || c == '\''; 170 | } 171 | 172 | static void WriteCharBytes (List buf, char ch, Encoding e) 173 | { 174 | if (ch > 255) { 175 | foreach (byte b in e.GetBytes (new char[] { ch })) 176 | buf.Add (b); 177 | } else 178 | buf.Add ((byte)ch); 179 | } 180 | } 181 | } 182 | -------------------------------------------------------------------------------- /Tancoder.Torrent/Source/VersionInfo.cs: -------------------------------------------------------------------------------- 1 | // 2 | // VersionInfo.cs 3 | // 4 | // Authors: 5 | // Alan McGovern alan.mcgovern@gmail.com 6 | // 7 | // Copyright (C) 2006 Alan McGovern 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining 10 | // a copy of this software and associated documentation files (the 11 | // "Software"), to deal in the Software without restriction, including 12 | // without limitation the rights to use, copy, modify, merge, publish, 13 | // distribute, sublicense, and/or sell copies of the Software, and to 14 | // permit persons to whom the Software is furnished to do so, subject to 15 | // the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be 18 | // included in all copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 24 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 25 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 26 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 27 | // 28 | 29 | 30 | 31 | using System; 32 | using System.Collections.Generic; 33 | using System.Reflection; 34 | using System.Runtime.CompilerServices; 35 | using System.Text; 36 | 37 | namespace Tancoder.Torrent.Common 38 | { 39 | public static class VersionInfo 40 | { 41 | /// 42 | /// Protocol string for version 1.0 of Bittorrent Protocol 43 | /// 44 | public static readonly string ProtocolStringV100 = "BitTorrent protocol"; 45 | 46 | public static readonly string DhtClientVersion = "TT00"; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Tancoder.Torrent/Tancoder.Torrent.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {B3FDEA8E-20F3-4BE3-B73A-505B45BA9501} 8 | Library 9 | Properties 10 | Tancoder.Torrent 11 | Tancoder.Torrent 12 | v4.5.2 13 | 512 14 | 15 | 16 | 17 | 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | true 26 | false 27 | 28 | 29 | pdbonly 30 | true 31 | bin\Release\ 32 | TRACE 33 | prompt 34 | 4 35 | true 36 | false 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 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 124 | -------------------------------------------------------------------------------- /Tancoder.Torrent/TransactionId.cs: -------------------------------------------------------------------------------- 1 | #if !DISABLE_DHT 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | using Tancoder.Torrent.BEncoding; 6 | 7 | namespace Tancoder.Torrent.Dht 8 | { 9 | public static class TransactionId 10 | { 11 | private static byte[] current = new byte[2]; 12 | 13 | public static BEncodedString NextId() 14 | { 15 | lock (current) 16 | { 17 | BEncodedString result = new BEncodedString((byte[])current.Clone()); 18 | if (current[0]++ == 255) 19 | current[1]++; 20 | return result; 21 | } 22 | } 23 | } 24 | } 25 | #endif -------------------------------------------------------------------------------- /Tancoder.Torrent/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhangkong828/DHTSpider/49f0055c78ed718bcda77e0466f25c277af9577a/demo.png --------------------------------------------------------------------------------