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));
}

 

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