2020-12-26 01:42:23 +08:00
< ? php
2022-03-19 14:55:43 +08:00
require '../include/bittorrent_announce.php' ;
require ROOT_PATH . 'include/core.php' ;
2023-06-04 15:24:56 +08:00
//do_log(nexus_json_encode($_SERVER));
//1. BLOCK ACCESS WITH WEB BROWSERS AND CHEATS!
$agent = $_SERVER [ " HTTP_USER_AGENT " ] ? ? '' ;
block_browser ();
//2. GET ANNOUNCE VARIABLES
// get string type passkey, info_hash, peer_id, event, ip from client
foreach ( array ( " passkey " , " info_hash " , " peer_id " , " event " ) as $x )
{
if ( isset ( $_GET [ $x ]))
$GLOBALS [ $x ] = $_GET [ $x ];
}
// get integer type port, downloaded, uploaded, left from client
foreach ( array ( " port " , " downloaded " , " uploaded " , " left " , " compact " , " no_peer_id " ) as $x )
{
$GLOBALS [ $x ] = intval ( $_GET [ $x ] ? ? 0 );
}
//check info_hash, peer_id and passkey
foreach ( array ( " info_hash " , " peer_id " , " port " , " downloaded " , " uploaded " , " left " ) as $x )
2023-06-10 02:07:56 +08:00
if ( ! isset ( $x )) warn ( " Missing key: $x " );
2023-06-04 15:24:56 +08:00
foreach ( array ( " info_hash " , " peer_id " ) as $x )
2023-06-10 02:07:56 +08:00
if ( strlen ( $GLOBALS [ $x ]) != 20 ) warn ( " Invalid $x ( " . strlen ( $GLOBALS [ $x ]) . " - " . rawurlencode ( $GLOBALS [ $x ]) . " ) " );
if ( isset ( $passkey ) && strlen ( $passkey ) != 32 ) warn ( " Invalid passkey ( " . strlen ( $passkey ) . " - $passkey ) " );
2023-06-04 15:24:56 +08:00
2023-05-30 03:02:49 +08:00
$redis = $Cache -> getRedis ();
$torrentNotExistsKey = " torrent_not_exists " ;
$authKeyInvalidKey = " authkey_invalid " ;
$passkeyInvalidKey = " passkey_invalid " ;
2023-06-04 15:24:56 +08:00
$isReAnnounce = false ;
2023-06-05 02:51:07 +08:00
$userAuthenticateKey = " " ;
2023-05-30 03:02:49 +08:00
if ( ! empty ( $_GET [ 'authkey' ])) {
$authkey = $_GET [ 'authkey' ];
$parts = explode ( " | " , $authkey );
if ( count ( $parts ) != 3 ) {
2023-06-10 02:07:56 +08:00
warn ( " authkey format error " );
2023-05-30 03:02:49 +08:00
}
2023-06-01 01:41:14 +08:00
$authKeyTid = $parts [ 0 ];
2023-06-05 02:51:07 +08:00
$authKeyUid = $userAuthenticateKey = $parts [ 1 ];
2023-06-01 01:41:14 +08:00
$subAuthkey = sprintf ( " %s|%s " , $authKeyTid , $authKeyUid );
2023-06-04 15:24:56 +08:00
//check ReAnnounce
2023-06-10 02:07:56 +08:00
$lockParams = [
'user' => $authKeyUid ,
'info_hash' => $info_hash
];
2023-06-04 15:24:56 +08:00
$lockString = http_build_query ( $lockParams );
$lockKey = " isReAnnounce: " . md5 ( $lockString );
if ( ! $redis -> set ( $lockKey , TIMENOW , [ 'nx' , 'ex' => 20 ])) {
$isReAnnounce = true ;
}
2023-06-05 02:51:07 +08:00
$reAnnounceCheckByAuthKey = " reAnnounceCheckByAuthKey: $subAuthkey " ;
if ( ! $isReAnnounce && ! $redis -> set ( $reAnnounceCheckByAuthKey , TIMENOW , [ 'nx' , 'ex' => 60 ])) {
2023-05-30 03:02:49 +08:00
$msg = " Request too frequent(a) " ;
2023-06-05 02:51:07 +08:00
do_log ( sprintf ( " [ANNOUNCE] %s key: %s already exists, value: %s " , $msg , $reAnnounceCheckByAuthKey , TIMENOW ));
2023-06-10 02:07:56 +08:00
warn ( $msg , 300 );
2023-05-30 03:02:49 +08:00
}
if ( $redis -> get ( " $authKeyInvalidKey : $authkey " )) {
$msg = " Invalid authkey " ;
do_log ( " [ANNOUNCE] $msg " );
2023-06-10 02:07:56 +08:00
warn ( $msg );
2023-05-30 03:02:49 +08:00
}
2023-06-04 15:24:56 +08:00
} elseif ( ! empty ( $_GET [ 'passkey' ])) {
2023-06-05 02:51:07 +08:00
$passkey = $userAuthenticateKey = $_GET [ 'passkey' ];
2023-05-30 03:02:49 +08:00
if ( $redis -> get ( " $passkeyInvalidKey : $passkey " )) {
$msg = " Passkey invalid " ;
do_log ( " [ANNOUNCE] $msg " );
2023-06-10 02:07:56 +08:00
warn ( $msg );
2023-05-30 03:02:49 +08:00
}
2023-06-04 15:24:56 +08:00
$lockParams = [];
2023-06-10 02:07:56 +08:00
foreach ([ 'info_hash' , 'passkey' ] as $lockField ) {
2023-06-04 15:24:56 +08:00
$lockParams [ $lockField ] = $_GET [ $lockField ];
}
$lockString = http_build_query ( $lockParams );
$lockKey = " isReAnnounce: " . md5 ( $lockString );
if ( ! $redis -> set ( $lockKey , TIMENOW , [ 'nx' , 'ex' => 20 ])) {
$isReAnnounce = true ;
2023-05-30 03:02:49 +08:00
}
2023-06-04 15:24:56 +08:00
} else {
2023-06-10 02:07:56 +08:00
warn ( " Require passkey or authkey " );
2023-05-30 03:02:49 +08:00
}
2023-06-04 15:24:56 +08:00
if ( $redis -> get ( " $torrentNotExistsKey : $info_hash " )) {
$msg = " Torrent not exists " ;
do_log ( " [ANNOUNCE] $msg " );
2023-09-05 15:48:21 +08:00
err ( $msg );
2023-06-04 15:24:56 +08:00
}
2023-06-05 03:02:04 +08:00
$torrentReAnnounceKey = sprintf ( 'reAnnounceCheckByInfoHash:%s:%s' , $userAuthenticateKey , $info_hash );
2023-06-05 02:51:07 +08:00
if ( ! $isReAnnounce && ! $redis -> set ( $torrentReAnnounceKey , TIMENOW , [ 'nx' , 'ex' => 60 ])) {
2023-06-04 15:24:56 +08:00
$msg = " Request too frequent(h) " ;
2023-06-05 02:51:07 +08:00
do_log ( sprintf ( " [ANNOUNCE] %s key: %s already exists, value: %s " , $msg , $torrentReAnnounceKey , TIMENOW ));
2023-06-10 02:07:56 +08:00
warn ( $msg , 300 );
2023-06-04 15:24:56 +08:00
}
2022-11-06 16:12:15 +08:00
dbconn_announce ();
2021-06-03 21:13:59 +08:00
//check authkey
if ( ! empty ( $_REQUEST [ 'authkey' ])) {
try {
2023-06-04 15:24:56 +08:00
$GLOBALS [ 'passkey' ] = $_GET [ 'passkey' ] = get_passkey_by_authkey ( $_REQUEST [ 'authkey' ]);
2021-06-03 21:13:59 +08:00
} catch ( \Exception $exception ) {
2023-05-30 03:02:49 +08:00
$redis -> set ( " $authKeyInvalidKey : " . $_REQUEST [ 'authkey' ], TIMENOW , [ 'ex' => 3600 * 24 ]);
2023-06-10 02:07:56 +08:00
warn ( $exception -> getMessage ());
2021-06-03 21:13:59 +08:00
}
}
2023-06-04 15:24:56 +08:00
2020-12-26 01:42:23 +08:00
//4. GET IP AND CHECK PORT
$ip = getip (); // avoid to get the spoof ip from some agent
2022-07-23 23:35:43 +08:00
$_GET [ 'ip' ] = $ip ;
2020-12-26 01:42:23 +08:00
if ( ! $port || $port > 0xffff )
2023-06-10 02:07:56 +08:00
warn ( " invalid port " );
2020-12-26 01:42:23 +08:00
if ( ! ip2long ( $ip )) //Disable compact announce with IPv6
$compact = 0 ;
2022-04-25 14:52:59 +08:00
$ipv4 = $ipv6 = '' ;
if ( isIPV4 ( $ip )) {
$ipv4 = $ip ;
} elseif ( isset ( $_GET [ 'ipv4' ]) && isIPV4 ( $_GET [ 'ipv4' ])) {
$ipv4 = $_GET [ 'ipv4' ];
}
if ( isIPV6 ( $ip )) {
$ipv6 = $ip ;
} elseif ( isset ( $_GET [ 'ipv6' ]) && isIPV6 ( $_GET [ 'ipv6' ])) {
$ipv6 = $_GET [ 'ipv6' ];
}
$peerIPV46 = " " ;
if ( $ipv4 ) {
$peerIPV46 .= " , ipv4 = " . sqlesc ( $ipv4 );
}
if ( $ipv6 ) {
$peerIPV46 .= " , ipv6 = " . sqlesc ( $ipv6 );
}
2020-12-26 01:42:23 +08:00
// check port and connectable
if ( portblacklisted ( $port ))
2023-06-10 02:07:56 +08:00
warn ( " Port $port is blacklisted. " );
2020-12-26 01:42:23 +08:00
//5. GET PEER LIST
// Number of peers that the client would like to receive from the tracker.This value is permitted to be zero. If omitted, typically defaults to 50 peers.
$rsize = 50 ;
foreach ( array ( " numwant " , " num want " , " num_want " ) as $k )
{
if ( isset ( $_GET [ $k ]))
{
2021-01-06 01:31:21 +08:00
$rsize = intval ( $_GET [ $k ] ? ? 0 );
2020-12-26 01:42:23 +08:00
break ;
}
}
// set if seeder based on left field
$seeder = ( $left == 0 ) ? " yes " : " no " ;
// check passkey
if ( ! $az = $Cache -> get_value ( 'user_passkey_' . $passkey . '_content' )){
2023-04-09 14:53:15 +08:00
$res = sql_query ( " SELECT id, username, downloadpos, enabled, uploaded, downloaded, class, parked, clientselect, showclienterror, passkey, donor, donoruntil, seedbonus FROM users WHERE passkey= " . sqlesc ( $passkey ) . " LIMIT 1 " );
2021-06-14 12:49:16 +08:00
$az = mysql_fetch_array ( $res );
2022-05-15 14:12:17 +08:00
do_log ( " [check passkey], currentUser: " . nexus_json_encode ( $az ));
2022-08-24 00:19:19 +08:00
$Cache -> cache_value ( 'user_passkey_' . $passkey . '_content' , $az , 3600 );
2020-12-26 01:42:23 +08:00
}
2023-05-30 03:02:49 +08:00
if ( ! $az ) {
$redis -> set ( " $passkeyInvalidKey : $passkey " , TIMENOW , [ 'ex' => 24 * 3600 ]);
2023-06-10 02:07:56 +08:00
warn ( " Invalid passkey! Re-download the .torrent from $BASEURL " );
2023-05-30 03:02:49 +08:00
}
2024-10-31 01:55:16 +08:00
if ( $az [ " enabled " ] == " no " )
warn ( " Your account is disabled! " , 300 );
elseif ( $az [ " parked " ] == " yes " )
warn ( " Your account is parked! (Read the FAQ) " , 300 );
elseif ( $az [ " downloadpos " ] == " no " )
warn ( " Your downloading privileges have been disabled! (Read the rules) " , 300 );
2021-01-06 01:31:21 +08:00
$userid = intval ( $az [ 'id' ] ? ? 0 );
2021-06-06 00:51:48 +08:00
unset ( $GLOBALS [ 'CURUSER' ]);
2021-06-14 12:49:16 +08:00
$CURUSER = $GLOBALS [ " CURUSER " ] = $az ;
2022-10-01 00:11:22 +08:00
$isDonor = is_donor ( $az );
2022-07-23 23:35:43 +08:00
$az [ '__is_donor' ] = $isDonor ;
$log = " user: $userid , isDonor: $isDonor , seeder: $seeder , ip: $ip , ipv4: $ipv4 , ipv6: $ipv6 " ;
2020-12-26 01:42:23 +08:00
//3. CHECK IF CLIENT IS ALLOWED
2022-02-25 19:12:14 +08:00
//$clicheck_res = check_client($peer_id,$agent,$client_familyid);
/**
* refactor check client
*
* @ since v1 . 6.0 - beta14
*/
$agentAllowRep = new \App\Repositories\AgentAllowRepository ();
$clicheck_res = '' ;
try {
$checkClientResult = $agentAllowRep -> checkClient ( $peer_id , $agent );
$client_familyid = $checkClientResult -> id ;
} catch ( \Exception $exception ) {
$clicheck_res = $exception -> getMessage ();
}
2020-12-26 01:42:23 +08:00
if ( $clicheck_res ){
if ( $az [ 'showclienterror' ] == 'no' )
{
2023-03-06 15:21:47 +08:00
sql_query ( " UPDATE users SET showclienterror = 'yes' WHERE id = " . sqlesc ( $userid ));
2020-12-26 01:42:23 +08:00
$Cache -> delete_value ( 'user_passkey_' . $passkey . '_content' );
}
err ( $clicheck_res );
}
elseif ( $az [ 'showclienterror' ] == 'yes' ){
$USERUPDATESET [] = " showclienterror = 'no' " ;
$Cache -> delete_value ( 'user_passkey_' . $passkey . '_content' );
}
// check torrent based on info_hash
2023-02-11 16:08:48 +08:00
$checkTorrentSql = " SELECT torrents.id, size, owner, sp_state, seeders, leechers, UNIX_TIMESTAMP(added) AS ts, added, banned, hr, approval_status, price, categories.mode FROM torrents left join categories on torrents.category = categories.id WHERE " . hash_where ( " info_hash " , $info_hash );
2020-12-26 01:42:23 +08:00
if ( ! $torrent = $Cache -> get_value ( 'torrent_hash_' . $info_hash . '_content' )){
2021-06-06 00:40:28 +08:00
$res = sql_query ( $checkTorrentSql );
2020-12-26 01:42:23 +08:00
$torrent = mysql_fetch_array ( $res );
$Cache -> cache_value ( 'torrent_hash_' . $info_hash . '_content' , $torrent , 350 );
}
2021-06-06 00:40:28 +08:00
if ( ! $torrent ) {
2021-06-06 01:30:59 +08:00
$firstNeedle = " info_hash= " ;
$queryString = $_SERVER [ 'QUERY_STRING' ];
$start = strpos ( $queryString , $firstNeedle ) + strlen ( $firstNeedle );
$end = strpos ( $queryString , " & " , $start );
$infoHashUrlEncode = substr ( $queryString , $start , $end - $start );
2022-11-06 16:12:15 +08:00
do_log ( " [TORRENT NOT EXISTS] $checkTorrentSql , params: $queryString , infoHashUrlEncode: $infoHashUrlEncode " );
2023-05-30 03:02:49 +08:00
$redis -> set ( " $torrentNotExistsKey : $info_hash " , TIMENOW , [ 'ex' => 24 * 3600 ]);
2023-09-05 15:48:21 +08:00
err ( " torrent not registered with this tracker " );
2022-08-23 01:02:54 +08:00
}
2023-06-08 01:59:28 +08:00
$GLOBALS [ 'torrent' ] = $torrent ;
2023-06-01 01:41:14 +08:00
$torrentid = $torrent [ " id " ];
if ( isset ( $authKeyTid ) && $authKeyTid != $torrentid ) {
$redis -> set ( " $authKeyInvalidKey : $authkey " , TIMENOW , [ 'ex' => 3600 * 24 ]);
$msg = " Invalid authkey: $authkey 2 " ;
do_log ( " [ANNOUNCE] $msg " );
2023-06-10 02:07:56 +08:00
warn ( $msg );
2023-06-01 01:41:14 +08:00
}
2022-08-24 14:31:34 +08:00
if ( $torrent [ 'banned' ] == 'yes' ) {
if ( ! user_can ( 'seebanned' , false , $az [ 'id' ])) {
2022-06-24 14:55:10 +08:00
err ( " torrent banned " );
2022-08-24 14:31:34 +08:00
}
}
if ( $torrent [ 'approval_status' ] != \App\Models\Torrent :: APPROVAL_STATUS_ALLOW && get_setting ( 'torrent.approval_status_none_visible' ) == 'no' ) {
if ( ! user_can ( 'seebanned' , false , $az [ 'id' ])) {
2022-06-24 14:55:10 +08:00
err ( " torrent review not approved " );
}
2021-06-06 00:40:28 +08:00
}
2022-08-24 14:31:34 +08:00
2020-12-26 01:42:23 +08:00
// select peers info from peers table for this torrent
2023-06-01 01:41:14 +08:00
2020-12-26 01:42:23 +08:00
$numpeers = $torrent [ " seeders " ] + $torrent [ " leechers " ];
2022-07-23 23:35:43 +08:00
$log .= " , torrent: $torrentid " ;
2020-12-26 01:42:23 +08:00
if ( $seeder == 'yes' ){ //Don't report seeds to other seeders
$only_leech_query = " AND seeder = 'no' " ;
$newnumpeers = $torrent [ " leechers " ];
}
else {
$only_leech_query = " " ;
$newnumpeers = $numpeers ;
}
if ( $newnumpeers > $rsize )
$limit = " ORDER BY RAND() LIMIT $rsize " ;
else $limit = " " ;
2023-06-08 01:59:28 +08:00
$announce_wait = \App\Repositories\TrackerRepository :: MIN_ANNOUNCE_WAIT_SECOND ;
2023-04-02 02:42:45 +08:00
$fields = " id, seeder, peer_id, ip, ipv4, ipv6, port, uploaded, downloaded, userid, last_action, UNIX_TIMESTAMP(last_action) as last_action_unix_timestamp, prev_action, ( " . TIMENOW . " - UNIX_TIMESTAMP(last_action)) AS announcetime, UNIX_TIMESTAMP(prev_action) AS prevts " ;
2021-06-21 02:01:26 +08:00
//$peerlistsql = "SELECT ".$fields." FROM peers WHERE torrent = ".$torrentid." AND connectable = 'yes' ".$only_leech_query.$limit;
/**
* return all peers , include connectable no
* @ since 1.6 . 0 - beta12
*/
$peerlistsql = " SELECT " . $fields . " FROM peers WHERE torrent = " . $torrentid . $only_leech_query . $limit ;
2020-12-26 01:42:23 +08:00
2024-07-06 01:15:25 +08:00
$announce_one_begin = ( 0 + $announce_interval ) / 2 ;
$announce_one_end = ( $announce_interval + $annintertwo ) / 2 ;
$announce_two_end = ( $annintertwo + $anninterthree ) / 2 ;
$announce_three_end = $anninterthree ; //can not bigger, cleanup will consider dead and delete it
$real_annnounce_interval = mt_rand ( $announce_one_begin , $announce_one_end );
2020-12-26 01:42:23 +08:00
if ( $anninterthreeage && ( $anninterthree > $announce_wait ) && ( TIMENOW - $torrent [ 'ts' ]) >= ( $anninterthreeage * 86400 ))
2024-07-06 01:15:25 +08:00
$real_annnounce_interval = mt_rand ( $announce_two_end , $announce_three_end );
2020-12-26 01:42:23 +08:00
elseif ( $annintertwoage && ( $annintertwo > $announce_wait ) && ( TIMENOW - $torrent [ 'ts' ]) >= ( $annintertwoage * 86400 ))
2024-07-06 01:15:25 +08:00
$real_annnounce_interval = mt_rand ( $announce_one_end , $announce_two_end );
2020-12-26 01:42:23 +08:00
2021-06-09 02:23:09 +08:00
//$resp = "d" . benc_str("interval") . "i" . $real_annnounce_interval . "e" . benc_str("min interval") . "i" . $announce_wait . "e". benc_str("complete") . "i" . $torrent["seeders"] . "e" . benc_str("incomplete") . "i" . $torrent["leechers"] . "e" . benc_str("peers");
$rep_dict = [
" interval " => ( int ) $real_annnounce_interval ,
" min interval " => ( int ) $announce_wait ,
" complete " => ( int ) $torrent [ " seeders " ],
" incomplete " => ( int ) $torrent [ " leechers " ],
2022-08-05 17:01:13 +08:00
" peers " => [], // By default it is a array object, only when `&compact=1` then it should be a string
2021-06-09 02:23:09 +08:00
];
if ( $compact == 1 ) {
$rep_dict [ 'peers' ] = '' ; // Change `peers` from array to string
$rep_dict [ 'peers6' ] = '' ; // If peer use IPv6 address , we should add packed string in `peers6`
}
2023-06-08 01:59:28 +08:00
$GLOBALS [ 'rep_dict' ] = $rep_dict ;
2023-06-04 15:24:56 +08:00
if ( $isReAnnounce ) {
2022-07-31 23:01:28 +08:00
do_log ( " $log , [YES_RE_ANNOUNCE] " );
2022-02-17 01:10:08 +08:00
benc_resp ( $rep_dict );
exit ();
}
2022-07-31 23:01:28 +08:00
$log .= " , [NO_RE_ANNOUNCE] " ;
2020-12-26 01:42:23 +08:00
unset ( $self );
2022-02-19 23:19:09 +08:00
$res = sql_query ( $peerlistsql );
2021-06-09 02:23:09 +08:00
if ( isset ( $event ) && $event == " stopped " ) {
// Don't fetch peers for stopped event
} else {
// bencoding the peers info get for this announce
while ( $row = mysql_fetch_assoc ( $res )) {
$row [ " peer_id " ] = hash_pad ( $row [ " peer_id " ]);
// $peer_id is the announcer's peer_id while $row["peer_id"] is randomly selected from the peers table
2023-04-02 02:42:45 +08:00
if ( $row [ " peer_id " ] === $peer_id && $row [ 'userid' ] == $userid ) {
2021-06-09 02:23:09 +08:00
$self = $row ;
continue ;
2021-05-01 02:02:01 +08:00
}
2021-06-09 02:23:09 +08:00
if ( $compact == 1 ) {
2022-08-05 17:01:13 +08:00
// $peerField = filter_var($row['ip'],FILTER_VALIDATE_IP,FILTER_FLAG_IPV6) ? 'peers6' : 'peers';
// $rep_dict[$peerField] .= inet_pton($row["ip"]) . pack("n", $row["port"]);
if ( ! empty ( $row [ 'ipv4' ])) {
$rep_dict [ 'peers' ] .= inet_pton ( $row [ " ipv4 " ]) . pack ( " n " , $row [ " port " ]);
}
if ( ! empty ( $row [ 'ipv6' ])) {
$rep_dict [ 'peers6' ] .= inet_pton ( $row [ " ipv6 " ]) . pack ( " n " , $row [ " port " ]);
}
2021-06-09 02:23:09 +08:00
} else {
2022-08-05 17:01:13 +08:00
// $peer = [
// 'ip' => $row["ip"],
// 'port' => (int) $row["port"]
// ];
//
// if ($no_peer_id == 1) {
// $peer['peer id'] = $row["peer_id"];
// }
// $rep_dict['peers'][] = $peer;
if ( ! empty ( $row [ 'ipv4' ])) {
$peer = [
'peer_id' => $row [ 'peer_id' ],
'ip' => $row [ 'ipv4' ],
'port' => ( int ) $row [ 'port' ],
];
if ( $no_peer_id ) unset ( $peer [ 'peer_id' ]);
$rep_dict [ 'peers' ][] = $peer ;
}
if ( ! empty ( $row [ 'ipv6' ])) {
$peer = [
'peer_id' => $row [ 'peer_id' ],
'ip' => $row [ 'ipv6' ],
'port' => ( int ) $row [ 'port' ],
];
if ( $no_peer_id ) unset ( $peer [ 'peer_id' ]);
2022-08-05 22:12:45 +08:00
$rep_dict [ 'peers' ][] = $peer ;
2022-08-05 17:01:13 +08:00
}
2021-06-09 02:23:09 +08:00
}
}
2021-05-01 02:02:01 +08:00
}
2023-04-02 02:42:45 +08:00
$selfwhere = " torrent = $torrentid AND " . hash_where ( " peer_id " , $peer_id ) . " AND userid = $userid " ;
2020-12-26 01:42:23 +08:00
//no found in the above random selection
if ( ! isset ( $self ))
{
$res = sql_query ( " SELECT $fields FROM peers WHERE $selfwhere LIMIT 1 " );
$row = mysql_fetch_assoc ( $res );
if ( $row )
{
$self = $row ;
}
}
2022-08-15 22:56:43 +08:00
if ( isset ( $self )) {
$log .= sprintf (
', [SELF], TIMENOW: %s(%s), last_action: %s, last_action_unix_timestamp: %s, announcetime: %s, prev_action: %s, prevts: %s' ,
TIMENOW , date ( 'Y-m-d H:i:s' , TIMENOW ), $self [ 'last_action' ], $self [ 'last_action_unix_timestamp' ], $self [ 'announcetime' ], $self [ 'prev_action' ], $self [ 'prevts' ]
);
}
2020-12-26 01:42:23 +08:00
// min announce time
2022-04-25 14:52:59 +08:00
if ( isset ( $self ) && empty ( $_GET [ 'event' ]) && $self [ 'prevts' ] > ( TIMENOW - $announce_wait )) {
2022-08-15 22:56:43 +08:00
do_log ( $log );
2021-06-14 12:49:16 +08:00
do_log ( sprintf (
2022-08-15 22:56:43 +08:00
'timezone: %s, self prevts(%s -> %s, %s) > now(%s, %s) - announce_wait(%s)' ,
ini_get ( 'date.timezone' ), $self [ 'prev_action' ], $self [ 'prevts' ], date ( 'Y-m-d H:i:s' , $self [ 'prevts' ]), TIMENOW , date ( 'Y-m-d H:i:s' , TIMENOW ), $announce_wait
2021-06-14 12:49:16 +08:00
));
2023-06-10 02:07:56 +08:00
warn ( 'There is a minimum announce time of ' . $announce_wait . ' seconds' , $announce_wait );
2021-06-14 12:49:16 +08:00
}
2022-07-23 15:05:32 +08:00
$isSeedBoxRuleEnabled = get_setting ( 'seed_box.enabled' ) == 'yes' ;
$isIPSeedBox = false ;
2022-09-13 00:50:56 +08:00
if ( $isSeedBoxRuleEnabled ) {
2022-09-12 20:00:07 +08:00
if ( ! empty ( $ipv4 )) {
$isIPSeedBox = isIPSeedBox ( $ipv4 , $userid );
}
if ( ! $isIPSeedBox && ! empty ( $ipv6 )) {
$isIPSeedBox = isIPSeedBox ( $ipv6 , $userid );
}
2022-07-23 15:05:32 +08:00
}
2022-08-15 22:56:43 +08:00
$log .= " , [SEED_BOX], isSeedBoxRuleEnabled: $isSeedBoxRuleEnabled , isIPSeedBox: $isIPSeedBox " ;
2022-07-23 23:35:43 +08:00
do_log ( $log );
2022-07-23 15:05:32 +08:00
2020-12-26 01:42:23 +08:00
// current peer_id, or you could say session with tracker not found in table peers
if ( ! isset ( $self ))
{
2023-06-10 02:07:56 +08:00
$sameIPRecord = mysql_fetch_assoc ( sql_query ( " select id from peers where torrent = $torrentid and userid = $userid and ip = ' $ip ' limit 1 " ));
if ( ! empty ( $sameIPRecord ) && $seeder == 'yes' ) {
warn ( " You cannot seed the same torrent in the same location from more than 1 client. " , 300 );
}
2020-12-26 01:42:23 +08:00
$valid = @ mysql_fetch_row ( @ sql_query ( " SELECT COUNT(*) FROM peers WHERE torrent= $torrentid AND userid= " . sqlesc ( $userid )));
2023-09-05 15:48:21 +08:00
if ( $valid [ 0 ] >= 1 && $seeder == 'no' ) err ( " You already are downloading the same torrent. You may only leech from one location at a time. " , 300 );
if ( $valid [ 0 ] >= 3 && $seeder == 'yes' ) err ( " You cannot seed the same torrent from more than 3 locations. " , 300 );
2020-12-26 01:42:23 +08:00
if ( $az [ " class " ] < UC_VIP )
{
$ratio = (( $az [ " downloaded " ] > 0 ) ? ( $az [ " uploaded " ] / $az [ " downloaded " ]) : 1 );
$gigs = $az [ " downloaded " ] / ( 1024 * 1024 * 1024 );
if ( $waitsystem == " yes " )
{
if ( $gigs > 10 )
{
$elapsed = strtotime ( date ( " Y-m-d H:i:s " )) - $torrent [ " ts " ];
if ( $ratio < 0.4 ) $wait = 24 ;
elseif ( $ratio < 0.5 ) $wait = 12 ;
elseif ( $ratio < 0.6 ) $wait = 6 ;
elseif ( $ratio < 0.8 ) $wait = 3 ;
else $wait = 0 ;
if ( $elapsed < $wait )
2023-06-10 02:07:56 +08:00
warn ( " Your ratio is too low! You need to wait " . mkprettytime ( $wait * 3600 - $elapsed ) . " to start, please read $BASEURL /faq.php#id46 for details " , $elapsed );
2020-12-26 01:42:23 +08:00
}
}
if ( $maxdlsystem == " yes " )
{
if ( $gigs > 10 )
if ( $ratio < 0.5 ) $max = 1 ;
elseif ( $ratio < 0.65 ) $max = 2 ;
elseif ( $ratio < 0.8 ) $max = 3 ;
elseif ( $ratio < 0.95 ) $max = 4 ;
else $max = 0 ;
if ( $max > 0 )
{
2023-06-10 02:07:56 +08:00
$res = sql_query ( " SELECT COUNT(*) AS num FROM peers WHERE userid=' $userid ' AND seeder='no' " ) or warn ( " Tracker error 5 " , 300 );
2020-12-26 01:42:23 +08:00
$row = mysql_fetch_assoc ( $res );
if ( $row [ 'num' ] >= $max ) err ( " Your slot limit is reached! You may at most download $max torrents at the same time, please read $BASEURL /faq.php#id66 for details " );
}
}
}
2023-06-04 15:24:56 +08:00
if (
$seeder == 'no'
&& isset ( $az [ 'seedbonus' ])
&& isset ( $torrent [ 'price' ])
&& $torrent [ 'price' ] > 0
&& $torrent [ 'owner' ] != $userid
&& get_setting ( " torrent.paid_torrent_enabled " ) == " yes "
) {
2024-10-31 01:55:16 +08:00
$torrentRep = new \App\Repositories\TorrentRepository ();
$buyStatus = $torrentRep -> getBuyStatus ( $userid , $torrentid );
if ( $buyStatus > 0 ) {
do_log ( sprintf ( " user: %v buy torrent: %v fail count: %v " , $userid , $torrentid , $buyStatus ), " error " );
if ( $buyStatus > 3 ) {
//warn
\App\Utils\MsgAlert :: getInstance () -> add (
" announce_paid_torrent_too_many_times " ,
time () + 86400 ,
" announce to paid torrent and fail too many times, please make sure you have enough bonus! " ,
" " ,
" black "
);
2023-06-08 01:59:28 +08:00
}
2024-10-31 01:55:16 +08:00
if ( $buyStatus > 10 ) {
//disable download
( new \App\Repositories\UserRepository ()) -> updateDownloadPrivileges ( null , $userid , 'no' , 'announce_paid_torrent_too_many_times' );
}
warn ( " purchase fail, please try again later, please make sure you have enough bonus " , 300 );
2023-06-08 01:59:28 +08:00
}
2024-11-03 15:29:21 +08:00
if ( $buyStatus == \App\Repositories\TorrentRepository :: BUY_STATUS_UNKNOWN ) {
//just enqueue job
\App\Utils\ThirdPartyJob :: addBuyTorrent ( $userid , $torrentid );
warn ( " purchase in progress, please wait " , 300 );
2023-06-04 15:24:56 +08:00
}
}
2020-12-26 01:42:23 +08:00
}
else // continue an existing session
{
$upthis = $trueupthis = max ( 0 , $uploaded - $self [ " uploaded " ]);
$downthis = $truedownthis = max ( 0 , $downloaded - $self [ " downloaded " ]);
2021-03-12 20:50:55 +08:00
$announcetime = ( $self [ " seeder " ] == " yes " ? " seedtime = seedtime + { $self [ 'announcetime' ] } " : " leechtime = leechtime + { $self [ 'announcetime' ] } " );
2020-12-26 01:42:23 +08:00
$is_cheater = false ;
2022-07-30 15:54:32 +08:00
if ( $self [ 'announcetime' ] > 0 && $isSeedBoxRuleEnabled && ! ( $az [ 'class' ] >= \App\Models\User :: CLASS_VIP || $isDonor ) && ! $isIPSeedBox ) {
$notSeedBoxMaxSpeedMbps = get_setting ( 'seed_box.not_seed_box_max_speed' );
$upSpeedMbps = number_format (( $trueupthis / $self [ 'announcetime' ] / 1024 / 1024 ) * 8 );
do_log ( " notSeedBoxMaxSpeedMbps: $notSeedBoxMaxSpeedMbps , upSpeedMbps: $upSpeedMbps " );
if ( $upSpeedMbps > $notSeedBoxMaxSpeedMbps ) {
2022-10-06 18:19:39 +08:00
( new \App\Repositories\UserRepository ()) -> updateDownloadPrivileges ( null , $userid , 'no' , 'upload_over_speed' );
2023-04-20 02:08:09 +08:00
do_log ( " user: $userid downloading privileges have been disabled! (over speed), upSpeedMbps: $upSpeedMbps > notSeedBoxMaxSpeedMbps: $notSeedBoxMaxSpeedMbps " , 'error' );
2023-06-10 02:07:56 +08:00
warn ( " Your downloading privileges have been disabled! (over speed) " , 300 );
2022-07-30 15:54:32 +08:00
}
2022-07-23 15:05:32 +08:00
}
2021-04-29 02:52:22 +08:00
2020-12-26 01:42:23 +08:00
if ( $cheaterdet_security ){
if ( $az [ 'class' ] < $nodetect_security && $self [ 'announcetime' ] > 10 )
{
$is_cheater = check_cheater ( $userid , $torrent [ 'id' ], $upthis , $downthis , $self [ 'announcetime' ], $torrent [ 'seeders' ], $torrent [ 'leechers' ]);
}
}
2021-04-29 02:52:22 +08:00
2021-03-12 20:50:55 +08:00
do_log ( " upthis: $upthis , downthis: $downthis , announcetime: $announcetime , is_cheater: $is_cheater " );
2023-09-20 01:14:08 +08:00
$snatchInfo = get_snatch_info ( $torrentid , $userid );
2020-12-26 01:42:23 +08:00
if ( ! $is_cheater && ( $trueupthis > 0 || $truedownthis > 0 ))
{
2023-06-04 15:24:56 +08:00
$dataTraffic = getDataTraffic ( $torrent , $_GET , $az , $self , $snatchInfo , apply_filter ( 'torrent_promotion' , $torrent ));
2022-07-23 23:35:43 +08:00
$USERUPDATESET [] = " uploaded = uploaded + " . $dataTraffic [ 'uploaded_increment_for_user' ];
$USERUPDATESET [] = " downloaded = downloaded + " . $dataTraffic [ 'downloaded_increment_for_user' ];
2020-12-26 01:42:23 +08:00
}
}
$dt = sqlesc ( date ( " Y-m-d H:i:s " ));
$updateset = array ();
2022-07-12 17:42:26 +08:00
$hasChangeSeederLeecher = false ;
2020-12-26 01:42:23 +08:00
// set non-type event
if ( ! isset ( $event ))
$event = " " ;
if ( isset ( $self ) && $event == " stopped " )
{
2023-04-02 02:42:45 +08:00
sql_query ( " DELETE FROM peers WHERE id = { $self [ 'id' ] } " ) or err ( " D Err " );
if ( mysql_affected_rows () && ! empty ( $snatchInfo ))
2020-12-26 01:42:23 +08:00
{
2024-11-04 13:09:25 +08:00
$updateset [] = ( $self [ " seeder " ] == " yes " ? " seeders = seeders - 1 " : " leechers = leechers - 1 " );
2022-07-12 17:42:26 +08:00
$hasChangeSeederLeecher = true ;
2023-04-02 02:42:45 +08:00
sql_query ( " UPDATE snatched SET uploaded = uploaded + $trueupthis , downloaded = downloaded + $truedownthis , to_go = $left , $announcetime , last_action = " . $dt . " WHERE id = { $snatchInfo [ 'id' ] } " ) or err ( " SL Err 1 " );
2020-12-26 01:42:23 +08:00
}
}
elseif ( isset ( $self ))
{
2021-01-20 20:06:48 +08:00
$finished = $finished_snatched = '' ;
2023-09-05 15:48:21 +08:00
if ( $event == " completed " )
2020-12-26 01:42:23 +08:00
{
//sql_query("UPDATE snatched SET finished = 'yes', completedat = $dt WHERE torrentid = $torrentid AND userid = $userid");
2021-01-20 20:06:48 +08:00
$finished .= " , finishedat = " . TIMENOW ;
2020-12-26 01:42:23 +08:00
$finished_snatched = " , completedat = " . $dt . " , finished = 'yes' " ;
$updateset [] = " times_completed = times_completed + 1 " ;
}
2023-04-02 02:42:45 +08:00
sql_query ( " UPDATE peers SET ip = " . sqlesc ( $ip ) . " , port = $port , uploaded = $uploaded , downloaded = $downloaded , to_go = $left , prev_action = last_action, last_action = $dt , seeder = ' $seeder ', agent = " . sqlesc ( $agent ) . " , is_seed_box = " . intval ( $isIPSeedBox ) . " $finished $peerIPV46 WHERE id = { $self [ 'id' ] } " ) or err ( " PL Err 1 " );
2020-12-26 01:42:23 +08:00
if ( mysql_affected_rows ())
{
2022-07-12 17:42:26 +08:00
if ( $seeder <> $self [ " seeder " ]) {
2024-11-04 13:09:25 +08:00
$updateset [] = ( $seeder == " yes " ? " seeders = seeders + 1, leechers = leechers - 1 " : " seeders = seeders - 1, leechers = leechers + 1 " );
2022-07-12 17:42:26 +08:00
$hasChangeSeederLeecher = true ;
}
2022-07-23 15:05:32 +08:00
if ( ! empty ( $snatchInfo )) {
2023-04-02 02:42:45 +08:00
sql_query ( " UPDATE snatched SET uploaded = uploaded + $trueupthis , downloaded = downloaded + $truedownthis , to_go = $left , $announcetime , last_action = " . $dt . " $finished_snatched WHERE id = { $snatchInfo [ 'id' ] } " ) or err ( " SL Err 2 " );
2022-07-23 15:05:32 +08:00
do_action ( 'snatched_saved' , $torrent , $snatchInfo );
2021-06-21 02:01:26 +08:00
}
2020-12-26 01:42:23 +08:00
}
}
else
{
2022-02-01 16:05:44 +08:00
if ( $event != 'stopped' ) {
$isPeerExistResultSet = sql_query ( " select id from peers where $selfwhere limit 1 " );
2022-07-23 15:05:32 +08:00
if ( mysql_num_rows ( $isPeerExistResultSet ) == 0 ) {
2024-10-31 01:55:16 +08:00
$connectable = " yes " ;
2022-09-12 20:00:07 +08:00
$insertPeerSql = " INSERT INTO peers (torrent, userid, peer_id, ip, port, connectable, uploaded, downloaded, to_go, started, last_action, seeder, agent, downloadoffset, uploadoffset, passkey, ipv4, ipv6, is_seed_box) VALUES ( $torrentid , $userid , " . sqlesc ( $peer_id ) . " , " . sqlesc ( $ip ) . " , $port , ' $connectable ', $uploaded , $downloaded , $left , $dt , $dt , ' $seeder ', " . sqlesc ( $agent ) . " , $downloaded , $uploaded , " . sqlesc ( $passkey ) . " , " . sqlesc ( $ipv4 ) . " , " . sqlesc ( $ipv6 ) . " , " . intval ( $isIPSeedBox ) . " ) " ;
2022-02-17 01:10:08 +08:00
do_log ( " [INSERT PEER] peer not exists for $selfwhere , do insert with $insertPeerSql " );
try {
sql_query ( $insertPeerSql ) or err ( " PL Err 2 " );
if ( mysql_affected_rows ())
{
2024-11-04 13:09:25 +08:00
$updateset [] = ( $seeder == " yes " ? " seeders = seeders + 1 " : " leechers = leechers + 1 " );
2022-07-12 17:42:26 +08:00
$hasChangeSeederLeecher = true ;
2023-04-02 02:42:45 +08:00
// $check = @mysql_fetch_row(@sql_query("SELECT COUNT(*) FROM snatched WHERE torrentid = $torrentid AND userid = $userid"));
$checkSnatchedRes = mysql_fetch_assoc ( sql_query ( " SELECT id FROM snatched WHERE torrentid = $torrentid AND userid = $userid limit 1 " ));
if ( empty ( $checkSnatchedRes [ 'id' ]))
2022-02-17 01:10:08 +08:00
sql_query ( " INSERT INTO snatched (torrentid, userid, ip, port, uploaded, downloaded, to_go, startdat, last_action) VALUES ( $torrentid , $userid , " . sqlesc ( $ip ) . " , $port , $uploaded , $downloaded , $left , $dt , $dt ) " ) or err ( " SL Err 4 " );
else
2023-04-02 02:42:45 +08:00
sql_query ( " UPDATE snatched SET to_go = $left , last_action = " . $dt . " WHERE id = { $checkSnatchedRes [ 'id' ] } " ) or err ( " SL Err 3.1 " );
2022-02-17 01:10:08 +08:00
}
} catch ( \Exception $exception ) {
do_log ( " [INSERT PEER] error: " . $exception -> getMessage ());
2022-02-01 16:05:44 +08:00
}
} else {
do_log ( " [INSERT PEER] peer already exists for $selfwhere . " );
}
2021-05-01 02:02:01 +08:00
} else {
2022-02-01 16:05:44 +08:00
do_log ( " [INSERT PEER] event = 'stopped', ignore. " );
2021-05-01 02:02:01 +08:00
}
2020-12-26 01:42:23 +08:00
}
2023-09-20 01:14:08 +08:00
//handle hr
2023-09-21 12:32:51 +08:00
if (( $left > 0 || $event == " completed " ) && $az [ 'class' ] < \App\Models\HitAndRun :: MINIMUM_IGNORE_USER_CLASS && ! $isDonor && isset ( $torrent [ 'mode' ])) {
2023-09-20 01:14:08 +08:00
$hrMode = \App\Models\HitAndRun :: getConfig ( 'mode' , $torrent [ 'mode' ]);
$hrLog = sprintf ( " [HR_LOG] user: %d, torrent: %d, hrMode: %s " , $userid , $torrentid , $hrMode );
if ( $hrMode == \App\Models\HitAndRun :: MODE_GLOBAL || ( $hrMode == \App\Models\HitAndRun :: MODE_MANUAL && $torrent [ 'hr' ] == \App\Models\Torrent :: HR_YES )) {
$hrCacheKey = sprintf ( " hit_and_run:%d:%d " , $userid , $torrentid );
2024-10-31 01:55:16 +08:00
$hrExists = \Nexus\Database\NexusDB :: remember ( $hrCacheKey , mt_rand ( 86400 * 365 * 5 , 86400 * 365 * 10 ), function () use ( $torrentid , $userid ) {
2024-11-03 15:29:21 +08:00
return \App\Models\HitAndRun :: query () -> where ( " uid " , $userid ) -> where ( " torrent_id " , $torrentid ) -> exists () ? 1 : 0 ;
2023-09-20 01:14:08 +08:00
});
$hrLog .= " , hrExists: $hrExists " ;
if ( ! $hrExists ) {
//last check include rate
$includeRate = \App\Models\HitAndRun :: getConfig ( 'include_rate' , $torrent [ 'mode' ]);
if ( $includeRate === " " || $includeRate === null ) {
//not set yet
$includeRate = 1 ;
}
$hrLog .= " , includeRate: $includeRate " ;
//get newest snatch info
$snatchInfo = get_snatch_info ( $torrentid , $userid );
$requiredDownloaded = $torrent [ 'size' ] * $includeRate ;
if ( $snatchInfo [ 'downloaded' ] >= $requiredDownloaded ) {
2023-09-21 13:26:06 +08:00
$nowStr = date ( 'Y-m-d H:i:s' );
$sql = sprintf (
" insert into hit_and_runs (uid, torrent_id, snatched_id, created_at, updated_at) values (%d, %d, %d, '%s', '%s') on duplicate key update created_at = '%s', updated_at = '%s' " ,
$userid , $torrentid , $snatchInfo [ 'id' ], $nowStr , $nowStr , $nowStr , $nowStr
);
2023-09-20 01:14:08 +08:00
$affectedRows = sql_query ( $sql );
2023-09-21 03:23:40 +08:00
do_log ( " $hrLog , total downloaded: { $snatchInfo [ 'downloaded' ] } >= required: $requiredDownloaded , [INSERT_H&R], sql: $sql , affectedRows: $affectedRows " );
2023-09-20 01:14:08 +08:00
} else {
2023-09-21 03:23:40 +08:00
do_log ( " $hrLog , total downloaded: { $snatchInfo [ 'downloaded' ] } < required: $requiredDownloaded " , " debug " );
2023-09-20 01:14:08 +08:00
}
} else {
do_log ( " $hrLog , already exists " , " debug " );
}
} else {
do_log ( " $hrLog , not match " , " debug " );
}
}
2024-11-04 13:09:25 +08:00
// revert to only increment/decrement
//if (isset($event) && !empty($event)) {
// $updateset[] = 'seeders = ' . get_row_count("peers", "where torrent = $torrentid and to_go = 0");
// $updateset[] = 'leechers = ' . get_row_count("peers", "where torrent = $torrentid and to_go > 0");
//}
2022-04-20 00:52:12 +08:00
2022-07-12 17:42:26 +08:00
if ( count ( $updateset ) || $hasChangeSeederLeecher ) // Update only when there is change in peer counts
2020-12-26 01:42:23 +08:00
{
$updateset [] = " visible = 'yes' " ;
$updateset [] = " last_action = $dt " ;
2022-07-12 17:42:26 +08:00
$sql = " UPDATE torrents SET " . join ( " , " , $updateset ) . " WHERE id = $torrentid " ;
sql_query ( $sql );
do_log ( " [ANNOUNCE_UPDATE_TORRENT], $sql " );
2020-12-26 01:42:23 +08:00
}
2022-05-31 01:10:20 +08:00
if ( $client_familyid != 0 && $client_familyid != $az [ 'clientselect' ]) {
$USERUPDATESET [] = " clientselect = " . sqlesc ( $client_familyid );
}
/**
* VIP do not calculate downloaded
* @ since 1.7 . 13
*/
if ( $az [ 'class' ] == UC_VIP ) {
foreach ( $USERUPDATESET as $key => $value ) {
if ( str_contains ( $value , 'downloaded' )) {
unset ( $USERUPDATESET [ $key ]);
2022-05-30 13:26:07 +08:00
}
}
2022-05-31 01:10:20 +08:00
}
if ( count ( $USERUPDATESET ) && $userid )
{
2022-07-12 17:42:26 +08:00
$sql = " UPDATE users SET " . join ( " , " , $USERUPDATESET ) . " WHERE id = " . $userid ;
sql_query ( $sql );
do_log ( " [ANNOUNCE_UPDATE_USER], $sql " );
2020-12-26 01:42:23 +08:00
}
2023-07-10 02:33:27 +08:00
$lockKey = sprintf ( " record_batch_lock:%s:%s " , $userid , $torrentid );
if ( $redis -> set ( $lockKey , TIMENOW , [ 'nx' , 'ex' => $autoclean_interval_one ])) {
\App\Repositories\CleanupRepository :: recordBatch ( $redis , $userid , $torrentid );
}
2022-06-08 14:15:59 +08:00
do_action ( 'announced' , $torrent , $az , $_REQUEST );
2021-06-09 02:23:09 +08:00
benc_resp ( $rep_dict );
2020-12-26 01:42:23 +08:00
?>