spice-gtk之spice-channel数据包的解析

spice-gtk,是红帽的一个远程连接的一个项目,这是一个c语言实现的面相对象的项目,采用的是gobject面相对象的方法,所以读懂spice-gtk的代码首先得了解一下gobject的语法。

spice-channel网络层接收所有服务端的包

spice_channel_init(SpiceChannel *channel)首先初始化初始化的时候将priv结构体中的一些变量初始化,公有变量SpiceChannel结构体,typedef转换的变量,其实是_SpiceChannel, 在spice-types.h中转换,存在于spice-channel.h中。SpiceChannelPrivate类似其实是_SpiceChannelPrivate存在于spice-channel-priv.h中类似于c++中的private变量这边是gobject编程的一种安全机制。

struct _SpiceChannel
{
    GObject parent;
    SpiceChannelPrivate *priv;
    /* Do not add fields to this struct */
};
struct _SpiceChannelPrivate {

    /* swapped on migration */
    SSL_CTX                     *ctx;
    SSL                         *ssl;
    SpiceOpenSSLVerify          *sslverify;
    GSocket                     *sock;
    GSocketConnection           *conn;
    GInputStream                *in;
    GOutputStream               *out;
    。
    。
    。
    下面变量未显示
};

其实spice-channel类初始化的时候还会调用一个spice_channel_class_init(SpiceChannelClass *kclass)

SpiceChannelClass这个类和上面的类似其实是_SpiceChannelClass这是在spice-type.h中转换的

实际上结构体是这样的都是一些函数指针,在class_init中会将这些函数指针真正的指向具体的函数,在spicechannelclass结构体中也会有一个spicechannelclassprivate变量,也是存在于spice-channel-priv.h中如下所示:

struct _SpiceChannelClass
{
    GObjectClass parent_class;
    /*< public >*/
    /* signals, main context */
    void (*channel_event)(SpiceChannel *channel, SpiceChannelEvent event);
    void (*open_fd)(SpiceChannel *channel, int with_tls);
    /*< private >*/
    /* virtual methods, coroutine context */
    void (*handle_msg)(SpiceChannel *channel, SpiceMsgIn *msg);
    void (*channel_up)(SpiceChannel *channel);
    void (*iterate_write)(SpiceChannel *channel);
    void (*iterate_read)(SpiceChannel *channel);
    /*< private >*/
    /* virtual method, any context */
    gpointer deprecated;
    void (*channel_reset)(SpiceChannel *channel, gboolean migrating);
    void (*channel_reset_capabilities)(SpiceChannel *channel);
    /*< private >*/
    /* virtual methods, coroutine context */
    void (*channel_send_migration_handshake)(SpiceChannel *channel);
    SpiceChannelClassPrivate *priv;
    /*
     * If adding fields to this struct, remove corresponding
     * amount of padding to avoid changing overall struct size
     */
    gchar _spice_reserved[SPICE_RESERVED_PADDING - 2 * sizeof(void *)];
};

struct _SpiceChannelClassPrivate
{
    GArray *handlers;
};

    这里面的有一个数组handlers接下来我们分析这个handlers的作用:

    首先分析一下客户端接收包的时候数据包走的流程,刚开始接收是在spice_channel_iterate_read这个函数中有一个调用很重要:

spice_channel_recv_msg(channel, (handler_msg_in)SPICE_CHANNEL_GET_CLASS(channel)->handle_msg, NULL);

第二个参数其实传递的是spicechannelclass中的一个函数指针,而这个函数指针很明确在class_init中指向的函数就是spice_chanel_handle_msg,因此我们要分析这个函数:

static void spice_channel_handle_msg(SpiceChannel *channel, SpiceMsgIn *msg)
{
    SpiceChannelClass *klass = SPICE_CHANNEL_GET_CLASS(channel);
    int type = spice_msg_in_type(msg);
    spice_msg_handler handler; //这边只是一个函数指针,具体的指向哪里还不知道
    g_return_if_fail(type < klass->priv->handlers->len);
    if (type > SPICE_MSG_BASE_LAST && channel->priv->disable_channel_msg)
        return;

    /*这个函数的第一个参数其实就是上面大黑字定义的一个garray,g_array_index函数的作用就是在这个数组中寻找到匹配这个type的函数,这样上面的函数指针就有明确指向的定义了*/
    handler = g_array_index(klass->priv->handlers, spice_msg_handler, type);//通过channel-display最底下的channel_set_handlers函数中去匹配
    g_return_if_fail(handler != NULL);
    handler(channel, msg);//这个handle其实已经是channel-display中的处理视频包的相关函数了
}

g_array_index会去查找garray这个包type和处理函数的对应表,而这个表存在每个模块的最后,因为包有视频的包,音频的包,鼠标操作的包键盘操作的包各种各样,这边给出一个视频包处理的文件,channel-display.c  处理网络层收到的包中关于视频的包,匹配表如下所示:

//本函数存在channel-display.c最后
static void channel_set_handlers(SpiceChannelClass *klass)
{
    static const spice_msg_handler handlers[] = {
        [ SPICE_MSG_DISPLAY_MODE ]               = display_handle_mode,
        [ SPICE_MSG_DISPLAY_MARK ]               = display_handle_mark,
        [ SPICE_MSG_DISPLAY_RESET ]              = display_handle_reset,
        [ SPICE_MSG_DISPLAY_COPY_BITS ]          = display_handle_copy_bits,
        [ SPICE_MSG_DISPLAY_INVAL_LIST ]         = display_handle_inv_list,
        [ SPICE_MSG_DISPLAY_INVAL_ALL_PIXMAPS ]  = display_handle_inv_pixmap_all,
        [ SPICE_MSG_DISPLAY_INVAL_PALETTE ]      = display_handle_inv_palette,
        [ SPICE_MSG_DISPLAY_INVAL_ALL_PALETTES ] = display_handle_inv_palette_all,

        [ SPICE_MSG_DISPLAY_STREAM_CREATE ]      = display_handle_stream_create,
        [ SPICE_MSG_DISPLAY_STREAM_DATA ]        = display_handle_stream_data,
        [ SPICE_MSG_DISPLAY_STREAM_CLIP ]        = display_handle_stream_clip,
        [ SPICE_MSG_DISPLAY_STREAM_DESTROY ]     = display_handle_stream_destroy,
        [ SPICE_MSG_DISPLAY_STREAM_DESTROY_ALL ] = display_handle_stream_destroy_all,
        [ SPICE_MSG_DISPLAY_STREAM_DATA_SIZED ]  = display_handle_stream_data,
        [ SPICE_MSG_DISPLAY_STREAM_ACTIVATE_REPORT ] = display_handle_stream_activate_report,

        [ SPICE_MSG_DISPLAY_DRAW_FILL ]          = display_handle_draw_fill,
        [ SPICE_MSG_DISPLAY_DRAW_OPAQUE ]        = display_handle_draw_opaque,
        [ SPICE_MSG_DISPLAY_DRAW_COPY ]          = display_handle_draw_copy,
        [ SPICE_MSG_DISPLAY_DRAW_BLEND ]         = display_handle_draw_blend,
        [ SPICE_MSG_DISPLAY_DRAW_BLACKNESS ]     = display_handle_draw_blackness,
        [ SPICE_MSG_DISPLAY_DRAW_WHITENESS ]     = display_handle_draw_whiteness,
        [ SPICE_MSG_DISPLAY_DRAW_INVERS ]        = display_handle_draw_invers,
        [ SPICE_MSG_DISPLAY_DRAW_ROP3 ]          = display_handle_draw_rop3,
        [ SPICE_MSG_DISPLAY_DRAW_STROKE ]        = display_handle_draw_stroke,
        [ SPICE_MSG_DISPLAY_DRAW_TEXT ]          = display_handle_draw_text,
        [ SPICE_MSG_DISPLAY_DRAW_TRANSPARENT ]   = display_handle_draw_transparent,
        [ SPICE_MSG_DISPLAY_DRAW_ALPHA_BLEND ]   = display_handle_draw_alpha_blend,
        [ SPICE_MSG_DISPLAY_DRAW_COMPOSITE ]     = display_handle_draw_composite,
        [ SPICE_MSG_DISPLAY_SURFACE_CREATE ]     = display_handle_surface_create,
        [ SPICE_MSG_DISPLAY_SURFACE_DESTROY ]    = display_handle_surface_destroy,
        [ SPICE_MSG_DISPLAY_MONITORS_CONFIG ]    = display_handle_monitors_config,
#ifdef G_OS_UNIX
        [ SPICE_MSG_DISPLAY_GL_SCANOUT_UNIX ]    = display_handle_gl_scanout_unix,
#endif
        [ SPICE_MSG_DISPLAY_GL_DRAW ]            = display_handle_gl_draw,
    };
    spice_channel_set_handlers(klass, handlers, G_N_ELEMENTS(handlers));
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章