一. server端 channel的实现
1、服务端注册Channel。
服务端channel类型
enum {
SPICE_CHANNEL_MAIN = 1,
SPICE_CHANNEL_DISPLAY,
SPICE_CHANNEL_INPUTS,
SPICE_CHANNEL_CURSOR,
SPICE_CHANNEL_PLAYBACK,
SPICE_CHANNEL_RECORD,
SPICE_CHANNEL_TUNNEL,
SPICE_CHANNEL_SMARTCARD,
SPICE_CHANNEL_USBREDIR,
SPICE_CHANNEL_PORT,
SPICE_END_CHANNEL
};
服务端最关键的数据结构为RedsState,又有一个别名叫SpiceServer,Server端会维护一个全局的RedsState变量,用来存储全局数据。该全局数据结构在CoreInterface初始化时由Qemu负责发起创建,并通过VDI接口将此对象传递给libspice。
RedsState中一个数据成员为Channel* channels,Server端通过此变量来维护一个Channel链表,所有Server端支持的Channel都需要通过reds_register_channel注册到此链表。除了InputChannle是在spice_server_init中注册的外(即:在CoreInterface初始化时注册的),其余Channel都是在Qemu进行虚拟设备初始化时,通过调用spice_server_add_interface函数注册VDI时注册的,列举如下:
// spice_server_init
inputs_init 中注册:SPICE_CHANNEL_INPUTS
// spice_server_add_interface(SPICE_INTERFACE_QXL)
red_dispatcher_init 中注册:SPICE_CHANNEL_DISPLAY、SPICE_CHANNEL_CURSOR
// spice_server_add_interface(SPICE_INTERFACE_PLAYBACK)
snd_attach_playback 中注册:SPICE_CHANNEL_PLAYBACK
// spice_server_add_interface(SPICE_INTERFACE_RECORD)
snd_attach_record 中注册:SPICE_CHANNEL_RECORD
// spice_server_add_interface(SPICE_INTERFACE_NET_WIRE)
red_tunnel_attach 中注册:SPICE_CHANNEL_TUNNEL
所谓注册Channel,就是初始化一个Channel对象,然后将其插入到RedsState的channels Ring中供后续的访问处理,具体的channel结构如下:
struct RedChannel {
uint32_t type;
uint32_t id;
uint32_t refs;
RingItem link; // channels link for reds
SpiceCoreInterface *core;
int handle_acks;
// RedChannel will hold only connected channel clients (logic - when pushing pipe item to all channel clients, there
// is no need to go over disconnect clients)
// . While client will hold the channel clients till it is destroyed
// and then it will destroy them as well.
// However RCC still holds a reference to the Channel.
// Maybe replace these logic with ref count?
// TODO: rename to 'connected_clients'?
Ring clients;
uint32_t clients_num;
OutgoingHandlerInterface outgoing_cb;
IncomingHandlerInterface incoming_cb;
ChannelCbs channel_cbs;
ClientCbs client_cbs;
RedChannelCapabilities local_caps;
uint32_t migration_flags;
void *data;
// TODO: when different channel_clients are in different threads from Channel -> need to protect!
pthread_t thread_id;
#ifdef RED_STATISTICS
uint64_t *out_bytes_counter;
#endif
};