Delete tftp will move to fusionpbx-apps repo
This commit is contained in:
parent
d56fb6f820
commit
4e2bb13242
|
|
@ -1,57 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
//application details
|
|
||||||
$apps[$x]['name'] = "TFTP Service";
|
|
||||||
$apps[$x]['uuid'] = "4b99ccfb-cb98-40e1-a5e5-aaa89e14a388";
|
|
||||||
$apps[$x]['category'] = "";;
|
|
||||||
$apps[$x]['subcategory'] = "";
|
|
||||||
$apps[$x]['version'] = "1.0";
|
|
||||||
$apps[$x]['license'] = "Mozilla Public License 1.1";
|
|
||||||
$apps[$x]['url'] = "http://www.fusionpbx.com";
|
|
||||||
$apps[$x]['description']['en-us'] = "TFTP Service";
|
|
||||||
$apps[$x]['description']['ar-eg'] = "";
|
|
||||||
$apps[$x]['description']['de-at'] = "TFTP Dienst";
|
|
||||||
$apps[$x]['description']['de-ch'] = "";
|
|
||||||
$apps[$x]['description']['de-de'] = "TFTP Dienst";
|
|
||||||
$apps[$x]['description']['es-cl'] = "";
|
|
||||||
$apps[$x]['description']['es-mx'] = "";
|
|
||||||
$apps[$x]['description']['fr-ca'] = "";
|
|
||||||
$apps[$x]['description']['fr-fr'] = "";
|
|
||||||
$apps[$x]['description']['he-il'] = "";
|
|
||||||
$apps[$x]['description']['it-it'] = "";
|
|
||||||
$apps[$x]['description']['nl-nl'] = "";
|
|
||||||
$apps[$x]['description']['pl-pl'] = "";
|
|
||||||
$apps[$x]['description']['pt-br'] = "";
|
|
||||||
$apps[$x]['description']['pt-pt'] = "";
|
|
||||||
$apps[$x]['description']['ro-ro'] = "";
|
|
||||||
$apps[$x]['description']['ru-ru'] = "TFTP Сервер";
|
|
||||||
$apps[$x]['description']['sv-se'] = "";
|
|
||||||
$apps[$x]['description']['uk-ua'] = "";
|
|
||||||
|
|
||||||
//default settings
|
|
||||||
$y=0;
|
|
||||||
$apps[$x]['default_settings'][$y]['default_setting_uuid'] = "e13895b7-ef2f-43ed-8d2a-e739ccffccc2";
|
|
||||||
$apps[$x]['default_settings'][$y]['default_setting_category'] = "provision";
|
|
||||||
$apps[$x]['default_settings'][$y]['default_setting_subcategory'] = "tftp_service_address";
|
|
||||||
$apps[$x]['default_settings'][$y]['default_setting_name'] = "text";
|
|
||||||
$apps[$x]['default_settings'][$y]['default_setting_value'] = "0.0.0.0";
|
|
||||||
$apps[$x]['default_settings'][$y]['default_setting_enabled'] = "true";
|
|
||||||
$apps[$x]['default_settings'][$y]['default_setting_description'] = "the address for the TFTP service to listen for connection on";
|
|
||||||
$y++;
|
|
||||||
$apps[$x]['default_settings'][$y]['default_setting_uuid'] = "3fe87ea5-9633-4af0-bb5c-a61dbba2772c";
|
|
||||||
$apps[$x]['default_settings'][$y]['default_setting_category'] = "provision";
|
|
||||||
$apps[$x]['default_settings'][$y]['default_setting_subcategory'] = "tftp_service_port";
|
|
||||||
$apps[$x]['default_settings'][$y]['default_setting_name'] = "numeric";
|
|
||||||
$apps[$x]['default_settings'][$y]['default_setting_value'] = "69";
|
|
||||||
$apps[$x]['default_settings'][$y]['default_setting_enabled'] = "true";
|
|
||||||
$apps[$x]['default_settings'][$y]['default_setting_description'] = "the port for the TFTP service to listen for connection on";
|
|
||||||
$y++;
|
|
||||||
$apps[$x]['default_settings'][$y]['default_setting_uuid'] = "5e21c189-ac27-42aa-acaf-57c8cdcbbcef";
|
|
||||||
$apps[$x]['default_settings'][$y]['default_setting_category'] = "provision";
|
|
||||||
$apps[$x]['default_settings'][$y]['default_setting_subcategory'] = "tftp_service_file_path";
|
|
||||||
$apps[$x]['default_settings'][$y]['default_setting_name'] = "numeric";
|
|
||||||
$apps[$x]['default_settings'][$y]['default_setting_value'] = "/tmp";
|
|
||||||
$apps[$x]['default_settings'][$y]['default_setting_enabled'] = "true";
|
|
||||||
$apps[$x]['default_settings'][$y]['default_setting_description'] = "the location for static files e.g. firmware";
|
|
||||||
|
|
||||||
?>
|
|
||||||
|
|
@ -1,33 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/*
|
|
||||||
FusionPBX
|
|
||||||
Version: MPL 1.1
|
|
||||||
|
|
||||||
The contents of this file are subject to the Mozilla Public License Version
|
|
||||||
1.1 (the "License"); you may not use this file except in compliance with
|
|
||||||
the License. You may obtain a copy of the License at
|
|
||||||
http://www.mozilla.org/MPL/
|
|
||||||
|
|
||||||
Software distributed under the License is distributed on an "AS IS" basis,
|
|
||||||
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
||||||
for the specific language governing rights and limitations under the
|
|
||||||
License.
|
|
||||||
|
|
||||||
The Original Code is FusionPBX
|
|
||||||
|
|
||||||
The Initial Developer of the Original Code is
|
|
||||||
Sebastian Krupinski <sebastian@ksacorp.com>
|
|
||||||
Portions created by the Initial Developer are Copyright (C) 2016
|
|
||||||
the Initial Developer. All Rights Reserved.
|
|
||||||
|
|
||||||
Contributor(s):
|
|
||||||
Sebastian Krupinski <sebastian@ksacorp.com>
|
|
||||||
*/
|
|
||||||
|
|
||||||
//process this code online once
|
|
||||||
if ($domains_processed == 1) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
<?php
|
|
||||||
#This file was last reorganized on 19th of September 2017 08:54:24 AM UTC
|
|
||||||
|
|
||||||
?>
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
?>
|
|
||||||
|
|
@ -1,293 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/*
|
|
||||||
FusionPBX
|
|
||||||
Version: MPL 1.1
|
|
||||||
|
|
||||||
The contents of this file are subject to the Mozilla Public License Version
|
|
||||||
1.1 (the "License"); you may not use this file except in compliance with
|
|
||||||
the License. You may obtain a copy of the License at
|
|
||||||
http://www.mozilla.org/MPL/
|
|
||||||
|
|
||||||
Software distributed under the License is distributed on an "AS IS" basis,
|
|
||||||
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
||||||
for the specific language governing rights and limitations under the
|
|
||||||
License.
|
|
||||||
|
|
||||||
The Original Code is FusionPBX
|
|
||||||
|
|
||||||
The Initial Developer of the Original Code is
|
|
||||||
Sebastian Krupinski <sebastian@ksacorp.com>
|
|
||||||
Portions created by the Initial Developer are Copyright (C) 2016
|
|
||||||
the Initial Developer. All Rights Reserved.
|
|
||||||
|
|
||||||
Contributor(s):
|
|
||||||
Sebastian Krupinski <sebastian@ksacorp.com>
|
|
||||||
*/
|
|
||||||
|
|
||||||
class database {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* generate dsn statement
|
|
||||||
* @param string $type - sqlite, mysql, pgsql, etc
|
|
||||||
* @param string $host - fqdn or ip address
|
|
||||||
* @param string $port - port number
|
|
||||||
* @param string $name - name of database or filename when using sqlite
|
|
||||||
* @return object pdo
|
|
||||||
*/
|
|
||||||
private static function _dsn($type,$host=null,$port=null,$name)
|
|
||||||
{
|
|
||||||
switch ($type) {
|
|
||||||
case 'sqlite':
|
|
||||||
return "$type:$name;";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return "$type:host=$host;port=$port;";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* connect to database
|
|
||||||
* @param string $type - sqlite, mysql, pgsql, etc
|
|
||||||
* @param string $host - fqdn or ip address
|
|
||||||
* @param string $port - port number
|
|
||||||
* @param string $name - name of database or filename when using sqlite
|
|
||||||
* @param string $username - authentication username
|
|
||||||
* @param string $password - authentication password
|
|
||||||
* @param array $options - array of database options
|
|
||||||
* @return object pdo
|
|
||||||
*/
|
|
||||||
public static function connect($type,$host=null,$port=null,$name,$username=null,$password=null,$options)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
$db = new PDO(self::_dsn($type,$host,$port,$name), $username, $password, $options);
|
|
||||||
}
|
|
||||||
catch (PDOException $exception)
|
|
||||||
{
|
|
||||||
echo "Exception: ".$exception->getMessage();
|
|
||||||
}
|
|
||||||
if ($db!==null) return $db;
|
|
||||||
else return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* disconnect from database
|
|
||||||
* @param pdo $db - database object as pdo type
|
|
||||||
*/
|
|
||||||
public static function disconnect($db)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
$db=null;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
catch (Exception $exception)
|
|
||||||
{
|
|
||||||
echo "Exception: ".$exception->getMessage();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* begin a transaction.
|
|
||||||
* @param pdo $db - database object as pdo type
|
|
||||||
*/
|
|
||||||
public static function begin_transaction($db)
|
|
||||||
{
|
|
||||||
$db->setAttribute(PDO::ATTR_AUTOCOMMIT, 0);
|
|
||||||
$db->beginTransaction();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* end the transaction.
|
|
||||||
* @param pdo $db - database object as pdo type
|
|
||||||
*/
|
|
||||||
public static function end_transaction($db)
|
|
||||||
{
|
|
||||||
$db->commit();
|
|
||||||
$db->setAttribute(PDO::ATTR_AUTOCOMMIT, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* revert the transaction.
|
|
||||||
* @param pdo $db - database object as pdo type
|
|
||||||
*/
|
|
||||||
public static function revert_transactions($db)
|
|
||||||
{
|
|
||||||
$db->rollBack();
|
|
||||||
$db->setAttribute(PDO::ATTR_AUTOCOMMIT, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* get last insert id
|
|
||||||
* @return int last insert id
|
|
||||||
*/
|
|
||||||
public static function get_lastid()
|
|
||||||
{
|
|
||||||
return $db->lastInsertId();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* get only single row
|
|
||||||
* @param pdo $db - database object as pdo type
|
|
||||||
* @param string $table - table name
|
|
||||||
* @param string $filterc - filter column
|
|
||||||
* @param string $filterv - filter value
|
|
||||||
* @return array table row
|
|
||||||
*/
|
|
||||||
public static function get_row($db,$table,$filterc,$filterv)
|
|
||||||
{
|
|
||||||
$db->prepare("SELECT * FROM $table WHERE $filterc=?");
|
|
||||||
$db->execute($filterv);
|
|
||||||
$data = $db->fetch();
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* get only single column
|
|
||||||
* @param pdo $db - database object as pdo type
|
|
||||||
* @param string $table - table name
|
|
||||||
* @param string $column - column to return value from
|
|
||||||
* @param array $filter - ["filter column",">","filter value"]
|
|
||||||
* @return array table row
|
|
||||||
*/
|
|
||||||
public static function get_col($db,$table,$column,$filter)
|
|
||||||
{
|
|
||||||
$db->prepare("SELECT $column FROM $table WHERE $filter[0] $filter[1] ?");
|
|
||||||
$db->execute($filter[2]);
|
|
||||||
$data = $cmd->fetchAll();
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* get only single value
|
|
||||||
* @param pdo $db - database object as pdo type
|
|
||||||
* @param string $table - table name
|
|
||||||
* @param string $column - column to return value from
|
|
||||||
* @param string $filterc - filter column
|
|
||||||
* @param string $filterv - filter value
|
|
||||||
* @return mixed data in field
|
|
||||||
*/
|
|
||||||
public static function get_value($db,$table,$column,$filterc,$filterv)
|
|
||||||
{
|
|
||||||
$cmd = $db->prepare("SELECT $column FROM $table WHERE $filterc=?");
|
|
||||||
$cmd->bindValue(1, $filterv);
|
|
||||||
$cmd->execute();
|
|
||||||
$data = $cmd->fetchColumn(0);
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* get count of rows
|
|
||||||
* @param pdo $db - database object as pdo type
|
|
||||||
* @param string $table - table name
|
|
||||||
* @param array $filter - ["filter column",">","filter value"]
|
|
||||||
* @return mixed data in field
|
|
||||||
*/
|
|
||||||
public static function get_count($db,$table,$filter)
|
|
||||||
{
|
|
||||||
|
|
||||||
$cmd = $db->prepare("SELECT COUNT(0) FROM $table WHERE $filter[0] $filter[1] ?");
|
|
||||||
$cmd->bindValue(1, $filter[2]);
|
|
||||||
$cmd->execute();
|
|
||||||
$data = $cmd->fetchColumn(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* get specific columns and rows
|
|
||||||
* @param pdo $db - database object as pdo type
|
|
||||||
* @param string $table - table name
|
|
||||||
* @param array $columns - specific columns to return
|
|
||||||
* @param array $filter - ["filter column",">","filter value"]
|
|
||||||
* @return array selected tables and rows
|
|
||||||
*/
|
|
||||||
public static function get_table($db,$table,$columns,$filter)
|
|
||||||
{
|
|
||||||
if($columns === null) $columns=array("*");
|
|
||||||
$cmd = $db->prepare("SELECT ".implode(',', $columns)." FROM $table WHERE $filter[0] $filter[1] ?");
|
|
||||||
$cmd->bindValue(1, $filter[2]);
|
|
||||||
$cmd->execute();
|
|
||||||
$data = $cmd->fetchAll();
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* get data with custom sql statment
|
|
||||||
* @param pdo $db - database object as pdo type
|
|
||||||
* @param string $sql - custom sql statment
|
|
||||||
* @return mixed - any returned data
|
|
||||||
*/
|
|
||||||
public static function execute($db,$sql)
|
|
||||||
{
|
|
||||||
if($sql === null) return null;
|
|
||||||
$cmd = $db->prepare($sql);
|
|
||||||
$cmd->execute();
|
|
||||||
$data = $cmd->fetchAll();
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* set single row
|
|
||||||
* @param pdo $db - database object as pdo type
|
|
||||||
* @param string $table - table name
|
|
||||||
* @param array $data - associative array 'col'=>'val'
|
|
||||||
* @param string $filterc - primary key column name or any other columns name
|
|
||||||
* @param string $filterv - value to match the condition field to
|
|
||||||
* @param int $val key value
|
|
||||||
*/
|
|
||||||
public static function set_row($db,$table,$data,$filterc,$filterv) {
|
|
||||||
|
|
||||||
if($data === null)
|
|
||||||
exit;
|
|
||||||
elseif ($filterc !== null&&$filterv !== null)
|
|
||||||
{
|
|
||||||
// get values
|
|
||||||
$v = array_values($data);
|
|
||||||
// add condition value
|
|
||||||
array_push($v,$filterv);
|
|
||||||
// get keys
|
|
||||||
$c=array();
|
|
||||||
foreach (array_keys($data) as $k) {
|
|
||||||
$c[]=$k."=?";
|
|
||||||
}
|
|
||||||
// phrase command
|
|
||||||
$cmd=$db->prepare("UPDATE $table SET ".implode(', ', $c)." WHERE $filterc=?;");
|
|
||||||
$cmd->execute($v);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// get values
|
|
||||||
$v = array_values($data);
|
|
||||||
// get keys
|
|
||||||
$c=implode(', ', array_keys($data));
|
|
||||||
// phrase command
|
|
||||||
$cmd=$db->prepare("INSERT INTO $table ($c) values (".str_repeat("?,",count($c)-1)."?)");
|
|
||||||
$cmd->execute($v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* delete row
|
|
||||||
* @param string $table table name
|
|
||||||
* @param string $where column name for condition (commonly primay key column name)
|
|
||||||
* @param int $id key value
|
|
||||||
*/
|
|
||||||
public static function delete_row($db,$table,$filterc,$filterv) {
|
|
||||||
$cmd=$db->prepare("DELETE FROM $table WHERE $filterc=?");
|
|
||||||
$cmd->execute($filterv);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* delete rows
|
|
||||||
* @param string $table table name
|
|
||||||
* @param string $where column name for condition (commonly primay key column name)
|
|
||||||
* @param int $id key value
|
|
||||||
*/
|
|
||||||
public static function delete_rows($db,$table,$filterc,$filterv) {
|
|
||||||
$cmd=$db->prepare("DELETE FROM $table WHERE $filterc=?");
|
|
||||||
$cmd->execute($filterv);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
|
|
@ -1,26 +0,0 @@
|
||||||
[Unit]
|
|
||||||
Description={$fullname}
|
|
||||||
After=syslog.target network.target {$database}
|
|
||||||
Requires={$database}
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
Type=simple
|
|
||||||
PIDFile=/run/{$shortname}.pid
|
|
||||||
WorkingDirectory={$scriptfolder}
|
|
||||||
StandardOutput=null
|
|
||||||
StandardError=syslog
|
|
||||||
ExecStart=/usr/bin/php {$scriptpath}
|
|
||||||
ExecStop=/bin/kill $MAINPID
|
|
||||||
PrivateTmp=true
|
|
||||||
InaccessibleDirectories=/home /root /boot /opt /mnt /media
|
|
||||||
ReadOnlyDirectories=/etc /usr
|
|
||||||
|
|
||||||
;Permissions
|
|
||||||
User=root
|
|
||||||
Group=daemon
|
|
||||||
|
|
||||||
;Limits
|
|
||||||
LimitCORE=1
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
WantedBy=multi-user.target
|
|
||||||
|
|
@ -1,873 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/*
|
|
||||||
* PHP TFTP Server
|
|
||||||
*
|
|
||||||
* Copyright (c) 2011 <mattias.wadman@gmail.com>
|
|
||||||
*
|
|
||||||
* MIT License:
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
* THE SOFTWARE.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* Extend TFTPServer class and then call loop method with UDP URL.
|
|
||||||
* Possible methods to override:
|
|
||||||
* exists($peer, $filename)
|
|
||||||
* Check if file exist, default always true.
|
|
||||||
* readable($peer, $filename)
|
|
||||||
* Check if file is readable, default always true.
|
|
||||||
* get($peer, $filename, $mode)
|
|
||||||
* Return content of file, default always false.
|
|
||||||
* Only called if both exists and readable returns true.
|
|
||||||
* writable($peer, $filename)
|
|
||||||
* Check if file is writable, default always false.
|
|
||||||
* put($peer, $filename, $mode, $content)
|
|
||||||
* Write content to file.
|
|
||||||
* Only falled if both exists and writable returns true.
|
|
||||||
*
|
|
||||||
* $peer is $ip:$port, source ip and port of client
|
|
||||||
* $filename is filename specified by client
|
|
||||||
* $mode is probably "octet" or "netascii"
|
|
||||||
* $content is file content
|
|
||||||
*
|
|
||||||
* The server support multiple concurrent read and writes, but the method calls
|
|
||||||
* are serialized, so make sure to return quickly.
|
|
||||||
*
|
|
||||||
* TODO:
|
|
||||||
* select must handle EINTR, how?
|
|
||||||
* multiple recv per select?
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Note about the Logger class:
|
|
||||||
* The "priority" and "minimum should be one of the constants used for syslog.
|
|
||||||
* See: http://php.net/manual/en/function.syslog.php
|
|
||||||
* They are: LOG_EMERG, LOG_ALERT, LOG_CRIT, LOG_ERR, LOG_WARNING, LOG_NOTICE,
|
|
||||||
* LOG_INFO, LOG_DEBUG
|
|
||||||
* Note that LOG_EMERG, LOG_ALERT, and LOG_CRIT are not really relevant to a
|
|
||||||
* tftp server - these represent instability in the entire operating system.
|
|
||||||
* Note that the number they are represented by are in reverse order -
|
|
||||||
* LOG_EMERG is the lowest, LOG_DEBUG the highest.
|
|
||||||
*/
|
|
||||||
|
|
||||||
abstract class Logger
|
|
||||||
{
|
|
||||||
function __construct($minimum)
|
|
||||||
{
|
|
||||||
$this->minimum = $minimum;
|
|
||||||
}
|
|
||||||
|
|
||||||
function shouldlog($priority)
|
|
||||||
{
|
|
||||||
// Note: this looks reversed, but is correct
|
|
||||||
// the priority must be AT LEAST the minimum,
|
|
||||||
// because higher priorities represent lower numbers.
|
|
||||||
return $priority <= $this->minimum;
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract function log($priority, $message);
|
|
||||||
}
|
|
||||||
|
|
||||||
class Logger_Null extends Logger
|
|
||||||
{
|
|
||||||
function log($priority, $message)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Logger_Syslog extends Logger
|
|
||||||
{
|
|
||||||
function log($priority, $message)
|
|
||||||
{
|
|
||||||
if($this->shouldlog($priority))
|
|
||||||
syslog($priority,$message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Logger_Filehandle extends Logger
|
|
||||||
{
|
|
||||||
private $priority_map = array(
|
|
||||||
LOG_DEBUG => "D",
|
|
||||||
LOG_INFO => "I",
|
|
||||||
LOG_NOTICE => "N",
|
|
||||||
LOG_WARNING => "W",
|
|
||||||
LOG_ERR => "E",
|
|
||||||
LOG_CRIT => "C",
|
|
||||||
LOG_ALERT => "A",
|
|
||||||
LOG_EMERG => "!"
|
|
||||||
);
|
|
||||||
function __construct($minimum, $filehandle, $dateformat = "r")
|
|
||||||
{
|
|
||||||
$this->filehandle = $filehandle;
|
|
||||||
$this->dateformat = $dateformat;
|
|
||||||
return parent::__construct($minimum);
|
|
||||||
}
|
|
||||||
|
|
||||||
function log($priority, $message)
|
|
||||||
{
|
|
||||||
if($this->shouldlog($priority))
|
|
||||||
fwrite($this->filehandle, date($this->dateformat) . ": " . $this->priority_map[$priority] . " $message\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Logger_Filename extends Logger_Filehandle
|
|
||||||
{
|
|
||||||
function __construct($minimum, $filename, $dateformat = "r")
|
|
||||||
{
|
|
||||||
return parent::__construct($minimum, fopen($filename, "a"), $dateformat);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Logger_Stderr extends Logger_Filehandle
|
|
||||||
{
|
|
||||||
function __construct($minimum, $dateformat = "r")
|
|
||||||
{
|
|
||||||
return parent::__construct($minimum, STDERR, $dateformat);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
class Logger_Stdout extends Logger_Filehandle
|
|
||||||
{
|
|
||||||
function __construct($minimum, $dateformat = "r")
|
|
||||||
{
|
|
||||||
return parent::__construct($minimum, STDOUT, $dateformat);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class TFTPOpcode
|
|
||||||
{
|
|
||||||
public static function name($v)
|
|
||||||
{
|
|
||||||
static $names = array(TFTPOpcode::RRQ => "RRQ",
|
|
||||||
TFTPOpcode::WRQ => "WRQ",
|
|
||||||
TFTPOpcode::DATA => "DATA",
|
|
||||||
TFTPOpcode::ACK => "ACK",
|
|
||||||
TFTPOpcode::ERROR => "ERROR",
|
|
||||||
TFTPOpcode::OACK => "OACK");
|
|
||||||
if(isset($names[$v]))
|
|
||||||
return $names[$v];
|
|
||||||
else
|
|
||||||
return "UNKNOWN";
|
|
||||||
}
|
|
||||||
|
|
||||||
const RRQ = 1; // read request
|
|
||||||
const WRQ = 2; // write request
|
|
||||||
const DATA = 3; // send data
|
|
||||||
const ACK = 4; // ack data
|
|
||||||
const ERROR = 5;
|
|
||||||
const OACK = 6; // option ack, instead of first ACK/DATA
|
|
||||||
}
|
|
||||||
|
|
||||||
class TFTPError
|
|
||||||
{
|
|
||||||
const NOT_DEFINED = 0; // see error message instead of error code
|
|
||||||
const FILE_NOT_FOUND = 1;
|
|
||||||
const ACCESS_VIOLATION = 2;
|
|
||||||
const DISK_FULL = 3;
|
|
||||||
const ILLEGAL_OPERATION = 4;
|
|
||||||
const UNKNOWN_TID = 5; // unknown transfer (id is ip:port pair)
|
|
||||||
const FILE_ALREADY_EXISTS = 6;
|
|
||||||
const NO_SUCH_USER = 7;
|
|
||||||
const OACK_FAILURE = 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
class TFTPTransferState
|
|
||||||
{
|
|
||||||
const READY = 1;
|
|
||||||
const SENDING_WAIT_OACK = 2;
|
|
||||||
const SENDING = 3;
|
|
||||||
const RECEIVING = 4;
|
|
||||||
const TERMINATING = 5;
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract class TFTPTransfer {
|
|
||||||
public $state;
|
|
||||||
public $peer;
|
|
||||||
public $retransmit_timeout;
|
|
||||||
public $block_size;
|
|
||||||
public $tsize;
|
|
||||||
protected $_server; // TFTPServer reference
|
|
||||||
|
|
||||||
function __construct($server, $peer, $extensions)
|
|
||||||
{
|
|
||||||
$this->state = TFTPTransferState::READY;
|
|
||||||
$this->peer = $peer;
|
|
||||||
$this->retransmit_timeout = $server->retransmit_timeout;
|
|
||||||
$this->block_size = $server->block_size;
|
|
||||||
$this->tsize = 0;
|
|
||||||
$this->_server = $server;
|
|
||||||
|
|
||||||
if(isset($extensions["timeout"])) {
|
|
||||||
$timeout = (int)$extensions["timeout"];
|
|
||||||
if($timeout > 0 && $timeout < 256)
|
|
||||||
$this->retransmit_timeout = $timeout;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(isset($extensions["blksize"])) {
|
|
||||||
$blksize = (int)$extensions["blksize"];
|
|
||||||
if($blksize > 0 && $blksize <= $server->max_block_size)
|
|
||||||
$this->block_size = $blksize;
|
|
||||||
}
|
|
||||||
|
|
||||||
// tsize is only checked for in write transfers
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function log_debug($message)
|
|
||||||
{
|
|
||||||
$this->_server->log_debug($this->peer, $message);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function log_info($message)
|
|
||||||
{
|
|
||||||
$this->_server->log_info($this->peer, $message);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function log_warning($message)
|
|
||||||
{
|
|
||||||
$this->_server->log_warning($this->peer, $message);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function log_error($message)
|
|
||||||
{
|
|
||||||
$this->_server->log_error($this->peer, $message);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function terminal_info($error, $message)
|
|
||||||
{
|
|
||||||
$this->log_info($message);
|
|
||||||
$this->state = TFTPTransferState::TERMINATING;
|
|
||||||
return TFTPServer::packet_error($error, $message);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function terminal_error($op, $error, $message)
|
|
||||||
{
|
|
||||||
$this->log_debug("$op: $message");
|
|
||||||
$this->state = TFTPTransferState::TERMINATING;
|
|
||||||
return TFTPServer::packet_error($error, $message);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function illegal_operation($op, $message = "Illegal operation")
|
|
||||||
{
|
|
||||||
return $this->terminal_error($op, TFTPError::ILLEGAL_OPERATION, $message);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function rrq($filename, $mode)
|
|
||||||
{
|
|
||||||
return $this->illegal_operation("RRQ");
|
|
||||||
}
|
|
||||||
|
|
||||||
public function wrq($filename, $mode)
|
|
||||||
{
|
|
||||||
return $this->illegal_operation("WRQ");
|
|
||||||
}
|
|
||||||
|
|
||||||
public function data($block, $data)
|
|
||||||
{
|
|
||||||
return $this->illegal_operation("DATA");
|
|
||||||
}
|
|
||||||
|
|
||||||
public function ack($block)
|
|
||||||
{
|
|
||||||
return $this->illegal_operation("ACK");
|
|
||||||
}
|
|
||||||
|
|
||||||
public function error($error, $message)
|
|
||||||
{
|
|
||||||
$this->log_debug("ERROR: $error: $message");
|
|
||||||
$this->state = TFTPTransferState::TERMINATING;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function use_extensions() {
|
|
||||||
return
|
|
||||||
$this->retransmit_timeout != $this->_server->retransmit_timeout ||
|
|
||||||
$this->block_size != $this->_server->block_size ||
|
|
||||||
$this->tsize != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function packet_oack() {
|
|
||||||
$options = array();
|
|
||||||
|
|
||||||
if($this->retransmit_timeout != $this->_server->retransmit_timeout)
|
|
||||||
$options["timeout"] = (string)$this->retransmit_timeout;
|
|
||||||
|
|
||||||
if($this->block_size != $this->_server->block_size)
|
|
||||||
$options["blksize"] = (string)$this->block_size;
|
|
||||||
|
|
||||||
if($this->tsize != 0)
|
|
||||||
$options["tsize"] = (string)$this->tsize;
|
|
||||||
|
|
||||||
return TFTPServer::packet_oack($options);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class TFTPReadTransfer extends TFTPTransfer {
|
|
||||||
private $_last_recv_ack;
|
|
||||||
private $_last_sent_data;
|
|
||||||
private $_buffer;
|
|
||||||
private $_block;
|
|
||||||
private $_last_block;
|
|
||||||
|
|
||||||
function __construct($server, $peer, $extensions)
|
|
||||||
{
|
|
||||||
parent::__construct($server, $peer, $extensions);
|
|
||||||
$this->_last_recv_ack = time();
|
|
||||||
$this->_last_sent_data = $this->_last_recv_ack;
|
|
||||||
$this->_buffer = false;
|
|
||||||
$this->_block = 1;
|
|
||||||
$this->_last_block = 1;
|
|
||||||
|
|
||||||
$this->log_debug("new read transfer");
|
|
||||||
}
|
|
||||||
|
|
||||||
private function current_block()
|
|
||||||
{
|
|
||||||
return substr($this->_buffer,
|
|
||||||
($this->_block - 1) * $this->block_size,
|
|
||||||
$this->block_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function packet_data_current()
|
|
||||||
{
|
|
||||||
$this->_last_sent_data = time();
|
|
||||||
|
|
||||||
if($this->state == TFTPTransferState::SENDING_WAIT_OACK)
|
|
||||||
return $this->packet_oack();
|
|
||||||
else
|
|
||||||
return TFTPServer::packet_data($this->_block, $this->current_block());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function rrq($filename, $mode)
|
|
||||||
{
|
|
||||||
$this->log_debug("RRQ: filename $filename in $mode mode");
|
|
||||||
|
|
||||||
if($this->state != TFTPTransferState::READY)
|
|
||||||
return $this->illegal_operation("RRQ", "Not in ready state");
|
|
||||||
|
|
||||||
if(!$this->_server->exists($this->peer, $filename))
|
|
||||||
return $this->terminal_info(TFTPError::FILE_NOT_FOUND,
|
|
||||||
"File $filename does not exist");
|
|
||||||
|
|
||||||
if(!$this->_server->readable($this->peer, $filename))
|
|
||||||
return $this->terminal_info(TFTPError::ACCESS_VIOLATION,
|
|
||||||
"File $filename is not readable");
|
|
||||||
|
|
||||||
$this->_buffer = $this->_server->get($this->peer, $filename, $mode);
|
|
||||||
if($this->_buffer === false)
|
|
||||||
return $this->terminal_info(TFTPError::FILE_NOT_FOUND,
|
|
||||||
"Failed to read $filename");
|
|
||||||
|
|
||||||
$this->log_info("Reading $filename (" .
|
|
||||||
strlen($this->_buffer) . " bytes)");
|
|
||||||
|
|
||||||
if($this->use_extensions())
|
|
||||||
$this->state = TFTPTransferState::SENDING_WAIT_OACK;
|
|
||||||
else
|
|
||||||
$this->state = TFTPTransferState::SENDING;
|
|
||||||
$this->_last_block = floor(strlen($this->_buffer) /
|
|
||||||
$this->block_size) + 1;
|
|
||||||
|
|
||||||
$this->log_debug("RRQ: send first block or OACK");
|
|
||||||
return $this->packet_data_current();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function ack($block)
|
|
||||||
{
|
|
||||||
if($this->state == TFTPTransferState::SENDING_WAIT_OACK) {
|
|
||||||
if($block != 0) {
|
|
||||||
$this->log_debug("ACK: waiting OACK ACK got block $block");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->state = TFTPTransferState::SENDING;
|
|
||||||
$this->log_debug("ACK: got OACK ACK, send first block");
|
|
||||||
return $this->packet_data_current();
|
|
||||||
}
|
|
||||||
|
|
||||||
if($this->state != TFTPTransferState::SENDING)
|
|
||||||
return $this->illegal_operation("ACK", "Not in sending state");
|
|
||||||
|
|
||||||
$this->log_debug("ACK: block $block");
|
|
||||||
$this->_last_recv_ack = time();
|
|
||||||
|
|
||||||
if($block < $this->_block) {
|
|
||||||
$this->log_debug("ACK: duplicate block $block");
|
|
||||||
// just ignore it
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if($block > $this->_last_block)
|
|
||||||
return $this->illegal_operation("ACK",
|
|
||||||
"Block $block outside " .
|
|
||||||
"range 1-{$this->_last_block}");
|
|
||||||
|
|
||||||
if($block == $this->_last_block) {
|
|
||||||
$this->log_debug("ACK: last block, done");
|
|
||||||
$this->state = TFTPTransferState::TERMINATING;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// move to next block
|
|
||||||
$this->_block = $block + 1;
|
|
||||||
|
|
||||||
$this->log_debug("ACK: sending block {$this->_block}");
|
|
||||||
return $this->packet_data_current();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function retransmit($now)
|
|
||||||
{
|
|
||||||
if($now - $this->_last_recv_ack > $this->_server->timeout) {
|
|
||||||
$this->log_debug("retransmit: timeout");
|
|
||||||
$this->state = TFTPTransferState::TERMINATING;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if($now - $this->_last_sent_data > $this->retransmit_timeout) {
|
|
||||||
$this->log_debug("retransmit: resending block {$this->_block} or OACK");
|
|
||||||
return $this->packet_data_current();
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class TFTPWriteTransfer extends TFTPTransfer {
|
|
||||||
private $_last_sent_ack;
|
|
||||||
private $_last_recv_data;
|
|
||||||
private $_buffer;
|
|
||||||
private $_buffer_size;
|
|
||||||
private $_next_block;
|
|
||||||
private $_filename;
|
|
||||||
private $_mode;
|
|
||||||
|
|
||||||
function __construct($server, $peer, $extensions)
|
|
||||||
{
|
|
||||||
parent::__construct($server, $peer, $extensions);
|
|
||||||
$this->_last_sent_ack = time();
|
|
||||||
$this->_last_recv_data = $this->_last_sent_ack;
|
|
||||||
$this->_buffer = array();
|
|
||||||
$this->_buffer_size = 0;
|
|
||||||
$this->_last_recv_block = 0;
|
|
||||||
$this->_filename = false;
|
|
||||||
$this->_mode = false;
|
|
||||||
|
|
||||||
if(isset($extensions["tsize"]))
|
|
||||||
$this->tsize = (int)$extensions["tsize"];
|
|
||||||
|
|
||||||
$this->log_debug("new write transfer");
|
|
||||||
}
|
|
||||||
|
|
||||||
private function packet_ack_current()
|
|
||||||
{
|
|
||||||
$this->_last_sent_ack = time();
|
|
||||||
|
|
||||||
if($this->_last_recv_block == 0 && $this->use_extensions())
|
|
||||||
return $this->packet_oack();
|
|
||||||
else
|
|
||||||
return TFTPServer::packet_ack($this->_last_recv_block);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function wrq($filename, $mode)
|
|
||||||
{
|
|
||||||
$this->log_debug("WRQ: filename $filename in $mode mode");
|
|
||||||
|
|
||||||
if($this->state != TFTPTransferState::READY)
|
|
||||||
return $this->illegal_operation("WRQ", "Not in ready state");
|
|
||||||
|
|
||||||
if(!$this->_server->writable($this->peer, $filename))
|
|
||||||
return $this->terminal_info(TFTPError::ACCESS_VIOLATION,
|
|
||||||
"File $filename is not writable");
|
|
||||||
|
|
||||||
if($this->tsize != 0 && $this->tsize > $this->_server->max_put_size)
|
|
||||||
return $this->terminal_info(TFTPError::DISK_FULL,
|
|
||||||
"File too big, " .
|
|
||||||
$this->tsize . "(tsize) > " .
|
|
||||||
$this->_server->max_put_size);
|
|
||||||
|
|
||||||
$this->state = TFTPTransferState::RECEIVING;
|
|
||||||
$this->_filename = $filename;
|
|
||||||
$this->_mode = $mode;
|
|
||||||
$this->_last_sent_ack = time();
|
|
||||||
|
|
||||||
$this->log_debug("WRQ: ack request");
|
|
||||||
if($this->use_extensions())
|
|
||||||
return $this->packet_oack();
|
|
||||||
else
|
|
||||||
return TFTPServer::packet_ack(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function data($block, $data)
|
|
||||||
{
|
|
||||||
if($this->state != TFTPTransferState::RECEIVING)
|
|
||||||
return $this->illegal_operation("DATA", "Not in receiving state");
|
|
||||||
|
|
||||||
$this->log_debug("DATA: block $block");
|
|
||||||
$this->last_recv_data = time();
|
|
||||||
|
|
||||||
if($block <= $this->_last_recv_block) {
|
|
||||||
$this->log_debug("DATA: duplicate block $block");
|
|
||||||
// just ignore it
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if($block != $this->_last_recv_block + 1)
|
|
||||||
return $this->illegal_operation("DATA",
|
|
||||||
"Expected block " .
|
|
||||||
($this->_last_recv_block + 1) .
|
|
||||||
" got $block");
|
|
||||||
|
|
||||||
$this->_last_recv_block = $block;
|
|
||||||
$this->_last_recv_data = time();
|
|
||||||
array_push($this->_buffer, $data);
|
|
||||||
$this->_buffer_size += strlen($data);
|
|
||||||
|
|
||||||
if($this->_buffer_size > $this->_server->max_put_size)
|
|
||||||
return $this->terminal_info(TFTPError::DISK_FULL,
|
|
||||||
"File too big, " .
|
|
||||||
$this->_buffer_size . " > " .
|
|
||||||
$this->_server->max_put_size);
|
|
||||||
|
|
||||||
if(strlen($data) < $this->block_size) {
|
|
||||||
$this->log_debug("DATA: last, done");
|
|
||||||
$this->state = TFTPTransferState::TERMINATING;
|
|
||||||
$this->log_info("Writing {$this->_filename} " .
|
|
||||||
"({$this->_buffer_size} bytes)");
|
|
||||||
$this->_server->put($this->peer, $this->_filename, $this->_mode,
|
|
||||||
implode("", $this->_buffer));
|
|
||||||
return $this->packet_ack_current();
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->log_debug("DATA: ack block $block");
|
|
||||||
return $this->packet_ack_current();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function retransmit($now)
|
|
||||||
{
|
|
||||||
if($now - $this->_last_recv_data > $this->_server->timeout) {
|
|
||||||
$this->log_debug("retransmit: timeout");
|
|
||||||
$this->state = TFTPTransferState::TERMINATING;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if($now - $this->_last_sent_ack > $this->retransmit_timeout) {
|
|
||||||
$this->log_debug("retransmit: reack block {$this->_last_recv_block}");
|
|
||||||
return $this->packet_ack_current();
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class TFTPServer {
|
|
||||||
public $block_size = 512;
|
|
||||||
public $max_block_size = 65464; // max block size from rfc2348
|
|
||||||
public $timeout = 10;
|
|
||||||
public $retransmit_timeout = 1;
|
|
||||||
public $max_put_size = 10485760; // 10 Mibi
|
|
||||||
private $_socket_url;
|
|
||||||
private $_socket;
|
|
||||||
private $_transfers = array();
|
|
||||||
private $_logger = NULL;
|
|
||||||
|
|
||||||
function __construct($socket_url, $logger = NULL)
|
|
||||||
{
|
|
||||||
$this->_socket_url = $socket_url;
|
|
||||||
$this->_logger = $logger;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function exists($peer, $filename)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function readable($peer, $filename)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function get($peer, $filename, $mode)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function writable($peer, $filename)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function put($peer, $filename, $mode, $content)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public function logger_log($priority, $message) {
|
|
||||||
if($this->_logger === NULL)
|
|
||||||
return;
|
|
||||||
|
|
||||||
$this->_logger->log($priority, $message);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function log_debug($peer, $message)
|
|
||||||
{
|
|
||||||
$this->logger_log(LOG_DEBUG, "$peer $message");
|
|
||||||
}
|
|
||||||
|
|
||||||
public function log_info($peer, $message)
|
|
||||||
{
|
|
||||||
$this->logger_log(LOG_INFO, "$peer $message");
|
|
||||||
}
|
|
||||||
|
|
||||||
public function log_warning($peer, $message)
|
|
||||||
{
|
|
||||||
$this->logger_log(LOG_WARNING, "$peer $message");
|
|
||||||
}
|
|
||||||
|
|
||||||
public function log_error($peer, $message)
|
|
||||||
{
|
|
||||||
$this->logger_log(LOG_ERR, "$peer $message");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function packet_ack($block)
|
|
||||||
{
|
|
||||||
return pack("nn", TFTPOpcode::ACK, $block);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function packet_data($block, $data)
|
|
||||||
{
|
|
||||||
return pack("nn", TFTPOpcode::DATA, $block) . $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function packet_error($code, $message = "")
|
|
||||||
{
|
|
||||||
return pack("nn", TFTPOpcode::ERROR, $code) . $message . "\0";
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function packet_oack($options)
|
|
||||||
{
|
|
||||||
$data = "";
|
|
||||||
foreach($options as $key => $value)
|
|
||||||
$data .= "$key\0$value\0";
|
|
||||||
return pack("n", TFTPOpcode::OACK) . $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function escape_string($str)
|
|
||||||
{
|
|
||||||
$b = "";
|
|
||||||
$l = strlen($str);
|
|
||||||
for($i = 0; $i < $l; $i++) {
|
|
||||||
$c = $str[$i];
|
|
||||||
if(ctype_print($c))
|
|
||||||
$b .= $c;
|
|
||||||
else
|
|
||||||
$b .= sprintf("\\x%'02x", ord($c));
|
|
||||||
}
|
|
||||||
|
|
||||||
return $b;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function loop(&$error = false, $user = null)
|
|
||||||
{
|
|
||||||
$this->_socket =
|
|
||||||
stream_socket_server($this->_socket_url, $errno, $errstr,
|
|
||||||
STREAM_SERVER_BIND);
|
|
||||||
if(!$this->_socket) {
|
|
||||||
if($error !== false)
|
|
||||||
$error = "$errno: $errstr";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if($user != null) {
|
|
||||||
posix_seteuid($user["uid"]);
|
|
||||||
posix_setegid($user["gid"]);
|
|
||||||
}
|
|
||||||
|
|
||||||
stream_set_blocking($this->_socket, false);
|
|
||||||
|
|
||||||
return $this->loop_ex();
|
|
||||||
}
|
|
||||||
|
|
||||||
private function loop_ex()
|
|
||||||
{
|
|
||||||
$now = $last = time();
|
|
||||||
|
|
||||||
while(true) {
|
|
||||||
$read = array($this->_socket);
|
|
||||||
$write = null;
|
|
||||||
$excpt = null;
|
|
||||||
$r = stream_select($read, $write, $excpt, 1);
|
|
||||||
|
|
||||||
if($r === false) {
|
|
||||||
$this->log_error("server", "select returned false");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(count($read) > 0) {
|
|
||||||
$packet = stream_socket_recvfrom($this->_socket,
|
|
||||||
65535, // max udp packet size
|
|
||||||
0, // no flags
|
|
||||||
$peer);
|
|
||||||
// ipv6 hack, convert to [host]:port format
|
|
||||||
if(strpos($peer, ".") === false) {
|
|
||||||
$portpos = strrpos($peer, ":");
|
|
||||||
$host = substr($peer, 0, $portpos);
|
|
||||||
$port = substr($peer, $portpos + 1);
|
|
||||||
$peer = "[$host]:$port";
|
|
||||||
}
|
|
||||||
$this->log_debug($peer, "request: ".strlen($packet)." bytes");
|
|
||||||
$this->log_debug($peer, "request: ".TFTPServer::escape_string($packet));
|
|
||||||
$reply = $this->request($peer, $packet);
|
|
||||||
if($reply !== false) {
|
|
||||||
$this->log_debug($peer, "reply: " .
|
|
||||||
TFTPServer::escape_string($reply));
|
|
||||||
stream_socket_sendto($this->_socket, $reply, 0, $peer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$now = time();
|
|
||||||
if($now != $last) {
|
|
||||||
$last = $now;
|
|
||||||
$this->retransmit($now);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function retransmit($now)
|
|
||||||
{
|
|
||||||
foreach($this->_transfers as $peer => $transfer) {
|
|
||||||
$reply = $transfer->retransmit($now);
|
|
||||||
if($reply !== false) {
|
|
||||||
$this->log_debug($peer, "resend: " .
|
|
||||||
TFTPServer::escape_string($reply));
|
|
||||||
stream_socket_sendto($this->_socket, $reply, 0, $peer);
|
|
||||||
}
|
|
||||||
|
|
||||||
if($transfer->state == TFTPTransferState::TERMINATING)
|
|
||||||
unset($this->_transfers[$peer]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function request($peer, $packet)
|
|
||||||
{
|
|
||||||
if(strlen($packet) < 4) {
|
|
||||||
$this->log_debug($peer, "request: short packet");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$reply = false;
|
|
||||||
$transfer = false;
|
|
||||||
if(isset($this->_transfers[$peer])) {
|
|
||||||
$this->log_debug($peer, "request: existing transfer");
|
|
||||||
$transfer = $this->_transfers[$peer];
|
|
||||||
}
|
|
||||||
|
|
||||||
$fields = unpack("n", $packet);
|
|
||||||
$op = $fields[1];
|
|
||||||
$this->log_debug($peer, "request: opcode " .
|
|
||||||
TFTPOpcode::name($op) . " ($op)");
|
|
||||||
switch($op) {
|
|
||||||
case TFTPOpcode::WRQ:
|
|
||||||
case TFTPOpcode::RRQ:
|
|
||||||
$a = explode("\0", substr($packet, 2));
|
|
||||||
if(count($a) < 3 || $a[count($a) - 1] != "") {
|
|
||||||
$this->log_warning($peer, "request: malformed " .
|
|
||||||
TFTPOpcode::name($op));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$rawexts = array_slice($a, 2, -1);
|
|
||||||
|
|
||||||
// Cisco IP Phone 7941 (and possibly others) return an extra null
|
|
||||||
// at the end; a breach of RFC rfc2347. This is a workaround.
|
|
||||||
// If odd count strip last and continue if empty, else warn and ignore
|
|
||||||
if(count($rawexts) % 2 != 0) {
|
|
||||||
if(array_pop($rawexts)!="") {
|
|
||||||
$this->log_warning($peer, "request: malformed extension " .
|
|
||||||
"key/value pairs " . TFTPOpcode::name($op));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$extensions = array();
|
|
||||||
foreach(array_chunk($rawexts, 2) as $pair)
|
|
||||||
$extensions[strtolower($pair[0])] = $pair[1];
|
|
||||||
|
|
||||||
if($transfer === false) {
|
|
||||||
if($op == TFTPOpcode::RRQ)
|
|
||||||
$transfer = new TFTPReadTransfer($this, $peer, $extensions);
|
|
||||||
else
|
|
||||||
$transfer = new TFTPWriteTransfer($this, $peer, $extensions);
|
|
||||||
|
|
||||||
$this->_transfers[$peer] = $transfer;
|
|
||||||
}
|
|
||||||
|
|
||||||
if($op == TFTPOpcode::RRQ)
|
|
||||||
$reply = $transfer->rrq($a[0], $a[1]);
|
|
||||||
else
|
|
||||||
$reply = $transfer->wrq($a[0], $a[1]);
|
|
||||||
|
|
||||||
break;
|
|
||||||
case TFTPOpcode::ACK:
|
|
||||||
if(strlen($packet) != 4) {
|
|
||||||
$this->log_warning($peer, "request: malformed ACK");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$a = unpack("n", substr($packet, 2));
|
|
||||||
if($transfer === false) {
|
|
||||||
// do not warn, some clients like BSD tftp sends ack on read error
|
|
||||||
$this->log_debug($peer, "request: ack from unknwon peer");
|
|
||||||
} else
|
|
||||||
$reply = $transfer->ack($a[1]);
|
|
||||||
break;
|
|
||||||
case TFTPOpcode::DATA:
|
|
||||||
if(strlen($packet) < 4) {
|
|
||||||
$this->log_warning($peer, "request: malformed DATA");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$a = unpack("n", substr($packet, 2));
|
|
||||||
$data = substr($packet, 4, strlen($packet) - 4);
|
|
||||||
if($transfer === false) {
|
|
||||||
$this->log_warning($peer, "request: data from unknwon peer");
|
|
||||||
$reply = TFTPServer::packet_error(TFTPError::UNKNOWN_TID,
|
|
||||||
"Unknown TID for DATA");
|
|
||||||
} else
|
|
||||||
$reply = $transfer->data($a[1], $data);
|
|
||||||
break;
|
|
||||||
case TFTPOpcode::ERROR:
|
|
||||||
$a = unpack("n", substr($packet, 2, 2));
|
|
||||||
$message = substr($packet, 4, strlen($packet) - 5);
|
|
||||||
|
|
||||||
if($transfer === false)
|
|
||||||
$this->log_warning($peer, "request: error from unknwon peer, " .
|
|
||||||
"{$a[1]}:$message");
|
|
||||||
else
|
|
||||||
$transfer->error($a[1], $message);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if($transfer !== false &&
|
|
||||||
$transfer->state == TFTPTransferState::TERMINATING) {
|
|
||||||
$this->log_debug($peer, "request: terminating");
|
|
||||||
unset($this->_transfers[$transfer->peer]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $reply;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
||||||
|
|
@ -1,178 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/*
|
|
||||||
FusionPBX
|
|
||||||
Version: MPL 1.1
|
|
||||||
|
|
||||||
The contents of this file are subject to the Mozilla Public License Version
|
|
||||||
1.1 (the "License"); you may not use this file except in compliance with
|
|
||||||
the License. You may obtain a copy of the License at
|
|
||||||
http://www.mozilla.org/MPL/
|
|
||||||
|
|
||||||
Software distributed under the License is distributed on an "AS IS" basis,
|
|
||||||
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
||||||
for the specific language governing rights and limitations under the
|
|
||||||
License.
|
|
||||||
|
|
||||||
The Original Code is FusionPBX
|
|
||||||
|
|
||||||
The Initial Developer of the Original Code is
|
|
||||||
Sebastian Krupinski <sebastian@ksacorp.com>
|
|
||||||
Portions created by the Initial Developer are Copyright (C) 2016
|
|
||||||
the Initial Developer. All Rights Reserved.
|
|
||||||
|
|
||||||
Contributor(s):
|
|
||||||
Sebastian Krupinski <sebastian@ksacorp.com>
|
|
||||||
*/
|
|
||||||
|
|
||||||
// load required files
|
|
||||||
require_once 'tftpserver.class.php';
|
|
||||||
|
|
||||||
class tftpservice extends TFTPServer
|
|
||||||
{
|
|
||||||
private $_headless=true;
|
|
||||||
private $_debug=false;
|
|
||||||
private $_dbtype;
|
|
||||||
private $_dbhost;
|
|
||||||
private $_dbport;
|
|
||||||
private $_dbname;
|
|
||||||
private $_dbusername;
|
|
||||||
private $_dbpassword;
|
|
||||||
private $_fileslocation;
|
|
||||||
|
|
||||||
function __construct($server_url, $config)
|
|
||||||
{
|
|
||||||
parent::__construct($server_url);
|
|
||||||
if (isset($config['headless'])) $this->_headless=$config['headless'];
|
|
||||||
if (isset($config['debug'])) $this->_debug=$config['debug'];
|
|
||||||
if (isset($config['db_type'])) $this->_dbtype=$config['db_type'];
|
|
||||||
if (isset($config['db_host'])) $this->_dbhost=$config['db_host'];
|
|
||||||
if (isset($config['db_port'])) $this->_dbport=$config['db_port'];
|
|
||||||
if (isset($config['db_name'])) $this->_dbname=$config['db_name'];
|
|
||||||
if (isset($config['db_username'])) $this->_dbusername=$config['db_username'];
|
|
||||||
if (isset($config['db_password'])) $this->_dbpassword=$config['db_password'];
|
|
||||||
if (isset($config['files_location'])) $this->_fileslocation=$config['files_location'];
|
|
||||||
|
|
||||||
if (!file_exists($_fileslocation)) {
|
|
||||||
$_fileslocation = (strpos(PHP_OS,"WIN") !== false) ? $_SERVER["TMP"] : "/tmp";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function log($client, $level, $message) {
|
|
||||||
if(!$this->_headless && ($level!='D' || $this->_debug)) {
|
|
||||||
echo
|
|
||||||
date("H:i:s") . " " .
|
|
||||||
$level . " " .
|
|
||||||
$client . " " .
|
|
||||||
$message . "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public function get($client, $filepath, $mode)
|
|
||||||
{
|
|
||||||
$this->log($client,"N", "Requested File ".$filepath);
|
|
||||||
|
|
||||||
try {
|
|
||||||
$regex_filter='/provision\/(?<domain>\b(?:(?-)[A-Za-z0-9-\_]{1,63}(?-)\.)+[A-Za-z]{1,63}\b|\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b)\/(?<mac>\b(?:[0-9a-fA-F]{2}(?:\-|\:)?){6}\b)/';
|
|
||||||
|
|
||||||
preg_match($regex_filter,$filepath,$regex_matches);
|
|
||||||
|
|
||||||
// check if filepath is in a specific format and respond acordingly
|
|
||||||
if ($regex_matches['domain']&&$regex_matches['mac'])
|
|
||||||
{
|
|
||||||
// generate file from db
|
|
||||||
$filedata = $this->generate_file($client,$regex_matches['domain'],$regex_matches['mac']);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// retrieve file from disk
|
|
||||||
$filedata = $this->retrieve_file($client,$filepath);
|
|
||||||
}
|
|
||||||
|
|
||||||
if($filedata !== false)
|
|
||||||
{
|
|
||||||
$this->log($client,"N", "Transmitting File ".$filepath);
|
|
||||||
|
|
||||||
return $filedata;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception $exception)
|
|
||||||
{
|
|
||||||
$this->log($client,"E", "Exception: ".$exception->getMessage());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function generate_file($client, $domain, $mac)
|
|
||||||
{
|
|
||||||
// load required files
|
|
||||||
require_once __DIR__.'/dbhelper.php';
|
|
||||||
require_once __DIR__.'/../../../resources/functions.php';
|
|
||||||
require_once __DIR__.'/../../../resources/classes/template.php';
|
|
||||||
require_once __DIR__.'/../../provision/resources/classes/provision.php';
|
|
||||||
|
|
||||||
$this->log($client,"D", "Generating File ".$domain." ".$mac);
|
|
||||||
|
|
||||||
// connect to database
|
|
||||||
$db = database::connect($this->_dbtype,$this->_dbhost,$this->_dbport,$this->_dbname,$this->_dbusername,$this->_dbpassword);
|
|
||||||
|
|
||||||
// get domain uuid
|
|
||||||
$domain_uuid = database::get_value($db,'v_domains','domain_uuid','domain_name',$domain);
|
|
||||||
|
|
||||||
// set temporary folder for template engine
|
|
||||||
$_SESSION['server']['temp']['dir'] = (strpos(PHP_OS,"WIN") !== false) ? $_SERVER["TMP"] : "/tmp";
|
|
||||||
|
|
||||||
// update device provisioned status
|
|
||||||
$data=array('device_provisioned_date'=>date("Y-m-d H:i:s"),'device_provisioned_method'=>'tftp','device_provisioned_ip'=>$client);
|
|
||||||
database::set_row($db,'v_devices',$data,'device_mac_address',$mac);
|
|
||||||
|
|
||||||
// generate file
|
|
||||||
$prov = new provision;
|
|
||||||
$prov->db = $db;
|
|
||||||
$prov->domain_uuid = $domain_uuid;
|
|
||||||
$prov->mac = $mac;
|
|
||||||
$data = $prov->render();
|
|
||||||
|
|
||||||
// return data or false
|
|
||||||
if($data === false)
|
|
||||||
{
|
|
||||||
$this->log($client,"W", "Generating File Failed ".$domain." ".$mac);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function retrieve_file($client, $path){
|
|
||||||
|
|
||||||
$this->log($client,"D", "Retrieve File ".$path);
|
|
||||||
// check for reletive path directive
|
|
||||||
if(strstr($path, "../") != false || strstr($path, "/..") != false) return false;
|
|
||||||
// combine base and path
|
|
||||||
$path = rtrim($this->_fileslocation,'/').'/'.ltrim($path,'/');
|
|
||||||
if(substr($path, 0, strlen($this->_fileslocation)) != $this->_fileslocation) return false;
|
|
||||||
// read contents
|
|
||||||
if($this->_debug) $this->log($client,"D", "Reading File ".$path);
|
|
||||||
$data = @file_get_contents($path);
|
|
||||||
// return data or false
|
|
||||||
if($data === false)
|
|
||||||
{
|
|
||||||
$this->log($client,"W", "Retrieving File Failed ".$path);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
||||||
|
|
@ -1,344 +0,0 @@
|
||||||
#!/usr/bin/env php
|
|
||||||
<?php
|
|
||||||
|
|
||||||
/*
|
|
||||||
FusionPBX
|
|
||||||
Version: MPL 1.1
|
|
||||||
|
|
||||||
The contents of this file are subject to the Mozilla Public License Version
|
|
||||||
1.1 (the "License"); you may not use this file except in compliance with
|
|
||||||
the License. You may obtain a copy of the License at
|
|
||||||
http://www.mozilla.org/MPL/
|
|
||||||
|
|
||||||
Software distributed under the License is distributed on an "AS IS" basis,
|
|
||||||
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
||||||
for the specific language governing rights and limitations under the
|
|
||||||
License.
|
|
||||||
|
|
||||||
The Original Code is FusionPBX
|
|
||||||
|
|
||||||
The Initial Developer of the Original Code is
|
|
||||||
Sebastian Krupinski <sebastian@ksacorp.com>
|
|
||||||
Portions created by the Initial Developer are Copyright (C) 2016
|
|
||||||
the Initial Developer. All Rights Reserved.
|
|
||||||
|
|
||||||
Contributor(s):
|
|
||||||
Sebastian Krupinski <sebastian@ksacorp.com>
|
|
||||||
*/
|
|
||||||
|
|
||||||
// define variables and constants
|
|
||||||
$appname = "fusionpbx-tftp";
|
|
||||||
$appdesc = "FusionPBX TFTP Service";
|
|
||||||
$pid=null;
|
|
||||||
$pidfile = (strpos(PHP_OS,"WIN") !== false) ? $_SERVER["TMP"]."\\$appname.pid" : "/var/run/$appname.pid";
|
|
||||||
$tftpservice_address="0.0.0.0";
|
|
||||||
$tftpservice_port=69;
|
|
||||||
$tftpservice_file_path=(strpos(PHP_OS,"WIN") !== false) ? $_SERVER["TMP"] : "/tmp";
|
|
||||||
|
|
||||||
function Service_Install()
|
|
||||||
{
|
|
||||||
global $appname;
|
|
||||||
global $appdesc;
|
|
||||||
|
|
||||||
// install for specific os
|
|
||||||
if (strpos(PHP_OS,"WIN") !== false)
|
|
||||||
{
|
|
||||||
// check if we found the executable binary
|
|
||||||
if (file_exists(PHP_BINARY))
|
|
||||||
{
|
|
||||||
win32_create_service( Array(
|
|
||||||
'service' => $appname,
|
|
||||||
'display' => $appdesc,
|
|
||||||
'params' => __FILE__ . " --Service",
|
|
||||||
'path' => PHP_BINARY
|
|
||||||
));
|
|
||||||
|
|
||||||
//exec('sc create '.$appname.' type=own binPath="'.PHP_BINARY.' '.$_SERVER["SCRIPT_FILENAME"].'" DisplayName="'.$appdesc.'" start=auto');
|
|
||||||
die($appdesc." was successfully installed.\n");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
die($appdesc." could not be installed because the php executable was not found.\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// load required files
|
|
||||||
require_once __DIR__.'/../../resources/config.php'; //required for database type
|
|
||||||
|
|
||||||
// read template file
|
|
||||||
$template=file_get_contents(dirname(__FILE__).'/resources/systemd.service.template');
|
|
||||||
|
|
||||||
// service short name
|
|
||||||
$template=str_replace('{$shortname}',$appname,$template);
|
|
||||||
// service full name
|
|
||||||
$template=str_replace('{$fullname}',$appdesc,$template);
|
|
||||||
// service dependencies
|
|
||||||
switch ($db_type) {
|
|
||||||
case 'pgsql':
|
|
||||||
$template=str_replace('{$database}','postgresql.service',$template);
|
|
||||||
break;
|
|
||||||
case 'mysql':
|
|
||||||
$template=str_replace('{$database}','mariadb.service',$template);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
$template=str_replace('{$database}','',$template);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// script path
|
|
||||||
$template=str_replace('{$scriptpath}',__FILE__,$template);
|
|
||||||
// script folder
|
|
||||||
$template=str_replace('{$scriptfolder}',dirname(__FILE__),$template);
|
|
||||||
// script filename
|
|
||||||
$template=str_replace('{$scriptfilename}',basename(__FILE__),$template);
|
|
||||||
|
|
||||||
// write service file
|
|
||||||
file_put_contents('/lib/systemd/system/'.$appname.'.service', $template);
|
|
||||||
// reload systemd and enable service
|
|
||||||
exec('systemctl daemon-reload');
|
|
||||||
exec('systemctl enable '.$appname);
|
|
||||||
|
|
||||||
die($appdesc." was successfully installed.\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function Service_Uninstall()
|
|
||||||
{
|
|
||||||
global $appname;
|
|
||||||
global $appdesc;
|
|
||||||
|
|
||||||
// uninstall for specific os
|
|
||||||
if (strpos(PHP_OS,"WIN") !== false)
|
|
||||||
{
|
|
||||||
win32_delete_service($appname);
|
|
||||||
//exec('sc delete "'.$appname.'"');
|
|
||||||
die($appdesc." was successfully uninstalled.\n");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// stop service and disable in systemd
|
|
||||||
exec('systemctl stop '.$appname);
|
|
||||||
exec('systemctl disable '.$appname);
|
|
||||||
// delete systemd service file
|
|
||||||
unlink('/lib/systemd/system/'.$appname.'.service');
|
|
||||||
die($appdesc." was successfully uninstalled.\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function Service_Run()
|
|
||||||
{
|
|
||||||
global $appname;
|
|
||||||
global $appdesc;
|
|
||||||
global $pid;
|
|
||||||
global $pidfile;
|
|
||||||
|
|
||||||
// check for existing process
|
|
||||||
if (file_exists($pidfile)) {
|
|
||||||
$pid = file_get_contents($pidfile);
|
|
||||||
if (is_numeric($pid)) {
|
|
||||||
if (strpos(PHP_OS,"WIN") !== false)
|
|
||||||
{
|
|
||||||
exec('tasklist -NH -FO TABLE -FI "PID eq '.$pid.'" 2>NUL', $data);
|
|
||||||
foreach($data as $line)
|
|
||||||
{
|
|
||||||
if (strpos($line,$pid) !== false) die($appdesc." already running with process id ".$pid);
|
|
||||||
}
|
|
||||||
|
|
||||||
Service_Windows_Run();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (file_exists('/proc/'.$pid)) die($appdesc." already running with process id".$pid);
|
|
||||||
|
|
||||||
Service_Linux_Run();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
function Service_Linux_Run()
|
|
||||||
{
|
|
||||||
global $appname;
|
|
||||||
global $appdesc;
|
|
||||||
global $pid;
|
|
||||||
global $pidfile;
|
|
||||||
global $tftpservice_address;
|
|
||||||
global $tftpservice_port;
|
|
||||||
global $tftpservice_file_path;
|
|
||||||
|
|
||||||
// write pid file
|
|
||||||
file_put_contents($pidfile, getmypid());
|
|
||||||
|
|
||||||
// load required files
|
|
||||||
require_once __DIR__.'/../../resources/config.php';
|
|
||||||
require_once 'resources/dbhelper.php';
|
|
||||||
|
|
||||||
// get service settings from database
|
|
||||||
// connect to database
|
|
||||||
$db = database::connect($db_type,$db_host,$db_port,$db_name,$db_username,$db_password);
|
|
||||||
// get settings
|
|
||||||
$s = database::get_table($db,'v_default_settings',array('default_setting_subcategory','default_setting_value'),array('default_setting_subcategory','LIKE','tftp_service_%'));
|
|
||||||
// set local variables
|
|
||||||
foreach ($s as $i) {
|
|
||||||
switch ($i[0]) {
|
|
||||||
case 'tftp_service_address':
|
|
||||||
$tftpservice_address=$i[1];
|
|
||||||
break;
|
|
||||||
case 'tftp_service_port':
|
|
||||||
$tftpservice_port=$i[1];
|
|
||||||
break;
|
|
||||||
case 'tftp_service_file_path':
|
|
||||||
$tftpservice_file_path=$i[1];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// disconnect from database
|
|
||||||
unset($db);
|
|
||||||
// destroy data
|
|
||||||
unset($s);
|
|
||||||
|
|
||||||
// load required files
|
|
||||||
require_once 'resources/tftpservice.class.php';
|
|
||||||
|
|
||||||
// start service
|
|
||||||
$server = new tftpservice("udp://$tftpservice_address:$tftpservice_port", array("headless"=>true, "db_type"=>$db_type, "db_host"=>$db_host, "db_port"=>$db_port, "db_name"=>$db_name, "db_username"=>$db_username, "db_password"=>$db_password, "files_location"=>$tftpservice_file_path));
|
|
||||||
if(!$server->loop($error, $user)) die("$error\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
function Service_Windows_Run()
|
|
||||||
{
|
|
||||||
global $appname;
|
|
||||||
global $appdesc;
|
|
||||||
global $pid;
|
|
||||||
global $pidfile;
|
|
||||||
global $tftpservice_address;
|
|
||||||
global $tftpservice_port;
|
|
||||||
global $tftpservice_file_path;
|
|
||||||
|
|
||||||
// write pid file
|
|
||||||
file_put_contents($pidfile, getmypid());
|
|
||||||
|
|
||||||
// load required files
|
|
||||||
require_once __DIR__.'/../../resources/config.php';
|
|
||||||
require_once 'resources/dbhelper.php';
|
|
||||||
|
|
||||||
// get service settings from database
|
|
||||||
// connect to database
|
|
||||||
$db = database::connect($db_type,$db_host,$db_port,$db_name,$db_username,$db_password);
|
|
||||||
// get settings
|
|
||||||
$s = database::get_table($db,'v_default_settings',array('default_setting_subcategory','default_setting_value'),array('default_setting_subcategory','LIKE','tftp_service_%'));
|
|
||||||
// set local variables
|
|
||||||
foreach ($s as $i) {
|
|
||||||
switch ($i[0]) {
|
|
||||||
case 'tftp_service_address':
|
|
||||||
$tftpservice_address=$i[1];
|
|
||||||
break;
|
|
||||||
case 'tftp_service_port':
|
|
||||||
$tftpservice_port=$i[1];
|
|
||||||
break;
|
|
||||||
case 'tftp_service_file_path':
|
|
||||||
$tftpservice_file_path=$i[1];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// disconnect from database
|
|
||||||
unset($db);
|
|
||||||
// destroy data
|
|
||||||
unset($s);
|
|
||||||
|
|
||||||
// load required files
|
|
||||||
require_once 'resources/tftpservice.class.php';
|
|
||||||
|
|
||||||
// start service
|
|
||||||
$server = new tftpservice("udp://$tftpservice_address:$tftpservice_port", array("headless"=>true, "db_type"=>$db_type, "db_host"=>$db_host, "db_port"=>$db_port, "db_name"=>$db_name, "db_username"=>$db_username, "db_password"=>$db_password, "files_location"=>$tftpservice_file_path));
|
|
||||||
// signal running to service controller
|
|
||||||
win32_start_service_ctrl_dispatcher($appname);
|
|
||||||
win32_set_service_status(WIN32_SERVICE_RUNNING);
|
|
||||||
// execute run loop
|
|
||||||
if(!$server->loop($error, $user)) die("$error\n");
|
|
||||||
// signal stopped to service controller
|
|
||||||
win32_set_service_status(WIN32_SERVICE_STOPPED);
|
|
||||||
}
|
|
||||||
|
|
||||||
function Run()
|
|
||||||
{
|
|
||||||
global $appname;
|
|
||||||
global $appdesc;
|
|
||||||
global $pid;
|
|
||||||
global $pidfile;
|
|
||||||
global $tftpservice_address;
|
|
||||||
global $tftpservice_port;
|
|
||||||
global $tftpservice_file_path;
|
|
||||||
|
|
||||||
// check for existing process
|
|
||||||
if (file_exists($pidfile)) {
|
|
||||||
$pid = file_get_contents($pidfile);
|
|
||||||
if (is_numeric($pid)) {
|
|
||||||
if (strpos(PHP_OS,"WIN") !== false)
|
|
||||||
{
|
|
||||||
exec('tasklist -NH -FO TABLE -FI "PID eq '.$pid.'" 2>NUL', $data);
|
|
||||||
foreach($data as $line)
|
|
||||||
{
|
|
||||||
if (strpos($line,$pid) !== false) die($appdesc." already running with process id ".$pid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (file_exists('/proc/'.$pid)) die($appdesc." already running with process id".$pid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// write pid file
|
|
||||||
file_put_contents($pidfile, getmypid());
|
|
||||||
|
|
||||||
// load required files
|
|
||||||
require_once __DIR__.'/../../resources/config.php';
|
|
||||||
require_once 'resources/dbhelper.php';
|
|
||||||
|
|
||||||
// get service settings from database
|
|
||||||
// connect to database
|
|
||||||
$db = database::connect($db_type,$db_host,$db_port,$db_name,$db_username,$db_password);
|
|
||||||
// get settings
|
|
||||||
$s = database::get_table($db,'v_default_settings',array('default_setting_subcategory','default_setting_value'),array('default_setting_subcategory','LIKE','tftp_service_%'));
|
|
||||||
// set local variables
|
|
||||||
foreach ($s as $i) {
|
|
||||||
switch ($i[0]) {
|
|
||||||
case 'tftp_service_address':
|
|
||||||
$tftpservice_address=$i[1];
|
|
||||||
break;
|
|
||||||
case 'tftp_service_port':
|
|
||||||
$tftpservice_port=$i[1];
|
|
||||||
break;
|
|
||||||
case 'tftp_service_file_path':
|
|
||||||
$tftpservice_file_path=$i[1];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// disconnect from database
|
|
||||||
unset($db);
|
|
||||||
// destroy data
|
|
||||||
unset($s);
|
|
||||||
|
|
||||||
// load required files
|
|
||||||
require_once 'resources/tftpservice.class.php';
|
|
||||||
|
|
||||||
// start service
|
|
||||||
$server = new tftpservice("udp://$tftpservice_address:$tftpservice_port", array('db_type'=>$db_type,'db_host'=>$db_host, "db_port"=>$db_port, "db_name"=>$db_name, "db_username"=>$db_username, "db_password"=>$db_password, "files_location"=>$tftpservice_file_path));
|
|
||||||
echo $appdesc." has started.\n";
|
|
||||||
if(!$server->loop($error, $user)) die("$error\n");
|
|
||||||
echo $appdesc." has stopped.\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (php_sapi_name() === 'cli') {
|
|
||||||
if(isset($_SERVER["argv"][1])&&$_SERVER["argv"][1]=="--InstallService")
|
|
||||||
Service_Install(); // Install System Service
|
|
||||||
elseif(isset($_SERVER["argv"][1])&&$_SERVER["argv"][1]=="--UninstallService")
|
|
||||||
Service_Uninstall(); // Uninstall System Service
|
|
||||||
elseif(isset($_SERVER["argv"][1])&&$_SERVER["argv"][1]=="--Service")
|
|
||||||
Service_Run(); // Run as a Service
|
|
||||||
else
|
|
||||||
Run(); // Run
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
Loading…
Reference in New Issue