File: 1.13.3b/server/base/tests/ppping.inc.php (View as Code)

1: 2: /* ------------------------------------------------------------- 3: This file is part of PurplePixie Ping (PPPing) 4: 5: PPPing is (C) Copyright 2010 PurplePixie Systems 6: 7: PPPing is free software: you can redistribute it and/or modify 8: it under the terms of the GNU General Public License as published by 9: the Free Software Foundation, either version 3 of the License, or 10: (at your option) any later version. 11: 12: PPPing is distributed in the hope that it will be useful, 13: but WITHOUT ANY WARRANTY; without even the implied warranty of 14: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15: GNU General Public License for more details. 16: 17: You should have received a copy of the GNU General Public License 18: along with PPPing. If not, see www.gnu.org/licenses 19: 20: For more information see www.purplepixie.org/phpping 21: -------------------------------------------------------------- */ 22: 23: /** 24: * PPPing PHP Ping Utility 25: * @package PPPing PHP Ping Utility 26: * @author David Cutting 27: * @version 0.01 28: **/ 29: 30: /** 31: * Main PPPing Class 32: * @package PPPing PHP Ping Utility 33: **/ 34: class PPPing 35: { 36: /** 37: * Time-to-Live for IP Packet (DO NOT USE) 38: * 39: * -1 Uses system default (usually 64). Please note that this is currently 40: * not functional. 41: **/ 42: var $ttl=-1; 43: 44: /** 45: * Hostname to ping (resolvable host or IP address) 46: **/ 47: var $hostname=""; 48: 49: /** 50: * Identifier - will fill with random content (16 bits) 51: **/ 52: var $identity=0; 53: 54: /** 55: * Sequence number in decimal (16 bits) 56: **/ 57: var $sequence=0; 58: 59: /** 60: * Timeout in seconds - maximum wait for a response before timeout 61: **/ 62: var $timeout=10; 63: 64: /** 65: * Timer start seconds 66: **/ 67: var $timer_start_sec=0; 68: 69: /** 70: * Timer start mseconds 71: **/ 72: var $timer_start_msec=0; 73: 74: /** 75: * Data package for the ping 76: **/ 77: var $data_package = "PPPing"; 78: 79: /** 80: * Debug - prints output to the screen 81: **/ 82: var $debug=false; 83: 84: /** 85: * Holds information on last result 86: **/ 87: var $Last = array(); 88: 89: /** 90: * Clears last data 91: **/ 92: function clearLast() 93: { 94: $this->last = array( 95: "set" => false, 96: "result" => 0, 97: "ttl" => 0, 98: "hops" => 0, 99: "source" => "", 100: "destination" => "" ); 101: } 102: /** 103: * Get a padded hex identifier 104: **/ 105: function getIdentity() 106: { 107: if ( (is_numeric($this->identity)) && ($this->identity>=0) && ($this->identity<65535) ) 108: $id=$this->identity; 109: else $id=0; 110: 111: $id=dechex($id); 112: $id=str_pad($id,4,"0",STR_PAD_LEFT); 113: $id=pack("H*",$id); 114: 115: return $id; 116: } 117: 118: /** 119: * Get a padded hex sequence 120: **/ 121: function getSequence() 122: { 123: if ( (is_numeric($this->sequence)) && ($this->sequence>=0) && ($this->sequence<65535) ) 124: $seq=$this->sequence; 125: else $seq=0; 126: $seq=dechex($seq); 127: $seq=str_pad($seq,4,"0",STR_PAD_LEFT); 128: $seq=pack("H*",$seq); 129: 130: return $seq; 131: } 132: 133: /** 134: * Returns a hex string of the binary data for debug purposes 135: **/ 136: function getHex($data) 137: { 138: $parts=unpack("H*",$data); 139: return $parts[1]; 140: } 141: 142: /** 143: * Randomise identity and/or sequence within 16 bit parameters 144: **/ 145: function Randomise($identity=true,$sequence=false) 146: { 147: mt_srand(microtime()*1000000); 148: if ($identity) $this->identity=mt_rand(0,65534); 149: if ($sequence) $this->sequence=mt_rand(0,65534); 150: } 151: 152: /** 153: * Start timer (reset values) 154: **/ 155: function startTimer() 156: { 157: $now=microtime(); 158: $timearray=explode(" ",$now); 159: $this->timer_start_sec=$timearray[1]; 160: $this->timer_start_msec=$timearray[0]; 161: } 162: 163: /** 164: * Stop timer (return result) 165: **/ 166: function stopTimer() 167: { 168: $now=microtime(); 169: $timearray=explode(" ",$now); 170: 171: $finish_secs=$timearray[1]; 172: $finish_msecs=$timearray[0]; 173: 174: $elapsed_seconds = $finish_secs - $this->timer_start_sec; 175: $elapsed_time = $elapsed_seconds + $finish_msecs - $this->timer_start_msec; 176: 177: $elapsed_ms = $elapsed_time * 1000; 178: 179: $elapsed_ms = round($elapsed_ms,3); 180: 181: return $elapsed_ms; 182: } 183: 184: 185: /** 186: * Constructor - randomises ID 187: **/ 188: function PPPing() 189: { 190: $this->Randomise(); 191: } 192: 193: /** 194: * Returns a dotted quad from hex format IPv4 address 195: **/ 196: function ipAddress($hexip) 197: { 198: $quad=""; 199: for($a=0; $a<=6; $a+=2) 200: { 201: $portion=substr($hexip,$a,2); 202: $decimal=hexdec($portion); 203: if ($quad!="") $quad.="."; 204: $quad.=$decimal; 205: } 206: return $quad; 207: } 208: 209: /** 210: * Generate an ICMP checksum 211: **/ 212: function Checksum($data) 213: { 214: if (strlen($data)%2) 215: $data .= "\x00"; 216: 217: $bit = unpack('n*', $data); 218: $sum = array_sum($bit); 219: 220: while ($sum >> 16) 221: $sum = ($sum >> 16) + ($sum & 0xffff); 222: 223: return pack('n*', ~$sum); 224: } 225: 226: /** 227: * Do a ping of the set hostname 228: * 229: * @return float 230: * Returns a negative number of failure which can be turned into text with 231: * the strError method. A positive number is a response in milliseconds (ms) 232: **/ 233: function Ping() 234: { 235: $this->clearLast(); 236: $type = "\x08"; // icmp echo 237: $code = "\x00"; 238: $checksum = "\x00\x00"; // initial 239: $identifier = $this->getIdentity(); 240: $dec_identity = $this->identity; 241: //$identifier = "\x00\x00"; 242: //$seqNumber = "\x00\x00"; 243: $seqNumber = $this->getSequence(); 244: $dec_sequence = $this->sequence; 245: $data = $this->data_package; 246: $package = $type.$code.$checksum.$identifier.$seqNumber.$data; 247: $checksum = $this->Checksum($package); // proper checksum 248: $package = $type.$code.$checksum.$identifier.$seqNumber.$data; 249: 250: $ip_protocol_code = getprotobyname("ip"); 251: $ip_ttl_code = 7; 252: 253: // Lookup hostname 254: $ips=str_replace(".","",$this->hostname); 255: if (!is_numeric($ips)) 256: { 257: $host=gethostbyname($this->hostname); 258: if ($host==$this->hostname) return -5; 259: } 260: else $host=$this->hostname; 261: 262: // Create Socket 263: $socket = socket_create(AF_INET, SOCK_RAW, 1); // @ 264: //or die(socket_strerror(socket_last_error())); 265: if (!$socket) return -3; 266: 267: // Set Non-Blocking 268: socket_set_nonblock($socket); // @ 269: 270: $socket_ttl = socket_get_option($socket,$ip_protocol_code,$ip_ttl_code); 271: 272: //for ($a=0; $a<64; $a++) 273: // echo $a." - ".@socket_get_option($socket,$ip_protocol_code,$a)."\n"; 274: 275: if ($this->ttl>0) 276: { 277: socket_set_option($socket,$ip_protocol_code,$ip_ttl_code,128); 278: $socket_ttl = socket_get_option($socket,$ip_protocol_code,$ip_ttl_code); 279: //socket_set_option($socket,Socket::IPPROTO_IP,Socket::IP_TTL,128); 280: //$socket_ttl = socket_get_option($socket,Socket::IPPROTO_IP,Socket::IP_TTL); 281: 282: } 283: else $socket_ttl = 64; // standard TTL 284: 285: 286: // Connect Socket 287: $sconn=socket_connect($socket, $host, null); // @ 288: if (!$sconn) return 0; 289: 290: // Package Size 291: //$package_size = 8+strlen($data); 292: $package_size = strlen($package); 293: 294: // Send Data 295: socket_send($socket, $package, $package_size, 0); // @ 296: 297: // Start Timer 298: $this->startTimer(); 299: $startTime = microtime(true); // need this for the looping section 300: 301: 302: // Read Data 303: $keepon=true; 304: 305: while( (false===($echo_reply=socket_read($socket, 255))) && $keepon) // @socket_read 306: { 307: 308: if ( (microtime(true) - $startTime) > $this->timeout ) 309: $keepon=false; 310: 311: } 312: 313: 314: if ($keepon) // didn't time out - read data 315: { 316: $elapsed=$this->stopTimer(); 317: 318: socket_close($socket); // @ 319: 320: if ( $echo_reply === false ) return -4; 321: else if (strlen($echo_reply)<2) return -2; 322: 323: $rx_parts = unpack("C*",$echo_reply); 324: $tx_parts = unpack("C*",$package); 325: $ipheader=""; 326: $ipheader_hex=""; 327: 328: if ($rx_parts[1] == 0x45) // IP Header Information 329: { 330: $ipheader=substr($echo_reply,0,20); 331: $ipheader_hex = $this->getHex($ipheader); 332: $echo_reply=substr($echo_reply,20); 333: $rx_parts = unpack("C*",$echo_reply); 334: } 335: 336: if ($this->debug) 337: { 338: echo "\n"; 339: echo " TyCoChksIdenSequData\n"; 340: echo "TX: ".$this->getHex($package)."\n"; 341: echo "RX: ".$this->getHex($echo_reply)."\n"; 342: if ($ipheader!="") echo "HR: ".$ipheader_hex."\n"; 343: } 344: 345: $echo_reply_hex = $this->getHex($echo_reply); 346: $reply_type = $rx_parts[1]; 347: $reply_code = $rx_parts[2]; 348: $reply_identity = hexdec(substr($echo_reply_hex,8,4)); 349: $reply_sequence = hexdec(substr($echo_reply_hex,12,4)); 350: 351: $match=true; 352: if ($ipheader!="") 353: { 354: $source=substr($ipheader_hex,24,8); 355: $dest=substr($ipheader_hex,32,8); 356: $ttl=hexdec(substr($ipheader_hex,16,2)); 357: if ($this->debug) echo $this->ipAddress($source)." => ".$this->ipAddress($dest)." | ttl: ".$ttl."\n"; 358: if ($source==$dest) $match=true; 359: else $match=false; 360: 361: $this->last["set"]=true; 362: $this->last["source"]=$this->ipAddress($source); 363: $this->last["destination"]=$this->ipAddress($dest); 364: $this->last["ttl"]=$ttl; 365: $this->last["hops"]=$socket_ttl - $ttl; 366: 367: 368: } 369: 370: if ( (($rx_parts[1]==0) || (($rx_parts[1]==8)&&($match))) && ($rx_parts[2]==0) ) 371: { // is echo_reply (0) or is echo_request (8) AND match (from same host) 372: // and has code of 0 373: // valid response 374: if ($reply_identity != $dec_identity) return -8; // ID mismatch 375: else if ($reply_sequence != $dec_sequence) return -7; // sequence mismatch 376: else 377: { 378: $this->last["result"]=$elapsed; 379: return $elapsed; 380: } 381: } 382: else 383: { // ICMP Error 384: return -9; 385: } 386: 387: } 388: socket_close($socket); // @ 389: return -1; // timeout 390: } 391: 392: /** 393: * Returns textual error for code 394: **/ 395: function strError($code) 396: { 397: switch($code) 398: { 399: case -1: return "Timed Out"; break; 400: case -2: return "Reply Too Short"; break; 401: case -3: return "Failed to Open Socket"; break; 402: case -4: return "Invalid (false) Response"; break; 403: case -5: return "Hostname Lookup Failed"; break; 404: case -7: return "Sequence Mismatch"; break; 405: case -8: return "Identity Mismatch"; break; 406: case -9: return "ICMP Generic Error"; break; 407: 408: default: return "Unknown Error"; break; 409: } 410: } 411: 412: 413: } 414: 415: ?>