spice-gtk-0.35源代码解析之spicy解析

 

spice-gtk介绍:

spice-gtk是基于红帽的spice远程连接协议的一套客户端核心源码,上层有一套virt-viewer也是客户端源代码,只不过spice-gtk属于底层直接对话协议的项目,而virt-viewer是基于spice-gtk的更加偏向于界面的项目。

spicy:

spicy是基于spice-gtk项目的一个测试可执行文件(virt-viewer的可执行文件remote-viewer是更加前端的连接客户端),此命令可以直接连接远程桌面,首先给一下spicy的使用方法:

spicy -h 192.168.112.32 -p 61000 -w 123

其中ip端口和密码都是服务端创建虚拟机时已经设置好的(在此不说服务端),spicy源代码在spice-gtk/tools/spicy.c下面,我们可以从这里作为头,开始慢慢渗透spice-gtk项目。下面是spicy的主函数入口:

int main(int argc, char *argv[])
{
    GError *error = NULL;
    GOptionContext *context;
    spice_connection *conn;
    gchar *conf_file, *conf;
    char *host = NULL, *port = NULL, *tls_port = NULL, *unix_path = NULL;

    keyfile = g_key_file_new();//keyfile是一个全局变量,我们将配置文件读到keyfile里面,再在程序里面读取保存的配置文件

    int mode = S_IRWXU;
    conf_file = g_build_filename(g_get_user_config_dir(), "spicy", NULL);//g_get_user_config_dir()这个在linux下是/root/.config

    if (g_mkdir_with_parents(conf_file, mode) == -1)
        SPICE_DEBUG("failed to create config directory");
    g_free(conf_file);

    conf_file = g_build_filename(g_get_user_config_dir(), "spicy", "settings", NULL);
    if (!g_key_file_load_from_file(keyfile, conf_file,
                                   G_KEY_FILE_KEEP_COMMENTS|G_KEY_FILE_KEEP_TRANSLATIONS, &error)) {
        SPICE_DEBUG("Couldn't load configuration: %s", error->message);
        g_clear_error(&error);
    }

    /* parse opts */
    gtk_init(&argc, &argv);
#if HAVE_GSTAUDIO || HAVE_GSTVIDEO
    gst_init(&argc, &argv);
#endif
    context = g_option_context_new("- spice client test application");
    g_option_context_set_summary(context, "Gtk+ test client to connect to Spice servers.");
    g_option_context_set_description(context, "Report bugs to " PACKAGE_BUGREPORT ".");
    g_option_context_add_group(context, spice_get_option_group());
    g_option_context_set_main_group(context, spice_cmdline_get_option_group());
    g_option_context_add_main_entries(context, cmd_entries, NULL);
    g_option_context_add_group(context, gtk_get_option_group(TRUE));
#if HAVE_GSTAUDIO || HAVE_GSTVIDEO
    g_option_context_add_group(context, gst_init_get_option_group());
#endif
    if (!g_option_context_parse (context, &argc, &argv, &error)) {
        g_print("option parsing failed: %s\n", error->message);
        exit(1);
    }
    g_option_context_free(context);

    if (version) {
        g_print("spicy " PACKAGE_VERSION "\n");
        exit(0);
    }

    /*从这里开始上面其实都不用看,上面keyfile是读配置文件的能记住上次连接的ip和端口什么的,option_context是spicy的参数列表,执行前命令行敲打spicy --help显示的东西,下面才是真正的开始*/

    mainloop = g_main_loop_new(NULL, false);//mainloop是个全局变量,先创建变量但是先不阻塞直到g_main_loop_run的时候程序阻塞

    conn = connection_new();
    spice_set_session_option(conn->session);
    spice_cmdline_session_setup(conn->session);

    g_object_get(conn->session,
                 "unix-path", &unix_path,
                 "host", &host,
                 "port", &port,
                 "tls-port", &tls_port,
                 NULL);
    /* If user doesn't provide hostname and port, show the dialog window
       instead of connecting to server automatically */
    if ((host == NULL || (port == NULL && tls_port == NULL)) && unix_path == NULL) {
        if (!spicy_connect_dialog(conn->session)) {
            exit(0);
        }
    }
    g_free(host);
    g_free(port);
    g_free(tls_port);
    g_free(unix_path);

    connection_connect(conn);
    if (connections > 0)
        g_main_loop_run(mainloop);//程序阻塞,在connection_destroy函数执行的时候会解开,程序就会往下走
    g_main_loop_unref(mainloop);

    /*写配置文件,从keyfile到conf_file*/
    if ((conf = g_key_file_to_data(keyfile, NULL, &error)) == NULL ||
        !g_file_set_contents(conf_file, conf, -1, &error)) {
        SPICE_DEBUG("Couldn't save configuration: %s", error->message);
        g_error_free(error);
        error = NULL;
    }

    g_free(conf_file);
    g_free(conf);
    g_key_file_free(keyfile);

    g_free(spicy_title);

    setup_terminal(true);
#if HAVE_GSTAUDIO || HAVE_GSTVIDEO
    gst_deinit();
#endif
    return 0;
}

从代码中间开始上面其实都不用看,上面keyfile是读配置文件的能记住上次连接的ip和端口什么的,option_context是spicy的参数列表,执行前命令行敲打spicy --help显示的东西,下面才是真正的开始,代码注释有解释

mainloop = g_main_loop_new(NULL, false); 这里是创建一个循环对象,false表示未开始循环,一旦执行g_main_loop_run(mainloop);,程序就会进入睡眠状态,所有的界面程序都会有这样的操作,主程序睡眠,等待触发的是界面上的信号和相应的方法。

conn = connection_new();//初始化一个连接的对象,里面包括另一个对象session(所有的连接参数都在这个对象里面)
           spice_set_session_option(conn->session);//设置一些session中的额外的参数
           spice_cmdline_session_setup(conn->session);//设置session中的最主要的几个参数ip端口密码等

如果spicy命令行没设置参数,下面代码会去判断session对象中到底有没有没初始化参数,没有的话会调用一个界面,然后卡在那边让你写参数,spicy_connect_dialog实现了一个gtk的界面。

    g_object_get(conn->session,
                 "unix-path", &unix_path,
                 "host", &host,
                 "port", &port,
                 "tls-port", &tls_port,
                 NULL);
    /* If user doesn't provide hostname and port, show the dialog window
       instead of connecting to server automatically */
    if ((host == NULL || (port == NULL && tls_port == NULL)) && unix_path == NULL) {
        if (!spicy_connect_dialog(conn->session)) {
            exit(0);
        }
    }

spicy不加参数调用spicy_connect_dialog,下面是界面。

spice-gtk-0.35源代码解析之spicy解析_第1张图片 spicy_connect_dialog界面

 

        点击connect会以后会设置参数之后spicy_connect_dialog正常返回,一切参数准备就绪以后,执行connection_connect(conn)连接远程桌面。g_main_loop_run(mainloop);主程序处于睡眠状态。

        connection_connect(conn);//连接远程桌面
        if (connections > 0)
                g_main_loop_run(mainloop);
//主函数睡眠,直到调用connection_destroy中的g_main_loop_quit才会往下走
        g_main_loop_unref(mainloop);

这里是spicy的大概的流程,关于connection_connect(conn);以后再分析。

 

你可能感兴趣的:(spice-gtk-0.35源代码解析之spicy解析)