1use jni::objects::{GlobalRef, JClass, JObject, JString, JValue};
81use jni::sys::{jboolean, jint, jlong, JNI_FALSE, JNI_TRUE};
82use jni::JNIEnv;
83use log::{error, info, warn};
84use once_cell::sync::OnceCell;
85use rustvncserver::server::{ServerEvent, VncServer};
86use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
87use std::sync::{Arc, Mutex};
88use tokio::runtime::Runtime;
89use tokio::sync::{broadcast, mpsc};
90
91static VNC_RUNTIME: OnceCell<Runtime> = OnceCell::new();
97static VNC_SERVER: OnceCell<Arc<Mutex<Option<Arc<VncServer>>>>> = OnceCell::new();
99static SHUTDOWN_SIGNAL: OnceCell<broadcast::Sender<()>> = OnceCell::new();
101static EVENT_HANDLER_RUNNING: AtomicBool = AtomicBool::new(false);
103
104static JAVA_VM: OnceCell<jni::JavaVM> = OnceCell::new();
106static INPUT_SERVICE_CLASS: OnceCell<GlobalRef> = OnceCell::new();
108static MAIN_SERVICE_CLASS: OnceCell<GlobalRef> = OnceCell::new();
110
111#[allow(dead_code)]
113static NEXT_CLIENT_ID: AtomicU64 = AtomicU64::new(1);
114
115static FRAMEBUFFER_UPDATE_IN_PROGRESS: AtomicBool = AtomicBool::new(false);
117
118pub fn register_vnc_natives(
152 env: &mut JNIEnv,
153 main_service_class: &str,
154 input_service_class: &str,
155) -> Result<(), String> {
156 if let Ok(vm) = env.get_java_vm() {
158 let _ = JAVA_VM.set(vm);
159 }
160
161 let main_class = env.find_class(main_service_class).map_err(|e| {
163 format!(
164 "Failed to find MainService class '{}': {}",
165 main_service_class, e
166 )
167 })?;
168
169 let main_global = env
170 .new_global_ref(main_class)
171 .map_err(|e| format!("Failed to create global ref for MainService: {}", e))?;
172
173 if MAIN_SERVICE_CLASS.set(main_global).is_err() {
174 return Err("MAIN_SERVICE_CLASS was already set".to_string());
175 }
176
177 let input_class = env.find_class(input_service_class).map_err(|e| {
179 format!(
180 "Failed to find InputService class '{}': {}",
181 input_service_class, e
182 )
183 })?;
184
185 let input_global = env
186 .new_global_ref(input_class)
187 .map_err(|e| format!("Failed to create global ref for InputService: {}", e))?;
188
189 if INPUT_SERVICE_CLASS.set(input_global).is_err() {
190 return Err("INPUT_SERVICE_CLASS was already set".to_string());
191 }
192
193 let main_class_local = env
195 .find_class(main_service_class)
196 .map_err(|e| format!("Failed to find MainService for registration: {}", e))?;
197
198 register_main_service_natives(env, main_class_local)?;
199
200 info!(
201 "VNC natives registered for {} and {}",
202 main_service_class, input_service_class
203 );
204
205 Ok(())
206}
207
208fn register_main_service_natives(env: &mut JNIEnv, class: JClass) -> Result<(), String> {
213 use jni::NativeMethod;
214
215 let required_methods: Vec<NativeMethod> = vec![
217 NativeMethod {
218 name: "vncInit".into(),
219 sig: "()V".into(),
220 fn_ptr: native_vnc_init as *mut std::ffi::c_void,
221 },
222 NativeMethod {
223 name: "vncStartServer".into(),
224 sig: "(IIILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z".into(),
225 fn_ptr: native_vnc_start_server as *mut std::ffi::c_void,
226 },
227 NativeMethod {
228 name: "vncStopServer".into(),
229 sig: "()Z".into(),
230 fn_ptr: native_vnc_stop_server as *mut std::ffi::c_void,
231 },
232 NativeMethod {
233 name: "vncIsActive".into(),
234 sig: "()Z".into(),
235 fn_ptr: native_vnc_is_active as *mut std::ffi::c_void,
236 },
237 NativeMethod {
238 name: "vncConnectRepeater".into(),
239 sig: "(Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)J".into(),
240 fn_ptr: native_vnc_connect_repeater as *mut std::ffi::c_void,
241 },
242 ];
243
244 env.register_native_methods(&class, &required_methods)
245 .map_err(|e| format!("Failed to register required MainService natives: {}", e))?;
246
247 let optional_methods: Vec<NativeMethod> = vec![
249 NativeMethod {
250 name: "vncUpdateFramebuffer".into(),
251 sig: "(Ljava/nio/ByteBuffer;)Z".into(),
252 fn_ptr: native_vnc_update_framebuffer as *mut std::ffi::c_void,
253 },
254 NativeMethod {
255 name: "vncUpdateFramebufferAndSend".into(),
256 sig: "(Ljava/nio/ByteBuffer;II)Z".into(),
257 fn_ptr: native_vnc_update_framebuffer_and_send as *mut std::ffi::c_void,
258 },
259 NativeMethod {
260 name: "vncUpdateFramebufferCropped".into(),
261 sig: "(Ljava/nio/ByteBuffer;IIIIII)Z".into(),
262 fn_ptr: native_vnc_update_framebuffer_cropped as *mut std::ffi::c_void,
263 },
264 NativeMethod {
265 name: "vncNewFramebuffer".into(),
266 sig: "(II)Z".into(),
267 fn_ptr: native_vnc_new_framebuffer as *mut std::ffi::c_void,
268 },
269 NativeMethod {
270 name: "vncSendCutText".into(),
271 sig: "(Ljava/lang/String;)V".into(),
272 fn_ptr: native_vnc_send_cut_text as *mut std::ffi::c_void,
273 },
274 NativeMethod {
275 name: "vncGetFramebufferWidth".into(),
276 sig: "()I".into(),
277 fn_ptr: native_vnc_get_framebuffer_width as *mut std::ffi::c_void,
278 },
279 NativeMethod {
280 name: "vncGetFramebufferHeight".into(),
281 sig: "()I".into(),
282 fn_ptr: native_vnc_get_framebuffer_height as *mut std::ffi::c_void,
283 },
284 NativeMethod {
285 name: "vncConnectReverse".into(),
286 sig: "(Ljava/lang/String;I)J".into(),
287 fn_ptr: native_vnc_connect_reverse as *mut std::ffi::c_void,
288 },
289 NativeMethod {
290 name: "vncGetRemoteHost".into(),
291 sig: "(J)Ljava/lang/String;".into(),
292 fn_ptr: native_vnc_get_remote_host as *mut std::ffi::c_void,
293 },
294 NativeMethod {
295 name: "vncGetDestinationPort".into(),
296 sig: "(J)I".into(),
297 fn_ptr: native_vnc_get_destination_port as *mut std::ffi::c_void,
298 },
299 NativeMethod {
300 name: "vncGetRepeaterId".into(),
301 sig: "(J)Ljava/lang/String;".into(),
302 fn_ptr: native_vnc_get_repeater_id as *mut std::ffi::c_void,
303 },
304 NativeMethod {
305 name: "vncDisconnect".into(),
306 sig: "(J)Z".into(),
307 fn_ptr: native_vnc_disconnect as *mut std::ffi::c_void,
308 },
309 NativeMethod {
310 name: "vncScheduleCopyRect".into(),
311 sig: "(IIIIII)V".into(),
312 fn_ptr: native_vnc_schedule_copy_rect as *mut std::ffi::c_void,
313 },
314 NativeMethod {
315 name: "vncDoCopyRect".into(),
316 sig: "(IIIIII)Z".into(),
317 fn_ptr: native_vnc_do_copy_rect as *mut std::ffi::c_void,
318 },
319 ];
320
321 for method in optional_methods {
322 let method_name = method.name.to_str().unwrap_or("unknown").to_string();
323 if env.register_native_methods(&class, &[method]).is_err() {
324 let _ = env.exception_clear();
326 log::debug!("Optional method {} not found, skipping", method_name);
327 }
328 }
329
330 Ok(())
331}
332
333fn get_or_init_vnc_runtime() -> &'static Runtime {
339 VNC_RUNTIME.get_or_init(|| {
340 tokio::runtime::Builder::new_multi_thread()
341 .enable_all()
342 .build()
343 .expect("Failed to build VNC Tokio runtime")
344 })
345}
346
347fn get_or_init_shutdown_signal() -> &'static broadcast::Sender<()> {
349 SHUTDOWN_SIGNAL.get_or_init(|| {
350 let (tx, _) = broadcast::channel(16);
351 tx
352 })
353}
354
355extern "system" fn native_vnc_init(env: JNIEnv, _class: JClass) {
360 android_logger::init_once(
362 android_logger::Config::default()
363 .with_max_level(log::LevelFilter::Info)
364 .with_tag("RustVNC"),
365 );
366
367 info!("Initializing Rust VNC Server");
368
369 get_or_init_vnc_runtime();
371 get_or_init_shutdown_signal();
372
373 if JAVA_VM.get().is_none() {
375 if let Ok(vm) = env.get_java_vm() {
376 let _ = JAVA_VM.set(vm);
377 }
378 }
379
380 VNC_SERVER.get_or_init(|| Arc::new(Mutex::new(None)));
382
383 info!("Rust VNC Server initialized");
384}
385
386extern "system" fn native_vnc_start_server(
387 mut env: JNIEnv,
388 _class: JClass,
389 width: jint,
390 height: jint,
391 port: jint,
392 desktop_name: JString,
393 password: JString,
394 _http_root_dir: JString,
395) -> jboolean {
396 const MAX_DIMENSION: i32 = 8192;
398 const MIN_DIMENSION: i32 = 1;
399
400 let width = match u16::try_from(width) {
401 Ok(w) if w >= MIN_DIMENSION as u16 && w <= MAX_DIMENSION as u16 => w,
402 _ => {
403 error!(
404 "Invalid width: {} (must be {}-{})",
405 width, MIN_DIMENSION, MAX_DIMENSION
406 );
407 return JNI_FALSE;
408 }
409 };
410
411 let height = match u16::try_from(height) {
412 Ok(h) if h >= MIN_DIMENSION as u16 && h <= MAX_DIMENSION as u16 => h,
413 _ => {
414 error!(
415 "Invalid height: {} (must be {}-{})",
416 height, MIN_DIMENSION, MAX_DIMENSION
417 );
418 return JNI_FALSE;
419 }
420 };
421
422 let port_opt: Option<u16> = if port == -1 {
424 None
425 } else {
426 match u16::try_from(port) {
427 Ok(p) if p > 0 => Some(p),
428 _ => {
429 error!(
430 "Invalid port: {} (must be -1 for disabled or 1-65535)",
431 port
432 );
433 return JNI_FALSE;
434 }
435 }
436 };
437
438 let desktop_name_str: String = match env.get_string(&desktop_name) {
439 Ok(s) => s.into(),
440 Err(e) => {
441 error!("Failed to get desktop name: {}", e);
442 return JNI_FALSE;
443 }
444 };
445
446 let password_str: Option<String> = if !password.is_null() {
447 match env.get_string(&password) {
448 Ok(s) => {
449 let pw: String = s.into();
450 if pw.is_empty() {
451 None
452 } else {
453 Some(pw)
454 }
455 }
456 Err(_) => None,
457 }
458 } else {
459 None
460 };
461
462 if let Some(p) = port_opt {
463 info!(
464 "Starting Rust VNC Server: {}x{} on port {}",
465 width, height, p
466 );
467 } else {
468 info!(
469 "Starting Rust VNC Server: {}x{} (inbound connections disabled)",
470 width, height
471 );
472 }
473
474 let (server, event_rx) = VncServer::new(width, height, desktop_name_str, password_str);
476 let server: Arc<VncServer> = Arc::new(server);
477
478 if let Some(server_container) = VNC_SERVER.get() {
480 match server_container.lock() {
481 Ok(mut guard) => {
482 *guard = Some(server.clone());
483 }
484 Err(e) => {
485 error!("Failed to lock server container: {}", e);
486 return JNI_FALSE;
487 }
488 }
489 } else {
490 error!("VNC server container not initialized");
491 return JNI_FALSE;
492 }
493
494 spawn_event_handler(event_rx);
496
497 if let Some(listen_port) = port_opt {
499 let runtime = get_or_init_vnc_runtime();
500 let server_clone = server.clone();
501 let mut shutdown_rx = get_or_init_shutdown_signal().subscribe();
502
503 runtime.spawn(async move {
504 tokio::select! {
505 result = server_clone.listen(listen_port) => {
506 if let Err(e) = result {
507 error!("VNC server listen error: {}", e);
508 }
509 }
510 _ = shutdown_rx.recv() => {
511 info!("VNC server received shutdown signal");
512 }
513 }
514 });
515 } else {
516 info!("VNC server running in outbound-only mode (no listener)");
517 }
518
519 info!("Rust VNC Server started successfully");
520 JNI_TRUE
521}
522
523extern "system" fn native_vnc_stop_server(_env: JNIEnv, _class: JClass) -> jboolean {
524 info!("Stopping Rust VNC Server");
525
526 if let Some(server_container) = VNC_SERVER.get() {
528 if let Ok(guard) = server_container.lock() {
529 if let Some(server_arc) = guard.as_ref() {
530 let client_ids = server_arc.get_client_ids().unwrap_or_else(|_| {
531 warn!("Failed to get read lock on client IDs list");
532 Vec::new()
533 });
534
535 info!("Found {} client(s) to disconnect", client_ids.len());
536
537 let runtime = get_or_init_vnc_runtime();
538 let server_clone = server_arc.clone();
539
540 if let Some(vm) = JAVA_VM.get() {
542 if let Ok(mut env) = vm.attach_current_thread() {
543 if let Some(main_class) = MAIN_SERVICE_CLASS.get() {
544 for client_id in &client_ids {
545 info!("Calling Java onClientDisconnected for client {}", client_id);
546 let args = [JValue::Long(*client_id as jlong)];
547 if let Err(e) = env.call_static_method(
548 main_class,
549 "onClientDisconnected",
550 "(J)V",
551 &args,
552 ) {
553 error!(
554 "Failed to call onClientDisconnected for client {}: {}",
555 client_id, e
556 );
557 }
558 }
559 }
560 }
561 }
562
563 info!("Disconnecting all clients with 3s timeout");
565 let disconnect_result = runtime.block_on(async {
566 tokio::time::timeout(
567 tokio::time::Duration::from_secs(3),
568 server_clone.disconnect_all_clients(),
569 )
570 .await
571 });
572
573 match disconnect_result {
574 Ok(_) => info!("All clients disconnected successfully"),
575 Err(_) => warn!("Client disconnect timed out after 3s"),
576 }
577 }
578 }
579 }
580
581 if let Some(shutdown_tx) = SHUTDOWN_SIGNAL.get() {
583 info!("Sending shutdown signal to tasks");
584 let _ = shutdown_tx.send(());
585 }
586
587 if let Some(server_container) = VNC_SERVER.get() {
589 if let Ok(mut guard) = server_container.lock() {
590 *guard = None;
591 info!("Server reference cleared");
592 }
593 }
594
595 EVENT_HANDLER_RUNNING.store(false, Ordering::SeqCst);
597
598 info!("Rust VNC Server stopped successfully");
599 JNI_TRUE
600}
601
602extern "system" fn native_vnc_update_framebuffer(
603 env: JNIEnv,
604 _class: JClass,
605 buffer: JObject,
606) -> jboolean {
607 let buffer_ptr = match env.get_direct_buffer_address((&buffer).into()) {
608 Ok(ptr) => ptr,
609 Err(e) => {
610 error!("Failed to get buffer address: {}", e);
611 return JNI_FALSE;
612 }
613 };
614
615 let buffer_capacity = match env.get_direct_buffer_capacity((&buffer).into()) {
616 Ok(cap) => cap,
617 Err(e) => {
618 error!("Failed to get buffer capacity: {}", e);
619 return JNI_FALSE;
620 }
621 };
622
623 let buffer_copy = {
625 let buffer_slice = unsafe { std::slice::from_raw_parts(buffer_ptr, buffer_capacity) };
626 buffer_slice.to_vec()
627 };
628
629 if FRAMEBUFFER_UPDATE_IN_PROGRESS
631 .compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst)
632 .is_err()
633 {
634 return JNI_TRUE;
635 }
636
637 if let Some(server_container) = VNC_SERVER.get() {
638 if let Ok(guard) = server_container.lock() {
639 if let Some(server) = guard.as_ref() {
640 let rt = get_or_init_vnc_runtime();
641 let server_clone = server.clone();
642
643 rt.spawn(async move {
644 if let Err(e) = server_clone
645 .framebuffer()
646 .update_from_slice(&buffer_copy)
647 .await
648 {
649 error!("Failed to update framebuffer: {}", e);
650 }
651 FRAMEBUFFER_UPDATE_IN_PROGRESS.store(false, Ordering::SeqCst);
652 });
653
654 return JNI_TRUE;
655 }
656 }
657 }
658
659 FRAMEBUFFER_UPDATE_IN_PROGRESS.store(false, Ordering::SeqCst);
660 JNI_FALSE
661}
662
663extern "system" fn native_vnc_update_framebuffer_and_send(
664 env: JNIEnv,
665 class: JClass,
666 buffer: JObject,
667 _width: jint,
668 _height: jint,
669) -> jboolean {
670 native_vnc_update_framebuffer(env, class, buffer)
671}
672
673extern "system" fn native_vnc_update_framebuffer_cropped(
674 env: JNIEnv,
675 _class: JClass,
676 buffer: JObject,
677 _width: jint,
678 _height: jint,
679 crop_x: jint,
680 crop_y: jint,
681 crop_width: jint,
682 crop_height: jint,
683) -> jboolean {
684 let buffer_ptr = match env.get_direct_buffer_address((&buffer).into()) {
685 Ok(ptr) => ptr,
686 Err(e) => {
687 error!("Failed to get buffer address: {}", e);
688 return JNI_FALSE;
689 }
690 };
691
692 let buffer_capacity = match env.get_direct_buffer_capacity((&buffer).into()) {
693 Ok(cap) => cap,
694 Err(e) => {
695 error!("Failed to get buffer capacity: {}", e);
696 return JNI_FALSE;
697 }
698 };
699
700 const MAX_DIMENSION: i32 = 8192;
702
703 if crop_x < 0 || crop_y < 0 || crop_width <= 0 || crop_height <= 0 {
704 error!(
705 "Invalid crop parameters: x={}, y={}, w={}, h={}",
706 crop_x, crop_y, crop_width, crop_height
707 );
708 return JNI_FALSE;
709 }
710
711 if crop_width > MAX_DIMENSION || crop_height > MAX_DIMENSION {
712 error!(
713 "Crop dimensions too large: {}x{} (max {})",
714 crop_width, crop_height, MAX_DIMENSION
715 );
716 return JNI_FALSE;
717 }
718
719 let expected_size = (crop_width as usize)
720 .checked_mul(crop_height as usize)
721 .and_then(|s| s.checked_mul(4))
722 .unwrap_or(0);
723
724 if expected_size == 0 || buffer_capacity != expected_size {
725 error!(
726 "Cropped buffer size mismatch: expected {}, got {}",
727 expected_size, buffer_capacity
728 );
729 return JNI_FALSE;
730 }
731
732 let buffer_copy = {
733 let buffer_slice = unsafe { std::slice::from_raw_parts(buffer_ptr, buffer_capacity) };
734 buffer_slice.to_vec()
735 };
736
737 if FRAMEBUFFER_UPDATE_IN_PROGRESS
738 .compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst)
739 .is_err()
740 {
741 return JNI_TRUE;
742 }
743
744 if let Some(server_container) = VNC_SERVER.get() {
745 if let Ok(guard) = server_container.lock() {
746 if let Some(server) = guard.as_ref() {
747 let rt = get_or_init_vnc_runtime();
748 let server_clone = server.clone();
749
750 rt.spawn(async move {
751 if let Err(e) = server_clone
752 .framebuffer()
753 .update_cropped(
754 &buffer_copy,
755 crop_x as u16,
756 crop_y as u16,
757 crop_width as u16,
758 crop_height as u16,
759 )
760 .await
761 {
762 error!("Failed to update cropped framebuffer: {}", e);
763 }
764 FRAMEBUFFER_UPDATE_IN_PROGRESS.store(false, Ordering::SeqCst);
765 });
766
767 return JNI_TRUE;
768 }
769 }
770 }
771
772 FRAMEBUFFER_UPDATE_IN_PROGRESS.store(false, Ordering::SeqCst);
773 JNI_FALSE
774}
775
776extern "system" fn native_vnc_new_framebuffer(
777 _env: JNIEnv,
778 _class: JClass,
779 width: jint,
780 height: jint,
781) -> jboolean {
782 const MAX_DIMENSION: i32 = 8192;
783 const MIN_DIMENSION: i32 = 1;
784
785 let width = match u16::try_from(width) {
786 Ok(w) if w >= MIN_DIMENSION as u16 && w <= MAX_DIMENSION as u16 => w,
787 _ => {
788 error!(
789 "Invalid width: {} (must be {}-{})",
790 width, MIN_DIMENSION, MAX_DIMENSION
791 );
792 return JNI_FALSE;
793 }
794 };
795
796 let height = match u16::try_from(height) {
797 Ok(h) if h >= MIN_DIMENSION as u16 && h <= MAX_DIMENSION as u16 => h,
798 _ => {
799 error!(
800 "Invalid height: {} (must be {}-{})",
801 height, MIN_DIMENSION, MAX_DIMENSION
802 );
803 return JNI_FALSE;
804 }
805 };
806
807 info!("Resizing framebuffer to {}x{}", width, height);
808
809 if let Some(server_container) = VNC_SERVER.get() {
810 if let Ok(guard) = server_container.lock() {
811 if let Some(server) = guard.as_ref() {
812 let runtime = get_or_init_vnc_runtime();
813
814 if let Err(e) = runtime.block_on(server.framebuffer().resize(width, height)) {
815 error!("Failed to resize framebuffer: {}", e);
816 return JNI_FALSE;
817 }
818
819 info!("Framebuffer resized successfully to {}x{}", width, height);
820 return JNI_TRUE;
821 }
822 }
823 }
824
825 error!("VNC server not initialized");
826 JNI_FALSE
827}
828
829extern "system" fn native_vnc_send_cut_text(mut env: JNIEnv, _class: JClass, text: JString) {
830 let text_str: String = match env.get_string(&text) {
831 Ok(s) => s.into(),
832 Err(e) => {
833 error!("Failed to get cut text: {}", e);
834 return;
835 }
836 };
837
838 if let Some(server_container) = VNC_SERVER.get() {
839 if let Ok(guard) = server_container.lock() {
840 if let Some(server) = guard.as_ref() {
841 let runtime = get_or_init_vnc_runtime();
842 let server_clone = server.clone();
843 let text_clone = text_str;
844
845 runtime.spawn(async move {
846 if let Err(e) = server_clone.send_cut_text_to_all(text_clone).await {
847 error!("Failed to send cut text: {}", e);
848 }
849 });
850 }
851 }
852 }
853}
854
855extern "system" fn native_vnc_is_active(_env: JNIEnv, _class: JClass) -> jboolean {
856 if let Some(server_container) = VNC_SERVER.get() {
857 if let Ok(guard) = server_container.lock() {
858 if guard.is_some() {
859 return JNI_TRUE;
860 }
861 }
862 }
863 JNI_FALSE
864}
865
866extern "system" fn native_vnc_get_framebuffer_width(_env: JNIEnv, _class: JClass) -> jint {
867 if let Some(server_container) = VNC_SERVER.get() {
868 if let Ok(guard) = server_container.lock() {
869 if let Some(server) = guard.as_ref() {
870 return server.framebuffer().width() as jint;
871 }
872 }
873 }
874 -1
875}
876
877extern "system" fn native_vnc_get_framebuffer_height(_env: JNIEnv, _class: JClass) -> jint {
878 if let Some(server_container) = VNC_SERVER.get() {
879 if let Ok(guard) = server_container.lock() {
880 if let Some(server) = guard.as_ref() {
881 return server.framebuffer().height() as jint;
882 }
883 }
884 }
885 -1
886}
887
888extern "system" fn native_vnc_connect_reverse(
889 mut env: JNIEnv,
890 _class: JClass,
891 host: JString,
892 port: jint,
893) -> jlong {
894 let host_str: String = match env.get_string(&host) {
895 Ok(s) => s.into(),
896 Err(e) => {
897 error!("Failed to get reverse connection host: {}", e);
898 return 0;
899 }
900 };
901
902 let port_u16 = port as u16;
903
904 info!("Initiating reverse connection to {}:{}", host_str, port_u16);
905
906 if let Some(server_container) = VNC_SERVER.get() {
907 let server = match server_container.lock() {
908 Ok(guard) => {
909 if let Some(s) = guard.as_ref() {
910 s.clone()
911 } else {
912 error!("VNC server not started");
913 return 0;
914 }
915 }
916 Err(e) => {
917 error!("Failed to lock server container: {}", e);
918 return 0;
919 }
920 };
921
922 let runtime = get_or_init_vnc_runtime();
923
924 return runtime.block_on(async move {
925 match server.connect_reverse(host_str, port_u16).await {
926 Ok(client_id) => {
927 info!("Reverse connection established, client ID: {}", client_id);
928 client_id as jlong
929 }
930 Err(e) => {
931 error!("Failed to establish reverse connection: {}", e);
932 0
933 }
934 }
935 });
936 }
937
938 error!("VNC server not initialized");
939 0
940}
941
942extern "system" fn native_vnc_connect_repeater(
943 mut env: JNIEnv,
944 _class: JClass,
945 host: JString,
946 port: jint,
947 repeater_id: JString,
948 request_id: JString,
949) -> jlong {
950 let host_str: String = match env.get_string(&host) {
951 Ok(s) => s.into(),
952 Err(e) => {
953 error!("Failed to get repeater host: {}", e);
954 return 0;
955 }
956 };
957
958 let repeater_id_str: String = match env.get_string(&repeater_id) {
959 Ok(s) => s.into(),
960 Err(e) => {
961 error!("Failed to get repeater ID: {}", e);
962 return 0;
963 }
964 };
965
966 let request_id_opt: Option<String> = if !request_id.is_null() {
967 match env.get_string(&request_id) {
968 Ok(s) => {
969 let req_id: String = s.into();
970 if req_id.is_empty() {
971 None
972 } else {
973 Some(req_id)
974 }
975 }
976 Err(_) => None,
977 }
978 } else {
979 None
980 };
981
982 let port_u16 = port as u16;
983
984 info!(
985 "Connecting to VNC repeater {}:{} with ID: {}, request_id: {:?}",
986 host_str, port_u16, repeater_id_str, request_id_opt
987 );
988
989 if let Some(server_container) = VNC_SERVER.get() {
990 let server = match server_container.lock() {
991 Ok(guard) => {
992 if let Some(s) = guard.as_ref() {
993 s.clone()
994 } else {
995 error!("VNC server not started");
996 return 0;
997 }
998 }
999 Err(e) => {
1000 error!("Failed to lock server container: {}", e);
1001 return 0;
1002 }
1003 };
1004
1005 let runtime = get_or_init_vnc_runtime();
1006
1007 return runtime.block_on(async move {
1008 match server
1009 .connect_repeater_with_request_id(
1010 host_str,
1011 port_u16,
1012 repeater_id_str,
1013 request_id_opt,
1014 )
1015 .await
1016 {
1017 Ok(client_id) => {
1018 info!("Repeater connection established, client ID: {}", client_id);
1019 client_id as jlong
1020 }
1021 Err(e) => {
1022 error!("Failed to connect to repeater: {}", e);
1023 0
1024 }
1025 }
1026 });
1027 }
1028
1029 error!("VNC server not initialized");
1030 0
1031}
1032
1033extern "system" fn native_vnc_get_remote_host<'local>(
1034 env: JNIEnv<'local>,
1035 _class: JClass<'local>,
1036 client_id: jlong,
1037) -> JString<'local> {
1038 if let Some(server_container) = VNC_SERVER.get() {
1039 if let Ok(guard) = server_container.lock() {
1040 if let Some(server) = guard.as_ref() {
1041 if let Ok(clients) = server.clients_try_read() {
1042 for client_arc in clients.iter() {
1043 if let Ok(client_guard) = client_arc.try_read() {
1044 if client_guard.get_client_id() == client_id as usize {
1045 let host = client_guard.get_remote_host().to_string();
1046 if let Ok(jstr) = env.new_string(&host) {
1047 return jstr;
1048 }
1049 }
1050 }
1051 }
1052 }
1053 }
1054 }
1055 }
1056
1057 JString::default()
1058}
1059
1060extern "system" fn native_vnc_get_destination_port(
1061 _env: JNIEnv,
1062 _class: JClass,
1063 client_id: jlong,
1064) -> jint {
1065 if let Some(server_container) = VNC_SERVER.get() {
1066 if let Ok(guard) = server_container.lock() {
1067 if let Some(server) = guard.as_ref() {
1068 if let Ok(clients) = server.clients_try_read() {
1069 for client_arc in clients.iter() {
1070 if let Ok(client_guard) = client_arc.try_read() {
1071 if client_guard.get_client_id() == client_id as usize {
1072 return client_guard.get_destination_port();
1073 }
1074 }
1075 }
1076 }
1077 }
1078 }
1079 }
1080
1081 -1
1082}
1083
1084extern "system" fn native_vnc_get_repeater_id<'local>(
1085 env: JNIEnv<'local>,
1086 _class: JClass<'local>,
1087 client_id: jlong,
1088) -> JString<'local> {
1089 if let Some(server_container) = VNC_SERVER.get() {
1090 if let Ok(guard) = server_container.lock() {
1091 if let Some(server) = guard.as_ref() {
1092 if let Ok(clients) = server.clients_try_read() {
1093 for client_arc in clients.iter() {
1094 if let Ok(client_guard) = client_arc.try_read() {
1095 if client_guard.get_client_id() == client_id as usize {
1096 if let Some(id) = client_guard.get_repeater_id() {
1097 if let Ok(jstr) = env.new_string(id) {
1098 return jstr;
1099 }
1100 }
1101 }
1102 }
1103 }
1104 }
1105 }
1106 }
1107 }
1108
1109 JString::default()
1110}
1111
1112extern "system" fn native_vnc_disconnect(
1113 _env: JNIEnv,
1114 _class: JClass,
1115 client_id: jlong,
1116) -> jboolean {
1117 if let Some(server_container) = VNC_SERVER.get() {
1118 if let Ok(guard) = server_container.lock() {
1119 if let Some(server) = guard.as_ref() {
1120 if let Ok(mut clients) = server.clients_try_write() {
1121 let initial_len = clients.len();
1122
1123 clients.retain(|client_arc| {
1124 if let Ok(client_guard) = client_arc.try_read() {
1125 client_guard.get_client_id() != client_id as usize
1126 } else {
1127 true
1128 }
1129 });
1130
1131 let removed = clients.len() < initial_len;
1132 if removed {
1133 info!("Client {} disconnected successfully", client_id);
1134 return JNI_TRUE;
1135 } else {
1136 warn!("Client {} not found for disconnect", client_id);
1137 return JNI_FALSE;
1138 }
1139 }
1140 }
1141 }
1142 }
1143
1144 JNI_FALSE
1145}
1146
1147extern "system" fn native_vnc_schedule_copy_rect(
1148 _env: JNIEnv,
1149 _class: JClass,
1150 x: jint,
1151 y: jint,
1152 width: jint,
1153 height: jint,
1154 dx: jint,
1155 dy: jint,
1156) {
1157 if x < 0 || y < 0 || width <= 0 || height <= 0 {
1158 error!(
1159 "Invalid copy rect parameters: x={}, y={}, w={}, h={}",
1160 x, y, width, height
1161 );
1162 return;
1163 }
1164
1165 if let Some(server_container) = VNC_SERVER.get() {
1166 if let Ok(guard) = server_container.lock() {
1167 if let Some(server) = guard.as_ref() {
1168 let runtime = get_or_init_vnc_runtime();
1169 let server_clone = server.clone();
1170
1171 runtime.spawn(async move {
1172 server_clone
1173 .schedule_copy_rect(
1174 x as u16,
1175 y as u16,
1176 width as u16,
1177 height as u16,
1178 dx as i16,
1179 dy as i16,
1180 )
1181 .await;
1182 });
1183 }
1184 }
1185 }
1186}
1187
1188extern "system" fn native_vnc_do_copy_rect(
1189 _env: JNIEnv,
1190 _class: JClass,
1191 x: jint,
1192 y: jint,
1193 width: jint,
1194 height: jint,
1195 dx: jint,
1196 dy: jint,
1197) -> jboolean {
1198 if x < 0 || y < 0 || width <= 0 || height <= 0 {
1199 error!(
1200 "Invalid copy rect parameters: x={}, y={}, w={}, h={}",
1201 x, y, width, height
1202 );
1203 return JNI_FALSE;
1204 }
1205
1206 if let Some(server_container) = VNC_SERVER.get() {
1207 if let Ok(guard) = server_container.lock() {
1208 if let Some(server) = guard.as_ref() {
1209 let runtime = get_or_init_vnc_runtime();
1210
1211 let result = runtime.block_on(server.do_copy_rect(
1212 x as u16,
1213 y as u16,
1214 width as u16,
1215 height as u16,
1216 dx as i16,
1217 dy as i16,
1218 ));
1219
1220 match result {
1221 Ok(()) => return JNI_TRUE,
1222 Err(e) => {
1223 error!("Failed to perform copy rect: {}", e);
1224 return JNI_FALSE;
1225 }
1226 }
1227 }
1228 }
1229 }
1230
1231 error!("VNC server not initialized");
1232 JNI_FALSE
1233}
1234
1235fn spawn_event_handler(mut event_rx: mpsc::UnboundedReceiver<ServerEvent>) {
1241 if EVENT_HANDLER_RUNNING
1242 .compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst)
1243 .is_err()
1244 {
1245 warn!("Event handler already running");
1246 return;
1247 }
1248
1249 let runtime = get_or_init_vnc_runtime();
1250 let mut shutdown_rx = get_or_init_shutdown_signal().subscribe();
1251
1252 runtime.spawn(async move {
1253 info!("VNC event handler started");
1254
1255 loop {
1256 tokio::select! {
1257 Some(event) = event_rx.recv() => {
1258 handle_server_event(event);
1259 }
1260 _ = shutdown_rx.recv() => {
1261 info!("Event handler received shutdown signal");
1262 break;
1263 }
1264 }
1265 }
1266
1267 EVENT_HANDLER_RUNNING.store(false, Ordering::SeqCst);
1268 info!("VNC event handler stopped");
1269 });
1270}
1271
1272fn handle_server_event(event: ServerEvent) {
1274 let vm = match JAVA_VM.get() {
1275 Some(vm) => vm,
1276 None => {
1277 error!("Java VM not available");
1278 return;
1279 }
1280 };
1281
1282 let mut env = match vm.attach_current_thread() {
1283 Ok(env) => env,
1284 Err(e) => {
1285 error!("Failed to attach to Java thread: {}", e);
1286 return;
1287 }
1288 };
1289
1290 match event {
1291 ServerEvent::ClientConnected { client_id } => {
1292 info!("Client {} connected", client_id);
1293 if let Some(main_class) = MAIN_SERVICE_CLASS.get() {
1294 let args = [JValue::Long(client_id as jlong)];
1295 if let Err(e) =
1296 env.call_static_method(main_class, "onClientConnected", "(J)V", &args)
1297 {
1298 error!("Failed to call onClientConnected: {}", e);
1299 }
1300 }
1301 }
1302 ServerEvent::ClientDisconnected { client_id } => {
1303 info!("Client {} disconnected", client_id);
1304 if let Some(main_class) = MAIN_SERVICE_CLASS.get() {
1305 let args = [JValue::Long(client_id as jlong)];
1306 if let Err(e) =
1307 env.call_static_method(main_class, "onClientDisconnected", "(J)V", &args)
1308 {
1309 error!("Failed to call onClientDisconnected: {}", e);
1310 }
1311 }
1312 }
1313 ServerEvent::KeyPress {
1314 client_id,
1315 down,
1316 key,
1317 } => {
1318 if let Some(input_class) = INPUT_SERVICE_CLASS.get() {
1319 let args = [
1320 JValue::Int(if down { 1 } else { 0 }),
1321 JValue::Long(key as jlong),
1322 JValue::Long(client_id as jlong),
1323 ];
1324 if let Err(e) = env.call_static_method(input_class, "onKeyEvent", "(IJJ)V", &args) {
1325 error!("Failed to call onKeyEvent: {}", e);
1326 }
1327 }
1328 }
1329 ServerEvent::PointerMove {
1330 client_id,
1331 x,
1332 y,
1333 button_mask,
1334 } => {
1335 if let Some(input_class) = INPUT_SERVICE_CLASS.get() {
1336 let args = [
1337 JValue::Int(button_mask as jint),
1338 JValue::Int(x as jint),
1339 JValue::Int(y as jint),
1340 JValue::Long(client_id as jlong),
1341 ];
1342 if let Err(e) =
1343 env.call_static_method(input_class, "onPointerEvent", "(IIIJ)V", &args)
1344 {
1345 error!("Failed to call onPointerEvent: {}", e);
1346 }
1347 }
1348 }
1349 ServerEvent::CutText { client_id, text } => {
1350 if let Some(input_class) = INPUT_SERVICE_CLASS.get() {
1351 if let Ok(jtext) = env.new_string(&text) {
1352 let args = [JValue::Object(&jtext), JValue::Long(client_id as jlong)];
1353 if let Err(e) = env.call_static_method(
1354 input_class,
1355 "onCutText",
1356 "(Ljava/lang/String;J)V",
1357 &args,
1358 ) {
1359 error!("Failed to call onCutText: {}", e);
1360 }
1361 }
1362 }
1363 }
1364 ServerEvent::RfbMessageSent {
1365 client_id: _,
1366 request_id,
1367 success,
1368 } => {
1369 info!(
1370 "RFB message sent: request_id={:?}, success={}",
1371 request_id, success
1372 );
1373 if let Some(main_class) = MAIN_SERVICE_CLASS.get() {
1374 let request_id_obj: JObject = match &request_id {
1375 Some(id) => match env.new_string(id) {
1376 Ok(jstr) => JObject::from(jstr),
1377 Err(_) => JObject::null(),
1378 },
1379 None => JObject::null(),
1380 };
1381
1382 let args = [
1383 JValue::Object(&request_id_obj),
1384 JValue::Bool(u8::from(success)),
1385 ];
1386 if let Err(e) = env.call_static_method(
1387 main_class,
1388 "notifyRfbMessageSent",
1389 "(Ljava/lang/String;Z)V",
1390 &args,
1391 ) {
1392 error!("Failed to call notifyRfbMessageSent: {}", e);
1393 }
1394 }
1395 }
1396 ServerEvent::HandshakeComplete {
1397 client_id: _,
1398 request_id,
1399 success,
1400 } => {
1401 info!(
1402 "Handshake complete: request_id={:?}, success={}",
1403 request_id, success
1404 );
1405 if let Some(main_class) = MAIN_SERVICE_CLASS.get() {
1406 let request_id_obj: JObject = match &request_id {
1407 Some(id) => match env.new_string(id) {
1408 Ok(jstr) => JObject::from(jstr),
1409 Err(_) => JObject::null(),
1410 },
1411 None => JObject::null(),
1412 };
1413
1414 let args = [
1415 JValue::Object(&request_id_obj),
1416 JValue::Bool(u8::from(success)),
1417 ];
1418 if let Err(e) = env.call_static_method(
1419 main_class,
1420 "notifyHandshakeComplete",
1421 "(Ljava/lang/String;Z)V",
1422 &args,
1423 ) {
1424 error!("Failed to call notifyHandshakeComplete: {}", e);
1425 }
1426 }
1427 }
1428 }
1429}
1430
1431#[cfg(vnc_standalone)]
1452#[no_mangle]
1453pub extern "system" fn JNI_OnLoad(
1454 vm: jni::JavaVM,
1455 _reserved: *mut std::ffi::c_void,
1456) -> jni::sys::jint {
1457 use jni::sys::{JNI_ERR, JNI_VERSION_1_6};
1458
1459 android_logger::init_once(
1461 android_logger::Config::default()
1462 .with_max_level(log::LevelFilter::Info)
1463 .with_tag(env!("VNC_LOG_TAG")),
1464 );
1465
1466 info!("JNI_OnLoad: Registering VNC native methods");
1467
1468 let mut env = match vm.get_env() {
1470 Ok(env) => env,
1471 Err(e) => {
1472 error!("Failed to get JNI environment: {}", e);
1473 return JNI_ERR;
1474 }
1475 };
1476
1477 let main_class = concat!(env!("VNC_PACKAGE"), "/", env!("VNC_MAIN_SERVICE"));
1479 let input_class = concat!(env!("VNC_PACKAGE"), "/", env!("VNC_INPUT_SERVICE"));
1480
1481 info!(
1482 "Registering for classes: {} and {}",
1483 main_class, input_class
1484 );
1485
1486 match register_vnc_natives(&mut env, main_class, input_class) {
1488 Ok(()) => {
1489 info!("VNC native methods registered successfully");
1490 JNI_VERSION_1_6
1491 }
1492 Err(e) => {
1493 error!("Failed to register VNC native methods: {}", e);
1494 JNI_ERR
1495 }
1496 }
1497}