mirror of
https://github.com/EasyTier/EasyTier.git
synced 2026-09-02 09:09:17 +00:00
feat(ffi): add async data plane API (#2321)
* feat(ffi): add async data plane API * feat(ffi): add async data plane examples * test(ffi): make async Go dataplane tests self-contained * docs(ffi): document Go async dataplane API * docs(android): document dataplane JNI API
This commit is contained in:
@@ -0,0 +1,673 @@
|
||||
use std::{
|
||||
ffi::{CStr, c_char},
|
||||
ptr,
|
||||
};
|
||||
|
||||
use easytier_ffi::{
|
||||
data_plane_async_op_cancel, data_plane_async_op_free, data_plane_async_op_status,
|
||||
data_plane_async_op_wait, data_plane_free_bytes, data_plane_tcp_accept_finish,
|
||||
data_plane_tcp_accept_start, data_plane_tcp_bind_finish, data_plane_tcp_bind_start,
|
||||
data_plane_tcp_close, data_plane_tcp_connect_finish, data_plane_tcp_connect_start,
|
||||
data_plane_tcp_listener_close, data_plane_tcp_read_finish, data_plane_tcp_read_start,
|
||||
data_plane_tcp_write_finish, data_plane_tcp_write_start, data_plane_udp_bind_finish,
|
||||
data_plane_udp_bind_start, data_plane_udp_close, data_plane_udp_recv_from_finish,
|
||||
data_plane_udp_recv_from_start, data_plane_udp_send_to_finish, data_plane_udp_send_to_start,
|
||||
free_string,
|
||||
};
|
||||
use jni::{
|
||||
JNIEnv,
|
||||
objects::{JByteArray, JClass, JObject, JString, JValue},
|
||||
sys::{jint, jlong, jobject},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
error::{get_last_error, throw_exception},
|
||||
strings::jstring_to_cstring,
|
||||
};
|
||||
|
||||
const SOCKET_ADDR_CLASS: &str = "com/easytier/jni/DataPlaneSocketAddress";
|
||||
const TCP_CONNECT_RESULT_CLASS: &str = "com/easytier/jni/DataPlaneTcpConnectResult";
|
||||
const TCP_BIND_RESULT_CLASS: &str = "com/easytier/jni/DataPlaneTcpBindResult";
|
||||
const TCP_ACCEPT_RESULT_CLASS: &str = "com/easytier/jni/DataPlaneTcpAcceptResult";
|
||||
const TCP_READ_RESULT_CLASS: &str = "com/easytier/jni/DataPlaneTcpReadResult";
|
||||
const UDP_BIND_RESULT_CLASS: &str = "com/easytier/jni/DataPlaneUdpBindResult";
|
||||
const UDP_RECV_RESULT_CLASS: &str = "com/easytier/jni/DataPlaneUdpRecvResult";
|
||||
|
||||
fn timeout_from_jlong(timeout_ms: jlong) -> u64 {
|
||||
timeout_ms.max(0) as u64
|
||||
}
|
||||
|
||||
fn port_from_jint(env: &mut JNIEnv, value: jint, name: &str) -> Option<u16> {
|
||||
match u16::try_from(value) {
|
||||
Ok(port) => Some(port),
|
||||
Err(_) => {
|
||||
throw_exception(env, &format!("Invalid {}: {}", name, value));
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn len_from_jint(env: &mut JNIEnv, value: jint, name: &str) -> Option<u32> {
|
||||
match u32::try_from(value) {
|
||||
Ok(len) => Some(len),
|
||||
Err(_) => {
|
||||
throw_exception(env, &format!("Invalid {}: {}", name, value));
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn throw_last(env: &mut JNIEnv) {
|
||||
let message = get_last_error().unwrap_or_else(|| "EasyTier data-plane call failed".to_string());
|
||||
throw_exception(env, &message);
|
||||
}
|
||||
|
||||
unsafe fn take_ffi_string(ptr: *const c_char) -> String {
|
||||
if ptr.is_null() {
|
||||
return String::new();
|
||||
}
|
||||
let value = unsafe { CStr::from_ptr(ptr) }
|
||||
.to_string_lossy()
|
||||
.into_owned();
|
||||
free_string(ptr);
|
||||
value
|
||||
}
|
||||
|
||||
fn new_socket_addr<'local>(
|
||||
env: &mut JNIEnv<'local>,
|
||||
ip: String,
|
||||
port: u16,
|
||||
) -> Option<JObject<'local>> {
|
||||
let class = match env.find_class(SOCKET_ADDR_CLASS) {
|
||||
Ok(class) => class,
|
||||
Err(err) => {
|
||||
throw_exception(
|
||||
env,
|
||||
&format!("Failed to find socket address class: {:?}", err),
|
||||
);
|
||||
return None;
|
||||
}
|
||||
};
|
||||
let ip = match env.new_string(ip) {
|
||||
Ok(ip) => ip,
|
||||
Err(err) => {
|
||||
throw_exception(env, &format!("Failed to create IP string: {:?}", err));
|
||||
return None;
|
||||
}
|
||||
};
|
||||
match env.new_object(
|
||||
class,
|
||||
"(Ljava/lang/String;I)V",
|
||||
&[JValue::Object(&ip), JValue::Int(port as jint)],
|
||||
) {
|
||||
Ok(addr) => Some(addr),
|
||||
Err(err) => {
|
||||
throw_exception(env, &format!("Failed to create socket address: {:?}", err));
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn new_handle_addr_result(
|
||||
env: &mut JNIEnv,
|
||||
class_name: &str,
|
||||
handle: u64,
|
||||
ip: String,
|
||||
port: u16,
|
||||
) -> jobject {
|
||||
let Some(addr) = new_socket_addr(env, ip, port) else {
|
||||
return ptr::null_mut();
|
||||
};
|
||||
let class = match env.find_class(class_name) {
|
||||
Ok(class) => class,
|
||||
Err(err) => {
|
||||
throw_exception(env, &format!("Failed to find result class: {:?}", err));
|
||||
return ptr::null_mut();
|
||||
}
|
||||
};
|
||||
let sig = format!("(JL{};)V", SOCKET_ADDR_CLASS);
|
||||
match env.new_object(
|
||||
class,
|
||||
sig.as_str(),
|
||||
&[JValue::Long(handle as jlong), JValue::Object(&addr)],
|
||||
) {
|
||||
Ok(result) => result.into_raw(),
|
||||
Err(err) => {
|
||||
throw_exception(env, &format!("Failed to create result object: {:?}", err));
|
||||
ptr::null_mut()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn close_tcp_stream_on_null(result: jobject, handle: u64) -> jobject {
|
||||
if result.is_null() {
|
||||
let _ = data_plane_tcp_close(handle);
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
fn close_tcp_listener_on_null(result: jobject, handle: u64) -> jobject {
|
||||
if result.is_null() {
|
||||
let _ = data_plane_tcp_listener_close(handle);
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
fn close_udp_socket_on_null(result: jobject, handle: u64) -> jobject {
|
||||
if result.is_null() {
|
||||
let _ = data_plane_udp_close(handle);
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
fn read_owned_bytes(ptr: *const u8, len: u32) -> Vec<u8> {
|
||||
if ptr.is_null() || len == 0 {
|
||||
return Vec::new();
|
||||
}
|
||||
let bytes = unsafe { std::slice::from_raw_parts(ptr, len as usize) }.to_vec();
|
||||
data_plane_free_bytes(ptr, len);
|
||||
bytes
|
||||
}
|
||||
|
||||
pub(crate) fn async_op_status_jni(_env: JNIEnv, _class: JClass, handle: jlong) -> jint {
|
||||
data_plane_async_op_status(handle as u64)
|
||||
}
|
||||
|
||||
pub(crate) fn async_op_wait_jni(
|
||||
_env: JNIEnv,
|
||||
_class: JClass,
|
||||
handle: jlong,
|
||||
timeout_ms: jlong,
|
||||
) -> jint {
|
||||
data_plane_async_op_wait(handle as u64, timeout_ms.max(0) as u64)
|
||||
}
|
||||
|
||||
pub(crate) fn async_op_cancel_jni(_env: JNIEnv, _class: JClass, handle: jlong) -> jint {
|
||||
data_plane_async_op_cancel(handle as u64)
|
||||
}
|
||||
|
||||
pub(crate) fn async_op_free_jni(_env: JNIEnv, _class: JClass, handle: jlong) -> jint {
|
||||
data_plane_async_op_free(handle as u64)
|
||||
}
|
||||
|
||||
pub(crate) fn tcp_connect_start_jni(
|
||||
mut env: JNIEnv,
|
||||
_class: JClass,
|
||||
inst_name: JString,
|
||||
dst_ip: JString,
|
||||
dst_port: jint,
|
||||
timeout_ms: jlong,
|
||||
) -> jlong {
|
||||
let inst_name = match jstring_to_cstring(&mut env, &inst_name) {
|
||||
Ok(value) => value,
|
||||
Err(err) => {
|
||||
throw_exception(&mut env, &format!("Invalid instance name: {}", err));
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
let dst_ip = match jstring_to_cstring(&mut env, &dst_ip) {
|
||||
Ok(value) => value,
|
||||
Err(err) => {
|
||||
throw_exception(&mut env, &format!("Invalid destination IP: {}", err));
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
let Some(dst_port) = port_from_jint(&mut env, dst_port, "destination port") else {
|
||||
return 0;
|
||||
};
|
||||
let op = unsafe {
|
||||
data_plane_tcp_connect_start(
|
||||
inst_name.as_ptr(),
|
||||
dst_ip.as_ptr(),
|
||||
dst_port,
|
||||
timeout_ms.max(0) as u64,
|
||||
)
|
||||
};
|
||||
if op == 0 {
|
||||
throw_last(&mut env);
|
||||
}
|
||||
op as jlong
|
||||
}
|
||||
|
||||
pub(crate) fn tcp_connect_finish_jni(mut env: JNIEnv, _class: JClass, op: jlong) -> jobject {
|
||||
let mut ip: *const c_char = ptr::null();
|
||||
let mut port = 0u16;
|
||||
let handle = unsafe { data_plane_tcp_connect_finish(op as u64, &mut ip, &mut port) };
|
||||
if handle == 0 {
|
||||
throw_last(&mut env);
|
||||
return ptr::null_mut();
|
||||
}
|
||||
close_tcp_stream_on_null(
|
||||
new_handle_addr_result(
|
||||
&mut env,
|
||||
TCP_CONNECT_RESULT_CLASS,
|
||||
handle,
|
||||
unsafe { take_ffi_string(ip) },
|
||||
port,
|
||||
),
|
||||
handle,
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn tcp_bind_start_jni(
|
||||
mut env: JNIEnv,
|
||||
_class: JClass,
|
||||
inst_name: JString,
|
||||
local_port: jint,
|
||||
timeout_ms: jlong,
|
||||
) -> jlong {
|
||||
let inst_name = match jstring_to_cstring(&mut env, &inst_name) {
|
||||
Ok(value) => value,
|
||||
Err(err) => {
|
||||
throw_exception(&mut env, &format!("Invalid instance name: {}", err));
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
let Some(local_port) = port_from_jint(&mut env, local_port, "local port") else {
|
||||
return 0;
|
||||
};
|
||||
let op = unsafe {
|
||||
data_plane_tcp_bind_start(
|
||||
inst_name.as_ptr(),
|
||||
local_port,
|
||||
timeout_from_jlong(timeout_ms),
|
||||
)
|
||||
};
|
||||
if op == 0 {
|
||||
throw_last(&mut env);
|
||||
}
|
||||
op as jlong
|
||||
}
|
||||
|
||||
pub(crate) fn tcp_bind_finish_jni(mut env: JNIEnv, _class: JClass, op: jlong) -> jobject {
|
||||
let mut ip: *const c_char = ptr::null();
|
||||
let mut port = 0u16;
|
||||
let handle = unsafe { data_plane_tcp_bind_finish(op as u64, &mut ip, &mut port) };
|
||||
if handle == 0 {
|
||||
throw_last(&mut env);
|
||||
return ptr::null_mut();
|
||||
}
|
||||
close_tcp_listener_on_null(
|
||||
new_handle_addr_result(
|
||||
&mut env,
|
||||
TCP_BIND_RESULT_CLASS,
|
||||
handle,
|
||||
unsafe { take_ffi_string(ip) },
|
||||
port,
|
||||
),
|
||||
handle,
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn tcp_accept_start_jni(
|
||||
mut env: JNIEnv,
|
||||
_class: JClass,
|
||||
handle: jlong,
|
||||
timeout_ms: jlong,
|
||||
) -> jlong {
|
||||
let op = unsafe { data_plane_tcp_accept_start(handle as u64, timeout_from_jlong(timeout_ms)) };
|
||||
if op == 0 {
|
||||
throw_last(&mut env);
|
||||
}
|
||||
op as jlong
|
||||
}
|
||||
|
||||
pub(crate) fn tcp_accept_finish_jni(mut env: JNIEnv, _class: JClass, op: jlong) -> jobject {
|
||||
let mut local_ip: *const c_char = ptr::null();
|
||||
let mut local_port = 0u16;
|
||||
let mut peer_ip: *const c_char = ptr::null();
|
||||
let mut peer_port = 0u16;
|
||||
let handle = unsafe {
|
||||
data_plane_tcp_accept_finish(
|
||||
op as u64,
|
||||
&mut local_ip,
|
||||
&mut local_port,
|
||||
&mut peer_ip,
|
||||
&mut peer_port,
|
||||
)
|
||||
};
|
||||
if handle == 0 {
|
||||
throw_last(&mut env);
|
||||
return ptr::null_mut();
|
||||
}
|
||||
let Some(local_addr) =
|
||||
new_socket_addr(&mut env, unsafe { take_ffi_string(local_ip) }, local_port)
|
||||
else {
|
||||
free_string(peer_ip);
|
||||
let _ = data_plane_tcp_close(handle);
|
||||
return ptr::null_mut();
|
||||
};
|
||||
let Some(peer_addr) = new_socket_addr(&mut env, unsafe { take_ffi_string(peer_ip) }, peer_port)
|
||||
else {
|
||||
let _ = data_plane_tcp_close(handle);
|
||||
return ptr::null_mut();
|
||||
};
|
||||
let class = match env.find_class(TCP_ACCEPT_RESULT_CLASS) {
|
||||
Ok(class) => class,
|
||||
Err(err) => {
|
||||
throw_exception(
|
||||
&mut env,
|
||||
&format!("Failed to find accept result class: {:?}", err),
|
||||
);
|
||||
let _ = data_plane_tcp_close(handle);
|
||||
return ptr::null_mut();
|
||||
}
|
||||
};
|
||||
let sig = format!("(JL{};L{};)V", SOCKET_ADDR_CLASS, SOCKET_ADDR_CLASS);
|
||||
let result = match env.new_object(
|
||||
class,
|
||||
sig.as_str(),
|
||||
&[
|
||||
JValue::Long(handle as jlong),
|
||||
JValue::Object(&local_addr),
|
||||
JValue::Object(&peer_addr),
|
||||
],
|
||||
) {
|
||||
Ok(result) => result.into_raw(),
|
||||
Err(err) => {
|
||||
throw_exception(
|
||||
&mut env,
|
||||
&format!("Failed to create accept result: {:?}", err),
|
||||
);
|
||||
ptr::null_mut()
|
||||
}
|
||||
};
|
||||
close_tcp_stream_on_null(result, handle)
|
||||
}
|
||||
|
||||
pub(crate) fn tcp_read_start_jni(
|
||||
mut env: JNIEnv,
|
||||
_class: JClass,
|
||||
handle: jlong,
|
||||
max_len: jint,
|
||||
timeout_ms: jlong,
|
||||
) -> jlong {
|
||||
let Some(max_len) = len_from_jint(&mut env, max_len, "max length") else {
|
||||
return 0;
|
||||
};
|
||||
let op = unsafe {
|
||||
data_plane_tcp_read_start(handle as u64, max_len, timeout_from_jlong(timeout_ms))
|
||||
};
|
||||
if op == 0 {
|
||||
throw_last(&mut env);
|
||||
}
|
||||
op as jlong
|
||||
}
|
||||
|
||||
pub(crate) fn tcp_read_finish_jni(mut env: JNIEnv, _class: JClass, op: jlong) -> jobject {
|
||||
let mut ptr: *const u8 = ptr::null();
|
||||
let mut len = 0u32;
|
||||
let ret = unsafe { data_plane_tcp_read_finish(op as u64, &mut ptr, &mut len) };
|
||||
if ret < 0 {
|
||||
throw_last(&mut env);
|
||||
return ptr::null_mut();
|
||||
}
|
||||
let bytes = read_owned_bytes(ptr, len);
|
||||
let array = match env.byte_array_from_slice(&bytes) {
|
||||
Ok(array) => array,
|
||||
Err(err) => {
|
||||
throw_exception(&mut env, &format!("Failed to create byte array: {:?}", err));
|
||||
return ptr::null_mut();
|
||||
}
|
||||
};
|
||||
let class = match env.find_class(TCP_READ_RESULT_CLASS) {
|
||||
Ok(class) => class,
|
||||
Err(err) => {
|
||||
throw_exception(
|
||||
&mut env,
|
||||
&format!("Failed to find read result class: {:?}", err),
|
||||
);
|
||||
return ptr::null_mut();
|
||||
}
|
||||
};
|
||||
match env.new_object(class, "([B)V", &[JValue::Object(&array)]) {
|
||||
Ok(result) => result.into_raw(),
|
||||
Err(err) => {
|
||||
throw_exception(
|
||||
&mut env,
|
||||
&format!("Failed to create read result: {:?}", err),
|
||||
);
|
||||
ptr::null_mut()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn tcp_write_start_jni(
|
||||
mut env: JNIEnv,
|
||||
_class: JClass,
|
||||
handle: jlong,
|
||||
data: JByteArray,
|
||||
timeout_ms: jlong,
|
||||
) -> jlong {
|
||||
let data = match env.convert_byte_array(&data) {
|
||||
Ok(data) => data,
|
||||
Err(err) => {
|
||||
throw_exception(&mut env, &format!("Invalid write buffer: {:?}", err));
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
let ptr = if data.is_empty() {
|
||||
ptr::null()
|
||||
} else {
|
||||
data.as_ptr()
|
||||
};
|
||||
let op = unsafe {
|
||||
data_plane_tcp_write_start(
|
||||
handle as u64,
|
||||
ptr,
|
||||
data.len() as u32,
|
||||
timeout_from_jlong(timeout_ms),
|
||||
)
|
||||
};
|
||||
if op == 0 {
|
||||
throw_last(&mut env);
|
||||
}
|
||||
op as jlong
|
||||
}
|
||||
|
||||
pub(crate) fn tcp_write_finish_jni(mut env: JNIEnv, _class: JClass, op: jlong) -> jint {
|
||||
let ret = data_plane_tcp_write_finish(op as u64);
|
||||
if ret < 0 {
|
||||
throw_last(&mut env);
|
||||
}
|
||||
ret
|
||||
}
|
||||
|
||||
pub(crate) fn udp_bind_start_jni(
|
||||
mut env: JNIEnv,
|
||||
_class: JClass,
|
||||
inst_name: JString,
|
||||
local_port: jint,
|
||||
timeout_ms: jlong,
|
||||
) -> jlong {
|
||||
let inst_name = match jstring_to_cstring(&mut env, &inst_name) {
|
||||
Ok(value) => value,
|
||||
Err(err) => {
|
||||
throw_exception(&mut env, &format!("Invalid instance name: {}", err));
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
let Some(local_port) = port_from_jint(&mut env, local_port, "local port") else {
|
||||
return 0;
|
||||
};
|
||||
let op = unsafe {
|
||||
data_plane_udp_bind_start(
|
||||
inst_name.as_ptr(),
|
||||
local_port,
|
||||
timeout_from_jlong(timeout_ms),
|
||||
)
|
||||
};
|
||||
if op == 0 {
|
||||
throw_last(&mut env);
|
||||
}
|
||||
op as jlong
|
||||
}
|
||||
|
||||
pub(crate) fn udp_bind_finish_jni(mut env: JNIEnv, _class: JClass, op: jlong) -> jobject {
|
||||
let mut ip: *const c_char = ptr::null();
|
||||
let mut port = 0u16;
|
||||
let handle = unsafe { data_plane_udp_bind_finish(op as u64, &mut ip, &mut port) };
|
||||
if handle == 0 {
|
||||
throw_last(&mut env);
|
||||
return ptr::null_mut();
|
||||
}
|
||||
close_udp_socket_on_null(
|
||||
new_handle_addr_result(
|
||||
&mut env,
|
||||
UDP_BIND_RESULT_CLASS,
|
||||
handle,
|
||||
unsafe { take_ffi_string(ip) },
|
||||
port,
|
||||
),
|
||||
handle,
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn udp_send_to_start_jni(
|
||||
mut env: JNIEnv,
|
||||
_class: JClass,
|
||||
handle: jlong,
|
||||
dst_ip: JString,
|
||||
dst_port: jint,
|
||||
data: JByteArray,
|
||||
timeout_ms: jlong,
|
||||
) -> jlong {
|
||||
let dst_ip = match jstring_to_cstring(&mut env, &dst_ip) {
|
||||
Ok(value) => value,
|
||||
Err(err) => {
|
||||
throw_exception(&mut env, &format!("Invalid destination IP: {}", err));
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
let Some(dst_port) = port_from_jint(&mut env, dst_port, "destination port") else {
|
||||
return 0;
|
||||
};
|
||||
let data = match env.convert_byte_array(&data) {
|
||||
Ok(data) => data,
|
||||
Err(err) => {
|
||||
throw_exception(&mut env, &format!("Invalid UDP send buffer: {:?}", err));
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
let ptr = if data.is_empty() {
|
||||
ptr::null()
|
||||
} else {
|
||||
data.as_ptr()
|
||||
};
|
||||
let op = unsafe {
|
||||
data_plane_udp_send_to_start(
|
||||
handle as u64,
|
||||
dst_ip.as_ptr(),
|
||||
dst_port,
|
||||
ptr,
|
||||
data.len() as u32,
|
||||
timeout_from_jlong(timeout_ms),
|
||||
)
|
||||
};
|
||||
if op == 0 {
|
||||
throw_last(&mut env);
|
||||
}
|
||||
op as jlong
|
||||
}
|
||||
|
||||
pub(crate) fn udp_send_to_finish_jni(mut env: JNIEnv, _class: JClass, op: jlong) -> jint {
|
||||
let ret = data_plane_udp_send_to_finish(op as u64);
|
||||
if ret < 0 {
|
||||
throw_last(&mut env);
|
||||
}
|
||||
ret
|
||||
}
|
||||
|
||||
pub(crate) fn udp_recv_from_start_jni(
|
||||
mut env: JNIEnv,
|
||||
_class: JClass,
|
||||
handle: jlong,
|
||||
max_len: jint,
|
||||
timeout_ms: jlong,
|
||||
) -> jlong {
|
||||
let Some(max_len) = len_from_jint(&mut env, max_len, "max length") else {
|
||||
return 0;
|
||||
};
|
||||
let op = unsafe {
|
||||
data_plane_udp_recv_from_start(handle as u64, max_len, timeout_from_jlong(timeout_ms))
|
||||
};
|
||||
if op == 0 {
|
||||
throw_last(&mut env);
|
||||
}
|
||||
op as jlong
|
||||
}
|
||||
|
||||
pub(crate) fn udp_recv_from_finish_jni(mut env: JNIEnv, _class: JClass, op: jlong) -> jobject {
|
||||
let mut ptr: *const u8 = ptr::null();
|
||||
let mut len = 0u32;
|
||||
let mut ip: *const c_char = ptr::null();
|
||||
let mut port = 0u16;
|
||||
let ret = unsafe {
|
||||
data_plane_udp_recv_from_finish(op as u64, &mut ptr, &mut len, &mut ip, &mut port)
|
||||
};
|
||||
if ret < 0 {
|
||||
throw_last(&mut env);
|
||||
return ptr::null_mut();
|
||||
}
|
||||
let bytes = read_owned_bytes(ptr, len);
|
||||
let array = match env.byte_array_from_slice(&bytes) {
|
||||
Ok(array) => array,
|
||||
Err(err) => {
|
||||
free_string(ip);
|
||||
throw_exception(&mut env, &format!("Failed to create byte array: {:?}", err));
|
||||
return ptr::null_mut();
|
||||
}
|
||||
};
|
||||
let Some(peer_addr) = new_socket_addr(&mut env, unsafe { take_ffi_string(ip) }, port) else {
|
||||
return ptr::null_mut();
|
||||
};
|
||||
let class = match env.find_class(UDP_RECV_RESULT_CLASS) {
|
||||
Ok(class) => class,
|
||||
Err(err) => {
|
||||
throw_exception(
|
||||
&mut env,
|
||||
&format!("Failed to find UDP recv result class: {:?}", err),
|
||||
);
|
||||
return ptr::null_mut();
|
||||
}
|
||||
};
|
||||
let sig = format!("([BL{};)V", SOCKET_ADDR_CLASS);
|
||||
match env.new_object(
|
||||
class,
|
||||
sig.as_str(),
|
||||
&[JValue::Object(&array), JValue::Object(&peer_addr)],
|
||||
) {
|
||||
Ok(result) => result.into_raw(),
|
||||
Err(err) => {
|
||||
throw_exception(
|
||||
&mut env,
|
||||
&format!("Failed to create UDP recv result: {:?}", err),
|
||||
);
|
||||
ptr::null_mut()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn tcp_close_jni(mut env: JNIEnv, _class: JClass, handle: jlong) -> jint {
|
||||
let ret = data_plane_tcp_close(handle as u64);
|
||||
if ret != 0 {
|
||||
throw_last(&mut env);
|
||||
}
|
||||
ret
|
||||
}
|
||||
|
||||
pub(crate) fn tcp_listener_close_jni(mut env: JNIEnv, _class: JClass, handle: jlong) -> jint {
|
||||
let ret = data_plane_tcp_listener_close(handle as u64);
|
||||
if ret != 0 {
|
||||
throw_last(&mut env);
|
||||
}
|
||||
ret
|
||||
}
|
||||
|
||||
pub(crate) fn udp_close_jni(mut env: JNIEnv, _class: JClass, handle: jlong) -> jint {
|
||||
let ret = data_plane_udp_close(handle as u64);
|
||||
if ret != 0 {
|
||||
throw_last(&mut env);
|
||||
}
|
||||
ret
|
||||
}
|
||||
@@ -19,17 +19,22 @@
|
||||
//!
|
||||
//! Error API:
|
||||
//! - `getLastError()`: return the latest FFI/JNI error string for the calling thread.
|
||||
//!
|
||||
//! Data-plane APIs:
|
||||
//! - `EasyTierDataPlaneJNI.*`: low-level async op-handle data-plane JNI.
|
||||
//! - `EasyTierJNI.dataPlane*`: compatibility exports for older callers.
|
||||
|
||||
mod callback;
|
||||
mod config_server_api;
|
||||
mod data_plane_api;
|
||||
mod error;
|
||||
mod logger;
|
||||
mod network_api;
|
||||
mod strings;
|
||||
|
||||
use jni::JNIEnv;
|
||||
use jni::objects::{JClass, JObject, JObjectArray, JString};
|
||||
use jni::sys::{jboolean, jint, jstring};
|
||||
use jni::objects::{JByteArray, JClass, JObject, JObjectArray, JString};
|
||||
use jni::sys::{jboolean, jint, jlong, jobject, jstring};
|
||||
|
||||
/// Attach a TUN file descriptor to an EasyTier network instance.
|
||||
///
|
||||
@@ -91,7 +96,7 @@ pub extern "system" fn Java_com_easytier_jni_EasyTierJNI_runNetworkInstance(
|
||||
/// `EasyTierJNI.retainNetworkInstance(instanceNames: Array<String>?): Int`
|
||||
///
|
||||
/// Passing `null` or an empty array stops all instances. Null elements inside a
|
||||
/// non-empty array are skipped. On failure this returns `-1` and throws
|
||||
/// non-empty array are invalid. On failure this returns `-1` and throws
|
||||
/// `RuntimeException`.
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "system" fn Java_com_easytier_jni_EasyTierJNI_retainNetworkInstance(
|
||||
@@ -201,3 +206,522 @@ pub extern "system" fn Java_com_easytier_jni_EasyTierJNI_isConfigServerClientCon
|
||||
logger::init();
|
||||
config_server_api::is_config_server_client_connected_jni(env, class)
|
||||
}
|
||||
|
||||
macro_rules! export_data_plane_jni {
|
||||
(
|
||||
$op_status:ident,
|
||||
$op_wait:ident,
|
||||
$op_cancel:ident,
|
||||
$op_free:ident,
|
||||
$tcp_connect_start:ident,
|
||||
$tcp_connect_finish:ident,
|
||||
$tcp_bind_start:ident,
|
||||
$tcp_bind_finish:ident,
|
||||
$tcp_accept_start:ident,
|
||||
$tcp_accept_finish:ident,
|
||||
$tcp_read_start:ident,
|
||||
$tcp_read_finish:ident,
|
||||
$tcp_write_start:ident,
|
||||
$tcp_write_finish:ident,
|
||||
$udp_bind_start:ident,
|
||||
$udp_bind_finish:ident,
|
||||
$udp_send_to_start:ident,
|
||||
$udp_send_to_finish:ident,
|
||||
$udp_recv_from_start:ident,
|
||||
$udp_recv_from_finish:ident,
|
||||
$tcp_close:ident,
|
||||
$tcp_listener_close:ident,
|
||||
$udp_close:ident
|
||||
) => {
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "system" fn $op_status(env: JNIEnv, class: JClass, handle: jlong) -> jint {
|
||||
logger::init();
|
||||
data_plane_api::async_op_status_jni(env, class, handle)
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "system" fn $op_wait(
|
||||
env: JNIEnv,
|
||||
class: JClass,
|
||||
handle: jlong,
|
||||
timeout_ms: jlong,
|
||||
) -> jint {
|
||||
logger::init();
|
||||
data_plane_api::async_op_wait_jni(env, class, handle, timeout_ms)
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "system" fn $op_cancel(env: JNIEnv, class: JClass, handle: jlong) -> jint {
|
||||
logger::init();
|
||||
data_plane_api::async_op_cancel_jni(env, class, handle)
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "system" fn $op_free(env: JNIEnv, class: JClass, handle: jlong) -> jint {
|
||||
logger::init();
|
||||
data_plane_api::async_op_free_jni(env, class, handle)
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "system" fn $tcp_connect_start(
|
||||
env: JNIEnv,
|
||||
class: JClass,
|
||||
inst_name: JString,
|
||||
dst_ip: JString,
|
||||
dst_port: jint,
|
||||
timeout_ms: jlong,
|
||||
) -> jlong {
|
||||
logger::init();
|
||||
data_plane_api::tcp_connect_start_jni(
|
||||
env, class, inst_name, dst_ip, dst_port, timeout_ms,
|
||||
)
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "system" fn $tcp_connect_finish(
|
||||
env: JNIEnv,
|
||||
class: JClass,
|
||||
op: jlong,
|
||||
) -> jobject {
|
||||
logger::init();
|
||||
data_plane_api::tcp_connect_finish_jni(env, class, op)
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "system" fn $tcp_bind_start(
|
||||
env: JNIEnv,
|
||||
class: JClass,
|
||||
inst_name: JString,
|
||||
local_port: jint,
|
||||
timeout_ms: jlong,
|
||||
) -> jlong {
|
||||
logger::init();
|
||||
data_plane_api::tcp_bind_start_jni(env, class, inst_name, local_port, timeout_ms)
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "system" fn $tcp_bind_finish(env: JNIEnv, class: JClass, op: jlong) -> jobject {
|
||||
logger::init();
|
||||
data_plane_api::tcp_bind_finish_jni(env, class, op)
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "system" fn $tcp_accept_start(
|
||||
env: JNIEnv,
|
||||
class: JClass,
|
||||
handle: jlong,
|
||||
timeout_ms: jlong,
|
||||
) -> jlong {
|
||||
logger::init();
|
||||
data_plane_api::tcp_accept_start_jni(env, class, handle, timeout_ms)
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "system" fn $tcp_accept_finish(
|
||||
env: JNIEnv,
|
||||
class: JClass,
|
||||
op: jlong,
|
||||
) -> jobject {
|
||||
logger::init();
|
||||
data_plane_api::tcp_accept_finish_jni(env, class, op)
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "system" fn $tcp_read_start(
|
||||
env: JNIEnv,
|
||||
class: JClass,
|
||||
handle: jlong,
|
||||
max_len: jint,
|
||||
timeout_ms: jlong,
|
||||
) -> jlong {
|
||||
logger::init();
|
||||
data_plane_api::tcp_read_start_jni(env, class, handle, max_len, timeout_ms)
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "system" fn $tcp_read_finish(env: JNIEnv, class: JClass, op: jlong) -> jobject {
|
||||
logger::init();
|
||||
data_plane_api::tcp_read_finish_jni(env, class, op)
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "system" fn $tcp_write_start(
|
||||
env: JNIEnv,
|
||||
class: JClass,
|
||||
handle: jlong,
|
||||
data: JByteArray,
|
||||
timeout_ms: jlong,
|
||||
) -> jlong {
|
||||
logger::init();
|
||||
data_plane_api::tcp_write_start_jni(env, class, handle, data, timeout_ms)
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "system" fn $tcp_write_finish(env: JNIEnv, class: JClass, op: jlong) -> jint {
|
||||
logger::init();
|
||||
data_plane_api::tcp_write_finish_jni(env, class, op)
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "system" fn $udp_bind_start(
|
||||
env: JNIEnv,
|
||||
class: JClass,
|
||||
inst_name: JString,
|
||||
local_port: jint,
|
||||
timeout_ms: jlong,
|
||||
) -> jlong {
|
||||
logger::init();
|
||||
data_plane_api::udp_bind_start_jni(env, class, inst_name, local_port, timeout_ms)
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "system" fn $udp_bind_finish(env: JNIEnv, class: JClass, op: jlong) -> jobject {
|
||||
logger::init();
|
||||
data_plane_api::udp_bind_finish_jni(env, class, op)
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "system" fn $udp_send_to_start(
|
||||
env: JNIEnv,
|
||||
class: JClass,
|
||||
handle: jlong,
|
||||
dst_ip: JString,
|
||||
dst_port: jint,
|
||||
data: JByteArray,
|
||||
timeout_ms: jlong,
|
||||
) -> jlong {
|
||||
logger::init();
|
||||
data_plane_api::udp_send_to_start_jni(
|
||||
env, class, handle, dst_ip, dst_port, data, timeout_ms,
|
||||
)
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "system" fn $udp_send_to_finish(env: JNIEnv, class: JClass, op: jlong) -> jint {
|
||||
logger::init();
|
||||
data_plane_api::udp_send_to_finish_jni(env, class, op)
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "system" fn $udp_recv_from_start(
|
||||
env: JNIEnv,
|
||||
class: JClass,
|
||||
handle: jlong,
|
||||
max_len: jint,
|
||||
timeout_ms: jlong,
|
||||
) -> jlong {
|
||||
logger::init();
|
||||
data_plane_api::udp_recv_from_start_jni(env, class, handle, max_len, timeout_ms)
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "system" fn $udp_recv_from_finish(
|
||||
env: JNIEnv,
|
||||
class: JClass,
|
||||
op: jlong,
|
||||
) -> jobject {
|
||||
logger::init();
|
||||
data_plane_api::udp_recv_from_finish_jni(env, class, op)
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "system" fn $tcp_close(env: JNIEnv, class: JClass, handle: jlong) -> jint {
|
||||
logger::init();
|
||||
data_plane_api::tcp_close_jni(env, class, handle)
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "system" fn $tcp_listener_close(
|
||||
env: JNIEnv,
|
||||
class: JClass,
|
||||
handle: jlong,
|
||||
) -> jint {
|
||||
logger::init();
|
||||
data_plane_api::tcp_listener_close_jni(env, class, handle)
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "system" fn $udp_close(env: JNIEnv, class: JClass, handle: jlong) -> jint {
|
||||
logger::init();
|
||||
data_plane_api::udp_close_jni(env, class, handle)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export_data_plane_jni!(
|
||||
Java_com_easytier_jni_EasyTierDataPlaneJNI_dataPlaneAsyncOpStatus,
|
||||
Java_com_easytier_jni_EasyTierDataPlaneJNI_dataPlaneAsyncOpWait,
|
||||
Java_com_easytier_jni_EasyTierDataPlaneJNI_dataPlaneAsyncOpCancel,
|
||||
Java_com_easytier_jni_EasyTierDataPlaneJNI_dataPlaneAsyncOpFree,
|
||||
Java_com_easytier_jni_EasyTierDataPlaneJNI_dataPlaneTcpConnectStart,
|
||||
Java_com_easytier_jni_EasyTierDataPlaneJNI_dataPlaneTcpConnectFinish,
|
||||
Java_com_easytier_jni_EasyTierDataPlaneJNI_dataPlaneTcpBindStart,
|
||||
Java_com_easytier_jni_EasyTierDataPlaneJNI_dataPlaneTcpBindFinish,
|
||||
Java_com_easytier_jni_EasyTierDataPlaneJNI_dataPlaneTcpAcceptStart,
|
||||
Java_com_easytier_jni_EasyTierDataPlaneJNI_dataPlaneTcpAcceptFinish,
|
||||
Java_com_easytier_jni_EasyTierDataPlaneJNI_dataPlaneTcpReadStart,
|
||||
Java_com_easytier_jni_EasyTierDataPlaneJNI_dataPlaneTcpReadFinish,
|
||||
Java_com_easytier_jni_EasyTierDataPlaneJNI_dataPlaneTcpWriteStart,
|
||||
Java_com_easytier_jni_EasyTierDataPlaneJNI_dataPlaneTcpWriteFinish,
|
||||
Java_com_easytier_jni_EasyTierDataPlaneJNI_dataPlaneUdpBindStart,
|
||||
Java_com_easytier_jni_EasyTierDataPlaneJNI_dataPlaneUdpBindFinish,
|
||||
Java_com_easytier_jni_EasyTierDataPlaneJNI_dataPlaneUdpSendToStart,
|
||||
Java_com_easytier_jni_EasyTierDataPlaneJNI_dataPlaneUdpSendToFinish,
|
||||
Java_com_easytier_jni_EasyTierDataPlaneJNI_dataPlaneUdpRecvFromStart,
|
||||
Java_com_easytier_jni_EasyTierDataPlaneJNI_dataPlaneUdpRecvFromFinish,
|
||||
Java_com_easytier_jni_EasyTierDataPlaneJNI_dataPlaneTcpClose,
|
||||
Java_com_easytier_jni_EasyTierDataPlaneJNI_dataPlaneTcpListenerClose,
|
||||
Java_com_easytier_jni_EasyTierDataPlaneJNI_dataPlaneUdpClose
|
||||
);
|
||||
|
||||
// Compatibility exports for older Kotlin/Java callers that used EasyTierJNI
|
||||
// directly for data-plane operations.
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "system" fn Java_com_easytier_jni_EasyTierJNI_dataPlaneAsyncOpStatus(
|
||||
env: JNIEnv,
|
||||
class: JClass,
|
||||
handle: jlong,
|
||||
) -> jint {
|
||||
logger::init();
|
||||
data_plane_api::async_op_status_jni(env, class, handle)
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "system" fn Java_com_easytier_jni_EasyTierJNI_dataPlaneAsyncOpWait(
|
||||
env: JNIEnv,
|
||||
class: JClass,
|
||||
handle: jlong,
|
||||
timeout_ms: jlong,
|
||||
) -> jint {
|
||||
logger::init();
|
||||
data_plane_api::async_op_wait_jni(env, class, handle, timeout_ms)
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "system" fn Java_com_easytier_jni_EasyTierJNI_dataPlaneAsyncOpCancel(
|
||||
env: JNIEnv,
|
||||
class: JClass,
|
||||
handle: jlong,
|
||||
) -> jint {
|
||||
logger::init();
|
||||
data_plane_api::async_op_cancel_jni(env, class, handle)
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "system" fn Java_com_easytier_jni_EasyTierJNI_dataPlaneAsyncOpFree(
|
||||
env: JNIEnv,
|
||||
class: JClass,
|
||||
handle: jlong,
|
||||
) -> jint {
|
||||
logger::init();
|
||||
data_plane_api::async_op_free_jni(env, class, handle)
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "system" fn Java_com_easytier_jni_EasyTierJNI_dataPlaneTcpConnectStart(
|
||||
env: JNIEnv,
|
||||
class: JClass,
|
||||
inst_name: JString,
|
||||
dst_ip: JString,
|
||||
dst_port: jint,
|
||||
timeout_ms: jlong,
|
||||
) -> jlong {
|
||||
logger::init();
|
||||
data_plane_api::tcp_connect_start_jni(env, class, inst_name, dst_ip, dst_port, timeout_ms)
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "system" fn Java_com_easytier_jni_EasyTierJNI_dataPlaneTcpConnectFinish(
|
||||
env: JNIEnv,
|
||||
class: JClass,
|
||||
op: jlong,
|
||||
) -> jobject {
|
||||
logger::init();
|
||||
data_plane_api::tcp_connect_finish_jni(env, class, op)
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "system" fn Java_com_easytier_jni_EasyTierJNI_dataPlaneTcpBindStart(
|
||||
env: JNIEnv,
|
||||
class: JClass,
|
||||
inst_name: JString,
|
||||
local_port: jint,
|
||||
timeout_ms: jlong,
|
||||
) -> jlong {
|
||||
logger::init();
|
||||
data_plane_api::tcp_bind_start_jni(env, class, inst_name, local_port, timeout_ms)
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "system" fn Java_com_easytier_jni_EasyTierJNI_dataPlaneTcpBindFinish(
|
||||
env: JNIEnv,
|
||||
class: JClass,
|
||||
op: jlong,
|
||||
) -> jobject {
|
||||
logger::init();
|
||||
data_plane_api::tcp_bind_finish_jni(env, class, op)
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "system" fn Java_com_easytier_jni_EasyTierJNI_dataPlaneTcpAcceptStart(
|
||||
env: JNIEnv,
|
||||
class: JClass,
|
||||
handle: jlong,
|
||||
timeout_ms: jlong,
|
||||
) -> jlong {
|
||||
logger::init();
|
||||
data_plane_api::tcp_accept_start_jni(env, class, handle, timeout_ms)
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "system" fn Java_com_easytier_jni_EasyTierJNI_dataPlaneTcpAcceptFinish(
|
||||
env: JNIEnv,
|
||||
class: JClass,
|
||||
op: jlong,
|
||||
) -> jobject {
|
||||
logger::init();
|
||||
data_plane_api::tcp_accept_finish_jni(env, class, op)
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "system" fn Java_com_easytier_jni_EasyTierJNI_dataPlaneTcpReadStart(
|
||||
env: JNIEnv,
|
||||
class: JClass,
|
||||
handle: jlong,
|
||||
max_len: jint,
|
||||
timeout_ms: jlong,
|
||||
) -> jlong {
|
||||
logger::init();
|
||||
data_plane_api::tcp_read_start_jni(env, class, handle, max_len, timeout_ms)
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "system" fn Java_com_easytier_jni_EasyTierJNI_dataPlaneTcpReadFinish(
|
||||
env: JNIEnv,
|
||||
class: JClass,
|
||||
op: jlong,
|
||||
) -> jobject {
|
||||
logger::init();
|
||||
data_plane_api::tcp_read_finish_jni(env, class, op)
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "system" fn Java_com_easytier_jni_EasyTierJNI_dataPlaneTcpWriteStart(
|
||||
env: JNIEnv,
|
||||
class: JClass,
|
||||
handle: jlong,
|
||||
data: JByteArray,
|
||||
timeout_ms: jlong,
|
||||
) -> jlong {
|
||||
logger::init();
|
||||
data_plane_api::tcp_write_start_jni(env, class, handle, data, timeout_ms)
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "system" fn Java_com_easytier_jni_EasyTierJNI_dataPlaneTcpWriteFinish(
|
||||
env: JNIEnv,
|
||||
class: JClass,
|
||||
op: jlong,
|
||||
) -> jint {
|
||||
logger::init();
|
||||
data_plane_api::tcp_write_finish_jni(env, class, op)
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "system" fn Java_com_easytier_jni_EasyTierJNI_dataPlaneUdpBindStart(
|
||||
env: JNIEnv,
|
||||
class: JClass,
|
||||
inst_name: JString,
|
||||
local_port: jint,
|
||||
timeout_ms: jlong,
|
||||
) -> jlong {
|
||||
logger::init();
|
||||
data_plane_api::udp_bind_start_jni(env, class, inst_name, local_port, timeout_ms)
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "system" fn Java_com_easytier_jni_EasyTierJNI_dataPlaneUdpBindFinish(
|
||||
env: JNIEnv,
|
||||
class: JClass,
|
||||
op: jlong,
|
||||
) -> jobject {
|
||||
logger::init();
|
||||
data_plane_api::udp_bind_finish_jni(env, class, op)
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "system" fn Java_com_easytier_jni_EasyTierJNI_dataPlaneUdpSendToStart(
|
||||
env: JNIEnv,
|
||||
class: JClass,
|
||||
handle: jlong,
|
||||
dst_ip: JString,
|
||||
dst_port: jint,
|
||||
data: JByteArray,
|
||||
timeout_ms: jlong,
|
||||
) -> jlong {
|
||||
logger::init();
|
||||
data_plane_api::udp_send_to_start_jni(env, class, handle, dst_ip, dst_port, data, timeout_ms)
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "system" fn Java_com_easytier_jni_EasyTierJNI_dataPlaneUdpSendToFinish(
|
||||
env: JNIEnv,
|
||||
class: JClass,
|
||||
op: jlong,
|
||||
) -> jint {
|
||||
logger::init();
|
||||
data_plane_api::udp_send_to_finish_jni(env, class, op)
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "system" fn Java_com_easytier_jni_EasyTierJNI_dataPlaneUdpRecvFromStart(
|
||||
env: JNIEnv,
|
||||
class: JClass,
|
||||
handle: jlong,
|
||||
max_len: jint,
|
||||
timeout_ms: jlong,
|
||||
) -> jlong {
|
||||
logger::init();
|
||||
data_plane_api::udp_recv_from_start_jni(env, class, handle, max_len, timeout_ms)
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "system" fn Java_com_easytier_jni_EasyTierJNI_dataPlaneUdpRecvFromFinish(
|
||||
env: JNIEnv,
|
||||
class: JClass,
|
||||
op: jlong,
|
||||
) -> jobject {
|
||||
logger::init();
|
||||
data_plane_api::udp_recv_from_finish_jni(env, class, op)
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "system" fn Java_com_easytier_jni_EasyTierJNI_dataPlaneTcpClose(
|
||||
env: JNIEnv,
|
||||
class: JClass,
|
||||
handle: jlong,
|
||||
) -> jint {
|
||||
logger::init();
|
||||
data_plane_api::tcp_close_jni(env, class, handle)
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "system" fn Java_com_easytier_jni_EasyTierJNI_dataPlaneTcpListenerClose(
|
||||
env: JNIEnv,
|
||||
class: JClass,
|
||||
handle: jlong,
|
||||
) -> jint {
|
||||
logger::init();
|
||||
data_plane_api::tcp_listener_close_jni(env, class, handle)
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "system" fn Java_com_easytier_jni_EasyTierJNI_dataPlaneUdpClose(
|
||||
env: JNIEnv,
|
||||
class: JClass,
|
||||
handle: jlong,
|
||||
) -> jint {
|
||||
logger::init();
|
||||
data_plane_api::udp_close_jni(env, class, handle)
|
||||
}
|
||||
|
||||
@@ -113,7 +113,11 @@ pub(crate) fn retain_network_instance_jni(
|
||||
};
|
||||
|
||||
if java_string.is_null() {
|
||||
continue;
|
||||
throw_exception(
|
||||
&mut env,
|
||||
&format!("Invalid instance name at index {}: null", i),
|
||||
);
|
||||
return -1;
|
||||
}
|
||||
|
||||
let jstring = JString::from(java_string);
|
||||
|
||||
Reference in New Issue
Block a user