1use futures::TryStreamExt;
2use tokio_stream::wrappers::ReceiverStream;
3
4use std::{
5 future::Future,
6 sync::{
7 atomic::{AtomicU32, Ordering},
8 Arc,
9 },
10};
11use tokio::{
12 io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt},
13 sync::{
14 mpsc::{channel, error::TryRecvError, Receiver, Sender},
15 oneshot, Mutex,
16 },
17};
18use tokio_util::compat::*;
19use tracing::*;
20
21use crate::{codec, PixelFormat, Rect, VncEncoding, VncError, VncEvent, X11Event};
22const NETWORK_CHANNEL_SIZE: usize = 4096;
23const INPUT_CHANNEL_SIZE: usize = 4096;
24const OUTPUT_CHANNEL_SIZE: usize = 2;
25
26mod output;
27
28#[cfg(not(target_arch = "wasm32"))]
29use tokio::spawn;
30#[cfg(target_arch = "wasm32")]
31use wasm_bindgen_futures::spawn_local as spawn;
32
33use super::messages::{ClientMsg, ServerMsg};
34use super::resize::DesktopState;
35
36struct ImageRect {
37 rect: Rect,
38 encoding: VncEncoding,
39}
40
41impl TryFrom<[u8; 12]> for ImageRect {
42 type Error = VncError;
43 fn try_from(buf: [u8; 12]) -> Result<Self, VncError> {
44 Ok(Self {
45 rect: Rect {
46 x: ((buf[0] as u16) << 8) | buf[1] as u16,
47 y: ((buf[2] as u16) << 8) | buf[3] as u16,
48 width: ((buf[4] as u16) << 8) | buf[5] as u16,
49 height: ((buf[6] as u16) << 8) | buf[7] as u16,
50 },
51 encoding: VncEncoding::from_wire(
52 ((buf[8] as u32) << 24)
53 | ((buf[9] as u32) << 16)
54 | ((buf[10] as u32) << 8)
55 | (buf[11] as u32),
56 )?,
57 })
58 }
59}
60
61impl ImageRect {
62 async fn read<S>(reader: &mut S) -> Result<Self, VncError>
63 where
64 S: AsyncRead + Unpin,
65 {
66 let mut rect_buf = [0_u8; 12];
67 reader.read_exact(&mut rect_buf).await?;
68 rect_buf.try_into()
69 }
70}
71
72fn pack_screen((width, height): (u16, u16)) -> u32 {
75 (u32::from(width) << 16) | u32::from(height)
76}
77
78fn unpack_screen(packed: u32) -> (u16, u16) {
79 ((packed >> 16) as u16, packed as u16)
80}
81
82struct VncInner {
83 name: String,
84 screen: Arc<AtomicU32>,
85 desktop: Arc<DesktopState>,
86 input_ch: Sender<ClientMsg>,
87 output_ch: Receiver<VncEvent>,
88 decoding_stop: Option<oneshot::Sender<()>>,
89 net_conn_stop: Option<oneshot::Sender<()>>,
90 closed: bool,
91}
92
93impl VncInner {
96 async fn new<S>(
97 mut stream: S,
98 shared: bool,
99 mut pixel_format: Option<PixelFormat>,
100 encodings: Vec<VncEncoding>,
101 ) -> Result<Self, VncError>
102 where
103 S: AsyncRead + AsyncWrite + Unpin + Send + 'static,
104 {
105 let (conn_ch_tx, conn_ch_rx) = channel(NETWORK_CHANNEL_SIZE);
106 let (input_ch_tx, input_ch_rx) = channel(INPUT_CHANNEL_SIZE);
107 let (output_ch_tx, output_ch_rx) = channel(OUTPUT_CHANNEL_SIZE);
108 let (decoding_stop_tx, mut decoding_stop_rx) = oneshot::channel();
109 let (net_conn_stop_tx, net_conn_stop_rx) = oneshot::channel();
110
111 trace!("client init msg");
112 send_client_init(&mut stream, shared).await?;
113
114 trace!("server init msg");
115 let (name, (width, height)) =
116 read_server_init(&mut stream, &mut pixel_format, &|e| async {
117 output_ch_tx.send(e).await?;
118 Ok(())
119 })
120 .await?;
121
122 let screen = Arc::new(AtomicU32::new(pack_screen((width, height))));
123 let decoder_screen = Arc::clone(&screen);
124 let desktop = Arc::new(DesktopState::default());
125 let decoder_desktop = Arc::clone(&desktop);
126 let network_desktop = Arc::clone(&desktop);
127 trace!("client encodings: {:?}", encodings);
128 send_client_encoding(&mut stream, encodings.clone()).await?;
129
130 trace!("Require the first frame");
131 input_ch_tx
132 .send(ClientMsg::FramebufferUpdateRequest(
133 Rect {
134 x: 0,
135 y: 0,
136 width,
137 height,
138 },
139 0,
140 ))
141 .await?;
142
143 spawn(async move {
145 trace!("Decoding thread starts");
146 let mut conn_ch_rx = {
147 let conn_ch_rx = ReceiverStream::new(conn_ch_rx).into_async_read();
148 FuturesAsyncReadCompatExt::compat(conn_ch_rx)
149 };
150
151 let output_func = |e| async {
152 output_ch_tx.send(e).await?;
153 Ok(())
154 };
155
156 let pf = pixel_format.as_ref().unwrap();
157 let result = asycn_vnc_read_loop(
158 &mut conn_ch_rx,
159 pf,
160 &output_func,
161 &mut decoding_stop_rx,
162 &encodings,
163 &decoder_screen,
164 &decoder_desktop,
165 )
166 .await;
167 drop(conn_ch_rx);
170 decoder_desktop.close();
171 if let Err(error) = result {
172 output::report_error(error, &output_ch_tx, &mut decoding_stop_rx).await;
173 }
174 trace!("Decoding thread stops");
175 });
176
177 spawn(async move {
179 trace!("Net Connection thread starts");
180 let _ =
181 async_connection_process_loop(stream, input_ch_rx, conn_ch_tx, net_conn_stop_rx)
182 .await;
183 network_desktop.close();
184 trace!("Net Connection thread stops");
185 });
186
187 info!("VNC Client {name} starts");
188 Ok(Self {
189 name,
190 screen,
191 desktop,
192 input_ch: input_ch_tx,
193 output_ch: output_ch_rx,
194 decoding_stop: Some(decoding_stop_tx),
195 net_conn_stop: Some(net_conn_stop_tx),
196 closed: false,
197 })
198 }
199
200 fn input_message(&self, event: X11Event) -> Result<ClientMsg, VncError> {
201 if self.closed {
202 Err(VncError::ClientNotRunning)
203 } else {
204 let (width, height) = unpack_screen(self.screen.load(Ordering::Acquire));
205 let msg = match event {
206 X11Event::Refresh => ClientMsg::FramebufferUpdateRequest(
207 Rect {
208 x: 0,
209 y: 0,
210 width,
211 height,
212 },
213 1,
214 ),
215 X11Event::FullRefresh => ClientMsg::FramebufferUpdateRequest(
216 Rect {
217 x: 0,
218 y: 0,
219 width,
220 height,
221 },
222 0, ),
224 X11Event::KeyEvent(key) => ClientMsg::KeyEvent(key.keycode, key.down),
225 X11Event::PointerEvent(mouse) => {
226 ClientMsg::PointerEvent(mouse.position_x, mouse.position_y, mouse.bottons)
227 }
228 X11Event::CopyText(text) => {
229 if text.len() > crate::limits::MAX_TEXT {
230 return Err(VncError::InvalidImageData);
231 }
232 ClientMsg::ClientCutText(text)
233 }
234 };
235 Ok(msg)
236 }
237 }
238
239 async fn recv_event(&mut self) -> Result<VncEvent, VncError> {
240 if self.closed {
241 Err(VncError::ClientNotRunning)
242 } else {
243 match self.output_ch.recv().await {
244 Some(e) => Ok(e),
245 None => {
246 self.closed = true;
247 Err(VncError::ClientNotRunning)
248 }
249 }
250 }
251 }
252
253 async fn poll_event(&mut self) -> Result<Option<VncEvent>, VncError> {
254 if self.closed {
255 Err(VncError::ClientNotRunning)
256 } else {
257 match self.output_ch.try_recv() {
258 Err(TryRecvError::Disconnected) => {
259 self.closed = true;
260 Err(VncError::ClientNotRunning)
261 }
262 Err(TryRecvError::Empty) => Ok(None),
263 Ok(e) => Ok(Some(e)),
264 }
265 }
267 }
268
269 fn close(&mut self) -> Result<(), VncError> {
272 self.desktop.close();
273 if self.net_conn_stop.is_some() {
274 let net_conn_stop: oneshot::Sender<()> = self.net_conn_stop.take().unwrap();
275 let _ = net_conn_stop.send(());
276 }
277 if self.decoding_stop.is_some() {
278 let decoding_stop = self.decoding_stop.take().unwrap();
279 let _ = decoding_stop.send(());
280 }
281 self.closed = true;
282 Ok(())
283 }
284}
285
286impl Drop for VncInner {
287 fn drop(&mut self) {
288 info!("VNC Client {} stops", self.name);
289 let _ = self.close();
290 }
291}
292
293pub struct VncClient {
294 inner: Arc<Mutex<VncInner>>,
295 desktop: Arc<DesktopState>,
296 input_ch: Sender<ClientMsg>,
297}
298
299impl VncClient {
300 pub(super) async fn new<S>(
301 stream: S,
302 shared: bool,
303 pixel_format: Option<PixelFormat>,
304 encodings: Vec<VncEncoding>,
305 ) -> Result<Self, VncError>
306 where
307 S: AsyncRead + AsyncWrite + Unpin + Send + 'static,
308 {
309 let inner = VncInner::new(stream, shared, pixel_format, encodings).await?;
310 Ok(Self {
311 desktop: Arc::clone(&inner.desktop),
312 input_ch: inner.input_ch.clone(),
313 inner: Arc::new(Mutex::new(inner)),
314 })
315 }
316
317 pub fn desktop_layout(&self) -> Option<crate::DesktopLayout> {
319 self.desktop.layout()
320 }
321
322 #[cfg(not(target_arch = "wasm32"))]
329 pub async fn resize_desktop(
330 &self,
331 width: u16,
332 height: u16,
333 ) -> Result<crate::DesktopLayout, crate::ResizeError> {
334 self.desktop.request(&self.input_ch, width, height).await
335 }
336
337 pub async fn input(&self, event: X11Event) -> Result<(), VncError> {
340 let sender = {
341 let inner = self.inner.lock().await;
342 if inner.closed {
343 return Err(VncError::ClientNotRunning);
344 }
345 inner.input_ch.clone()
346 };
347 let permit = sender.reserve().await?;
349 let inner = self.inner.lock().await;
350 permit.send(inner.input_message(event)?);
351 Ok(())
352 }
353
354 pub async fn recv_event(&self) -> Result<VncEvent, VncError> {
358 self.inner.lock().await.recv_event().await
359 }
360
361 pub async fn poll_event(&self) -> Result<Option<VncEvent>, VncError> {
364 self.inner.lock().await.poll_event().await
365 }
366
367 pub async fn close(&self) -> Result<(), VncError> {
370 self.inner.lock().await.close()
371 }
372}
373
374impl Clone for VncClient {
375 fn clone(&self) -> Self {
376 Self {
377 inner: self.inner.clone(),
378 desktop: Arc::clone(&self.desktop),
379 input_ch: self.input_ch.clone(),
380 }
381 }
382}
383
384async fn send_client_init<S>(stream: &mut S, shared: bool) -> Result<(), VncError>
385where
386 S: AsyncRead + AsyncWrite + Unpin + Send + 'static,
387{
388 trace!("Send shared flag: {}", shared);
389 stream.write_u8(shared as u8).await?;
390 Ok(())
391}
392
393async fn read_server_init<S, F, Fut>(
394 stream: &mut S,
395 pf: &mut Option<PixelFormat>,
396 output_func: &F,
397) -> Result<(String, (u16, u16)), VncError>
398where
399 S: AsyncRead + AsyncWrite + Unpin + Send + 'static,
400 F: Fn(VncEvent) -> Fut,
401 Fut: Future<Output = Result<(), VncError>>,
402{
403 let screen_width = stream.read_u16().await?;
414 let screen_height = stream.read_u16().await?;
415 crate::limits::dimensions(screen_width, screen_height)?;
416 let mut send_our_pf = false;
417
418 output_func(VncEvent::SetResolution(
419 (screen_width, screen_height).into(),
420 ))
421 .await?;
422
423 let pixel_format = PixelFormat::read(stream).await?;
424 if pf.is_none() {
425 output_func(VncEvent::SetPixelFormat(pixel_format)).await?;
426 let _ = pf.insert(pixel_format);
427 } else {
428 send_our_pf = true;
429 }
430
431 let name = crate::limits::string(stream, crate::limits::MAX_NAME).await?;
432
433 if send_our_pf {
434 trace!("Send customized pixel format {:#?}", pf);
435 ClientMsg::SetPixelFormat(*pf.as_ref().unwrap())
436 .write(stream)
437 .await?;
438 }
439 Ok((name, (screen_width, screen_height)))
440}
441
442async fn send_client_encoding<S>(
443 stream: &mut S,
444 encodings: Vec<VncEncoding>,
445) -> Result<(), VncError>
446where
447 S: AsyncRead + AsyncWrite + Unpin + Send + 'static,
448{
449 ClientMsg::SetEncodings(encodings).write(stream).await?;
450 Ok(())
451}
452
453async fn asycn_vnc_read_loop<S, F, Fut>(
454 stream: &mut S,
455 pf: &PixelFormat,
456 output_func: &F,
457 stop_ch: &mut oneshot::Receiver<()>,
458 encodings: &[VncEncoding],
459 screen: &AtomicU32,
460 desktop: &DesktopState,
461) -> Result<(), VncError>
462where
463 S: AsyncRead + Unpin,
464 F: Fn(VncEvent) -> Fut,
465 Fut: Future<Output = Result<(), VncError>>,
466{
467 tokio::select! {
468 biased;
469 _ = stop_ch => Ok(()),
470 result = read_vnc_messages(stream, pf, output_func, encodings, screen, desktop) => result,
471 }
472}
473
474async fn read_vnc_messages<S, F, Fut>(
475 stream: &mut S,
476 pf: &PixelFormat,
477 output_func: &F,
478 encodings: &[VncEncoding],
479 shared_screen: &AtomicU32,
480 desktop: &DesktopState,
481) -> Result<(), VncError>
482where
483 S: AsyncRead + Unpin,
484 F: Fn(VncEvent) -> Fut,
485 Fut: Future<Output = Result<(), VncError>>,
486{
487 let mut raw_decoder = codec::RawDecoder::new();
488 let mut zrle_decoder = codec::ZrleDecoder::new();
489 let mut tight_decoder = codec::TightDecoder::new();
490 let mut trle_decoder = codec::TrleDecoder::new();
491 let mut cursor = codec::CursorDecoder::new();
492 let mut screen = unpack_screen(shared_screen.load(Ordering::Acquire));
493
494 loop {
496 let server_msg = ServerMsg::read(stream).await?;
497 trace!("Server message got: {:?}", server_msg);
498 match server_msg {
499 ServerMsg::FramebufferUpdate(rect_num) => {
500 let mut updates = crate::desktop::UpdateBatch::default();
501 let mut framebuffer_changed = false;
502 for _ in 0..rect_num {
503 let rect = ImageRect::read(stream).await?;
504 if rect.encoding != VncEncoding::Raw && !encodings.contains(&rect.encoding) {
505 return Err(VncError::InvalidImageData);
506 }
507 if !matches!(
508 rect.encoding,
509 VncEncoding::DesktopSizePseudo
510 | VncEncoding::ExtendedDesktopSizePseudo
511 | VncEncoding::LastRectPseudo
512 | VncEncoding::CursorPseudo
513 ) {
514 crate::limits::rectangle(&rect.rect, screen)?;
515 }
516 if !matches!(
517 rect.encoding,
518 VncEncoding::CursorPseudo
519 | VncEncoding::ExtendedDesktopSizePseudo
520 | VncEncoding::LastRectPseudo
521 ) {
522 if !updates.is_empty() {
523 return Err(VncError::InvalidImageData);
524 }
525 framebuffer_changed = true;
526 }
527
528 match rect.encoding {
529 VncEncoding::Raw => {
530 raw_decoder
531 .decode(pf, &rect.rect, stream, output_func)
532 .await?;
533 }
534 VncEncoding::CopyRect => {
535 let source_x = stream.read_u16().await?;
536 let source_y = stream.read_u16().await?;
537 let mut src_rect = rect.rect;
538 src_rect.x = source_x;
539 src_rect.y = source_y;
540 crate::limits::rectangle(&src_rect, screen)?;
541 output_func(VncEvent::Copy(rect.rect, src_rect)).await?;
542 }
543 VncEncoding::Tight => {
544 tight_decoder
545 .decode(pf, &rect.rect, stream, output_func)
546 .await?;
547 }
548 VncEncoding::Trle => {
549 trle_decoder
550 .decode(pf, &rect.rect, stream, output_func)
551 .await?;
552 }
553 VncEncoding::Zrle => {
554 zrle_decoder
555 .decode(pf, &rect.rect, stream, output_func)
556 .await?;
557 }
558 VncEncoding::CursorPseudo => {
559 cursor.decode(pf, &rect.rect, stream, output_func).await?;
560 }
561 VncEncoding::ExtendedDesktopSizePseudo => {
562 if framebuffer_changed {
565 return Err(VncError::InvalidImageData);
566 }
567 updates.push(crate::DesktopUpdate::read(stream, rect.rect).await?)?;
568 }
569 VncEncoding::DesktopSizePseudo => {
570 crate::limits::dimensions(rect.rect.width, rect.rect.height)?;
571 if rect.rect.x != 0 || rect.rect.y != 0 {
572 return Err(VncError::InvalidImageData);
573 }
574 screen = (rect.rect.width, rect.rect.height);
575 shared_screen.store(pack_screen(screen), Ordering::Release);
576 desktop.legacy_resize();
577 output_func(VncEvent::SetResolution(
578 (rect.rect.width, rect.rect.height).into(),
579 ))
580 .await?;
581 }
582 VncEncoding::LastRectPseudo => {
583 break;
584 }
585 }
586 }
587 for update in updates.into_updates() {
588 if let Some(layout) = &update.layout {
589 screen = (layout.width, layout.height);
590 shared_screen.store(pack_screen(screen), Ordering::Release);
591 }
592 desktop.observe(&update);
593 output_func(VncEvent::DesktopUpdate(update)).await?;
594 }
595 }
596 ServerMsg::Bell => {
598 output_func(VncEvent::Bell).await?;
599 }
600 ServerMsg::ServerCutText(text) => {
601 output_func(VncEvent::Text(text)).await?;
602 }
603 }
604 }
605}
606
607async fn async_connection_process_loop<S>(
608 mut stream: S,
609 mut input_ch: Receiver<ClientMsg>,
610 conn_ch: Sender<std::io::Result<Vec<u8>>>,
611 mut stop_ch: oneshot::Receiver<()>,
612) -> Result<(), VncError>
613where
614 S: AsyncRead + AsyncWrite + Unpin + Send + 'static,
615{
616 let mut buffer = [0; 65535];
617 let mut pending = 0;
618
619 loop {
620 tokio::select! {
621 _ = &mut stop_ch => break,
622 _ = conn_ch.closed() => break,
623 permit = conn_ch.reserve(), if pending > 0 => {
624 match permit {
625 Ok(permit) => {
626 permit.send(Ok(buffer[..pending].to_vec()));
627 pending = 0;
628 }
629 Err(_) => break,
630 }
631 }
632 result = stream.read(&mut buffer), if pending == 0 => {
633 match result {
634 Ok(0) | Err(_) => break,
635 Ok(length) => pending = length,
636 }
637 }
638 message = input_ch.recv() => {
639 let Some(message) = message else { break; };
640 tokio::select! {
641 biased;
642 _ = &mut stop_ch => break,
643 result = message.write(&mut stream) => result?,
644 }
645 }
646 }
647 }
648 Ok(())
650}
651
652#[cfg(test)]
653mod tests;
654
655#[cfg(test)]
656mod queue_tests;
657
658#[cfg(test)]
659mod resize_tests;