[mio] 适配新版vnt,增加jni java端代码

This commit is contained in:
lubeilin
2024-02-29 22:29:39 +08:00
parent ceadadee68
commit 8d7eb5ba1b
18 changed files with 1208 additions and 412 deletions
+4
View File
@@ -8,7 +8,11 @@ edition = "2021"
[dependencies]
common = { path = "../common" }
vnt = {path="../vnt"}
parking_lot = "0.12.1"
jni = { version = "0.21.1", default-features = false }
log = "0.4.20"
spki = { version = "0.7.2", features = ["fingerprint", "alloc","base64","pem"]}
[lib]
crate-type = ["staticlib", "cdylib"]
@@ -0,0 +1,53 @@
package top.wherewego.vnt.jni;
import top.wherewego.vnt.jni.param.*;
/**
* 回调
*
* @author https://github.com/lbl8603/vnt
*/
public interface CallBack {
/**
* 创建虚拟网卡成功的回调方法
*
* @param info 网卡信息
*/
void createTun(DeviceInfo info);
/**
* 连接服务端
*
* @param info 将要连接的服务端信息
*/
void connect(ConnectInfo info);
/**
* 和服务端握手
*
* @param info 握手信息
* @return 是否确认握手
*/
boolean handshake(HandshakeInfo info);
/**
* 注册成功回调
*
* @param info 注册信息
* @return 是否确认注册信息
*/
boolean register(RegisterInfo info);
/**
* 异常回调
*
* @param info 错误信息
*/
void error(ErrorInfo info);
/**
* 服务停止
*/
void stop();
}
@@ -0,0 +1,264 @@
package top.wherewego.vnt.jni;
/**
* 启动配置
*
* @author https://github.com/lbl8603/vnt
*/
public class Config {
/**
* 是否是tap模式,仅支持windows和linux
*/
private boolean tap;
/**
* 组网标识
*/
private String token;
/**
* 设备名称
*/
private String name;
/**
* 客户端间加密的密码
*/
private String password;
/**
* 客户端间加密模式 aes_gcm/aes_cbc/aes_ecb/sm4_cbc
*/
private String cipherModel;
/**
* 打洞模式 ipv4/ipv6/all
*/
private String punchModel;
/**
* mtu 默认自动计算
*/
private Integer mtu;
/**
* 是否开启服务端加密
*/
private boolean serverEncrypt;
/**
* 仅使用中继转发
*/
private boolean relay;
/**
* 设备id,请使用唯一值
*/
private String deviceId;
/**
* 服务端地址
*/
private String server;
/**
* stun服务地址
*/
private String[] stunServer;
/**
* 和服务端使用tcp通信,默认使用udp
*/
private boolean tcp;
/**
* 指定组网IP
*/
private String ip;
/**
* 开启加密指纹校验
*/
private boolean finger;
/**
* 延迟优先,默认p2p优先
*/
private boolean firstLatency;
/**
* 点对网入口 格式 192.168.0.0/26,10.26.0.2
*/
private String[] inIps;
/**
* 点对网出口 格式 192.168.0.0/26
*/
private String[] outIps;
/**
* 端口组,udp会监听一组端口,tcp监听ports[0]端口
*/
private int[] ports;
/**
* 虚拟网卡名称 仅在linux、windows、macos上支持
*/
private String deviceName;
/**
* 虚拟网卡fd 仅在android上支持
*/
private int deviceFd;
public Config() {
}
public boolean isTap() {
return tap;
}
public void setTap(boolean tap) {
this.tap = tap;
}
public String getToken() {
return token;
}
public void setToken(String token) {
this.token = token;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getCipherModel() {
return cipherModel;
}
public void setCipherModel(String cipherModel) {
this.cipherModel = cipherModel;
}
public String getPunchModel() {
return punchModel;
}
public void setPunchModel(String punchModel) {
this.punchModel = punchModel;
}
public Integer getMtu() {
return mtu;
}
public void setMtu(Integer mtu) {
this.mtu = mtu;
}
public boolean isServerEncrypt() {
return serverEncrypt;
}
public void setServerEncrypt(boolean serverEncrypt) {
this.serverEncrypt = serverEncrypt;
}
public boolean isRelay() {
return relay;
}
public void setRelay(boolean relay) {
this.relay = relay;
}
public String getDeviceId() {
return deviceId;
}
public void setDeviceId(String deviceId) {
this.deviceId = deviceId;
}
public String getServer() {
return server;
}
public void setServer(String server) {
this.server = server;
}
public String[] getStunServer() {
return stunServer;
}
public void setStunServer(String[] stunServer) {
this.stunServer = stunServer;
}
public boolean isTcp() {
return tcp;
}
public void setTcp(boolean tcp) {
this.tcp = tcp;
}
public String getIp() {
return ip;
}
public void setIp(String ip) {
this.ip = ip;
}
public boolean isFinger() {
return finger;
}
public void setFinger(boolean finger) {
this.finger = finger;
}
public boolean isFirstLatency() {
return firstLatency;
}
public void setFirstLatency(boolean firstLatency) {
this.firstLatency = firstLatency;
}
public String[] getInIps() {
return inIps;
}
public void setInIps(String[] inIps) {
this.inIps = inIps;
}
public String[] getOutIps() {
return outIps;
}
public void setOutIps(String[] outIps) {
this.outIps = outIps;
}
public int[] getPorts() {
return ports;
}
public void setPorts(int[] ports) {
this.ports = ports;
}
public String getDeviceName() {
return deviceName;
}
public void setDeviceName(String deviceName) {
this.deviceName = deviceName;
}
public int getDeviceFd() {
return deviceFd;
}
public void setDeviceFd(int deviceFd) {
this.deviceFd = deviceFd;
}
}
@@ -0,0 +1,29 @@
package top.wherewego.vnt.jni;
/**
* @author lubeilin
* @date: 2024/02/27 18:31
*/
public class IpUtils {
public static String intToIpAddress(int ipAddress) {
return ((ipAddress & 0xFF000000) >>> 24) + "." +
((ipAddress & 0x00FF0000) >>> 16) + "." +
((ipAddress & 0x0000FF00) >>> 8) + "." +
(ipAddress & 0x000000FF);
}
public static int subnetMaskToPrefixLength(int subnetMask) {
int prefixLength = 0;
int bit = 1 << 31;
while (subnetMask != 0) {
if ((subnetMask & bit) != bit) {
break;
}
prefixLength++;
subnetMask <<= 1;
}
return prefixLength;
}
}
@@ -0,0 +1,46 @@
package top.wherewego.vnt.jni;
/**
* 对端设备信息
*
* @author https://github.com/lbl8603/vnt
*/
public class PeerDeviceInfo {
private final int virtualIp;
private final String name;
private final String status;
private final Route route;
public PeerDeviceInfo(int virtualIp, String name, String status, Route route) {
this.virtualIp = virtualIp;
this.name = name;
this.status = status;
this.route = route;
}
public int getVirtualIp() {
return virtualIp;
}
public String getName() {
return name;
}
public String getStatus() {
return status;
}
public Route getRoute() {
return route;
}
@Override
public String toString() {
return "PeerDeviceInfo{" +
"virtualIp=" + IpUtils.intToIpAddress(virtualIp) +
", name='" + name + '\'' +
", status='" + status + '\'' +
", route=" + route +
'}';
}
}
@@ -0,0 +1,39 @@
package top.wherewego.vnt.jni;
/**
* 路由信息
*
* @author https://github.com/lbl8603/vnt
*/
public class Route {
private final String address;
private final byte metric;
private final int rt;
public Route(String address, byte metric, int rt) {
this.address = address;
this.metric = metric;
this.rt = rt;
}
public String getAddress() {
return address;
}
public byte getMetric() {
return metric;
}
public int getRt() {
return rt;
}
@Override
public String toString() {
return "Route{" +
"address='" + address + '\'' +
", metric=" + metric +
", rt=" + rt +
'}';
}
}
@@ -0,0 +1,47 @@
package top.wherewego.vnt.jni;
import java.io.Closeable;
import java.io.IOException;
/**
* vnt的Java映射
*
* @author https://github.com/lbl8603/vnt
*/
public class Vnt implements Closeable {
private final long raw;
public Vnt(Config config, CallBack callBack) {
this.raw = new0(config, callBack);
if(this.raw == 0){
throw new RuntimeException();
}
}
public void stop() {
stop0(raw);
}
public void await() {
wait0(raw);
}
public PeerDeviceInfo[] list() {
return list0(raw);
}
private native long new0(Config config, CallBack callBack);
private native void stop0(long raw);
private native void wait0(long raw);
private native void drop0(long raw);
private native PeerDeviceInfo[] list0(long raw);
@Override
public void close() throws IOException {
drop0(raw);
}
}
@@ -0,0 +1,32 @@
package top.wherewego.vnt.jni.param;
/**
* 连接信息
*
* @author https://github.com/lbl8603/vnt
*/
public class ConnectInfo {
private final long count;
private final String address;
public ConnectInfo(long count, String address) {
this.count = count;
this.address = address;
}
public long getCount() {
return count;
}
public String getAddress() {
return address;
}
@Override
public String toString() {
return "ConnectInfo{" +
"count=" + count +
", address='" + address + '\'' +
'}';
}
}
@@ -0,0 +1,38 @@
package top.wherewego.vnt.jni.param;
/**
* 网卡信息
*
* @author https://github.com/lbl8603/vnt
*/
public class DeviceInfo {
/**
* 虚拟网卡名称
*/
private final String name;
/**
* 虚拟网卡版本
*/
private final String version;
public DeviceInfo(String name, String version) {
this.name = name;
this.version = version;
}
public String getName() {
return name;
}
public String getVersion() {
return version;
}
@Override
public String toString() {
return "DeviceInfo{" +
"name='" + name + '\'' +
", version='" + version + '\'' +
'}';
}
}
@@ -0,0 +1,55 @@
package top.wherewego.vnt.jni.param;
/**
* 异常回调信息
*
* @author https://github.com/lbl8603/vnt
*/
public class ErrorInfo {
/**
* 错误码
*/
public final ErrorCodeEnum code;
/**
* 错误信息,可能为空
*/
public final String msg;
public ErrorInfo(int code, String msg) {
this.code = switch (code) {
case 1 -> ErrorCodeEnum.TokenError;
case 2 -> ErrorCodeEnum.Disconnect;
case 3 -> ErrorCodeEnum.AddressExhausted;
case 4 -> ErrorCodeEnum.IpAlreadyExists;
case 5 -> ErrorCodeEnum.InvalidIp;
case 6 -> ErrorCodeEnum.Unknown;
default -> null;
};
this.msg = msg;
}
public ErrorCodeEnum getCode() {
return code;
}
public String getMsg() {
return msg;
}
public enum ErrorCodeEnum {
TokenError,
Disconnect,
AddressExhausted,
IpAlreadyExists,
InvalidIp,
Unknown,
}
@Override
public String toString() {
return "ErrorInfo{" +
"code=" + code +
", msg='" + msg + '\'' +
'}';
}
}
@@ -0,0 +1,54 @@
package top.wherewego.vnt.jni.param;
/**
* 握手回调信息
*
* @author https://github.com/lbl8603/vnt
*/
public class HandshakeInfo {
/**
* 公钥 pem格式 CRLF分隔,不加密时为空
*/
private final String publicKey;
/**
* 公钥签名,不加密时为空
*/
private final String finger;
/**
* 服务端版本
*/
private final String version;
public HandshakeInfo() {
this.publicKey = "publicKey";
this.finger = "finger";
this.version = "version";
}
public HandshakeInfo(String publicKey, String finger, String version) {
this.publicKey = publicKey;
this.finger = finger;
this.version = version;
}
public String getPublicKey() {
return publicKey;
}
public String getFinger() {
return finger;
}
public String getVersion() {
return version;
}
@Override
public String toString() {
return "HandshakeInfo{" +
"publicKey='" + publicKey + '\'' +
", finger='" + finger + '\'' +
", version='" + version + '\'' +
'}';
}
}
@@ -0,0 +1,48 @@
package top.wherewego.vnt.jni.param;
/**
* 注册回调信息
*
* @author https://github.com/lbl8603/vnt
*/
public class RegisterInfo {
/**
* 虚拟IP
*/
public final String virtualIp;
/**
* 掩码
*/
public final String virtualNetmask;
/**
* 网关
*/
public final String virtualGateway;
public RegisterInfo(String virtualIp, String virtualNetmask, String virtualGateway) {
this.virtualIp = virtualIp;
this.virtualNetmask = virtualNetmask;
this.virtualGateway = virtualGateway;
}
public String getVirtualIp() {
return virtualIp;
}
public String getVirtualNetmask() {
return virtualNetmask;
}
public String getVirtualGateway() {
return virtualGateway;
}
@Override
public String toString() {
return "RegisterInfo{" +
"virtualIp='" + virtualIp + '\'' +
", virtualNetmask='" + virtualNetmask + '\'' +
", virtualGateway='" + virtualGateway + '\'' +
'}';
}
}
+185
View File
@@ -0,0 +1,185 @@
use std::sync::Arc;
use jni::objects::{GlobalRef, JString, JValue};
use jni::{JNIEnv, JavaVM};
use spki::der::pem::LineEnding;
use spki::EncodePublicKey;
use vnt::handle::callback::ConnectInfo;
use vnt::{DeviceInfo, ErrorInfo, HandshakeInfo, RegisterInfo, VntCallback};
#[derive(Clone)]
pub struct CallBack {
jvm: Arc<JavaVM>,
this: GlobalRef,
}
unsafe impl Send for CallBack {}
impl CallBack {
pub fn new(jvm: JavaVM, this: GlobalRef) -> Self {
Self {
jvm: Arc::new(jvm),
this,
}
}
}
impl CallBack {
fn create_tun0(&self, info: DeviceInfo) -> jni::errors::Result<()> {
let env = &mut self.jvm.attach_current_thread()? as &mut JNIEnv;
let param = env.new_object(
"top/wherewego/vnt/jni/param/DeviceInfo",
"(Ljava/lang/String;Ljava/lang/String;)V",
&[
JValue::Object(&env.new_string(info.name)?.into()),
JValue::Object(&env.new_string(info.version)?.into()),
],
)?;
env.call_method(
&self.this,
"createTun",
"(Ltop/wherewego/vnt/jni/param/DeviceInfo;)V",
&[JValue::Object(&param)],
)?;
Ok(())
}
fn connect0(&self, info: ConnectInfo) -> jni::errors::Result<()> {
let env = &mut self.jvm.attach_current_thread()? as &mut JNIEnv;
let param = env.new_object(
"top/wherewego/vnt/jni/param/ConnectInfo",
"(JLjava/lang/String;)V",
&[
JValue::Long(info.count as _),
JValue::Object(&env.new_string(info.address.to_string())?.into()),
],
)?;
env.call_method(
&self.this,
"connect",
"(Ltop/wherewego/vnt/jni/param/ConnectInfo;)V",
&[JValue::Object(&param)],
)?;
Ok(())
}
fn handshake0(&self, info: HandshakeInfo) -> jni::errors::Result<bool> {
let env = &mut self.jvm.attach_current_thread()? as &mut JNIEnv;
let public_key = if let Some(public_key) = info.public_key {
match public_key.to_public_key_pem(LineEnding::CRLF) {
Ok(public_key) => env.new_string(public_key)?,
Err(e) => {
log::warn!("{:?}", e);
JString::default()
}
}
} else {
JString::default()
};
let finger = if let Some(finger) = info.finger {
env.new_string(finger)?
} else {
JString::default()
};
let param = env.new_object(
"top/wherewego/vnt/jni/param/HandshakeInfo",
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V",
&[
JValue::Object(&public_key),
JValue::Object(&finger),
JValue::Object(&env.new_string(info.version)?.into()),
],
)?;
let rs = env.call_method(
&self.this,
"handshake",
"(Ltop/wherewego/vnt/jni/param/HandshakeInfo;)Z",
&[JValue::Object(&param)],
)?;
rs.z()
}
fn register0(&self, info: RegisterInfo) -> jni::errors::Result<bool> {
let env = &mut self.jvm.attach_current_thread()? as &mut JNIEnv;
let param = env.new_object(
"top/wherewego/vnt/jni/param/RegisterInfo",
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V",
&[
JValue::Object(&env.new_string(info.virtual_ip.to_string())?.into()),
JValue::Object(&env.new_string(info.virtual_netmask.to_string())?.into()),
JValue::Object(&env.new_string(info.virtual_gateway.to_string())?.into()),
],
)?;
let rs = env.call_method(
&self.this,
"register",
"(Ltop/wherewego/vnt/jni/param/RegisterInfo;)Z",
&[JValue::Object(&param)],
)?;
rs.z()
}
fn error0(&self, info: ErrorInfo) -> jni::errors::Result<()> {
let code: u8 = info.code.into();
let env = &mut self.jvm.attach_current_thread()? as &mut JNIEnv;
let msg = if let Some(msg) = info.msg {
env.new_string(msg)?
} else {
JString::default()
};
let param = env.new_object(
"top/wherewego/vnt/jni/param/ErrorInfo",
"(ILjava/lang/String;)V",
&[JValue::Int(code as _), JValue::Object(&msg.into())],
)?;
env.call_method(
&self.this,
"error",
"(Ltop/wherewego/vnt/jni/param/ErrorInfo;)V",
&[JValue::Object(&param)],
)?;
Ok(())
}
fn stop0(&self) -> jni::errors::Result<()> {
let env = &mut self.jvm.attach_current_thread()? as &mut JNIEnv;
env.call_method(&self.this, "error", "()V", &[])?;
Ok(())
}
}
impl VntCallback for CallBack {
fn create_tun(&self, info: DeviceInfo) {
if let Err(e) = self.create_tun0(info) {
log::warn!("create_tun {:?}", e);
}
}
fn connect(&self, info: ConnectInfo) {
if let Err(e) = self.connect0(info) {
log::warn!("connect {:?}", e);
}
}
fn handshake(&self, info: HandshakeInfo) -> bool {
self.handshake0(info).unwrap_or_else(|e| {
log::warn!("handshake {:?}", e);
false
})
}
fn register(&self, info: RegisterInfo) -> bool {
self.register0(info).unwrap_or_else(|e| {
log::warn!("register {:?}", e);
false
})
}
fn error(&self, info: ErrorInfo) {
if let Err(e) = self.error0(info) {
log::warn!("error {:?}", e);
}
}
fn stop(&self) {
if let Err(e) = self.stop0() {
log::warn!("stop {:?}", e);
}
}
}
+145
View File
@@ -0,0 +1,145 @@
use std::net::ToSocketAddrs;
use std::str::FromStr;
use jni::errors::Error;
use jni::JNIEnv;
use jni::objects::JObject;
use vnt::channel::punch::PunchModel;
use vnt::cipher::CipherModel;
use vnt::core::Config;
use crate::utils::*;
pub fn new_config(env: &mut JNIEnv, config: JObject) -> Result<Config, Error> {
#[cfg(any(target_os = "windows", target_os = "linux"))]
let tap = env.get_field(&config, "tap", "Z")?.z()?;
let token = to_string_not_null(env, &config, "token")?;
let name = to_string_not_null(env, &config, "name")?;
let device_id = to_string_not_null(env, &config, "deviceId")?;
let password = to_string(env, &config, "password")?;
let server_address_str = to_string_not_null(env, &config, "server")?;
let stun_server = to_string_array_not_null(env, &config, "stunServer")?;
let cipher_model = to_string_not_null(env, &config, "cipherModel")?;
let punch_model = to_string(env, &config, "punchModel")?;
let mtu = to_integer(env, &config, "mtu")?.map(|v|v as u32);
let tcp = env.get_field(&config, "tcp", "Z")?.z()?;
let server_encrypt = env.get_field(&config, "serverEncrypt", "Z")?.z()?;
let relay = env.get_field(&config, "relay", "Z")?.z()?;
let finger = env.get_field(&config, "finger", "Z")?.z()?;
let first_latency = env.get_field(&config, "firstLatency", "Z")?.z()?;
let in_ips = to_string_array(env, &config, "inIps")?;
let out_ips = to_string_array(env, &config, "outIps")?;
let ports =
to_i32_array(env, &config, "ports")?.map(|v| v.into_iter().map(|v| v as u16).collect());
let ip = if let Some(ip) = to_string(env, &config, "ip")? {
match ip.parse() {
Ok(ip) => {
Some(ip)
}
Err(e) => {
env.throw_new("java/lang/RuntimeException", format!("ip {} err: {}", ip, e))
.expect("throw");
return Err(Error::JavaException);
}
}
} else {
None
};
let in_ips = if let Some(in_ips) = in_ips {
match common::args_parse::ips_parse(&in_ips) {
Ok(in_ips) => in_ips,
Err(e) => {
env.throw_new("java/lang/RuntimeException", format!("in_ips {}", e))
.expect("throw");
return Err(Error::JavaException);
}
}
} else {
vec![]
};
let out_ips = if let Some(out_ips) = out_ips {
match common::args_parse::out_ips_parse(&out_ips) {
Ok(out_ips) => out_ips,
Err(e) => {
env.throw_new("java/lang/RuntimeException", format!("out_ips {}", e))
.expect("throw");
return Err(Error::JavaException);
}
}
} else {
vec![]
};
let server_address = match server_address_str.to_socket_addrs() {
Ok(mut rs) => {
if let Some(addr) = rs.next() {
addr
} else {
env.throw_new("java/lang/RuntimeException", "server address err")
.expect("throw");
return Err(Error::JavaException);
}
}
Err(e) => {
env.throw_new(
"java/lang/RuntimeException",
format!("server address {}", e),
)
.expect("throw");
return Err(Error::JavaException);
}
};
let cipher_model = match CipherModel::from_str(&cipher_model) {
Ok(cipher_model) => cipher_model,
Err(e) => {
env.throw_new("java/lang/RuntimeException", format!("cipher_model {}", e))
.expect("throw");
return Err(Error::JavaException);
}
};
#[cfg(not(target_os = "android"))]
let device_name = to_string(env, &config, "deviceName")?;
#[cfg(target_os = "android")]
let device_fd = env.get_field(&config, "deviceFd", "I")?.i()? as i32;
let config = match Config::new(
#[cfg(any(target_os = "windows", target_os = "linux"))]
tap,
token,
device_id,
name,
server_address,
server_address_str,
stun_server,
in_ips,
out_ips,
password,
mtu,
tcp,
ip,
relay,
false,
server_encrypt,
1,
cipher_model,
finger,
PunchModel::from_str(&punch_model.unwrap_or_default()).unwrap_or_default(),
ports,
first_latency,
#[cfg(not(target_os = "android"))]
device_name,
#[cfg(target_os = "android")]
device_fd,
) {
Ok(config) => config,
Err(e) => {
env.throw_new(
"java/lang/RuntimeException",
format!("vnt start error {}", e),
)
.expect("throw");
return Err(Error::JavaException);
}
};
Ok(config)
}
+3 -1
View File
@@ -1,2 +1,4 @@
pub mod callback;
pub mod config;
pub mod vnt;
pub mod vnt_util;
pub mod utils;
+115
View File
@@ -0,0 +1,115 @@
use jni::errors::Error;
use jni::JNIEnv;
use jni::objects::{JIntArray, JObject, JObjectArray, JString};
pub fn to_string_not_null(
env: &mut JNIEnv,
config: &JObject,
name: &'static str,
) -> Result<String, Error> {
let value = env.get_field(config, name, "Ljava/lang/String;")?.l()?;
if value.is_null() {
env.throw_new("java/lang/NullPointerException", name)
.expect("throw");
return Err(Error::NullPtr(name));
}
let binding = JString::from(value);
let value = env.get_string(binding.as_ref())?;
match value.to_str() {
Ok(value) => Ok(value.to_string()),
Err(_) => {
env.throw_new("java/lang/RuntimeException", "not utf-8")
.expect("throw");
return Err(Error::JavaException);
}
}
}
pub fn to_string(env: &mut JNIEnv, config: &JObject, name: &str) -> Result<Option<String>, Error> {
let value = env.get_field(config, name, "Ljava/lang/String;")?.l()?;
if value.is_null() {
return Ok(None);
}
let tmp = JString::from(value);
let value = env.get_string(tmp.as_ref())?;
match value.to_str() {
Ok(value) => Ok(Some(value.to_string())),
Err(_) => {
env.throw_new("java/lang/RuntimeException", "not utf-8")
.expect("throw");
return Err(Error::JavaException);
}
}
}
pub fn to_string_array_not_null(
env: &mut JNIEnv,
config: &JObject,
name: &str,
) -> Result<Vec<String>, Error> {
match to_string_array(env, config, name)? {
None => {
env.throw_new("java/lang/NullPointerException", name)
.expect("throw");
return Err(Error::JavaException);
}
Some(rs) => Ok(rs),
}
}
pub fn to_string_array(
env: &mut JNIEnv,
config: &JObject,
name: &str,
) -> Result<Option<Vec<String>>, Error> {
let value = env.get_field(config, name, "[Ljava/lang/String;")?.l()?;
if value.is_null() {
return Ok(None);
}
let arr = JObjectArray::from(value);
let len = env.get_array_length(&arr)?;
let mut rs = Vec::with_capacity(len as usize);
for index in 0..len {
let object = env.get_object_array_element(&arr, index)?;
if object.is_null() {
env.throw_new(
"java/lang/NullPointerException",
format!("{},index={}", name, index),
)
.expect("throw");
return Err(Error::JavaException);
}
match env.get_string(JString::from(object).as_ref())?.to_str() {
Ok(value) => {
rs.push(value.to_string());
}
Err(_) => {
env.throw_new("java/lang/RuntimeException", "not utf-8")
.expect("throw");
return Err(Error::JavaException);
}
}
}
Ok(Some(rs))
}
pub fn to_i32_array(env: &mut JNIEnv, config: &JObject, name: &str) -> Result<Option<Vec<i32>>, Error> {
let obj = env.get_field(&config, name, "[I")?.l()?;
if obj.is_null() {
Ok(None)
} else {
let j_arr = JIntArray::from(obj);
let len = env.get_array_length(&j_arr)?;
let mut arr = vec![0i32; len as usize];
env.get_int_array_region(j_arr, 0, &mut arr)?;
Ok(Some(arr))
}
}
pub fn to_integer(env: &mut JNIEnv, config: &JObject, name: &str) -> Result<Option<i32>, Error> {
let value = env.get_field(config, name, "Ljava/lang/Integer;")?.l()?;
if value.is_null() {
return Ok(None);
}
// 调用 intValue
return Ok(Some(env.call_method(value,"intValue","()I",&[])?.i()? as _))
}
+51 -25
View File
@@ -1,45 +1,71 @@
use std::ptr;
use jni::errors::Error;
use jni::objects::{JClass, JObject, JValue};
use jni::sys::{jboolean, jbyte, jint, jlong, jobject, jobjectArray, jsize};
use jni::sys::{jbyte, jint, jlong, jobject, jobjectArray, jsize};
use jni::JNIEnv;
use std::ptr;
use vnt::channel::Route;
use vnt::core::sync::VntSync;
use vnt::core::Vnt;
use vnt::handle::PeerDeviceInfo;
use crate::callback::CallBack;
#[no_mangle]
pub unsafe extern "C" fn Java_top_wherewego_vnt_jni_Vnt_new0(
mut env: JNIEnv<'static>,
_class: JClass,
config: JObject,
call_back: JObject<'static>,
) -> jlong {
let jvm = if let Ok(jvm) = env.get_java_vm() {
jvm
} else {
return 0;
};
match crate::config::new_config(&mut env, config) {
Ok(config) => {
let call_back = if let Ok(call_back) = env.new_global_ref(call_back) {
call_back
} else {
return 0;
};
let vnt_util = match Vnt::new(config, CallBack::new(jvm, call_back)) {
Ok(vnt_util) => vnt_util,
Err(e) => {
env.throw_new(
"java/lang/RuntimeException",
format!("vnt start error {}", e),
)
.expect("throw");
return 0;
}
};
let ptr = Box::into_raw(Box::new(vnt_util));
return ptr as jlong;
}
Err(_) => {}
}
return 0;
}
#[no_mangle]
pub unsafe extern "C" fn Java_top_wherewego_vnt_jni_Vnt_stop0(
_env: JNIEnv,
_class: JClass,
raw_vnt: jlong,
) {
let vnt = raw_vnt as *mut VntSync;
let vnt = raw_vnt as *mut Vnt;
let _ = (&*vnt).stop();
}
#[no_mangle]
pub unsafe extern "C" fn Java_top_wherewego_vnt_jni_Vnt_waitStop0(
pub unsafe extern "C" fn Java_top_wherewego_vnt_jni_Vnt_wait0(
_env: JNIEnv,
_class: JClass,
raw_vnt: jlong,
) {
let vnt = raw_vnt as *mut VntSync;
let _ = (&mut *vnt).wait_stop();
}
#[no_mangle]
pub unsafe extern "C" fn Java_top_wherewego_vnt_jni_Vnt_waitStopMs0(
_env: JNIEnv,
_class: JClass,
raw_vnt: jlong,
ms: jlong,
) -> jboolean {
let vnt = raw_vnt as *mut VntSync;
if (&mut *vnt).wait_stop_ms(ms as _) {
jni::sys::JNI_TRUE
} else {
jni::sys::JNI_FALSE
}
let vnt = raw_vnt as *mut Vnt;
let _ = (&*vnt).wait();
}
#[no_mangle]
@@ -48,7 +74,7 @@ pub unsafe extern "C" fn Java_top_wherewego_vnt_jni_Vnt_drop0(
_class: JClass,
raw_vnt: jlong,
) {
let vnt = raw_vnt as *mut VntSync;
let vnt = raw_vnt as *mut Vnt;
let _ = Box::from_raw(vnt).stop();
}
@@ -58,7 +84,7 @@ pub unsafe extern "C" fn Java_top_wherewego_vnt_jni_Vnt_list0(
_class: JClass,
raw_vnt: jlong,
) -> jobjectArray {
let vnt = raw_vnt as *mut VntSync;
let vnt = raw_vnt as *mut Vnt;
let vnt = &mut *vnt;
let list = vnt.device_list();
-386
View File
@@ -1,386 +0,0 @@
use std::net::ToSocketAddrs;
use std::ptr;
use std::str::FromStr;
use jni::errors::Error;
use jni::objects::{JClass, JObject, JString, JValue};
#[cfg(not(target_os = "android"))]
use jni::sys::jboolean;
use jni::sys::{jint, jlong, jobject};
use jni::JNIEnv;
use vnt::channel::punch::PunchModel;
use vnt::cipher::CipherModel;
use vnt::core::sync::VntUtilSync;
use vnt::core::Config;
use vnt::handle::registration_handler::{RegResponse, ReqEnum};
#[cfg(not(target_os = "android"))]
use vnt::tun_tap_device::DriverInfo;
fn to_string_not_null(
env: &mut JNIEnv,
config: &JObject,
name: &'static str,
) -> Result<String, Error> {
let value = env.get_field(config, name, "Ljava/lang/String;")?.l()?;
if value.is_null() {
env.throw_new("java/lang/NullPointerException", name)
.expect("throw");
return Err(Error::NullPtr(name));
}
let binding = JString::from(value);
let value = env.get_string(binding.as_ref())?;
match value.to_str() {
Ok(value) => Ok(value.to_string()),
Err(_) => {
env.throw_new("java/lang/RuntimeException", "not utf-8")
.expect("throw");
return Err(Error::JavaException);
}
}
}
fn to_string(env: &mut JNIEnv, config: &JObject, name: &str) -> Result<Option<String>, Error> {
let value = env.get_field(config, name, "Ljava/lang/String;")?.l()?;
if value.is_null() {
return Ok(None);
}
let tmp = JString::from(value);
let value = env.get_string(tmp.as_ref())?;
match value.to_str() {
Ok(value) => Ok(Some(value.to_string())),
Err(_) => {
env.throw_new("java/lang/RuntimeException", "not utf-8")
.expect("throw");
return Err(Error::JavaException);
}
}
}
fn new_sync(env: &mut JNIEnv, config: JObject) -> Result<VntUtilSync, Error> {
let token = to_string_not_null(env, &config, "token")?;
let name = to_string_not_null(env, &config, "name")?;
let device_id = to_string_not_null(env, &config, "deviceId")?;
let password = to_string(env, &config, "password")?;
let server_address_str = to_string_not_null(env, &config, "server")?;
let stun_server_str = to_string_not_null(env, &config, "stunServer")?;
let cipher_model = to_string_not_null(env, &config, "cipherModel")?;
let tcp = env.get_field(&config, "tcp", "Z")?.z()?;
let finger = env.get_field(&config, "finger", "Z")?.z()?;
let first_latency = env.get_field(&config, "firstLatency", "Z")?.z()?;
let in_ips = to_string(env, &config, "inIps")?;
let out_ips = to_string(env, &config, "outIps")?;
let port = env.get_field(&config, "port", "I")?.i()? as u16;
let in_ips = if let Some(in_ips) = in_ips {
let in_ips: Vec<&str> = in_ips.split("\n").collect();
let in_ips = in_ips.iter().map(|v| v.to_string()).collect();
match common::args_parse::ips_parse(&in_ips) {
Ok(in_ips) => in_ips,
Err(e) => {
env.throw_new("java/lang/RuntimeException", format!("in_ips {}", e))
.expect("throw");
return Err(Error::JavaException);
}
}
} else {
vec![]
};
let out_ips = if let Some(out_ips) = out_ips {
let out_ips: Vec<&str> = out_ips.split("\n").collect();
let out_ips = out_ips.iter().map(|v| v.to_string()).collect();
match common::args_parse::out_ips_parse(&out_ips) {
Ok(out_ips) => out_ips,
Err(e) => {
env.throw_new("java/lang/RuntimeException", format!("out_ips {}", e))
.expect("throw");
return Err(Error::JavaException);
}
}
} else {
vec![]
};
let server_address = match server_address_str.to_socket_addrs() {
Ok(mut rs) => {
if let Some(addr) = rs.next() {
addr
} else {
env.throw_new("java/lang/RuntimeException", "server address err")
.expect("throw");
return Err(Error::JavaException);
}
}
Err(e) => {
env.throw_new(
"java/lang/RuntimeException",
format!("server address {}", e),
)
.expect("throw");
return Err(Error::JavaException);
}
};
let cipher_model = match CipherModel::from_str(&cipher_model) {
Ok(cipher_model) => cipher_model,
Err(e) => {
env.throw_new("java/lang/RuntimeException", format!("cipher_model {}", e))
.expect("throw");
return Err(Error::JavaException);
}
};
let mut stun_server = Vec::new();
for addr in stun_server_str.split(",") {
stun_server.push(addr.trim().to_string());
}
let config = match Config::new(
false,
token,
device_id,
name,
server_address,
server_address_str,
stun_server,
in_ips,
out_ips,
password,
false,
None,
tcp,
None,
false,
false,
false,
1,
cipher_model,
finger,
PunchModel::All,
port,
first_latency,
) {
Ok(config) => config,
Err(e) => {
env.throw_new(
"java/lang/RuntimeException",
format!("vnt start error {}", e),
)
.expect("throw");
return Err(Error::JavaException);
}
};
match VntUtilSync::new(config) {
Ok(vnt_util) => Ok(vnt_util),
Err(e) => {
env.throw_new(
"java/lang/RuntimeException",
format!("vnt start error {}", e),
)
.expect("throw");
return Err(Error::JavaException);
}
}
}
#[no_mangle]
pub unsafe extern "C" fn Java_top_wherewego_vnt_jni_VntUtil_new0(
mut env: JNIEnv,
_class: JClass,
config: JObject,
) -> jlong {
match new_sync(&mut env, config) {
Ok(vnt_util) => {
let ptr = Box::into_raw(Box::new(vnt_util));
return ptr as jlong;
}
Err(_) => {}
}
return 0;
}
#[no_mangle]
pub unsafe extern "C" fn Java_top_wherewego_vnt_jni_VntUtil_connect0(
mut env: JNIEnv,
_class: JClass,
raw_vnt_util: jlong,
) {
let raw_vnt_util = raw_vnt_util as *mut VntUtilSync;
match (&mut *raw_vnt_util).connect() {
Ok(_) => {}
Err(e) => {
env.throw_new(
"java/lang/RuntimeException",
format!("vnt connect error {}", e),
)
.expect("throw");
}
}
}
#[no_mangle]
pub unsafe extern "C" fn Java_top_wherewego_vnt_jni_VntUtil_register0(
mut env: JNIEnv,
_class: JClass,
raw_vnt_util: jlong,
) -> jobject {
let raw_vnt_util = raw_vnt_util as *mut VntUtilSync;
match (&mut *raw_vnt_util).register() {
Ok(response) => match reg_response(&mut env, response) {
Ok(res) => {
return res;
}
Err(e) => {
env.throw(format!("vnt register error {}", e))
.expect("throw");
}
},
Err(e) => match e {
ReqEnum::TokenError => {
env.throw_new(
"top/wherewego/vnt/jni/exception/TokenErrorException",
"TokenError",
)
.expect("throw");
}
ReqEnum::AddressExhausted => {
env.throw_new(
"top/wherewego/vnt/jni/exception/AddressExhaustedException",
"AddressExhausted",
)
.expect("throw");
}
ReqEnum::Timeout => {
env.throw_new(
"top/wherewego/vnt/jni/exception/TimeoutException",
"Timeout",
)
.expect("throw");
}
ReqEnum::ServerError(str) => {
env.throw_new(
"java/lang/RuntimeException",
format!("vnt register error {}", str),
)
.expect("throw");
}
ReqEnum::Other(str) => {
env.throw_new(
"java/lang/RuntimeException",
format!("vnt register error {}", str),
)
.expect("throw");
}
ReqEnum::IpAlreadyExists => {
env.throw_new(
"top/wherewego/vnt/jni/exception/IpAlreadyExistsException",
"IpAlreadyExists",
)
.expect("throw");
}
ReqEnum::InvalidIp => {
env.throw_new(
"top/wherewego/vnt/jni/exception/InvalidIpException",
"InvalidIp",
)
.expect("throw");
}
},
}
return ptr::null_mut();
}
#[cfg(target_os = "android")]
#[no_mangle]
pub unsafe extern "C" fn Java_top_wherewego_vnt_jni_VntUtil_createIface0(
_env: JNIEnv,
_class: JClass,
raw_vnt_util: jlong,
fd: jint,
) {
let raw_vnt_util = raw_vnt_util as *mut VntUtilSync;
(&mut *raw_vnt_util).create_iface(fd as i32);
}
#[cfg(not(target_os = "android"))]
#[no_mangle]
pub unsafe extern "C" fn Java_top_wherewego_vnt_jni_VntUtil_createIface0(
mut env: JNIEnv,
_class: JClass,
raw_vnt_util: jlong,
) -> jobject {
let raw_vnt_util = raw_vnt_util as *mut VntUtilSync;
let rs = (&mut *raw_vnt_util).create_iface();
match rs {
Ok(driver_info) => match driver_info_e(&mut env, driver_info) {
Ok(res) => {
return res;
}
Err(e) => {
env.throw(format!("vnt create iface error {}", e))
.expect("throw");
}
},
Err(e) => {
env.throw_new(
"java/lang/RuntimeException",
format!("vnt create iface error {}", e),
)
.expect("throw");
}
}
return ptr::null_mut();
}
#[no_mangle]
pub unsafe extern "C" fn Java_top_wherewego_vnt_jni_VntUtil_build0(
mut env: JNIEnv,
_class: JClass,
raw_vnt_util: jlong,
) -> jlong {
let raw_vnt_util = Box::from_raw(raw_vnt_util as *mut VntUtilSync);
match raw_vnt_util.build() {
Ok(rs) => {
return Box::into_raw(Box::new(rs)) as jlong;
}
Err(e) => {
env.throw_new(
"java/lang/RuntimeException",
format!("vnt start error:{:?}", e),
)
.expect("throw");
}
}
return 0;
}
fn reg_response(env: &mut JNIEnv, response: RegResponse) -> Result<jobject, Error> {
let virtual_ip = u32::from(response.virtual_ip);
let virtual_gateway = u32::from(response.virtual_gateway);
let virtual_netmask = u32::from(response.virtual_netmask);
let response = env.new_object(
"top/wherewego/vnt/jni/RegResponse",
"(III)V",
&[
JValue::Int(virtual_ip as jint),
JValue::Int(virtual_gateway as jint),
JValue::Int(virtual_netmask as jint),
],
)?;
Ok(response.into_raw())
}
#[cfg(not(target_os = "android"))]
fn driver_info_e(env: &mut JNIEnv, driver_info: DriverInfo) -> Result<jobject, Error> {
let is_tun = driver_info.device_type.is_tun();
let name = driver_info.name;
let version = driver_info.version;
let mac = driver_info.mac.unwrap_or(String::new());
let response = env.new_object(
"top/wherewego/vnt/jni/DriverInfo",
"(ZLjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V",
&[
JValue::Bool(is_tun as jboolean),
JValue::Object(&env.new_string(name)?.into()),
JValue::Object(&env.new_string(version)?.into()),
JValue::Object(&env.new_string(mac)?.into()),
],
)?;
Ok(response.into_raw())
}