|
/*
* Created by SharpDevelop.
* User: kelsayfst
* Date: 6/9/2015
* Time: 1:54 PM
*
* To change this template use Tools | Options | Coding | Edit Standard Headers.
*/
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using API = FTKernelAPI.TorrentController;
namespace FTKernelAPI
{
/*
*The kernel written in C++, support multi-thread, stable and fast, very low CPU usage while downloading at a high speed;
*Multiple simultaneous downloads, ability to select download files in one torrent and set file priority;
*Ability to limit the upload speed as well as download speed, avoid influencing other networks procedure;
*Using only one TCP listening port to upload and download;
Support Multi-tracker, and multi-languages code, UDP tracker Protocol v2;
*Fast-Resume, you can download again at other time;
*Decrease the potential damage to the hard disk when high-speed downloading (>500KB/s) by decrease the read / write frequency, extra memory usage is the cost;
*Intelligent Disk Allocating, no long-time disk allocation, no big file, also decrease the disk fragment to almost zero;
*Make the individual file or the direcotry into Torrent file easily;
*/
///
/// !!! Not for commercial usage !!!
/// FTKernelAPI is a kernel API library based on BitTorrent protocol.
/// It is also used in the BitTorrent client - FlashBT.
/// !!! Not for commercial usage !!!
/// <remarks>
///
///
///
public class TorrentController
{
#region FTKernelAPI
#region Consts ...
const string _dllLocation = "FTKernelAPI.dll";
internal const uint CP_ACP = 0;
//Download status
internal const uint DLSTATE_NONE = 0;
internal const uint DLSTATE_ALLOCING = 1;
internal const uint DLSTATE_CHECKING = 2;
internal const uint DLSTATE_DOWNLOAD = 3;
internal const uint DLSTATE_PAUSING = 4;
internal const uint DLSTATE_CHECKEND = 5;
internal const uint DLSTATE_FETALERR = 6;
internal const uint DLSTATE_TERMINATE = 7;
#endregion
#region Context interface ...
///
/// Initialize context
///
/// <param name="lpszIniFile" />kernel configuration file - INI file
/// <returns>
[DllImport(_dllLocation, CallingConvention = CallingConvention.Cdecl)]
static extern bool FTK_Context_Init(string lpszIniFile);
///
/// Release context
///
[DllImport(_dllLocation, CallingConvention = CallingConvention.Cdecl)]
static extern void FTK_Context_Release();
///
/// Context event driver
///
/// <returns>
[DllImport(_dllLocation, CallingConvention = CallingConvention.Cdecl)]
static extern bool FTK_Context_Run();
///
/// Stop context event driver
///
[DllImport(_dllLocation, CallingConvention = CallingConvention.Cdecl)]
static extern void FTK_Context_Stop();
///
/// Is context initialized?
///
/// <returns>
[DllImport(_dllLocation, CallingConvention = CallingConvention.Cdecl)]
static extern bool FTK_Context_IsInit();
///
/// Is context running?
///
/// <returns>
[DllImport(_dllLocation, CallingConvention = CallingConvention.Cdecl)]
static extern bool FTK_Context_IsRunning();
///
/// Return context thread ID
///
/// <returns>
[DllImport(_dllLocation, CallingConvention = CallingConvention.Cdecl)]
static extern long FTK_Context_GetThreadID();
///
/// Return listening port
///
/// <returns>
[DllImport(_dllLocation, CallingConvention = CallingConvention.Cdecl)]
static extern ushort FTK_Context_GetListenPort();
///
/// Return binding ip address
///
/// <returns>
[DllImport(_dllLocation, CallingConvention = CallingConvention.Cdecl)]
static extern string FTK_Context_GetBindIP();
#endregion
#region Downloader interface ...
///
/// Create a new HDownloader handle
///
/// <returns>
[DllImport(_dllLocation, CallingConvention = CallingConvention.Cdecl)]
internal static extern IntPtr FTK_Downloader_Open();
///
/// Destroy a HDownloader handle
///
/// <param name="hDownloader" />
[DllImport(_dllLocation, CallingConvention = CallingConvention.Cdecl)]
internal static extern void FTK_Downloader_Close(IntPtr hDownloader);
///
/// Initialize a HDownloader
///
/// <param name="hDownloader" />a HDownloader handle
/// <param name="lpszTorrentFileName" />a torrent file name
/// <param name="pPreAllocFile" />a array of preallocated files, 0->no, 1->yes
/// <param name="nPreAllocFileLen" />length of preallocated array
/// <param name="bOnlyCheckFile" />only verify data of files
/// <param name="lpszDestFileName" />the downloaded filename
/// <param name="lpszConfig" />kernel configuration file - INI file
/// <param name="lpszLogFileName" />output log filename
/// <param name="lpszStatusFileName" />downloading status filename
/// <param name="lpszDesKey" />DES-EDE2 password
/// <param name="nCodePage" />code page of the torrent file
/// <returns>
[DllImport(_dllLocation, CallingConvention = CallingConvention.Cdecl)]
internal static extern bool FTK_Downloader_Init(
IntPtr hDownloader,
//[MarshalAs(UnmanagedType.LPTStr)]
string lpszTorrentFileName,
byte[] pPreAllocFile,
int nPreAllocFileLen,
bool bOnlyCheckFile,
//[MarshalAs(UnmanagedType.LPTStr)]
string lpszDestFileName,
//[MarshalAs(UnmanagedType.LPTStr)]
string lpszConfig,
//[MarshalAs(UnmanagedType.LPTStr)]
string lpszLogFileName,
//[MarshalAs(UnmanagedType.LPTStr)]
string lpszStatusFileName,
//[MarshalAs(UnmanagedType.LPTStr)]
string lpszDesKey,
uint nCodePage);
///
/// Release downloader handle
///
/// <param name="hDownloader" />
/// <returns>
[DllImport(_dllLocation, CallingConvention = CallingConvention.Cdecl)]
internal static extern bool FTK_Downloader_Release(IntPtr hDownloader);
///
/// Execute downloader
///
/// <param name="hDownloader" />
/// <returns>
[DllImport(_dllLocation, CallingConvention = CallingConvention.Cdecl)]
internal static extern bool FTK_Downloader_Execute(IntPtr hDownloader);
///
/// Pause downloader
///
/// <param name="hDownloader" />
[DllImport(_dllLocation, CallingConvention = CallingConvention.Cdecl)]
internal static extern void FTK_Downloader_Pause(IntPtr hDownloader);
///
/// Resume downloader
///
/// <param name="hDownloader" />
[DllImport(_dllLocation, CallingConvention = CallingConvention.Cdecl)]
internal static extern void FTK_Downloader_Resume(IntPtr hDownloader);
///
/// Is downloader intialized?
///
/// <param name="hDownloader" />
/// <returns>
[DllImport(_dllLocation, CallingConvention = CallingConvention.Cdecl)]
internal static extern bool FTK_Downloader_IsInit(IntPtr hDownloader);
///
/// Return downloader state
///
/// <param name="hDownloader" />
/// <returns>
[DllImport(_dllLocation, CallingConvention = CallingConvention.Cdecl)]
internal static extern uint FTK_Downloader_GetState(IntPtr hDownloader);
#endregion
#region Torrent file interface ...
[DllImport(_dllLocation, CallingConvention = CallingConvention.Cdecl)]
internal static extern IntPtr FTK_Torrent_Open(
//[MarshalAs(UnmanagedType.LPTStr)]
string lpszFileName,
uint nCodePage,
//[MarshalAs(UnmanagedType.LPTStr)]
string lpszDesKey);
[DllImport(_dllLocation, CallingConvention = CallingConvention.Cdecl)]
internal static extern void FTK_Torrent_Close(IntPtr hTorrentFile);
[DllImport(_dllLocation, CallingConvention = CallingConvention.Cdecl)]
internal static extern string FTK_Torrent_GetHexInfoHash(IntPtr hTorrentFile);
[DllImport(_dllLocation, CallingConvention = CallingConvention.Cdecl)]
internal static extern string FTK_Torrent_GetTorrentName(IntPtr hTorrentFile);
[DllImport(_dllLocation, CallingConvention = CallingConvention.Cdecl)]
internal static extern int FTK_Torrent_GetFilesCount(IntPtr hTorrentFile);
[DllImport(_dllLocation, CallingConvention = CallingConvention.Cdecl)]
internal static extern int FTK_Torrent_IsCipherTorrent(
//[MarshalAs(UnmanagedType.LPTStr)]
string lpszFileName);
///
/// Get the total file size to transfer
///
/// <param name="hTorrentFile" />
/// <returns>
[DllImport(_dllLocation, CallingConvention = CallingConvention.Cdecl)]
internal static extern uint FTK_Torrent_GetFileSize(IntPtr hTorrentFile);
#endregion
#region Globals settings ...
///
/// Add torrent into SHA1 list
///
/// <param name="lpszSHA1" />
/// <param name="hDownloader" />
[DllImport(_dllLocation, CallingConvention = CallingConvention.Cdecl)]
internal static extern void FTK_GlobalVar_AddTorrentSHA1(
//[MarshalAs(UnmanagedType.LPTStr)]
string lpszSHA1,
IntPtr hDownloader);
///
/// Remove torrent from SHA1 list
///
/// <param name="lpszSHA1" />
[DllImport(_dllLocation, CallingConvention = CallingConvention.Cdecl)]
internal static extern void FTK_GlobalVar_RemoveTorrentSHA1(
//[MarshalAs(UnmanagedType.LPTStr)]
string lpszSHA1);
#endregion
#region Downloader statistic information interface ...
///
/// Get the size of having received data for all file
///
/// <param name="hDownloader" />
/// <returns>
[DllImport(_dllLocation, CallingConvention = CallingConvention.Cdecl)]
internal static extern uint FTK_Stat_GetTotalFileHaveSize(IntPtr hDownloader);
///
/// Get the size of having received data for a file
///
/// <param name="hDownloader" />
/// <returns>
[DllImport(_dllLocation, CallingConvention = CallingConvention.Cdecl)]
internal static extern uint FTK_Stat_GetSelectedFileHaveSize(IntPtr hDownloader);
///
/// Get downloading rate
///
/// <param name="hDownloader" />
/// <returns>
[DllImport(_dllLocation, CallingConvention = CallingConvention.Cdecl)]
internal static extern double FTK_Stat_GetDownloadRate(IntPtr hDownloader);
///
/// Get upload rate
///
/// <param name="hDownloader" />
/// <returns>
[DllImport(_dllLocation, CallingConvention = CallingConvention.Cdecl)]
internal static extern double FTK_Stat_GetUploadRate(IntPtr hDownloader);
///
/// Get the left time to download
///
/// <param name="hDownloader" />
/// <returns>
[DllImport(_dllLocation, CallingConvention = CallingConvention.Cdecl)]
internal static extern double FTK_Stat_GetLeftTime(IntPtr hDownloader);
#endregion
#endregion
static bool StartContext()
{
//Debug.Assert(!FTK_Context_IsInit());
if (!FTK_Context_Init("Config.ini")) {
return false;
}
//Debug.Assert(FTK_Context_IsRunning() == false);
FTK_Context_Run();
return FTK_Context_IsRunning() == true;
}
static bool StopContext()
{
if (FTK_Context_IsInit()) {
FTK_Context_Stop();
FTK_Context_Release();
return true;
}
return false;
}
static List<torrentmanager> torrents; // The list where all the torrentManagers will be stored that the engine gives us
static Top10Listener listener; // This is a subclass of TraceListener which remembers the last 20 statements sent to it
public readonly string TorrentsPath;
public readonly string DownloadsPath;
public readonly string BasePath;
public readonly string LogPath;
static TorrentController()
{
Debug.WriteLine(StartContext().ToString());
Application.Idle += delegate(object sender, EventArgs e) {
for (int i = 0; i < torrents.Count; i++) {
torrents[i].Tick(Environment.TickCount);
}
};
}
static void AppendSeperator(StringBuilder sb)
{
AppendFormat(sb, "", null);
AppendFormat(sb, "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -", null);
AppendFormat(sb, "", null);
}
static void AppendFormat(StringBuilder sb, string str, params object[] formatting)
{
if (formatting != null)
sb.AppendFormat(str, formatting);
else
sb.Append(str);
sb.AppendLine();
}
#region old ...
/*public static bool StartDownload(string strTorrentFile)
{
IntPtr torrentFile = FTK_Torrent_Open(strTorrentFile, CP_ACP, null);
if (IntPtr.Zero == torrentFile) {
return false;
}
string strKeyValue = FTK_Torrent_GetHexInfoHash(torrentFile);
strKeyValue.Replace("%", "");
IntPtr downloader = FTK_Downloader_Open();
bool bRet = FTK_Downloader_Init(
downloader,
strTorrentFile,
IntPtr.Zero,//arryPreAllocFile.GetData(),
0,//arryPreAllocFile.GetSize(),
false,
downloadsPath + "\\" + FTK_Torrent_GetTorrentName(torrentFile),
basePath + "Config.INI",
logPath + "\\" + FTK_Torrent_GetTorrentName(torrentFile) + ".log",
basePath + strKeyValue + ".status",
null,
CP_ACP);
if (false == bRet) {
FTK_Downloader_Close(downloader);
downloader = IntPtr.Zero;
return false;
}
bRet = FTK_Downloader_Execute(downloader);
if (false == bRet) {
FTK_Downloader_Close(downloader);
downloader = IntPtr.Zero;
return false;
}
FTK_GlobalVar_AddTorrentSHA1(strKeyValue, downloader);
return true;
}
public static bool StopDownload(string strKeyValue, IntPtr downloader)
{
FTK_GlobalVar_RemoveTorrentSHA1(strKeyValue);
FTK_Downloader_Close(downloader);
downloader = IntPtr.Zero;
return true;
}
*/
#endregion
public static TorrentController Instance = new TorrentController("");
public TorrentController(string configFile)
{
/* Generate the paths to the folder we will save .torrent files to and where we download files to */
BasePath = Environment.CurrentDirectory.Replace(@"\", "\\"); // This is the directory we are currently in
TorrentsPath = Path.Combine(BasePath, "Torrents").Replace(@"\", "\\"); // This is the directory we will save .torrents to
DownloadsPath = Path.Combine(BasePath, "Downloads").Replace(@"\", "\\"); // This is the directory we will save downloads to
LogPath = Path.Combine(BasePath, "Log").Replace(@"\", "\\");
torrents = new List<torrentmanager>(); // This is where we will store the torrentmanagers
listener = new Top10Listener(10);
// If the torrentsPath does not exist, we want to create it
if (!Directory.Exists(TorrentsPath))
Directory.CreateDirectory(TorrentsPath);
// If the downloadsPath does not exist, we want to create it
if (!Directory.Exists(DownloadsPath))
Directory.CreateDirectory(DownloadsPath);
// If the logPath does not exist, we want to create it
if (!Directory.Exists(LogPath))
Directory.CreateDirectory(LogPath);
}
~ TorrentController()
{
StopAll();
StopContext();
}
public static TorrentManager[] AddTorrent(string[] filenames) {
Torrent torrent = null;
TorrentManager torrentManager = null;
for (int i = 0; i < filenames.Length; i++) {
string filename = filenames[i].Replace(@"\", "\\");
try {
torrent = Torrent.Load(filename);
} catch (Exception) {
torrent = null;
continue;
}
if(torrent != null) {
torrentManager = TorrentController.Instance.AddTorrent(torrent);
try {
torrentManager.Start();
} catch (Exception) {
torrentManager = null;
continue;
}
}
}
TorrentController.Instance.StartAll();
return new List<torrentmanager>(torrents).ToArray();
}
public TorrentManager AddTorrent(Torrent torrent)
{
TorrentManager tm = new TorrentManager(this, torrent);
lock(torrents) {
torrents.Add(tm);
}
try {
tm.Start();
} catch (Exception) {
}
return tm;
}
public void StartAll()
{
ThreadPool.QueueUserWorkItem(
delegate (object o) {
for (int i = 0; i < torrents.Count; i++) {
try {
torrents[i].Start();
} catch (Exception) {
}
}
});
}
public void StopAll()
{
//ThreadPool.QueueUserWorkItem(
// delegate (object o) {
for (int i = 0; i < torrents.Count; i++)
torrents[i].Stop();
// });
}
}
///
///
///
public class TorrentManager {
public readonly Torrent Torrent; // Torrent
TorrentController Controller; // TorrentController
bool IsPaused; // Is the Downloader paused or not
IntPtr Handle; // Downloader Handle
public EventHandler OnUpdate;
public double DownloadRate;
public double UploadRate;
public uint State;
public double TimeLeft;
public uint TotalFileHaveSize;
public int PercentComplected;
public TorrentManager(TorrentController controller, Torrent torrent)
{
Controller = controller;
Torrent = torrent;
}
internal void Tick(int milliseconds)
{
// post process events
if (IntPtr.Zero != Handle) {
State = API.FTK_Downloader_GetState(Handle);
if (State == API.DLSTATE_CHECKING) {
}
if (State < API.DLSTATE_DOWNLOAD ||
State >= API.DLSTATE_FETALERR ) {
return;
}
TotalFileHaveSize = API.FTK_Stat_GetTotalFileHaveSize(Handle);
DownloadRate = API.FTK_Stat_GetDownloadRate(Handle);
UploadRate = API.FTK_Stat_GetUploadRate(Handle);
TimeLeft = API.FTK_Stat_GetLeftTime(Handle);
PercentComplected = PERCENT((uint)TotalFileHaveSize, (uint)Torrent.TotalFileSize);
}
if(OnUpdate != null)
OnUpdate(this, new EventArgs());
}
static int PERCENT(uint n, uint d) {
return (int)((100 * (double)(n)) / (double)(d));
}
public void Start()
{
if(Handle != IntPtr.Zero) {
return;
}
//IsPaused = false;
if(IsPaused) {
API.FTK_Downloader_Resume(Handle);
return;
}
Handle = API.FTK_Downloader_Open();
if (IntPtr.Zero == Handle) {
throw new ExternalException("Couldn't download file " + Torrent.Name);
}
byte[] arryPreAllocFile = new byte[Torrent.FilesCount];
int size = Torrent.FilesCount;
//IntPtr pointer = Marshal.AllocHGlobal(size);
// Copy the array to unmanaged memory.
//Marshal.Copy(arryPreAllocFile, 0, pointer, arryPreAllocFile.Length);
bool bRet = API.FTK_Downloader_Init(
Handle,
Torrent.FullFileName,
arryPreAllocFile,
size,
false,
Controller.DownloadsPath + "\\" + Torrent.Name,
Controller.BasePath + "\\" + "Config.INI",
Controller.LogPath + "\\"+ Torrent.Name + ".log",
Controller.BasePath + "\\" + Torrent.HexInfoHash + ".status",
null,
API.CP_ACP);
if (bRet == false) {
API.FTK_Downloader_Release(Handle);
API.FTK_Downloader_Close(Handle);
Handle = IntPtr.Zero;
throw new ExternalException("Couldn't download file " + Torrent.Name);
}
bRet = API.FTK_Downloader_Execute(Handle);
if (bRet == false) {
API.FTK_Downloader_Release(Handle);
API.FTK_Downloader_Close(Handle);
Handle = IntPtr.Zero;
throw new ExternalException("Couldn't download file " + Torrent.Name);
}
API.FTK_GlobalVar_AddTorrentSHA1(Torrent.HexInfoHash, Handle);
}
public void Stop()
{
//TogglePause();
if(Handle != IntPtr.Zero) {
API.FTK_GlobalVar_RemoveTorrentSHA1(Torrent.HexInfoHash);
API.FTK_Downloader_Release(Handle);
API.FTK_Downloader_Close(Handle);
Handle = IntPtr.Zero;
IsPaused = false;
}
}
public void Pause()
{
TogglePause();
}
public void Resume()
{
TogglePause();
}
void TogglePause()
{
if(Handle != IntPtr.Zero) {
IsPaused = !IsPaused;
if(IsPaused) {
API.FTK_Downloader_Pause(Handle);
} else {
API.FTK_Downloader_Resume(Handle);
}
}
}
}
///
/// Torrent file interface
///
public class Torrent {
IntPtr Handle; // Torrent Handle
public readonly string FullFileName; // Path + Filename
public readonly string Name; // Filename
public readonly string HexInfoHash; // HexInfoHash
public readonly int FilesCount; // FilesCount
public readonly uint TotalFileSize; // TotalFileSize
protected Torrent(string torrentFileName)
{
FullFileName = torrentFileName.Replace(@"\", "\\");
int boolean = API.FTK_Torrent_IsCipherTorrent(FullFileName);
Handle = API.FTK_Torrent_Open(FullFileName, API.CP_ACP, null);
if (IntPtr.Zero == Handle) {
throw new ExternalException("Couldn't open torrent file " + torrentFileName);
}
Name = API.FTK_Torrent_GetTorrentName(Handle);
HexInfoHash = API.FTK_Torrent_GetHexInfoHash(Handle).Replace("%", "");
FilesCount = API.FTK_Torrent_GetFilesCount(Handle);
TotalFileSize = API.FTK_Torrent_GetFileSize(Handle);
API.FTK_Torrent_Close(Handle);
}
public static Torrent Load(string torrentFileName)
{
return new Torrent(torrentFileName);
}
}
///
///
///
public class TorrentCreator {
IntPtr Handle;
}
///
/// Keeps track of the X most recent number of events recorded by the listener.
/// X is specified in the constructor
///
public class Top10Listener : TraceListener
{
private int capacity;
private LinkedList<string> traces;
public Top10Listener(int capacity)
{
this.capacity = capacity;
this.traces = new LinkedList<string>();
}
public override void Write(string message)
{
lock (traces)
traces.Last.Value += message;
}
public override void WriteLine(string message)
{
lock (traces)
{
if (traces.Count >= capacity)
traces.RemoveFirst();
traces.AddLast(message);
}
}
public void ExportTo(TextWriter output)
{
lock (traces)
foreach (string s in this.traces)
output.WriteLine(s);
}
}
}
All things come to one, who is patient.
modified 11-Jun-15 11:42am.
|
|
|
|
|
Hi,
Please advice me your FTKernelAPI BitTorrent Protocol Library & Demo Source is not working with downloading abc.torrnet having 1080p.
Please advise me or if possible could you provide me latest updated library for FTKernelAPI BitTorrent Protocol Library & Demo Source.
|
|
|
|
|
Hi,
I downloaded the SDK with the Delphi demo in it, and tried it in D7. It runs fine, no errors, but when you click "Start" to download a torrent it says "starting download" or whatever, but doesn't download anything. Any idea what I might be doing wrong? Thanks.
|
|
|
|
|
Hi!
Why some ".torrent" files are not loaded?
The function FTK_Torrent_Open() returns NULL!
Please help me ...
modified on Friday, July 10, 2009 12:49 PM
|
|
|
|
|
I Am Interested In Creating A Tracker Is Asp.Net. This Of Course Is A Peer Protocol For BitTorrent. Have You Heard Of Anyone Porting The Many PHP Versions Of Tracker Scripts? Did You Per Chance Write A .Net Or Even Windows Tracker To Test This Or Did You Simply Test It On The Many Public Sites?
A .Net Tracker Seems To Only Need A Simple Script To Respond To The Peer Application With These Vars:
info_hash
peer_id
ip
port
uploaded
downloaded
left
event
And Then Of Course Keep A Simple Database(Likley SQL Driven) Of peers(IP/Port), peerids To Return To The App.
In Addition A Smarter Script Could Also Keep Track Of Current Seeders/Leechers, Total Downloads Etc..
However That Would Require An Outside Process To Rid Database Of Any Peers That Did Not Respond With A Completed Event And Or Respond In The Alloted Next Announce Time.
Have You Heard Of Any Work Being Done Of That Kind Of Script In .Net. I Have Only Found One On SourceForge But Its In The Planning Stages.
Thanks For Your Time
Bobby
There Is A Crack In Everything, Thats How The Light Gets In :->
|
|
|
|
|
If someone can help me on how to implement this into my Borland C++ Builder 6 program, I would be extremly happy!
The ones who can do that will ofource get paid!
If you wan't get in touch with me mail me at jesper @ jptorrent.com
|
|
|
|
|
Yes, If you like, you can use it in your C# or VB.net project or program. I am very glad to help you to know hwo to do this. Please contact me by MSN:FlashBT@Hotmail.com
Hwycheng Leo - a programer, at work on p2p and instant message system. website:http://www.hwysoft.com
|
|
|
|
|
It's totally free, no advertisement, no spyware. Enjoy it freelly in yourself.
Hwycheng Leo - a programer, at work on p2p and instant message system. website:http://www.hwysoft.com
|
|
|
|