139 lines
No EOL
4.7 KiB
PHP
139 lines
No EOL
4.7 KiB
PHP
<?php
|
|
require("../php/config.php");
|
|
require("bencoder.php");
|
|
require("peer.php");
|
|
$DB_NAME = "torrent";
|
|
|
|
class Tracker {
|
|
const ANN_USERAGENT = "Transmission/3.00";
|
|
const ANN_PEER_ID = "01234567890123456789";
|
|
const ANN_TIMEOUT_MS = 500;
|
|
|
|
protected $proto;
|
|
protected $host;
|
|
protected $port;
|
|
protected $path;
|
|
protected $passkey;
|
|
protected $proxy;
|
|
|
|
public function __toString() {
|
|
return $this->proto . "://" . $this->host
|
|
. ":" . $this->port . $this->path;
|
|
}
|
|
|
|
public function getHttpUrl() {
|
|
return $this->proto . "://" . $this->host . $this->path;
|
|
}
|
|
|
|
public function getPasskeyName() {
|
|
if (!is_null($this->passkey)) {
|
|
return explode(' ', $this->passkey)[0];
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
protected function doHttpAnnounce($infoHash, $peerIp, $peerPort, $peerId = null, $uploaded = 0, $downloaded = 0, $left = 0) {
|
|
$peers = array();
|
|
|
|
$passkey = is_null($this->passkey) ? "" : $this->passkey . "&";
|
|
$params = http_build_query(array(
|
|
"info_hash" => hash_encode($infoHash),
|
|
"peer_id" => is_null($peerId) ? self::ANN_PEER_ID : $peerId,
|
|
"ip" => $peerIp,
|
|
"port" => $peerPort,
|
|
"uploaded" => $uploaded,
|
|
"downloaded" => $downloaded,
|
|
"left" => $left,
|
|
));
|
|
|
|
$ch = curl_init();
|
|
curl_setopt($ch, CURLOPT_URL, $this->getHttpUrl() . "?" . $passkey . $params);
|
|
curl_setopt($ch, CURLOPT_PORT, intval($this->port));
|
|
curl_setopt($ch, CURLOPT_USERAGENT, self::ANN_USERAGENT);
|
|
curl_setopt($ch, CURLOPT_TIMEOUT_MS, self::ANN_TIMEOUT_MS);
|
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
|
if (!is_null($this->proxy)) {
|
|
curl_setopt($ch, CURLOPT_PROXY, $this->proxy);
|
|
}
|
|
|
|
$result = curl_exec($ch);
|
|
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
|
curl_close($ch);
|
|
if ($code != 200 || $result == false) {
|
|
return false;
|
|
}
|
|
|
|
$response = bdecode($result);
|
|
if (!array_key_exists("peers", $response)) {
|
|
return false;
|
|
}
|
|
|
|
$peersEnc = $response["peers"];
|
|
for ($i = 0; $i < strlen($peersEnc); $i+=6) {
|
|
$remoteIp = long2ip(unpack("N", $peersEnc, $i)[1]);
|
|
$remotePort = unpack("n", $peersEnc, $i + 4)[1];
|
|
array_push($peers, new Peer($infoHash, $remoteIp, $remotePort));
|
|
}
|
|
|
|
return $peers;
|
|
}
|
|
|
|
protected function doUdpAnnounce($infoHash, $peerIp, $peerPort, $peerId = null, $uploaded = 0, $downloaded = 0, $left = 0) {
|
|
$peers = array();
|
|
|
|
$addr = gethostbyname($this->host);
|
|
$port = $this->port;
|
|
$key = 0;
|
|
|
|
$sockfd = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
|
|
socket_set_option($sockfd, SOL_SOCKET, SO_RCVTIMEO,
|
|
array("sec" => 0, "usec" => self::ANN_TIMEOUT_MS*1000));
|
|
|
|
$transaction_id = rand();
|
|
$req = pack("JNN", 4497486125440, 0, $transaction_id);
|
|
socket_sendto($sockfd, $req, 16, 0, $addr, $port);
|
|
$recv = socket_recvfrom($sockfd, $buf, 16, 0, $addr, $port);
|
|
if ($recv == false || $recv == 0) {
|
|
return false;
|
|
}
|
|
$res = unpack("Naction/Ntransaction_id/Jconnection_id", $buf);
|
|
$connection_id = $res["connection_id"];
|
|
|
|
$transaction_id = rand();
|
|
$req = pack("JNN", $connection_id, 1, $transaction_id)
|
|
. hex2bin($infoHash)
|
|
. (is_null($peerId) ? self::ANN_PEER_ID : $peerId)
|
|
. pack("JJJNNNNn", $downloaded, $uploaded, $left,
|
|
0, $peerIp, $key, -1, $peerPort);
|
|
socket_sendto($sockfd, $req, 98, 0, $addr, $port);
|
|
$recv = socket_recvfrom($sockfd, $buf, 65535, 0, $addr, $port);
|
|
if ($recv == false || $recv == 0) {
|
|
return false;
|
|
}
|
|
$res = unpack("Naction/Ntransaction_id/Ninterval/Nleechers/Nseeders", $buf);
|
|
//$count = $res["leechers"] + $res["seeders"];
|
|
$count = ($recv - 20) / 6;
|
|
for ($i = 0; $i < $count; $i++) {
|
|
$peer = unpack("Nip/nport", $buf, 20 + $i*6);
|
|
array_push($peers, new Peer($infoHash,
|
|
long2ip($peer["ip"]), $peer["port"]));
|
|
}
|
|
|
|
socket_close($sockfd);
|
|
|
|
return $peers;
|
|
}
|
|
|
|
public function announce($infoHash, $peerIp, $peerPort, $peerId = null, $uploaded = 0, $downloaded = 0, $left = 0) {
|
|
if ($this->proto == "http" || $this->proto == "https") {
|
|
return $this->doHttpAnnounce($infoHash, $peerIp, $peerPort, $peerId, $uploaded, $downloaded, $left);
|
|
} else if ($this->proto == "udp") {
|
|
return $this->doUdpAnnounce($infoHash, $peerIp, $peerPort, $peerId, $uploaded, $downloaded, $left);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
?>
|