File:
1.17.7a/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: ?>