jni
This commit is contained in:
@@ -0,0 +1,97 @@
|
||||
package com.vnt;
|
||||
|
||||
import org.json.JSONObject;
|
||||
|
||||
/**
|
||||
* 注册结果
|
||||
*
|
||||
* 包含服务器分配的IP地址、掩码等信息
|
||||
* 注意:如果能创建此对象,说明注册一定成功了(失败会抛异常)
|
||||
*/
|
||||
public class RegisterResult {
|
||||
|
||||
private final String ip;
|
||||
private final int prefixLen;
|
||||
private final String gateway;
|
||||
private final String broadcast;
|
||||
|
||||
private RegisterResult(String ip, int prefixLen, String gateway, String broadcast) {
|
||||
this.ip = ip;
|
||||
this.prefixLen = prefixLen;
|
||||
this.gateway = gateway;
|
||||
this.broadcast = broadcast;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从JSON字符串解析注册结果
|
||||
* @throws VntException 如果注册失败或解析失败
|
||||
*/
|
||||
static RegisterResult fromJson(String json) throws VntException {
|
||||
try {
|
||||
JSONObject obj = new JSONObject(json);
|
||||
boolean success = obj.getBoolean("success");
|
||||
|
||||
if (success) {
|
||||
return new RegisterResult(
|
||||
obj.getString("ip"),
|
||||
obj.getInt("prefix_len"),
|
||||
obj.getString("gateway"),
|
||||
obj.getString("broadcast")
|
||||
);
|
||||
} else {
|
||||
// 注册失败,抛出异常
|
||||
String error = obj.getString("error");
|
||||
throw new VntException("Registration failed: " + error);
|
||||
}
|
||||
} catch (VntException e) {
|
||||
throw e; // 重新抛出VntException
|
||||
} catch (Exception e) {
|
||||
throw new VntException("Failed to parse register result: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取分配的IP地址
|
||||
*/
|
||||
public String getIp() {
|
||||
return ip;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取前缀长度(掩码位数)
|
||||
*/
|
||||
public int getPrefixLen() {
|
||||
return prefixLen;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取网关地址
|
||||
*/
|
||||
public String getGateway() {
|
||||
return gateway;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取广播地址
|
||||
*/
|
||||
public String getBroadcast() {
|
||||
return broadcast;
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换为CIDR格式字符串(例如:10.0.0.2/24)
|
||||
*/
|
||||
public String toCidr() {
|
||||
return ip + "/" + prefixLen;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "RegisterResult{" +
|
||||
"ip='" + ip + '\'' +
|
||||
", prefixLen=" + prefixLen +
|
||||
", gateway='" + gateway + '\'' +
|
||||
", broadcast='" + broadcast + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,428 @@
|
||||
package com.vnt;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* VNT API接口 - 用于查询网络状态和信息
|
||||
*
|
||||
* 通过VntNetwork.getApi()获取实例
|
||||
*/
|
||||
public class VntApi {
|
||||
|
||||
private final long nativeHandle;
|
||||
|
||||
// 包内构造,只能通过VntNetwork创建
|
||||
VntApi(long handle) {
|
||||
this.nativeHandle = handle;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取客户端列表
|
||||
* @return 客户端信息列表
|
||||
*/
|
||||
public List<ClientInfo> getClientList() throws VntException {
|
||||
try {
|
||||
String json = nativeGetClientList(nativeHandle);
|
||||
JSONArray array = new JSONArray(json);
|
||||
List<ClientInfo> clients = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < array.length(); i++) {
|
||||
JSONObject obj = array.getJSONObject(i);
|
||||
clients.add(new ClientInfo(
|
||||
obj.getString("ip"),
|
||||
obj.getBoolean("online")
|
||||
));
|
||||
}
|
||||
return clients;
|
||||
} catch (Exception e) {
|
||||
throw new VntException("Failed to get client list: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前网络配置
|
||||
* @return 网络信息,未连接返回null
|
||||
*/
|
||||
public NetworkInfo getNetwork() throws VntException {
|
||||
try {
|
||||
String json = nativeGetNetwork(nativeHandle);
|
||||
if ("null".equals(json)) {
|
||||
return null;
|
||||
}
|
||||
JSONObject obj = new JSONObject(json);
|
||||
return new NetworkInfo(
|
||||
obj.getString("ip"),
|
||||
obj.getInt("prefix_len"),
|
||||
obj.getString("gateway"),
|
||||
obj.getString("broadcast")
|
||||
);
|
||||
} catch (Exception e) {
|
||||
throw new VntException("Failed to get network info: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取本地NAT信息
|
||||
* @return NAT信息,未检测到返回null
|
||||
*/
|
||||
public NatInfo getNatInfo() throws VntException {
|
||||
try {
|
||||
String json = nativeGetNatInfo(nativeHandle);
|
||||
if ("null".equals(json)) {
|
||||
return null;
|
||||
}
|
||||
return NatInfo.fromJson(json);
|
||||
} catch (Exception e) {
|
||||
throw new VntException("Failed to get NAT info: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取服务器节点列表
|
||||
* @return 服务器信息列表
|
||||
*/
|
||||
public List<ServerInfo> getServerList() throws VntException {
|
||||
try {
|
||||
String json = nativeGetServerList(nativeHandle);
|
||||
JSONArray array = new JSONArray(json);
|
||||
List<ServerInfo> servers = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < array.length(); i++) {
|
||||
JSONObject obj = array.getJSONObject(i);
|
||||
servers.add(new ServerInfo(
|
||||
obj.getInt("server_id"),
|
||||
obj.getString("server_addr"),
|
||||
obj.getBoolean("connected"),
|
||||
obj.isNull("rtt") ? null : obj.getInt("rtt"),
|
||||
obj.getLong("data_version"),
|
||||
obj.isNull("server_version") ? null : obj.getString("server_version")
|
||||
));
|
||||
}
|
||||
return servers;
|
||||
} catch (Exception e) {
|
||||
throw new VntException("Failed to get server list: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取路由表
|
||||
* @return 路由信息列表
|
||||
*/
|
||||
public List<RouteInfo> getRouteTable() throws VntException {
|
||||
try {
|
||||
String json = nativeGetRouteTable(nativeHandle);
|
||||
JSONArray array = new JSONArray(json);
|
||||
List<RouteInfo> routes = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < array.length(); i++) {
|
||||
JSONObject obj = array.getJSONObject(i);
|
||||
String ip = obj.getString("ip");
|
||||
JSONArray routesArray = obj.getJSONArray("routes");
|
||||
|
||||
List<RouteDetail> details = new ArrayList<>();
|
||||
for (int j = 0; j < routesArray.length(); j++) {
|
||||
JSONObject route = routesArray.getJSONObject(j);
|
||||
details.add(new RouteDetail(
|
||||
route.getString("route_key"),
|
||||
route.getString("protocol"),
|
||||
route.getInt("metric"),
|
||||
route.getInt("rtt")
|
||||
));
|
||||
}
|
||||
routes.add(new RouteInfo(ip, details));
|
||||
}
|
||||
return routes;
|
||||
} catch (Exception e) {
|
||||
throw new VntException("Failed to get route table: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查目标IP是否直连(P2P)
|
||||
* @param ip 目标IP地址
|
||||
* @return true表示直连,false表示通过服务器中转
|
||||
*/
|
||||
public boolean isDirect(String ip) {
|
||||
return nativeIsDirect(nativeHandle, ip);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取对端NAT信息
|
||||
* @param ip 目标IP地址
|
||||
* @return NAT信息,未知返回null
|
||||
*/
|
||||
public NatInfo getPeerNatInfo(String ip) throws VntException {
|
||||
try {
|
||||
String json = nativeGetPeerNatInfo(nativeHandle, ip);
|
||||
if ("null".equals(json)) {
|
||||
return null;
|
||||
}
|
||||
return NatInfo.fromJson(json);
|
||||
} catch (Exception e) {
|
||||
throw new VntException("Failed to get peer NAT info: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取对端丢包信息
|
||||
* @param ip 目标IP地址
|
||||
* @return 丢包信息,未知返回null
|
||||
*/
|
||||
public PacketLossInfo getPacketLoss(String ip) throws VntException {
|
||||
try {
|
||||
String json = nativeGetPacketLoss(nativeHandle, ip);
|
||||
if ("null".equals(json)) {
|
||||
return null;
|
||||
}
|
||||
JSONObject obj = new JSONObject(json);
|
||||
return new PacketLossInfo(
|
||||
obj.getString("ip"),
|
||||
obj.getLong("sent"),
|
||||
obj.getLong("received"),
|
||||
obj.getDouble("loss_rate")
|
||||
);
|
||||
} catch (Exception e) {
|
||||
throw new VntException("Failed to get packet loss: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取对端流量统计
|
||||
* @param ip 目标IP地址
|
||||
* @return 流量信息,未知返回null
|
||||
*/
|
||||
public TrafficInfo getTrafficInfo(String ip) throws VntException {
|
||||
try {
|
||||
String json = nativeGetTrafficInfo(nativeHandle, ip);
|
||||
if ("null".equals(json)) {
|
||||
return null;
|
||||
}
|
||||
JSONObject obj = new JSONObject(json);
|
||||
return new TrafficInfo(
|
||||
obj.getString("ip"),
|
||||
obj.getLong("tx_bytes"),
|
||||
obj.getLong("rx_bytes")
|
||||
);
|
||||
} catch (Exception e) {
|
||||
throw new VntException("Failed to get traffic info: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
// ========== Native 方法 ==========
|
||||
|
||||
private static native String nativeGetClientList(long apiHandle);
|
||||
private static native String nativeGetNetwork(long apiHandle);
|
||||
private static native String nativeGetNatInfo(long apiHandle);
|
||||
private static native String nativeGetServerList(long apiHandle);
|
||||
private static native String nativeGetRouteTable(long apiHandle);
|
||||
private static native boolean nativeIsDirect(long apiHandle, String ip);
|
||||
private static native String nativeGetPeerNatInfo(long apiHandle, String ip);
|
||||
private static native String nativeGetPacketLoss(long apiHandle, String ip);
|
||||
private static native String nativeGetTrafficInfo(long apiHandle, String ip);
|
||||
|
||||
// ========== 数据类 ==========
|
||||
|
||||
public static class ClientInfo {
|
||||
private final String ip;
|
||||
private final boolean online;
|
||||
|
||||
public ClientInfo(String ip, boolean online) {
|
||||
this.ip = ip;
|
||||
this.online = online;
|
||||
}
|
||||
|
||||
public String getIp() { return ip; }
|
||||
public boolean isOnline() { return online; }
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ClientInfo{ip='" + ip + "', online=" + online + "}";
|
||||
}
|
||||
}
|
||||
|
||||
public static class NetworkInfo {
|
||||
private final String ip;
|
||||
private final int prefixLen;
|
||||
private final String gateway;
|
||||
private final String broadcast;
|
||||
|
||||
public NetworkInfo(String ip, int prefixLen, String gateway, String broadcast) {
|
||||
this.ip = ip;
|
||||
this.prefixLen = prefixLen;
|
||||
this.gateway = gateway;
|
||||
this.broadcast = broadcast;
|
||||
}
|
||||
|
||||
public String getIp() { return ip; }
|
||||
public int getPrefixLen() { return prefixLen; }
|
||||
public String getGateway() { return gateway; }
|
||||
public String getBroadcast() { return broadcast; }
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "NetworkInfo{ip='" + ip + "', prefixLen=" + prefixLen +
|
||||
", gateway='" + gateway + "', broadcast='" + broadcast + "'}";
|
||||
}
|
||||
}
|
||||
|
||||
public static class NatInfo {
|
||||
private final String natType;
|
||||
private final List<String> publicIps;
|
||||
private final String ipv6;
|
||||
|
||||
private NatInfo(String natType, List<String> publicIps, String ipv6) {
|
||||
this.natType = natType;
|
||||
this.publicIps = publicIps;
|
||||
this.ipv6 = ipv6;
|
||||
}
|
||||
|
||||
static NatInfo fromJson(String json) throws Exception {
|
||||
JSONObject obj = new JSONObject(json);
|
||||
JSONArray ipsArray = obj.getJSONArray("public_ips");
|
||||
List<String> publicIps = new ArrayList<>();
|
||||
for (int i = 0; i < ipsArray.length(); i++) {
|
||||
publicIps.add(ipsArray.getString(i));
|
||||
}
|
||||
return new NatInfo(
|
||||
obj.getString("nat_type"),
|
||||
publicIps,
|
||||
obj.isNull("ipv6") ? null : obj.getString("ipv6")
|
||||
);
|
||||
}
|
||||
|
||||
public String getNatType() { return natType; }
|
||||
public List<String> getPublicIps() { return publicIps; }
|
||||
public String getIpv6() { return ipv6; }
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "NatInfo{natType='" + natType + "', publicIps=" + publicIps +
|
||||
", ipv6='" + ipv6 + "'}";
|
||||
}
|
||||
}
|
||||
|
||||
public static class ServerInfo {
|
||||
private final int serverId;
|
||||
private final String serverAddr;
|
||||
private final boolean connected;
|
||||
private final Integer rtt;
|
||||
private final long dataVersion;
|
||||
private final String serverVersion;
|
||||
|
||||
public ServerInfo(int serverId, String serverAddr, boolean connected,
|
||||
Integer rtt, long dataVersion, String serverVersion) {
|
||||
this.serverId = serverId;
|
||||
this.serverAddr = serverAddr;
|
||||
this.connected = connected;
|
||||
this.rtt = rtt;
|
||||
this.dataVersion = dataVersion;
|
||||
this.serverVersion = serverVersion;
|
||||
}
|
||||
|
||||
public int getServerId() { return serverId; }
|
||||
public String getServerAddr() { return serverAddr; }
|
||||
public boolean isConnected() { return connected; }
|
||||
public Integer getRtt() { return rtt; }
|
||||
public long getDataVersion() { return dataVersion; }
|
||||
public String getServerVersion() { return serverVersion; }
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ServerInfo{serverId=" + serverId + ", serverAddr='" + serverAddr +
|
||||
"', connected=" + connected + ", rtt=" + rtt + "}";
|
||||
}
|
||||
}
|
||||
|
||||
public static class RouteInfo {
|
||||
private final String ip;
|
||||
private final List<RouteDetail> routes;
|
||||
|
||||
public RouteInfo(String ip, List<RouteDetail> routes) {
|
||||
this.ip = ip;
|
||||
this.routes = routes;
|
||||
}
|
||||
|
||||
public String getIp() { return ip; }
|
||||
public List<RouteDetail> getRoutes() { return routes; }
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "RouteInfo{ip='" + ip + "', routes=" + routes + "}";
|
||||
}
|
||||
}
|
||||
|
||||
public static class RouteDetail {
|
||||
private final String routeKey;
|
||||
private final String protocol;
|
||||
private final int metric;
|
||||
private final int rtt;
|
||||
|
||||
public RouteDetail(String routeKey, String protocol, int metric, int rtt) {
|
||||
this.routeKey = routeKey;
|
||||
this.protocol = protocol;
|
||||
this.metric = metric;
|
||||
this.rtt = rtt;
|
||||
}
|
||||
|
||||
public String getRouteKey() { return routeKey; }
|
||||
public String getProtocol() { return protocol; }
|
||||
public int getMetric() { return metric; }
|
||||
public int getRtt() { return rtt; }
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "RouteDetail{routeKey='" + routeKey + "', protocol='" + protocol +
|
||||
"', metric=" + metric + ", rtt=" + rtt + "}";
|
||||
}
|
||||
}
|
||||
|
||||
public static class PacketLossInfo {
|
||||
private final String ip;
|
||||
private final long sent;
|
||||
private final long received;
|
||||
private final double lossRate;
|
||||
|
||||
public PacketLossInfo(String ip, long sent, long received, double lossRate) {
|
||||
this.ip = ip;
|
||||
this.sent = sent;
|
||||
this.received = received;
|
||||
this.lossRate = lossRate;
|
||||
}
|
||||
|
||||
public String getIp() { return ip; }
|
||||
public long getSent() { return sent; }
|
||||
public long getReceived() { return received; }
|
||||
public double getLossRate() { return lossRate; }
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PacketLossInfo{ip='" + ip + "', sent=" + sent +
|
||||
", received=" + received + ", lossRate=" + lossRate + "}";
|
||||
}
|
||||
}
|
||||
|
||||
public static class TrafficInfo {
|
||||
private final String ip;
|
||||
private final long txBytes;
|
||||
private final long rxBytes;
|
||||
|
||||
public TrafficInfo(String ip, long txBytes, long rxBytes) {
|
||||
this.ip = ip;
|
||||
this.txBytes = txBytes;
|
||||
this.rxBytes = rxBytes;
|
||||
}
|
||||
|
||||
public String getIp() { return ip; }
|
||||
public long getTxBytes() { return txBytes; }
|
||||
public long getRxBytes() { return rxBytes; }
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TrafficInfo{ip='" + ip + "', txBytes=" + txBytes +
|
||||
", rxBytes=" + rxBytes + "}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,310 @@
|
||||
package com.vnt;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* VNT网络配置
|
||||
*
|
||||
* 使用Builder模式构建配置
|
||||
*/
|
||||
public class VntConfig {
|
||||
|
||||
private final List<String> servers;
|
||||
private final String networkCode;
|
||||
private final String password;
|
||||
private final String deviceId;
|
||||
private final String deviceName;
|
||||
private final String tunName;
|
||||
private final String ip;
|
||||
private final String certMode;
|
||||
private final boolean noPunch;
|
||||
private final boolean compress;
|
||||
private final boolean rtx;
|
||||
private final boolean fec;
|
||||
private final boolean noNat;
|
||||
private final boolean noTun;
|
||||
private final Integer mtu;
|
||||
private final boolean allowMapping;
|
||||
private final List<String> portMapping;
|
||||
private final List<String> udpStun;
|
||||
private final List<String> tcpStun;
|
||||
|
||||
private VntConfig(Builder builder) {
|
||||
this.servers = builder.servers;
|
||||
this.networkCode = builder.networkCode;
|
||||
this.password = builder.password;
|
||||
this.deviceId = builder.deviceId;
|
||||
this.deviceName = builder.deviceName;
|
||||
this.tunName = builder.tunName;
|
||||
this.ip = builder.ip;
|
||||
this.certMode = builder.certMode;
|
||||
this.noPunch = builder.noPunch;
|
||||
this.compress = builder.compress;
|
||||
this.rtx = builder.rtx;
|
||||
this.fec = builder.fec;
|
||||
this.noNat = builder.noNat;
|
||||
this.noTun = builder.noTun;
|
||||
this.mtu = builder.mtu;
|
||||
this.allowMapping = builder.allowMapping;
|
||||
this.portMapping = builder.portMapping;
|
||||
this.udpStun = builder.udpStun;
|
||||
this.tcpStun = builder.tcpStun;
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换为JSON字符串
|
||||
*/
|
||||
String toJson() {
|
||||
JSONObject json = new JSONObject();
|
||||
|
||||
// 必填项
|
||||
JSONArray serverArray = new JSONArray();
|
||||
for (String server : servers) {
|
||||
serverArray.put(server);
|
||||
}
|
||||
json.put("server", serverArray);
|
||||
json.put("network_code", networkCode);
|
||||
|
||||
// 可选项
|
||||
if (password != null) json.put("password", password);
|
||||
if (deviceId != null) json.put("device_id", deviceId);
|
||||
if (deviceName != null) json.put("device_name", deviceName);
|
||||
if (tunName != null) json.put("tun_name", tunName);
|
||||
if (ip != null) json.put("ip", ip);
|
||||
if (certMode != null) json.put("cert_mode", certMode);
|
||||
if (mtu != null) json.put("mtu", mtu);
|
||||
|
||||
// 布尔值
|
||||
json.put("no_punch", noPunch);
|
||||
json.put("compress", compress);
|
||||
json.put("rtx", rtx);
|
||||
json.put("fec", fec);
|
||||
json.put("no_nat", noNat);
|
||||
json.put("no_tun", noTun);
|
||||
json.put("allow_mapping", allowMapping);
|
||||
|
||||
// 数组
|
||||
if (!portMapping.isEmpty()) {
|
||||
JSONArray mappingArray = new JSONArray();
|
||||
for (String mapping : portMapping) {
|
||||
mappingArray.put(mapping);
|
||||
}
|
||||
json.put("port_mapping", mappingArray);
|
||||
}
|
||||
|
||||
if (!udpStun.isEmpty()) {
|
||||
JSONArray stunArray = new JSONArray();
|
||||
for (String stun : udpStun) {
|
||||
stunArray.put(stun);
|
||||
}
|
||||
json.put("udp_stun", stunArray);
|
||||
}
|
||||
|
||||
if (!tcpStun.isEmpty()) {
|
||||
JSONArray stunArray = new JSONArray();
|
||||
for (String stun : tcpStun) {
|
||||
stunArray.put(stun);
|
||||
}
|
||||
json.put("tcp_stun", stunArray);
|
||||
}
|
||||
|
||||
return json.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 配置构建器
|
||||
*/
|
||||
public static class Builder {
|
||||
private List<String> servers = new ArrayList<>();
|
||||
private String networkCode;
|
||||
private String password;
|
||||
private String deviceId;
|
||||
private String deviceName;
|
||||
private String tunName;
|
||||
private String ip;
|
||||
private String certMode;
|
||||
private boolean noPunch = false;
|
||||
private boolean compress = false;
|
||||
private boolean rtx = false;
|
||||
private boolean fec = false;
|
||||
private boolean noNat = false;
|
||||
private boolean noTun = false;
|
||||
private Integer mtu;
|
||||
private boolean allowMapping = false;
|
||||
private List<String> portMapping = new ArrayList<>();
|
||||
private List<String> udpStun = new ArrayList<>();
|
||||
private List<String> tcpStun = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* 添加服务器地址(必填)
|
||||
* @param server 服务器地址,格式:tcp://host:port 或 wss://host:port
|
||||
*/
|
||||
public Builder addServer(String server) {
|
||||
this.servers.add(server);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置网络代码(必填)
|
||||
* @param networkCode 组网代码
|
||||
*/
|
||||
public Builder setNetworkCode(String networkCode) {
|
||||
this.networkCode = networkCode;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置密码(可选)
|
||||
*/
|
||||
public Builder setPassword(String password) {
|
||||
this.password = password;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置设备ID(可选,默认自动生成)
|
||||
*/
|
||||
public Builder setDeviceId(String deviceId) {
|
||||
this.deviceId = deviceId;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置设备名称(可选)
|
||||
*/
|
||||
public Builder setDeviceName(String deviceName) {
|
||||
this.deviceName = deviceName;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置TUN设备名称(可选)
|
||||
*/
|
||||
public Builder setTunName(String tunName) {
|
||||
this.tunName = tunName;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置固定IP(可选)
|
||||
*/
|
||||
public Builder setIp(String ip) {
|
||||
this.ip = ip;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置证书验证模式(可选)
|
||||
* @param certMode "insecure" | "system" | "embedded"
|
||||
*/
|
||||
public Builder setCertMode(String certMode) {
|
||||
this.certMode = certMode;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 禁用打洞(默认false)
|
||||
*/
|
||||
public Builder setNoPunch(boolean noPunch) {
|
||||
this.noPunch = noPunch;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 启用压缩(默认false)
|
||||
*/
|
||||
public Builder setCompress(boolean compress) {
|
||||
this.compress = compress;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 启用QUIC重传(默认false)
|
||||
*/
|
||||
public Builder setRtx(boolean rtx) {
|
||||
this.rtx = rtx;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 启用FEC冗余传输(默认false)
|
||||
*/
|
||||
public Builder setFec(boolean fec) {
|
||||
this.fec = fec;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 禁用NAT(默认false)
|
||||
*/
|
||||
public Builder setNoNat(boolean noNat) {
|
||||
this.noNat = noNat;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 无TUN模式(默认false)
|
||||
*/
|
||||
public Builder setNoTun(boolean noTun) {
|
||||
this.noTun = noTun;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置MTU(可选,默认1380)
|
||||
*/
|
||||
public Builder setMtu(int mtu) {
|
||||
this.mtu = mtu;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 允许端口映射(默认false)
|
||||
*/
|
||||
public Builder setAllowMapping(boolean allowMapping) {
|
||||
this.allowMapping = allowMapping;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加端口映射规则(可选)
|
||||
* @param mapping 格式:tcp:80->192.168.1.100:8080
|
||||
*/
|
||||
public Builder addPortMapping(String mapping) {
|
||||
this.portMapping.add(mapping);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加UDP STUN服务器(可选)
|
||||
*/
|
||||
public Builder addUdpStun(String stun) {
|
||||
this.udpStun.add(stun);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加TCP STUN服务器(可选)
|
||||
*/
|
||||
public Builder addTcpStun(String stun) {
|
||||
this.tcpStun.add(stun);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建配置对象
|
||||
*/
|
||||
public VntConfig build() {
|
||||
if (servers.isEmpty()) {
|
||||
throw new IllegalArgumentException("At least one server must be specified");
|
||||
}
|
||||
if (networkCode == null || networkCode.isEmpty()) {
|
||||
throw new IllegalArgumentException("Network code must be specified");
|
||||
}
|
||||
return new VntConfig(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.vnt;
|
||||
|
||||
/**
|
||||
* VNT异常
|
||||
*
|
||||
* VNT操作失败时抛出的异常
|
||||
*/
|
||||
public class VntException extends Exception {
|
||||
|
||||
public VntException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public VntException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public VntException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package com.vnt;
|
||||
|
||||
/**
|
||||
* VNT网络管理器 - 主入口类
|
||||
*
|
||||
* 使用示例:
|
||||
* 1. 初始化: VntManager.init()
|
||||
* 2. 创建网络: VntNetwork network = VntManager.createNetwork(config)
|
||||
* 3. 注册: RegisterResult result = network.register()
|
||||
* 4. (Android端用result的IP/掩码创建VPN接口,获取tunFd)
|
||||
* 5. 启动TUN: network.startTun(tunFd)
|
||||
* 6. 获取API: VntApi api = network.getApi()
|
||||
* 7. 关闭: network.stop()
|
||||
*/
|
||||
public class VntManager {
|
||||
|
||||
static {
|
||||
// 加载JNI库
|
||||
System.loadLibrary("vnt_jni");
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化VNT模块(全局初始化,只需调用一次)
|
||||
* @return true表示成功,false表示失败
|
||||
*/
|
||||
public static boolean init() {
|
||||
return nativeInit();
|
||||
}
|
||||
|
||||
/**
|
||||
* 销毁VNT模块(全局清理)
|
||||
*/
|
||||
public static void destroy() {
|
||||
nativeDestroy();
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建网络实例
|
||||
* @param config 网络配置对象
|
||||
* @return VntNetwork实例,失败返回null
|
||||
*/
|
||||
public static VntNetwork createNetwork(VntConfig config) {
|
||||
String configJson = config.toJson();
|
||||
long handle = nativeCreateNetwork(configJson);
|
||||
if (handle < 0) {
|
||||
return null;
|
||||
}
|
||||
return new VntNetwork(handle);
|
||||
}
|
||||
|
||||
// ========== Native 方法 ==========
|
||||
|
||||
private static native boolean nativeInit();
|
||||
private static native void nativeDestroy();
|
||||
private static native long nativeCreateNetwork(String configJson);
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
package com.vnt;
|
||||
|
||||
/**
|
||||
* VNT网络实例
|
||||
*
|
||||
* 代表一个VNT网络连接,持有native资源
|
||||
*/
|
||||
public class VntNetwork {
|
||||
|
||||
private long nativeHandle;
|
||||
private boolean closed = false;
|
||||
|
||||
// 包内构造,只能通过VntManager创建
|
||||
VntNetwork(long handle) {
|
||||
this.nativeHandle = handle;
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册网络(连接服务器)
|
||||
* @return 注册结果,包含分配的IP、掩码等信息
|
||||
* @throws VntException 注册失败时抛出异常
|
||||
*/
|
||||
public RegisterResult register() throws VntException {
|
||||
checkClosed();
|
||||
String resultJson = nativeRegister(nativeHandle);
|
||||
return RegisterResult.fromJson(resultJson);
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动TUN设备
|
||||
* @param tunFd TUN设备文件描述符(Android VpnService.Builder.establish()返回的fd)
|
||||
* 传入-1表示让VNT自动创建(仅非Android平台支持)
|
||||
* @throws VntException 启动失败时抛出异常
|
||||
*/
|
||||
public void startTun(int tunFd) throws VntException {
|
||||
checkClosed();
|
||||
if (!nativeStartTun(nativeHandle, tunFd)) {
|
||||
throw new VntException("Failed to start TUN device");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置网络IP(仅非Android平台使用)
|
||||
* @param ip IP地址
|
||||
* @param prefixLen 前缀长度
|
||||
* @throws VntException 设置失败时抛出异常
|
||||
*/
|
||||
public void setNetworkIp(String ip, int prefixLen) throws VntException {
|
||||
checkClosed();
|
||||
if (!nativeSetNetworkIp(nativeHandle, ip, prefixLen)) {
|
||||
throw new VntException("Failed to set network IP");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取VNT API实例
|
||||
* @return VntApi实例
|
||||
* @throws VntException 获取失败时抛出异常
|
||||
*/
|
||||
public VntApi getApi() throws VntException {
|
||||
checkClosed();
|
||||
long apiHandle = nativeGetApi(nativeHandle);
|
||||
if (apiHandle < 0) {
|
||||
throw new VntException("Failed to get VntApi");
|
||||
}
|
||||
return new VntApi(apiHandle);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否为无TUN模式
|
||||
* @return true表示无TUN模式
|
||||
*/
|
||||
public boolean isNoTun() {
|
||||
checkClosed();
|
||||
return nativeIsNoTun(nativeHandle);
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止并关闭网络
|
||||
*/
|
||||
public void stop() {
|
||||
if (closed) {
|
||||
return;
|
||||
}
|
||||
nativeStop(nativeHandle);
|
||||
closed = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取native句柄(供内部使用)
|
||||
*/
|
||||
long getNativeHandle() {
|
||||
return nativeHandle;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否已关闭
|
||||
*/
|
||||
private void checkClosed() {
|
||||
if (closed) {
|
||||
throw new IllegalStateException("VntNetwork has been closed");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
try {
|
||||
stop();
|
||||
} finally {
|
||||
super.finalize();
|
||||
}
|
||||
}
|
||||
|
||||
// ========== Native 方法 ==========
|
||||
|
||||
private static native String nativeRegister(long handle);
|
||||
private static native boolean nativeStartTun(long handle, int tunFd);
|
||||
private static native boolean nativeSetNetworkIp(long handle, String ip, int prefixLen);
|
||||
private static native long nativeGetApi(long handle);
|
||||
private static native boolean nativeIsNoTun(long handle);
|
||||
private static native boolean nativeStop(long handle);
|
||||
}
|
||||
Reference in New Issue
Block a user