https://wiki.uniformserver.com/index.php?title=US_Tray_Menu_2:_Defensive&feed=atom&action=historyUS Tray Menu 2: Defensive - Revision history2024-03-29T01:26:41ZRevision history for this page on the wikiMediaWiki 1.41.0https://wiki.uniformserver.com/index.php?title=US_Tray_Menu_2:_Defensive&diff=4260&oldid=prevRic: New page: {{Nav US Tray Menu 2}} '''''US Tray Menu 2 Defensive code''''' == Introduction == Our tray menu is dynamic providing real time user feedback. That said it is lacking a fundamental piece of...2010-06-27T13:39:34Z<p>New page: {{Nav US Tray Menu 2}} '''''US Tray Menu 2 Defensive code''''' == Introduction == Our tray menu is dynamic providing real time user feedback. That said it is lacking a fundamental piece of...</p>
<p><b>New page</b></p><div>{{Nav US Tray Menu 2}}<br />
'''''US Tray Menu 2 Defensive code'''''<br />
== Introduction ==<br />
Our tray menu is dynamic providing real time user feedback. That said it is lacking a fundamental piece of user information! Can the servers be run on a user’s machine?<br />
<br />
Although it is impossible to predict every eventuality any known issues that would prevent servers from running should be detected and a user informed accordingly.<br />
<br />
This to a certain extent is defensive programming, attempting to run servers in an unpredictable environment may cause undesirable side effects.<br />
<br />
It is of little use displaying an error number; if you have detected a cause provide useful feedback as to its remedy.<br />
<br />
== Initialisation checks ==<br />
Prior to starting servers it is worth considering the following pre-checks ideally you would implement all of them. <br />
<br />
=== Incorrect location ===<br />
Strange as it may seem the first thing to perform is a correct installation check.<br />
<br />
If extracted or copied to an incorrect location be draconian and refuse to start menu until corrective action is taken.<br />
<br />
'''''[[#top | Top]]'''''<br />
=== Spaces in paths ===<br />
Spaces in paths is a contentious issue, most modern programs will accept spaces however there are some useful legacy programs that will not. Uniform Serer imposes a restriction of no spaces in paths to folder UniServer. This allows any legacy code to be run in particular that used for some of its plugins.<br />
<br />
Ideally to gain a small increase in performance Uniform Server should be installed at a disk top-level. For development that is not always convenient generally Uniform Server is installed in sub-folders. This is where a space issue comes to light, silently check for spaces if detected inform user and terminate script.<br />
<br />
'''''Note'':'''<br />
<br />
The above two scenarios are probably the only time you need to be draconian and refuse to start menu. All other situations may be corrected or resolved using menu items; hence start it. It provides a user quick access to error logs and ability to edit files.<br />
<br />
'''''[[#top | Top]]'''''<br />
<br />
=== Ports in use ===<br />
A fresh extraction of Uniform Server standard Apache and MySQL ports are used. A user may change these either manually or by running the move server script. In any event we know what values have been set. To run servers these ports must be free.<br />
<br />
On detecting a port in use determine what is using it. Could be Skype, another server or even server that is performing the check. Inform user with information obtained.<br />
<br />
'''''Note'':''' Server detected is current server, no need to inform user. This scenario occurs when tray menu is closed without shutting down servers these remain running either as a program or service. <br />
<br />
'''''[[#top | Top]]'''''<br />
<br />
=== Passwords ===<br />
For a test server generally there is no need to set any passwords.<br />
<br />
That said we assume a user is going to use servers for production.<br />
It is important to set a MySQL password (default is root) hence at start-up nag user if it has not been changed.<br />
<br />
Servers may be used to host other users it is important to set a password for Apanel. Otherwise servers are open to cross-site scripting allowing a user to set server passwords. We have no way of knowing how the servers will be used hence again nag admin user to set a password for Apanel.<br />
<br />
Novice users may appreciate being nagged however this would drive me insane. Hence a configuration option to disable nagging would be a good idea especially for development.<br />
<br />
A user should change above passwords at the first opportunity. Well if you are going to nag, that’s the first opportunity, present user with an option to change password. <br />
<br />
If a user is going to ignore nagging and not change a password provide an option to disable nagging.<br />
<br />
'''''[[#top | Top]]'''''<br />
<br />
== Implementation ==<br />
I am not going to provide full code if you are interested it can be found in file UniServer\unicon\tray_menu_2\start_unitray.php.<br />
<br />
This section looks at code snippets.<br />
=== Port in use - Manual check ===<br />
To manually check a port in use type the following into a command prompt<br />
* '''netstat -anop TCP'''<br />
It displays something similar to this:<br />
<pre><br />
C:\>netstat -anop TCP<br />
Active Connections<br />
Proto Local Address Foreign Address State PID<br />
TCP 0.0.0.0:81 0.0.0.0:0 LISTENING 1068<br />
TCP 0.0.0.0:445 0.0.0.0:0 LISTENING 4<br />
TCP 0.0.0.0:3307 0.0.0.0:0 LISTENING 3212<br />
TCP 127.0.0.1:1029 0.0.0.0:0 LISTENING 2884<br />
TCP 127.0.0.1:1037 127.0.0.1:1038 ESTABLISHED 3708<br />
TCP 192.168.1.6:1122 243.252.232.123:80 CLOSE_WAIT 3708<br />
</pre><br />
* Scan down local address column for port number you are checking.<br />
* Example port 81 is displayed hence is in use.<br />
<br />
'''''Note'':'''<br />
<br />
To the right is the parent process PID (1068). This allows you to find parent process name.<br />
<br />
Open "Task Manager" scan down list locate pid (e.g 1068) to the left (Column Image Name) is the parent process name.<br />
<br />
'''''[[#top | Top]]'''''<br />
=== Port in use - Script ===<br />
Understanding mechanics of a manual process allows us to convert it to a script.<br />
* We want to run the command '''''netstat -anop tcp'''''<br />
* Capture the result into an array '''''$list'''''<br />
PHP function exec() is ideal for this, code as shown.<br />
<pre><br />
$cmd = 'netstat -anop tcp'; // Command<br />
exec($cmd,$list,$return); // Run cmd <br />
</pre><br />
You can of course use a single line I prefer two, its just coding style. <br />
<br />
==== PID's ====<br />
Process identifiers (PID’s) are by definition unique first process created is assigned zero. Significance of this, in the above list you will never see a zero PID. Hence it can be used as a valid return value signifying port not found (not in use).<br />
<br />
The following code:<br />
<pre><br />
function find_port_pid($port){<br />
<br />
$cmd = 'netstat -anop tcp'; // Command<br />
exec($cmd,$list,$return); // Run cmd <br />
<br />
foreach($list as $text){ // Scan array<br />
$pos = strpos($text, "TCP"); // Look for TCP<br />
if ($pos !== false) { // String found<br />
$text = trim($text); // Remove L&R spaces<br />
$text = preg_replace('/\s+/', ' ', $text); // Remove double spaces<br />
$str_array = explode(" ", $text); // Create narray line split <br />
$str_array2 = explode(":", $str_array[1]); // Create narray split to find portt <br />
if($str_array2[1] == $port){ // Is it our port<br />
return $str_array[4]; // Return pid<br />
}<br />
}<br />
}<br />
return 0 ; // Port not found return pid=0<br />
}<br />
</pre><br />
* Scans '''''$list''''' array looking for '''TCP''' these lines have a format of five columns<br />
* In preparation to blowing it apart each line has any excess white space removed <br />
* Line is blown apart at each space, creating an array '''''$str_array''''' of five elements corresponding to a column entry.<br />
* The second array element '''''$str_array[1]''''' is blown apart at character “''''':'''''” to create a new array '''''$str_array2''''' with two elements.<br />
* Second element '''''$str_array2[1]''''' of this array contains a port number. <br />
* This port number is compared to the port ('''$port''') we are checking<br />
* On finding a match its corresponding pid '''''$str_array[4]''''' is returned.<br />
* If no match found above process is repeated for next line in array.<br />
* If array is exhausted a '''''zero''''' pid is returned.<br />
<br />
'''''[[#top | Top]]'''''<br />
<br />
=== Port in use – Parent process ===<br />
Having discovered a process is using a port we wish to use we need to find name of the offending process.<br />
<br />
Code on the previous page provides a solution.<br />
<br />
This code is converted into a suitable function, pass it a PID and its corresponding process name is returned.<br />
<br />
Code shown below:<br />
<pre><br />
//=== PrintProcessNameAndID ===================================================<br />
// Used by functions:<br />
// is_process_running($proces_name)<br />
// get_process_using_pid($pid)<br />
<br />
function PrintProcessNameAndID( $processID ){<br />
global $process_list; // Array List of processes<br />
global $pid_process_array; // Lis of pis processes<br />
<br />
$szProcessName = "<unknown>";<br />
$szProcessName = str_pad($szProcessName, MAX_PATH, "\0");<br />
<br />
$hProcess = Kernel32::OpenProcess (PROCESS_QUERY_INFORMATION | <br />
PROCESS_VM_READ,<br />
false, $processID );<br />
<br />
if ( null != $hProcess ){<br />
$hMod = 0;<br />
$cbNeeded = 0;<br />
<br />
if (Psapi::EnumProcessModules( $hProcess, wb_get_address($hMod),<br />
\cStruct\HMODULE::sizeOf(), wb_get_address($cbNeeded) )){<br />
Psapi::GetModuleBaseName( $hProcess, $hMod, $szProcessName,<br />
strlen($szProcessName));<br />
}<br />
$szProcessName = \cStruct\rtrim($szProcessName);<br />
//echo "$szProcessName (PID: $processID)\n"; // Original<br />
$process_list[] = $szProcessName; // Create list of processes<br />
$pid_process_array[$processID] = $szProcessName; // Create list of keys(pids) processes<br />
}<br />
}<br />
//=============================================== END PrintProcessNameAndID ===<br />
<br />
//=== GET PROCESS USING PID ===================================================<br />
function get_process_using_pid($pid){;<br />
<br />
global $pid_process_array; // Array keys(pids) processes<br />
$pid_process_array = array(); <br />
<br />
$aProcesses = new PROCESS_ARRAY();<br />
$cbNeeded = 0;<br />
<br />
if (! Psapi::EnumProcesses( $aProcesses, $aProcesses->sizeOf(), wb_get_address($cbNeeded))){<br />
echo "Enum Processes failed";<br />
exit;<br />
}<br />
<br />
$cProcesses = $cbNeeded / \cStruct\DWORD::sizeOf(); // use DWORD in the cStruct namespace to get the size of<br />
<br />
for ($i = 0; $i < $cProcesses; $i++){<br />
if( $aProcesses->aProcesses[$i] != 0){<br />
PrintProcessNameAndID( $aProcesses->aProcesses[$i] ) ;<br />
}<br />
}<br />
<br />
//print_r($pid_process_array);<br />
<br />
return $pid_process_array[$pid]; // Return process name<br />
<br />
}// end ia_proges_running<br />
<br />
//=============================================== END GET PROCESS USING PID ===<br />
</pre><br />
<br />
'''''[[#top | Top]]'''''<br />
<br />
== Summary ==<br />
However due to a lack of interest for another plugin along with its continuing increase in size I decided to take the project to a more logical conclusion.<br />
<br />
On the introduction page I referred to a final twist!<br />
<br />
Remainder of this tutorial looks at integrating our new tray menu into Uniform Servers architecture. Next page covers [[US Tray Menu 2: Binaries | '''binaries''']]<br />
<br />
<br />
'''''[[#top | Top]]'''''<br />
<br />
----<br />
<br />
[[Category: Tutorials]]<br />
[[Category: How To]]<br />
[[Category: Uniform Server 5.0-Nano]]</div>Ric