@@ -14,15 +14,21 @@ use sanzu_common::{
1414 ReadWrite , Tunnel ,
1515} ;
1616
17+ use serde:: { Deserialize , Serialize } ;
18+
1719use spin_sleep:: LoopHelper ;
1820use std:: {
1921 net:: { self , IpAddr , TcpListener } ,
22+ sync:: Mutex ,
2023 time:: Instant ,
2124} ;
2225
26+ #[ cfg( unix) ]
27+ use std:: io:: { self , BufRead , Write } ;
28+
2329#[ cfg( unix) ]
2430use std:: {
25- sync:: mpsc:: channel,
31+ sync:: mpsc:: { channel, Sender } ,
2632 thread:: { self } ,
2733} ;
2834
@@ -47,6 +53,21 @@ use crate::server_x11::init_x11rb;
4753#[ cfg( windows) ]
4854use crate :: server_windows:: init_win;
4955
56+ #[ derive( Debug , Serialize , Deserialize , Clone , Default ) ]
57+ struct ServerStats {
58+ fps : u64 ,
59+ frame_time : u64 ,
60+ grab : u64 ,
61+ enc : u64 ,
62+ send : u64 ,
63+ recv : u64 ,
64+ size : ( u16 , u16 ) ,
65+ }
66+
67+ lazy_static ! {
68+ static ref SERVER_STATS : Mutex <ServerStats > = Mutex :: new( ServerStats :: default ( ) ) ;
69+ }
70+
5071/// Tls auth / Kerberos Auth
5172fn auth_client (
5273 config_tls : & ConfigTls ,
@@ -97,6 +118,57 @@ fn auth_client(
97118 Ok ( ( tls_conn, username) )
98119}
99120
121+ #[ cfg( unix) ]
122+ /// Handle control api
123+ /// restart => restart encoder
124+ /// stats => send encoding stats
125+ fn control_api ( control_path : & str , control_sender : Sender < ( ) > ) {
126+ let pid = std:: process:: id ( ) ;
127+ let control_path = control_path. replace ( "%PID%" , & format ! ( "{pid}" ) ) ;
128+ // Try to remove path first
129+ let _ = std:: fs:: remove_file ( & control_path) ;
130+ let listener = std:: os:: unix:: net:: UnixListener :: bind ( & control_path)
131+ . unwrap_or_else ( |_| panic ! ( "Cannot bind {:?}" , control_path) ) ;
132+ loop {
133+ let ( mut client, addr) = listener. accept ( ) . expect ( "Error in UnixListener accept" ) ;
134+ info ! ( "Client {:?}" , addr) ;
135+ let control_sender_cp = control_sender. clone ( ) ;
136+ thread:: spawn ( move || {
137+ let mut command = String :: new ( ) ;
138+ if let Ok ( length) = io:: BufReader :: new ( & mut client) . read_line ( & mut command) {
139+ info ! ( "Command: {:?} {}" , command, length) ;
140+ match command. trim_end ( ) {
141+ "restart" => {
142+ info ! ( "Restart encoder requested" ) ;
143+ control_sender_cp. send ( ( ) ) . expect ( "Cannot send control" ) ;
144+ if client. write_all ( "Ok" . as_bytes ( ) ) . is_err ( ) {
145+ warn ! ( "Cannot send ok" ) ;
146+ }
147+ }
148+ "stats" => {
149+ info ! ( "Stats requested" ) ;
150+ let stats = SERVER_STATS . lock ( ) . unwrap ( ) . clone ( ) ;
151+
152+ if let Ok ( stats_str) = serde_json:: to_string ( & stats) {
153+ if client. write_all ( stats_str. as_bytes ( ) ) . is_err ( ) {
154+ warn ! ( "Cannot send stat" ) ;
155+ }
156+ } else {
157+ warn ! ( "Cannot generate stats" ) ;
158+ }
159+ }
160+ _ => {
161+ error ! ( "Unknown command" ) ;
162+ if client. write_all ( "Unknown command" . as_bytes ( ) ) . is_err ( ) {
163+ warn ! ( "Cannot send stat" ) ;
164+ }
165+ }
166+ }
167+ }
168+ } ) ;
169+ }
170+ }
171+
100172/// Exec main loop
101173///
102174pub fn run ( config : & ConfigServer , arguments : & ArgumentsSrv ) -> Result < ( ) > {
@@ -374,34 +446,18 @@ pub fn run_server(config: &ConfigServer, arguments: &ArgumentsSrv) -> Result<()>
374446 let mut loop_helper = LoopHelper :: builder ( ) . build_with_target_rate ( config. video . max_fps as f64 ) ; // limit FPS if possible
375447
376448 let mut new_size = None ;
377- let mut cur_size = None ;
449+ let ( width, height) = server_info. size ( ) ;
450+ let mut cur_size = Some ( ( width as u32 , height as u32 ) ) ;
378451
379452 // Do socket control
380453 #[ cfg( unix) ]
381454 let ( control_sender, control_receiver) = channel ( ) ;
382455 #[ cfg( unix) ]
383456 {
384- let control_path = config
385- . video
386- . control_path
387- . as_ref ( )
388- . map ( |path| path. to_owned ( ) ) ;
389- if let Some ( control_path) = control_path {
457+ if let Some ( control_path) = config. video . control_path . as_ref ( ) . cloned ( ) {
390458 info ! ( "Listening on control path {:?}" , control_path) ;
391459 thread:: spawn ( move || {
392- let pid = std:: process:: id ( ) ;
393- let control_path = control_path. replace ( "%PID%" , & format ! ( "{pid}" ) ) ;
394- // Try to remove path first
395- let _ = std:: fs:: remove_file ( & control_path) ;
396- let listener = std:: os:: unix:: net:: UnixListener :: bind ( & control_path)
397- . unwrap_or_else ( |_| panic ! ( "Cannot bind {:?}" , control_path) ) ;
398- loop {
399- let ( _, addr) = listener. accept ( ) . expect ( "Error in UnixListener accept" ) ;
400- info ! ( "Client {:?}" , addr) ;
401- control_sender
402- . send ( "test" . to_owned ( ) )
403- . expect ( "Cannot send control" ) ;
404- }
460+ control_api ( & control_path. clone ( ) , control_sender) ;
405461 } ) ;
406462 }
407463 }
@@ -563,6 +619,23 @@ pub fn run_server(config: &ConfigServer, arguments: &ArgumentsSrv) -> Result<()>
563619 ) ;
564620 debug ! ( "{}" , msg) ;
565621 msg_stats = msg;
622+ let fps = match frame_time_micro as u64 {
623+ 0 => 0 ,
624+ micros => 1_000_000 / micros,
625+ } ;
626+ let size = match cur_size. as_ref ( ) {
627+ Some ( ( width, height) ) => ( * width as u16 , * height as u16 ) ,
628+ None => ( 0 , 0 ) ,
629+ } ;
630+ * SERVER_STATS . lock ( ) . unwrap ( ) = ServerStats {
631+ fps,
632+ frame_time : ( time_start - prev_time_start) . as_millis ( ) as u64 ,
633+ grab : ( time_grab - time_start) . as_millis ( ) as u64 ,
634+ enc : ( time_encode - time_event) . as_millis ( ) as u64 ,
635+ send : ( time_send - time_sound) . as_millis ( ) as u64 ,
636+ recv : ( time_stop - time_send) . as_millis ( ) as u64 ,
637+ size,
638+ } ;
566639
567640 prev_time_start = time_start;
568641 loop_helper. loop_sleep ( ) ; // sleeps to acheive target FPS rate
0 commit comments