refactor windows specific session (#7170)

1. Modify the process to have the control side lead the session switching: After the control side sends a `LoginRequest`, the controlled side will add all session information and the current session ID in the `LoginResponse`. Upon receiving the `LoginResponse`, the control side will check if the current session ID matches the ID in the `LoginConfigHandler`. If they match, the control side will send the current session ID. If they don't match, a session selection dialog will pop up, the selected session id will be sent. Upon receiving this message, the controlled side will restart if different or sub service if same .
2. Always show physical console session on the top
3. Show running session and distinguish sessions with the same name
4. Not sub service until correct session id is ensured
5. Fix switch sides not work for multisession session
6. Remove all session string join/split except get_available_sessions in
   windows.rs
7. Fix prelogin, when share rdp is enabled and there is a rdp session,
   the console is in login screen, get_active_username will be the rdp's
   username and prelogin will be false, cm can't be created an that
   causes disconnection in a loop
8. Rename all user session to windows session

Known issue:
1. Use current process session id for `run_as_user`, sahil says it can
   be wrong but I didn't reproduce.
2. Have not change tray process to current session
3. File transfer doesn't update home directory when session changed
4. When it's in login screen, remote file directory is empty, because cm
   have not start up

Signed-off-by: 21pages <pages21@163.com>
This commit is contained in:
21pages
2024-02-18 22:08:25 +08:00
committed by GitHub
parent 4f1a4dc6a5
commit 0f44de7dc3
18 changed files with 376 additions and 416 deletions

View File

@@ -237,8 +237,8 @@ pub struct Connection {
file_remove_log_control: FileRemoveLogControl,
#[cfg(feature = "gpucodec")]
supported_encoding_flag: (bool, Option<bool>),
user_session_id: Option<u32>,
checked_multiple_session: bool,
need_sub_remote_service: bool,
remote_service_subed: bool,
}
impl ConnInner {
@@ -386,8 +386,8 @@ impl Connection {
file_remove_log_control: FileRemoveLogControl::new(id),
#[cfg(feature = "gpucodec")]
supported_encoding_flag: (false, None),
user_session_id: None,
checked_multiple_session: false,
need_sub_remote_service: false,
remote_service_subed: false,
};
let addr = hbb_common::try_into_v4(addr);
if !conn.on_open(addr).await {
@@ -1194,6 +1194,9 @@ impl Connection {
.into();
let mut sub_service = false;
let mut delay_sub_service = false;
#[cfg(windows)]
self.handle_windows_specific_session(&mut pi, &mut delay_sub_service);
if self.file_transfer.is_some() {
res.set_peer_info(pi);
} else {
@@ -1255,6 +1258,16 @@ impl Connection {
};
self.read_dir(dir, show_hidden);
} else if sub_service {
self.need_sub_remote_service = true;
if !delay_sub_service {
self.check_sub_remote_services();
}
}
}
fn check_sub_remote_services(&mut self) {
if self.need_sub_remote_service && !self.remote_service_subed {
self.remote_service_subed = true;
if let Some(s) = self.server.upgrade() {
let mut noperms = Vec::new();
if !self.peer_keyboard_enabled() && !self.show_remote_cursor {
@@ -1279,6 +1292,27 @@ impl Connection {
}
}
#[cfg(windows)]
fn handle_windows_specific_session(&mut self, pi: &mut PeerInfo, delay_sub_service: &mut bool) {
let sessions = crate::platform::get_available_sessions(true);
let current_sid = crate::platform::get_current_process_session_id().unwrap_or_default();
if crate::platform::is_installed()
&& crate::platform::is_share_rdp()
&& raii::AuthedConnID::remote_and_file_conn_count() == 1
&& sessions.len() > 1
&& current_sid != 0
&& self.lr.option.support_windows_specific_session == BoolOption::Yes.into()
{
pi.windows_sessions = Some(WindowsSessions {
sessions,
current_sid,
..Default::default()
})
.into();
*delay_sub_service = true;
}
}
fn on_remote_authorized(&self) {
self.update_codec_on_login();
#[cfg(any(target_os = "windows", target_os = "linux"))]
@@ -1495,50 +1529,8 @@ impl Connection {
self.video_ack_required = lr.video_ack_required;
}
#[cfg(target_os = "windows")]
async fn handle_multiple_user_sessions(&mut self, usid: Option<u32>) -> bool {
if self.port_forward_socket.is_some() {
return true;
} else {
let active_sessions = crate::platform::get_all_active_sessions();
if active_sessions.len() <= 1 {
return true;
}
let current_process_usid = crate::platform::get_current_process_session_id();
if usid.is_none() {
let mut res = Misc::new();
let mut rdp = Vec::new();
for session in active_sessions {
let u_sid = &session[0];
let u_name = &session[1];
let mut rdp_session = RdpUserSession::new();
rdp_session.user_session_id = u_sid.clone();
rdp_session.user_name = u_name.clone();
rdp.push(rdp_session);
}
res.set_rdp_user_sessions(RdpUserSessions {
rdp_user_sessions: rdp,
..Default::default()
});
let mut msg_out = Message::new();
msg_out.set_misc(res);
self.send(msg_out).await;
return true;
}
if usid != Some(current_process_usid) {
self.on_close("Reconnecting...", false).await;
std::thread::spawn(move || {
let _ = ipc::connect_to_user_session(usid);
});
return false;
}
true
}
}
#[cfg(not(any(target_os = "android", target_os = "ios")))]
fn try_start_cm_ipc(&mut self) {
let usid = self.user_session_id;
if let Some(p) = self.start_cm_ipc_para.take() {
tokio::spawn(async move {
#[cfg(windows)]
@@ -1548,7 +1540,6 @@ impl Connection {
p.tx_from_cm,
p.rx_desktop_ready,
p.tx_cm_stream_ready,
usid.clone(),
)
.await
{
@@ -1562,7 +1553,7 @@ impl Connection {
#[cfg(all(windows, feature = "flutter"))]
std::thread::spawn(move || {
if crate::is_server() && !crate::check_process("--tray", false) {
crate::platform::run_as_user(vec!["--tray"], usid).ok();
crate::platform::run_as_user(vec!["--tray"]).ok();
}
});
}
@@ -1570,19 +1561,6 @@ impl Connection {
async fn on_message(&mut self, msg: Message) -> bool {
if let Some(message::Union::LoginRequest(lr)) = msg.union {
#[cfg(target_os = "windows")]
{
if !self.checked_multiple_session {
let usid;
match lr.option.user_session.parse::<u32>() {
Ok(n) => usid = Some(n),
Err(..) => usid = None,
}
if usid.is_some() {
self.user_session_id = usid;
}
}
}
self.handle_login_request_without_validation(&lr).await;
if self.authorized {
return true;
@@ -1821,22 +1799,6 @@ impl Connection {
}
}
} else if self.authorized {
#[cfg(target_os = "windows")]
if !self.checked_multiple_session {
self.checked_multiple_session = true;
if crate::platform::is_installed()
&& crate::platform::is_share_rdp()
&& Self::alive_conns().len() == 1
&& get_version_number(&self.lr.version) >= get_version_number("1.2.4")
{
if !self
.handle_multiple_user_sessions(self.user_session_id)
.await
{
return false;
}
}
}
match msg.union {
Some(message::Union::MouseEvent(me)) => {
#[cfg(any(target_os = "android", target_os = "ios"))]
@@ -2304,6 +2266,26 @@ impl Connection {
.lock()
.unwrap()
.user_record(self.inner.id(), status),
#[cfg(windows)]
Some(misc::Union::SelectedSid(sid)) => {
let current_process_usid =
crate::platform::get_current_process_session_id().unwrap_or_default();
let sessions = crate::platform::get_available_sessions(false);
if crate::platform::is_installed()
&& crate::platform::is_share_rdp()
&& raii::AuthedConnID::remote_and_file_conn_count() == 1
&& sessions.len() > 1
&& current_process_usid != 0
&& current_process_usid != sid
&& sessions.iter().any(|e| e.sid == sid)
{
std::thread::spawn(move || {
let _ = ipc::connect_to_user_session(Some(sid));
});
return false;
}
self.check_sub_remote_services();
}
_ => {}
},
Some(message::Union::AudioFrame(frame)) => {
@@ -3087,7 +3069,6 @@ async fn start_ipc(
tx_from_cm: mpsc::UnboundedSender<ipc::Data>,
mut _rx_desktop_ready: mpsc::Receiver<()>,
tx_stream_ready: mpsc::Sender<()>,
user_session_id: Option<u32>,
) -> ResultType<()> {
use hbb_common::anyhow::anyhow;
@@ -3135,7 +3116,7 @@ async fn start_ipc(
if crate::platform::is_root() {
let mut res = Ok(None);
for _ in 0..10 {
#[cfg(not(any(target_os = "linux", target_os = "windows")))]
#[cfg(not(any(target_os = "linux")))]
{
log::debug!("Start cm");
res = crate::platform::run_as_user(args.clone());
@@ -3149,14 +3130,10 @@ async fn start_ipc(
None::<(&str, &str)>,
);
}
#[cfg(target_os = "windows")]
{
log::debug!("Start cm");
res = crate::platform::run_as_user(args.clone(), user_session_id);
}
if res.is_ok() {
break;
}
log::error!("Failed to run cm: {res:?}");
sleep(1.).await;
}
if let Some(task) = res? {
@@ -3540,6 +3517,15 @@ mod raii {
.unwrap()
.send((conn_count, remote_count)));
}
pub fn remote_and_file_conn_count() -> usize {
AUTHED_CONNS
.lock()
.unwrap()
.iter()
.filter(|c| c.1 == AuthConnType::Remote || c.1 == AuthConnType::FileTransfer)
.count()
}
}
impl Drop for AuthedConnID {

View File

@@ -50,7 +50,7 @@ use scrap::hwcodec::{HwEncoder, HwEncoderConfig};
use scrap::Capturer;
use scrap::{
aom::AomEncoderConfig,
codec::{Encoder, EncoderCfg, EncodingUpdate, Quality},
codec::{Encoder, EncoderCfg, Quality},
record::{Recorder, RecorderContext},
vpxcodec::{VpxEncoderConfig, VpxVideoCodecId},
CodecName, Display, Frame, TraitCapturer,
@@ -643,7 +643,7 @@ fn get_encoder_config(
GpuEncoder::set_not_use(_display_idx, true);
}
#[cfg(feature = "gpucodec")]
Encoder::update(EncodingUpdate::Check);
Encoder::update(scrap::codec::EncodingUpdate::Check);
// https://www.wowza.com/community/t/the-correct-keyframe-interval-in-obs-studio/95162
let keyframe_interval = if record { Some(240) } else { None };
let negotiated_codec = Encoder::negotiated_codec();