2022-05-08 21:01:03 +08:00
|
|
|
|
use std::{
|
|
|
|
|
collections::HashMap,
|
|
|
|
|
net::SocketAddr,
|
2022-05-19 21:45:25 +08:00
|
|
|
|
ops::{Deref, Not},
|
2022-05-19 18:39:13 +08:00
|
|
|
|
sync::{mpsc, Arc, Mutex, RwLock},
|
2022-05-08 21:01:03 +08:00
|
|
|
|
};
|
|
|
|
|
|
2021-03-29 15:59:14 +08:00
|
|
|
|
pub use async_trait::async_trait;
|
2022-04-23 02:17:33 +08:00
|
|
|
|
#[cfg(not(any(target_os = "android", target_os = "linux")))]
|
2021-03-29 15:59:14 +08:00
|
|
|
|
use cpal::{
|
|
|
|
|
traits::{DeviceTrait, HostTrait, StreamTrait},
|
|
|
|
|
Device, Host, StreamConfig,
|
|
|
|
|
};
|
2022-05-08 21:01:03 +08:00
|
|
|
|
use magnum_opus::{Channels::*, Decoder as AudioDecoder};
|
2022-05-29 17:23:14 +08:00
|
|
|
|
use scrap::{
|
2022-05-29 19:22:09 +08:00
|
|
|
|
codec::{Decoder, DecoderCfg},
|
2022-05-29 17:23:14 +08:00
|
|
|
|
VpxDecoderConfig, VpxVideoCodecId,
|
|
|
|
|
};
|
|
|
|
|
|
2022-05-08 21:01:03 +08:00
|
|
|
|
use sha2::{Digest, Sha256};
|
|
|
|
|
use uuid::Uuid;
|
|
|
|
|
|
2021-03-29 15:59:14 +08:00
|
|
|
|
use hbb_common::{
|
|
|
|
|
allow_err,
|
|
|
|
|
anyhow::{anyhow, Context},
|
|
|
|
|
bail,
|
|
|
|
|
config::{Config, PeerConfig, PeerInfoSerde, CONNECT_TIMEOUT, RELAY_PORT, RENDEZVOUS_TIMEOUT},
|
|
|
|
|
log,
|
2022-01-17 16:53:17 +08:00
|
|
|
|
message_proto::{option_message::BoolOption, *},
|
2021-03-29 15:59:14 +08:00
|
|
|
|
protobuf::Message as _,
|
|
|
|
|
rendezvous_proto::*,
|
2022-01-02 22:55:33 +08:00
|
|
|
|
socket_client,
|
2021-03-29 15:59:14 +08:00
|
|
|
|
sodiumoxide::crypto::{box_, secretbox, sign},
|
|
|
|
|
timeout,
|
|
|
|
|
tokio::time::Duration,
|
2022-03-26 00:06:06 +08:00
|
|
|
|
AddrMangle, ResultType, Stream,
|
2021-03-29 15:59:14 +08:00
|
|
|
|
};
|
2022-05-08 21:01:03 +08:00
|
|
|
|
|
|
|
|
|
pub use super::lang::*;
|
2022-05-12 17:35:25 +08:00
|
|
|
|
pub mod file_trait;
|
|
|
|
|
pub use file_trait::FileManager;
|
2022-05-20 00:11:48 +08:00
|
|
|
|
pub mod helper;
|
|
|
|
|
pub use helper::LatencyController;
|
2021-03-29 15:59:14 +08:00
|
|
|
|
pub const SEC30: Duration = Duration::from_secs(30);
|
|
|
|
|
|
|
|
|
|
pub struct Client;
|
|
|
|
|
|
2022-04-23 02:17:33 +08:00
|
|
|
|
#[cfg(not(any(target_os = "android", target_os = "linux")))]
|
2021-03-29 15:59:14 +08:00
|
|
|
|
lazy_static::lazy_static! {
|
|
|
|
|
static ref AUDIO_HOST: Host = cpal::default_host();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cfg_if::cfg_if! {
|
|
|
|
|
if #[cfg(target_os = "android")] {
|
|
|
|
|
|
|
|
|
|
use libc::{c_float, c_int, c_void};
|
|
|
|
|
type Oboe = *mut c_void;
|
|
|
|
|
extern "C" {
|
|
|
|
|
fn create_oboe_player(channels: c_int, sample_rate: c_int) -> Oboe;
|
|
|
|
|
fn push_oboe_data(oboe: Oboe, d: *const c_float, n: c_int);
|
|
|
|
|
fn destroy_oboe_player(oboe: Oboe);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct OboePlayer {
|
|
|
|
|
raw: Oboe,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Default for OboePlayer {
|
|
|
|
|
fn default() -> Self {
|
|
|
|
|
Self {
|
|
|
|
|
raw: std::ptr::null_mut(),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl OboePlayer {
|
|
|
|
|
fn new(channels: i32, sample_rate: i32) -> Self {
|
|
|
|
|
unsafe {
|
|
|
|
|
Self {
|
|
|
|
|
raw: create_oboe_player(channels, sample_rate),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn is_null(&self) -> bool {
|
|
|
|
|
self.raw.is_null()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn push(&mut self, d: &[f32]) {
|
|
|
|
|
if self.raw.is_null() {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
unsafe {
|
|
|
|
|
push_oboe_data(self.raw, d.as_ptr(), d.len() as _);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Drop for OboePlayer {
|
|
|
|
|
fn drop(&mut self) {
|
|
|
|
|
unsafe {
|
|
|
|
|
if !self.raw.is_null() {
|
|
|
|
|
destroy_oboe_player(self.raw);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Client {
|
2022-05-12 17:35:25 +08:00
|
|
|
|
pub async fn start(
|
|
|
|
|
peer: &str,
|
|
|
|
|
key: &str,
|
|
|
|
|
token: &str,
|
|
|
|
|
conn_type: ConnType,
|
|
|
|
|
) -> ResultType<(Stream, bool)> {
|
|
|
|
|
match Self::_start(peer, key, token, conn_type).await {
|
2022-01-05 23:50:13 +08:00
|
|
|
|
Err(err) => {
|
|
|
|
|
let err_str = err.to_string();
|
|
|
|
|
if err_str.starts_with("Failed") {
|
|
|
|
|
bail!(err_str + ": Please try later");
|
|
|
|
|
} else {
|
|
|
|
|
return Err(err);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Ok(x) => Ok(x),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-12 17:35:25 +08:00
|
|
|
|
async fn _start(
|
|
|
|
|
peer: &str,
|
|
|
|
|
key: &str,
|
|
|
|
|
token: &str,
|
|
|
|
|
conn_type: ConnType,
|
|
|
|
|
) -> ResultType<(Stream, bool)> {
|
2021-03-29 15:59:14 +08:00
|
|
|
|
// to-do: remember the port for each peer, so that we can retry easier
|
|
|
|
|
let any_addr = Config::get_any_listen_addr();
|
2022-01-05 23:50:13 +08:00
|
|
|
|
if crate::is_ip(peer) {
|
|
|
|
|
return Ok((
|
|
|
|
|
socket_client::connect_tcp(
|
|
|
|
|
crate::check_port(peer, RELAY_PORT + 1),
|
|
|
|
|
any_addr,
|
|
|
|
|
RENDEZVOUS_TIMEOUT,
|
|
|
|
|
)
|
|
|
|
|
.await?,
|
|
|
|
|
true,
|
|
|
|
|
));
|
|
|
|
|
}
|
2021-03-29 15:59:14 +08:00
|
|
|
|
let rendezvous_server = crate::get_rendezvous_server(1_000).await;
|
|
|
|
|
log::info!("rendezvous server: {}", rendezvous_server);
|
2022-01-02 22:55:33 +08:00
|
|
|
|
|
|
|
|
|
let mut socket =
|
2022-01-07 18:03:55 +08:00
|
|
|
|
socket_client::connect_tcp(&*rendezvous_server, any_addr, RENDEZVOUS_TIMEOUT).await?;
|
2022-01-02 22:55:33 +08:00
|
|
|
|
let my_addr = socket.local_addr();
|
2022-03-20 20:20:32 +08:00
|
|
|
|
let mut signed_id_pk = Vec::new();
|
2021-03-29 15:59:14 +08:00
|
|
|
|
let mut relay_server = "".to_owned();
|
|
|
|
|
|
|
|
|
|
let start = std::time::Instant::now();
|
|
|
|
|
let mut peer_addr = any_addr;
|
|
|
|
|
let mut peer_nat_type = NatType::UNKNOWN_NAT;
|
|
|
|
|
let my_nat_type = crate::get_nat_type(100).await;
|
|
|
|
|
let mut is_local = false;
|
|
|
|
|
for i in 1..=3 {
|
|
|
|
|
log::info!("#{} punch attempt with {}, id: {}", i, my_addr, peer);
|
|
|
|
|
let mut msg_out = RendezvousMessage::new();
|
|
|
|
|
use hbb_common::protobuf::ProtobufEnum;
|
|
|
|
|
let nat_type = NatType::from_i32(my_nat_type).unwrap_or(NatType::UNKNOWN_NAT);
|
|
|
|
|
msg_out.set_punch_hole_request(PunchHoleRequest {
|
|
|
|
|
id: peer.to_owned(),
|
2022-05-12 17:35:25 +08:00
|
|
|
|
token: token.to_owned(),
|
2021-03-29 15:59:14 +08:00
|
|
|
|
nat_type: nat_type.into(),
|
2022-05-12 17:35:25 +08:00
|
|
|
|
licence_key: key.to_owned(),
|
2021-07-27 23:53:12 +08:00
|
|
|
|
conn_type: conn_type.into(),
|
2021-03-29 15:59:14 +08:00
|
|
|
|
..Default::default()
|
|
|
|
|
});
|
|
|
|
|
socket.send(&msg_out).await?;
|
2021-08-04 00:57:03 +08:00
|
|
|
|
if let Some(Ok(bytes)) = socket.next_timeout(i * 6000).await {
|
2021-03-29 15:59:14 +08:00
|
|
|
|
if let Ok(msg_in) = RendezvousMessage::parse_from_bytes(&bytes) {
|
|
|
|
|
match msg_in.union {
|
|
|
|
|
Some(rendezvous_message::Union::punch_hole_response(ph)) => {
|
|
|
|
|
if ph.socket_addr.is_empty() {
|
2022-03-20 20:20:32 +08:00
|
|
|
|
if !ph.other_failure.is_empty() {
|
|
|
|
|
bail!(ph.other_failure);
|
|
|
|
|
}
|
2021-03-29 15:59:14 +08:00
|
|
|
|
match ph.failure.enum_value_or_default() {
|
|
|
|
|
punch_hole_response::Failure::ID_NOT_EXIST => {
|
2021-06-05 07:27:53 +08:00
|
|
|
|
bail!("ID does not exist");
|
2021-03-29 15:59:14 +08:00
|
|
|
|
}
|
|
|
|
|
punch_hole_response::Failure::OFFLINE => {
|
|
|
|
|
bail!("Remote desktop is offline");
|
|
|
|
|
}
|
2021-11-14 23:22:05 +08:00
|
|
|
|
punch_hole_response::Failure::LICENSE_MISMATCH => {
|
2021-07-27 23:53:12 +08:00
|
|
|
|
bail!("Key mismatch");
|
|
|
|
|
}
|
2022-03-20 20:20:32 +08:00
|
|
|
|
punch_hole_response::Failure::LICENSE_OVERUSE => {
|
|
|
|
|
bail!("Key overuse");
|
2021-07-27 23:53:12 +08:00
|
|
|
|
}
|
2021-03-29 15:59:14 +08:00
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
peer_nat_type = ph.get_nat_type();
|
|
|
|
|
is_local = ph.get_is_local();
|
2022-03-20 20:20:32 +08:00
|
|
|
|
signed_id_pk = ph.pk;
|
2021-03-29 15:59:14 +08:00
|
|
|
|
relay_server = ph.relay_server;
|
|
|
|
|
peer_addr = AddrMangle::decode(&ph.socket_addr);
|
|
|
|
|
log::info!("Hole Punched {} = {}", peer, peer_addr);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Some(rendezvous_message::Union::relay_response(rr)) => {
|
|
|
|
|
log::info!(
|
|
|
|
|
"relay requested from peer, time used: {:?}, relay_server: {}",
|
|
|
|
|
start.elapsed(),
|
|
|
|
|
rr.relay_server
|
|
|
|
|
);
|
2022-03-20 20:20:32 +08:00
|
|
|
|
signed_id_pk = rr.get_pk().into();
|
2021-03-29 15:59:14 +08:00
|
|
|
|
let mut conn =
|
2022-05-12 17:35:25 +08:00
|
|
|
|
Self::create_relay(peer, rr.uuid, rr.relay_server, key, conn_type)
|
2021-07-27 23:53:12 +08:00
|
|
|
|
.await?;
|
2022-05-12 17:35:25 +08:00
|
|
|
|
Self::secure_connection(peer, signed_id_pk, key, &mut conn).await?;
|
2021-03-29 15:59:14 +08:00
|
|
|
|
return Ok((conn, false));
|
|
|
|
|
}
|
|
|
|
|
_ => {
|
|
|
|
|
log::error!("Unexpected protobuf msg received: {:?}", msg_in);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
log::error!("Non-protobuf message bytes received: {:?}", bytes);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
drop(socket);
|
|
|
|
|
if peer_addr.port() == 0 {
|
|
|
|
|
bail!("Failed to connect via rendezvous server");
|
|
|
|
|
}
|
|
|
|
|
let time_used = start.elapsed().as_millis() as u64;
|
|
|
|
|
log::info!(
|
|
|
|
|
"{} ms used to punch hole, relay_server: {}, {}",
|
|
|
|
|
time_used,
|
|
|
|
|
relay_server,
|
|
|
|
|
if is_local {
|
|
|
|
|
"is_local: true".to_owned()
|
|
|
|
|
} else {
|
|
|
|
|
format!("nat_type: {:?}", peer_nat_type)
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
Self::connect(
|
|
|
|
|
my_addr,
|
|
|
|
|
peer_addr,
|
|
|
|
|
peer,
|
2022-03-20 20:20:32 +08:00
|
|
|
|
signed_id_pk,
|
2021-03-29 15:59:14 +08:00
|
|
|
|
&relay_server,
|
2022-01-05 13:21:14 +08:00
|
|
|
|
&rendezvous_server,
|
2021-03-29 15:59:14 +08:00
|
|
|
|
time_used,
|
|
|
|
|
peer_nat_type,
|
|
|
|
|
my_nat_type,
|
|
|
|
|
is_local,
|
2022-05-12 17:35:25 +08:00
|
|
|
|
key,
|
|
|
|
|
token,
|
2021-07-27 23:53:12 +08:00
|
|
|
|
conn_type,
|
2021-03-29 15:59:14 +08:00
|
|
|
|
)
|
|
|
|
|
.await
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async fn connect(
|
|
|
|
|
local_addr: SocketAddr,
|
|
|
|
|
peer: SocketAddr,
|
|
|
|
|
peer_id: &str,
|
2022-03-20 20:20:32 +08:00
|
|
|
|
signed_id_pk: Vec<u8>,
|
2021-03-29 15:59:14 +08:00
|
|
|
|
relay_server: &str,
|
2022-01-05 13:21:14 +08:00
|
|
|
|
rendezvous_server: &str,
|
2021-03-29 15:59:14 +08:00
|
|
|
|
punch_time_used: u64,
|
|
|
|
|
peer_nat_type: NatType,
|
|
|
|
|
my_nat_type: i32,
|
|
|
|
|
is_local: bool,
|
2022-05-12 17:35:25 +08:00
|
|
|
|
key: &str,
|
|
|
|
|
token: &str,
|
2021-07-27 23:53:12 +08:00
|
|
|
|
conn_type: ConnType,
|
2021-03-29 15:59:14 +08:00
|
|
|
|
) -> ResultType<(Stream, bool)> {
|
2021-07-27 23:53:12 +08:00
|
|
|
|
let direct_failures = PeerConfig::load(peer_id).direct_failures;
|
2021-03-29 15:59:14 +08:00
|
|
|
|
let mut connect_timeout = 0;
|
|
|
|
|
const MIN: u64 = 1000;
|
|
|
|
|
if is_local || peer_nat_type == NatType::SYMMETRIC {
|
|
|
|
|
connect_timeout = MIN;
|
|
|
|
|
} else {
|
|
|
|
|
if relay_server.is_empty() {
|
|
|
|
|
connect_timeout = CONNECT_TIMEOUT;
|
|
|
|
|
} else {
|
|
|
|
|
if peer_nat_type == NatType::ASYMMETRIC {
|
|
|
|
|
let mut my_nat_type = my_nat_type;
|
|
|
|
|
if my_nat_type == NatType::UNKNOWN_NAT as i32 {
|
|
|
|
|
my_nat_type = crate::get_nat_type(100).await;
|
|
|
|
|
}
|
|
|
|
|
if my_nat_type == NatType::ASYMMETRIC as i32 {
|
|
|
|
|
connect_timeout = CONNECT_TIMEOUT;
|
2021-07-27 23:53:12 +08:00
|
|
|
|
if direct_failures > 0 {
|
|
|
|
|
connect_timeout = punch_time_used * 6;
|
|
|
|
|
}
|
2021-03-29 15:59:14 +08:00
|
|
|
|
} else if my_nat_type == NatType::SYMMETRIC as i32 {
|
|
|
|
|
connect_timeout = MIN;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if connect_timeout == 0 {
|
|
|
|
|
let n = if direct_failures > 0 { 3 } else { 6 };
|
|
|
|
|
connect_timeout = punch_time_used * (n as u64);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if connect_timeout < MIN {
|
|
|
|
|
connect_timeout = MIN;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
log::info!("peer address: {}, timeout: {}", peer, connect_timeout);
|
|
|
|
|
let start = std::time::Instant::now();
|
2022-01-02 22:55:33 +08:00
|
|
|
|
// NOTICE: Socks5 is be used event in intranet. Which may be not a good way.
|
|
|
|
|
let mut conn = socket_client::connect_tcp(peer, local_addr, connect_timeout).await;
|
2021-03-29 15:59:14 +08:00
|
|
|
|
let direct = !conn.is_err();
|
|
|
|
|
if conn.is_err() {
|
|
|
|
|
if !relay_server.is_empty() {
|
|
|
|
|
conn = Self::request_relay(
|
|
|
|
|
peer_id,
|
|
|
|
|
relay_server.to_owned(),
|
|
|
|
|
rendezvous_server,
|
2022-03-20 20:20:32 +08:00
|
|
|
|
!signed_id_pk.is_empty(),
|
2022-05-12 17:35:25 +08:00
|
|
|
|
key,
|
|
|
|
|
token,
|
2021-07-27 23:53:12 +08:00
|
|
|
|
conn_type,
|
2021-03-29 15:59:14 +08:00
|
|
|
|
)
|
|
|
|
|
.await;
|
|
|
|
|
if conn.is_err() {
|
2021-07-27 23:53:12 +08:00
|
|
|
|
bail!(
|
|
|
|
|
"Failed to connect via relay server: {}",
|
|
|
|
|
conn.err().unwrap()
|
|
|
|
|
);
|
2021-03-29 15:59:14 +08:00
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
bail!("Failed to make direct connection to remote desktop");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if !relay_server.is_empty() && (direct_failures == 0) != direct {
|
|
|
|
|
let mut config = PeerConfig::load(peer_id);
|
|
|
|
|
config.direct_failures = if direct { 0 } else { 1 };
|
|
|
|
|
log::info!("direct_failures updated to {}", config.direct_failures);
|
|
|
|
|
config.store(peer_id);
|
|
|
|
|
}
|
|
|
|
|
let mut conn = conn?;
|
|
|
|
|
log::info!("{:?} used to establish connection", start.elapsed());
|
2022-05-12 17:35:25 +08:00
|
|
|
|
Self::secure_connection(peer_id, signed_id_pk, key, &mut conn).await?;
|
2021-03-29 15:59:14 +08:00
|
|
|
|
Ok((conn, direct))
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-12 17:35:25 +08:00
|
|
|
|
async fn secure_connection(
|
|
|
|
|
peer_id: &str,
|
|
|
|
|
signed_id_pk: Vec<u8>,
|
|
|
|
|
key: &str,
|
|
|
|
|
conn: &mut Stream,
|
|
|
|
|
) -> ResultType<()> {
|
|
|
|
|
let rs_pk = get_rs_pk(if key.is_empty() {
|
|
|
|
|
"OeVuKk5nlHiXp+APNn0Y3pC1Iwpwn44JGqrQCsWqmBw="
|
|
|
|
|
} else {
|
|
|
|
|
key
|
|
|
|
|
});
|
2022-03-20 20:20:32 +08:00
|
|
|
|
let mut sign_pk = None;
|
|
|
|
|
if !signed_id_pk.is_empty() && rs_pk.is_some() {
|
2022-03-26 00:06:06 +08:00
|
|
|
|
if let Ok((id, pk)) = decode_id_pk(&signed_id_pk, &rs_pk.unwrap()) {
|
|
|
|
|
if id == peer_id {
|
|
|
|
|
sign_pk = Some(sign::PublicKey(pk));
|
2022-03-20 20:20:32 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if sign_pk.is_none() {
|
2021-12-28 18:33:36 +08:00
|
|
|
|
log::error!("Handshake failed: invalid public key from rendezvous server");
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-03-20 20:20:32 +08:00
|
|
|
|
let sign_pk = match sign_pk {
|
|
|
|
|
Some(v) => v,
|
|
|
|
|
None => {
|
|
|
|
|
// send an empty message out in case server is setting up secure and waiting for first message
|
|
|
|
|
conn.send(&Message::new()).await?;
|
|
|
|
|
return Ok(());
|
|
|
|
|
}
|
|
|
|
|
};
|
2021-03-29 15:59:14 +08:00
|
|
|
|
match timeout(CONNECT_TIMEOUT, conn.next()).await? {
|
|
|
|
|
Some(res) => {
|
|
|
|
|
let bytes = res?;
|
|
|
|
|
if let Ok(msg_in) = Message::parse_from_bytes(&bytes) {
|
|
|
|
|
if let Some(message::Union::signed_id(si)) = msg_in.union {
|
2022-03-26 00:06:06 +08:00
|
|
|
|
if let Ok((id, their_pk_b)) = decode_id_pk(&si.id, &sign_pk) {
|
2021-12-28 18:33:36 +08:00
|
|
|
|
if id == peer_id {
|
2022-03-26 00:06:06 +08:00
|
|
|
|
let their_pk_b = box_::PublicKey(their_pk_b);
|
2021-03-29 15:59:14 +08:00
|
|
|
|
let (our_pk_b, out_sk_b) = box_::gen_keypair();
|
|
|
|
|
let key = secretbox::gen_key();
|
|
|
|
|
let nonce = box_::Nonce([0u8; box_::NONCEBYTES]);
|
|
|
|
|
let sealed_key = box_::seal(&key.0, &nonce, &their_pk_b, &out_sk_b);
|
|
|
|
|
let mut msg_out = Message::new();
|
|
|
|
|
msg_out.set_public_key(PublicKey {
|
|
|
|
|
asymmetric_value: our_pk_b.0.into(),
|
|
|
|
|
symmetric_value: sealed_key,
|
|
|
|
|
..Default::default()
|
|
|
|
|
});
|
|
|
|
|
timeout(CONNECT_TIMEOUT, conn.send(&msg_out)).await??;
|
|
|
|
|
conn.set_key(key);
|
|
|
|
|
} else {
|
2021-12-28 18:33:36 +08:00
|
|
|
|
log::error!("Handshake failed: sign failure");
|
|
|
|
|
conn.send(&Message::new()).await?;
|
2021-03-29 15:59:14 +08:00
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// fall back to non-secure connection in case pk mismatch
|
2021-07-27 23:53:12 +08:00
|
|
|
|
log::info!("pk mismatch, fall back to non-secure");
|
2021-03-29 15:59:14 +08:00
|
|
|
|
let mut msg_out = Message::new();
|
|
|
|
|
msg_out.set_public_key(PublicKey::new());
|
2022-03-26 00:06:06 +08:00
|
|
|
|
conn.send(&msg_out).await?;
|
2021-03-29 15:59:14 +08:00
|
|
|
|
}
|
|
|
|
|
} else {
|
2021-12-28 18:33:36 +08:00
|
|
|
|
log::error!("Handshake failed: invalid message type");
|
|
|
|
|
conn.send(&Message::new()).await?;
|
2021-03-29 15:59:14 +08:00
|
|
|
|
}
|
|
|
|
|
} else {
|
2021-12-28 18:33:36 +08:00
|
|
|
|
log::error!("Handshake failed: invalid message format");
|
|
|
|
|
conn.send(&Message::new()).await?;
|
2021-03-29 15:59:14 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
None => {
|
|
|
|
|
bail!("Reset by the peer");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async fn request_relay(
|
|
|
|
|
peer: &str,
|
|
|
|
|
relay_server: String,
|
2022-01-05 13:21:14 +08:00
|
|
|
|
rendezvous_server: &str,
|
2021-03-29 15:59:14 +08:00
|
|
|
|
secure: bool,
|
2022-05-12 17:35:25 +08:00
|
|
|
|
key: &str,
|
|
|
|
|
token: &str,
|
2021-07-27 23:53:12 +08:00
|
|
|
|
conn_type: ConnType,
|
2021-03-29 15:59:14 +08:00
|
|
|
|
) -> ResultType<Stream> {
|
|
|
|
|
let any_addr = Config::get_any_listen_addr();
|
|
|
|
|
let mut succeed = false;
|
|
|
|
|
let mut uuid = "".to_owned();
|
|
|
|
|
for i in 1..=3 {
|
|
|
|
|
// use different socket due to current hbbs implement requiring different nat address for each attempt
|
2022-01-02 22:55:33 +08:00
|
|
|
|
let mut socket =
|
|
|
|
|
socket_client::connect_tcp(rendezvous_server, any_addr, RENDEZVOUS_TIMEOUT)
|
|
|
|
|
.await
|
|
|
|
|
.with_context(|| "Failed to connect to rendezvous server")?;
|
|
|
|
|
|
2021-03-29 15:59:14 +08:00
|
|
|
|
let mut msg_out = RendezvousMessage::new();
|
|
|
|
|
uuid = Uuid::new_v4().to_string();
|
|
|
|
|
log::info!(
|
|
|
|
|
"#{} request relay attempt, id: {}, uuid: {}, relay_server: {}, secure: {}",
|
|
|
|
|
i,
|
|
|
|
|
peer,
|
|
|
|
|
uuid,
|
|
|
|
|
relay_server,
|
|
|
|
|
secure,
|
|
|
|
|
);
|
|
|
|
|
msg_out.set_request_relay(RequestRelay {
|
|
|
|
|
id: peer.to_owned(),
|
2022-05-12 17:35:25 +08:00
|
|
|
|
token: token.to_owned(),
|
2021-03-29 15:59:14 +08:00
|
|
|
|
uuid: uuid.clone(),
|
|
|
|
|
relay_server: relay_server.clone(),
|
|
|
|
|
secure,
|
|
|
|
|
..Default::default()
|
|
|
|
|
});
|
|
|
|
|
socket.send(&msg_out).await?;
|
2021-07-28 19:41:34 +08:00
|
|
|
|
if let Some(Ok(bytes)) = socket.next_timeout(CONNECT_TIMEOUT).await {
|
2021-03-29 15:59:14 +08:00
|
|
|
|
if let Ok(msg_in) = RendezvousMessage::parse_from_bytes(&bytes) {
|
2021-07-27 23:53:12 +08:00
|
|
|
|
if let Some(rendezvous_message::Union::relay_response(rs)) = msg_in.union {
|
|
|
|
|
if !rs.refuse_reason.is_empty() {
|
|
|
|
|
bail!(rs.refuse_reason);
|
|
|
|
|
}
|
2021-03-29 15:59:14 +08:00
|
|
|
|
succeed = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if !succeed {
|
2021-07-28 19:41:34 +08:00
|
|
|
|
bail!("Timeout");
|
2021-03-29 15:59:14 +08:00
|
|
|
|
}
|
2022-05-12 17:35:25 +08:00
|
|
|
|
Self::create_relay(peer, uuid, relay_server, key, conn_type).await
|
2021-03-29 15:59:14 +08:00
|
|
|
|
}
|
|
|
|
|
|
2021-07-27 23:53:12 +08:00
|
|
|
|
async fn create_relay(
|
|
|
|
|
peer: &str,
|
|
|
|
|
uuid: String,
|
|
|
|
|
relay_server: String,
|
2022-05-12 17:35:25 +08:00
|
|
|
|
key: &str,
|
2021-07-27 23:53:12 +08:00
|
|
|
|
conn_type: ConnType,
|
|
|
|
|
) -> ResultType<Stream> {
|
2022-01-02 22:55:33 +08:00
|
|
|
|
let mut conn = socket_client::connect_tcp(
|
2021-03-29 15:59:14 +08:00
|
|
|
|
crate::check_port(relay_server, RELAY_PORT),
|
|
|
|
|
Config::get_any_listen_addr(),
|
|
|
|
|
CONNECT_TIMEOUT,
|
|
|
|
|
)
|
|
|
|
|
.await
|
|
|
|
|
.with_context(|| "Failed to connect to relay server")?;
|
|
|
|
|
let mut msg_out = RendezvousMessage::new();
|
|
|
|
|
msg_out.set_request_relay(RequestRelay {
|
2022-05-12 17:35:25 +08:00
|
|
|
|
licence_key: key.to_owned(),
|
2021-03-29 15:59:14 +08:00
|
|
|
|
id: peer.to_owned(),
|
|
|
|
|
uuid,
|
2021-07-27 23:53:12 +08:00
|
|
|
|
conn_type: conn_type.into(),
|
2021-03-29 15:59:14 +08:00
|
|
|
|
..Default::default()
|
|
|
|
|
});
|
|
|
|
|
conn.send(&msg_out).await?;
|
|
|
|
|
Ok(conn)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Default)]
|
|
|
|
|
pub struct AudioHandler {
|
|
|
|
|
audio_decoder: Option<(AudioDecoder, Vec<f32>)>,
|
2022-04-23 02:17:33 +08:00
|
|
|
|
#[cfg(target_os = "android")]
|
|
|
|
|
oboe: Option<OboePlayer>,
|
|
|
|
|
#[cfg(target_os = "linux")]
|
|
|
|
|
simple: Option<psimple::Simple>,
|
|
|
|
|
#[cfg(not(any(target_os = "android", target_os = "linux")))]
|
|
|
|
|
audio_buffer: Arc<std::sync::Mutex<std::collections::vec_deque::VecDeque<f32>>>,
|
2021-03-29 15:59:14 +08:00
|
|
|
|
sample_rate: (u32, u32),
|
2022-04-23 02:17:33 +08:00
|
|
|
|
#[cfg(not(any(target_os = "android", target_os = "linux")))]
|
2021-03-29 15:59:14 +08:00
|
|
|
|
audio_stream: Option<Box<dyn StreamTrait>>,
|
|
|
|
|
channels: u16,
|
2022-05-19 21:45:25 +08:00
|
|
|
|
latency_controller: Arc<Mutex<LatencyController>>,
|
2021-03-29 15:59:14 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl AudioHandler {
|
2022-05-19 21:45:25 +08:00
|
|
|
|
pub fn new(latency_controller: Arc<Mutex<LatencyController>>) -> Self {
|
|
|
|
|
AudioHandler {
|
|
|
|
|
latency_controller,
|
|
|
|
|
..Default::default()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-23 02:17:33 +08:00
|
|
|
|
#[cfg(target_os = "linux")]
|
2021-03-29 15:59:14 +08:00
|
|
|
|
fn start_audio(&mut self, format0: AudioFormat) -> ResultType<()> {
|
2022-04-23 02:17:33 +08:00
|
|
|
|
use psimple::Simple;
|
|
|
|
|
use pulse::sample::{Format, Spec};
|
|
|
|
|
use pulse::stream::Direction;
|
|
|
|
|
|
|
|
|
|
let spec = Spec {
|
|
|
|
|
format: Format::F32le,
|
|
|
|
|
channels: format0.channels as _,
|
|
|
|
|
rate: format0.sample_rate as _,
|
|
|
|
|
};
|
|
|
|
|
if !spec.is_valid() {
|
|
|
|
|
bail!("Invalid audio format");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
self.simple = Some(Simple::new(
|
2022-05-13 14:46:37 +08:00
|
|
|
|
None, // Use the default server
|
|
|
|
|
&crate::get_app_name(), // Our application’s name
|
|
|
|
|
Direction::Playback, // We want a playback stream
|
|
|
|
|
None, // Use the default device
|
|
|
|
|
"playback", // Description of our stream
|
|
|
|
|
&spec, // Our sample format
|
|
|
|
|
None, // Use default channel map
|
|
|
|
|
None, // Use default buffering attributes
|
2022-04-23 02:17:33 +08:00
|
|
|
|
)?);
|
|
|
|
|
self.sample_rate = (format0.sample_rate, format0.sample_rate);
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(target_os = "android")]
|
|
|
|
|
fn start_audio(&mut self, format0: AudioFormat) -> ResultType<()> {
|
|
|
|
|
self.oboe = Some(OboePlayer::new(
|
|
|
|
|
format0.channels as _,
|
|
|
|
|
format0.sample_rate as _,
|
|
|
|
|
));
|
2021-03-29 15:59:14 +08:00
|
|
|
|
self.sample_rate = (format0.sample_rate, format0.sample_rate);
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-23 02:17:33 +08:00
|
|
|
|
#[cfg(not(any(target_os = "android", target_os = "linux")))]
|
2021-03-29 15:59:14 +08:00
|
|
|
|
fn start_audio(&mut self, format0: AudioFormat) -> ResultType<()> {
|
|
|
|
|
let device = AUDIO_HOST
|
|
|
|
|
.default_output_device()
|
|
|
|
|
.with_context(|| "Failed to get default output device")?;
|
|
|
|
|
log::info!(
|
|
|
|
|
"Using default output device: \"{}\"",
|
|
|
|
|
device.name().unwrap_or("".to_owned())
|
|
|
|
|
);
|
|
|
|
|
let config = device.default_output_config().map_err(|e| anyhow!(e))?;
|
|
|
|
|
let sample_format = config.sample_format();
|
|
|
|
|
log::info!("Default output format: {:?}", config);
|
|
|
|
|
log::info!("Remote input format: {:?}", format0);
|
|
|
|
|
let mut config: StreamConfig = config.into();
|
|
|
|
|
config.channels = format0.channels as _;
|
|
|
|
|
match sample_format {
|
|
|
|
|
cpal::SampleFormat::F32 => self.build_output_stream::<f32>(&config, &device)?,
|
|
|
|
|
cpal::SampleFormat::I16 => self.build_output_stream::<i16>(&config, &device)?,
|
|
|
|
|
cpal::SampleFormat::U16 => self.build_output_stream::<u16>(&config, &device)?,
|
|
|
|
|
}
|
|
|
|
|
self.sample_rate = (format0.sample_rate, config.sample_rate.0);
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn handle_format(&mut self, f: AudioFormat) {
|
|
|
|
|
match AudioDecoder::new(f.sample_rate, if f.channels > 1 { Stereo } else { Mono }) {
|
|
|
|
|
Ok(d) => {
|
|
|
|
|
let buffer = vec![0.; f.sample_rate as usize * f.channels as usize];
|
|
|
|
|
self.audio_decoder = Some((d, buffer));
|
|
|
|
|
self.channels = f.channels as _;
|
|
|
|
|
allow_err!(self.start_audio(f));
|
|
|
|
|
}
|
|
|
|
|
Err(err) => {
|
|
|
|
|
log::error!("Failed to create audio decoder: {}", err);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-30 21:16:08 +08:00
|
|
|
|
pub fn handle_frame(&mut self, frame: AudioFrame) {
|
2022-05-19 21:45:25 +08:00
|
|
|
|
if frame.timestamp != 0 {
|
|
|
|
|
if self
|
|
|
|
|
.latency_controller
|
|
|
|
|
.lock()
|
|
|
|
|
.unwrap()
|
|
|
|
|
.check_audio(frame.timestamp)
|
|
|
|
|
.not()
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-23 02:17:33 +08:00
|
|
|
|
#[cfg(not(any(target_os = "android", target_os = "linux")))]
|
2021-03-29 15:59:14 +08:00
|
|
|
|
if self.audio_stream.is_none() {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2022-04-23 02:17:33 +08:00
|
|
|
|
#[cfg(target_os = "linux")]
|
|
|
|
|
if self.simple.is_none() {
|
|
|
|
|
return;
|
2021-03-29 15:59:14 +08:00
|
|
|
|
}
|
2022-04-23 02:17:33 +08:00
|
|
|
|
#[cfg(target_os = "android")]
|
|
|
|
|
if self.oboe.is_none() {
|
|
|
|
|
return;
|
2021-03-29 15:59:14 +08:00
|
|
|
|
}
|
|
|
|
|
self.audio_decoder.as_mut().map(|(d, buffer)| {
|
|
|
|
|
if let Ok(n) = d.decode_float(&frame.data, buffer, false) {
|
2022-04-23 02:17:33 +08:00
|
|
|
|
let channels = self.channels;
|
2021-03-29 15:59:14 +08:00
|
|
|
|
let n = n * (channels as usize);
|
2022-04-23 02:17:33 +08:00
|
|
|
|
#[cfg(not(any(target_os = "android", target_os = "linux")))]
|
2021-03-29 15:59:14 +08:00
|
|
|
|
{
|
2022-04-23 02:17:33 +08:00
|
|
|
|
let sample_rate0 = self.sample_rate.0;
|
|
|
|
|
let sample_rate = self.sample_rate.1;
|
|
|
|
|
let audio_buffer = self.audio_buffer.clone();
|
|
|
|
|
// avoiding memory overflow if audio_buffer consumer side has problem
|
|
|
|
|
if audio_buffer.lock().unwrap().len() as u32 > sample_rate * 120 {
|
|
|
|
|
*audio_buffer.lock().unwrap() = Default::default();
|
|
|
|
|
}
|
2021-03-29 15:59:14 +08:00
|
|
|
|
if sample_rate != sample_rate0 {
|
|
|
|
|
let buffer = crate::resample_channels(
|
|
|
|
|
&buffer[0..n],
|
|
|
|
|
sample_rate0,
|
|
|
|
|
sample_rate,
|
|
|
|
|
channels,
|
|
|
|
|
);
|
|
|
|
|
audio_buffer.lock().unwrap().extend(buffer);
|
|
|
|
|
} else {
|
2022-01-10 01:29:50 +08:00
|
|
|
|
audio_buffer
|
|
|
|
|
.lock()
|
|
|
|
|
.unwrap()
|
|
|
|
|
.extend(buffer[0..n].iter().cloned());
|
2021-03-29 15:59:14 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
2022-04-23 02:17:33 +08:00
|
|
|
|
#[cfg(target_os = "android")]
|
|
|
|
|
{
|
|
|
|
|
self.oboe.as_mut().map(|x| x.push(&buffer[0..n]));
|
|
|
|
|
}
|
|
|
|
|
#[cfg(target_os = "linux")]
|
2021-03-29 15:59:14 +08:00
|
|
|
|
{
|
2022-04-23 02:17:33 +08:00
|
|
|
|
let data_u8 =
|
|
|
|
|
unsafe { std::slice::from_raw_parts::<u8>(buffer.as_ptr() as _, n * 4) };
|
|
|
|
|
self.simple.as_mut().map(|x| x.write(data_u8));
|
2021-03-29 15:59:14 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-23 02:17:33 +08:00
|
|
|
|
#[cfg(not(any(target_os = "android", target_os = "linux")))]
|
2021-03-29 15:59:14 +08:00
|
|
|
|
fn build_output_stream<T: cpal::Sample>(
|
|
|
|
|
&mut self,
|
|
|
|
|
config: &StreamConfig,
|
|
|
|
|
device: &Device,
|
|
|
|
|
) -> ResultType<()> {
|
|
|
|
|
let err_fn = move |err| {
|
2021-12-25 16:45:22 +08:00
|
|
|
|
// too many errors, will improve later
|
|
|
|
|
log::trace!("an error occurred on stream: {}", err);
|
2021-03-29 15:59:14 +08:00
|
|
|
|
};
|
|
|
|
|
let audio_buffer = self.audio_buffer.clone();
|
|
|
|
|
let stream = device.build_output_stream(
|
|
|
|
|
config,
|
|
|
|
|
move |data: &mut [T], _: &_| {
|
|
|
|
|
let mut lock = audio_buffer.lock().unwrap();
|
2022-02-28 18:35:40 +08:00
|
|
|
|
let mut n = data.len();
|
2021-03-29 15:59:14 +08:00
|
|
|
|
if lock.len() < n {
|
2022-02-28 18:35:40 +08:00
|
|
|
|
n = lock.len();
|
2021-03-29 15:59:14 +08:00
|
|
|
|
}
|
|
|
|
|
let mut input = lock.drain(0..n);
|
|
|
|
|
for sample in data.iter_mut() {
|
|
|
|
|
*sample = match input.next() {
|
|
|
|
|
Some(x) => T::from(&x),
|
|
|
|
|
_ => T::from(&0.),
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
err_fn,
|
|
|
|
|
)?;
|
|
|
|
|
stream.play()?;
|
|
|
|
|
self.audio_stream = Some(Box::new(stream));
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub struct VideoHandler {
|
|
|
|
|
decoder: Decoder,
|
2022-05-19 21:45:25 +08:00
|
|
|
|
latency_controller: Arc<Mutex<LatencyController>>,
|
2021-03-29 15:59:14 +08:00
|
|
|
|
pub rgb: Vec<u8>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl VideoHandler {
|
2022-05-19 21:45:25 +08:00
|
|
|
|
pub fn new(latency_controller: Arc<Mutex<LatencyController>>) -> Self {
|
2021-03-29 15:59:14 +08:00
|
|
|
|
VideoHandler {
|
2022-05-29 17:23:14 +08:00
|
|
|
|
decoder: Decoder::new(DecoderCfg {
|
|
|
|
|
vpx: VpxDecoderConfig {
|
|
|
|
|
codec: VpxVideoCodecId::VP9,
|
|
|
|
|
num_threads: (num_cpus::get() / 2) as _,
|
|
|
|
|
},
|
|
|
|
|
}),
|
2022-05-19 21:45:25 +08:00
|
|
|
|
latency_controller,
|
2021-03-29 15:59:14 +08:00
|
|
|
|
rgb: Default::default(),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-19 21:45:25 +08:00
|
|
|
|
pub fn handle_frame(&mut self, vf: VideoFrame) -> ResultType<bool> {
|
|
|
|
|
if vf.timestamp != 0 {
|
|
|
|
|
self.latency_controller
|
|
|
|
|
.lock()
|
|
|
|
|
.unwrap()
|
|
|
|
|
.update_video(vf.timestamp);
|
|
|
|
|
}
|
|
|
|
|
match &vf.union {
|
2022-05-29 17:23:14 +08:00
|
|
|
|
Some(frame) => self.decoder.handle_video_frame(frame, &mut self.rgb),
|
2022-05-19 21:45:25 +08:00
|
|
|
|
_ => Ok(false),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-29 15:59:14 +08:00
|
|
|
|
pub fn reset(&mut self) {
|
2022-05-29 17:23:14 +08:00
|
|
|
|
self.decoder = Decoder::new(DecoderCfg {
|
|
|
|
|
vpx: VpxDecoderConfig {
|
|
|
|
|
codec: VpxVideoCodecId::VP9,
|
|
|
|
|
num_threads: 1,
|
|
|
|
|
},
|
|
|
|
|
});
|
2021-03-29 15:59:14 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Default)]
|
|
|
|
|
pub struct LoginConfigHandler {
|
|
|
|
|
id: String,
|
2022-05-12 17:35:25 +08:00
|
|
|
|
pub is_file_transfer: bool,
|
2021-03-29 15:59:14 +08:00
|
|
|
|
is_port_forward: bool,
|
|
|
|
|
hash: Hash,
|
|
|
|
|
password: Vec<u8>, // remember password for reconnect
|
|
|
|
|
pub remember: bool,
|
|
|
|
|
config: PeerConfig,
|
|
|
|
|
pub port_forward: (String, i32),
|
2022-01-10 01:29:50 +08:00
|
|
|
|
pub version: i64,
|
2022-05-12 17:35:25 +08:00
|
|
|
|
pub conn_id: i32,
|
2022-04-25 12:28:28 +08:00
|
|
|
|
features: Option<Features>,
|
2021-03-29 15:59:14 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Deref for LoginConfigHandler {
|
|
|
|
|
type Target = PeerConfig;
|
|
|
|
|
|
|
|
|
|
fn deref(&self) -> &Self::Target {
|
|
|
|
|
&self.config
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn load_config(id: &str) -> PeerConfig {
|
|
|
|
|
PeerConfig::load(id)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl LoginConfigHandler {
|
|
|
|
|
pub fn initialize(&mut self, id: String, is_file_transfer: bool, is_port_forward: bool) {
|
|
|
|
|
self.id = id;
|
|
|
|
|
self.is_file_transfer = is_file_transfer;
|
|
|
|
|
self.is_port_forward = is_port_forward;
|
|
|
|
|
let config = self.load_config();
|
|
|
|
|
self.remember = !config.password.is_empty();
|
|
|
|
|
self.config = config;
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-12 17:35:25 +08:00
|
|
|
|
pub fn should_auto_login(&self) -> String {
|
|
|
|
|
let l = self.lock_after_session_end;
|
|
|
|
|
let a = !self.get_option("auto-login").is_empty();
|
|
|
|
|
let p = self.get_option("os-password");
|
|
|
|
|
if !p.is_empty() && l && a {
|
|
|
|
|
p
|
|
|
|
|
} else {
|
|
|
|
|
"".to_owned()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-29 15:59:14 +08:00
|
|
|
|
fn load_config(&self) -> PeerConfig {
|
|
|
|
|
load_config(&self.id)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn save_config(&mut self, config: PeerConfig) {
|
|
|
|
|
config.store(&self.id);
|
|
|
|
|
self.config = config;
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-25 16:45:22 +08:00
|
|
|
|
pub fn set_option(&mut self, k: String, v: String) {
|
|
|
|
|
let mut config = self.load_config();
|
|
|
|
|
config.options.insert(k, v);
|
|
|
|
|
self.save_config(config);
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-29 15:59:14 +08:00
|
|
|
|
pub fn save_view_style(&mut self, value: String) {
|
|
|
|
|
let mut config = self.load_config();
|
|
|
|
|
config.view_style = value;
|
|
|
|
|
self.save_config(config);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn toggle_option(&mut self, name: String) -> Option<Message> {
|
|
|
|
|
let mut option = OptionMessage::default();
|
|
|
|
|
let mut config = self.load_config();
|
|
|
|
|
if name == "show-remote-cursor" {
|
|
|
|
|
config.show_remote_cursor = !config.show_remote_cursor;
|
|
|
|
|
option.show_remote_cursor = (if config.show_remote_cursor {
|
|
|
|
|
BoolOption::Yes
|
|
|
|
|
} else {
|
|
|
|
|
BoolOption::No
|
|
|
|
|
})
|
|
|
|
|
.into();
|
|
|
|
|
} else if name == "disable-audio" {
|
|
|
|
|
config.disable_audio = !config.disable_audio;
|
|
|
|
|
option.disable_audio = (if config.disable_audio {
|
|
|
|
|
BoolOption::Yes
|
|
|
|
|
} else {
|
|
|
|
|
BoolOption::No
|
|
|
|
|
})
|
|
|
|
|
.into();
|
|
|
|
|
} else if name == "disable-clipboard" {
|
|
|
|
|
config.disable_clipboard = !config.disable_clipboard;
|
|
|
|
|
option.disable_clipboard = (if config.disable_clipboard {
|
|
|
|
|
BoolOption::Yes
|
|
|
|
|
} else {
|
|
|
|
|
BoolOption::No
|
|
|
|
|
})
|
|
|
|
|
.into();
|
|
|
|
|
} else if name == "lock-after-session-end" {
|
|
|
|
|
config.lock_after_session_end = !config.lock_after_session_end;
|
|
|
|
|
option.lock_after_session_end = (if config.lock_after_session_end {
|
|
|
|
|
BoolOption::Yes
|
|
|
|
|
} else {
|
|
|
|
|
BoolOption::No
|
|
|
|
|
})
|
|
|
|
|
.into();
|
|
|
|
|
} else if name == "privacy-mode" {
|
2022-04-25 12:28:28 +08:00
|
|
|
|
// try toggle privacy mode
|
2021-03-29 15:59:14 +08:00
|
|
|
|
option.privacy_mode = (if config.privacy_mode {
|
|
|
|
|
BoolOption::No
|
2022-04-25 12:28:28 +08:00
|
|
|
|
} else {
|
|
|
|
|
BoolOption::Yes
|
2021-03-29 15:59:14 +08:00
|
|
|
|
})
|
|
|
|
|
.into();
|
2022-02-15 14:46:08 +08:00
|
|
|
|
} else if name == "enable-file-transfer" {
|
|
|
|
|
config.enable_file_transfer = !config.enable_file_transfer;
|
|
|
|
|
option.enable_file_transfer = (if config.enable_file_transfer {
|
|
|
|
|
BoolOption::Yes
|
|
|
|
|
} else {
|
|
|
|
|
BoolOption::No
|
|
|
|
|
})
|
|
|
|
|
.into();
|
2021-03-29 15:59:14 +08:00
|
|
|
|
} else if name == "block-input" {
|
|
|
|
|
option.block_input = BoolOption::Yes.into();
|
|
|
|
|
} else if name == "unblock-input" {
|
|
|
|
|
option.block_input = BoolOption::No.into();
|
2022-06-23 17:42:30 +08:00
|
|
|
|
} else if name == "show-quality-monitor" {
|
|
|
|
|
config.show_quality_monitor = !config.show_quality_monitor;
|
2021-03-29 15:59:14 +08:00
|
|
|
|
} else {
|
|
|
|
|
let v = self.options.get(&name).is_some();
|
|
|
|
|
if v {
|
|
|
|
|
self.config.options.remove(&name);
|
|
|
|
|
} else {
|
|
|
|
|
self.config.options.insert(name, "Y".to_owned());
|
|
|
|
|
}
|
|
|
|
|
self.config.store(&self.id);
|
|
|
|
|
return None;
|
|
|
|
|
}
|
2022-01-15 18:27:15 +08:00
|
|
|
|
if !name.contains("block-input") {
|
|
|
|
|
self.save_config(config);
|
|
|
|
|
}
|
2021-03-29 15:59:14 +08:00
|
|
|
|
let mut misc = Misc::new();
|
|
|
|
|
misc.set_option(option);
|
|
|
|
|
let mut msg_out = Message::new();
|
|
|
|
|
msg_out.set_misc(misc);
|
|
|
|
|
Some(msg_out)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn get_option_message(&self, ignore_default: bool) -> Option<OptionMessage> {
|
|
|
|
|
if self.is_port_forward || self.is_file_transfer {
|
|
|
|
|
return None;
|
|
|
|
|
}
|
|
|
|
|
let mut n = 0;
|
|
|
|
|
let mut msg = OptionMessage::new();
|
|
|
|
|
let q = self.image_quality.clone();
|
|
|
|
|
if let Some(q) = self.get_image_quality_enum(&q, ignore_default) {
|
|
|
|
|
msg.image_quality = q.into();
|
|
|
|
|
n += 1;
|
|
|
|
|
} else if q == "custom" {
|
|
|
|
|
let config = PeerConfig::load(&self.id);
|
2022-06-23 17:42:30 +08:00
|
|
|
|
msg.custom_image_quality = config.custom_image_quality[0] as _;
|
|
|
|
|
n += 1;
|
2021-03-29 15:59:14 +08:00
|
|
|
|
}
|
|
|
|
|
if self.get_toggle_option("show-remote-cursor") {
|
|
|
|
|
msg.show_remote_cursor = BoolOption::Yes.into();
|
|
|
|
|
n += 1;
|
|
|
|
|
}
|
|
|
|
|
if self.get_toggle_option("lock-after-session-end") {
|
|
|
|
|
msg.lock_after_session_end = BoolOption::Yes.into();
|
|
|
|
|
n += 1;
|
|
|
|
|
}
|
2022-01-15 16:31:21 +08:00
|
|
|
|
if self.get_toggle_option("privacy-mode") {
|
2021-03-29 15:59:14 +08:00
|
|
|
|
msg.privacy_mode = BoolOption::Yes.into();
|
|
|
|
|
n += 1;
|
|
|
|
|
}
|
2022-01-29 21:30:14 +08:00
|
|
|
|
if self.get_toggle_option("disable-audio") {
|
|
|
|
|
msg.disable_audio = BoolOption::Yes.into();
|
|
|
|
|
n += 1;
|
|
|
|
|
}
|
2022-02-15 14:46:08 +08:00
|
|
|
|
if self.get_toggle_option("enable-file-transfer") {
|
|
|
|
|
msg.enable_file_transfer = BoolOption::Yes.into();
|
|
|
|
|
n += 1;
|
|
|
|
|
}
|
2022-01-29 21:30:14 +08:00
|
|
|
|
if self.get_toggle_option("disable-clipboard") {
|
|
|
|
|
msg.disable_clipboard = BoolOption::Yes.into();
|
|
|
|
|
n += 1;
|
|
|
|
|
}
|
2022-05-29 17:23:14 +08:00
|
|
|
|
// TODO: add option
|
|
|
|
|
let state = Decoder::video_codec_state();
|
|
|
|
|
msg.video_codec_state = hbb_common::protobuf::MessageField::some(state);
|
|
|
|
|
n += 1;
|
|
|
|
|
|
2021-03-29 15:59:14 +08:00
|
|
|
|
if n > 0 {
|
|
|
|
|
Some(msg)
|
|
|
|
|
} else {
|
|
|
|
|
None
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn get_image_quality_enum(&self, q: &str, ignore_default: bool) -> Option<ImageQuality> {
|
|
|
|
|
if q == "low" {
|
|
|
|
|
Some(ImageQuality::Low)
|
|
|
|
|
} else if q == "best" {
|
|
|
|
|
Some(ImageQuality::Best)
|
|
|
|
|
} else if q == "balanced" {
|
|
|
|
|
if ignore_default {
|
|
|
|
|
None
|
|
|
|
|
} else {
|
|
|
|
|
Some(ImageQuality::Balanced)
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
None
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn get_toggle_option(&self, name: &str) -> bool {
|
|
|
|
|
if name == "show-remote-cursor" {
|
|
|
|
|
self.config.show_remote_cursor
|
|
|
|
|
} else if name == "lock-after-session-end" {
|
|
|
|
|
self.config.lock_after_session_end
|
|
|
|
|
} else if name == "privacy-mode" {
|
|
|
|
|
self.config.privacy_mode
|
2022-02-15 15:35:19 +08:00
|
|
|
|
} else if name == "enable-file-transfer" {
|
|
|
|
|
self.config.enable_file_transfer
|
2021-03-29 15:59:14 +08:00
|
|
|
|
} else if name == "disable-audio" {
|
|
|
|
|
self.config.disable_audio
|
|
|
|
|
} else if name == "disable-clipboard" {
|
|
|
|
|
self.config.disable_clipboard
|
2022-06-23 17:42:30 +08:00
|
|
|
|
} else if name == "show-quality-monitor" {
|
|
|
|
|
self.config.show_quality_monitor
|
2021-03-29 15:59:14 +08:00
|
|
|
|
} else {
|
|
|
|
|
!self.get_option(name).is_empty()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-25 12:28:28 +08:00
|
|
|
|
pub fn is_privacy_mode_supported(&self) -> bool {
|
|
|
|
|
if let Some(features) = &self.features {
|
|
|
|
|
features.privacy_mode
|
|
|
|
|
} else {
|
|
|
|
|
false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-29 15:59:14 +08:00
|
|
|
|
pub fn refresh() -> Message {
|
|
|
|
|
let mut misc = Misc::new();
|
|
|
|
|
misc.set_refresh_video(true);
|
|
|
|
|
let mut msg_out = Message::new();
|
|
|
|
|
msg_out.set_misc(misc);
|
|
|
|
|
msg_out
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-27 18:30:46 +08:00
|
|
|
|
pub fn save_custom_image_quality(&mut self, custom_image_quality: i32) -> Message {
|
2021-03-29 15:59:14 +08:00
|
|
|
|
let mut misc = Misc::new();
|
|
|
|
|
misc.set_option(OptionMessage {
|
2022-06-23 17:42:30 +08:00
|
|
|
|
custom_image_quality,
|
2021-03-29 15:59:14 +08:00
|
|
|
|
..Default::default()
|
|
|
|
|
});
|
|
|
|
|
let mut msg_out = Message::new();
|
|
|
|
|
msg_out.set_misc(misc);
|
|
|
|
|
let mut config = self.load_config();
|
|
|
|
|
config.image_quality = "custom".to_owned();
|
2022-06-23 17:42:30 +08:00
|
|
|
|
config.custom_image_quality = vec![custom_image_quality as _];
|
2021-03-29 15:59:14 +08:00
|
|
|
|
self.save_config(config);
|
|
|
|
|
msg_out
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn save_image_quality(&mut self, value: String) -> Option<Message> {
|
|
|
|
|
let mut res = None;
|
|
|
|
|
if let Some(q) = self.get_image_quality_enum(&value, false) {
|
|
|
|
|
let mut misc = Misc::new();
|
|
|
|
|
misc.set_option(OptionMessage {
|
|
|
|
|
image_quality: q.into(),
|
|
|
|
|
..Default::default()
|
|
|
|
|
});
|
|
|
|
|
let mut msg_out = Message::new();
|
|
|
|
|
msg_out.set_misc(misc);
|
|
|
|
|
res = Some(msg_out);
|
|
|
|
|
}
|
|
|
|
|
let mut config = self.load_config();
|
|
|
|
|
config.image_quality = value;
|
|
|
|
|
self.save_config(config);
|
|
|
|
|
res
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn get_option(&self, k: &str) -> String {
|
|
|
|
|
if let Some(v) = self.config.options.get(k) {
|
|
|
|
|
v.clone()
|
|
|
|
|
} else {
|
|
|
|
|
"".to_owned()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn handle_login_error(&mut self, err: &str, interface: &impl Interface) -> bool {
|
|
|
|
|
if err == "Wrong Password" {
|
|
|
|
|
self.password = Default::default();
|
|
|
|
|
interface.msgbox("re-input-password", err, "Do you want to enter again?");
|
|
|
|
|
true
|
|
|
|
|
} else {
|
|
|
|
|
interface.msgbox("error", "Login Error", err);
|
|
|
|
|
false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn get_username(&self, pi: &PeerInfo) -> String {
|
|
|
|
|
return if pi.username.is_empty() {
|
|
|
|
|
self.info.username.clone()
|
|
|
|
|
} else {
|
|
|
|
|
pi.username.clone()
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn handle_peer_info(&mut self, username: String, pi: PeerInfo) {
|
|
|
|
|
if !pi.version.is_empty() {
|
2022-01-15 02:16:00 +08:00
|
|
|
|
self.version = hbb_common::get_version_number(&pi.version);
|
2021-03-29 15:59:14 +08:00
|
|
|
|
}
|
2022-04-25 12:28:28 +08:00
|
|
|
|
self.features = pi.features.into_option();
|
2021-03-29 15:59:14 +08:00
|
|
|
|
let serde = PeerInfoSerde {
|
|
|
|
|
username,
|
|
|
|
|
hostname: pi.hostname.clone(),
|
|
|
|
|
platform: pi.platform.clone(),
|
|
|
|
|
};
|
|
|
|
|
let mut config = self.load_config();
|
|
|
|
|
config.info = serde;
|
|
|
|
|
let password = self.password.clone();
|
|
|
|
|
let password0 = config.password.clone();
|
|
|
|
|
let remember = self.remember;
|
|
|
|
|
if remember {
|
|
|
|
|
if !password.is_empty() && password != password0 {
|
|
|
|
|
config.password = password;
|
|
|
|
|
log::debug!("remember password of {}", self.id);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if !password0.is_empty() {
|
|
|
|
|
config.password = Default::default();
|
|
|
|
|
log::debug!("remove password of {}", self.id);
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-05-12 17:35:25 +08:00
|
|
|
|
self.conn_id = pi.conn_id;
|
2021-03-29 15:59:14 +08:00
|
|
|
|
// no matter if change, for update file time
|
|
|
|
|
self.save_config(config);
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-12 17:35:25 +08:00
|
|
|
|
pub fn get_remote_dir(&self) -> String {
|
2022-04-07 22:13:30 +08:00
|
|
|
|
serde_json::from_str::<HashMap<String, String>>(&self.get_option("remote_dir"))
|
|
|
|
|
.unwrap_or_default()
|
|
|
|
|
.remove(&self.info.username)
|
|
|
|
|
.unwrap_or_default()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn get_all_remote_dir(&self, path: String) -> String {
|
|
|
|
|
let d = self.get_option("remote_dir");
|
|
|
|
|
let user = self.info.username.clone();
|
|
|
|
|
let mut x = serde_json::from_str::<HashMap<String, String>>(&d).unwrap_or_default();
|
|
|
|
|
if path.is_empty() {
|
|
|
|
|
x.remove(&user);
|
|
|
|
|
} else {
|
|
|
|
|
x.insert(user, path);
|
|
|
|
|
}
|
|
|
|
|
serde_json::to_string::<HashMap<String, String>>(&x).unwrap_or_default()
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-29 15:59:14 +08:00
|
|
|
|
fn create_login_msg(&self, password: Vec<u8>) -> Message {
|
|
|
|
|
#[cfg(any(target_os = "android", target_os = "ios"))]
|
2022-05-12 17:35:25 +08:00
|
|
|
|
let my_id = Config::get_id_or(crate::common::MOBILE_INFO1.lock().unwrap().clone());
|
2021-03-29 15:59:14 +08:00
|
|
|
|
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
|
|
|
|
let my_id = Config::get_id();
|
|
|
|
|
let mut lr = LoginRequest {
|
|
|
|
|
username: self.id.clone(),
|
|
|
|
|
password,
|
|
|
|
|
my_id,
|
|
|
|
|
my_name: crate::username(),
|
|
|
|
|
option: self.get_option_message(true).into(),
|
|
|
|
|
..Default::default()
|
|
|
|
|
};
|
|
|
|
|
if self.is_file_transfer {
|
|
|
|
|
lr.set_file_transfer(FileTransfer {
|
2022-04-07 22:13:30 +08:00
|
|
|
|
dir: self.get_remote_dir(),
|
2021-03-29 15:59:14 +08:00
|
|
|
|
show_hidden: !self.get_option("remote_show_hidden").is_empty(),
|
|
|
|
|
..Default::default()
|
|
|
|
|
});
|
|
|
|
|
} else if self.is_port_forward {
|
|
|
|
|
lr.set_port_forward(PortForward {
|
|
|
|
|
host: self.port_forward.0.clone(),
|
|
|
|
|
port: self.port_forward.1,
|
|
|
|
|
..Default::default()
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
let mut msg_out = Message::new();
|
|
|
|
|
msg_out.set_login_request(lr);
|
|
|
|
|
msg_out
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-30 21:16:08 +08:00
|
|
|
|
pub enum MediaData {
|
|
|
|
|
VideoFrame(VideoFrame),
|
|
|
|
|
AudioFrame(AudioFrame),
|
|
|
|
|
AudioFormat(AudioFormat),
|
|
|
|
|
Reset,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub type MediaSender = mpsc::Sender<MediaData>;
|
|
|
|
|
|
|
|
|
|
pub fn start_video_audio_threads<F>(video_callback: F) -> (MediaSender, MediaSender)
|
|
|
|
|
where
|
|
|
|
|
F: 'static + FnMut(&[u8]) + Send,
|
|
|
|
|
{
|
|
|
|
|
let (video_sender, video_receiver) = mpsc::channel::<MediaData>();
|
|
|
|
|
let (audio_sender, audio_receiver) = mpsc::channel::<MediaData>();
|
|
|
|
|
let mut video_callback = video_callback;
|
|
|
|
|
|
2022-05-19 21:45:25 +08:00
|
|
|
|
let latency_controller = LatencyController::new();
|
|
|
|
|
let latency_controller_cl = latency_controller.clone();
|
2022-06-09 17:14:26 +08:00
|
|
|
|
// Create video_handler out of the thread below to ensure that the handler exists before client start.
|
|
|
|
|
// It will take a few tenths of a second for the first time, and then tens of milliseconds.
|
|
|
|
|
let mut video_handler = VideoHandler::new(latency_controller);
|
2022-05-19 21:45:25 +08:00
|
|
|
|
|
2022-01-30 21:16:08 +08:00
|
|
|
|
std::thread::spawn(move || {
|
|
|
|
|
loop {
|
|
|
|
|
if let Ok(data) = video_receiver.recv() {
|
|
|
|
|
match data {
|
|
|
|
|
MediaData::VideoFrame(vf) => {
|
2022-05-19 21:45:25 +08:00
|
|
|
|
if let Ok(true) = video_handler.handle_frame(vf) {
|
|
|
|
|
video_callback(&video_handler.rgb);
|
2022-01-30 21:16:08 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
MediaData::Reset => {
|
|
|
|
|
video_handler.reset();
|
|
|
|
|
}
|
|
|
|
|
_ => {}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
log::info!("Video decoder loop exits");
|
|
|
|
|
});
|
|
|
|
|
std::thread::spawn(move || {
|
2022-05-19 21:45:25 +08:00
|
|
|
|
let mut audio_handler = AudioHandler::new(latency_controller_cl);
|
2022-01-30 21:16:08 +08:00
|
|
|
|
loop {
|
|
|
|
|
if let Ok(data) = audio_receiver.recv() {
|
|
|
|
|
match data {
|
|
|
|
|
MediaData::AudioFrame(af) => {
|
2022-05-19 21:45:25 +08:00
|
|
|
|
audio_handler.handle_frame(af);
|
2022-01-30 21:16:08 +08:00
|
|
|
|
}
|
|
|
|
|
MediaData::AudioFormat(f) => {
|
|
|
|
|
audio_handler.handle_format(f);
|
|
|
|
|
}
|
|
|
|
|
_ => {}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
log::info!("Audio decoder loop exits");
|
|
|
|
|
});
|
|
|
|
|
return (video_sender, audio_sender);
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-12 17:35:25 +08:00
|
|
|
|
// mask = buttons << 3 | type
|
|
|
|
|
// type, 1: down, 2: up, 3: wheel
|
|
|
|
|
// buttons, 1: left, 2: right, 4: middle
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn send_mouse(
|
|
|
|
|
mask: i32,
|
|
|
|
|
x: i32,
|
|
|
|
|
y: i32,
|
|
|
|
|
alt: bool,
|
|
|
|
|
ctrl: bool,
|
|
|
|
|
shift: bool,
|
|
|
|
|
command: bool,
|
|
|
|
|
interface: &impl Interface,
|
|
|
|
|
) {
|
|
|
|
|
let mut msg_out = Message::new();
|
|
|
|
|
let mut mouse_event = MouseEvent {
|
|
|
|
|
mask,
|
|
|
|
|
x,
|
|
|
|
|
y,
|
|
|
|
|
..Default::default()
|
|
|
|
|
};
|
|
|
|
|
if alt {
|
|
|
|
|
mouse_event.modifiers.push(ControlKey::Alt.into());
|
|
|
|
|
}
|
|
|
|
|
if shift {
|
|
|
|
|
mouse_event.modifiers.push(ControlKey::Shift.into());
|
|
|
|
|
}
|
|
|
|
|
if ctrl {
|
|
|
|
|
mouse_event.modifiers.push(ControlKey::Control.into());
|
|
|
|
|
}
|
|
|
|
|
if command {
|
|
|
|
|
mouse_event.modifiers.push(ControlKey::Meta.into());
|
|
|
|
|
}
|
|
|
|
|
msg_out.set_mouse_event(mouse_event);
|
|
|
|
|
interface.send(Data::Message(msg_out));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn activate_os(interface: &impl Interface) {
|
|
|
|
|
send_mouse(0, 0, 0, false, false, false, false, interface);
|
|
|
|
|
std::thread::sleep(Duration::from_millis(50));
|
|
|
|
|
send_mouse(0, 3, 3, false, false, false, false, interface);
|
|
|
|
|
std::thread::sleep(Duration::from_millis(50));
|
|
|
|
|
send_mouse(1 | 1 << 3, 0, 0, false, false, false, false, interface);
|
|
|
|
|
send_mouse(2 | 1 << 3, 0, 0, false, false, false, false, interface);
|
|
|
|
|
/*
|
|
|
|
|
let mut key_event = KeyEvent::new();
|
|
|
|
|
// do not use Esc, which has problem with Linux
|
|
|
|
|
key_event.set_control_key(ControlKey::RightArrow);
|
|
|
|
|
key_event.press = true;
|
|
|
|
|
let mut msg_out = Message::new();
|
|
|
|
|
msg_out.set_key_event(key_event.clone());
|
|
|
|
|
interface.send(Data::Message(msg_out.clone()));
|
|
|
|
|
*/
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn input_os_password(p: String, activate: bool, interface: impl Interface) {
|
|
|
|
|
std::thread::spawn(move || {
|
|
|
|
|
_input_os_password(p, activate, interface);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn _input_os_password(p: String, activate: bool, interface: impl Interface) {
|
|
|
|
|
if activate {
|
|
|
|
|
activate_os(&interface);
|
|
|
|
|
std::thread::sleep(Duration::from_millis(1200));
|
|
|
|
|
}
|
|
|
|
|
let mut key_event = KeyEvent::new();
|
|
|
|
|
key_event.press = true;
|
|
|
|
|
let mut msg_out = Message::new();
|
|
|
|
|
key_event.set_seq(p);
|
|
|
|
|
msg_out.set_key_event(key_event.clone());
|
|
|
|
|
interface.send(Data::Message(msg_out.clone()));
|
|
|
|
|
key_event.set_control_key(ControlKey::Return);
|
|
|
|
|
msg_out.set_key_event(key_event);
|
|
|
|
|
interface.send(Data::Message(msg_out));
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-29 15:59:14 +08:00
|
|
|
|
pub async fn handle_hash(
|
|
|
|
|
lc: Arc<RwLock<LoginConfigHandler>>,
|
|
|
|
|
hash: Hash,
|
|
|
|
|
interface: &impl Interface,
|
|
|
|
|
peer: &mut Stream,
|
|
|
|
|
) {
|
|
|
|
|
let mut password = lc.read().unwrap().password.clone();
|
|
|
|
|
if password.is_empty() {
|
|
|
|
|
password = lc.read().unwrap().config.password.clone();
|
|
|
|
|
}
|
|
|
|
|
if password.is_empty() {
|
|
|
|
|
// login without password, the remote side can click accept
|
|
|
|
|
send_login(lc.clone(), Vec::new(), peer).await;
|
|
|
|
|
interface.msgbox("input-password", "Password Required", "");
|
|
|
|
|
} else {
|
|
|
|
|
let mut hasher = Sha256::new();
|
|
|
|
|
hasher.update(&password);
|
|
|
|
|
hasher.update(&hash.challenge);
|
|
|
|
|
send_login(lc.clone(), hasher.finalize()[..].into(), peer).await;
|
|
|
|
|
}
|
|
|
|
|
lc.write().unwrap().hash = hash;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async fn send_login(lc: Arc<RwLock<LoginConfigHandler>>, password: Vec<u8>, peer: &mut Stream) {
|
|
|
|
|
let msg_out = lc.read().unwrap().create_login_msg(password);
|
|
|
|
|
allow_err!(peer.send(&msg_out).await);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub async fn handle_login_from_ui(
|
|
|
|
|
lc: Arc<RwLock<LoginConfigHandler>>,
|
|
|
|
|
password: String,
|
|
|
|
|
remember: bool,
|
|
|
|
|
peer: &mut Stream,
|
|
|
|
|
) {
|
|
|
|
|
let mut hasher = Sha256::new();
|
|
|
|
|
hasher.update(password);
|
|
|
|
|
hasher.update(&lc.read().unwrap().hash.salt);
|
|
|
|
|
let res = hasher.finalize();
|
|
|
|
|
lc.write().unwrap().remember = remember;
|
|
|
|
|
lc.write().unwrap().password = res[..].into();
|
|
|
|
|
let mut hasher2 = Sha256::new();
|
|
|
|
|
hasher2.update(&res[..]);
|
|
|
|
|
hasher2.update(&lc.read().unwrap().hash.challenge);
|
|
|
|
|
send_login(lc.clone(), hasher2.finalize()[..].into(), peer).await;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[async_trait]
|
|
|
|
|
pub trait Interface: Send + Clone + 'static + Sized {
|
2022-05-12 17:35:25 +08:00
|
|
|
|
fn send(&self, data: Data);
|
2021-03-29 15:59:14 +08:00
|
|
|
|
fn msgbox(&self, msgtype: &str, title: &str, text: &str);
|
|
|
|
|
fn handle_login_error(&mut self, err: &str) -> bool;
|
|
|
|
|
fn handle_peer_info(&mut self, pi: PeerInfo);
|
|
|
|
|
async fn handle_hash(&mut self, hash: Hash, peer: &mut Stream);
|
|
|
|
|
async fn handle_login_from_ui(&mut self, password: String, remember: bool, peer: &mut Stream);
|
|
|
|
|
async fn handle_test_delay(&mut self, t: TestDelay, peer: &mut Stream);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Clone)]
|
|
|
|
|
pub enum Data {
|
|
|
|
|
Close,
|
|
|
|
|
Login((String, bool)),
|
|
|
|
|
Message(Message),
|
2022-05-13 11:23:30 +08:00
|
|
|
|
SendFiles((i32, String, String, i32, bool, bool)),
|
2021-03-29 15:59:14 +08:00
|
|
|
|
RemoveDirAll((i32, String, bool)),
|
|
|
|
|
ConfirmDeleteFiles((i32, i32)),
|
|
|
|
|
SetNoConfirm(i32),
|
|
|
|
|
RemoveDir((i32, String)),
|
|
|
|
|
RemoveFile((i32, String, i32, bool)),
|
|
|
|
|
CreateDir((i32, String, bool)),
|
|
|
|
|
CancelJob(i32),
|
|
|
|
|
RemovePortForward(i32),
|
|
|
|
|
AddPortForward((i32, String, i32)),
|
2022-02-15 15:35:19 +08:00
|
|
|
|
ToggleClipboardFile,
|
2021-03-29 15:59:14 +08:00
|
|
|
|
NewRDP,
|
2022-04-28 17:42:22 +08:00
|
|
|
|
SetConfirmOverrideFile((i32, i32, bool, bool, bool)),
|
2022-05-14 11:58:47 +08:00
|
|
|
|
AddJob((i32, String, String, i32, bool, bool)),
|
|
|
|
|
ResumeJob((i32, bool)),
|
2021-03-29 15:59:14 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Clone)]
|
|
|
|
|
pub enum Key {
|
|
|
|
|
ControlKey(ControlKey),
|
|
|
|
|
Chr(u32),
|
|
|
|
|
_Raw(u32),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
lazy_static::lazy_static! {
|
|
|
|
|
pub static ref KEY_MAP: HashMap<&'static str, Key> =
|
|
|
|
|
[
|
|
|
|
|
("VK_A", Key::Chr('a' as _)),
|
|
|
|
|
("VK_B", Key::Chr('b' as _)),
|
|
|
|
|
("VK_C", Key::Chr('c' as _)),
|
|
|
|
|
("VK_D", Key::Chr('d' as _)),
|
|
|
|
|
("VK_E", Key::Chr('e' as _)),
|
|
|
|
|
("VK_F", Key::Chr('f' as _)),
|
|
|
|
|
("VK_G", Key::Chr('g' as _)),
|
|
|
|
|
("VK_H", Key::Chr('h' as _)),
|
|
|
|
|
("VK_I", Key::Chr('i' as _)),
|
|
|
|
|
("VK_J", Key::Chr('j' as _)),
|
|
|
|
|
("VK_K", Key::Chr('k' as _)),
|
|
|
|
|
("VK_L", Key::Chr('l' as _)),
|
|
|
|
|
("VK_M", Key::Chr('m' as _)),
|
|
|
|
|
("VK_N", Key::Chr('n' as _)),
|
|
|
|
|
("VK_O", Key::Chr('o' as _)),
|
|
|
|
|
("VK_P", Key::Chr('p' as _)),
|
|
|
|
|
("VK_Q", Key::Chr('q' as _)),
|
|
|
|
|
("VK_R", Key::Chr('r' as _)),
|
|
|
|
|
("VK_S", Key::Chr('s' as _)),
|
|
|
|
|
("VK_T", Key::Chr('t' as _)),
|
|
|
|
|
("VK_U", Key::Chr('u' as _)),
|
|
|
|
|
("VK_V", Key::Chr('v' as _)),
|
|
|
|
|
("VK_W", Key::Chr('w' as _)),
|
|
|
|
|
("VK_X", Key::Chr('x' as _)),
|
|
|
|
|
("VK_Y", Key::Chr('y' as _)),
|
|
|
|
|
("VK_Z", Key::Chr('z' as _)),
|
|
|
|
|
("VK_0", Key::Chr('0' as _)),
|
|
|
|
|
("VK_1", Key::Chr('1' as _)),
|
|
|
|
|
("VK_2", Key::Chr('2' as _)),
|
|
|
|
|
("VK_3", Key::Chr('3' as _)),
|
|
|
|
|
("VK_4", Key::Chr('4' as _)),
|
|
|
|
|
("VK_5", Key::Chr('5' as _)),
|
|
|
|
|
("VK_6", Key::Chr('6' as _)),
|
|
|
|
|
("VK_7", Key::Chr('7' as _)),
|
|
|
|
|
("VK_8", Key::Chr('8' as _)),
|
|
|
|
|
("VK_9", Key::Chr('9' as _)),
|
|
|
|
|
("VK_COMMA", Key::Chr(',' as _)),
|
|
|
|
|
("VK_SLASH", Key::Chr('/' as _)),
|
|
|
|
|
("VK_SEMICOLON", Key::Chr(';' as _)),
|
|
|
|
|
("VK_QUOTE", Key::Chr('\'' as _)),
|
|
|
|
|
("VK_LBRACKET", Key::Chr('[' as _)),
|
|
|
|
|
("VK_RBRACKET", Key::Chr(']' as _)),
|
|
|
|
|
("VK_BACKSLASH", Key::Chr('\\' as _)),
|
|
|
|
|
("VK_MINUS", Key::Chr('-' as _)),
|
|
|
|
|
("VK_PLUS", Key::Chr('=' as _)), // it is =, but sciter return VK_PLUS
|
|
|
|
|
("VK_DIVIDE", Key::ControlKey(ControlKey::Divide)), // numpad
|
|
|
|
|
("VK_MULTIPLY", Key::ControlKey(ControlKey::Multiply)), // numpad
|
|
|
|
|
("VK_SUBTRACT", Key::ControlKey(ControlKey::Subtract)), // numpad
|
|
|
|
|
("VK_ADD", Key::ControlKey(ControlKey::Add)), // numpad
|
|
|
|
|
("VK_DECIMAL", Key::ControlKey(ControlKey::Decimal)), // numpad
|
|
|
|
|
("VK_F1", Key::ControlKey(ControlKey::F1)),
|
|
|
|
|
("VK_F2", Key::ControlKey(ControlKey::F2)),
|
|
|
|
|
("VK_F3", Key::ControlKey(ControlKey::F3)),
|
|
|
|
|
("VK_F4", Key::ControlKey(ControlKey::F4)),
|
|
|
|
|
("VK_F5", Key::ControlKey(ControlKey::F5)),
|
|
|
|
|
("VK_F6", Key::ControlKey(ControlKey::F6)),
|
|
|
|
|
("VK_F7", Key::ControlKey(ControlKey::F7)),
|
|
|
|
|
("VK_F8", Key::ControlKey(ControlKey::F8)),
|
|
|
|
|
("VK_F9", Key::ControlKey(ControlKey::F9)),
|
|
|
|
|
("VK_F10", Key::ControlKey(ControlKey::F10)),
|
|
|
|
|
("VK_F11", Key::ControlKey(ControlKey::F11)),
|
|
|
|
|
("VK_F12", Key::ControlKey(ControlKey::F12)),
|
|
|
|
|
("VK_ENTER", Key::ControlKey(ControlKey::Return)),
|
|
|
|
|
("VK_CANCEL", Key::ControlKey(ControlKey::Cancel)),
|
|
|
|
|
("VK_BACK", Key::ControlKey(ControlKey::Backspace)),
|
|
|
|
|
("VK_TAB", Key::ControlKey(ControlKey::Tab)),
|
|
|
|
|
("VK_CLEAR", Key::ControlKey(ControlKey::Clear)),
|
|
|
|
|
("VK_RETURN", Key::ControlKey(ControlKey::Return)),
|
|
|
|
|
("VK_SHIFT", Key::ControlKey(ControlKey::Shift)),
|
|
|
|
|
("VK_CONTROL", Key::ControlKey(ControlKey::Control)),
|
2021-05-26 12:42:21 +08:00
|
|
|
|
("VK_MENU", Key::ControlKey(ControlKey::Alt)),
|
2021-03-29 15:59:14 +08:00
|
|
|
|
("VK_PAUSE", Key::ControlKey(ControlKey::Pause)),
|
|
|
|
|
("VK_CAPITAL", Key::ControlKey(ControlKey::CapsLock)),
|
|
|
|
|
("VK_KANA", Key::ControlKey(ControlKey::Kana)),
|
|
|
|
|
("VK_HANGUL", Key::ControlKey(ControlKey::Hangul)),
|
|
|
|
|
("VK_JUNJA", Key::ControlKey(ControlKey::Junja)),
|
|
|
|
|
("VK_FINAL", Key::ControlKey(ControlKey::Final)),
|
|
|
|
|
("VK_HANJA", Key::ControlKey(ControlKey::Hanja)),
|
|
|
|
|
("VK_KANJI", Key::ControlKey(ControlKey::Kanji)),
|
|
|
|
|
("VK_ESCAPE", Key::ControlKey(ControlKey::Escape)),
|
|
|
|
|
("VK_CONVERT", Key::ControlKey(ControlKey::Convert)),
|
|
|
|
|
("VK_SPACE", Key::ControlKey(ControlKey::Space)),
|
|
|
|
|
("VK_PRIOR", Key::ControlKey(ControlKey::PageUp)),
|
|
|
|
|
("VK_NEXT", Key::ControlKey(ControlKey::PageDown)),
|
|
|
|
|
("VK_END", Key::ControlKey(ControlKey::End)),
|
|
|
|
|
("VK_HOME", Key::ControlKey(ControlKey::Home)),
|
|
|
|
|
("VK_LEFT", Key::ControlKey(ControlKey::LeftArrow)),
|
|
|
|
|
("VK_UP", Key::ControlKey(ControlKey::UpArrow)),
|
|
|
|
|
("VK_RIGHT", Key::ControlKey(ControlKey::RightArrow)),
|
|
|
|
|
("VK_DOWN", Key::ControlKey(ControlKey::DownArrow)),
|
|
|
|
|
("VK_SELECT", Key::ControlKey(ControlKey::Select)),
|
|
|
|
|
("VK_PRINT", Key::ControlKey(ControlKey::Print)),
|
|
|
|
|
("VK_EXECUTE", Key::ControlKey(ControlKey::Execute)),
|
|
|
|
|
("VK_SNAPSHOT", Key::ControlKey(ControlKey::Snapshot)),
|
|
|
|
|
("VK_INSERT", Key::ControlKey(ControlKey::Insert)),
|
|
|
|
|
("VK_DELETE", Key::ControlKey(ControlKey::Delete)),
|
|
|
|
|
("VK_HELP", Key::ControlKey(ControlKey::Help)),
|
|
|
|
|
("VK_SLEEP", Key::ControlKey(ControlKey::Sleep)),
|
|
|
|
|
("VK_SEPARATOR", Key::ControlKey(ControlKey::Separator)),
|
|
|
|
|
("VK_NUMPAD0", Key::ControlKey(ControlKey::Numpad0)),
|
|
|
|
|
("VK_NUMPAD1", Key::ControlKey(ControlKey::Numpad1)),
|
|
|
|
|
("VK_NUMPAD2", Key::ControlKey(ControlKey::Numpad2)),
|
|
|
|
|
("VK_NUMPAD3", Key::ControlKey(ControlKey::Numpad3)),
|
|
|
|
|
("VK_NUMPAD4", Key::ControlKey(ControlKey::Numpad4)),
|
|
|
|
|
("VK_NUMPAD5", Key::ControlKey(ControlKey::Numpad5)),
|
|
|
|
|
("VK_NUMPAD6", Key::ControlKey(ControlKey::Numpad6)),
|
|
|
|
|
("VK_NUMPAD7", Key::ControlKey(ControlKey::Numpad7)),
|
|
|
|
|
("VK_NUMPAD8", Key::ControlKey(ControlKey::Numpad8)),
|
|
|
|
|
("VK_NUMPAD9", Key::ControlKey(ControlKey::Numpad9)),
|
2021-08-10 12:18:10 +08:00
|
|
|
|
("Apps", Key::ControlKey(ControlKey::Apps)),
|
|
|
|
|
("Meta", Key::ControlKey(ControlKey::Meta)),
|
2021-05-26 12:42:21 +08:00
|
|
|
|
("RAlt", Key::ControlKey(ControlKey::RAlt)),
|
|
|
|
|
("RWin", Key::ControlKey(ControlKey::RWin)),
|
|
|
|
|
("RControl", Key::ControlKey(ControlKey::RControl)),
|
|
|
|
|
("RShift", Key::ControlKey(ControlKey::RShift)),
|
2021-03-29 15:59:14 +08:00
|
|
|
|
("CTRL_ALT_DEL", Key::ControlKey(ControlKey::CtrlAltDel)),
|
|
|
|
|
("LOCK_SCREEN", Key::ControlKey(ControlKey::LockScreen)),
|
|
|
|
|
].iter().cloned().collect();
|
|
|
|
|
}
|
2021-08-11 01:28:53 +08:00
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn check_if_retry(msgtype: &str, title: &str, text: &str) -> bool {
|
|
|
|
|
msgtype == "error"
|
|
|
|
|
&& title == "Connection Error"
|
|
|
|
|
&& !text.to_lowercase().contains("offline")
|
|
|
|
|
&& !text.to_lowercase().contains("exist")
|
|
|
|
|
&& !text.to_lowercase().contains("handshake")
|
|
|
|
|
&& !text.to_lowercase().contains("failed")
|
|
|
|
|
&& !text.to_lowercase().contains("resolve")
|
|
|
|
|
&& !text.to_lowercase().contains("mismatch")
|
|
|
|
|
&& !text.to_lowercase().contains("manually")
|
2022-03-26 00:06:06 +08:00
|
|
|
|
&& !text.to_lowercase().contains("not allowed")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
fn get_pk(pk: &[u8]) -> Option<[u8; 32]> {
|
|
|
|
|
if pk.len() == 32 {
|
|
|
|
|
let mut tmp = [0u8; 32];
|
|
|
|
|
tmp[..].copy_from_slice(&pk);
|
|
|
|
|
Some(tmp)
|
|
|
|
|
} else {
|
|
|
|
|
None
|
|
|
|
|
}
|
2021-08-11 01:28:53 +08:00
|
|
|
|
}
|
2022-01-20 12:48:55 +08:00
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
fn get_rs_pk(str_base64: &str) -> Option<sign::PublicKey> {
|
|
|
|
|
if let Ok(pk) = base64::decode(str_base64) {
|
2022-03-26 00:06:06 +08:00
|
|
|
|
get_pk(&pk).map(|x| sign::PublicKey(x))
|
|
|
|
|
} else {
|
|
|
|
|
None
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn decode_id_pk(signed: &[u8], key: &sign::PublicKey) -> ResultType<(String, [u8; 32])> {
|
|
|
|
|
let res = IdPk::parse_from_bytes(
|
|
|
|
|
&sign::verify(signed, key).map_err(|_| anyhow!("Signature mismatch"))?,
|
|
|
|
|
)?;
|
|
|
|
|
if let Some(pk) = get_pk(&res.pk) {
|
|
|
|
|
Ok((res.id, pk))
|
|
|
|
|
} else {
|
|
|
|
|
bail!("Wrong public length");
|
2022-01-20 12:48:55 +08:00
|
|
|
|
}
|
|
|
|
|
}
|