* Copyright (C) 2023 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#![allow(missing_docs)]
use crate::common::base::Base;
use crate::common::hdctransfer::echo_client;
use crate::config::{self, *};
use crate::serializer::native_struct;
use crate::serializer::serialize::Serialization;
use crate::{transfer, utils};
use openssl::base64;
use openssl::rsa::{Padding, Rsa};
use ylong_runtime::sync::RwLock;
use crate::daemon_lib::sys_para::*;
use crate::utils::hdc_log::*;
use std::collections::HashMap;
use std::fs::File;
use std::io::{self, prelude::*, Error, ErrorKind, Write};
use std::path::Path;
use std::process::Command;
use std::string::ToString;
use std::sync::Arc;
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum AuthStatus {
BasC(bool),
Init(String),
Pubk(String, String, String),
Reject(String),
Ok,
Fail,
}
pub enum UserPermit {
Refuse = 0,
AllowOnce = 1,
AllowForever = 2,
}
type AuthStatusMap_ = Arc<RwLock<HashMap<u32, AuthStatus>>>;
pub struct AuthStatusMap {}
impl AuthStatusMap {
fn get_instance() -> AuthStatusMap_ {
static mut AUTH_STATUS_MAP: Option<AuthStatusMap_> = None;
unsafe {
AUTH_STATUS_MAP
.get_or_insert_with(|| Arc::new(RwLock::new(HashMap::new())))
.clone()
}
}
pub async fn get(session_id: u32) -> AuthStatus {
let instance = Self::get_instance();
let map = instance.read().await;
map.get(&session_id)
.unwrap_or(&AuthStatus::BasC(false))
.clone()
}
async fn put(session_id: u32, auth_status: AuthStatus) {
crate::info!(
"update auth status {:?} for session {}",
auth_status,
session_id
);
let instance = Self::get_instance();
let mut map = instance.write().await;
map.insert(session_id, auth_status);
}
pub async fn remove(session_id: u32) {
crate::info!(
"remove auth status for session {}",
session_id
);
let instance = Self::get_instance();
let mut map = instance.write().await;
let _ = map.remove(&session_id);
}
}
pub async fn handshake_init(task_message: TaskMessage) -> io::Result<(u32, TaskMessage)> {
if task_message.command != HdcCommand::KernelHandshake {
return Err(Error::new(ErrorKind::Other, "unknown command flag"));
}
let mut recv = native_struct::SessionHandShake::default();
recv.parse(task_message.payload)?;
crate::info!("recv handshake: {:#?}", recv);
if recv.banner != HANDSHAKE_MESSAGE {
return Err(Error::new(ErrorKind::Other, "Recv server-hello failed"));
}
let session_id = recv.session_id;
let channel_id = task_message.channel_id;
let host_ver = recv.version.as_str();
crate::info!("client version({}) for session:{}", host_ver, session_id);
create_basic_channel(session_id, channel_id, host_ver).await;
if host_ver < AUTH_BASE_VERSDION {
crate::info!(
"client version({}) is too low, return OK for session:{}",
host_ver,
recv.session_id
);
send_reject_message(session_id, channel_id, host_ver).await;
return Ok((
recv.session_id,
make_channel_close_message(channel_id).await,
));
}
if !is_auth_enable() {
crate::info!(
"auth enable is false, return OK for session:{}",
recv.session_id
);
return Ok((
recv.session_id,
make_ok_message(session_id, channel_id).await,
));
}
let buf = generate_token_wait().await;
AuthStatusMap::put(session_id, AuthStatus::Init(buf.clone())).await;
let send = native_struct::SessionHandShake {
banner: HANDSHAKE_MESSAGE.to_string(),
session_id,
connect_key: "".to_string(),
buf,
auth_type: AuthType::Publickey as u8,
version: get_version(),
};
crate::info!("send handshake: {:?}", send);
let message = TaskMessage {
channel_id,
command: HdcCommand::KernelHandshake,
payload: send.serialize(),
};
Ok((session_id, message))
}
async fn make_sign_message(session_id: u32, token: String, channel_id: u32) -> TaskMessage {
let send = native_struct::SessionHandShake {
banner: HANDSHAKE_MESSAGE.to_string(),
session_id,
connect_key: "".to_string(),
buf: token,
auth_type: AuthType::Signature as u8,
version: get_version(),
};
TaskMessage {
channel_id,
command: HdcCommand::KernelHandshake,
payload: send.serialize(),
}
}
async fn make_bypass_message(session_id: u32, channel_id: u32, host_ver: &str) -> TaskMessage {
let mut handshake_msg = "".to_string();
let hostname = get_hostname();
if host_ver < AUTH_BASE_VERSDION {
handshake_msg = hostname;
} else {
handshake_msg = Base::tlv_append(handshake_msg, config::TAG_DEVNAME, hostname.as_str());
if is_auth_enable() {
handshake_msg = Base::tlv_append(handshake_msg, config::TAG_DAEOMN_AUTHSTATUS, DAEOMN_UNAUTHORIZED);
}
}
let send = native_struct::SessionHandShake {
banner: HANDSHAKE_MESSAGE.to_string(),
session_id,
connect_key: "".to_string(),
auth_type: AuthType::OK as u8,
version: get_version(),
buf: handshake_msg,
};
TaskMessage {
channel_id,
command: HdcCommand::KernelHandshake,
payload: send.serialize(),
}
}
async fn create_basic_channel(session_id: u32, channel_id: u32, host_ver: &str) {
if let AuthStatus::BasC(created) = AuthStatusMap::get(session_id).await {
if !created {
transfer::put(
session_id,
make_bypass_message(session_id, channel_id, host_ver).await,
)
.await;
crate::info!(
"create_basic_channel created success for session {}",
session_id
);
AuthStatusMap::put(session_id, AuthStatus::BasC(true)).await;
}
}
crate::info!(
"create_basic_channel already created for session {}",
session_id
);
}
async fn make_emg_message(session_id: u32, channel_id: u32, emgmsg: &str) -> TaskMessage {
let mut handshake_msg = "".to_string();
let hostname = get_hostname();
handshake_msg = Base::tlv_append(handshake_msg, config::TAG_DEVNAME, hostname.as_str());
handshake_msg = Base::tlv_append(handshake_msg, config::TAG_EMGMSG, emgmsg);
handshake_msg = Base::tlv_append(handshake_msg, config::TAG_DAEOMN_AUTHSTATUS, DAEOMN_UNAUTHORIZED);
let send = native_struct::SessionHandShake {
banner: HANDSHAKE_MESSAGE.to_string(),
session_id,
connect_key: "".to_string(),
auth_type: AuthType::OK as u8,
version: get_version(),
buf: handshake_msg,
};
TaskMessage {
channel_id,
command: HdcCommand::KernelHandshake,
payload: send.serialize(),
}
}
async fn make_reject_message(
session_id: u32,
channel_id: u32,
host_ver: &str,
emgmsg: &str,
) -> TaskMessage {
let mut handshake_msg = "".to_string();
let hostname = get_hostname();
if host_ver < AUTH_BASE_VERSDION {
handshake_msg = hostname;
} else {
handshake_msg = Base::tlv_append(handshake_msg, config::TAG_DEVNAME, hostname.as_str());
handshake_msg = Base::tlv_append(handshake_msg, config::TAG_EMGMSG, emgmsg);
}
let send = native_struct::SessionHandShake {
banner: HANDSHAKE_MESSAGE.to_string(),
session_id,
connect_key: "".to_string(),
auth_type: AuthType::OK as u8,
version: get_version(),
buf: handshake_msg,
};
TaskMessage {
channel_id,
command: HdcCommand::KernelHandshake,
payload: send.serialize(),
}
}
async fn send_reject_message(session_id: u32, channel_id: u32, host_ver: &str) {
crate::info!("send_reject_message for session {}", session_id);
let msg = "[E000001]:The sdk hdc.exe version is too low, please upgrade to the latest version.";
echo_client(session_id, channel_id, msg, MessageLevel::Fail).await;
transfer::put(
session_id,
make_reject_message(session_id, channel_id, host_ver, msg).await,
)
.await;
AuthStatusMap::put(session_id, AuthStatus::Reject(msg.to_string())).await;
}
async fn make_ok_message(session_id: u32, channel_id: u32) -> TaskMessage {
crate::info!("make_ok_message for session {}", session_id);
AuthStatusMap::put(session_id, AuthStatus::Ok).await;
let mut succmsg = "".to_string();
let hostname = get_hostname();
succmsg = Base::tlv_append(succmsg, config::TAG_DEVNAME, hostname.as_str());
if succmsg.is_empty() {
crate::error!(
"append {} failed for session {}",
config::TAG_DEVNAME,
session_id
);
}
succmsg = Base::tlv_append(
succmsg,
config::TAG_DAEOMN_AUTHSTATUS,
config::DAEOMN_AUTH_SUCCESS,
);
if succmsg.is_empty() {
crate::error!(
"append {} failed for session {}",
config::TAG_DAEOMN_AUTHSTATUS,
session_id
);
}
succmsg = Base::tlv_append(succmsg, config::TAG_EMGMSG, "");
if succmsg.is_empty() {
crate::error!(
"append {} failed for session {}",
config::TAG_EMGMSG,
session_id
);
}
let send = native_struct::SessionHandShake {
banner: HANDSHAKE_MESSAGE.to_string(),
session_id,
connect_key: "".to_string(),
auth_type: AuthType::OK as u8,
version: get_version(),
buf: succmsg,
};
TaskMessage {
channel_id,
command: HdcCommand::KernelHandshake,
payload: send.serialize(),
}
}
pub async fn get_auth_msg(session_id: u32) -> String {
match AuthStatusMap::get(session_id).await {
AuthStatus::BasC(_) => "Error request.".to_string(),
AuthStatus::Init(_) => "Wait handshake init finish.".to_string(),
AuthStatus::Pubk(_, _, confirm) => {
if confirm.is_empty() {
"Wait handshake public key and signure.".to_string()
} else {
confirm
}
}
AuthStatus::Reject(reject) => reject,
AuthStatus::Ok => "There seems nothing wrong.".to_string(),
AuthStatus::Fail => "Internal error.".to_string(),
}
}
pub async fn make_channel_close_message(channel_id: u32) -> TaskMessage {
crate::debug!("make_channel_close_message: channel {channel_id}");
TaskMessage {
channel_id,
command: HdcCommand::KernelChannelClose,
payload: vec![0],
}
}
pub fn get_host_pubkey_info(buf: &str) -> (String, String) {
if let Some((hostname, pubkey)) = buf.split_once(HDC_HOST_DAEMON_BUF_SEPARATOR) {
(hostname.to_string(), pubkey.to_string())
} else {
("".to_string(), "".to_string())
}
}
pub async fn get_session_id_from_msg(task_message: &TaskMessage) -> io::Result<u32> {
let mut recv = native_struct::SessionHandShake::default();
recv.parse(task_message.payload.clone())?;
Ok(recv.session_id)
}
pub async fn handshake_init_new(session_id: u32, channel_id: u32) -> io::Result<()> {
let buf = generate_token_wait().await;
AuthStatusMap::put(session_id, AuthStatus::Init(buf.clone())).await;
let send = native_struct::SessionHandShake {
banner: HANDSHAKE_MESSAGE.to_string(),
session_id,
connect_key: "".to_string(),
buf,
auth_type: AuthType::Publickey as u8,
version: get_version(),
};
crate::info!("send handshake: {:?}", send);
let message = TaskMessage {
channel_id,
command: HdcCommand::KernelHandshake,
payload: send.serialize(),
};
transfer::put(session_id, message).await;
Ok(())
}
pub async fn handshake_deal_pubkey(
session_id: u32,
channel_id: u32,
token: String,
buf: String,
) -> io::Result<()> {
let (hostname, pubkey) = get_host_pubkey_info(buf.trim());
if pubkey.is_empty() {
crate::error!("get public key from host failed");
handshake_fail(
session_id,
channel_id,
"no public key, you may need update your hdc client".to_string(),
)
.await;
return Ok(());
}
if hostname.is_empty() {
crate::error!("get hostname from host failed");
handshake_fail(
session_id,
channel_id,
"no hostname, you may need update your hdc client".to_string(),
)
.await;
return Ok(());
}
let known_hosts = read_known_hosts_pubkey();
if known_hosts.contains(&pubkey) {
crate::info!("pubkey matches known host({})", hostname);
AuthStatusMap::put(
session_id,
AuthStatus::Pubk(token.clone(), pubkey, "".to_string()),
)
.await;
transfer::put(
session_id,
make_sign_message(session_id, token.clone(), channel_id).await,
)
.await;
return Ok(());
}
let confirmmsg = concat!(
"[E000002]:The device unauthorized.\n",
"This server's public key is not set.\n",
"Please check for a confirmation dialog on your device.\n",
"Otherwise try 'hdc kill' if that seems wrong."
);
AuthStatusMap::put(
session_id,
AuthStatus::Pubk(token.clone(), pubkey.clone(), confirmmsg.to_string()),
)
.await;
utils::spawn(async move {
echo_client(
session_id,
channel_id,
confirmmsg,
MessageLevel::Fail,
)
.await;
transfer::put(
session_id,
make_emg_message(session_id, channel_id, confirmmsg).await,
)
.await;
transfer::put(session_id, make_channel_close_message(channel_id).await).await;
});
match require_user_permittion(&hostname).await {
UserPermit::AllowForever => {
crate::info!("allow forever");
if write_known_hosts_pubkey(&pubkey).is_err() {
handshake_fail(
session_id,
channel_id,
"write public key failed".to_string(),
)
.await;
crate::error!("write public key failed");
return Ok(());
}
AuthStatusMap::put(
session_id,
AuthStatus::Pubk(token.clone(), pubkey, "".to_string()),
)
.await;
transfer::put(
session_id,
make_sign_message(session_id, token.clone(), channel_id).await,
)
.await;
}
UserPermit::AllowOnce => {
crate::info!("allow once");
AuthStatusMap::put(
session_id,
AuthStatus::Pubk(token.clone(), pubkey, "".to_string()),
)
.await;
transfer::put(
session_id,
make_sign_message(session_id, token.clone(), channel_id).await,
)
.await;
}
_ => {
crate::info!("user refuse");
let denymsg = concat!(
"[E000003]:The device unauthorized.\n",
"The user denied the access for the device.\n",
"Please execute 'hdc kill' and redo your command, ",
"then check for a confirmation dialog on your device."
);
AuthStatusMap::put(session_id, AuthStatus::Reject(denymsg.to_string())).await;
echo_client(session_id, channel_id, denymsg, MessageLevel::Fail).await;
transfer::put(
session_id,
make_emg_message(session_id, channel_id, denymsg).await,
)
.await;
transfer::put(session_id, make_channel_close_message(channel_id).await).await;
return Ok(());
}
}
Ok(())
}
pub async fn handshake_deal_signature(
session_id: u32,
channel_id: u32,
token: String,
pubkey: String,
buf: String,
) -> io::Result<()> {
match validate_signature(token, pubkey, buf).await {
Ok(()) => {
crate::info!("user Signature");
transfer::put(session_id, make_ok_message(session_id, channel_id).await).await;
transfer::put(session_id, make_channel_close_message(channel_id).await).await;
Ok(())
}
Err(e) => {
let errlog = e.to_string();
crate::error!("validate signature failed: {}", &errlog);
handshake_fail(session_id, channel_id, errlog).await;
Err(Error::new(ErrorKind::Other, "validate signature failed"))
}
}
}
pub async fn handshake_task(task_message: TaskMessage, session_id: u32) -> io::Result<()> {
if let AuthStatus::Ok = AuthStatusMap::get(session_id).await {
crate::info!("session {} already auth ok", session_id);
return Ok(());
}
let mut recv = native_struct::SessionHandShake::default();
recv.parse(task_message.payload)?;
crate::info!("recv handshake: {:?}", recv);
if recv.banner != HANDSHAKE_MESSAGE {
return Err(Error::new(ErrorKind::Other, "Recv server-hello failed"));
}
let session_id = recv.session_id;
let channel_id = task_message.channel_id;
let host_ver = recv.version.as_str();
crate::info!("client version({}) for session:{}", host_ver, session_id);
if !is_auth_enable() {
crate::info!("auth enable is false, return OK for session:{}", session_id);
transfer::put(session_id, make_ok_message(session_id, channel_id).await).await;
return Ok(());
}
create_basic_channel(session_id, channel_id, host_ver).await;
if host_ver < AUTH_BASE_VERSDION {
crate::info!(
"client version({}) is too low, cannt access for session:{}",
host_ver,
recv.session_id
);
send_reject_message(session_id, channel_id, host_ver).await;
transfer::put(session_id, make_channel_close_message(channel_id).await).await;
return Err(Error::new(ErrorKind::Other, "client version is too low"));
}
match AuthStatusMap::get(session_id).await {
AuthStatus::BasC(created) => {
crate::info!(
"auth status is BasC({}) for session {}",
created,
session_id
);
if !created {
create_basic_channel(session_id, channel_id, host_ver).await;
}
handshake_init_new(session_id, channel_id).await
}
AuthStatus::Init(token) => {
crate::info!("auth status is Init() for session {}", session_id);
if recv.auth_type != AuthType::Publickey as u8 {
return Err(Error::new(
ErrorKind::Other,
"wrong command, need pubkey now",
));
}
handshake_deal_pubkey(session_id, channel_id, token, recv.buf).await
}
AuthStatus::Pubk(token, pubkey, confirm) => {
crate::info!(
"auth status is Pubk({}) for session {}",
confirm,
session_id
);
if recv.auth_type != AuthType::Signature as u8 {
return Err(Error::new(
ErrorKind::Other,
"wrong command, need signature now",
));
}
handshake_deal_signature(session_id, channel_id, token, pubkey, recv.buf).await
}
AuthStatus::Reject(reject) => {
crate::info!(
"auth status is Reject({}) for session {}",
reject,
session_id
);
Ok(())
}
AuthStatus::Ok => {
crate::info!("auth status is Ok() for session {}", session_id);
Ok(())
}
AuthStatus::Fail => {
crate::info!("auth status is Fail() for session {}", session_id);
Ok(())
}
}
}
async fn validate_signature(plain: String, pubkey: String, signature: String) -> io::Result<()> {
let signature_bytes = if let Ok(bytes) = base64::decode_block(&signature) {
bytes
} else {
return Err(Error::new(ErrorKind::Other, "signature decode failed"));
};
let rsa = if let Ok(cipher) = Rsa::public_key_from_pem(pubkey.as_bytes()) {
cipher
} else {
return Err(Error::new(ErrorKind::Other, "pubkey convert failed"));
};
let mut buf = vec![0_u8; config::RSA_BIT_NUM];
let dec_size = rsa
.public_decrypt(&signature_bytes, &mut buf, Padding::PKCS1)
.unwrap_or(0);
if plain.as_bytes() == &buf[..dec_size] {
Ok(())
} else {
Err(Error::new(ErrorKind::Other, "signature not match"))
}
}
pub fn clear_auth_pub_key_file() {
if !is_auth_enable() {
return;
}
let (_, auth_cancel) = get_dev_item("persist.hdc.daemon.auth_cancel", "_");
if auth_cancel.trim().to_lowercase() != "true" {
crate::info!("auth_cancel is {}, no need clear pubkey file", auth_cancel);
return;
}
if !set_dev_item("persist.hdc.daemon.auth_cancel", "false") {
crate::error!("clear param auth_cancel failed.");
}
let file_name = Path::new(config::RSA_PUBKEY_PATH).join(config::RSA_PUBKEY_NAME);
match std::fs::remove_file(&file_name) {
Ok(_) => {
crate::info!("remove pubkey file {:?} success", file_name);
}
Err(err) => {
crate::error!("remove pubkey file {:?} failed: {}", file_name, err);
}
}
}
fn read_known_hosts_pubkey() -> Vec<String> {
let file_name = Path::new(config::RSA_PUBKEY_PATH).join(config::RSA_PUBKEY_NAME);
if let Ok(keys) = std::fs::read_to_string(&file_name) {
let mut key_vec = vec![];
let mut tmp_vec = vec![];
for line in keys.split('\n') {
if line.contains("BEGIN PUBLIC KEY") {
tmp_vec.clear();
}
tmp_vec.push(line);
if line.contains("END PUBLIC KEY") {
key_vec.push(tmp_vec.join("\n"));
}
}
crate::debug!("read {} known hosts from file", key_vec.len());
key_vec
} else {
crate::info!("pubkey file {:?} not exists", file_name);
vec![]
}
}
fn write_known_hosts_pubkey(pubkey: &String) -> io::Result<()> {
let file_name = Path::new(config::RSA_PUBKEY_PATH).join(config::RSA_PUBKEY_NAME);
if !file_name.exists() {
crate::info!("will create pubkeys file at {:?}", file_name);
if let Err(e) = std::fs::create_dir_all(config::RSA_PUBKEY_PATH) {
log::error!("create pubkeys dir: {}", e.to_string());
}
if let Err(e) = std::fs::File::create(&file_name) {
log::error!("create pubkeys file: {}", e.to_string());
}
}
let _ = match std::fs::File::options().append(true).open(file_name) {
Ok(mut f) => writeln!(&mut f, "{}", pubkey),
Err(e) => {
crate::error!("write pubkey err: {}", e.to_string());
return Err(e);
}
};
Ok(())
}
fn show_permit_dialog() -> bool {
let cmd = "/system/bin/hdcd_user_permit";
let result = Command::new(cmd).output();
match result {
Ok(output) => {
let msg = [output.stdout, output.stderr].concat();
let mut str = match String::from_utf8(msg) {
Ok(s) => s,
Err(e) => {
crate::error!("show dialog over, {}.", e.to_string());
return false;
}
};
str = str.replace('\n', " ");
crate::error!("show dialog over, {}.", str);
true
}
Err(e) => {
crate::error!("show dialog failed, {}.", e.to_string());
false
}
}
}
pub fn is_auth_enable() -> bool {
#[cfg(feature = "emulator")]
return false;
let (_, auth_enable) = get_dev_item("const.hdc.secure", "_");
crate::error!("const.hdc.secure is {}.", auth_enable);
if auth_enable.trim().to_lowercase() != "1" {
return false;
}
let (_, auth_bypass) = get_dev_item("persist.hdc.auth_bypass", "_");
crate::error!("persist.hdc.auth_bypass is {}.", auth_bypass);
auth_bypass.trim().to_lowercase() != "1"
}
async fn require_user_permittion(hostname: &str) -> UserPermit {
let default_permit = "auth_result_none";
if !set_dev_item("persist.hdc.daemon.auth_result", default_permit) {
crate::error!("debug auth result failed, so refuse this connect.");
return UserPermit::Refuse;
}
if !set_dev_item("persist.hdc.client.hostname", hostname) {
crate::error!("set param({}) failed.", hostname);
return UserPermit::Refuse;
}
if !show_permit_dialog() {
crate::error!("show dialog failed, so refuse this connect.");
return UserPermit::Refuse;
}
let permit_result = match get_dev_item("persist.hdc.daemon.auth_result", "_") {
(false, _) => {
crate::error!("get_dev_item auth_result failed");
UserPermit::Refuse
}
(true, auth_result) => {
crate::error!("user permit result is:({})", auth_result);
match auth_result.strip_prefix("auth_result:") {
Some(result) => match result.trim() {
"1" => UserPermit::AllowOnce,
"2" => UserPermit::AllowForever,
_ => UserPermit::Refuse,
},
None => {
crate::error!("get_dev_item auth_result failed");
UserPermit::Refuse
}
}
}
};
permit_result
}
async fn handshake_fail(session_id: u32, channel_id: u32, msg: String) {
AuthStatusMap::put(session_id, AuthStatus::Fail).await;
let send = native_struct::SessionHandShake {
banner: HANDSHAKE_MESSAGE.to_string(),
session_id,
auth_type: AuthType::Fail as u8,
buf: msg,
..Default::default()
};
transfer::put(
session_id,
TaskMessage {
channel_id,
command: config::HdcCommand::KernelHandshake,
payload: send.serialize(),
},
)
.await;
}
async fn generate_token() -> io::Result<String> {
let mut random_file = File::open("/dev/random")?;
let mut buffer = [0; HDC_HANDSHAKE_TOKEN_LEN];
random_file.read_exact(&mut buffer)?;
let random_vec: Vec<_> = buffer.iter().map(|h| format!("{:02X}", h)).collect();
let token = random_vec.join("");
Ok(token)
}
async fn generate_token_wait() -> String {
loop {
match generate_token().await {
Ok(token) => {
break token;
}
Err(e) => {
let errlog = e.to_string();
crate::error!("generate token failed: {}", &errlog);
}
}
}
}
fn get_hostname() -> String {
use libc::{c_char, sysconf, _SC_HOST_NAME_MAX};
let maxlen = unsafe { sysconf(_SC_HOST_NAME_MAX) };
let mut out = vec![0; (maxlen as usize) + 1];
let ret = unsafe { libc::gethostname(out.as_mut_ptr() as *mut c_char, out.len()) };
if ret != 0 {
crate::error!("get hostname failed, {}.", std::io::Error::last_os_error());
return "".to_string();
}
let len = out.iter().position(|&c| c == 0).unwrap_or(out.len());
out.resize(len, 0);
let output = String::from_utf8(out)
.unwrap_or("".to_string())
.trim()
.to_string();
crate::info!("get hostname is {}", output);
output
}