aboutsummaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
author1992414357@qq.com <1992414357@qq.com>2025-06-16 05:39:08 +0800
committer1992414357@qq.com <1992414357@qq.com>2025-06-16 05:39:08 +0800
commit2f12f40bdccc8911a25f6e059288ee5e51948001 (patch)
tree2a851cb6ffde53f8ee4378e85f3c65eca92ff8a8 /core
parent05f078b19471d2d05c71613afd42bab8df522b00 (diff)
Add CBindings of TcpNetworkService
Diffstat (limited to 'core')
-rw-r--r--core/bindings/lang/clang/configures/nogamepads_data.toml1
-rw-r--r--core/bindings/lang/clang/headers/nogamepads_data.h115
-rw-r--r--core/bindings/lang/clang/src/data/ngpd_controller.rs14
-rw-r--r--core/bindings/lang/clang/src/data/ngpd_game.rs74
-rw-r--r--core/bindings/lang/clang/src/service/mod.rs3
-rw-r--r--core/bindings/lang/clang/src/service/ngpd_tcp_service.rs305
6 files changed, 473 insertions, 39 deletions
diff --git a/core/bindings/lang/clang/configures/nogamepads_data.toml b/core/bindings/lang/clang/configures/nogamepads_data.toml
index a408296..9feb4a9 100644
--- a/core/bindings/lang/clang/configures/nogamepads_data.toml
+++ b/core/bindings/lang/clang/configures/nogamepads_data.toml
@@ -15,4 +15,5 @@ include = [
"ngpd_game",
"ngpd_service_types",
+ "ngpd_tcp_service"
] \ No newline at end of file
diff --git a/core/bindings/lang/clang/headers/nogamepads_data.h b/core/bindings/lang/clang/headers/nogamepads_data.h
index 8340bdd..dde4f43 100644
--- a/core/bindings/lang/clang/headers/nogamepads_data.h
+++ b/core/bindings/lang/clang/headers/nogamepads_data.h
@@ -203,6 +203,14 @@ typedef struct FfiPlayerList {
uintptr_t cap;
} FfiPlayerList;
+typedef struct FfiTcpClientService {
+ void *_0;
+} FfiTcpClientService;
+
+typedef struct FfiTcpServerService {
+ void *_0;
+} FfiTcpServerService;
+
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
@@ -515,6 +523,11 @@ struct FfiPlayerList game_runtime_get_online_list(struct FfiGameRuntime *runtime
struct FfiPlayerList game_runtime_get_banned_list(struct FfiGameRuntime *runtime);
/**
+ * Free game runtime
+ */
+void free_game_runtime(struct FfiGameRuntime *runtime);
+
+/**
* Free control event
*/
void free_control_event(struct FfiControlEvent *event);
@@ -529,6 +542,108 @@ void free_player_list(struct FfiPlayerList list);
*/
void free_ffi_service_type(enum FfiServiceType *ptr);
+/**
+ * Build tcp client
+ */
+struct FfiTcpClientService tcp_client_build(struct FfiControllerRuntime *runtime);
+
+/**
+ * Bind ipv4 address
+ */
+void tcp_client_bind_ipv4(struct FfiTcpClientService service,
+ uint8_t a0,
+ uint8_t a1,
+ uint8_t a2,
+ uint8_t a3);
+
+/**
+ * Bind ipv6 address
+ */
+bool tcp_client_bind_ipv6(struct FfiTcpClientService service, const char *ip_str);
+
+/**
+ * Bind port
+ */
+void tcp_client_bind_port(struct FfiTcpClientService service, uint16_t port);
+
+/**
+ * Bind address with ipv4
+ */
+void tcp_client_bind_address_v4(struct FfiTcpClientService service,
+ uint8_t a0,
+ uint8_t a1,
+ uint8_t a2,
+ uint8_t a3,
+ uint16_t port);
+
+/**
+ * Bind address with ipv6
+ */
+bool tcp_client_bind_address_v6(struct FfiTcpClientService service,
+ const char *ip_str,
+ uint16_t port);
+
+/**
+ * Connect
+ */
+void tcp_client_connect(struct FfiTcpClientService service);
+
+/**
+ * Free tcp client
+ */
+void free_tcp_client(struct FfiTcpClientService service);
+
+/**
+ * Build tcp server
+ */
+struct FfiTcpServerService tcp_server_build(struct FfiGameRuntime *runtime);
+
+/**
+ * Bind ipv4 address
+ */
+void tcp_server_bind_ipv4(struct FfiTcpServerService service,
+ uint8_t a0,
+ uint8_t a1,
+ uint8_t a2,
+ uint8_t a3);
+
+/**
+ * Bind ipv6 address
+ */
+bool tcp_server_bind_ipv6(struct FfiTcpServerService service, const char *ip_str);
+
+/**
+ * Bind port
+ */
+void tcp_server_bind_port(struct FfiTcpServerService service, uint16_t port);
+
+/**
+ * Bind address with ipv4
+ */
+void tcp_server_bind_address_v4(struct FfiTcpServerService service,
+ uint8_t a0,
+ uint8_t a1,
+ uint8_t a2,
+ uint8_t a3,
+ uint16_t port);
+
+/**
+ * Bind address with ipv6
+ */
+bool tcp_server_bind_address_v6(struct FfiTcpServerService service,
+ const char *ip_str,
+ uint16_t port);
+
+/**
+ * Start listening
+ */
+void tcp_server_listening_block_on(struct FfiTcpServerService service);
+
+/**
+ * Free tcp server
+ */
+void free_tcp_server(struct FfiTcpServerService service);
+
#ifdef __cplusplus
} // extern "C"
#endif // __cplusplus
diff --git a/core/bindings/lang/clang/src/data/ngpd_controller.rs b/core/bindings/lang/clang/src/data/ngpd_controller.rs
index c954df4..a264239 100644
--- a/core/bindings/lang/clang/src/data/ngpd_controller.rs
+++ b/core/bindings/lang/clang/src/data/ngpd_controller.rs
@@ -13,7 +13,7 @@ pub struct FfiControllerData(*mut c_void);
#[repr(C)]
pub struct FfiControllerRuntime {
- inner: *mut c_void,
+ pub(crate) inner: *mut c_void,
drop_fn: extern "C" fn(*mut c_void),
}
@@ -114,9 +114,9 @@ impl FfiControllerRuntime {
}
let arc_ptr = unsafe { (*runtime).inner as *const Arc<Mutex<ControllerRuntime>> };
- let arc_ref = unsafe { Arc::from_raw(arc_ptr) };
+ let arc_ref: Arc<Mutex<ControllerRuntime>> = unsafe { (&*arc_ptr).clone() };
- entry_mutex!(*arc_ref, |mutex_guard| {
+ entry_mutex!(arc_ref, |mutex_guard| {
mutex_guard.close();
});
@@ -135,10 +135,10 @@ impl FfiControllerRuntime {
}
let arc_ptr = unsafe { (*runtime).inner as *const Arc<Mutex<ControllerRuntime>> };
- let arc_ref = unsafe { Arc::from_raw(arc_ptr) };
+ let arc_ref: Arc<Mutex<ControllerRuntime>> = unsafe { (&*arc_ptr).clone() };
let msg = unsafe { ControlMessage::from(control_message.read()) };
- entry_mutex!(*arc_ref, |mutex_guard| {
+ entry_mutex!(arc_ref, |mutex_guard| {
mutex_guard.send_message(msg);
});
@@ -258,12 +258,12 @@ impl FfiControllerRuntime {
}
let arc_ptr = unsafe { (*runtime).inner as *const Arc<Mutex<ControllerRuntime>> };
- let arc_ref = unsafe { Arc::from_raw(arc_ptr) };
+ let arc_ref: Arc<Mutex<ControllerRuntime>> = unsafe { (&*arc_ptr).clone() };
let result = {
let mut pop_result = None;
- entry_mutex!(*arc_ref, |mutex_guard| {
+ entry_mutex!(arc_ref, |mutex_guard| {
pop_result = mutex_guard.pop();
});
diff --git a/core/bindings/lang/clang/src/data/ngpd_game.rs b/core/bindings/lang/clang/src/data/ngpd_game.rs
index dc82822..39cb738 100644
--- a/core/bindings/lang/clang/src/data/ngpd_game.rs
+++ b/core/bindings/lang/clang/src/data/ngpd_game.rs
@@ -25,7 +25,7 @@ pub struct FfiControlEvent {
#[repr(C)]
pub struct FfiGameRuntime {
- inner: *mut c_void,
+ pub(crate) inner: *mut c_void,
drop_fn: extern "C" fn(*mut c_void),
}
@@ -191,12 +191,12 @@ impl FfiGameRuntime {
) {
if runtime.is_null() || player.is_null() { return; }
let arc_ptr = unsafe { (*runtime).inner as *const Arc<Mutex<GameRuntime>> };
- let arc_ref = unsafe { Arc::from_raw(arc_ptr) };
+ let arc_ref: Arc<Mutex<GameRuntime>> = unsafe { (&*arc_ptr).clone() };
let ffi_player_ref = unsafe { &*player };
let player = Player::try_from(&*ffi_player_ref).unwrap_or_default();
let service = unsafe { ServiceType::from(&service_type.read()) };
- entry_mutex!(*arc_ref, |mutex_guard| {
+ entry_mutex!(arc_ref, |mutex_guard| {
mutex_guard.send_game_message(&player.account, message, service);
});
}
@@ -207,9 +207,9 @@ impl FfiGameRuntime {
) {
if runtime.is_null() { return; }
let arc_ptr = unsafe { (*runtime).inner as *const Arc<Mutex<GameRuntime>> };
- let arc_ref = unsafe { Arc::from_raw(arc_ptr) };
+ let arc_ref: Arc<Mutex<GameRuntime>> = unsafe { (&*arc_ptr).clone() };
- entry_mutex!(*arc_ref, |mutex_guard| {
+ entry_mutex!(arc_ref, |mutex_guard| {
do_on(mutex_guard);
});
}
@@ -255,9 +255,9 @@ impl FfiGameRuntime {
pub extern "C" fn game_runtime_pop_control_event(runtime: *mut FfiGameRuntime) -> *mut FfiControlEvent {
if runtime.is_null() { return std::ptr::null_mut(); }
let arc_ptr = unsafe { (*runtime).inner as *const Arc<Mutex<GameRuntime>> };
- let arc_ref = unsafe { Arc::from_raw(arc_ptr) };
+ let arc_ref: Arc<Mutex<GameRuntime>> = unsafe { (&*arc_ptr).clone() };
let mut control_event = None;
- entry_mutex!(*arc_ref, |mutex_guard| {
+ entry_mutex!(arc_ref, |mutex_guard| {
control_event = mutex_guard.pop_control_event();
});
match control_event {
@@ -300,8 +300,8 @@ impl FfiGameRuntime {
if runtime.is_null() { return; }
let arc_ptr = unsafe { (*runtime).inner as *const Arc<Mutex<GameRuntime>> };
- let arc_ref = unsafe { Arc::from_raw(arc_ptr) };
- entry_mutex!(*arc_ref, |mutex_guard| {
+ let arc_ref: Arc<Mutex<GameRuntime>> = unsafe { (&*arc_ptr).clone() };
+ entry_mutex!(arc_ref, |mutex_guard| {
mutex_guard.kick_player(&player, service);
});
}
@@ -321,8 +321,8 @@ impl FfiGameRuntime {
if runtime.is_null() { return; }
let arc_ptr = unsafe { (*runtime).inner as *const Arc<Mutex<GameRuntime>> };
- let arc_ref = unsafe { Arc::from_raw(arc_ptr) };
- entry_mutex!(*arc_ref, |mutex_guard| {
+ let arc_ref: Arc<Mutex<GameRuntime>> = unsafe { (&*arc_ptr).clone() };
+ entry_mutex!(arc_ref, |mutex_guard| {
mutex_guard.ban_player(&player, service);
});
}
@@ -340,8 +340,8 @@ impl FfiGameRuntime {
if runtime.is_null() { return; }
let arc_ptr = unsafe { (*runtime).inner as *const Arc<Mutex<GameRuntime>> };
- let arc_ref = unsafe { Arc::from_raw(arc_ptr) };
- entry_mutex!(*arc_ref, |mutex_guard| {
+ let arc_ref: Arc<Mutex<GameRuntime>> = unsafe { (&*arc_ptr).clone() };
+ entry_mutex!(arc_ref, |mutex_guard| {
mutex_guard.pardon_player(&player);
});
}
@@ -380,8 +380,8 @@ impl FfiGameRuntime {
let mut locked = false;
let arc_ptr = unsafe { (*runtime).inner as *const Arc<Mutex<GameRuntime>> };
- let arc_ref = unsafe { Arc::from_raw(arc_ptr) };
- entry_mutex!(*arc_ref, |mutex_guard| {
+ let arc_ref: Arc<Mutex<GameRuntime>> = unsafe { (&*arc_ptr).clone() };
+ entry_mutex!(arc_ref, |mutex_guard| {
locked = mutex_guard.is_game_locked();
});
@@ -402,8 +402,8 @@ impl FfiGameRuntime {
let mut status = None;
let arc_ptr = unsafe { (*runtime).inner as *const Arc<Mutex<GameRuntime>> };
- let arc_ref = unsafe { Arc::from_raw(arc_ptr) };
- entry_mutex!(*arc_ref, |mutex_guard| {
+ let arc_ref: Arc<Mutex<GameRuntime>> = unsafe { (&*arc_ptr).clone() };
+ entry_mutex!(arc_ref, |mutex_guard| {
status = mutex_guard.control.get_button_status(&account, &key);
});
@@ -429,8 +429,8 @@ impl FfiGameRuntime {
let mut status = None;
let arc_ptr = unsafe { (*runtime).inner as *const Arc<Mutex<GameRuntime>> };
- let arc_ref = unsafe { Arc::from_raw(arc_ptr) };
- entry_mutex!(*arc_ref, |mutex_guard| {
+ let arc_ref: Arc<Mutex<GameRuntime>> = unsafe { (&*arc_ptr).clone() };
+ entry_mutex!(arc_ref, |mutex_guard| {
status = mutex_guard.control.get_axis(&account, &key);
});
@@ -456,8 +456,8 @@ impl FfiGameRuntime {
let mut status = None;
let arc_ptr = unsafe { (*runtime).inner as *const Arc<Mutex<GameRuntime>> };
- let arc_ref = unsafe { Arc::from_raw(arc_ptr) };
- entry_mutex!(*arc_ref, |mutex_guard| {
+ let arc_ref: Arc<Mutex<GameRuntime>> = unsafe { (&*arc_ptr).clone() };
+ entry_mutex!(arc_ref, |mutex_guard| {
status = mutex_guard.control.get_direction(&account, &key);
});
@@ -482,8 +482,8 @@ impl FfiGameRuntime {
let mut service_type = None;
let arc_ptr = unsafe { (*runtime).inner as *const Arc<Mutex<GameRuntime>> };
- let arc_ref = unsafe { Arc::from_raw(arc_ptr) };
- entry_mutex!(*arc_ref, |mutex_guard| {
+ let arc_ref: Arc<Mutex<GameRuntime>> = unsafe { (&*arc_ptr).clone() };
+ entry_mutex!(arc_ref, |mutex_guard| {
service_type = mutex_guard.data.get_service_type(&account);
});
@@ -508,8 +508,8 @@ impl FfiGameRuntime {
let mut banned = None;
let arc_ptr = unsafe { (*runtime).inner as *const Arc<Mutex<GameRuntime>> };
- let arc_ref = unsafe { Arc::from_raw(arc_ptr) };
- entry_mutex!(*arc_ref, |mutex_guard| {
+ let arc_ref: Arc<Mutex<GameRuntime>> = unsafe { (&*arc_ptr).clone() };
+ entry_mutex!(arc_ref, |mutex_guard| {
banned = Some(mutex_guard.data.is_account_banned(&account));
});
@@ -534,8 +534,8 @@ impl FfiGameRuntime {
let mut online = None;
let arc_ptr = unsafe { (*runtime).inner as *const Arc<Mutex<GameRuntime>> };
- let arc_ref = unsafe { Arc::from_raw(arc_ptr) };
- entry_mutex!(*arc_ref, |mutex_guard| {
+ let arc_ref: Arc<Mutex<GameRuntime>> = unsafe { (&*arc_ptr).clone() };
+ entry_mutex!(arc_ref, |mutex_guard| {
online = Some(mutex_guard.data.is_account_online(&account));
});
@@ -553,8 +553,8 @@ impl FfiGameRuntime {
let mut online_list = None;
let arc_ptr = unsafe { (*runtime).inner as *const Arc<Mutex<GameRuntime>> };
- let arc_ref = unsafe { Arc::from_raw(arc_ptr) };
- entry_mutex!(*arc_ref, |mutex_guard| {
+ let arc_ref: Arc<Mutex<GameRuntime>> = unsafe { (&*arc_ptr).clone() };
+ entry_mutex!(arc_ref, |mutex_guard| {
online_list = Some(mutex_guard.data.online_accounts());
});
@@ -581,8 +581,8 @@ impl FfiGameRuntime {
let mut banned_list = None;
let arc_ptr = unsafe { (*runtime).inner as *const Arc<Mutex<GameRuntime>> };
- let arc_ref = unsafe { Arc::from_raw(arc_ptr) };
- entry_mutex!(*arc_ref, |mutex_guard| {
+ let arc_ref: Arc<Mutex<GameRuntime>> = unsafe { (&*arc_ptr).clone() };
+ entry_mutex!(arc_ref, |mutex_guard| {
banned_list = Some(mutex_guard.data.banned_accounts());
});
@@ -602,6 +602,18 @@ impl FfiGameRuntime {
cap,
}
}
+
+ /// Free game runtime
+ #[unsafe(no_mangle)]
+ pub extern "C" fn free_game_runtime(runtime: *mut FfiGameRuntime) {
+ if runtime.is_null() {
+ return;
+ }
+
+ let runtime_box = unsafe { Box::from_raw(runtime) };
+
+ (runtime_box.drop_fn)(runtime_box.inner);
+ }
}
impl FfiControlEvent {
diff --git a/core/bindings/lang/clang/src/service/mod.rs b/core/bindings/lang/clang/src/service/mod.rs
index 464cfba..9e56cb7 100644
--- a/core/bindings/lang/clang/src/service/mod.rs
+++ b/core/bindings/lang/clang/src/service/mod.rs
@@ -1 +1,2 @@
-pub mod ngpd_service_types; \ No newline at end of file
+pub mod ngpd_service_types;
+pub mod ngpd_tcp_service; \ No newline at end of file
diff --git a/core/bindings/lang/clang/src/service/ngpd_tcp_service.rs b/core/bindings/lang/clang/src/service/ngpd_tcp_service.rs
new file mode 100644
index 0000000..f80d5ea
--- /dev/null
+++ b/core/bindings/lang/clang/src/service/ngpd_tcp_service.rs
@@ -0,0 +1,305 @@
+use std::ffi::{c_char, c_void, CStr};
+use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
+use std::sync::{Arc, Mutex};
+use nogamepads_core::data::controller::controller_runtime::ControllerRuntime;
+use nogamepads_core::data::game::game_runtime::GameRuntime;
+use nogamepads_core::service::tcp_network::pad_client::pad_client_service::PadClientNetwork;
+use nogamepads_core::service::tcp_network::pad_server::pad_server_service::PadServerNetwork;
+use crate::data::ngpd_controller::FfiControllerRuntime;
+use crate::data::ngpd_game::FfiGameRuntime;
+
+#[repr(C)]
+pub struct FfiTcpClientService(*mut c_void);
+
+#[repr(C)]
+pub struct FfiTcpServerService(*mut c_void);
+
+impl FfiTcpClientService {
+
+ fn as_inner(&self) -> &mut PadClientNetwork {
+ unsafe { &mut *(self.0 as *mut PadClientNetwork) }
+ }
+
+ /// Build tcp client
+ #[unsafe(no_mangle)]
+ pub extern "C" fn tcp_client_build(
+ runtime: *mut FfiControllerRuntime,
+ ) -> FfiTcpClientService {
+
+ let arc_ptr = unsafe { (*runtime).inner as *const Arc<Mutex<ControllerRuntime>> };
+ let arc_clone: Arc<Mutex<ControllerRuntime>> = unsafe { (&*arc_ptr).clone() };
+
+ let service = Box::new(PadClientNetwork::build(arc_clone));
+ let ptr = Box::into_raw(service);
+
+ FfiTcpClientService(ptr as *mut c_void)
+ }
+
+ /// Bind ipv4 address
+ #[unsafe(no_mangle)]
+ pub extern "C" fn tcp_client_bind_ipv4(
+ service: FfiTcpClientService,
+ a0: u8,
+ a1: u8,
+ a2: u8,
+ a3: u8
+ ) {
+ let inner = service.as_inner();
+ let ip = IpAddr::V4(Ipv4Addr::new(a0, a1, a2, a3));
+ inner.bind_ip(ip);
+ }
+
+ /// Bind ipv6 address
+ #[unsafe(no_mangle)]
+ pub extern "C" fn tcp_client_bind_ipv6(
+ service: FfiTcpClientService,
+ ip_str: *const c_char
+ ) -> bool {
+ if ip_str.is_null() {
+ return false;
+ }
+
+ let inner = service.as_inner();
+
+ let c_str = unsafe { CStr::from_ptr(ip_str) };
+ if let Ok(ip_str) = c_str.to_str() {
+ if let Ok(ipv6) = ip_str.parse::<Ipv6Addr>() {
+ inner.bind_ip(IpAddr::V6(ipv6));
+ return true;
+ }
+ }
+
+ false
+ }
+
+ /// Bind port
+ #[unsafe(no_mangle)]
+ pub extern "C" fn tcp_client_bind_port(
+ service: FfiTcpClientService,
+ port: u16
+ ) {
+ service.as_inner().bind_port(port);
+ }
+
+ /// Bind address with ipv4
+ #[unsafe(no_mangle)]
+ pub extern "C" fn tcp_client_bind_address_v4(
+ service: FfiTcpClientService,
+ a0: u8,
+ a1: u8,
+ a2: u8,
+ a3: u8,
+ port: u16
+ ) {
+ let inner = service.as_inner();
+ let addr = SocketAddr::new(
+ IpAddr::V4(Ipv4Addr::new(a0, a1, a2, a3)),
+ port
+ );
+ inner.bind_ip(addr.ip());
+ inner.bind_port(addr.port());
+ }
+
+ /// Bind address with ipv6
+ #[unsafe(no_mangle)]
+ pub extern "C" fn tcp_client_bind_address_v6(
+ service: FfiTcpClientService,
+ ip_str: *const c_char,
+ port: u16
+ ) -> bool {
+ if ip_str.is_null() {
+ return false;
+ }
+
+ let inner = service.as_inner();
+
+ let c_str = unsafe { CStr::from_ptr(ip_str) };
+ if let Ok(ip_str) = c_str.to_str() {
+ if let Ok(ipv6) = ip_str.parse::<Ipv6Addr>() {
+ let addr = SocketAddr::new(
+ IpAddr::V6(ipv6),
+ port
+ );
+ inner.bind_ip(addr.ip());
+ inner.bind_port(addr.port());
+ return true;
+ }
+ }
+
+ false
+ }
+
+ /// Connect
+ #[unsafe(no_mangle)]
+ pub extern "C" fn tcp_client_connect(
+ service: FfiTcpClientService
+ ) {
+ let service_ptr = service.0 as *mut PadClientNetwork;
+ assert!(!service_ptr.is_null(), "Service pointer is null");
+
+ let service = unsafe { Box::from_raw(service_ptr) };
+
+ service.connect();
+ }
+
+ /// Free tcp client
+ #[unsafe(no_mangle)]
+ pub extern "C" fn free_tcp_client(
+ service: FfiTcpClientService
+ ) {
+ if service.0.is_null() {
+ return;
+ }
+
+ let service_ptr = service.0 as *mut PadClientNetwork;
+
+ unsafe {
+ let _ = Box::from_raw(service_ptr);
+ }
+ }
+}
+
+impl FfiTcpServerService {
+
+ fn as_inner(&self) -> &mut PadServerNetwork {
+ unsafe { &mut *(self.0 as *mut PadServerNetwork) }
+ }
+
+ /// Build tcp server
+ #[unsafe(no_mangle)]
+ pub extern "C" fn tcp_server_build(
+ runtime: *mut FfiGameRuntime,
+ ) -> FfiTcpServerService {
+
+ let arc_ptr = unsafe { (*runtime).inner as *const Arc<Mutex<GameRuntime>> };
+ let arc_clone: Arc<Mutex<GameRuntime>> = unsafe { (&*arc_ptr).clone() };
+
+ let service = Box::new(PadServerNetwork::build(arc_clone));
+ let ptr = Box::into_raw(service);
+
+ FfiTcpServerService(ptr as *mut c_void)
+ }
+
+ /// Bind ipv4 address
+ #[unsafe(no_mangle)]
+ pub extern "C" fn tcp_server_bind_ipv4(
+ service: FfiTcpServerService,
+ a0: u8,
+ a1: u8,
+ a2: u8,
+ a3: u8
+ ) {
+ let inner = service.as_inner();
+ let ip = IpAddr::V4(Ipv4Addr::new(a0, a1, a2, a3));
+ inner.bind_ip(ip);
+ }
+
+ /// Bind ipv6 address
+ #[unsafe(no_mangle)]
+ pub extern "C" fn tcp_server_bind_ipv6(
+ service: FfiTcpServerService,
+ ip_str: *const c_char
+ ) -> bool {
+ if ip_str.is_null() {
+ return false;
+ }
+
+ let inner = service.as_inner();
+
+ let c_str = unsafe { CStr::from_ptr(ip_str) };
+ if let Ok(ip_str) = c_str.to_str() {
+ if let Ok(ipv6) = ip_str.parse::<Ipv6Addr>() {
+ inner.bind_ip(IpAddr::V6(ipv6));
+ return true;
+ }
+ }
+
+ false
+ }
+
+ /// Bind port
+ #[unsafe(no_mangle)]
+ pub extern "C" fn tcp_server_bind_port(
+ service: FfiTcpServerService,
+ port: u16
+ ) {
+ service.as_inner().bind_port(port);
+ }
+
+ /// Bind address with ipv4
+ #[unsafe(no_mangle)]
+ pub extern "C" fn tcp_server_bind_address_v4(
+ service: FfiTcpServerService,
+ a0: u8,
+ a1: u8,
+ a2: u8,
+ a3: u8,
+ port: u16
+ ) {
+ let inner = service.as_inner();
+ let addr = SocketAddr::new(
+ IpAddr::V4(Ipv4Addr::new(a0, a1, a2, a3)),
+ port
+ );
+ inner.bind_ip(addr.ip());
+ inner.bind_port(addr.port());
+ }
+
+ /// Bind address with ipv6
+ #[unsafe(no_mangle)]
+ pub extern "C" fn tcp_server_bind_address_v6(
+ service: FfiTcpServerService,
+ ip_str: *const c_char,
+ port: u16
+ ) -> bool {
+ if ip_str.is_null() {
+ return false;
+ }
+
+ let inner = service.as_inner();
+
+ let c_str = unsafe { CStr::from_ptr(ip_str) };
+ if let Ok(ip_str) = c_str.to_str() {
+ if let Ok(ipv6) = ip_str.parse::<Ipv6Addr>() {
+ let addr = SocketAddr::new(
+ IpAddr::V6(ipv6),
+ port
+ );
+ inner.bind_ip(addr.ip());
+ inner.bind_port(addr.port());
+ return true;
+ }
+ }
+
+ false
+ }
+
+ /// Start listening
+ #[unsafe(no_mangle)]
+ pub extern "C" fn tcp_server_listening_block_on(
+ service: FfiTcpServerService
+ ) {
+ let service_ptr = service.0 as *mut PadServerNetwork;
+ assert!(!service_ptr.is_null(), "Service pointer is null");
+
+ let service = unsafe { Box::from_raw(service_ptr) };
+
+ service.listening_block_on();
+ }
+
+ /// Free tcp server
+ #[unsafe(no_mangle)]
+ pub extern "C" fn free_tcp_server(
+ service: FfiTcpServerService
+ ) {
+ if service.0.is_null() {
+ return;
+ }
+
+ let service_ptr = service.0 as *mut PadServerNetwork;
+
+ unsafe {
+ let _ = Box::from_raw(service_ptr);
+ }
+ }
+} \ No newline at end of file