1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/openeuler-stratovirt

Присоединиться к Gitlife
Откройте для себя и примите участие в публичных проектах с открытым исходным кодом с участием более 10 миллионов разработчиков. Приватные репозитории также полностью бесплатны :)
Присоединиться бесплатно
В этом репозитории не указан файл с открытой лицензией (LICENSE). При использовании обратитесь к конкретному описанию проекта и его зависимостям в коде.
Клонировать/Скачать
server.rs 14 КБ
Копировать Редактировать Исходные данные Просмотреть построчно История
yexiao Отправлено 3 лет назад c51ae5b
// Copyright (c) 2022 Huawei Technologies Co.,Ltd. All rights r&eserved.
//
// StratoVirt is licensed under Mulan PSL v2.
// You can use this software according to the terms and conditions of the Mulan
// PSL v2.
// You may obtain a copy of Mulan PSL v2 at:
// http://license.coscl.org.cn/MulanPSL2
// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY
// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
// See the Mulan PSL v2 for more details.
use super::errors::Result;
use machine_manager::{
config::{ObjConfig, VncConfig},
event_loop::EventLoop,
};
use std::{
cmp,
collections::HashMap,
net::{Shutdown, TcpListener},
os::unix::prelude::{AsRawFd, RawFd},
ptr,
sync::{Arc, Mutex},
};
use util::{
bitmap::Bitmap,
loop_context::{read_fd, EventNotifier, EventNotifierHelper, NotifierOperation},
pixman::{
pixman_format_bpp, pixman_format_code_t, pixman_image_composite, pixman_image_create_bits,
pixman_image_t, pixman_op_t,
},
};
use vmm_sys_util::epoll::EventSet;
use crate::{
bytes_per_pixel, data::keycode::KEYSYM2KEYCODE, get_image_data, get_image_format,
get_image_height, get_image_stride, get_image_width, round_up_div, unref_pixman_image,
update_client_surface, AuthState, DisplayMouse, SubAuthState, VncClient, DIRTY_PIXELS_NUM,
MAX_WINDOW_HEIGHT, MAX_WINDOW_WIDTH, REFRESH_EVT, VNC_BITMAP_WIDTH, VNC_SERVERS,
};
/// Info of image.
/// stride is not always equal to stride because of memory alignment.
pub struct ImageInfo {
/// The start pointer to image.
data: *mut u8,
/// The memory size of each line for image.
stride: i32,
/// The memory size of each line to store pixel for image
length: i32,
/// Middle pointer.
ptr: *mut u8,
}
impl Default for ImageInfo {
fn default() -> Self {
ImageInfo {
data: ptr::null_mut(),
stride: 0,
length: 0,
ptr: ptr::null_mut(),
}
}
}
impl ImageInfo {
fn new(image: *mut pixman_image_t) -> Self {
let bpp = pixman_format_bpp(get_image_format(image) as u32);
let length = get_image_width(image) * round_up_div(bpp as u64, 8) as i32;
ImageInfo {
data: get_image_data(image) as *mut u8,
stride: get_image_stride(image),
length,
ptr: ptr::null_mut(),
}
}
}
/// VncServer
pub struct VncServer {
/// Tcp connection listened by server.
listener: Arc<Mutex<TcpListener>>,
/// Clients connected to vnc.
pub clients: HashMap<String, Arc<Mutex<VncClient>>>,
/// Auth type.
pub auth: AuthState,
/// Subauth type.
pub subauth: SubAuthState,
/// Mapping ASCII to keycode.
pub keysym2keycode: HashMap<u16, u16>,
/// Image refresh to VncClient.
pub server_image: *mut pixman_image_t,
/// Image from gpu.
pub guest_image: *mut pixman_image_t,
/// Identify the image update area for guest image.
pub guest_dirtymap: Bitmap<u64>,
/// Image format of pixman.
pub guest_format: pixman_format_code_t,
/// Cursor property.
pub cursor: Option<DisplayMouse>,
/// Identify the area need update for cursor.
pub mask: Option<Vec<u8>>,
/// Connection limit.
conn_limits: usize,
/// Width of current image.
pub true_width: i32,
}
unsafe impl Send for VncServer {}
impl VncServer {
/// Create a new VncServer.
pub fn new(listener: Arc<Mutex<TcpListener>>, guest_image: *mut pixman_image_t) -> Self {
VncServer {
listener,
clients: HashMap::new(),
auth: AuthState::No,
subauth: SubAuthState::VncAuthVencryptPlain,
keysym2keycode: HashMap::new(),
server_image: ptr::null_mut(),
guest_image,
guest_dirtymap: Bitmap::<u64>::new(
MAX_WINDOW_HEIGHT as usize
* round_up_div(
(MAX_WINDOW_WIDTH / DIRTY_PIXELS_NUM) as u64,
u64::BITS as u64,
) as usize,
),
guest_format: pixman_format_code_t::PIXMAN_x8r8g8b8,
cursor: None,
mask: None,
conn_limits: 1,
true_width: 0,
}
}
/// make configuration for VncServer
///
/// # Arguments
///
/// * `vnc_cfg` - configure of vnc.
/// * `object` - configure of sasl and tls.
pub fn make_config(
&mut self,
_vnc_cfg: &VncConfig,
_object: &HashMap<String, ObjConfig>,
) -> Result<()> {
// tls configuration
// Mapping ASCII to keycode.
for &(k, v) in KEYSYM2KEYCODE.iter() {
self.keysym2keycode.insert(k, v);
}
Ok(())
}
/// Set diry for client
///
/// # Arguments
///
/// * `x` `y`- coordinates of dirty area.
fn set_dirty_for_clients(&mut self, x: usize, y: usize) {
for client in self.clients.values_mut() {
client
.lock()
.unwrap()
.dirty_bitmap
.set(x + y * VNC_BITMAP_WIDTH as usize)
.unwrap();
}
}
/// Transfer dirty data to buff in one line
///
/// # Arguments
///
/// * `s_info` - source image.
/// * `g_info` - dest image.
fn get_one_line_buf(
&self,
s_info: &mut ImageInfo,
g_info: &mut ImageInfo,
) -> *mut pixman_image_t {
let mut line_buf = ptr::null_mut();
if self.guest_format != pixman_format_code_t::PIXMAN_x8r8g8b8 {
line_buf = unsafe {
pixman_image_create_bits(
pixman_format_code_t::PIXMAN_x8r8g8b8,
get_image_width(self.server_image),
1,
ptr::null_mut(),
0,
)
};
g_info.stride = s_info.stride;
g_info.length = g_info.stride;
}
line_buf
}
/// Get min width.
fn get_min_width(&self) -> i32 {
cmp::min(
get_image_width(self.server_image),
get_image_width(self.guest_image),
)
}
/// Get min height.
fn get_min_height(&self) -> i32 {
cmp::min(
get_image_height(self.server_image),
get_image_height(self.guest_image),
)
}
/// Update each line
///
/// # Arguments
///
/// * `x` `y` - start coordinate in image to refresh
/// * `s_info` - source image.
/// * `g_info` - dest image.
fn update_one_line(
&mut self,
mut x: usize,
y: usize,
s_info: &mut ImageInfo,
g_info: &mut ImageInfo,
cmp_bytes: usize,
) -> i32 {
let mut count = 0;
let width = self.get_min_width();
let line_bytes = cmp::min(s_info.stride, g_info.length);
while x < round_up_div(width as u64, DIRTY_PIXELS_NUM as u64) as usize {
if !self
.guest_dirtymap
.contain(x + y * VNC_BITMAP_WIDTH as usize)
.unwrap()
{
x += 1;
g_info.ptr = (g_info.ptr as usize + cmp_bytes) as *mut u8;
s_info.ptr = (s_info.ptr as usize + cmp_bytes) as *mut u8;
continue;
}
self.guest_dirtymap
.clear(x + y * VNC_BITMAP_WIDTH as usize)
.unwrap();
let mut _cmp_bytes = cmp_bytes;
if (x + 1) * cmp_bytes > line_bytes as usize {
_cmp_bytes = line_bytes as usize - x * cmp_bytes;
}
unsafe {
if libc::memcmp(
s_info.ptr as *mut libc::c_void,
g_info.ptr as *mut libc::c_void,
_cmp_bytes,
) == 0
{
x += 1;
g_info.ptr = (g_info.ptr as usize + cmp_bytes) as *mut u8;
s_info.ptr = (s_info.ptr as usize + cmp_bytes) as *mut u8;
continue;
}
ptr::copy(g_info.ptr, s_info.ptr, _cmp_bytes);
};
self.set_dirty_for_clients(x, y);
count += 1;
x += 1;
g_info.ptr = (g_info.ptr as usize + cmp_bytes) as *mut u8;
s_info.ptr = (s_info.ptr as usize + cmp_bytes) as *mut u8;
}
count
}
/// Flush dirty data from guest_image to server_image.
/// Return the number of dirty area.
pub fn update_server_image(&mut self) -> i32 {
let mut dirty_num = 0;
let height = self.get_min_height();
let g_bpl = self.guest_dirtymap.vol() / MAX_WINDOW_HEIGHT as usize;
let mut offset = self.guest_dirtymap.find_next_bit(0).unwrap();
if offset >= (height as usize) * g_bpl {
return dirty_num;
}
let mut s_info = ImageInfo::new(self.server_image);
let mut g_info = ImageInfo::new(self.guest_image);
let cmp_bytes = cmp::min(
DIRTY_PIXELS_NUM as usize * bytes_per_pixel(),
s_info.stride as usize,
);
let line_buf = self.get_one_line_buf(&mut s_info, &mut g_info);
loop {
let mut y = offset / g_bpl;
let x = offset % g_bpl;
s_info.ptr =
(s_info.data as usize + y * s_info.stride as usize + x * cmp_bytes) as *mut u8;
if self.guest_format != pixman_format_code_t::PIXMAN_x8r8g8b8 {
unsafe {
pixman_image_composite(
pixman_op_t::PIXMAN_OP_SRC,
self.guest_image,
ptr::null_mut(),
line_buf,
0,
y as i16,
0,
0,
0,
0,
self.get_min_width() as u16,
1,
);
};
g_info.ptr = get_image_data(line_buf) as *mut u8;
} else {
g_info.ptr = (g_info.data as usize + y * g_info.stride as usize) as *mut u8;
}
g_info.ptr = (g_info.ptr as usize + x * cmp_bytes) as *mut u8;
dirty_num += self.update_one_line(x, y, &mut s_info, &mut g_info, cmp_bytes);
y += 1;
offset = self.guest_dirtymap.find_next_bit(y * g_bpl).unwrap();
if offset >= (height as usize) * g_bpl {
break;
}
unref_pixman_image(line_buf);
}
dirty_num
}
/// Listen to the port and accpet client's connection.
pub fn handle_connection(&mut self) -> Result<()> {
match self.listener.lock().unwrap().accept() {
Ok((stream, addr)) => {
if self.clients.len() >= self.conn_limits {
stream.shutdown(Shutdown::Both).unwrap();
return Ok(());
}
info!("new client: {:?}", addr);
stream
.set_nonblocking(true)
.expect("set nonblocking failed");
let server = VNC_SERVERS.lock().unwrap()[0].clone();
let mut client = VncClient::new(
stream,
addr.to_string(),
self.auth,
self.subauth,
server,
self.server_image,
);
client.write_msg("RFB 003.008\n".to_string().as_bytes());
info!("{:?}", client.stream);
let tmp_client = Arc::new(Mutex::new(client));
self.clients.insert(addr.to_string(), tmp_client.clone());
EventLoop::update_event(EventNotifierHelper::internal_notifiers(tmp_client), None)?;
}
Err(e) => {
info!("Connect failed: {:?}", e);
}
}
update_client_surface(self);
Ok(())
}
}
/// Internal_notifiers for VncServer.
impl EventNotifierHelper for VncServer {
fn internal_notifiers(server_handler: Arc<Mutex<Self>>) -> Vec<EventNotifier> {
let server = server_handler.clone();
let handler: Box<dyn Fn(EventSet, RawFd) -> Option<Vec<EventNotifier>>> =
Box::new(move |event, fd: RawFd| {
read_fd(fd);
if event & EventSet::HANG_UP == EventSet::HANG_UP {
info!("Client Closed");
} else if event == EventSet::IN {
let mut locked_handler = server.lock().unwrap();
if let Err(e) = locked_handler.handle_connection() {
error!("Failed to handle vnc client connection, error is {}", e);
}
drop(locked_handler);
}
None as Option<Vec<EventNotifier>>
});
let mut notifiers = vec![
(EventNotifier::new(
NotifierOperation::AddShared,
server_handler
.lock()
.unwrap()
.listener
.lock()
.unwrap()
.as_raw_fd(),
None,
EventSet::IN | EventSet::HANG_UP,
vec![Arc::new(Mutex::new(handler))],
)),
];
let handler: Box<dyn Fn(EventSet, RawFd) -> Option<Vec<EventNotifier>>> =
Box::new(move |_event, fd: RawFd| {
read_fd(fd);
vnc_refresh();
None as Option<Vec<EventNotifier>>
});
notifiers.push(EventNotifier::new(
NotifierOperation::AddShared,
REFRESH_EVT.lock().unwrap().as_raw_fd(),
None,
EventSet::IN,
vec![Arc::new(Mutex::new(handler))],
));
notifiers
}
}
/// Refresh server_image to guest_image.
fn vnc_refresh() {
if VNC_SERVERS.lock().unwrap().is_empty() {
return;
}
let server = VNC_SERVERS.lock().unwrap()[0].clone();
if server.lock().unwrap().clients.is_empty() {
return;
}
let dirty_num = server.lock().unwrap().update_server_image();
let mut _rects: i32 = 0;
for client in server.lock().unwrap().clients.values_mut() {
_rects += client.lock().unwrap().get_rects(dirty_num);
}
}

Комментарий ( 0 )

Вы можете оставить комментарий после Вход в систему

1
https://gitlife.ru/oschina-mirror/openeuler-stratovirt.git
git@gitlife.ru:oschina-mirror/openeuler-stratovirt.git
oschina-mirror
openeuler-stratovirt
openeuler-stratovirt
v2.2.0-rc4