diff options
author | Leandro A. F. Pereira <leandro@hardinfo.org> | 2009-04-25 14:45:00 -0300 |
---|---|---|
committer | Leandro A. F. Pereira <leandro@hardinfo.org> | 2009-04-25 14:45:00 -0300 |
commit | 77baf70fba7d7fbdd10d677a3a0357c7337d8b12 (patch) | |
tree | a0a2a1d4f365ba65d89a72fab7d91a29a599cee9 | |
parent | 77d3c49309059979067f37e62a44936e00594aa7 (diff) |
Add XML-RPC server (prototype); early work on the "Open Connection" dialog
-rw-r--r-- | hardinfo2/Makefile.in | 2 | ||||
-rw-r--r-- | hardinfo2/hardinfo.c | 6 | ||||
-rw-r--r-- | hardinfo2/hardinfo.h | 1 | ||||
-rw-r--r-- | hardinfo2/pixmaps/home.png | bin | 0 -> 920 bytes | |||
-rw-r--r-- | hardinfo2/pixmaps/server-large.png | bin | 0 -> 1525 bytes | |||
-rw-r--r-- | hardinfo2/pixmaps/server.png | bin | 0 -> 878 bytes | |||
-rw-r--r-- | hardinfo2/remote.c | 83 | ||||
-rw-r--r-- | hardinfo2/socket.c | 1 | ||||
-rw-r--r-- | hardinfo2/util.c | 8 | ||||
-rw-r--r-- | hardinfo2/xmlrpc-server.c | 143 | ||||
-rw-r--r-- | hardinfo2/xmlrpc-server.h | 7 |
11 files changed, 228 insertions, 23 deletions
diff --git a/hardinfo2/Makefile.in b/hardinfo2/Makefile.in index 98379ec5..3cf83329 100644 --- a/hardinfo2/Makefile.in +++ b/hardinfo2/Makefile.in @@ -8,7 +8,7 @@ CCSLOW = gcc -O0 -g OBJECTS = hardinfo.o shell.o util.o iconcache.o loadgraph.o \ menu.o stock.o callbacks.o expr.o report.o binreloc.o \ - vendor.o socket.o syncmanager.o remote.o + vendor.o socket.o syncmanager.o remote.o xmlrpc-server.o BENCHMARK_OBJECTS = fbench.o sha1.o blowfish.o md5.o nqueens.o fftbench.o MODULES = computer.so devices.so benchmark.so network.so diff --git a/hardinfo2/hardinfo.c b/hardinfo2/hardinfo.c index 3f638a87..d8eb40a1 100644 --- a/hardinfo2/hardinfo.c +++ b/hardinfo2/hardinfo.c @@ -24,6 +24,7 @@ #include <iconcache.h> #include <stock.h> #include <vendor.h> +#include <xmlrpc-server.h> #include <binreloc.h> @@ -114,7 +115,10 @@ int main(int argc, char **argv) /* initialize vendor database */ vendor_init(); - if (params.run_benchmark) { + if (params.run_xmlrpc_server) { + xmlrpc_server_init(); + xmlrpc_server_start(); + } else if (params.run_benchmark) { gchar *result; result = module_call_method_param("benchmark::runBenchmark", params.run_benchmark); diff --git a/hardinfo2/hardinfo.h b/hardinfo2/hardinfo.h index 2fe955fe..030cc46a 100644 --- a/hardinfo2/hardinfo.h +++ b/hardinfo2/hardinfo.h @@ -33,6 +33,7 @@ struct _ProgramParameters { gboolean gui_running; gboolean list_modules; gboolean autoload_deps; + gboolean run_xmlrpc_server; gint report_format; diff --git a/hardinfo2/pixmaps/home.png b/hardinfo2/pixmaps/home.png Binary files differnew file mode 100644 index 00000000..9d62109a --- /dev/null +++ b/hardinfo2/pixmaps/home.png diff --git a/hardinfo2/pixmaps/server-large.png b/hardinfo2/pixmaps/server-large.png Binary files differnew file mode 100644 index 00000000..6ada9d08 --- /dev/null +++ b/hardinfo2/pixmaps/server-large.png diff --git a/hardinfo2/pixmaps/server.png b/hardinfo2/pixmaps/server.png Binary files differnew file mode 100644 index 00000000..a0d7118d --- /dev/null +++ b/hardinfo2/pixmaps/server.png diff --git a/hardinfo2/remote.c b/hardinfo2/remote.c index a8cda9b6..ae144b5d 100644 --- a/hardinfo2/remote.c +++ b/hardinfo2/remote.c @@ -33,7 +33,7 @@ * - IP range scan * - mDNS * - Allow the user to add/remove/edit a machine - * - Use ~/.ssh/hosts as a starting point? + * - Use ~/.ssh/known_hosts as a starting point? * - Different icons for different machines? * - Make sure SSH can do port forwarding * - Make sure the remote host has HardInfo installed, with the correct @@ -56,7 +56,7 @@ * - Use libsoup XML-RPC support to implement the remote mode * - Introduce a flag on the modules, stating their ability to be used locally/remotely * (Benchmarks can't be used remotely; Displays won't work remotely [unless we use - X forwarding, but that'll be local X11 info anyway]). + * X forwarding, but that'll be local X11 info anyway]). */ typedef struct _RemoteDialog RemoteDialog; @@ -67,31 +67,73 @@ struct _RemoteDialog { static RemoteDialog *remote_dialog_new(GtkWidget *parent); +static void remote_connect(RemoteDialog *rd) +{ + +} + void remote_dialog_show(GtkWidget *parent) { gboolean success; RemoteDialog *rd = remote_dialog_new(parent); if (gtk_dialog_run(GTK_DIALOG(rd->dialog)) == GTK_RESPONSE_ACCEPT) { - shell_status_update("Generating remote..."); gtk_widget_hide(rd->dialog); shell_view_set_enabled(FALSE); shell_status_set_enabled(TRUE); - -// success = remote_generate(rd); - + + remote_connect(rd); shell_status_set_enabled(FALSE); - - if (success) - shell_status_update("Remote saved."); - else - shell_status_update("Error while creating the remote."); } gtk_widget_destroy(rd->dialog); g_free(rd); } +static void populate_store(GtkListStore * store) +{ + GKeyFile *remote; + GtkTreeIter iter; + gchar *path; + + gtk_list_store_clear(store); + + gtk_list_store_append(store, &iter); + gtk_list_store_set(store, &iter, + 0, icon_cache_get_pixbuf("home.png"), + 1, g_strdup("Local Computer"), + 2, GINT_TO_POINTER(-1), + -1); + + remote = g_key_file_new(); + path = g_build_filename(g_get_home_dir(), ".hardinfo", "remote.conf", NULL); + if (g_key_file_load_from_file(remote, path, 0, NULL)) { + gint no_hosts, i; + + no_hosts = g_key_file_get_integer(remote, "$Global$", "no_hosts", NULL); + for (i = 0; i < no_hosts; i++) { + gchar *hostname; + gchar *hostgroup; + + hostgroup = g_strdup_printf("Host%d", i); + + hostname = g_key_file_get_string(remote, hostgroup, "name", NULL); + + gtk_list_store_append(store, &iter); + gtk_list_store_set(store, &iter, + 0, icon_cache_get_pixbuf("server.png"), + 1, hostname, + 2, GINT_TO_POINTER(i), + -1); + + g_free(hostgroup); + } + } + + g_free(path); + g_key_file_free(remote); +} + static RemoteDialog *remote_dialog_new(GtkWidget *parent) { RemoteDialog *rd; @@ -110,6 +152,8 @@ static RemoteDialog *remote_dialog_new(GtkWidget *parent) GtkTreeViewColumn *column; GtkCellRenderer *cr_text, *cr_pbuf, *cr_toggle; + GtkListStore *store; + GtkTreeModel *model; rd = g_new0(RemoteDialog, 1); @@ -137,9 +181,8 @@ static RemoteDialog *remote_dialog_new(GtkWidget *parent) gtk_label_set_use_markup(GTK_LABEL(label), TRUE); gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); - gtk_box_pack_start(GTK_BOX(hbox), - icon_cache_get_image("network.png"), + icon_cache_get_image("server-large.png"), FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, TRUE, 0); gtk_widget_show_all(hbox); @@ -159,7 +202,10 @@ static RemoteDialog *remote_dialog_new(GtkWidget *parent) gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW (scrolledwindow2), GTK_SHADOW_IN); - treeview2 = gtk_tree_view_new(); + store = gtk_list_store_new(3, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_INT); + model = GTK_TREE_MODEL(store); + + treeview2 = gtk_tree_view_new_with_model(model); gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview2), FALSE); gtk_widget_show(treeview2); gtk_container_add(GTK_CONTAINER(scrolledwindow2), treeview2); @@ -167,13 +213,6 @@ static RemoteDialog *remote_dialog_new(GtkWidget *parent) column = gtk_tree_view_column_new(); gtk_tree_view_append_column(GTK_TREE_VIEW(treeview2), column); - cr_toggle = gtk_cell_renderer_toggle_new(); - gtk_tree_view_column_pack_start(column, cr_toggle, FALSE); -// g_signal_connect(cr_toggle, "toggled", -// G_CALLBACK(remote_dialog_sel_toggle), rd); - gtk_tree_view_column_add_attribute(column, cr_toggle, "active", - TREE_COL_SEL); - cr_pbuf = gtk_cell_renderer_pixbuf_new(); gtk_tree_view_column_pack_start(column, cr_pbuf, FALSE); gtk_tree_view_column_add_attribute(column, cr_pbuf, "pixbuf", @@ -184,6 +223,8 @@ static RemoteDialog *remote_dialog_new(GtkWidget *parent) gtk_tree_view_column_add_attribute(column, cr_text, "markup", TREE_COL_NAME); + populate_store(store); + vbuttonbox3 = gtk_vbutton_box_new(); gtk_widget_show(vbuttonbox3); gtk_box_pack_start(GTK_BOX(hbox), vbuttonbox3, FALSE, TRUE, 0); diff --git a/hardinfo2/socket.c b/hardinfo2/socket.c index cada32b6..66d3f56d 100644 --- a/hardinfo2/socket.c +++ b/hardinfo2/socket.c @@ -120,6 +120,7 @@ int sock_write(Socket * s, gchar * str) void sock_close(Socket * s) { + shutdown(s->sock, 2); close(s->sock); g_free(s); } diff --git a/hardinfo2/util.c b/hardinfo2/util.c index dd89e199..510c5d0e 100644 --- a/hardinfo2/util.c +++ b/hardinfo2/util.c @@ -363,6 +363,7 @@ void parameters_init(int *argc, char ***argv, ProgramParameters * param) static gboolean show_version = FALSE; static gboolean list_modules = FALSE; static gboolean autoload_deps = FALSE; + static gboolean run_xmlrpc_server = FALSE; static gchar *report_format = NULL; static gchar *run_benchmark = NULL; static gchar **use_modules = NULL; @@ -405,6 +406,12 @@ void parameters_init(int *argc, char ***argv, ProgramParameters * param) .arg_data = &autoload_deps, .description = "automatically load module dependencies"}, { + .long_name = "xmlrpc-server", + .short_name = 'x', + .arg = G_OPTION_ARG_NONE, + .arg_data = &run_xmlrpc_server, + .description = "run in XML-RPC server mode"}, + { .long_name = "version", .short_name = 'v', .arg = G_OPTION_ARG_NONE, @@ -436,6 +443,7 @@ void parameters_init(int *argc, char ***argv, ProgramParameters * param) param->use_modules = use_modules; param->run_benchmark = run_benchmark; param->autoload_deps = autoload_deps; + param->run_xmlrpc_server = run_xmlrpc_server; param->argv0 = *(argv)[0]; if (report_format && g_str_equal(report_format, "html")) diff --git a/hardinfo2/xmlrpc-server.c b/hardinfo2/xmlrpc-server.c new file mode 100644 index 00000000..519eef81 --- /dev/null +++ b/hardinfo2/xmlrpc-server.c @@ -0,0 +1,143 @@ +#include <stdio.h> +#include <libsoup/soup.h> + +#include "config.h" + +#define XMLRPC_SERVER_VERSION 1 + +static void method_get_api_version(SoupMessage *msg, GValueArray *params); +static void method_shutdown_server(SoupMessage *msg, GValueArray *params); + +static const struct { + gchar *method_name; + void *callback; +} handler_table[] = { + { "getAPIVersion", method_get_api_version }, + { "shutdownServer", method_shutdown_server }, + { NULL } +}; + +static GHashTable *handlers = NULL; +static GMainLoop *loop = NULL; + +static void method_get_api_version(SoupMessage *msg, GValueArray *params) +{ + soup_xmlrpc_set_response(msg, G_TYPE_INT, 1); +} + +static void method_shutdown_server(SoupMessage *msg, GValueArray *params) +{ + soup_xmlrpc_set_response(msg, G_TYPE_BOOLEAN, TRUE); + + g_main_loop_quit(loop); +} + +void xmlrpc_server_init(void) +{ + if (!loop) { + loop = g_main_loop_new(NULL, FALSE); + } + + if (!handlers) { + int i; + handlers = g_hash_table_new(g_str_hash, g_str_equal); + + for (i = 0; handler_table[i].method_name; i++) { + g_hash_table_insert(handlers, + handler_table[i].method_name, handler_table[i].callback); + } + } +} + +static SoupServer *xmlrpc_server_new(void) +{ + SoupServer *server; + + DEBUG("creating server"); + server = soup_server_new(SOUP_SERVER_SSL_CERT_FILE, NULL, + SOUP_SERVER_SSL_KEY_FILE, NULL, + SOUP_SERVER_ASYNC_CONTEXT, NULL, + NULL); + if (!server) { + return NULL; + } + + soup_server_run_async(server); + + return server; +} + +static void xmlrpc_server_callback(SoupServer *server, + SoupMessage *msg, + const char *path, + GHashTable *query, + SoupClientContext *context, + gpointer data) +{ + if (msg->method == SOUP_METHOD_POST) { + gchar *method_name; + GValueArray *params; + void (*callback)(SoupMessage *msg, GValueArray *params); + + DEBUG("received POST request"); + + if (!soup_xmlrpc_parse_method_call(msg->request_body->data, + msg->request_body->length, + &method_name, ¶ms)) { + soup_message_set_status(msg, SOUP_STATUS_BAD_REQUEST); + return; + } + + DEBUG("method: %s", method_name); + + if ((callback = g_hash_table_lookup(handlers, method_name))) { + soup_message_set_status(msg, SOUP_STATUS_OK); + + DEBUG("found callback: %p", callback); + callback(msg, params); + } else { + DEBUG("callback not found"); + soup_message_set_status(msg, SOUP_STATUS_NOT_ACCEPTABLE); + } + + g_free(method_name); + g_value_array_free(params); + } else { + DEBUG("received request of unknown method"); + soup_message_set_status(msg, SOUP_STATUS_NOT_IMPLEMENTED); + } +} + +void xmlrpc_server_start(void) +{ + SoupServer *server; + + if (!loop || !handlers) { + xmlrpc_server_init(); + } + + server = xmlrpc_server_new(); + if (!server) { + g_error("Cannot create XML-RPC server. Aborting"); + } + + soup_server_add_handler(server, "/xmlrpc", xmlrpc_server_callback, NULL, NULL); + + g_print("XML-RPC server listening on port: %d\n", soup_server_get_port(server)); + + DEBUG("starting server"); + g_main_loop_run(loop); + DEBUG("shutting down server"); + g_main_loop_unref(loop); +} + +#ifdef XMLRPC_SERVER_TEST +int main(void) +{ + g_type_init(); + g_thread_init(NULL); + + xmlrpc_server_init(); + xmlrpc_server_start(); +} +#endif /* XMLRPC_SERVER_TEST */ diff --git a/hardinfo2/xmlrpc-server.h b/hardinfo2/xmlrpc-server.h new file mode 100644 index 00000000..5ecafba4 --- /dev/null +++ b/hardinfo2/xmlrpc-server.h @@ -0,0 +1,7 @@ +#ifndef __XMLRPC_SERVER_H__ +#define __XMLRPC_SERVER_H__ + +void xmlrpc_server_start(void); +void xmlrpc_server_init(void); + +#endif /* __XMLRPC_SERVER_H__ */
\ No newline at end of file |