From: InHong Han Date: Thu, 7 Nov 2019 05:03:04 +0000 (+0900) Subject: Support on-demand launch X-Git-Tag: submit/tizen/20200117.041212~4 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=ec53be564d596116ed261e6150a8cf98a4e376f9;p=platform%2Fcore%2Fuifw%2Fcapi-ui-sticker.git Support on-demand launch Change-Id: I58af3046adb9eef35e85d6466b286b345adfae6e --- diff --git a/client/sticker_dbus.c b/client/sticker_dbus.c index 12b6722..627fe46 100644 --- a/client/sticker_dbus.c +++ b/client/sticker_dbus.c @@ -37,9 +37,10 @@ static void _server_vanished_cb(GDBusConnection *connection, const gchar *name, } //LCOV_EXCL_STOP -static int _dbus_init(GDBusConnection **gdbus_connection, guint *server_watcher_id) +static int _dbus_init(GDBusConnection **gdbus_connection) { GError *error = NULL; + int watch_id = 0; if (*gdbus_connection == NULL) { GDBusConnection *conn = NULL; @@ -55,17 +56,15 @@ static int _dbus_init(GDBusConnection **gdbus_connection, guint *server_watcher_ } LOGD("Connected bus name : %s", g_dbus_connection_get_unique_name(*gdbus_connection)); - if (*server_watcher_id == 0) { - *server_watcher_id = g_bus_watch_name(G_BUS_TYPE_SYSTEM, - STICKER_DBUS_NAME, - G_BUS_NAME_WATCHER_FLAGS_NONE, - _server_appeared_cb, - _server_vanished_cb, - NULL, NULL); - } + watch_id = g_bus_watch_name(G_BUS_TYPE_SYSTEM, + STICKER_DBUS_NAME, + G_BUS_NAME_WATCHER_FLAGS_NONE, + _server_appeared_cb, + _server_vanished_cb, + NULL, NULL); - LOGD("server_watcher_id : %d", *server_watcher_id); - if (*server_watcher_id == 0) { + LOGD("watch_id : %d", watch_id); + if (watch_id == 0) { LOGE("Failed to get identifier"); return STICKER_CLIENT_ERROR_IO_ERROR; } @@ -413,70 +412,54 @@ static int _send_sync_message(GDBusConnection *gdbus_connection, GVariant *body, return ret; } -static void _gdbus_reply_message_async_cb(GDBusConnection *connection, GAsyncResult *res, gpointer user_data) -{ - GDBusMessage *reply = NULL; - GError *err = NULL; - - reply = g_dbus_connection_send_message_with_reply_finish(connection, res, &err); - - if (reply) { - if (g_dbus_message_to_gerror(reply, &err)) { - LOGE("error message = %s, code = %d", err->message, err->code); - g_error_free(err); - return; - } - } else { - LOGE("There is no reply"); - return; - } - - if (reply) - g_object_unref(reply); - - LOGD("Reply message was received"); - return; -} - static int _send_async_message(GDBusConnection *gdbus_connection, GVariant *body, char *cmd) { int ret = STICKER_CLIENT_ERROR_NONE; GDBusMessage *msg = NULL; + GError *err = NULL; msg = _get_gbus_message(body, cmd); if (msg == NULL) return STICKER_CLIENT_ERROR_IO_ERROR; - g_dbus_connection_send_message_with_reply( - gdbus_connection, - msg, - G_DBUS_SEND_MESSAGE_FLAGS_NONE, - -1, - NULL, - NULL, - (GAsyncReadyCallback)_gdbus_reply_message_async_cb, - NULL); + g_dbus_connection_send_message(gdbus_connection, msg, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, &err); if (msg) g_object_unref(msg); + if (err != NULL) { + ret = STICKER_CLIENT_ERROR_SERVICE_NOT_READY; + LOGE("Error occurred when sending message(%s) : %s", cmd, err->message); + + if (err->code == G_DBUS_ERROR_ACCESS_DENIED) + ret = STICKER_CLIENT_ERROR_PERMISSION_DENIED; + + g_error_free(err); + return ret; + } + return ret; } -static int _monitor_register(GDBusConnection *gdbus_connection) +static int _monitor_register(GDBusConnection *gdbus_connection, int *server_watcher_id) { int ret; GDBusMessage *reply = NULL; + GVariant *reply_body = NULL; ret = _send_sync_message(gdbus_connection, g_variant_new("()"), &reply, "sticker_service_register"); - if (reply) - g_object_unref(reply); if (ret != STICKER_CLIENT_ERROR_NONE) { LOGE("_send_sync_message() failed : %d", ret); return ret; } + reply_body = g_dbus_message_get_body(reply); + g_variant_get(reply_body, "(i)", server_watcher_id); + + if (reply) + g_object_unref(reply); + is_server_started = 1; return ret; } @@ -486,8 +469,10 @@ static void _on_name_appeared(GDBusConnection *connection, const gchar *name_owner, gpointer user_data) { - if (is_server_started == 0) - _monitor_register(connection); + if (is_server_started == 0) { + int *watcher_id = (int *)user_data; + _monitor_register(connection, watcher_id); + } } //LCOV_EXCL_START @@ -499,12 +484,12 @@ static void _on_name_vanished(GDBusConnection *connection, } //LCOV_EXCL_STOP -int sticker_dbus_init(GDBusConnection **gdbus_connection, guint *server_watcher_id, +int sticker_dbus_init(GDBusConnection **gdbus_connection, int *server_watcher_id, int *monitor_id, int *server_monitor_id, CLIENT_LIB lib, void *data) { int ret; - ret = _dbus_init(gdbus_connection, server_watcher_id); + ret = _dbus_init(gdbus_connection); if (ret != STICKER_CLIENT_ERROR_NONE) { LOGE("_dbus_init() failed : %d", ret); return ret; @@ -516,7 +501,7 @@ int sticker_dbus_init(GDBusConnection **gdbus_connection, guint *server_watcher_ return ret; } - ret = _monitor_register(*gdbus_connection); + ret = _monitor_register(*gdbus_connection, server_watcher_id); if (ret != STICKER_CLIENT_ERROR_NONE) { LOGE("_monitor_register() failed : %d", ret); return ret; @@ -529,7 +514,7 @@ int sticker_dbus_init(GDBusConnection **gdbus_connection, guint *server_watcher_ G_BUS_NAME_WATCHER_FLAGS_NONE, _on_name_appeared, _on_name_vanished, - NULL, + server_watcher_id, NULL); if (*server_monitor_id == 0) { g_dbus_connection_signal_unsubscribe(*gdbus_connection, *monitor_id); @@ -542,8 +527,22 @@ int sticker_dbus_init(GDBusConnection **gdbus_connection, guint *server_watcher_ return STICKER_CLIENT_ERROR_NONE; } -int sticker_dbus_shutdown(GDBusConnection *gdbus_connection, int *server_monitor_id, int *monitor_id) +int sticker_dbus_shutdown(GDBusConnection *gdbus_connection, int *server_watcher_id, int *server_monitor_id, int *monitor_id) { + int ret; + GVariant *body = NULL; + + if (server_watcher_id) { + body = g_variant_new("(i)", *server_watcher_id); + ret = _send_async_message(gdbus_connection, body, "sticker_service_unregister"); + if (ret != STICKER_CLIENT_ERROR_NONE) { + LOGE("Failed to unregister sticker service"); + return ret; + } + + *server_watcher_id = 0; + } + if (*server_monitor_id) { g_bus_unwatch_name(*server_monitor_id); *server_monitor_id = 0; @@ -554,6 +553,9 @@ int sticker_dbus_shutdown(GDBusConnection *gdbus_connection, int *server_monitor *monitor_id = 0; } + if (body) + g_variant_unref(body); + return STICKER_CLIENT_ERROR_NONE; } diff --git a/client/sticker_dbus.h b/client/sticker_dbus.h index d8fcbcd..44d2309 100644 --- a/client/sticker_dbus.h +++ b/client/sticker_dbus.h @@ -42,9 +42,9 @@ enum sticker_client_error { STICKER_CLIENT_ERROR_IO_ERROR, }; -int sticker_dbus_init(GDBusConnection **gdbus_connection, guint *server_watcher_id, +int sticker_dbus_init(GDBusConnection **gdbus_connection, int *server_watcher_id, int *monitor_id, int *server_monitor_id, CLIENT_LIB lib, void *data); -int sticker_dbus_shutdown(GDBusConnection *gdbus_connection, int *server_monitor_id, int *monitor_id); +int sticker_dbus_shutdown(GDBusConnection *gdbus_connection, int *server_watcher_id, int *server_monitor_id, int *monitor_id); int sticker_dbus_insert_sticker_info(GDBusConnection *gdbus_connection, sticker_data_h sticker_data); int sticker_dbus_insert_sticker_info_by_json(GDBusConnection *gdbus_connection, const char *app_id, const char *json_path); int sticker_dbus_delete_sticker_info(GDBusConnection *gdbus_connection, int record_id); diff --git a/consumer/sticker_consumer.c b/consumer/sticker_consumer.c index 7b5d544..8602652 100644 --- a/consumer/sticker_consumer.c +++ b/consumer/sticker_consumer.c @@ -180,7 +180,8 @@ EXPORT_API int sticker_consumer_destroy(sticker_consumer_h consumer_handle) return STICKER_ERROR_INVALID_PARAMETER; LOGD("consumer_handle : %p", consumer_handle); - ret = sticker_dbus_shutdown(consumer_handle->gdbus_connection, &consumer_handle->server_monitor_id, &consumer_handle->monitor_id); + ret = sticker_dbus_shutdown(consumer_handle->gdbus_connection, &consumer_handle->server_watcher_id, + &consumer_handle->server_monitor_id, &consumer_handle->monitor_id); if (ret != STICKER_ERROR_NONE) { LOGE("Failed to finalize dbus : %d", ret); free(consumer_handle); diff --git a/consumer/sticker_consumer_main.h b/consumer/sticker_consumer_main.h index ba7f90d..7a08ad2 100644 --- a/consumer/sticker_consumer_main.h +++ b/consumer/sticker_consumer_main.h @@ -28,7 +28,7 @@ extern "C" struct sticker_consumer_s { GDBusConnection *gdbus_connection; - guint server_watcher_id; + int server_watcher_id; int monitor_id; int server_monitor_id; }; diff --git a/packaging/capi-ui-sticker.spec b/packaging/capi-ui-sticker.spec index 50c55df..9ded0a6 100644 --- a/packaging/capi-ui-sticker.spec +++ b/packaging/capi-ui-sticker.spec @@ -76,9 +76,8 @@ find . -name '*.gcno' -exec cp '{}' gcov-obj ';' rm -rf %{buildroot} %make_install -mkdir -p %{buildroot}%{_unitdir}/multi-user.target.wants +mkdir -p %{buildroot}%{_prefix}/lib/systemd/system install -m 0644 %SOURCE1 %{buildroot}%{_unitdir}/capi-ui-sticker.service -%install_service multi-user.target.wants capi-ui-sticker.service mkdir -p %{buildroot}%{_datadir}/dbus-1/system-services install -m 0644 %SOURCE2 %{buildroot}%{_datadir}/dbus-1/system-services/org.tizen.sticker.server.service @@ -107,7 +106,6 @@ chsmack -a "System::Shared" %{TZ_SYS_SHARE}/sticker-data %{_libdir}/lib*.so %attr(0755,ui_fw,ui_fw) %{_bindir}/sticker-server %attr(0644,root,root) %{_unitdir}/capi-ui-sticker.service -%attr(0644,root,root) %{_unitdir}/multi-user.target.wants/capi-ui-sticker.service %attr(0644,root,root) %{_datadir}/dbus-1/system-services/org.tizen.sticker.server.service %config %{_sysconfdir}/dbus-1/system.d/capi-ui-sticker.conf %{TZ_SYS_RO_SHARE}/parser-plugins/capi-ui-sticker.info diff --git a/provider/sticker_provider.c b/provider/sticker_provider.c index 3761d6a..a271ca6 100644 --- a/provider/sticker_provider.c +++ b/provider/sticker_provider.c @@ -106,7 +106,8 @@ EXPORT_API int sticker_provider_destroy(sticker_provider_h provider_handle) return STICKER_ERROR_INVALID_PARAMETER; LOGD("provider_handle : %p", provider_handle); - ret = sticker_dbus_shutdown(provider_handle->gdbus_connection, &provider_handle->server_monitor_id, &provider_handle->monitor_id); + ret = sticker_dbus_shutdown(provider_handle->gdbus_connection, &provider_handle->server_watcher_id, + &provider_handle->server_monitor_id, &provider_handle->monitor_id); if (ret != STICKER_ERROR_NONE) { LOGE("Failed to finalize dbus : %d", ret); free(provider_handle); diff --git a/provider/sticker_provider_main.h b/provider/sticker_provider_main.h index 6280801..4f1c9dd 100644 --- a/provider/sticker_provider_main.h +++ b/provider/sticker_provider_main.h @@ -28,7 +28,7 @@ extern "C" struct sticker_provider_s { GDBusConnection *gdbus_connection; - guint server_watcher_id; + int server_watcher_id; int monitor_id; int server_monitor_id; sticker_provider_insert_finished_cb insert_finished_cb; diff --git a/server/stickerd_data_manager.c b/server/stickerd_data_manager.c index b0922da..f7a1e7b 100644 --- a/server/stickerd_data_manager.c +++ b/server/stickerd_data_manager.c @@ -42,8 +42,19 @@ #define STICKER_DIRECTORY tzplatform_mkpath(TZ_SYS_SHARE, "sticker-data") #define MAX_ERROR_BUFFER 256 -static GHashTable *_monitoring_hash; +static GHashTable *_monitoring_hash = NULL; static char error_buffer[MAX_ERROR_BUFFER]; +extern GMainLoop *main_loop; + +static void _check_watcher_exist() +{ + if (_monitoring_hash != NULL && g_hash_table_size(_monitoring_hash) == 0) { + LOGD("Terminate sticker daemon"); + g_hash_table_destroy(_monitoring_hash); + _monitoring_hash = NULL; + g_main_loop_quit(main_loop); + } +} static void _on_name_appeared(GDBusConnection *connection, const gchar *name, @@ -60,15 +71,19 @@ static void _on_name_vanished(GDBusConnection *connection, monitoring_info_s *info = (monitoring_info_s *)user_data; if (info) { - LOGD("name: %s", name); - g_bus_unwatch_name(info->watcher_id); - delete_monitoring_list(&_monitoring_hash, info->bus_name, info->uid); + if (_monitoring_hash != NULL && g_hash_table_lookup(_monitoring_hash, GUINT_TO_POINTER(info->watcher_id)) != NULL) { + LOGD("name: %s", name); + g_bus_unwatch_name(info->watcher_id); + delete_monitoring_list(&_monitoring_hash, info->bus_name, info->watcher_id); + } if (info->bus_name) free(info->bus_name); free(info); info = NULL; } + + _check_watcher_exist(); } static void _stickerd_client_dbus_method_call_handler(GDBusConnection *conn, const gchar *sender, const gchar *object_path, @@ -77,12 +92,17 @@ static void _stickerd_client_dbus_method_call_handler(GDBusConnection *conn, con { LOGD("stickerd method_name: %s, sender: %s", method_name, sender); + if (_monitoring_hash == NULL) + _monitoring_hash = g_hash_table_new(g_direct_hash, g_direct_equal); + GVariant *reply_body = NULL; int ret = STICKERD_SERVER_ERROR_OPERATION_FAILED; if (g_strcmp0(method_name, "sticker_service_register") == 0) { ret = stickerd_server_register(parameters, &reply_body, sender, _on_name_appeared, _on_name_vanished, &_monitoring_hash); + } else if (g_strcmp0(method_name, "sticker_service_unregister") == 0) { + ret = stickerd_server_unregister(parameters, &reply_body, sender, &_monitoring_hash); } else if (g_strcmp0(method_name, "insert_sticker_info") == 0) { ret = stickerd_insert_sticker_info(parameters, &reply_body); } else if (g_strcmp0(method_name, "update_sticker_info_by_json") == 0) { @@ -131,6 +151,8 @@ static void _stickerd_client_dbus_method_call_handler(GDBusConnection *conn, con if (reply_body) g_variant_unref(reply_body); + + _check_watcher_exist(); } static const GDBusInterfaceVTable _sticker_interface_vtable = { @@ -145,6 +167,11 @@ int stickerd_register_dbus_interface(void) " " " " " " + " " + " " + + " " + " " " " " " diff --git a/server/stickerd_dbus.c b/server/stickerd_dbus.c index 4ff175a..6184033 100644 --- a/server/stickerd_dbus.c +++ b/server/stickerd_dbus.c @@ -29,67 +29,92 @@ #define LOG_TAG "STICKERD_DBUS" static GDBusConnection *_gdbus_connection; +extern GMainLoop *main_loop; int stickerd_server_register(GVariant *parameters, GVariant **reply_body, const gchar *sender, GBusNameAppearedCallback name_appeared_handler, GBusNameVanishedCallback name_vanished_handler, GHashTable **monitoring_hash) { - GList *sender_list = NULL; - const char *bus_name = sender; + int ret = STICKERD_SERVER_ERROR_NONE; + char *m_info_bus_name = NULL; + char *list_bus_name = NULL; monitoring_info_s *m_info = NULL; - uid_t request_uid = 0; GList *monitoring_list = NULL; - if (bus_name == NULL) - return STICKERD_SERVER_ERROR_IO_ERROR; - - g_variant_get(parameters, "(i)", &request_uid); - monitoring_list = (GList *)g_hash_table_lookup(*monitoring_hash, GUINT_TO_POINTER(request_uid)); - sender_list = g_list_find_custom(monitoring_list, bus_name, (GCompareFunc) strcmp); + if (reply_body == NULL) + return STICKERD_SERVER_ERROR_INVALID_PARAMETER; - if (sender_list == NULL) { - LOGD("Add a new sender"); - m_info = (monitoring_info_s *)calloc(1, sizeof(monitoring_info_s)); - if (m_info == NULL) { - LOGE("Failed to alloc memory"); - return STICKERD_SERVER_ERROR_IO_ERROR; - } + m_info_bus_name = strdup(sender); + list_bus_name = strdup(sender); + if (m_info_bus_name == NULL || list_bus_name == NULL) { + ret = STICKERD_SERVER_ERROR_IO_ERROR; + goto cleanup; + } - m_info->bus_name = strdup(bus_name); - m_info->uid = request_uid; - m_info->watcher_id = g_bus_watch_name_on_connection( - _gdbus_connection, - bus_name, - G_BUS_NAME_WATCHER_FLAGS_NONE, - name_appeared_handler, - name_vanished_handler, - m_info, - NULL); - if (m_info->watcher_id == 0) { - LOGE("Failed to get identifier"); - free(m_info->bus_name); - free(m_info); - return STICKERD_SERVER_ERROR_IO_ERROR; - } + LOGD("Add a new sender"); + m_info = (monitoring_info_s *)calloc(1, sizeof(monitoring_info_s)); + if (m_info == NULL) { + LOGE("Failed to alloc memory"); + ret = STICKERD_SERVER_ERROR_OUT_OF_MEMORY; + goto cleanup; + } - monitoring_list = g_list_append(monitoring_list, strdup(bus_name)); - LOGD("sender: %s, len: %d", sender, g_list_length(monitoring_list)); - if (g_hash_table_lookup(*monitoring_hash, GUINT_TO_POINTER(request_uid)) == NULL) - g_hash_table_insert(*monitoring_hash, GUINT_TO_POINTER(request_uid), monitoring_list); - } else { - LOGW("Sender(%s) already exist", sender); + m_info->bus_name = m_info_bus_name; + m_info->watcher_id = g_bus_watch_name_on_connection( + _gdbus_connection, + m_info_bus_name, + G_BUS_NAME_WATCHER_FLAGS_NONE, + name_appeared_handler, + name_vanished_handler, + m_info, + NULL); + if (m_info->watcher_id == 0) { + LOGE("Failed to get identifier"); + ret = STICKERD_SERVER_ERROR_OPERATION_FAILED; + goto cleanup; } - *reply_body = g_variant_new("()"); + *reply_body = g_variant_new("(i)", m_info->watcher_id); if (*reply_body == NULL) { - if (m_info) { - if (m_info->bus_name) - free(m_info->bus_name); - free(m_info); - } - monitoring_list = g_list_remove(monitoring_list, bus_name); LOGE("Failed to make reply"); - return STICKERD_SERVER_ERROR_OUT_OF_MEMORY; + ret = STICKERD_SERVER_ERROR_OUT_OF_MEMORY; + goto cleanup; } + + LOGD("sender: %s, watcher: %d", sender, m_info->watcher_id); + monitoring_list = g_list_append(monitoring_list, list_bus_name); + if (g_hash_table_lookup(*monitoring_hash, GUINT_TO_POINTER(m_info->watcher_id)) == NULL) + g_hash_table_insert(*monitoring_hash, GUINT_TO_POINTER(m_info->watcher_id), monitoring_list); + else + LOGW("Sender(%s) already exist", sender); + + return STICKERD_SERVER_ERROR_NONE; + +cleanup: + if (m_info_bus_name) + free(m_info_bus_name); + + if (list_bus_name) + free(list_bus_name); + + if (m_info) { + free(m_info); + m_info = NULL; + } + + return ret; +} + +int stickerd_server_unregister(GVariant *parameters, GVariant **reply_body, const gchar *sender, GHashTable **monitoring_hash) +{ + int watcher_id = 0; + + g_variant_get(parameters, "(i)", &watcher_id); + + if (g_hash_table_lookup(*monitoring_hash, GUINT_TO_POINTER(watcher_id)) != NULL) { + g_bus_unwatch_name(watcher_id); + delete_monitoring_list(monitoring_hash, sender, watcher_id); + } + return STICKERD_SERVER_ERROR_NONE; } @@ -156,15 +181,15 @@ cleanup: return result; } -int delete_monitoring_list(GHashTable **monitoring_hash, const char *sender, uid_t uid) +int delete_monitoring_list(GHashTable **monitoring_hash, const char *sender, int watcher_id) { GList *monitoring_list = NULL; GList *del_list = NULL; char *bus_name; - monitoring_list = (GList *)g_hash_table_lookup(*monitoring_hash, GUINT_TO_POINTER(uid)); + monitoring_list = (GList *)g_hash_table_lookup(*monitoring_hash, GUINT_TO_POINTER(watcher_id)); if (monitoring_list == NULL) { - LOGE("The key(%d) is not found", uid); + LOGE("The key(%d) is not found", watcher_id); return STICKERD_SERVER_ERROR_IO_ERROR; } @@ -179,10 +204,10 @@ int delete_monitoring_list(GHashTable **monitoring_hash, const char *sender, uid monitoring_list = g_list_delete_link(monitoring_list, del_list); if (monitoring_list == NULL) { - g_hash_table_steal(*monitoring_hash, GUINT_TO_POINTER(uid)); + g_hash_table_steal(*monitoring_hash, GUINT_TO_POINTER(watcher_id)); } else { monitoring_list = g_list_first(monitoring_list); - g_hash_table_replace(*monitoring_hash, GUINT_TO_POINTER(uid), monitoring_list); + g_hash_table_replace(*monitoring_hash, GUINT_TO_POINTER(watcher_id), monitoring_list); } } return STICKERD_SERVER_ERROR_NONE; diff --git a/server/stickerd_dbus.h b/server/stickerd_dbus.h index 0197793..e8ad143 100644 --- a/server/stickerd_dbus.h +++ b/server/stickerd_dbus.h @@ -28,14 +28,13 @@ extern "C" { typedef struct monitoring_info { int watcher_id; char *bus_name; - uid_t uid; } monitoring_info_s; int stickerd_server_register(GVariant *parameters, GVariant **reply_body, const gchar *sender, GBusNameAppearedCallback name_appeared_handler, GBusNameVanishedCallback name_vanished_handler, GHashTable **monitoring_hash); int stickerd_server_unregister(GVariant *parameters, GVariant **reply_body, const gchar *sender, GHashTable **monitoring_hash); int stickerd_server_register_dbus_interface(char *introspection_xml, GDBusInterfaceVTable interface_vtable); -int delete_monitoring_list(GHashTable **monitoring_hash, const char *sender, uid_t uid); +int delete_monitoring_list(GHashTable **monitoring_hash, const char *sender, int monitoring_id); int stickerd_send_dbus_message(GVariant *body, const char *dest, char *cmd, CLIENT_LIB lib); #ifdef __cplusplus diff --git a/server/stickerd_main.c b/server/stickerd_main.c index 1650437..38d92f9 100644 --- a/server/stickerd_main.c +++ b/server/stickerd_main.c @@ -33,7 +33,7 @@ #define MAX_ERROR_BUFFER 256 -static GMainLoop *main_loop; +GMainLoop *main_loop = NULL; static GIOChannel *channel = NULL; static guint source = 0;