package com.netease.LDNetDiagnoService;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import android.util.Log;
/**
* 通过ping模拟traceroute过程
*
* @author panghui
*
*/
public class LDNetTraceRoute {
private final String LOG_TAG = "LDNetTraceRoute";
private static LDNetTraceRoute instance;
private LDNetTraceRoute() {
}
public static LDNetTraceRoute getInstance() {
if (instance == null) {
instance = new LDNetTraceRoute();
}
return instance;
}
LDNetTraceRouteListener listener;
public boolean isCTrace = true;
public void initListenter(LDNetTraceRouteListener listener) {
this.listener = listener;
}
/**
* 监控NetPing的日志输出到Service
*
* @author panghui
*
*/
public interface LDNetTraceRouteListener {
public void OnNetTraceUpdated(String log);
public void OnNetTraceFinished();
}
/**
* 执行指定host的traceroute
*
* @param host
* @return
*/
public void startTraceRoute(String host) {
if (isCTrace && loaded) {
try {
startJNICTraceRoute(host);
} catch (UnsatisfiedLinkError e) {
e.printStackTrace();
// 如果c调用失败改调JAVA代码
Log.i("LDNetTraceRoute", "调用java模拟traceRoute");
TraceTask trace = new TraceTask(host, 1);
execTrace(trace);
}
} else {
TraceTask trace = new TraceTask(host, 1);
execTrace(trace);
}
}
public void resetInstance() {
if (instance != null) {
instance = null;
}
}
/**
* 调用jni c函数执行traceroute过程
*/
public native void startJNICTraceRoute(String traceCommand);
static boolean loaded;
static {
try {
System.loadLibrary("tracepath");
loaded = true;
} catch (UnsatisfiedLinkError e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 供jni c函数回调
*
* @param log
*/
public void printTraceInfo(String log) {
// Log.i(LOG_TAG, log);
listener.OnNetTraceUpdated(log);
}
private static final String MATCH_TRACE_IP = "(?<=From )(?:[0-9]{1,3}\\.){3}[0-9]{1,3}";
private static final String MATCH_PING_IP = "(?<=from ).*(?=: icmp_seq=1 ttl=)";
private static final String MATCH_PING_TIME = "(?<=time=).*?ms";
/**
* 执行ping命令,返回ping命令的全部控制台输出
*
* @param ping
* @return
*/
private String execPing(PingTask ping) {
Process process = null;
String str = "";
BufferedReader reader = null;
try {
process = Runtime.getRuntime().exec("ping -c 1 " + ping.getHost());
reader = new BufferedReader(new InputStreamReader(
process.getInputStream()));
String line = null;
while ((line = reader.readLine()) != null) {
str += line;
}
reader.close();
process.waitFor();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
try {
if (reader != null) {
reader.close();
}
process.destroy();
} catch (Exception e) {
}
}
return str;
}
/**
* 通过ping命令模拟执行traceroute的过程
*
* @param trace
* @return
*/
private void execTrace(TraceTask trace) {
Pattern patternTrace = Pattern.compile(MATCH_TRACE_IP);
Pattern patternIp = Pattern.compile(MATCH_PING_IP);
Pattern patternTime = Pattern.compile(MATCH_PING_TIME);
Process process = null;
BufferedReader reader = null;
boolean finish = false;
try {
// 通过ping的跳数控制,取得相应跳输的ip地址,然后再次执行ping命令读取时间
while (!finish && trace.getHop() < 30) {
// 先发出ping命令获得某个跳数的ip地址
String str = "";
// -c 1 同时发送消息次数 -t是指跳数
String command = "ping -c 1 -t " + trace.getHop() + " "
+ trace.getHost();
process = Runtime.getRuntime().exec(command);
reader = new BufferedReader(new InputStreamReader(
process.getInputStream()));
String line = null;
while ((line = reader.readLine()) != null) {
str += line;
}
reader.close();
process.waitFor();
Matcher m = patternTrace.matcher(str);
// 如果成功获得trace:IP,则再次发送ping命令获取ping的时间
StringBuilder log = new StringBuilder(256);
if (m.find()) {
String pingIp = m.group();
PingTask pingTask = new PingTask(pingIp);
String status = execPing(pingTask);
if (status.length() == 0) {
log.append("unknown host or network error\n");
finish = true;
} else {
Matcher matcherTime = patternTime.matcher(status);
if (matcherTime.find()) {
String time = matcherTime.group();
log.append(trace.getHop());
log.append("\t\t");
log.append(pingIp);
log.append("\t\t");
log.append(time);
log.append("\t");
} else {
log.append(trace.getHop());
log.append("\t\t");
log.append(pingIp);
log.append("\t\t timeout \t");
}
listener.OnNetTraceUpdated(log.toString());
trace.setHop(trace.getHop() + 1);
}
}
// 否则:what
else {
Matcher matchPingIp = patternIp.matcher(str);
if (matchPingIp.find()) {
String pingIp = matchPingIp.group();
Matcher matcherTime = patternTime.matcher(str);
if (matcherTime.find()) {
String time = matcherTime.group();
log.append(trace.getHop());
log.append("\t\t");
log.append(pingIp);
log.append("\t\t");
log.append(time);
log.append("\t");
listener.OnNetTraceUpdated(log.toString());
}
finish = true;
} else {
if (str.length() == 0) {
log.append("unknown host or network error\t");
finish = true;
} else {
log.append(trace.getHop());
log.append("\t\t timeout \t");
trace.setHop(trace.getHop() + 1);
}
listener.OnNetTraceUpdated(log.toString());
}
}// else no match traceIPPattern
}// while
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
try {
if (reader != null) {
reader.close();
}
process.destroy();
} catch (Exception e) {
}
}
listener.OnNetTraceFinished();
}
/**
* Ping任务
*
* @author panghui
*
*/
private class PingTask {
private String host;
private static final String MATCH_PING_HOST_IP = "(?<=\\().*?(?=\\))";
public String getHost() {
return host;
}
public PingTask(String host) {
super();
this.host = host;
Pattern p = Pattern.compile(MATCH_PING_HOST_IP);
Matcher m = p.matcher(host);
if (m.find()) {
this.host = m.group();
}
}
}
/**
* 生成trace任务
*
* @author panghui
*
*/
private class TraceTask {
private final String host;
private int hop;
public TraceTask(String host, int hop) {
super();
this.host = host;
this.hop = hop;
}
public String getHost() {
return host;
}
public int getHop() {
return hop;
}
public void setHop(int hop) {
this.hop = hop;
}
}
}