mirror of https://github.com/BOINC/boinc.git
Moved source code into a separate repo.
See: https://github.com/BOINC/boinc-bittorrent
This commit is contained in:
parent
ac7ac7986d
commit
49b671f523
|
@ -1,25 +0,0 @@
|
|||
-----------------
|
||||
Setting it all up
|
||||
-----------------
|
||||
The .torrent cache will need to know where to look for the files that are going
|
||||
to be sent to the clients. Usually this will be the project download directory.
|
||||
|
||||
<insert more settings here>
|
||||
|
||||
Also, you need to run the database scripts in the /database/-directory in order
|
||||
to set up your database for bittorrent tracking.
|
||||
|
||||
------------------
|
||||
How to enable this
|
||||
------------------
|
||||
By default Bittorrent support is turned off on both server and client. You must
|
||||
enable bittorrent in your server configuration files by doing this:
|
||||
|
||||
<insert useful guide here>
|
||||
|
||||
You must also convince your users that enabling Bittorrent support on their clients
|
||||
is a useful way to help the project. It is a good idea to let them know that
|
||||
setting the "Maximum upload rate" under general preferences enables them to
|
||||
control just how much of their outgoing bandwidth is ever used. A setting of 70%
|
||||
or less of their actual bandwidth is recommended to avoid creating latency issues
|
||||
on their connection.
|
|
@ -1,47 +0,0 @@
|
|||
NOTE: THE CODE IN THIS DIRECTORY DOESN'T CURRENTLY WORK,
|
||||
AND IS NOT BEING MAINTAINED.
|
||||
IT'S HERE IN CASE SOMEONE WANTS TO REVIVE IT.
|
||||
|
||||
-----------------------------------
|
||||
Bittorrent file distribution system
|
||||
-----------------------------------
|
||||
When several workunits require the same file (for instance any particularly big
|
||||
application file) it is really a waste to use a central server to distribute this
|
||||
file. First of all a central server requires lots of bandwidth - which may be
|
||||
quite expensive. Secondly getting 10'000 requests for the same multi-megabyte
|
||||
file may be too much for even the largest of servers.
|
||||
|
||||
The solution is to harness the power of peer-to-peer computing in the domain of
|
||||
volunteer and desktop grid computing by allowing the clients to share pieces of the
|
||||
files they are downloading.
|
||||
|
||||
How it works
|
||||
------------
|
||||
Since noone can be trusted, "Bob" (a client) will need some way of knowing if "Eve"
|
||||
(another client) sent him a valid piece of the original file. To enable him to do
|
||||
so Bob has downloaded a .torrent from the project servers. The .torrent describes
|
||||
the file he is downloading; it contains hash values for each piece so that he can
|
||||
check whether "Eve" is trying to cheat him.
|
||||
|
||||
If "Alice" also wants to download the same file as "Bob" they can each fetch a
|
||||
different piece from the project servers and then share the pieces. Seen from
|
||||
"Bob" and "Alice"'s perspective this potentially doubles the download rate (if you
|
||||
see it from the project perspective it cuts the required network bandwidth in half).
|
||||
As more people join the synergetic effect increases dramatically.
|
||||
|
||||
Isn't Bittorrent illegal?
|
||||
-------------------------
|
||||
Bittorrent is a protocol for sharing files across the internet. As such it cannot
|
||||
be illegal in itself - it is what you do with it that matters.
|
||||
If you take a look at all the filesharing protocols out there Bittorrent seems to
|
||||
be the one that has been taken into widespread use in the whitehat part of the
|
||||
internet. Several major companies, including the movie industry, have adopted the
|
||||
technology because of its unique ability to distribute load. To name a few uses:
|
||||
- Bittorrent.com (Works with the movie industry, sells movies and shows)
|
||||
- Blizzard Entertainment (Uses BT to distribute data patches for their World of
|
||||
Warcraft game)
|
||||
- EletricSheep screensaver (Uses BT to distribute computed "dreams")
|
||||
|
||||
How do I enable this?
|
||||
---------------------
|
||||
Have a look at the INSTALL file located in the same directory as this file.
|
|
@ -1,100 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* This file contains the main portion of the tracker.
|
||||
* The tracker is the central part of any Bittorrent system. The tracker coordinates the downloads
|
||||
* between peers and ensures that only valid files are tracked. It is queried multiple times during
|
||||
* any Bittorrent-enabled download - usually whenever a peer wants to expand its list of other peers.
|
||||
*
|
||||
* The tracker also keeps track of how the downloads are progressing.
|
||||
*/
|
||||
$cvs_version_tracker[]="\$Id$"; //Generated automatically - do not edit
|
||||
|
||||
require_once("config.php");
|
||||
|
||||
function trackerError($error){
|
||||
echo BDictionary::toEncoded(array("failure_reason"=>$error));
|
||||
exit;
|
||||
}
|
||||
|
||||
$info_hash = rawurldecode($_GET["info_hash"]);
|
||||
if (strlen($info_hash)!=20) throw new IllegalArgumentException("Malformed infohash key (length ".strlen($info_hash).")");
|
||||
$peer_id = $_GET["peer_id"];
|
||||
if (strlen($peer_id)!=20) throw new IllegalArgumentException("Malformed peer ID (".strlen($peer_id).")");
|
||||
$port = $_GET["port"];
|
||||
if (!is_numeric($port)) throw new IllegalArgumentException("Non-numeric port supplied");
|
||||
$event = $_GET["event"];
|
||||
$ip = $_GET["ip"];
|
||||
$uploaded = $_GET["uploaded"];
|
||||
if (!$uploaded) $uploaded = 0;
|
||||
if (!is_numeric($uploaded)) throw new IllegalArgumentException("Non-numeric upload amount specified");
|
||||
$downloaded = $_GET["downloaded"]; if (!$downloaded) $downloaded = 0;
|
||||
if (!is_numeric($downloaded)) throw new IllegalArgumentException("Non-numeric download amount specified");
|
||||
|
||||
if (!$ip){
|
||||
$ip = $_SERVER["REMOTE_ADDR"];
|
||||
}
|
||||
|
||||
// Is the IP banned?
|
||||
db_init();
|
||||
if (isIPBanned($ip)){
|
||||
trackerError("Banned IP: ".$ip);
|
||||
}
|
||||
|
||||
// Check that the info_hash is one that we allow:
|
||||
$queryHandle = mysql_query("SELECT * from bittorrent_files where info_hash=\"".process_user_text($info_hash)."\""); echo mysql_error();
|
||||
if (!mysql_num_rows($queryHandle)){
|
||||
trackerError("The tracker does not allow tracking of this file:".$info_hash . " [] ".$_GET["info_hash"]);
|
||||
}
|
||||
$infoHashObject = mysql_fetch_object($queryHandle);
|
||||
|
||||
// If the peer is actively doing something let's update the DB
|
||||
if ($event=="started" || $event=="stopped" || $event=="completed"){
|
||||
mysql_query("REPLACE into bittorrent_peers SET fileid=".$infoHashObject->id.", peerid=\"".process_user_text($peer_id)."\", ip=\"".process_user_text($ip)."\", port=\"".process_user_text($port)."\", status=\"".$event."\", uploaded=".process_user_text($uploaded).", downloaded=".process_user_text($downloaded).", timestamp=".time());
|
||||
echo mysql_error();
|
||||
} else {
|
||||
mysql_query("REPLACE delayed into bittorrent_peers SET fileid=".$infoHashObject->id.", peerid=\"".process_user_text($peer_id)."\", ip=\"".process_user_text($ip)."\", port=\"".process_user_text($port)."\", uploaded=".process_user_text($uploaded).", downloaded=".process_user_text($downloaded).", timestamp=".time());
|
||||
echo mysql_error();
|
||||
}
|
||||
|
||||
// Always send back a random selection of peers who are downloading a file with the same info_hash
|
||||
$queryHandle = mysql_query("SELECT * from bittorrent_peers WHERE fileid = ".$infoHashObject->id." order by RAND() limit ".MAX_INFO_HASH_PEERS); echo mysql_error();
|
||||
$peerList = array();
|
||||
while ($dbPeer = mysql_fetch_object($queryHandle)){
|
||||
$peer = array("peer id"=>$dbPeer->peerid, "ip"=>$dbPeer->ip, "port"=>intval($dbPeer->port));
|
||||
$peerList[] = new BElement(BDictionary::toEncoded($peer));
|
||||
}
|
||||
|
||||
// Get some statistical counts
|
||||
$queryHandle = mysql_query("SELECT count(fileid) as complete from bittorrent_peers where fileid = '".$infoHashObject->id."' and status='completed'");
|
||||
$data = mysql_fetch_object($queryHandle);
|
||||
$complete = intval($data->complete);
|
||||
$queryHandle = mysql_query("SELECT count(fileid) as incomplete from bittorrent_peers where fileid = '".$infoHashObject->id."' and status!='completed'");
|
||||
$data = mysql_fetch_object($queryHandle);
|
||||
$incomplete = intval($data->incomplete);
|
||||
|
||||
|
||||
$peersElement = new BElement(BList::toEncoded($peerList));
|
||||
$out = BDictionary::toEncoded(array("interval"=>DEFAULT_CONNECTION_INTERVAL, "complete"=>$complete, "incomplete"=>$incomplete, "peers"=>$peersElement));
|
||||
|
||||
// Echo the answer to stdout
|
||||
echo $out;
|
||||
$fh = fopen(TRACKER_LOGFILE, "a");
|
||||
fputs($fh, date(DATE_ATOM, time())." ".$_SERVER["REMOTE_ADDR"]." - ".$event."\n");
|
||||
fclose($fh);
|
||||
|
||||
// ------------------------------------------------------
|
||||
// Check if the database needs cleaning
|
||||
$cache_args = "tracker_timer";
|
||||
$cacheddata=get_cached_data(DB_CLEAN_TTL,$cache_args);
|
||||
if ($cacheddata){ //If we have got the timer in cache
|
||||
// Do nothing
|
||||
} else { //if not do queries etc to clean DB
|
||||
// TODO: update the bittorrent_statistics table here before deleting entries
|
||||
mysql_query("DELETE from bittorrent_files where timestamp<".(time()-TORRENT_TTL)); echo mysql_error();
|
||||
mysql_query("DELETE from bittorrent_peers where timestamp<".(time()-PEER_TTL)); echo mysql_error();
|
||||
mysql_query("DELETE from bittorrent_ipbans where timestamp<".time()); echo mysql_error();
|
||||
// And reset the timer in the cache
|
||||
set_cache_data(serialize(time()),$cache_args); //save data in cache
|
||||
};
|
||||
|
||||
?>
|
|
@ -1,81 +0,0 @@
|
|||
<?php
|
||||
// Includes from BOINC
|
||||
require_once("../inc/cache.inc");
|
||||
require_once("../inc/util.inc");
|
||||
|
||||
// Includes from BT
|
||||
require_once("./inc/illegalargumentexception.php");
|
||||
require_once("./inc/torrent.php");
|
||||
require_once("./inc/belement.php");
|
||||
require_once("./inc/blist.php");
|
||||
require_once("./inc/bstring.php");
|
||||
require_once("./inc/bdictionary.php");
|
||||
require_once("./inc/binteger.php");
|
||||
require_once("./inc/checks.php");
|
||||
|
||||
// Includes for filtering
|
||||
require_once("./filters/filefilter.php");
|
||||
|
||||
$cvs_version_tracker[]="\$Id$"; //Generated automatically - do not edit
|
||||
|
||||
|
||||
/**
|
||||
* Usually it should be enough to edit the lines below this comment to fit your usage scenario -
|
||||
* ie. if you have a lot of users and the files you have change a lot you may wish to cut down on
|
||||
* the torrent_ttl (since this determines the final size of the database).
|
||||
* The remaining part of this configuation file is split into 2 subparts: One for configuration
|
||||
* of the tracker and one for configuration of the .torrent-generator.
|
||||
*/
|
||||
|
||||
// Tracker --------------------------------------------------------------------------------------------------------
|
||||
define (TORRENT_TTL, 3600*24*15); // How long any torrent will remain in the database if it hasn't been accessed
|
||||
define (PEER_TTL, 3600*24); // How long any peer will remain in the database if it hasn't talked to us
|
||||
define (DB_CLEAN_TTL, 3600*24); // How often the DB will be cleaned
|
||||
define (DEFAULT_CONNECTION_INTERVAL, 3600); // How often we would like clients to talk to the tracker
|
||||
define (MAX_INFO_HASH_PEERS, 30); // How many peers to send back for each tracker request
|
||||
define (TRACKER_LOGFILE, "../../logs/bittorrent.log");
|
||||
// Tracker end ----------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
// Generator ------------------------------------------------------------------------------------------------------
|
||||
define (TORRENT_CACHE_TTL, 3600*24); // How long before regenerating any torrent information (if your files are immutable simply set this to TORRENT_TTL).
|
||||
/**
|
||||
* The file filter determines which files to use bittorrent for and which not to track through bittorrent.
|
||||
* Setting the file filter requires that you include whatever filter you decide to use first. For a list
|
||||
* of available filters please have a look in the ./filters/-folder.
|
||||
* A good default behaviour is to either track anything or only track files greater than some set size.
|
||||
*/
|
||||
require_once("./filters/allfilesfilefilter.php"); // Include happens with the FILEname of the chosen FileFilter class
|
||||
$fileFilter = new AllFilesFileFilter(); // Instantiation happens with the CLASSname of the class.
|
||||
|
||||
/**
|
||||
* FileDirectory: The base directory to serve files from. All file references will be relative to this.
|
||||
* Symlinks outside the $fileDirectory are not allowed. Either do hardlinking or make the
|
||||
* entire $fileDirectory a symlink somewhere.
|
||||
*/
|
||||
$fileDirectory="../../download";
|
||||
$trackerURL = "http://bittorrent.burp.boinc.dk/announce.php"; // The externally accessible URL to use for tracking purposes (should point to announce.php)
|
||||
|
||||
/**
|
||||
* Webseeds: This optional array lists any project HTTP webservers capable of handing out the files.
|
||||
* Note that the servers must have a very strict hierarchy for the files:
|
||||
* The optional webseeds must be HTTP servers with a similar structure to $fileDirectory
|
||||
* For instance if you have a webseed called "http://burp.boinc.dk/download/" and a file
|
||||
* $fileDirectory/dir/file
|
||||
* then the webseed musst respond to queries on http://burp.boinc.dk/download/dir/file.
|
||||
*/
|
||||
$webseeds = array(
|
||||
"http://burp.boinc.dk/mirror/mirror_download.php?fetch=true&mirsug=0&getfile=",
|
||||
"http://burp.boinc.dk/mirror/mirror_download.php?fetch=true&mirsug=1&getfile=",
|
||||
"http://burp.boinc.dk/mirror/mirror_download.php?fetch=true&mirsug=2&getfile=",
|
||||
"http://burp.boinc.dk/mirror/mirror_download.php?fetch=true&mirsug=3&getfile=",
|
||||
"http://burp.boinc.dk/mirror/mirror_download.php?fetch=true&mirsug=4&getfile=",
|
||||
"http://burp.boinc.dk/mirror/mirror_download.php?fetch=true&mirsug=5&getfile=",
|
||||
"http://burp.boinc.dk/mirror/mirror_download.php?fetch=true&mirsug=6&getfile=",
|
||||
"http://burp.boinc.dk/mirror/mirror_download.php?fetch=true&mirsug=7&getfile=",
|
||||
"http://burp.boinc.dk/mirror/mirror_download.php?fetch=true&mirsug=8&getfile=",
|
||||
"http://burp.boinc.dk/mirror/mirror_download.php?fetch=true&mirsug=9&getfile=");
|
||||
// Generator end --------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
?>
|
|
@ -1,9 +0,0 @@
|
|||
CREATE TABLE `bittorrent_files` (
|
||||
`id` int(11) NOT NULL auto_increment,
|
||||
`filename` varchar(256) default NULL,
|
||||
`info_hash` varbinary(22) default NULL,
|
||||
`timestamp` int(14) NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `filename` (`filename`),
|
||||
KEY `info_hash` (`info_hash`)
|
||||
) ENGINE=MEMORY;
|
|
@ -1,5 +0,0 @@
|
|||
CREATE TABLE `bittorrent_ipbans` (
|
||||
`ip` varbinary(256) NOT NULL default '',
|
||||
`timestamp` int(14) NOT NULL,
|
||||
PRIMARY KEY (`ip`)
|
||||
) ENGINE=MEMORY COMMENT='Banned IPs and when they can be unbanned (reset when SQL-server restarts)';
|
|
@ -1,13 +0,0 @@
|
|||
CREATE TABLE `bittorrent_peers` (
|
||||
`fileid` int(11) NOT NULL default '0',
|
||||
`peerid` varbinary(20) NOT NULL,
|
||||
`ip` varbinary(50) default NULL,
|
||||
`port` int(11) NOT NULL,
|
||||
`status` enum('started','stopped','completed') NOT NULL,
|
||||
`uploaded` int(11) NOT NULL,
|
||||
`downloaded` int(11) NOT NULL,
|
||||
`timestamp` int(14) NOT NULL,
|
||||
PRIMARY KEY (`fileid`,`peerid`),
|
||||
KEY `timestamp` (`timestamp`)
|
||||
) ENGINE=MEMORY;
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* A file filter that simply accepts any file whatsoever
|
||||
*/
|
||||
|
||||
$cvs_version_tracker[]="\$Id: checks.php 12885 2007-06-11 18:27:24Z jbk $"; //Generated automatically - do not edit
|
||||
|
||||
|
||||
class AllFilesFileFilter extends FileFilter {
|
||||
function isValid($file){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -1,13 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* Any file filter must implement the following interface
|
||||
*/
|
||||
|
||||
$cvs_version_tracker[]="\$Id: checks.php 12885 2007-06-11 18:27:24Z jbk $"; //Generated automatically - do not edit
|
||||
|
||||
|
||||
abstract class FileFilter {
|
||||
abstract function isValid($file);
|
||||
}
|
||||
|
||||
?>
|
|
@ -1,53 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* A dictionary is a mapping from strings to elements. When BEncoded a dictionary is
|
||||
* two lists interleaved. In PHP dictionaries are represented as arrays with the
|
||||
* string as index and value as entry at that index.
|
||||
* In BEncoded form a dictionary starts with "d" and is followed directly by the
|
||||
* contents of the interleaved data list and ends with "e".
|
||||
*
|
||||
* d3:cow3:moo4:spam4:eggse represents the dictionary { "cow" => "moo", "spam" => "eggs" }
|
||||
*/
|
||||
|
||||
$cvs_version_tracker[]="\$Id$"; //Generated automatically - do not edit
|
||||
|
||||
class BDictionary {
|
||||
private function __construct(){
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the decoded array from $str
|
||||
* @throws an IllegalArgumentException in the case
|
||||
* that the string is malformed.
|
||||
*/
|
||||
public static function toArray($str){
|
||||
if (substr($str, 0, 1)!="d" || substr($str, -1, 1)!="e") throw new IllegalArgumentException("BEncoded dictionary does not start with d or end with e.");
|
||||
// An array is simply two lists encoded in an alternating list
|
||||
$arrays = BList::toList("l".substr($str, 1));
|
||||
|
||||
$i=0;
|
||||
for ($i=0;$i<sizeof($arrays); $i+=2){
|
||||
$array[$arrays[$i]] = $arrays[$i+1];
|
||||
}
|
||||
return $array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a BEncoded dictonary
|
||||
*/
|
||||
public static function toEncoded($array){
|
||||
ksort($array);
|
||||
|
||||
// An array is simply two lists encoded as an alternating list
|
||||
$list = array();
|
||||
foreach ($array as $key => $value){
|
||||
$list[] = $key;
|
||||
$list[] = $value;
|
||||
}
|
||||
|
||||
return "d".substr(BList::toEncoded($list), 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
?>
|
|
@ -1,29 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* This class is used as part of the Bittorrent .torrent creator and tracker system.
|
||||
* A BElement is used to contain BEncoded elements inside other BEncodings (like lists or dictonaries)
|
||||
*/
|
||||
|
||||
$cvs_version_tracker[]="\$Id: belement.inc 12611 2007-05-08 08:25:13Z jbk $"; //Generated automatically - do not edit
|
||||
|
||||
class BElement {
|
||||
private $encodedText;
|
||||
|
||||
/**
|
||||
* Constructs a new BElement with the $bEncoding as BEncoded
|
||||
* value to be used
|
||||
*/
|
||||
public function __construct($bEncoding){
|
||||
$this->encodedText = $bEncoding;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a BEncoded value
|
||||
*/
|
||||
public function toEncoded(){
|
||||
return $this->encodedText;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
?>
|
|
@ -1,35 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* A BInteger takes care of the BEncoding and BDecoding of integers for the
|
||||
* Bittorrent features.
|
||||
* An integer starts with "i", has the value and then ends with "e".
|
||||
*/
|
||||
|
||||
$cvs_version_tracker[]="\$Id$"; //Generated automatically - do not edit
|
||||
|
||||
class BInteger {
|
||||
private function __construct(){
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ordinary value decoded from $str
|
||||
* @throws an IllegalArgumentException in the case
|
||||
* that the string is malformed.
|
||||
*/
|
||||
public static function toInteger($str){
|
||||
if (substr($str, 0, 1)!="i" || substr($str, -1, 1)!="e") throw new IllegalArgumentException("BEncoded integer value does not start with i or end with e.");
|
||||
$value = substr($str, 1,-1);
|
||||
if (!is_numeric($value)) throw new IllegalArgumentException("BEncoded string has non-numeric length specification.");
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a BEncoded integer value
|
||||
*/
|
||||
public static function toEncoded($value){
|
||||
return "i".$value."e";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
?>
|
|
@ -1,102 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* The BList class is part of the Bittorrent serverside utility classes
|
||||
* It implements a BEncoded list - which always starts with l and ends with e.
|
||||
* In PHP lists are simply non-keyed (ie. standard keyed) arrays.
|
||||
*/
|
||||
|
||||
$cvs_version_tracker[]="\$Id$"; //Generated automatically - do not edit
|
||||
|
||||
class BList {
|
||||
private function __construct(){
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the decoded array from $str
|
||||
* @throws an IllegalArgumentException in the case
|
||||
* that the string is malformed.
|
||||
*/
|
||||
public static function toList($str){
|
||||
if (substr($str, 0, 1)!="l" || substr($str, -1, 1)!="e") throw new IllegalArgumentException("BEncoded list does not start with l or end with e.");
|
||||
$value = substr($str, 1,-1);
|
||||
|
||||
// Scan through encoded list and decode everything
|
||||
$list = array();
|
||||
$i=0; $lastI = 0;
|
||||
while ($i<strlen($value)){
|
||||
$curChar = substr($value, $i,1);
|
||||
if ($curChar == "i"){ // We just saw an Integer
|
||||
$endPos = strpos($value, "e", $i); // Search for the end of it
|
||||
if ($endPos===false) throw new IllegalArgumentException("BEncoded list contains non-terminated integer");
|
||||
$list[] = BInteger::toInteger(substr($value, $i, $endPos-$i+1));
|
||||
$i=$endPos+1;
|
||||
} elseif (is_numeric($curChar)){ // A number means we just saw a string starting
|
||||
$seperatorPos = strpos($value, ":", $i); // Search for the seperator
|
||||
if ($seperatorPos===false) throw new IllegalArgumentException("BEncoded list contains malformed string with no length specified");
|
||||
$totalLength = substr($value, $i, $seperatorPos-$i);
|
||||
$list[] = BString::toString(substr($value, $i, $seperatorPos-$i+$totalLength+1));
|
||||
$i=$seperatorPos+$totalLength+1;
|
||||
} elseif ($curChar == "d" || $curChar == "l"){ // Found a dictionary or list
|
||||
// Scan for end of it
|
||||
$listLength = BList::getListLength(substr($value, $i));
|
||||
if ($curChar == "d"){
|
||||
$list[] = BDictionary::toArray(substr($value, $i, $listLength));
|
||||
} else {
|
||||
$list[] = BList::toList(substr($value, $i, $listLength));
|
||||
}
|
||||
$i+=$listLength;
|
||||
}
|
||||
if ($i==$lastI) throw new IllegalArgumentException("BEncoded list contains malfomed or unrecognized content");
|
||||
$lastI = $i;
|
||||
}
|
||||
return $list;
|
||||
}
|
||||
|
||||
private static function getListLength($text){
|
||||
$i = 1; $lastI = 0; $foundEnd = false;
|
||||
while ($i<strlen($text)){
|
||||
$curChar = substr($text, $i, 1);
|
||||
if ($curChar == "i"){
|
||||
$i = strpos($text, "e", $i);
|
||||
if ($i===false) throw new IllegalArgumentException("BEncoded sublist/dictionary integer has no end");
|
||||
$i++;
|
||||
} elseif (is_numeric($curChar)){
|
||||
$seperatorPos = strpos($text, ":", $i); // Search for the seperator
|
||||
if ($seperatorPos===false) throw new IllegalArgumentException("BEncoded sublist/dictionary contains a string with no length specified");
|
||||
$totalLength = substr($text, $i, $seperatorPos-$i);
|
||||
$i=$seperatorPos+$totalLength+1;
|
||||
} elseif ($curChar == "d" || $curChar == "l"){
|
||||
$i+=BList::getListLength(substr($text, $i));
|
||||
} elseif ($curChar == "e"){
|
||||
$foundEnd = true;
|
||||
break;
|
||||
}
|
||||
if ($i==$lastI) throw new IllegalArgumentException("BEncoded sublist/dictionary contains malfomed or unrecognized content");
|
||||
$lastI = $i;
|
||||
}
|
||||
if (!$foundEnd) throw new IllegalArgumentException("BEncoded sublist/dictionary had no end");
|
||||
return $i+1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a BEncoded list
|
||||
*/
|
||||
public static function toEncoded($list){
|
||||
$values = array_values($list);
|
||||
$text = "l";
|
||||
foreach ($values as $value){
|
||||
if (is_integer($value)){
|
||||
$text.=BInteger::toEncoded($value);
|
||||
} elseif (is_string($value)){
|
||||
$text.=BString::toEncoded($value);
|
||||
} elseif ($value instanceof BElement){
|
||||
$text.=$value->toEncoded();
|
||||
}
|
||||
}
|
||||
$text.= "e";
|
||||
return $text;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
?>
|
|
@ -1,36 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* The BString class represents BEncoded strings for the serverside Bittorrent system.
|
||||
* A BEncoded string always starts with the length, then a ":" and then the actual data.
|
||||
* Strings are native in PHP.
|
||||
*/
|
||||
|
||||
$cvs_version_tracker[]="\$Id$"; //Generated automatically - do not edit
|
||||
|
||||
class BString {
|
||||
private function __construct(){
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ordinary string decoded from $str
|
||||
* @throws an IllegalArgumentException in the case
|
||||
* that the string is malformed (ie. has more/less chars than specified
|
||||
* or does not correctly define a BEncoded string)
|
||||
*/
|
||||
public static function toString($str){
|
||||
list($length, $data) = explode(":", $str);
|
||||
if (!is_numeric($length)) throw new IllegalArgumentException("BEncoded string has non-numeric length specification.");
|
||||
if ($length != strlen($data)) throw new IllegalArgumentException("BEncoded string length does not match actual length of string.");
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a BEncoded string
|
||||
*/
|
||||
public static function toEncoded($str){
|
||||
return strlen($str).":".$str;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
?>
|
|
@ -1,31 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* Checks common to both the tracker and the scraping mechanism.
|
||||
*/
|
||||
|
||||
$cvs_version_tracker[]="\$Id$"; //Generated automatically - do not edit
|
||||
|
||||
|
||||
function isIPBanned($ip){
|
||||
$queryHandle = mysql_query("SELECT * from bittorrent_ipbans where ip=\"".process_user_text($ip)."\" and timestamp > ".time()); echo mysql_error();
|
||||
if (mysql_num_rows($queryHandle)){
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (get_magic_quotes_gpc()) {
|
||||
function stripslashes_deep($value) {
|
||||
$value = is_array($value) ?
|
||||
array_map('stripslashes_deep', $value) :
|
||||
stripslashes($value);
|
||||
return $value;
|
||||
}
|
||||
|
||||
$_POST = array_map('stripslashes_deep', $_POST);
|
||||
$_GET = array_map('stripslashes_deep', $_GET);
|
||||
$_COOKIE = array_map('stripslashes_deep', $_COOKIE);
|
||||
$_REQUEST = array_map('stripslashes_deep', $_REQUEST);
|
||||
}
|
||||
?>
|
|
@ -1,9 +0,0 @@
|
|||
<?php
|
||||
|
||||
$cvs_version_tracker[]="\$Id$"; //Generated automatically - do not edit
|
||||
|
||||
|
||||
class IllegalArgumentException extends Exception {
|
||||
}
|
||||
|
||||
?>
|
|
@ -1,89 +0,0 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* A .torrent is a metafile containing info about a P2P file
|
||||
* This class encapsulates all related .torrent information
|
||||
* for a single file.
|
||||
* We don't seem to need multifile support since the clients can
|
||||
* simply download a .torrent for each file they want to fetch.
|
||||
*/
|
||||
|
||||
$cvs_version_tracker[]="\$Id$"; //Generated automatically - do not edit
|
||||
|
||||
class Torrent {
|
||||
private $trackerURL; // String
|
||||
private $name; // String
|
||||
private $pieceLength = 524288; // (512KB)
|
||||
private $filename; // String
|
||||
private $webseeds; // URL String Array
|
||||
|
||||
private $concattedSHA1; // Imploded string of SHA1 hashes
|
||||
private $generatedPieceLength;
|
||||
private $infoHash;
|
||||
|
||||
/**
|
||||
* Filename is the full path to the file to be encapsulated.
|
||||
*/
|
||||
function __construct($filename, $trackerURL, $webseeds=array()){
|
||||
if (!file_exists($filename)) throw new IllegalArgumentException("No such file found");
|
||||
|
||||
$this->filename = $filename;
|
||||
$this->trackerURL = $trackerURL;
|
||||
$this->webseeds = $webseeds;
|
||||
$this->name = basename($filename);
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans the entire file generating SHA1 hashes for each piece
|
||||
*/
|
||||
public function ensureSHA1Loaded(){
|
||||
if (!$this->concattedSHA1 || ($this->pieceLength!=$this->generatedPieceLength)){
|
||||
$fh = fopen($this->filename, "rb");
|
||||
if (!$fh) throw new Exception("No filehandle");
|
||||
$fsize = filesize($this->filename);
|
||||
$this->concattedSHA1 = "";
|
||||
for ($i = 0; $i<ceil($fsize/$this->pieceLength); $i++){
|
||||
fseek($fh, $i*$this->pieceLength);
|
||||
$this->concattedSHA1 .= sha1(fread($fh,$this->pieceLength), true);
|
||||
}
|
||||
$this->generatedPieceLength = $this->pieceLength;
|
||||
fclose($fh);
|
||||
if (!$this->concattedSHA1) throw new Exception("No SHA gotten");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches all relevant information from the file and generates a
|
||||
* .torrent
|
||||
*/
|
||||
public function toEncoded(){
|
||||
$infoArray["name"] = $this->name;
|
||||
$infoArray["piece length"] = $this->pieceLength;
|
||||
$infoArray["length"] = filesize($this->filename);
|
||||
$this->ensureSHA1Loaded();
|
||||
$infoArray["pieces"] = $this->concattedSHA1;
|
||||
$infoDictionary = new BElement(BDictionary::toEncoded($infoArray));
|
||||
$this->infoHash = sha1($infoDictionary->toEncoded(), true);
|
||||
$metainfoArray = array("announce"=>$this->trackerURL, "info"=>$infoDictionary);
|
||||
$metainfoArray["url-list"] = new BElement(BList::toEncoded($this->webseeds));
|
||||
$metainfoDictionary = BDictionary::toEncoded($metainfoArray);
|
||||
|
||||
return $metainfoDictionary;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers this torrent in the database
|
||||
*/
|
||||
public function register(){
|
||||
$this->toEncoded();
|
||||
// Check if exists:
|
||||
$queryHandle = mysql_query("SELECT id from bittorrent_files where filename=\"".process_user_text($this->filename)."\"");
|
||||
if ($queryHandle && $data = mysql_fetch_object($queryHandle)){
|
||||
$extra = "id=".$data->id.", ";
|
||||
} else {
|
||||
$extra = "";
|
||||
}
|
||||
mysql_query("REPLACE into bittorrent_files set ".$extra."filename=\"".process_user_text($this->filename)."\", info_hash=\"".process_user_text($this->infoHash)."\", timestamp=".time());
|
||||
}
|
||||
}
|
|
@ -1,78 +0,0 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This index-file helps setup and debug any Bittorrent tracker and generator installation through
|
||||
* the use of some built-in checks in the code.
|
||||
* It is advised that you leave the index file in place even after succesful installation so that any
|
||||
* later debugging can easily be done.
|
||||
*
|
||||
* Also, at some point, this file will display some statistical information about the data distributed
|
||||
* through the use of the tracker.
|
||||
*/
|
||||
$cvs_version_tracker[]="\$Id$"; //Generated automatically - do not edit
|
||||
|
||||
?>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title>BOINC Bittorrent</title>
|
||||
</head
|
||||
<body>
|
||||
<h1>BOINC Bittorrent</h1>
|
||||
<p>
|
||||
This page helps you identify whether the BOINC Bittorrent system has succesfully been installed
|
||||
on the server. If all of the bellow checks are green and all of the settings seem to match your
|
||||
setup then everything should be perfectly fine.<br />
|
||||
If, for some reason, the entire page (including the text at the bottom, bellow the table of checks)
|
||||
isn't displayed, you should have a look at the error-log for your server. Similarly, if one of the
|
||||
checks fail you may find additional information on the page or in your server logs.
|
||||
</p>
|
||||
<table>
|
||||
<tr>
|
||||
<th>Check</th><th>Status</th>
|
||||
</tr>
|
||||
<?php
|
||||
function showCheck($check, $status, $comment){
|
||||
echo "<tr><td>".$check."</td><td>";
|
||||
if ($status){
|
||||
echo "<font color='green'>OK";
|
||||
} else {
|
||||
echo "<font color='yellow'>Hm...";
|
||||
}
|
||||
echo "</td><td>";
|
||||
if (!$status) echo $comment;
|
||||
echo "</td></tr>";
|
||||
}
|
||||
showCheck("Linking to config.php", file_exists("./config.php"), "config.php is missing - did you remember to copy from the sample?");
|
||||
require_once("./config.php");
|
||||
showCheck("Linking to BOINC serverside framework", file_exists("../inc/util.inc"), "Cannot find the BOINC framework - did you install the BT system in the html/-directory of your BOINC installation?");
|
||||
require_once("../inc/util.inc");
|
||||
showCheck("Database link", (db_init()||true), "");
|
||||
showCheck("bittorrent_files table", mysql_query("select * from bittorrent_files"), "Table inaccessible");
|
||||
showCheck("bittorrent_ipbans table", mysql_query("select * from bittorrent_ipbans"), "Table inaccessible");
|
||||
showCheck("bittorrent_peers table", mysql_query("select * from bittorrent_peers"), "Table inaccessible");
|
||||
showCheck("bittorrent_statistics table", mysql_query("select * from bittorrent_statistics"), "Table inaccessible");
|
||||
showCheck("Linking to download dir (".$fileDirectory.")", file_exists($fileDirectory), "Directory not accessible or present");
|
||||
showCheck("Tracker present (".$trackerURL.")", fopen($trackerURL, "r"), "Either this webserver doesn't support URL-fopen-wrappers or the tracker is not available. In the first case you may safely ignore this warning.");
|
||||
showCheck("Webseeds defined", (sizeof($webseeds)>0), "No webseeds defined");
|
||||
foreach ($webseeds as $webseed){
|
||||
showCheck("Seed present (".$webseed.")", fopen($webseed, "r"), "Either this webserver doesn't support URL-fopen-wrappers or the webseed is not present. If the first is the case this warning may safely be ignored.");
|
||||
}
|
||||
showCheck("Linking to logfile (".TRACKER_LOGFILE.")", file_exists(TRACKER_LOGFILE), "The logfile doesn't exist - this may be because the system hasn't been run yet or because the file couldn't be created.");
|
||||
?>
|
||||
</table>
|
||||
<p>
|
||||
Files used in this distribution:
|
||||
<ul>
|
||||
<?php
|
||||
for ($i=0;$i<sizeof($cvs_version_tracker);$i++) {
|
||||
echo "<li>".$cvs_version_tracker[$i]."\n";
|
||||
}
|
||||
?>
|
||||
</ul>
|
||||
</p>
|
||||
<p>
|
||||
For more information check the documentation delivered within the bt directory.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
|
@ -1,47 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* For multiple purposes it may be interesting for clients to know a little about
|
||||
* the network statistics for the entire Bittorrent swarm controlled by the tracker.
|
||||
* Scraping allows clients to get this information easily and quickly.
|
||||
*/
|
||||
|
||||
$cvs_version_tracker[]="\$Id$"; //Generated automatically - do not edit
|
||||
|
||||
require_once("config.php");
|
||||
|
||||
function trackerError($error){
|
||||
echo BDictionary::toEncoded(array("failure_reason"=>$error));
|
||||
exit;
|
||||
}
|
||||
|
||||
$info_hash = rawurldecode($_GET["info_hash"]);
|
||||
if (strlen($info_hash)!=20) throw new IllegalArgumentException("Malformed infohash key (length ".strlen($info_hash).")");
|
||||
|
||||
if (!$ip){
|
||||
$ip = $_SERVER["REMOTE_ADDR"];
|
||||
}
|
||||
|
||||
// Is the IP banned?
|
||||
db_init();
|
||||
if (isIPBanned($ip)){
|
||||
trackerError("Banned IP: ".$ip);
|
||||
}
|
||||
|
||||
// Check that the info_hash is one that we allow:
|
||||
$queryHandle = mysql_query("SELECT * from bittorrent_files where info_hash=\"".process_user_text($info_hash)."\""); echo mysql_error();
|
||||
if (!mysql_num_rows($queryHandle)){
|
||||
trackerError("The tracker does not allow tracking of this file:".$info_hash);
|
||||
}
|
||||
$infoHashObject = mysql_fetch_object($queryHandle);
|
||||
|
||||
// Get some statistical counts
|
||||
$queryHandle = mysql_query("SELECT count(fileid) as complete from bittorrent_peers where fileid = '".$infoHashObject->id."' and status='completed'");
|
||||
$data = mysql_fetch_object($queryHandle);
|
||||
$complete = intval($data->complete);
|
||||
$queryHandle = mysql_query("SELECT count(fileid) as incomplete from bittorrent_peers where fileid = '".$infoHashObject->id."' and status!='completed'");
|
||||
$data = mysql_fetch_object($queryHandle);
|
||||
$incomplete = intval($data->incomplete);
|
||||
|
||||
$out = BDictionary::toEncoded(array("interval"=>DEFAULT_CONNECTION_INTERVAL, "downloaded"=>$complete, "complete"=>$complete, "incomplete"=>$incomplete));
|
||||
|
||||
?>
|
|
@ -1,71 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* The torrent cache and generator script takes care of dynamically generating .torrents
|
||||
* when they are requested by clients.
|
||||
* To optimize performance .torrent-objects are cached in the cache directory so that
|
||||
* on any second request they can be directly sent without re-calculating the SHA1 strings.
|
||||
*
|
||||
* A file is requested by torrent_cache.php?file=/some_file.filetype
|
||||
*
|
||||
* Symlinks outside the $fileDirectory are not allowed. Either do hardlinking or make the
|
||||
* entire $fileDirectory a symlink somewhere.
|
||||
*
|
||||
* The optional webseeds must be HTTP servers with a similar structure to $fileDirectory
|
||||
* For instance if you have a webseed called "http://burp.boinc.dk/download/" and a file
|
||||
* $fileDirectory/dir/file
|
||||
* then the webseed musst respond to queries on http://burp.boinc.dk/download/dir/file.
|
||||
*
|
||||
* Please see config.php for the setting of these variables.
|
||||
*/
|
||||
require_once("config.php");
|
||||
|
||||
function isSubDir($possibleSubDir, $parent){
|
||||
$realPossible = realpath($possibleSubDir);
|
||||
$realParent = realpath($parent);
|
||||
return (substr($realPossible, 0, strlen($realParent)) == $realParent);
|
||||
}
|
||||
|
||||
// Get the file request and do some checkups
|
||||
$file = $_GET["file"];
|
||||
if (!$file) throw new IllegalArgumentException("No file specified");
|
||||
if (strpos(urldecode($file), "..")!==false) throw new IllegalArgumentException("Cannot use '..' in path");
|
||||
|
||||
|
||||
// See if we've got the file
|
||||
while (!$fileModTime){
|
||||
if (($fileModTime = @filemtime($fileDirectory.$file)) === false){
|
||||
$pos = strpos($file, "/", 1);
|
||||
if ($pos === false){
|
||||
throw new IllegalArgumentException("File does not exist");
|
||||
} else {
|
||||
$file = substr($file, $pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$file = $fileDirectory.$file;
|
||||
|
||||
if (!$fileFilter->isValid($file)) throw new IllegalArgumentException("File was not accepted by the server for tracking.");
|
||||
|
||||
// Everything's fine let's lookup the .torrent in the cache if needed:
|
||||
$cache_args = "file=".$file."&modtime=".$fileModTime;
|
||||
$cacheddata=get_cached_data(TORRENT_CACHE_TTL,$cache_args);
|
||||
if ($cacheddata){ //If we have got the data in cache
|
||||
$torrent = unserialize($cacheddata); // use the cached data
|
||||
} else { //if not do queries etc to generate new data
|
||||
for ($i=0; $i<sizeof($webseeds);$i++){
|
||||
$realWebseeds[] = $webseeds[$i].substr($file, strlen($fileDirectory));
|
||||
}
|
||||
|
||||
$torrent = new Torrent($file, $trackerURL, $realWebseeds);
|
||||
$torrent->ensureSHA1Loaded();
|
||||
db_init();
|
||||
$torrent->register();
|
||||
set_cache_data(serialize($torrent),$cache_args); //save data in cache
|
||||
};
|
||||
|
||||
header("Content-type: application/x-bittorrent");
|
||||
header("Content-Disposition: attachment; filename=\"".basename($file).".torrent\"");
|
||||
|
||||
echo $torrent->toEncoded();
|
||||
?>
|
Loading…
Reference in New Issue