refactor(core): separate portable core from native runtime (#2451)

Create easytier-core as the portable owner of configuration,
connectivity, tunnels, peer and routing state, gateways, management,
the data plane, and instance lifecycle. Keep operating-system
integration, native protocol engines, process startup, and presentation
in easytier behind explicit Host capability adapters.

Create easytier-proto to own schemas, generated RPC types, descriptors,
and feature-scoped protocol slices. Remove runtime protobuf reflection
from core while preserving unknown route-peer fields across forwarding.

Normalize instance construction through CoreInstance, CoreHostAdapters,
CoreProcessRuntime, and InstanceManager. Make the runtime config store
the only authoritative mutable configuration after startup.

Move the portable TCP/UDP data plane into core and extract a generic
OperationBroker for completion, cancellation, disposal, and capacity
accounting. Expose the session-based FFI v2 completion API and keep the
WASI guest ABI, wire schemas, and adapters with core.

Migrate CLI, GUI, web, FFI, Android JNI, OHOS, uptime, and mobile
consumers to the shared manager and core state. Add explicit user/web
config ownership and revision-aware web reconciliation.

Preserve configuration, wire, and management behavior while fixing
regressions discovered by the full platform and integration matrix:

- inherit advertised relay capabilities in foreign networks;
- refresh OSPF peer state immediately after runtime config changes;
- restore CLI GlobalCtx event output without forcing GUI logging;
- retain legacy encryption names and standalone RPC tunnel metadata;
- restore ICMP host composition and fragmented UDP handling;
- use portable 64-bit atomics on 32-bit MIPS targets; and
- retain discarded operations until late cancellation completes.

Validate the refactor across 45 GitHub checks, including Linux, macOS,
Windows, FreeBSD, web, GUI, Android, OHOS, feature profiles, and
three-node and subnet-proxy integration tests.

BREAKING CHANGE: internal Rust module paths are not preserved. Legacy
native data-plane APIs are replaced by the session-based FFI v2 API.
The dedicated Android data-plane wrapper is removed.
This commit is contained in:
KKRainbow
2026-07-26 15:41:55 +08:00
committed by GitHub
parent 346f32d3d0
commit 021f523431
523 changed files with 102785 additions and 67067 deletions
@@ -14,4 +14,4 @@ android_logger = "0.13"
serde = { version = "1.0.220", features = ["derive"] }
serde_json = "1.0"
easytier = { path = "../../easytier" }
easytier-ffi = { path = "../easytier-ffi", default-features = false, features = ["ffi-dataplane"] }
easytier-ffi = { path = "../easytier-ffi", default-features = false }
@@ -1,7 +1,6 @@
{
global:
Java_com_easytier_jni_EasyTierJNI_*;
Java_com_easytier_jni_EasyTierDataPlaneJNI_*;
local:
*;
};
@@ -1,451 +0,0 @@
package com.easytier.jni
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.currentCoroutineContext
import kotlinx.coroutines.ensureActive
import kotlinx.coroutines.withContext
/**
* EasyTier data-plane API for Android.
*
* Dataplane APIs do not create or start an EasyTier instance by themselves.
* Start an instance with [EasyTierJNI.runNetworkInstance] first, then pass the
* same `instanceName` to [EasyTierDataPlane.tcpConnect],
* [EasyTierDataPlane.tcpBind], or [EasyTierDataPlane.udpBind]. If that instance
* is not running, the native start call fails and the coroutine wrapper throws
* the last EasyTier FFI error.
*
* Typical setup:
* ```
* val instanceName = "android-dataplane-demo"
* val config = """
* instance_name = "$instanceName"
* ipv4 = "10.144.0.1"
* listeners = ["tcp://0.0.0.0:11010"]
*
* [network_identity]
* network_name = "android-dataplane-demo"
* network_secret = "replace-with-a-real-secret"
*
* [[peer]]
* uri = "tcp://peer.example.com:11010"
*
* [flags]
* no_tun = true
* bind_device = false
* """.trimIndent()
*
* EasyTierJNI.runNetworkInstance(config)
* ```
*
* After the instance is running, most callers should use [EasyTierDataPlane]
* and the socket/stream classes below. [EasyTierDataPlaneJNI] is the low-level
* native op-handle ABI used by the coroutine wrappers.
*
* TCP client usage:
* ```
* val stream = EasyTierDataPlane.tcpConnect(instanceName, "10.144.0.2", 8080, 5_000)
* try {
* stream.write("ping".toByteArray(), 5_000)
* val reply = stream.read(4096, 5_000)
* } finally {
* stream.close()
* }
* ```
*
* TCP server usage:
* ```
* val listener = EasyTierDataPlane.tcpBind(instanceName, 8080, 5_000)
* try {
* val stream = listener.accept(30_000)
* try {
* stream.write(stream.read(4096, 5_000), 5_000)
* } finally {
* stream.close()
* }
* } finally {
* listener.close()
* }
* ```
*
* UDP usage:
* ```
* val socket = EasyTierDataPlane.udpBind(instanceName, 0, 5_000)
* try {
* socket.sendTo("10.144.0.2", 9000, "ping".toByteArray(), 5_000)
* val packet = socket.recvFrom(4096, 5_000)
* } finally {
* socket.close()
* }
* ```
*
* Operation model:
* - Each suspend function starts one native async op, waits on Dispatchers.IO,
* then consumes the op with the matching finish call.
* - Coroutine cancellation cancels and frees the native op.
* - Returned stream/listener/socket handles must be closed by the caller.
* - Input ByteArray data is copied by the native start call; output data is
* copied into Kotlin ByteArray before the native buffer is freed.
*/
/** Data-plane IPv4/port pair returned by EasyTier FFI. */
data class DataPlaneSocketAddress(val ip: String, val port: Int)
/** Result of a completed TCP connect op. */
data class DataPlaneTcpConnectResult(val handle: Long, val localAddress: DataPlaneSocketAddress)
/** Result of a completed TCP bind op. */
data class DataPlaneTcpBindResult(val handle: Long, val localAddress: DataPlaneSocketAddress)
/** Result of a completed TCP accept op. */
data class DataPlaneTcpAcceptResult(
val handle: Long,
val localAddress: DataPlaneSocketAddress,
val peerAddress: DataPlaneSocketAddress
)
/** Result of a completed TCP read op. */
data class DataPlaneTcpReadResult(val data: ByteArray)
/** Result of a completed UDP bind op. */
data class DataPlaneUdpBindResult(val handle: Long, val localAddress: DataPlaneSocketAddress)
/** Result of a completed UDP recv_from op. */
data class DataPlaneUdpRecvResult(
val data: ByteArray,
val peerAddress: DataPlaneSocketAddress
)
/** TCP data-plane stream handle. Call [close] when the stream is no longer needed. */
class DataPlaneTcpStream(
val handle: Long,
val localAddress: DataPlaneSocketAddress? = null,
val peerAddress: DataPlaneSocketAddress? = null
) {
/** Read up to [maxLength] bytes, waiting at most [timeoutMs] in native code. */
suspend fun read(maxLength: Int, timeoutMs: Long): ByteArray =
EasyTierDataPlane.tcpRead(this, maxLength, timeoutMs)
/** Write [data], waiting at most [timeoutMs] in native code. */
suspend fun write(data: ByteArray, timeoutMs: Long): Int =
EasyTierDataPlane.tcpWrite(this, data, timeoutMs)
/** Close the native TCP stream handle. */
fun close(): Int = EasyTierDataPlaneJNI.dataPlaneTcpClose(handle)
}
/** TCP data-plane listener handle. Call [close] when the listener is no longer needed. */
class DataPlaneTcpListener(val handle: Long, val localAddress: DataPlaneSocketAddress) {
/** Accept one TCP data-plane stream. */
suspend fun accept(timeoutMs: Long): DataPlaneTcpStream =
EasyTierDataPlane.tcpAccept(this, timeoutMs)
/** Close the native TCP listener handle. */
fun close(): Int = EasyTierDataPlaneJNI.dataPlaneTcpListenerClose(handle)
}
/** UDP data-plane socket handle. Call [close] when the socket is no longer needed. */
class DataPlaneUdpSocket(val handle: Long, val localAddress: DataPlaneSocketAddress) {
/** Send one UDP datagram to [dstIp]:[dstPort]. */
suspend fun sendTo(
dstIp: String,
dstPort: Int,
data: ByteArray,
timeoutMs: Long
): Int = EasyTierDataPlane.udpSendTo(this, dstIp, dstPort, data, timeoutMs)
/** Receive one UDP datagram and its peer address. */
suspend fun recvFrom(maxLength: Int, timeoutMs: Long): DataPlaneUdpRecvResult =
EasyTierDataPlane.udpRecvFrom(this, maxLength, timeoutMs)
/** Close the native UDP socket handle. */
fun close(): Int = EasyTierDataPlaneJNI.dataPlaneUdpClose(handle)
}
/**
* Low-level native data-plane JNI entry points.
*
* These functions mirror the Rust FFI op-handle ABI directly. They are exposed
* for completeness, but most Android callers should use [EasyTierDataPlane]
* instead so coroutine cancellation and op cleanup are handled consistently.
*/
object EasyTierDataPlaneJNI {
init {
System.loadLibrary("easytier_android_jni")
}
@JvmStatic external fun dataPlaneAsyncOpStatus(handle: Long): Int
@JvmStatic external fun dataPlaneAsyncOpWait(handle: Long, timeoutMs: Long): Int
@JvmStatic external fun dataPlaneAsyncOpCancel(handle: Long): Int
@JvmStatic external fun dataPlaneAsyncOpFree(handle: Long): Int
@JvmStatic
external fun dataPlaneTcpConnectStart(
instanceName: String,
dstIp: String,
dstPort: Int,
timeoutMs: Long
): Long
@JvmStatic external fun dataPlaneTcpConnectFinish(op: Long): DataPlaneTcpConnectResult?
@JvmStatic
external fun dataPlaneTcpBindStart(
instanceName: String,
localPort: Int,
timeoutMs: Long
): Long
@JvmStatic external fun dataPlaneTcpBindFinish(op: Long): DataPlaneTcpBindResult?
@JvmStatic external fun dataPlaneTcpAcceptStart(handle: Long, timeoutMs: Long): Long
@JvmStatic external fun dataPlaneTcpAcceptFinish(op: Long): DataPlaneTcpAcceptResult?
@JvmStatic external fun dataPlaneTcpReadStart(handle: Long, maxLength: Int, timeoutMs: Long): Long
@JvmStatic external fun dataPlaneTcpReadFinish(op: Long): DataPlaneTcpReadResult?
@JvmStatic external fun dataPlaneTcpWriteStart(handle: Long, data: ByteArray, timeoutMs: Long): Long
@JvmStatic external fun dataPlaneTcpWriteFinish(op: Long): Int
@JvmStatic
external fun dataPlaneUdpBindStart(
instanceName: String,
localPort: Int,
timeoutMs: Long
): Long
@JvmStatic external fun dataPlaneUdpBindFinish(op: Long): DataPlaneUdpBindResult?
@JvmStatic
external fun dataPlaneUdpSendToStart(
handle: Long,
dstIp: String,
dstPort: Int,
data: ByteArray,
timeoutMs: Long
): Long
@JvmStatic external fun dataPlaneUdpSendToFinish(op: Long): Int
@JvmStatic external fun dataPlaneUdpRecvFromStart(handle: Long, maxLength: Int, timeoutMs: Long): Long
@JvmStatic external fun dataPlaneUdpRecvFromFinish(op: Long): DataPlaneUdpRecvResult?
@JvmStatic external fun dataPlaneTcpClose(handle: Long): Int
@JvmStatic external fun dataPlaneTcpListenerClose(handle: Long): Int
@JvmStatic external fun dataPlaneUdpClose(handle: Long): Int
}
/** Coroutine-friendly Android data-plane API. */
object EasyTierDataPlane {
private const val DATA_PLANE_OP_PENDING = 0
private const val DATA_PLANE_OP_READY = 1
private const val DATA_PLANE_OP_FAILED = -1
private const val DATA_PLANE_OP_INVALID = -2
private const val DATA_PLANE_WAIT_SLICE_MS = 50L
/** Connect to a TCP endpoint through the named EasyTier instance. */
@JvmStatic
suspend fun tcpConnect(
instanceName: String,
dstIp: String,
dstPort: Int,
timeoutMs: Long
): DataPlaneTcpStream {
val op =
requireOp(
EasyTierDataPlaneJNI.dataPlaneTcpConnectStart(
instanceName,
dstIp,
dstPort,
timeoutMs
)
)
val result = awaitOp(op) {
EasyTierDataPlaneJNI.dataPlaneTcpConnectFinish(it) ?: throw lastDataPlaneException()
}
return DataPlaneTcpStream(result.handle, result.localAddress)
}
/** Bind a TCP data-plane listener on [localPort]. Port 0 asks EasyTier to allocate one. */
@JvmStatic
suspend fun tcpBind(
instanceName: String,
localPort: Int,
timeoutMs: Long
): DataPlaneTcpListener {
val op =
requireOp(
EasyTierDataPlaneJNI.dataPlaneTcpBindStart(
instanceName,
localPort,
timeoutMs
)
)
val result = awaitOp(op) {
EasyTierDataPlaneJNI.dataPlaneTcpBindFinish(it) ?: throw lastDataPlaneException()
}
return DataPlaneTcpListener(result.handle, result.localAddress)
}
/** Accept one TCP stream from [listener]. */
@JvmStatic
suspend fun tcpAccept(listener: DataPlaneTcpListener, timeoutMs: Long): DataPlaneTcpStream {
val op =
requireOp(
EasyTierDataPlaneJNI.dataPlaneTcpAcceptStart(listener.handle, timeoutMs)
)
val result = awaitOp(op) {
EasyTierDataPlaneJNI.dataPlaneTcpAcceptFinish(it) ?: throw lastDataPlaneException()
}
return DataPlaneTcpStream(result.handle, result.localAddress, result.peerAddress)
}
/** Read up to [maxLength] bytes from [stream]. */
@JvmStatic
suspend fun tcpRead(
stream: DataPlaneTcpStream,
maxLength: Int,
timeoutMs: Long
): ByteArray {
val op =
requireOp(
EasyTierDataPlaneJNI.dataPlaneTcpReadStart(
stream.handle,
maxLength,
timeoutMs
)
)
return awaitOp(op) {
EasyTierDataPlaneJNI.dataPlaneTcpReadFinish(it)?.data
?: throw lastDataPlaneException()
}
}
/** Write [data] to [stream]. */
@JvmStatic
suspend fun tcpWrite(stream: DataPlaneTcpStream, data: ByteArray, timeoutMs: Long): Int {
val op =
requireOp(
EasyTierDataPlaneJNI.dataPlaneTcpWriteStart(
stream.handle,
data,
timeoutMs
)
)
return awaitOp(op) { EasyTierDataPlaneJNI.dataPlaneTcpWriteFinish(it) }
}
/** Bind a UDP data-plane socket on [localPort]. Port 0 asks EasyTier to allocate one. */
@JvmStatic
suspend fun udpBind(
instanceName: String,
localPort: Int,
timeoutMs: Long
): DataPlaneUdpSocket {
val op =
requireOp(
EasyTierDataPlaneJNI.dataPlaneUdpBindStart(
instanceName,
localPort,
timeoutMs
)
)
val result = awaitOp(op) {
EasyTierDataPlaneJNI.dataPlaneUdpBindFinish(it) ?: throw lastDataPlaneException()
}
return DataPlaneUdpSocket(result.handle, result.localAddress)
}
/** Send one UDP datagram through [socket]. */
@JvmStatic
suspend fun udpSendTo(
socket: DataPlaneUdpSocket,
dstIp: String,
dstPort: Int,
data: ByteArray,
timeoutMs: Long
): Int {
val op =
requireOp(
EasyTierDataPlaneJNI.dataPlaneUdpSendToStart(
socket.handle,
dstIp,
dstPort,
data,
timeoutMs
)
)
return awaitOp(op) { EasyTierDataPlaneJNI.dataPlaneUdpSendToFinish(it) }
}
/** Receive one UDP datagram through [socket]. */
@JvmStatic
suspend fun udpRecvFrom(
socket: DataPlaneUdpSocket,
maxLength: Int,
timeoutMs: Long
): DataPlaneUdpRecvResult {
val op =
requireOp(
EasyTierDataPlaneJNI.dataPlaneUdpRecvFromStart(
socket.handle,
maxLength,
timeoutMs
)
)
return awaitOp(op) {
EasyTierDataPlaneJNI.dataPlaneUdpRecvFromFinish(it) ?: throw lastDataPlaneException()
}
}
private fun requireOp(op: Long): Long {
if (op == 0L) {
throw lastDataPlaneException()
}
return op
}
private suspend fun <T> awaitOp(op: Long, finish: (Long) -> T): T =
withContext(Dispatchers.IO) {
var consumed = false
try {
awaitReady(op)
val result = finish(op)
consumed = true
result
} catch (e: CancellationException) {
EasyTierDataPlaneJNI.dataPlaneAsyncOpCancel(op)
throw e
} finally {
if (!consumed) {
EasyTierDataPlaneJNI.dataPlaneAsyncOpFree(op)
}
}
}
private suspend fun awaitReady(op: Long) {
while (true) {
currentCoroutineContext().ensureActive()
when (EasyTierDataPlaneJNI.dataPlaneAsyncOpWait(op, DATA_PLANE_WAIT_SLICE_MS)) {
DATA_PLANE_OP_READY, DATA_PLANE_OP_FAILED -> return
DATA_PLANE_OP_PENDING -> Unit
DATA_PLANE_OP_INVALID -> throw RuntimeException("Data-plane async operation is invalid")
else -> throw RuntimeException("Unknown data-plane async operation status")
}
}
}
private fun lastDataPlaneException(): RuntimeException {
return RuntimeException(EasyTierJNI.getLastError() ?: "EasyTier data-plane call failed")
}
}
@@ -1,673 +0,0 @@
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
}
@@ -22,13 +22,8 @@
//! 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 json_rpc_api;
mod logger;
@@ -36,8 +31,8 @@ mod network_api;
mod strings;
use jni::JNIEnv;
use jni::objects::{JByteArray, JClass, JObject, JObjectArray, JString};
use jni::sys::{jboolean, jint, jlong, jobject, jstring};
use jni::objects::{JClass, JObject, JObjectArray, JString};
use jni::sys::{jboolean, jint, jstring};
/// Attach a TUN file descriptor to an EasyTier network instance.
///
@@ -256,522 +251,3 @@ 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)
}