1
0

ClientHandler.php 34 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067
  1. <?php
  2. /* $Id: ClientHandler.php 3057 2007-05-27 13:06:39Z b4rt $ */
  3. /*******************************************************************************
  4. LICENSE
  5. This program is free software; you can redistribute it and/or
  6. modify it under the terms of the GNU General Public License (GPL)
  7. as published by the Free Software Foundation; either version 2
  8. of the License, or (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. To read the license please visit http://www.gnu.org/copyleft/gpl.html
  14. *******************************************************************************/
  15. // states
  16. define('CLIENTHANDLER_STATE_NULL', 0); // null
  17. define('CLIENTHANDLER_STATE_READY', 1); // ready
  18. define('CLIENTHANDLER_STATE_OK', 2); // started
  19. define('CLIENTHANDLER_STATE_ERROR', -1); // error
  20. /**
  21. * base class ClientHandler
  22. */
  23. class ClientHandler
  24. {
  25. // public fields
  26. // client-specific fields
  27. var $type = "";
  28. var $client = "";
  29. var $binSystem = ""; // the system-binary of this client.
  30. var $binSocket = ""; // the binary this client uses for socket-connections.
  31. var $binClient = ""; // the binary of this client. (eg. python-script))
  32. // generic vars for a transfer-start
  33. var $rate = "";
  34. var $drate = "";
  35. var $superseeder = "";
  36. var $runtime = "";
  37. var $maxuploads = "";
  38. var $minport = "";
  39. var $maxport = "";
  40. var $port = "";
  41. var $maxcons = "";
  42. var $rerequest = "";
  43. var $sharekill = "";
  44. var $sharekill_param = "";
  45. var $skip_hash_check = "";
  46. // queue
  47. var $queue = false;
  48. // transfer
  49. var $transfer = "";
  50. var $transferFilePath = "";
  51. // running
  52. var $running = 0;
  53. // hash
  54. var $hash = "";
  55. // datapath
  56. var $datapath = "";
  57. // savepath
  58. var $savepath = "";
  59. // pid
  60. var $pid = "";
  61. // owner
  62. var $owner = "";
  63. // command (startup)
  64. var $command = "";
  65. // umask
  66. var $umask = "";
  67. // nice
  68. var $nice = "";
  69. // call-result
  70. var $callResult;
  71. // messages-array
  72. var $messages = array();
  73. // handler-state
  74. var $state = CLIENTHANDLER_STATE_NULL;
  75. // =========================================================================
  76. // public static methods
  77. // =========================================================================
  78. /**
  79. * get ClientHandler-instance
  80. *
  81. * @param $client client-type
  82. * @return ClientHandler
  83. */
  84. function getInstance($client = "") {
  85. // create and return object-instance
  86. switch ($client) {
  87. case "tornado":
  88. require_once('inc/classes/ClientHandler.tornado.php');
  89. return new ClientHandlerTornado();
  90. case "transmission":
  91. require_once('inc/classes/ClientHandler.transmission.php');
  92. return new ClientHandlerTransmission();
  93. case "mainline":
  94. require_once('inc/classes/ClientHandler.mainline.php');
  95. return new ClientHandlerMainline();
  96. case "azureus":
  97. require_once('inc/classes/ClientHandler.azureus.php');
  98. return new ClientHandlerAzureus();
  99. case "wget":
  100. require_once('inc/classes/ClientHandler.wget.php');
  101. return new ClientHandlerWget();
  102. case "nzbperl":
  103. require_once('inc/classes/ClientHandler.nzbperl.php');
  104. return new ClientHandlerNzbperl();
  105. default:
  106. global $cfg;
  107. return ClientHandler::getInstance($cfg["btclient"]);
  108. }
  109. }
  110. // =========================================================================
  111. // ctor
  112. // =========================================================================
  113. /**
  114. * ctor
  115. */
  116. function ClientHandler() {
  117. die('base class -- don\'t do this');
  118. }
  119. // =========================================================================
  120. // public methods (abstract)
  121. // =========================================================================
  122. /**
  123. * starts a client
  124. * @param $transfer name of the transfer
  125. * @param $interactive (boolean) : is this a interactive startup with dialog ?
  126. * @param $enqueue (boolean) : enqueue ?
  127. */
  128. function start($transfer, $interactive = false, $enqueue = false) { return; }
  129. /**
  130. * deletes cache of a transfer
  131. *
  132. * @param $transfer
  133. */
  134. function deleteCache($transfer) { return; }
  135. /**
  136. * set upload rate of a transfer
  137. *
  138. * @param $transfer
  139. * @param $uprate
  140. * @param $autosend
  141. */
  142. function setRateUpload($transfer, $uprate, $autosend = false) { return; }
  143. /**
  144. * set download rate of a transfer
  145. *
  146. * @param $transfer
  147. * @param $downrate
  148. * @param $autosend
  149. */
  150. function setRateDownload($transfer, $downrate, $autosend = false) { return; }
  151. /**
  152. * set runtime of a transfer
  153. *
  154. * @param $transfer
  155. * @param $runtime
  156. * @param $autosend
  157. * @return boolean
  158. */
  159. function setRuntime($transfer, $runtime, $autosend = false) { return true; }
  160. /**
  161. * set sharekill of a transfer
  162. *
  163. * @param $transfer
  164. * @param $sharekill
  165. * @param $autosend
  166. * @return boolean
  167. */
  168. function setSharekill($transfer, $sharekill, $autosend = false) { return true; }
  169. // =========================================================================
  170. // public methods
  171. // =========================================================================
  172. /**
  173. * sets settings-fields
  174. */
  175. function settingsInit() {
  176. $this->_settingsInit();
  177. }
  178. /**
  179. * sets fields from default-vals
  180. *
  181. * @param $transfer
  182. */
  183. function settingsDefault($transfer = "") {
  184. global $cfg;
  185. // transfer vars
  186. if ($transfer != "")
  187. $this->_setVarsForTransfer($transfer);
  188. // common vars
  189. $this->hash = getTransferHash($this->transfer);
  190. $this->datapath = getTransferDatapath($this->transfer);
  191. $this->savepath = getTransferSavepath($this->transfer);
  192. $this->running = 0;
  193. $this->rate = $cfg["max_upload_rate"];
  194. $this->drate = $cfg["max_download_rate"];
  195. $this->maxuploads = $cfg["max_uploads"];
  196. $this->superseeder = $cfg["superseeder"];
  197. $this->runtime = $cfg["die_when_done"];
  198. $this->sharekill = $cfg["sharekill"];
  199. $this->minport = $cfg["minport"];
  200. $this->maxport = $cfg["maxport"];
  201. $this->maxcons = $cfg["maxcons"];
  202. $this->rerequest = $cfg["rerequest_interval"];
  203. }
  204. /**
  205. * load settings
  206. *
  207. * @param $transfer
  208. * @return boolean
  209. */
  210. function settingsLoad($transfer = "") {
  211. global $db;
  212. // transfer vars
  213. if ($transfer != "")
  214. $this->_setVarsForTransfer($transfer);
  215. // common vars
  216. $sql = "SELECT * FROM tf_transfers WHERE transfer = ".$db->qstr($this->transfer);
  217. $result = $db->Execute($sql);
  218. if ($db->ErrorNo() != 0) dbError($sql);
  219. if ($row = $result->FetchRow()) {
  220. $this->hash = $row["hash"];
  221. $this->datapath = $row["datapath"];
  222. $this->savepath = $row["savepath"];
  223. $this->running = $row["running"];
  224. $this->rate = $row["rate"];
  225. $this->drate = $row["drate"];
  226. $this->maxuploads = $row["maxuploads"];
  227. $this->superseeder = $row["superseeder"];
  228. $this->runtime = $row["runtime"];
  229. $this->sharekill = $row["sharekill"];
  230. $this->minport = $row["minport"];
  231. $this->maxport = $row["maxport"];
  232. $this->maxcons = $row["maxcons"];
  233. $this->rerequest = $row["rerequest"];
  234. // loaded
  235. return true;
  236. } else {
  237. // not loaded
  238. return false;
  239. }
  240. }
  241. /**
  242. * save settings
  243. */
  244. function settingsSave() {
  245. global $db;
  246. // Messy - a not exists would prob work better
  247. deleteTransferSettings($this->transfer);
  248. // insert
  249. $sql = "INSERT INTO tf_transfers "
  250. ."("
  251. ."transfer,"
  252. ."type,"
  253. ."client,"
  254. ."hash,"
  255. ."datapath,"
  256. ."savepath,"
  257. ."running,"
  258. ."rate,"
  259. ."drate,"
  260. ."maxuploads,"
  261. ."superseeder,"
  262. ."runtime,"
  263. ."sharekill,"
  264. ."minport,"
  265. ."maxport,"
  266. ."maxcons,"
  267. ."rerequest"
  268. .") VALUES ("
  269. . $db->qstr($this->transfer).","
  270. . $db->qstr($this->type).","
  271. . $db->qstr($this->client).","
  272. . $db->qstr($this->hash).","
  273. . $db->qstr($this->datapath).","
  274. . $db->qstr($this->savepath).","
  275. . $db->qstr($this->running).","
  276. . $db->qstr($this->rate).","
  277. . $db->qstr($this->drate).","
  278. . $db->qstr($this->maxuploads).","
  279. . $db->qstr($this->superseeder).","
  280. . $db->qstr($this->runtime).","
  281. . $db->qstr($this->sharekill).","
  282. . $db->qstr($this->minport).","
  283. . $db->qstr($this->maxport).","
  284. . $db->qstr($this->maxcons).","
  285. . $db->qstr($this->rerequest)
  286. .")";
  287. $db->Execute($sql);
  288. if ($db->ErrorNo() != 0) dbError($sql);
  289. // set transfers-cache
  290. cacheTransfersSet();
  291. return true;
  292. }
  293. /**
  294. * stops a client
  295. *
  296. * @param $transfer name of the transfer
  297. * @param $kill kill-param (optional)
  298. * @param $transferPid transfer Pid (optional)
  299. */
  300. function stop($transfer, $kill = false, $transferPid = 0) {
  301. // set vars
  302. $this->_setVarsForTransfer($transfer);
  303. // stop the client
  304. $this->_stop($kill, $transferPid);
  305. }
  306. /**
  307. * deletes a transfer
  308. *
  309. * @param $transfer name of the transfer
  310. * @return boolean of success
  311. */
  312. function delete($transfer) {
  313. // set vars
  314. $this->_setVarsForTransfer($transfer);
  315. // delete
  316. return $this->_delete();
  317. }
  318. /**
  319. * gets current transfer-vals of a transfer
  320. *
  321. * @param $transfer
  322. * @return array with downtotal and uptotal
  323. */
  324. function getTransferCurrent($transfer) {
  325. global $transfers;
  326. // transfer from stat-file
  327. $sf = new StatFile($transfer);
  328. return array("uptotal" => $sf->uptotal, "downtotal" => $sf->downtotal);
  329. }
  330. /**
  331. * gets current transfer-vals of a transfer. optimized version
  332. *
  333. * @param $transfer
  334. * @param $tid of the transfer
  335. * @param $sfu stat-file-uptotal of the transfer
  336. * @param $sfd stat-file-downtotal of the transfer
  337. * @return array with downtotal and uptotal
  338. */
  339. function getTransferCurrentOP($transfer, $tid, $sfu, $sfd) {
  340. return array("uptotal" => $sfu, "downtotal" => $sfd);
  341. }
  342. /**
  343. * gets total transfer-vals of a transfer
  344. *
  345. * @param $transfer
  346. * @return array with downtotal and uptotal
  347. */
  348. function getTransferTotal($transfer) {
  349. global $db, $transfers;
  350. $retVal = array();
  351. // transfer from db
  352. $sql = "SELECT uptotal,downtotal FROM tf_transfer_totals WHERE tid = ".$db->qstr(getTransferHash($transfer));
  353. $result = $db->Execute($sql);
  354. $row = $result->FetchRow();
  355. if (empty($row)) {
  356. $retVal["uptotal"] = 0;
  357. $retVal["downtotal"] = 0;
  358. } else {
  359. $retVal["uptotal"] = $row["uptotal"];
  360. $retVal["downtotal"] = $row["downtotal"];
  361. }
  362. // transfer from stat-file
  363. $sf = new StatFile($transfer);
  364. $retVal["uptotal"] += $sf->uptotal;
  365. $retVal["downtotal"] += $sf->downtotal;
  366. return $retVal;
  367. }
  368. /**
  369. * gets total transfer-vals of a transfer. optimized version
  370. *
  371. * @param $transfer
  372. * @param $tid of the transfer
  373. * @param $sfu stat-file-uptotal of the transfer
  374. * @param $sfd stat-file-downtotal of the transfer
  375. * @return array with downtotal and uptotal
  376. */
  377. function getTransferTotalOP($transfer, $tid, $sfu, $sfd) {
  378. global $transfers;
  379. $retVal = array();
  380. $retVal["uptotal"] = (isset($transfers['totals'][$tid]['uptotal']))
  381. ? $transfers['totals'][$tid]['uptotal'] + $sfu
  382. : $sfu;
  383. $retVal["downtotal"] = (isset($transfers['totals'][$tid]['downtotal']))
  384. ? $transfers['totals'][$tid]['downtotal'] + $sfd
  385. : $sfd;
  386. return $retVal;
  387. }
  388. /**
  389. * gets ary of running clients (via call to ps)
  390. *
  391. * @return array
  392. */
  393. function runningProcesses() {
  394. global $cfg;
  395. $retAry = array();
  396. $screenStatus = shell_exec("ps x -o pid='' -o ppid='' -o command='' -ww | ".$cfg['bin_grep']." ".tfb_shellencode($this->binClient)." | ".$cfg['bin_grep']." ".tfb_shellencode($cfg["transfer_file_path"])." | ".$cfg['bin_grep']." -v grep");
  397. $arScreen = array();
  398. $tok = strtok($screenStatus, "\n");
  399. while ($tok) {
  400. array_push($arScreen, $tok);
  401. $tok = strtok("\n");
  402. }
  403. $arySize = sizeof($arScreen);
  404. for ($i = 0; $i < $arySize; $i++) {
  405. if(strpos($arScreen[$i], $this->binClient) !== false) {
  406. $pinfo = new ProcessInfo($arScreen[$i]);
  407. if (intval($pinfo->ppid) == 1) {
  408. if (!strpos($pinfo->cmdline, "rep ". $this->binSystem) > 0) {
  409. if (!strpos($pinfo->cmdline, "ps x") > 0) {
  410. array_push($retAry, array(
  411. 'client' => $this->client,
  412. 'pinfo' => $pinfo->pid." ".$pinfo->cmdline
  413. )
  414. );
  415. }
  416. }
  417. }
  418. }
  419. }
  420. return $retAry;
  421. }
  422. /**
  423. * get info of running clients (via call to ps)
  424. *
  425. * @return string
  426. */
  427. function runningProcessInfo() {
  428. global $cfg;
  429. // ps-string
  430. $screenStatus = shell_exec("ps x -o pid='' -o ppid='' -o command='' -ww | ".$cfg['bin_grep']." ".tfb_shellencode($this->binClient)." | ".$cfg['bin_grep']." ".tfb_shellencode($cfg["transfer_file_path"])." | ".$cfg['bin_grep']." -v grep");
  431. $arScreen = array();
  432. $tok = strtok($screenStatus, "\n");
  433. while ($tok) {
  434. array_push($arScreen, $tok);
  435. $tok = strtok("\n");
  436. }
  437. $cProcess = array();
  438. $cpProcess = array();
  439. $pProcess = array();
  440. $ProcessCmd = array();
  441. for ($i = 0; $i < sizeof($arScreen); $i++) {
  442. if (strpos($arScreen[$i], $this->binClient) !== false) {
  443. $pinfo = new ProcessInfo($arScreen[$i]);
  444. if (intval($pinfo->ppid) == 1) {
  445. if (!strpos($pinfo->cmdline, "rep ". $this->binSystem) > 0) {
  446. if (!strpos($pinfo->cmdline, "ps x") > 0) {
  447. array_push($pProcess,$pinfo->pid);
  448. $rt = RunningTransfer::getInstance($pinfo->pid." ".$pinfo->cmdline, $this->client);
  449. array_push($ProcessCmd, $rt->transferowner."\t".$rt->transferFile);
  450. }
  451. }
  452. } else {
  453. if (!strpos($pinfo->cmdline, "rep ". $this->binSystem) > 0) {
  454. if (!strpos($pinfo->cmdline, "ps x") > 0) {
  455. array_push($cProcess, $pinfo->pid);
  456. array_push($cpProcess, $pinfo->ppid);
  457. }
  458. }
  459. }
  460. }
  461. }
  462. $retVal = " --- Running Processes ---\n";
  463. $retVal .= " Parents : " . count($pProcess) . "\n";
  464. $retVal .= " Children : " . count($cProcess) . "\n";
  465. $retVal .= "\n";
  466. $retVal .= " PID \tOwner\tTransfer File\n";
  467. foreach ($pProcess as $key => $value)
  468. $retVal .= " " . $value . "\t" . $ProcessCmd[$key] . "\n";
  469. $retVal .= "\n";
  470. return $retVal;
  471. }
  472. /**
  473. * writes a message to the per-transfer-logfile
  474. *
  475. * @param $message
  476. * @param $withTS
  477. */
  478. function logMessage($message, $withTS = true) {
  479. // return if transfer-file-field not set
  480. if ($this->transferFilePath == "") return false;
  481. // log
  482. if ($handle = @fopen($this->transferFilePath.".log", "a+")) {
  483. $content = ($withTS)
  484. ? @date("[Y/m/d - H:i:s]")." ".$message
  485. : $message;
  486. $resultSuccess = (@fwrite($handle, $content) !== false);
  487. @fclose($handle);
  488. return $resultSuccess;
  489. }
  490. return false;
  491. }
  492. // =========================================================================
  493. // protected methods
  494. // =========================================================================
  495. /**
  496. * sets all fields depending on "transfer"-value
  497. *
  498. * @param $transfer
  499. */
  500. function _setVarsForTransfer($transfer) {
  501. global $cfg;
  502. $this->transfer = $transfer;
  503. $this->transferFilePath = $cfg["transfer_file_path"].$this->transfer;
  504. $this->owner = getOwner($transfer);
  505. }
  506. /**
  507. * sets common settings-fields
  508. */
  509. function _settingsInit() {
  510. global $cfg;
  511. // customize settings
  512. if ($cfg['transfer_customize_settings'] == 2)
  513. $customize_settings = 1;
  514. elseif ($cfg['transfer_customize_settings'] == 1 && $cfg['isAdmin'])
  515. $customize_settings = 1;
  516. else
  517. $customize_settings = 0;
  518. // init default-settings
  519. $this->settingsDefault();
  520. // only read request-vars if enabled
  521. if ($customize_settings == 1) {
  522. // rate
  523. $reqvar = tfb_getRequestVar('max_upload_rate');
  524. if ($reqvar != "")
  525. $this->rate = $reqvar;
  526. // drate
  527. $reqvar = tfb_getRequestVar('max_download_rate');
  528. if ($reqvar != "")
  529. $this->drate = $reqvar;
  530. // maxuploads
  531. $reqvar = tfb_getRequestVar('max_uploads');
  532. if ($reqvar != "")
  533. $this->maxuploads = $reqvar;
  534. // superseeder
  535. $reqvar = tfb_getRequestVar('superseeder');
  536. if ($reqvar != "")
  537. $this->superseeder = $reqvar;
  538. // runtime
  539. $reqvar = tfb_getRequestVar('die_when_done');
  540. if ($reqvar != "")
  541. $this->runtime = $reqvar;
  542. // sharekill
  543. $reqvar = tfb_getRequestVar('sharekill');
  544. if ($reqvar != "")
  545. $this->sharekill = $reqvar;
  546. // minport
  547. $reqvar = tfb_getRequestVar('minport');
  548. if (!empty($reqvar))
  549. $this->minport = $reqvar;
  550. // maxport
  551. $reqvar = tfb_getRequestVar('maxport');
  552. if (!empty($reqvar))
  553. $this->maxport = $reqvar;
  554. // maxcons
  555. $reqvar = tfb_getRequestVar('maxcons');
  556. if ($reqvar != "")
  557. $this->maxcons = $reqvar;
  558. // rerequest
  559. $reqvar = tfb_getRequestVar('rerequest');
  560. if ($reqvar != "")
  561. $this->rerequest = $reqvar;
  562. }
  563. // savepath
  564. if ($cfg["showdirtree"] == 1)
  565. $this->savepath = tfb_getRequestVar('savepath');
  566. // skip_hash_check
  567. $this->skip_hash_check = tfb_getRequestVar('skiphashcheck');
  568. }
  569. /**
  570. * init start of a client.
  571. *
  572. * @param $interactive
  573. * @param $enqueue
  574. * @param $setPort
  575. * @param $recalcSharekill
  576. */
  577. function _init($interactive, $enqueue = false, $setPort = false, $recalcSharekill = false) {
  578. global $cfg;
  579. // request-vars / defaults / database
  580. if ($interactive) { // interactive, get vars from request vars
  581. $this->settingsInit();
  582. } else { // non-interactive, load settings from db
  583. $this->skip_hash_check = $cfg["skiphashcheck"];
  584. // load settings, default if settings could not be loaded (fresh transfer)
  585. if ($this->settingsLoad() !== true)
  586. $this->settingsDefault();
  587. }
  588. // queue
  589. if ($enqueue) {
  590. $this->queue = ($cfg['isAdmin'])
  591. ? $enqueue
  592. : true;
  593. } else {
  594. $this->queue = false;
  595. }
  596. // savepath-check
  597. if (empty($this->savepath))
  598. $this->savepath = ($cfg["enable_home_dirs"] != 0)
  599. ? $cfg['path'].$this->owner."/"
  600. : $cfg['path'].$cfg["path_incoming"]."/";
  601. else
  602. $this->savepath = checkDirPathString($this->savepath);
  603. // check target-directory, create if not present
  604. if (!(checkDirectory($this->savepath, 0777))) {
  605. $this->state = CLIENTHANDLER_STATE_ERROR;
  606. $msg = "Error checking savepath ".$this->savepath;
  607. array_push($this->messages, $msg);
  608. AuditAction($cfg["constants"]["error"], $msg);
  609. $this->logMessage($msg."\n", true);
  610. // write error to stat
  611. $sf = new StatFile($this->transfer, $this->owner);
  612. $sf->time_left = 'Error';
  613. $sf->write();
  614. return false;
  615. }
  616. // umask
  617. $this->umask = ($cfg["enable_umask"] != 0)
  618. ? " umask 0000;"
  619. : "";
  620. // nice
  621. $this->nice = ($cfg["nice_adjust"] != 0)
  622. ? "nice -n ".$cfg["nice_adjust"]." "
  623. : "";
  624. // set param for sharekill
  625. $this->sharekill = intval($this->sharekill);
  626. // recalc sharekill
  627. if ($recalcSharekill) {
  628. if ($this->_recalcSharekill() === false)
  629. return false;
  630. } else {
  631. $this->sharekill_param = $this->sharekill;
  632. $this->logMessage("setting sharekill-param to ".$this->sharekill_param."\n", true);
  633. }
  634. // set port if start (only if not queue)
  635. if (($setPort) && (!$this->queue)) {
  636. if ($this->_setClientPort() === false)
  637. return false;
  638. }
  639. // get current transfer
  640. $transferTotals = $this->getTransferCurrent($this->transfer);
  641. //XFER: before a transfer start/restart save upload/download xfer to SQL
  642. if ($cfg['enable_xfer'] == 1)
  643. Xfer::save($this->owner,($transferTotals["downtotal"]),($transferTotals["uptotal"]));
  644. // update totals for this transfer
  645. $this->_updateTotals();
  646. // set state
  647. $this->state = CLIENTHANDLER_STATE_READY;
  648. }
  649. /**
  650. * start a client.
  651. */
  652. function _start() {
  653. global $cfg;
  654. if ($this->state != CLIENTHANDLER_STATE_READY) {
  655. $this->state = CLIENTHANDLER_STATE_ERROR;
  656. array_push($this->messages , "Error. ClientHandler in wrong state on start-request.");
  657. // write error to stat
  658. $sf = new StatFile($this->transfer, $this->owner);
  659. $sf->time_left = 'Error';
  660. $sf->write();
  661. // return
  662. return;
  663. }
  664. // Save transfer settings
  665. $this->settingsSave();
  666. // flush session-cache (trigger transfers-cache-set on next page-load)
  667. cacheFlush($cfg['user']);
  668. // write the session to close so older version of PHP will not hang
  669. @session_write_close();
  670. // sf
  671. $sf = new StatFile($this->transfer, $this->owner);
  672. // queue or start ?
  673. if ($this->queue) { // queue
  674. if (FluxdQmgr::isRunning()) {
  675. // write stat-file
  676. $sf->queue();
  677. // send command
  678. FluxdQmgr::enqueueTransfer($this->transfer, $cfg['user']);
  679. // log
  680. AuditAction($cfg["constants"]["queued_transfer"], $this->transfer);
  681. $this->logMessage("transfer enqueued : ".$this->transfer."\n", true);
  682. } else {
  683. $msg = "queue-request (".$this->transfer."/".$cfg['user'].") but Qmgr not active";
  684. array_push($this->messages , $msg);
  685. AuditAction($cfg["constants"]["error"], $msg);
  686. $this->logMessage($msg."\n", true);
  687. }
  688. // set flag
  689. $this->running = 0;
  690. } else { // start
  691. // write stat-file
  692. $sf->start();
  693. // log the command
  694. $this->logMessage("executing command : \n".$this->command."\n", true);
  695. // startup
  696. $this->callResult = exec($this->command);
  697. AuditAction($cfg["constants"]["start_torrent"], $this->transfer);
  698. // set flag
  699. $this->running = 1;
  700. // wait until transfer is up
  701. waitForTransfer($this->transfer, true, 20);
  702. }
  703. if (empty($this->messages)) {
  704. // set state
  705. $this->state = CLIENTHANDLER_STATE_OK;
  706. } else {
  707. // error
  708. $this->state = CLIENTHANDLER_STATE_ERROR;
  709. $msg = "error starting client. messages :\n";
  710. $msg .= implode("\n", $this->messages);
  711. $this->logMessage($msg."\n", true);
  712. // write error to stat
  713. $sf->time_left = 'Error';
  714. $sf->write();
  715. }
  716. }
  717. /**
  718. * stop a client
  719. *
  720. * @param $kill kill-param (optional)
  721. * @param $transferPid transfer Pid (optional)
  722. */
  723. function _stop($kill = false, $transferPid = 0) {
  724. global $cfg;
  725. // log
  726. AuditAction($cfg["constants"]["stop_transfer"], $this->transfer);
  727. // send quit-command to client
  728. CommandHandler::add($this->transfer, "q");
  729. CommandHandler::send($this->transfer);
  730. // wait until transfer is down
  731. waitForTransfer($this->transfer, false, 25);
  732. // one more second
  733. sleep(1);
  734. // flag the transfer as stopped (in db)
  735. stopTransferSettings($this->transfer);
  736. // set transfers-cache
  737. cacheTransfersSet();
  738. // see if the transfer process is hung.
  739. $running = $this->runningProcesses();
  740. $isHung = false;
  741. foreach ($running as $rng) {
  742. $rt = RunningTransfer::getInstance($rng['pinfo'], $this->client);
  743. if ($rt->transferFile == $this->transfer) {
  744. $isHung = true;
  745. AuditAction($cfg["constants"]["error"], "Possible Hung Process for ".$rt->transferFile." (".$rt->processId.")");
  746. }
  747. }
  748. // kill-request
  749. if ($kill && $isHung) {
  750. AuditAction($cfg["constants"]["kill_transfer"], $this->transfer);
  751. // set pid
  752. if (!empty($transferPid)) {
  753. // test for valid pid-var
  754. if (preg_match('/^[0-9]+$/D', $transferPid)) {
  755. $this->pid = $transferPid;
  756. } else {
  757. $this->state = CLIENTHANDLER_STATE_ERROR;
  758. AuditAction($cfg["constants"]["error"], "INVALID PID: ".$transferPid);
  759. array_push($this->messages, "INVALID PID: ".$transferPid);
  760. return false;
  761. }
  762. } else {
  763. $this->pid = getTransferPid($this->transfer);;
  764. }
  765. // kill it
  766. require_once('inc/defines/defines.signals.php');
  767. if ($this->pid > 0)
  768. $this->callResult = posix_kill($this->pid, SIGKILL);
  769. // try to remove the pid file
  770. @unlink($this->transferFilePath.".pid");
  771. }
  772. }
  773. /**
  774. * deletes a transfer
  775. *
  776. * @return boolean
  777. */
  778. function _delete() {
  779. global $cfg;
  780. // delete
  781. if (($cfg["user"] == $this->owner) || $cfg['isAdmin']) {
  782. // XFER: before deletion save upload/download xfer data to SQL
  783. if ($cfg['enable_xfer'] == 1) {
  784. $transferTotals = $this->getTransferCurrent($this->transfer);
  785. Xfer::save($this->owner, $transferTotals["downtotal"], $transferTotals["uptotal"]);
  786. }
  787. // update totals
  788. $this->_updateTotals();
  789. // remove settings from db
  790. deleteTransferSettings($this->transfer);
  791. // client-cache
  792. $this->deleteCache($this->transfer);
  793. // command-clean
  794. CommandHandler::clean($this->transfer);
  795. // remove meta-file
  796. if (@file_exists($this->transferFilePath))
  797. @unlink($this->transferFilePath);
  798. // remove stat-file
  799. if (@file_exists($this->transferFilePath.".stat"))
  800. @unlink($this->transferFilePath.".stat");
  801. // if exist remove pid file
  802. if (@file_exists($this->transferFilePath.".pid"))
  803. @unlink($this->transferFilePath.".pid");
  804. // if exist remove log-file
  805. if (@file_exists($this->transferFilePath.".log"))
  806. @unlink($this->transferFilePath.".log");
  807. // if exist remove prio-file
  808. if (@file_exists($this->transferFilePath.".prio"))
  809. @unlink($this->transferFilePath.".prio");
  810. AuditAction($cfg["constants"]["delete_transfer"], $this->transfer);
  811. return true;
  812. } else {
  813. AuditAction($cfg["constants"]["error"], "ILLEGAL DELETE: ".$this->transfer);
  814. return false;
  815. }
  816. }
  817. // =========================================================================
  818. // private methods
  819. // =========================================================================
  820. /**
  821. * updates totals of a transfer
  822. */
  823. function _updateTotals() {
  824. global $db;
  825. $tid = getTransferHash($this->transfer);
  826. $transferTotals = $this->getTransferTotal($this->transfer);
  827. $sql = ($db->GetOne("SELECT 1 FROM tf_transfer_totals WHERE tid = ".$db->qstr($tid)))
  828. ? "UPDATE tf_transfer_totals SET uptotal = ".$db->qstr($transferTotals["uptotal"]).", downtotal = ".$db->qstr($transferTotals["downtotal"])." WHERE tid = ".$db->qstr($tid)
  829. : "INSERT INTO tf_transfer_totals (tid,uptotal,downtotal) VALUES (".$db->qstr($tid).",".$db->qstr($transferTotals["uptotal"]).",".$db->qstr($transferTotals["downtotal"]).")";
  830. $db->Execute($sql);
  831. // set transfers-cache
  832. cacheTransfersSet();
  833. }
  834. /**
  835. * recalc sharekill
  836. *
  837. * @return boolean
  838. */
  839. function _recalcSharekill() {
  840. global $cfg;
  841. $this->logMessage("recalc sharekill for ".$this->transfer."\n", true);
  842. if ($this->sharekill == 0) { // nice, we seed forever
  843. $this->sharekill_param = 0;
  844. $this->logMessage("seed forever\n", true);
  845. // return
  846. return true;
  847. } elseif ($this->sharekill > 0) { // recalc sharekill
  848. /* get size */
  849. // try stat-file first
  850. $sf = new StatFile($this->transfer, $this->owner);
  851. $transferSize = (empty($sf->size)) ? 0 : floatval($sf->size);
  852. // try to reget if stat was empty
  853. if ($transferSize <= 0)
  854. $transferSize = floatval(getTransferSize($this->transfer));
  855. // if still no size just pass thru the param
  856. if ($transferSize <= 0) {
  857. // message
  858. $msg = "data-size = '".$transferSize."' when recalcing share-kill for ".$this->transfer.", setting sharekill-param to ".$this->sharekill_param;
  859. array_push($this->messages , $msg);
  860. // debug-log
  861. if ($cfg['debuglevel'] > 0)
  862. AuditAction($cfg["constants"]["debug"], $msg);
  863. // log
  864. $this->logMessage($msg."\n", true);
  865. // set sharekill param
  866. $this->sharekill_param = $this->sharekill;
  867. // return
  868. return true;
  869. }
  870. /* get vars */
  871. // get totals
  872. $totalAry = $this->getTransferTotal($this->transfer);
  873. $upTotal = floatval($totalAry["uptotal"]);
  874. $downTotal = floatval($totalAry["downtotal"]);
  875. // check totals
  876. if (($upTotal < 0) || ($downTotal < 0)) {
  877. // message
  878. $msg = "problems getting totals (upTotal: ".$upTotal."; downTotal: ".$downTotal.") when recalcing share-kill for ".$this->transfer.", setting sharekill-param to ".$this->sharekill_param;
  879. array_push($this->messages , $msg);
  880. // debug-log
  881. if ($cfg['debuglevel'] > 0)
  882. AuditAction($cfg["constants"]["debug"], $msg);
  883. // log
  884. $this->logMessage($msg."\n", true);
  885. // set sharekill param
  886. $this->sharekill_param = $this->sharekill;
  887. // return
  888. return true;
  889. }
  890. // wanted
  891. $upWanted = ($this->sharekill / 100) * $transferSize;
  892. // check wanted
  893. if ($upWanted <= 0) {
  894. // message
  895. $msg = "problems calculating wanted upload (upWanted: ".$upWanted.") when recalcing share-kill for ".$this->transfer.", setting sharekill-param to ".$this->sharekill_param;
  896. array_push($this->messages , $msg);
  897. // debug-log
  898. if ($cfg['debuglevel'] > 0)
  899. AuditAction($cfg["constants"]["debug"], $msg);
  900. // log
  901. $this->logMessage($msg."\n", true);
  902. // set sharekill param
  903. $this->sharekill_param = $this->sharekill;
  904. // return
  905. return true;
  906. }
  907. // share percentage
  908. $sharePercentage = ($upTotal / $transferSize) * 100;
  909. // check percentage
  910. if (($sharePercentage < 0) || ($sharePercentage >= 2147483647)) {
  911. // message
  912. $msg = "problems calculating share percentage (sharePercentage: ".$sharePercentage.") when recalcing share-kill for ".$this->transfer.", setting sharekill-param to ".$this->sharekill_param;
  913. array_push($this->messages , $msg);
  914. // debug-log
  915. if ($cfg['debuglevel'] > 0)
  916. AuditAction($cfg["constants"]["debug"], $msg);
  917. // log
  918. $this->logMessage($msg."\n", true);
  919. // set sharekill param
  920. $this->sharekill_param = $this->sharekill;
  921. // return
  922. return true;
  923. }
  924. /* check */
  925. if (($upTotal >= $upWanted) && ($downTotal >= $transferSize)) {
  926. // just pass thru param if runtime is true
  927. if ($this->runtime == "True") {
  928. $this->sharekill_param = $this->sharekill;
  929. $this->logMessage("setting sharekill-param to ".$this->sharekill_param."\n", true);
  930. // return
  931. return true;
  932. }
  933. // we already have seeded at least wanted percentage. skip start of client
  934. // set state
  935. $this->state = CLIENTHANDLER_STATE_NULL;
  936. // message
  937. $msg = "skip ".$this->transfer." due to share-ratio (has: ".@number_format($sharePercentage, 2)."; set:".$this->sharekill."; upTotal: ".$upTotal."; upWanted: ".$upWanted.")";
  938. array_push($this->messages , $msg);
  939. // debug-log
  940. if ($cfg['debuglevel'] > 0)
  941. AuditAction($cfg["constants"]["debug"], $msg);
  942. // log
  943. $this->logMessage($msg."\n", true);
  944. // write Skipped to stat
  945. $sf = new StatFile($this->transfer, $this->owner);
  946. $sf->time_left = 'Skipped';
  947. $sf->write();
  948. // return
  949. return false;
  950. } else {
  951. // not done seeding wanted percentage
  952. $this->sharekill_param = intval(ceil($this->sharekill - $sharePercentage));
  953. // sanity-check.
  954. if ($this->sharekill_param < 1)
  955. $this->sharekill_param = 1;
  956. $this->logMessage("recalcing sharekill. wanted: ".$this->sharekill."; done: ".$sharePercentage."\n", true);
  957. $this->logMessage("setting sharekill-param to ".$this->sharekill_param."\n", true);
  958. // return
  959. return true;
  960. }
  961. } else {
  962. $this->sharekill_param = $this->sharekill;
  963. $this->logMessage("setting sharekill-param to ".$this->sharekill_param."\n", true);
  964. // return
  965. return true;
  966. }
  967. // return
  968. return true;
  969. }
  970. /**
  971. * gets available port and sets port field
  972. *
  973. * @return boolean
  974. */
  975. function _setClientPort() {
  976. global $cfg;
  977. $portString = netstatPortList();
  978. $portAry = explode("\n", $portString);
  979. $this->port = intval($this->minport);
  980. while (1) {
  981. if (in_array($this->port, $portAry))
  982. $this->port += 1;
  983. else
  984. return true;
  985. if ($this->port > $this->maxport) {
  986. // state
  987. $this->state = CLIENTHANDLER_STATE_ERROR;
  988. // message
  989. $msg = "All ports in use.";
  990. array_push($this->messages , $msg);
  991. AuditAction($cfg["constants"]["error"], $msg);
  992. $this->logMessage($msg."\n", true);
  993. // write error to stat
  994. $sf = new StatFile($this->transfer, $this->owner);
  995. $sf->time_left = 'Error';
  996. $sf->write();
  997. // return
  998. return false;
  999. }
  1000. }
  1001. return false;
  1002. }
  1003. } // end class
  1004. ?>