download this file: class.icmp.php view text/plain: class.icmp.php file encoding: UTF-8 [goback]
<?php
##
## this file name is 'class.ping.php'
##
## ping object
##
## [author]
## - http://linuxchannel.net/
##
## [changes]
## - 2016.05.23 : add error_print()
## - 2016.01.06 : some
## - 2015.12.23 : more
## - 2008.12.01 : new build
##
## [references]
## - http://kr.php.net/manual/en/function.socket-create.php
##
## [usage]
##
## [example]
##
@error_reporting(E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED);
class icmp
{
public function make_socket($timeout = array('sec'=>0,'usec'=>500000))
{
if(!$sock = @socket_create(AF_INET, SOCK_RAW, getprotobyname('icmp')))
{
return array(-2, socket_last_error());
}
// do not set this options san2@2016.01.06
//@socket_set_option($sock,SOL_SOCKET,SO_RCVTIMEO,$timeout); // good idea for blocking mode
//@socket_set_option($sock,SOL_SOCKET,SO_SNDTIMEO,$timeout);
return $sock;
}
// timeout in (seconds, microtime)
public function ping($host, $sock=NULL, $timeout=array('sec'=>1,'usec'=>0))
{
static $_port = 0;
static $_datasize = 58; // default 58 bytes + 8 = 64 bytes
static $_timeout = array('sec'=>1, 'usec'=>0);
static $_select_timeout = 2;
if(!$timeout) $timeout = $_timeout;
$ident = array(ord('J'), ord('C'));
$seq = array(rand(0, 255), rand(0, 255));
//$seq = array(55,56);
## 8 bytes of ICMP header data
$packet = '';
$packet .= chr(8); // type = 8 : request
$packet .= chr(0); // code = 0
$packet .= chr(0); // checksum init
$packet .= chr(0); // checksum init
$packet .= chr($ident[0]); // identifier
$packet .= chr($ident[1]); // identifier
$packet .= chr($seq[0]); // seq
$packet .= chr($seq[1]); // seq
for($i=0; $i<$_datasize; $i++) $packet .= chr(0);
$chk = icmp::icmpchecksum($packet);
$packet[2] = $chk[0]; // checksum init
$packet[3] = $chk[1]; // checksum init
if(preg_match('/[a-z]/',$host)) $host = gethostbyname($host); // to ip
if(!$sock)
{
$sock = icmp::make_socket($timeout);
if(is_array($sock)) return $sock; // error
}
$_time = time(); // idle check initial
$read = array($sock);
$buf = '';
$time_start = microtime();
@socket_sendto($sock, $packet, strlen($packet), MSG_DONTWAIT, $host, $_port);
$time_send = microtime();
while(1)
{
if((time()-$_time) >= $_select_timeout)
{
return array(-1, "Timeout Response ${_select_timeout}s,".$isvalid[1]);
break;
}
$select = @socket_select($read, $write=NULL, $except=NULL, $timeout['sec'], $timeout['usec']);
//$errno = @socket_last_error();
//echo "$i $select $errno\n";
if($select === FALSE) continue;
if($select === NULL)
{
//@socket_close($sock);
return array(-1, 'Select Error.'.$isvalid[1]);
}
else if($select === 0)
{
//@socket_close($sock);
return array(-1, 'Timeout.'.$isvalid[1]);
}
$recv = socket_read($sock,1024);
$time_stop = microtime();
$recv = unpack('C*',$recv);
if(is_array($isvalid=icmp::is_valid_packet($recv,$ident,$seq))) continue;
break; // require
}
if(!$time_stop) $time_stop = microtime();
@socket_close($sock);
//echo "\n".implode(',',array_slice($recv,0,32))."\n";
//$ttt = icmp::getms($time_start, $time_send);
//$gtt = icmp::getms($time_send, $time_stop);
$rtt = icmp::getms($time_start, $time_stop);
return array($rtt);
}
private function is_valid_packet($recv, $ident, $seq)
{
if($recv[4] != 86) return array(-1,"Not Match packet, 86=>$recv[4], 1=>$recv[10], 0=>$recv[21]");
// ICMP proto = 1
if($recv[10] !== 1) return array(-1,"Not ICMP packet, 1=>$recv[10]");
// ICMP response = 0
if($recv[21] !== 0) return array(-1,"Not ICMP response, 0=>$recv[21]");
if($ident[0] !== $recv[25] || $ident[1] !== $recv[26]) return array(-1,"Bad identification number, $ident[0]=>$recv[25], $ident[1]=>$recv[26]");
if($seq[0] !== $recv[27] || $seq[1] !== $recv[28]) return array(-1,"Bad sequence number, $seq[0]=>$recv[27], $seq[1]=>$recv[28])");
return TRUE;
}
private function icmpchecksum($data)
{
$bit = unpack('n*', $data);
$sum = array_sum($bit);
if(strlen($data) % 2)
{
$temp = unpack('C*', $data[strlen($data) - 1]);
$sum += $temp[1];
}
$sum = ($sum >> 16) + ($sum & 0xffff);
$sum += ($sum >> 16);
return pack('n*', ~$sum);
}
public function getms($_start, $_end)
{
$end = explode(' ', $_end);
$start = explode(' ', $_start);
return sprintf('%.3f',(($end[1]+$end[0])-($start[1]+$start[0])) * 1000);
}
public function error($errstr)
{
return error_log($errstr,0);
}
public function error_print($errstr)
{
return fwrite(STDERR,rtrim($errstr)."\n");
}
public function socket_info($socket)
{
$opt = array
(
'SO_DEBUG'=>SO_DEBUG,
'SO_ACCEPTCONN'=>SO_ACCEPTCONN,
'SO_BROADCAST'=>SO_BROADCAST,
'SO_REUSEADDR'=>SO_REUSEADDR,
'SO_KEEPALIVE'=>SO_KEEPALIVE,
'SO_LINGER'=>SO_LINGER,
'SO_OOBINLINE'=>SO_OOBINLINE,
'SO_SNDBUF'=>SO_SNDBUF,
'SO_RCVBUF'=>SO_RCVBUF,
'SO_ERROR'=>SO_ERROR,
'SO_TYPE'=>SO_TYPE,
'SO_DONTROUTE'=>SO_DONTROUTE,
'SO_RCVLOWAT'=>SO_RCVLOWAT,
'SO_RCVTIMEO'=>SO_RCVTIMEO,
'SO_SNDLOWAT'=>SO_SNDLOWAT,
'SO_SNDTIMEO'=>SO_SNDTIMEO,
);
foreach ($opt as $k=>$value)
{
$r = socket_get_option($socket, SOL_SOCKET, $value);
echo "$k : \n";
print_r($r);
echo "\n";
}
}
} // end of class
?>